root/trunk/llmozlib2/llembeddedbrowserwindow.cpp

Revision 3, 34.3 kB (checked in by rob.linden, 2 years ago)

I believe this is the version included in 1.18.6.3
Last Changed Rev: 76367
Last Changed Date: 2007-12-21 09:34:18 -0800 (Fri, 21 Dec 2007)

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1 /**
2  * @file llembeddedbrowserwindow.cpp
3  * @brief LLEmbeddedBrowserWindow implementation.
4  *
5  * $LicenseInfo:firstyear=2006&license=viewergpl$
6  *
7  * Copyright (c) 2006-2007, Linden Research, Inc.
8  *
9  * Second Life Viewer Source Code
10  * The source code in this file ("Source Code") is provided by Linden Lab
11  * to you under the terms of the GNU General Public License, version 2.0
12  * ("GPL"), unless you have obtained a separate licensing agreement
13  * ("Other License"), formally executed by you and Linden Lab.  Terms of
14  * the GPL can be found in doc/GPL-license.txt in this distribution, or
15  * online at http://secondlife.com/developers/opensource/gplv2
16  *
17  * There are special exceptions to the terms and conditions of the GPL as
18  * it is applied to this Source Code. View the full text of the exception
19  * in the file doc/FLOSS-exception.txt in this software distribution, or
20  * online at http://secondlife.com/developers/opensource/flossexception
21  *
22  * By copying, modifying or distributing this software, you acknowledge
23  * that you have read and understood your obligations described above,
24  * and agree to abide by those obligations.
25  *
26  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
27  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28  * COMPLETENESS OR PERFORMANCE.
29  * $/LicenseInfo$
30  */
31
32 // required by LibXUL/Mozilla code to avoid crashes in their debug code, but only on Windows.
33 // undef'd at end of this
34 #ifdef _DEBUG
35         #ifdef WIN32
36                 #define DEBUG 1
37         #endif
38 #endif
39
40 #include "llembeddedbrowserwindow.h"
41
42 // Mozilla code has non-virtual destructors
43 #ifdef WIN32
44 #pragma warning( disable : 4291 ) // (no matching operator delete found; memory will not be freed if initialization throws an exception)
45 #pragma warning( disable : 4265 ) // "class has virtual functions, but destructor is not virtual"
46 #endif
47
48 #include "nsCWebBrowser.h"
49 #include "nsGUIEvent.h"
50 #include "nsICaret.h"
51 #include "nsIContent.h"
52 #include "nsIDOMDocument.h"
53 #include "nsIDOMElement.h"
54 #include "nsIDOMWindow.h"
55 #include "nsIDOMEvent.h"
56 #include "nsIDocShell.h"
57 #include "nsIDocShellTreeItem.h"
58 #include "nsIDocument.h"
59 #include "nsIFrame.h"
60 #include "nsIHttpChannel.h"
61 #include "nsIInterfaceRequestorUtils.h"
62 #include "nsIScrollableView.h"
63 #include "nsISelection.h"
64 #include "nsISelectionController.h"
65 #include "nsIWebBrowserChrome.h"
66 #include "nsIWebBrowserChromeFocus.h"
67 #include "nsIWebBrowserFocus.h"
68 #include "nsIWebProgress.h"
69 #include "nsIWebProgressListener.h"
70 #include "nsPresContext.h"
71 #include "nsProfileDirServiceProvider.h"
72 #include "nsXPCOMGlue.h"
73 #include "nsXULAppAPI.h"
74
75 #ifdef WIN32
76 #pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual"
77 #endif
78
79 ////////////////////////////////////////////////////////////////////////////////
80 //
81 LLEmbeddedBrowserWindow::LLEmbeddedBrowserWindow() :
82         mWebBrowser( nsnull ),
83         mBaseWindow( nsnull ),
84         mWindowId( 0 ),
85         mPercentComplete( 0 ),
86         mBrowserWidth( 0 ),
87         mBrowserHeight( 0 ),
88         mBrowserDepth( 4 ),
89         mPageBuffer( NULL ),
90         mPageBufferSize ( 0 ),
91         mCurrentUri( "" ),
92         mStatusText( "" ),
93         mClickHref( "" ),
94         mBackgroundRed( 0xff ),
95         mBackgroundGreen( 0xff ),
96         mBackgroundBlue( 0xff ),
97         mCaretRed( 0x0 ),
98         mCaretGreen( 0x0 ),
99         mCaretBlue( 0x0 ),
100         m404RedirectUrl( "" )
101 {
102 }
103
104 ////////////////////////////////////////////////////////////////////////////////
105 //
106 LLEmbeddedBrowserWindow::~LLEmbeddedBrowserWindow()
107 {
108         if ( mWebNav )
109         {
110                 mWebNav->Stop ( nsIWebNavigation::STOP_ALL );
111                 mWebNav = nsnull;
112         };
113
114         if ( mBaseWindow )
115         {
116                 mBaseWindow->Destroy();
117                 mBaseWindow = nsnull;
118         };
119
120         if ( mPageBuffer )
121         {
122                 delete[] mPageBuffer;
123                 mPageBuffer = NULL;
124                 mPageBufferSize = 0;
125         };
126 }
127
128 ////////////////////////////////////////////////////////////////////////////////
129 //
130 nsresult LLEmbeddedBrowserWindow::createBrowser( void* nativeWindowHandleIn, PRInt32 widthIn, PRInt32 heightIn, nsIWebBrowser **aBrowser )
131 {
132         NS_ENSURE_ARG_POINTER(aBrowser);
133         *aBrowser = nsnull;
134
135         mWebBrowser = do_CreateInstance( NS_WEBBROWSER_CONTRACTID );
136         if ( ! mWebBrowser )
137                 return NS_ERROR_FAILURE;
138
139     (void)mWebBrowser->SetContainerWindow(NS_STATIC_CAST(nsIWebBrowserChrome*, this));
140
141     nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(mWebBrowser);
142     dsti->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
143
144     mBaseWindow = do_QueryInterface(mWebBrowser);
145
146     mBaseWindow->InitWindow( nativeWindowHandleIn, nsnull,  0, 0, mBrowserWidth, mBrowserHeight );
147     mBaseWindow->Create();
148
149     nsCOMPtr<nsIWebProgressListener> listener(NS_STATIC_CAST(nsIWebProgressListener*, this));
150     nsCOMPtr<nsIWeakReference> thisListener(do_GetWeakReference(listener));
151     (void)mWebBrowser->AddWebBrowserListener(thisListener,
152         NS_GET_IID(nsIWebProgressListener));
153
154         nsresult result;
155         // set the listener to we can catch nsURIContentListener events
156         if ( mWebBrowser )
157         {
158                 result = mWebBrowser->SetParentURIContentListener( NS_STATIC_CAST( nsIURIContentListener*, this ) );
159                 if ( NS_FAILED( result ) )
160                 {
161                 };
162         };
163
164         mWebNav = do_QueryInterface( mWebBrowser, &result );
165         if ( NS_FAILED( result ) || ! mWebNav )
166         {
167         };
168
169         mBaseWindow->SetVisibility( PR_FALSE );
170
171         setSize( widthIn, heightIn );
172
173     if (mWebBrowser)
174     {
175                 *aBrowser = mWebBrowser;
176                 NS_ADDREF(*aBrowser);
177                 return NS_OK;
178     };
179
180     return NS_ERROR_FAILURE;
181 }
182
183 ////////////////////////////////////////////////////////////////////////////////
184 //
185 NS_IMPL_ADDREF( LLEmbeddedBrowserWindow )
186 NS_IMPL_RELEASE( LLEmbeddedBrowserWindow )
187
188 ////////////////////////////////////////////////////////////////////////////////
189 //
190 NS_INTERFACE_MAP_BEGIN( LLEmbeddedBrowserWindow )
191         NS_INTERFACE_MAP_ENTRY_AMBIGUOUS( nsISupports, nsIWebBrowserChrome )
192         NS_INTERFACE_MAP_ENTRY( nsIInterfaceRequestor )
193         NS_INTERFACE_MAP_ENTRY( nsIWebBrowserChrome )
194         NS_INTERFACE_MAP_ENTRY( nsIWebProgressListener )
195         NS_INTERFACE_MAP_ENTRY( nsIURIContentListener )
196         NS_INTERFACE_MAP_ENTRY( nsISupportsWeakReference )
197 NS_INTERFACE_MAP_END
198
199 ////////////////////////////////////////////////////////////////////////////////
200 //
201 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetInterface( const nsIID &aIID, void** aInstancePtr )
202 {
203         if ( aIID.Equals( NS_GET_IID( nsIDOMWindow ) ) )
204         {
205                 if ( mWebBrowser )
206                 {
207                         return mWebBrowser->GetContentDOMWindow( ( nsIDOMWindow** )aInstancePtr );
208                 };
209
210                 return NS_ERROR_NOT_INITIALIZED;
211         };
212
213         return QueryInterface( aIID, aInstancePtr );
214 }
215
216 ////////////////////////////////////////////////////////////////////////////////
217 // called when something changes the status text - emits event to consumer
218 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetStatus( PRUint32 aType, const PRUnichar* aStatus )
219 {
220         mStatusText = std::string( NS_ConvertUTF16toUTF8( aStatus ).get() );
221
222         LLEmbeddedBrowserWindowEvent event( getWindowId(), mStatusText );
223         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onStatusTextChange, event );
224
225         return NS_OK;
226 }
227
228 ////////////////////////////////////////////////////////////////////////////////
229 //
230 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetWebBrowser( nsIWebBrowser** aWebBrowser )
231 {
232         NS_ENSURE_ARG_POINTER( aWebBrowser );
233
234         *aWebBrowser = mWebBrowser;
235
236         NS_IF_ADDREF( *aWebBrowser );
237
238         return NS_OK;
239 }
240
241 ////////////////////////////////////////////////////////////////////////////////
242 //
243 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetWebBrowser( nsIWebBrowser* aWebBrowser )
244 {
245         NS_ENSURE_ARG_POINTER( aWebBrowser );
246
247         mWebBrowser = aWebBrowser;
248
249         return NS_OK;
250 }
251
252 ////////////////////////////////////////////////////////////////////////////////
253 //
254 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetChromeFlags( PRUint32* aChromeMask )
255 {
256         return NS_ERROR_NOT_IMPLEMENTED;
257 }
258
259 ////////////////////////////////////////////////////////////////////////////////
260 //
261 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetChromeFlags( PRUint32 aChromeMask )
262 {
263         return NS_ERROR_NOT_IMPLEMENTED;
264 }
265
266 ////////////////////////////////////////////////////////////////////////////////
267 //
268 NS_IMETHODIMP LLEmbeddedBrowserWindow::DestroyBrowserWindow()
269 {
270         return NS_OK;
271 }
272
273 ////////////////////////////////////////////////////////////////////////////////
274 //
275 NS_IMETHODIMP LLEmbeddedBrowserWindow::SizeBrowserTo( PRInt32 aCX, PRInt32 aCY )
276 {
277         return NS_OK;
278 }
279
280 ////////////////////////////////////////////////////////////////////////////////
281 //
282 NS_IMETHODIMP LLEmbeddedBrowserWindow::ShowAsModal()
283 {
284         return NS_ERROR_NOT_IMPLEMENTED;
285 }
286
287 ////////////////////////////////////////////////////////////////////////////////
288 //
289 //
290 NS_IMETHODIMP LLEmbeddedBrowserWindow::IsWindowModal( PRBool* retval )
291 {
292         *retval = PR_FALSE;
293
294         return NS_OK;
295 }
296
297 ////////////////////////////////////////////////////////////////////////////////
298 //
299 NS_IMETHODIMP LLEmbeddedBrowserWindow::ExitModalEventLoop( nsresult aStatus )
300 {
301         return NS_OK;
302 }
303
304 ////////////////////////////////////////////////////////////////////////////////
305 // called when the page loading progress changes - emits event to consumer
306 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnProgressChange( nsIWebProgress* progress, nsIRequest* request,
307                                                                                                         PRInt32 curSelfProgress, PRInt32 maxSelfProgress,
308                                                                                                                 PRInt32 curTotalProgress, PRInt32 maxTotalProgress )
309 {
310         mPercentComplete = static_cast< PRInt16 >
311                 ( static_cast< float >( curTotalProgress * 100.0f ) / static_cast< float >( maxTotalProgress ) );
312
313         if ( mPercentComplete < 0 )
314                 mPercentComplete = 0;
315
316         if ( mPercentComplete > 100 )
317                 mPercentComplete = 100;
318
319         LLEmbeddedBrowserWindowEvent event( getWindowId(), mPercentComplete );
320         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onUpdateProgress, event );
321
322         return NS_OK;
323 }
324
325 ////////////////////////////////////////////////////////////////////////////////
326 // called when the browser state changes - as described below - emits event to consumer
327 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnStateChange( nsIWebProgress* progress, nsIRequest* request,
328                                                                                                         PRUint32 progressStateFlags, nsresult status )
329 {
330         if ( ( progressStateFlags & STATE_START ) && ( progressStateFlags & STATE_IS_DOCUMENT ) && ( status == NS_OK ) )
331         {
332                 // page load is starting so remove listener that catches "click" events
333                 nsCOMPtr< nsIDOMWindow > window;
334                 nsresult result = progress->GetDOMWindow( getter_AddRefs( window ) );
335                 if ( result == NS_OK )
336                 {
337                         nsCOMPtr< nsIDOMEventTarget > target = do_QueryInterface( window );
338                         if ( target )
339                                 target->RemoveEventListener(NS_ConvertUTF8toUTF16( "click" ), this, PR_TRUE );
340                 };
341
342                 // emit event that navigation is beginning
343                 mStatusText = std::string( "Browser loaded" );
344                 LLEmbeddedBrowserWindowEvent event( getWindowId() );
345                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onNavigateBegin, event );
346         };
347
348         if ( ( progressStateFlags & STATE_STOP ) && ( progressStateFlags & STATE_IS_WINDOW ) && ( status == NS_OK ) )
349         {
350                 // page load is complete so add listener that catches "click" events
351                 nsCOMPtr< nsIDOMWindow > window;
352                 nsresult result = progress->GetDOMWindow( getter_AddRefs( window ) );
353                 if ( result == NS_OK )
354                 {
355                         nsCOMPtr< nsIDOMEventTarget > target = do_QueryInterface( window );
356                         if ( target )
357                                 target->AddEventListener(NS_ConvertUTF8toUTF16( "click" ), this, PR_TRUE );
358                 };
359
360                 // emit event that navigation is finished
361                 mStatusText = std::string( "Done" );
362                 LLEmbeddedBrowserWindowEvent event( getWindowId() );
363                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onNavigateComplete, event );
364         };
365
366         if ( progressStateFlags & STATE_REDIRECTING )
367         {
368                 mStatusText = std::string( "Redirecting..." );
369         };
370
371         if ( progressStateFlags & STATE_TRANSFERRING )
372         {
373                 mStatusText = std::string( "Transferring..." );
374         };
375
376         if ( progressStateFlags & STATE_NEGOTIATING )
377         {
378                 mStatusText = std::string( "Negotiating..." );
379         };
380
381         LLEmbeddedBrowserWindowEvent event( getWindowId(), mStatusText );
382         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onStatusTextChange, event );
383
384         return NS_OK;
385 }
386
387 ////////////////////////////////////////////////////////////////////////////////
388 // call when the location changes - e.g. when a site redirects - emits event to consumer
389 // TODO: ought to check that this change is on the top frame and
390 // indicate this to the consumer of this class
391 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnLocationChange( nsIWebProgress* progress,
392                                                                                                                         nsIRequest* request,
393                                                                                                                                 nsIURI* location )
394 {
395         if ( request )
396         {
397                 nsCOMPtr< nsIHttpChannel > http_channel = do_QueryInterface( request );
398                 if ( http_channel )
399                 {
400                         PRUint32 response_status = 0;
401                         http_channel->GetResponseStatus( &response_status );
402
403                         if ( response_status == 404 )
404                         {
405                                 if ( ! m404RedirectUrl.empty() )
406                                 {
407                                         if ( mWebNav )
408                                         {
409                                                 mWebNav->LoadURI( reinterpret_cast< const PRUnichar* >
410                                                         ( NS_ConvertUTF8toUTF16( m404RedirectUrl.c_str() ).get() ),
411                                                                 nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY,
412                                                                         nsnull, nsnull, nsnull );
413                                         };
414                                 };
415                         };
416                 };
417         };
418
419         nsCAutoString newURI;
420         location->GetSpec( newURI );
421
422         mCurrentUri = newURI.get();
423
424         LLEmbeddedBrowserWindowEvent event( getWindowId(), mCurrentUri );
425         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onLocationChange, event );
426
427         return NS_OK;
428 }
429
430 ////////////////////////////////////////////////////////////////////////////////
431 // allow consumers of this class to observe events - add themselves as an observer
432 bool LLEmbeddedBrowserWindow::addObserver( LLEmbeddedBrowserWindowObserver* observerIn )
433 {
434         return mEventEmitter.addObserver( observerIn );
435 }
436
437 ////////////////////////////////////////////////////////////////////////////////
438 // allow consumers of this class to observe events - remove themselves as an observer
439 bool LLEmbeddedBrowserWindow::remObserver( LLEmbeddedBrowserWindowObserver* observerIn )
440 {
441         return mEventEmitter.remObserver( observerIn );
442 }
443
444 ////////////////////////////////////////////////////////////////////////////////
445 // used by observers of this class to get the current URI
446 const std::string& LLEmbeddedBrowserWindow::getCurrentUri()
447 {
448         return mCurrentUri;
449 }
450
451 ////////////////////////////////////////////////////////////////////////////////
452 // utility method that is used by observers to retrieve data after an event
453 const PRInt16 LLEmbeddedBrowserWindow::getPercentComplete()
454 {
455         return mPercentComplete;
456 }
457
458 ////////////////////////////////////////////////////////////////////////////////
459 // utility method that is used by observers to retrieve data after an event
460 const std::string& LLEmbeddedBrowserWindow::getStatusMsg()
461 {
462         return mStatusText;
463 }
464
465 ////////////////////////////////////////////////////////////////////////////////
466 // utility method that is used by observers to retrieve data after an event
467 const std::string& LLEmbeddedBrowserWindow::getClickLinkHref()
468 {
469         return mClickHref;
470 }
471
472 ////////////////////////////////////////////////////////////////////////////////
473 // called when the status text is changed - emits event to consumer
474 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnStatusChange( nsIWebProgress* aWebProgress,
475                                                                                                                 nsIRequest* aRequest,
476                                                                                                                         nsresult aStatus,
477                                                                                                                                 const PRUnichar* aMessage )
478 {
479         mStatusText = std::string( NS_ConvertUTF16toUTF8( aMessage ).get() );
480
481         LLEmbeddedBrowserWindowEvent event( getWindowId(), mStatusText );
482         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onStatusTextChange, event );
483
484         return NS_OK;
485 }
486
487 ////////////////////////////////////////////////////////////////////////////////
488 // implement this if you want to do something when the security state changtes
489 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnSecurityChange( nsIWebProgress* aWebProgress,
490                                                                                                         nsIRequest* aRequest,
491                                                                                                                 PRUint32 state )
492 {
493         return NS_OK;
494 }
495
496 ////////////////////////////////////////////////////////////////////////////////
497 //
498 unsigned char* LLEmbeddedBrowserWindow::grabWindow()
499 {
500         nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
501         if ( ! docShell )
502                 return PR_FALSE;
503
504         nsCOMPtr< nsPresContext > presContext;
505         nsresult result = docShell->GetPresContext( getter_AddRefs( presContext ) );
506         if ( NS_FAILED( result ) || ( ! presContext ) )
507                 return PR_FALSE;
508
509         nsIViewManager* viewManager = presContext->GetViewManager();
510         if ( ! viewManager )
511                 return PR_FALSE;
512
513         nsIScrollableView* scrollableView = NULL;
514         viewManager->GetRootScrollableView( &scrollableView );
515
516         nsIView* view = NULL;
517         if ( scrollableView )
518                 scrollableView->GetScrolledView( view );
519         else
520                 viewManager->GetRootView( view );
521
522         nsRect rect = view->GetBounds() - view->GetPosition() - view->GetPosition();
523         if ( rect.IsEmpty() )
524                 return 0;
525
526         float p2t = presContext->PixelsToTwips();
527         rect.width = NSIntPixelsToTwips( mBrowserWidth, p2t );
528         rect.height = NSIntPixelsToTwips( mBrowserHeight, p2t );
529
530         nsCOMPtr< nsIRenderingContext > context;
531         result = viewManager->RenderOffscreen( view, rect, PR_FALSE, PR_FALSE, NS_RGB( mBackgroundRed, mBackgroundGreen, mBackgroundBlue ), getter_AddRefs( context ) );
532         if ( NS_FAILED( result ) )
533                 return 0;
534
535         nsIDrawingSurface* surface = nsnull;
536         context->GetDrawingSurface( &surface );
537         if ( ! surface )
538                 return 0;
539
540         float t2p = presContext->TwipsToPixels();
541         PRInt32 width = NSTwipsToIntPixels( rect.width, t2p );
542         PRInt32 height = NSTwipsToIntPixels( rect.height, t2p );
543
544         PRUint8* data;
545         PRInt32 rowLen;
546
547         // sometime rowspan ! width in pixels * bytes per pixel so save row span value and use in application
548         result = surface->Lock( 0, 0, width, height, reinterpret_cast< void** >( &data ), &mBrowserRowSpan, &rowLen, NS_LOCK_SURFACE_READ_ONLY );
549         if ( NS_FAILED ( result ) )
550                 return 0;
551
552         PRUint32 bytesPerPix = rowLen / width;
553         nsPixelFormat format;
554         surface->GetPixelFormat( &format );
555         mBrowserDepth = bytesPerPix;
556         size_t bufferSize = mBrowserRowSpan * mBrowserHeight;
557
558         if( (mPageBuffer) && ( mPageBufferSize < bufferSize ) )
559         {
560                 // the page buffer exists, but it's too small.  Delete it so it'll be recreated.
561                 delete[] mPageBuffer;
562                 mPageBuffer = NULL;
563                 mPageBufferSize = 0;
564         }
565
566         // create it here so it can be deleted and recreated elsewhere
567         if ( ! mPageBuffer )
568         {
569                 mPageBufferSize = bufferSize;
570                 mPageBuffer = new unsigned char[ mPageBufferSize ];
571         }
572
573         memcpy( mPageBuffer, data, bufferSize );
574
575         surface->Unlock();
576         context->DestroyDrawingSurface( surface );
577
578         renderCaret();
579
580         return mPageBuffer;
581 }
582
583 ////////////////////////////////////////////////////////////////////////////////
584 // return the buffer that contains the rendered page
585 unsigned char* LLEmbeddedBrowserWindow::getPageBuffer()
586 {
587         return mPageBuffer;
588 }
589
590 ////////////////////////////////////////////////////////////////////////////////
591 //
592 PRInt16 LLEmbeddedBrowserWindow::getBrowserWidth()
593 {
594         return mBrowserWidth;
595 }
596
597 ////////////////////////////////////////////////////////////////////////////////
598 //
599 PRInt16 LLEmbeddedBrowserWindow::getBrowserHeight()
600 {
601         return mBrowserHeight;
602 }
603
604 ////////////////////////////////////////////////////////////////////////////////
605 //
606 PRInt16 LLEmbeddedBrowserWindow::getBrowserDepth()
607 {
608         return mBrowserDepth;
609 }
610
611 ////////////////////////////////////////////////////////////////////////////////
612 //
613 PRInt32 LLEmbeddedBrowserWindow::getBrowserRowSpan()
614 {
615         return mBrowserRowSpan;
616 }
617
618 ////////////////////////////////////////////////////////////////////////////////
619 //
620 PRBool LLEmbeddedBrowserWindow::navigateTo( const std::string uriIn )
621 {
622         if ( mWebNav )
623         {
624                 mWebNav->LoadURI( reinterpret_cast< const PRUnichar* >( NS_ConvertUTF8toUTF16( uriIn.c_str() ).get() ),
625                         nsIWebNavigation::LOAD_FLAGS_NONE,
626                                 nsnull, nsnull, nsnull );
627
628                 return PR_TRUE;
629         };
630
631         return PR_FALSE;
632 };
633
634 ////////////////////////////////////////////////////////////////////////////////
635 //
636 PRBool LLEmbeddedBrowserWindow::canNavigateBack()
637 {
638         if ( ! mWebNav )
639                 return PR_FALSE;
640
641         PRBool canGoBack = PR_FALSE;
642
643         nsresult result = mWebNav->GetCanGoBack( &canGoBack );
644         if ( NS_FAILED( result ) )
645         {
646                 return PR_FALSE;
647         };
648
649         return canGoBack;
650 };
651
652 ////////////////////////////////////////////////////////////////////////////////
653 //
654 void LLEmbeddedBrowserWindow::navigateStop()
655 {
656         if ( mWebNav )
657                 mWebNav->Stop( nsIWebNavigation::STOP_ALL );
658 };
659
660 ////////////////////////////////////////////////////////////////////////////////
661 //
662 void LLEmbeddedBrowserWindow::navigateBack()
663 {
664         if ( mWebNav )
665                 mWebNav->GoBack();
666 };
667
668 ////////////////////////////////////////////////////////////////////////////////
669 //
670 PRBool LLEmbeddedBrowserWindow::canNavigateForward()
671 {
672         if ( ! mWebNav )
673                 return PR_FALSE;
674
675         PRBool canGoForward = PR_FALSE;
676
677         nsresult result = mWebNav->GetCanGoForward( &canGoForward );
678         if ( NS_FAILED( result ) )
679         {
680                 return PR_FALSE;
681         };
682
683         return canGoForward;
684 };
685
686 ////////////////////////////////////////////////////////////////////////////////
687 //
688 void LLEmbeddedBrowserWindow::navigateForward()
689 {
690         if ( mWebNav )
691                 mWebNav->GoForward();
692 };
693
694 ////////////////////////////////////////////////////////////////////////////////
695 //
696 PRBool LLEmbeddedBrowserWindow::setSize( PRInt16 widthIn, PRInt16 heightIn )
697 {
698         if ( widthIn > 2048 )
699                 widthIn = 2048;
700
701         if ( heightIn > 2048 )
702                 heightIn = 2048;
703
704         if ( mBaseWindow )
705         {
706                 // if there is a buffer already, get rid of it (it will get created as required in grabWindow())
707                 if ( mPageBuffer )
708                 {
709                         delete[] mPageBuffer;
710                         mPageBuffer = NULL;
711                         mPageBufferSize = 0;
712                 };
713
714                 // record new size
715                 mBrowserWidth = widthIn;
716                 mBrowserHeight = heightIn;
717
718                 // On the Mac, these calls do strange things to the main viewer window, and they don't seem necessary in any case.
719 #if WIN32
720                 // this is the actual OS (on Win32) Window so it needs to be hidden
721                 mBaseWindow->SetVisibility( PR_FALSE );
722
723                 // move off screen (and in a place that makes the combobox hack work
724                 mBaseWindow->SetPosition( 8000, -6000 );
725 #endif
726
727                 // tell Mozilla about the new size
728                 mBaseWindow->SetSize( widthIn, heightIn, PR_FALSE );
729
730                 return PR_TRUE;
731         };
732
733         return PR_FALSE;
734 }
735
736 ////////////////////////////////////////////////////////////////////////////////
737 // higher level mouse event
738 void LLEmbeddedBrowserWindow::mouseDown( PRInt16 xPosIn, PRInt16 yPosIn )
739 {
740         const PRUint32 clickCount = 1;
741         sendMozillaMouseEvent( NS_MOUSE_LEFT_BUTTON_DOWN, xPosIn, yPosIn, clickCount );
742 }
743
744 ////////////////////////////////////////////////////////////////////////////////
745 // higher level mouse event
746 void LLEmbeddedBrowserWindow::mouseUp( PRInt16 xPosIn, PRInt16 yPosIn )
747 {
748         const PRUint32 clickCount = 1;
749         sendMozillaMouseEvent( NS_MOUSE_LEFT_BUTTON_UP, xPosIn, yPosIn, clickCount );
750 }
751
752 ////////////////////////////////////////////////////////////////////////////////
753 // higher level mouse event
754 void LLEmbeddedBrowserWindow::mouseMove( PRInt16 xPosIn, PRInt16 yPosIn )
755 {
756         const PRUint32 clickCount = 1;  // ignored?
757         sendMozillaMouseEvent( NS_MOUSE_MOVE, xPosIn, yPosIn, clickCount );
758 }
759
760 ////////////////////////////////////////////////////////////////////////////////
761 // higher level mouse event
762 void LLEmbeddedBrowserWindow::mouseLeftDoubleClick( PRInt16 xPosIn, PRInt16 yPosIn )
763 {
764         // Internally Mozilla represents double-click as a 2-count mouse down event.
765         // TODO: support triple-click
766         const PRUint32 clickCount = 2;
767         sendMozillaMouseEvent( NS_MOUSE_LEFT_BUTTON_DOWN, xPosIn, yPosIn, clickCount );
768 }
769
770 ////////////////////////////////////////////////////////////////////////////////
771 // utility methods to set an error message so something else can look at it
772 void LLEmbeddedBrowserWindow::scrollByLines( PRInt16 linesIn )
773 {
774         if ( mWebBrowser )
775         {
776                 nsCOMPtr< nsIDOMWindow > window;
777                 nsresult result = mWebBrowser->GetContentDOMWindow( getter_AddRefs( window ) );
778
779                 if ( ! NS_FAILED( result ) && window )
780                 {
781                         result = window->ScrollByLines( linesIn );
782                 };
783         };
784 }
785
786 ////////////////////////////////////////////////////////////////////////////////
787 // synthesizes a mouse event and sends into the embedded instance
788 //
789 // eventIn - NS_MOUSE_LEFT_BUTTON_DOWN, NS_MOUSE_LEFT_BUTTON_UP, etc.
790 // xPosIn, yPosIn - coordinates (in browser window space?)
791 // clickCountIn - use 1 for single click, 2 for double-click, etc.
792 PRBool LLEmbeddedBrowserWindow::sendMozillaMouseEvent( PRInt16 eventIn, PRInt16 xPosIn, PRInt16 yPosIn, PRUint32 clickCountIn )
793 {
794         nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
795         if ( ! docShell )
796                 return PR_FALSE;
797
798         nsCOMPtr< nsPresContext > presContext;
799         nsresult result = docShell->GetPresContext( getter_AddRefs( presContext ) );
800         if ( NS_FAILED( result ) || ( ! presContext ) )
801                 return PR_FALSE;
802
803         nsIViewManager* viewManager = presContext->GetViewManager();
804         if ( ! viewManager )
805                 return PR_FALSE;
806
807         nsIView* rootView;
808         result = viewManager->GetRootView( rootView );
809         if ( NS_FAILED( result ) || ( ! rootView ) )
810                 return PR_FALSE;
811
812         nsCOMPtr< nsIWidget > widget = rootView->GetWidget();
813         if ( ! widget )
814                 return PR_FALSE;
815
816         nsMouseEvent mouseEvent( PR_TRUE, eventIn, widget, nsMouseEvent::eReal );
817         mouseEvent.clickCount = clickCountIn;
818         mouseEvent.isShift = 0;
819         mouseEvent.isControl = 0;
820         mouseEvent.isAlt = 0;
821         mouseEvent.isMeta = 0;
822         mouseEvent.widget = widget;
823         mouseEvent.nativeMsg = nsnull;
824         mouseEvent.point.x = xPosIn;
825         mouseEvent.point.y = yPosIn;
826         mouseEvent.refPoint.x = xPosIn;
827         mouseEvent.refPoint.y = yPosIn;
828         mouseEvent.flags = 0;
829
830         nsEventStatus status;
831         result = viewManager->DispatchEvent( &mouseEvent, &status );
832         if ( NS_FAILED( result ) )
833                 return PR_FALSE;
834
835         return PR_TRUE;
836 };
837
838 ////////////////////////////////////////////////////////////////////////////////
839 // higher level keyboard functions
840
841 // accept a (mozilla-style) keycode
842 void LLEmbeddedBrowserWindow::keyPress( PRInt16 keyCode )
843 {
844         sendMozillaKeyboardEvent( 0, keyCode );
845 }
846
847 // accept keyboard input that's already been translated into a unicode char.
848 void LLEmbeddedBrowserWindow::unicodeInput( PRUint32 uni_char )
849 {
850         sendMozillaKeyboardEvent( uni_char, 0 );
851 }
852
853 ////////////////////////////////////////////////////////////////////////////////
854 // synthesizes a keyboard event and sends into the embedded instance
855 PRBool LLEmbeddedBrowserWindow::sendMozillaKeyboardEvent( PRUint32 uni_char, PRUint32 ns_vk_code )
856 {
857         nsresult result = NS_OK;
858
859         nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
860         if ( ! docShell )
861                 return PR_FALSE;
862
863         nsCOMPtr< nsPresContext > presContext;
864         docShell->GetPresContext( getter_AddRefs( presContext ) );
865         if ( ! presContext )
866                 return PR_FALSE;
867
868         nsIViewManager* viewManager = presContext->GetViewManager();
869         if ( ! viewManager )
870                 return PR_FALSE;
871
872         nsIView* rootView;
873         viewManager->GetRootView( rootView );
874         if ( ! rootView )
875                 return PR_FALSE;
876
877         nsCOMPtr< nsIWidget > widget = rootView->GetWidget();
878         if ( ! widget )
879                 return PR_FALSE;
880
881         nsKeyEvent keyEvent( PR_TRUE, NS_KEY_PRESS, widget );
882         keyEvent.keyCode = ns_vk_code;
883         keyEvent.charCode = uni_char;
884         keyEvent.isChar = uni_char ? PR_TRUE : PR_FALSE;
885         keyEvent.isShift = 0;
886         keyEvent.isControl = 0;
887         keyEvent.isAlt = 0;
888         keyEvent.isMeta = 0;
889         keyEvent.widget = widget;
890         keyEvent.nativeMsg = nsnull;
891         keyEvent.point.x = 0;
892         keyEvent.point.y = 0;
893         keyEvent.refPoint.x = 0;
894         keyEvent.refPoint.y = 0;
895         keyEvent.flags = 0;
896
897         nsEventStatus status;
898         result = viewManager->DispatchEvent( &keyEvent, &status );
899         if ( NS_FAILED( result ) )
900                 return PR_FALSE;
901
902         return PR_TRUE;
903 }
904
905 ////////////////////////////////////////////////////////////////////////////////
906 // all this just to render a caret!
907 PRBool LLEmbeddedBrowserWindow::renderCaret()
908 {
909         nsCOMPtr< nsIWebBrowserFocus > focus = do_QueryInterface( mWebBrowser );
910
911         nsCOMPtr< nsIDOMElement > focusedElement;
912         focus->GetFocusedElement( getter_AddRefs( focusedElement ) );
913         if ( ! focusedElement )
914                 return NS_ERROR_FAILURE;
915
916         nsCOMPtr<nsIContent> focusedContent = do_QueryInterface( focusedElement );
917
918         nsCOMPtr< nsIDOMWindow > domWindow;
919         mWebBrowser->GetContentDOMWindow( getter_AddRefs( domWindow ) );
920         if ( ! domWindow )
921                 return NS_ERROR_FAILURE;
922
923         nsCOMPtr< nsIDOMDocument > domDocument;
924         domWindow->GetDocument( getter_AddRefs( domDocument ) );
925         if ( ! domDocument )
926                 return NS_ERROR_FAILURE;
927
928         nsCOMPtr< nsIDocument> document = do_QueryInterface( domDocument );
929         if ( ! document )
930                 return NS_ERROR_FAILURE;
931
932         nsIPresShell* presShell = document->GetShellAt( 0 );
933         if ( ! presShell )
934                 return NS_ERROR_FAILURE;
935
936         nsCOMPtr< nsICaret > caret;
937         presShell->GetCaret( getter_AddRefs( caret ) );
938
939         nsIFrame* frame = nsnull;
940         presShell->GetPrimaryFrameFor( focusedContent, &frame );
941         if ( ! frame )
942                 return NS_ERROR_FAILURE;
943
944         nsCOMPtr<nsISelectionController> selCtrl;
945         frame->GetSelectionController( presShell->GetPresContext(), getter_AddRefs( selCtrl ) );
946
947         nsCOMPtr<nsISelection> selection;
948         selCtrl->GetSelection( nsISelectionController::SELECTION_NORMAL, getter_AddRefs( selection ) );
949
950         PRBool collapsed;
951         nsRect coords;
952         nsIView* caretView;
953         caret->GetCaretCoordinates( nsICaret::eTopLevelWindowCoordinates, selection, &coords, &collapsed, &caretView );
954
955         float twips2Pixls = presShell->GetPresContext()->TwipsToPixels();
956
957         PRInt32 caretX = NSTwipsToIntPixels( coords.x, twips2Pixls );
958         PRInt32 caretY = NSTwipsToIntPixels( coords.y, twips2Pixls );
959         PRInt32 caretHeight = NSTwipsToIntPixels( coords.height, twips2Pixls );
960
961         if ( caretX > -1 && caretX < mBrowserWidth && caretY > -1 && caretY < mBrowserHeight )
962         {
963                 if ( mPageBuffer )
964                 {
965                         for( int y = 1; y < caretHeight - 1; ++y )
966                         {
967                                 // sometimes the caret seems valid when it really isn't - cap it to size of screen
968                                 if ( caretY + y + caretHeight < mBrowserHeight )
969                                 {
970                                         mPageBuffer[ ( caretY + y ) * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 0 ] = mCaretBlue;
971                                         mPageBuffer[ ( caretY + y ) * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 1 ] = mCaretGreen;
972                                         mPageBuffer[ ( caretY + y ) * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 2 ] = mCaretRed;
973                                 };
974                         };
975                 };
976         };
977
978         return NS_OK;
979 }
980
981 ////////////////////////////////////////////////////////////////////////////////
982 //
983 void LLEmbeddedBrowserWindow::setBackgroundColor( PRUint8 redIn, PRUint8 greenIn, PRUint8 blueIn )
984 {
985         mBackgroundRed = redIn;
986         mBackgroundGreen = greenIn;
987         mBackgroundBlue = blueIn;
988 }
989
990 ////////////////////////////////////////////////////////////////////////////////
991 // change the caret color (we have different backgrounds to edit fields - black caret on black background == bad)
992 void LLEmbeddedBrowserWindow::setCaretColor( const PRUint8 redIn, const PRUint8 greenIn, const PRUint8 blueIn )
993 {
994         mCaretRed = redIn;
995         mCaretGreen = greenIn;
996         mCaretBlue = blueIn;
997 }
998
999 ////////////////////////////////////////////////////////////////////////////////
1000 // override nsIWebBrowserChrome::HandleEvent ()
1001 NS_IMETHODIMP LLEmbeddedBrowserWindow::HandleEvent( nsIDOMEvent* anEvent )
1002 {
1003         nsCOMPtr< nsIDOMEventTarget > eventTarget;
1004         anEvent->GetTarget( getter_AddRefs( eventTarget ) );
1005
1006         nsCOMPtr<nsIDOMElement> linkElement ( do_QueryInterface ( eventTarget ) );
1007         if ( linkElement )
1008         {
1009                 nsString name;
1010                 linkElement->GetAttribute( NS_ConvertUTF8toUTF16( "href" ), name );
1011                 mClickHref = std::string( NS_ConvertUTF16toUTF8( name ).get() );
1012
1013                 LLEmbeddedBrowserWindowEvent event( getWindowId(), mClickHref );
1014                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onClickLinkHref, event );
1015         };
1016
1017         return NS_OK;
1018 };
1019
1020 ////////////////////////////////////////////////////////////////////////////////
1021 // override nsIURIContentListener methods
1022 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnStartURIOpen( nsIURI *aURI, PRBool *_retval )
1023 {
1024         nsCAutoString newURI;
1025         aURI->GetSpec( newURI );
1026         std::string rawUri = newURI.get();
1027
1028         if ( rawUri.substr( 0, std::string( "secondlife://" ).length() ) == "secondlife://" )
1029         {
1030                 LLEmbeddedBrowserWindowEvent event( getWindowId(), rawUri );
1031                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onClickLinkSecondLife, event );
1032
1033                 // tell browser we're handling things and don't follow link
1034                 *_retval = PR_TRUE;
1035         }
1036         else
1037         {
1038                 // tell browser to proceed as normal
1039                 *_retval = PR_FALSE;
1040         };
1041
1042         return NS_OK;
1043 }
1044
1045 ////////////////////////////////////////////////////////////////////////////////
1046 //
1047 NS_IMETHODIMP LLEmbeddedBrowserWindow::DoContent( const char *aContentType,
1048                                                                                                         PRBool aIsContentPreferred,
1049                                                                                                                 nsIRequest *aRequest,
1050                                                                                                                         nsIStreamListener **aContentHandler,
1051                                                                                                                                 PRBool *_retval )
1052 {
1053         return NS_ERROR_NOT_IMPLEMENTED;
1054 }
1055
1056 ////////////////////////////////////////////////////////////////////////////////
1057 //
1058 NS_IMETHODIMP LLEmbeddedBrowserWindow::IsPreferred( const char *aContentType,
1059                                                                                                                 char **aDesiredContentType,
1060                                                                                                                         PRBool *_retval )
1061 {
1062         // important (otherwise, links try to open in a new window and trigger the window watcher code)
1063         *_retval = PR_TRUE;
1064         return NS_OK;
1065 }
1066
1067 ////////////////////////////////////////////////////////////////////////////////
1068 //
1069 NS_IMETHODIMP LLEmbeddedBrowserWindow::CanHandleContent( const char *aContentType,
1070                                                                                                                         PRBool aIsContentPreferred,
1071                                                                                                                                 char **aDesiredContentType,
1072                                                                                                                                         PRBool *_retval )
1073 {
1074         return NS_ERROR_NOT_IMPLEMENTED;
1075 }
1076
1077 ////////////////////////////////////////////////////////////////////////////////
1078 //
1079 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetLoadCookie( nsISupports * *aLoadCookie )
1080 {
1081         return NS_ERROR_NOT_IMPLEMENTED;
1082 }
1083
1084 ////////////////////////////////////////////////////////////////////////////////
1085 //
1086 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetLoadCookie( nsISupports * aLoadCookie )
1087 {
1088         return NS_ERROR_NOT_IMPLEMENTED;
1089 }
1090
1091 ////////////////////////////////////////////////////////////////////////////////
1092 //
1093 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetParentContentListener( nsIURIContentListener** aParentContentListener )
1094 {
1095         return NS_ERROR_NOT_IMPLEMENTED;
1096 }
1097
1098 ////////////////////////////////////////////////////////////////////////////////
1099 //
1100 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetParentContentListener( nsIURIContentListener* aParentContentListener )
1101 {
1102         return NS_ERROR_NOT_IMPLEMENTED;
1103 }
1104
1105 ////////////////////////////////////////////////////////////////////////////////
1106 // give focus to the browser so that input keyboard events work
1107 void LLEmbeddedBrowserWindow::focusBrowser( PRBool focusBrowserIn )
1108 {
1109         if ( focusBrowserIn )
1110         {
1111                 nsCOMPtr< nsIWebBrowserFocus > focus( do_GetInterface( mWebBrowser ) );
1112                 focus->Activate();
1113         }
1114         else
1115         {
1116                 nsCOMPtr< nsIWebBrowserFocus > focus( do_GetInterface( mWebBrowser ) );
1117                 focus->Deactivate();
1118         };
1119 }
1120
1121 ////////////////////////////////////////////////////////////////////////////////
1122 //
1123 void LLEmbeddedBrowserWindow::setWindowId( int windowIdIn )
1124 {
1125         mWindowId = windowIdIn;
1126 }
1127
1128 ////////////////////////////////////////////////////////////////////////////////
1129 //
1130 int LLEmbeddedBrowserWindow::getWindowId()
1131 {
1132         return mWindowId;
1133 }
1134
1135 ////////////////////////////////////////////////////////////////////////////////
1136 //
1137 bool LLEmbeddedBrowserWindow::set404RedirectUrl( std::string redirect_url )
1138 {
1139         m404RedirectUrl = redirect_url;
1140
1141         return true;
1142 }
1143
1144 ////////////////////////////////////////////////////////////////////////////////
1145 //
1146 bool LLEmbeddedBrowserWindow::clr404RedirectUrl()
1147 {
1148         m404RedirectUrl = std::string( "" );
1149
1150         return true;
1151 }
1152
1153 // #define required by this file for LibXUL/Mozilla code to avoid crashes in their debug code
1154 #ifdef _DEBUG
1155         #ifdef WIN32
1156                 #undef DEBUG
1157         #endif
1158 #endif
Note: See TracBrowser for help on using the browser.