root/trunk/llmozlib2/llembeddedbrowserwindow.cpp

Revision 20, 42.8 kB (checked in by callum.linden, 1 year ago)

Fix for DEV-21419 (Caret doesn't always appear in edit fields on Windows)
Reviewed by: Andrew Cheah

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is Linden Lab Inc. (http://lindenlab.com) code.
15  *
16  * The Initial Developer of the Original Code is:
17  *   Callum Prentice (callum@ubrowser.com)
18  *
19  * Portions created by the Initial Developer are Copyright (C) 2006
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *  Callum Prentice (callum@ubrowser.com)
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either the GNU General Public License Version 2 or later (the "GPL"), or
27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK ***** */
38
39 // seems to be required by LibXUL/Mozilla code to avoid crashes in their debug code, but only on Windows.
40 // undef'd at end of this
41 #ifdef _DEBUG
42         #ifdef WIN32
43                 #define DEBUG 1
44         #endif
45 #endif
46
47 // needed for the code in LLEmbeddedBrowserWindow::NotifyInvalidated() which will
48 // one day be moved to platform agnostic code when I find out how...
49 #ifdef WIN32
50 #include "windows.h"
51 #endif
52
53 #include "llembeddedbrowser.h"
54 #include "llembeddedbrowserwindow.h"
55
56 // Mozilla code has non-virtual destructors
57 #ifdef WIN32
58 #pragma warning( disable : 4291 ) // (no matching operator delete found; memory will not be freed if initialization throws an exception)
59 #pragma warning( disable : 4265 ) // "class has virtual functions, but destructor is not virtual"
60 #endif
61
62 #include "nsCWebBrowser.h"
63 #include "nsGUIEvent.h"
64 #include "nsICaret.h"
65 #include "nsIContent.h"
66 #include "nsIDOMDocument.h"
67 #include "nsIDOMElement.h"
68 #include "nsIDOMWindow.h"
69 #include "nsIDOMEvent.h"
70 #include "nsIDocShell.h"
71 #include "nsIDocShellTreeItem.h"
72 #include "nsIDocument.h"
73 #include "nsIFrame.h"
74 #include "nsIHttpChannel.h"
75 #include "nsIInterfaceRequestorUtils.h"
76 #include "nsIScrollableView.h"
77 #include "nsISelection.h"
78 #include "nsISelectionController.h"
79 #include "nsIWebBrowserChrome.h"
80 #include "nsIWebBrowserChromeFocus.h"
81 #include "nsIWebBrowserFocus.h"
82 #include "nsIWebProgress.h"
83 #include "nsIWebProgressListener.h"
84 #include "nsPresContext.h"
85 #include "nsProfileDirServiceProvider.h"
86 #include "nsXPCOMGlue.h"
87 #include "nsXULAppAPI.h"
88
89 #include "llembeddedbrowserwindow.h"
90
91 #include <iostream>
92
93 #ifdef WIN32
94 #pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual"
95 #endif
96
97 ////////////////////////////////////////////////////////////////////////////////
98 //
99 LLEmbeddedBrowserWindow::LLEmbeddedBrowserWindow() :
100         mParent( 0 ),
101         mWebBrowser( nsnull ),
102         mBaseWindow( nsnull ),
103         mWindowId( 0 ),
104         mPercentComplete( 0 ),
105         mBrowserWidth( 0 ),
106         mBrowserHeight( 0 ),
107         mBrowserDepth( 4 ),
108         mPageBuffer( 0 ),
109         mEnabled( true ),
110         mCurrentUri( "" ),
111         mStatusText( "" ),
112         mClickHref( "" ),
113         mClickTarget( "" ),
114         mNoFollowScheme( "secondlife://" ),
115         mBkgRed( 0xff ),
116         mBkgGreen( 0xff ),
117         mBkgBlue( 0xff ),
118         mCaretRed( 0x00 ),
119         mCaretGreen( 0x00 ),
120         mCaretBlue( 0x00 ),
121         m404RedirectUrl( "" ),
122         mFlipBitmap( false )
123 {
124 }
125
126 ////////////////////////////////////////////////////////////////////////////////
127 //
128 LLEmbeddedBrowserWindow::~LLEmbeddedBrowserWindow()
129 {
130         if ( mWebNav )
131         {
132                 mWebNav->Stop ( nsIWebNavigation::STOP_ALL );
133                 mWebNav = nsnull;
134         };
135
136         if ( mBaseWindow )
137         {
138                 mBaseWindow->Destroy();
139                 mBaseWindow = nsnull;
140         };
141
142         if ( mPageBuffer )
143         {
144                 delete[] mPageBuffer;
145                 mPageBuffer = 0;
146         };
147 }
148
149 ////////////////////////////////////////////////////////////////////////////////
150 //
151 nsresult LLEmbeddedBrowserWindow::createBrowser( void* nativeWindowHandleIn, PRInt32 widthIn, PRInt32 heightIn, nsIWebBrowser **aBrowser )
152 {
153         NS_ENSURE_ARG_POINTER(aBrowser);
154         *aBrowser = nsnull;
155
156         nsresult rv;
157         mWebBrowser = do_CreateInstance( NS_WEBBROWSER_CONTRACTID, &rv );
158         if ( ! mWebBrowser )
159         {
160                 return NS_ERROR_FAILURE;
161         }
162
163     (void)mWebBrowser->SetContainerWindow( NS_STATIC_CAST( nsIWebBrowserChrome*, this ) );
164
165     nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface( mWebBrowser );
166     dsti->SetItemType( nsIDocShellTreeItem::typeContentWrapper );
167
168     mBaseWindow = do_QueryInterface( mWebBrowser );
169
170     mBaseWindow->InitWindow( nativeWindowHandleIn, nsnull,  0, 0, mBrowserWidth, mBrowserHeight );
171     mBaseWindow->Create();
172
173     nsCOMPtr< nsIWebProgressListener > listener( NS_STATIC_CAST( nsIWebProgressListener*, this ) );
174     nsCOMPtr< nsIWeakReference > thisListener( do_GetWeakReference( listener ) );
175     mWebBrowser->AddWebBrowserListener( thisListener, NS_GET_IID( nsIWebProgressListener ) );
176
177 #if LL_DARWIN
178         // Without this, the mac doesn't get upates for animating gifs, mouseovers, etc.
179         mBaseWindow->SetVisibility( PR_TRUE );
180 #else
181         mBaseWindow->SetVisibility( PR_FALSE );
182 #endif
183
184         nsresult result;
185         mWebNav = do_QueryInterface( mWebBrowser, &result );
186         if ( NS_FAILED( result ) || ! mWebNav )
187         {
188                 return NS_ERROR_FAILURE;
189         };
190
191         setSize( widthIn, heightIn );
192
193     if ( mWebBrowser )
194     {
195                 *aBrowser = mWebBrowser;
196                 NS_ADDREF( *aBrowser );
197
198                 return NS_OK;
199     };
200
201     return NS_ERROR_FAILURE;
202 }
203
204 ////////////////////////////////////////////////////////////////////////////////
205 //
206 NS_IMPL_ADDREF( LLEmbeddedBrowserWindow )
207 NS_IMPL_RELEASE( LLEmbeddedBrowserWindow )
208
209 ////////////////////////////////////////////////////////////////////////////////
210 //
211 NS_INTERFACE_MAP_BEGIN( LLEmbeddedBrowserWindow )
212         NS_INTERFACE_MAP_ENTRY_AMBIGUOUS( nsISupports, nsIWebBrowserChrome )
213         NS_INTERFACE_MAP_ENTRY( nsIInterfaceRequestor )
214         NS_INTERFACE_MAP_ENTRY( nsIWebBrowserChrome )
215         NS_INTERFACE_MAP_ENTRY( nsIWebProgressListener )
216         NS_INTERFACE_MAP_ENTRY( nsIURIContentListener )
217         NS_INTERFACE_MAP_ENTRY( nsISupportsWeakReference )
218         NS_INTERFACE_MAP_ENTRY( nsIToolkitObserver )
219 NS_INTERFACE_MAP_END
220
221 ////////////////////////////////////////////////////////////////////////////////
222 //
223 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetInterface( const nsIID &aIID, void** aInstancePtr )
224 {
225         if ( aIID.Equals( NS_GET_IID( nsIDOMWindow ) ) )
226         {
227                 if ( mWebBrowser )
228                 {
229                         return mWebBrowser->GetContentDOMWindow( ( nsIDOMWindow** )aInstancePtr );
230                 };
231
232                 return NS_ERROR_NOT_INITIALIZED;
233         };
234
235         return QueryInterface( aIID, aInstancePtr );
236 }
237
238 ////////////////////////////////////////////////////////////////////////////////
239 // called when something changes the status text - emits event to consumer
240 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetStatus( PRUint32 aType, const PRUnichar* aStatus )
241 {
242         mStatusText = std::string( NS_ConvertUTF16toUTF8( aStatus ).get() );
243
244         LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), mStatusText );
245         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onStatusTextChange, event );
246
247         return NS_OK;
248 }
249
250 ////////////////////////////////////////////////////////////////////////////////
251 //
252 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetWebBrowser( nsIWebBrowser** aWebBrowser )
253 {
254         NS_ENSURE_ARG_POINTER( aWebBrowser );
255
256         *aWebBrowser = mWebBrowser;
257
258         NS_IF_ADDREF( *aWebBrowser );
259
260         return NS_OK;
261 }
262
263 ////////////////////////////////////////////////////////////////////////////////
264 //
265 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetWebBrowser( nsIWebBrowser* aWebBrowser )
266 {
267         NS_ENSURE_ARG_POINTER( aWebBrowser );
268
269         mWebBrowser = aWebBrowser;
270
271         return NS_OK;
272 }
273
274 ////////////////////////////////////////////////////////////////////////////////
275 //
276 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetChromeFlags( PRUint32* aChromeMask )
277 {
278         return NS_ERROR_NOT_IMPLEMENTED;
279 }
280
281 ////////////////////////////////////////////////////////////////////////////////
282 //
283 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetChromeFlags( PRUint32 aChromeMask )
284 {
285         return NS_ERROR_NOT_IMPLEMENTED;
286 }
287
288 ////////////////////////////////////////////////////////////////////////////////
289 //
290 NS_IMETHODIMP LLEmbeddedBrowserWindow::DestroyBrowserWindow()
291 {
292         return NS_OK;
293 }
294
295 ////////////////////////////////////////////////////////////////////////////////
296 //
297 NS_IMETHODIMP LLEmbeddedBrowserWindow::SizeBrowserTo( PRInt32 aCX, PRInt32 aCY )
298 {
299         return NS_OK;
300 }
301
302 ////////////////////////////////////////////////////////////////////////////////
303 //
304 NS_IMETHODIMP LLEmbeddedBrowserWindow::ShowAsModal()
305 {
306         return NS_ERROR_NOT_IMPLEMENTED;
307 }
308
309 ////////////////////////////////////////////////////////////////////////////////
310 //
311 //
312 NS_IMETHODIMP LLEmbeddedBrowserWindow::IsWindowModal( PRBool* retval )
313 {
314         *retval = PR_FALSE;
315
316         return NS_OK;
317 }
318
319 ////////////////////////////////////////////////////////////////////////////////
320 //
321 NS_IMETHODIMP LLEmbeddedBrowserWindow::ExitModalEventLoop( nsresult aStatus )
322 {
323         return NS_OK;
324 }
325
326 ////////////////////////////////////////////////////////////////////////////////
327 // called when the page loading progress changes - emits event to consumer
328 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnProgressChange( nsIWebProgress* progress, nsIRequest* request,
329                                                                                                         PRInt32 curSelfProgress, PRInt32 maxSelfProgress,
330                                                                                                                 PRInt32 curTotalProgress, PRInt32 maxTotalProgress )
331 {
332         mPercentComplete = static_cast< PRInt16 >
333                 ( static_cast< float >( curTotalProgress * 100.0f ) / static_cast< float >( maxTotalProgress ) );
334
335         if ( mPercentComplete < 0 )
336                 mPercentComplete = 0;
337
338         if ( mPercentComplete > 100 )
339                 mPercentComplete = 100;
340
341         LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), mPercentComplete );
342         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onUpdateProgress, event );
343
344         return NS_OK;
345 }
346
347 ////////////////////////////////////////////////////////////////////////////////
348 // called when the browser state changes - as described below - emits event to consumer
349 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnStateChange( nsIWebProgress* progress, nsIRequest* request,
350                                                                                                         PRUint32 progressStateFlags, nsresult status )
351 {
352         if ( ( progressStateFlags & STATE_START ) && ( progressStateFlags & STATE_IS_DOCUMENT ) && ( status == NS_OK ) )
353         {
354                 // TODO: move this to a better place.
355                 enableToolkitObserver( false );
356                 enableToolkitObserver( true );
357
358                 // page load is starting so remove listener that catches "click" events
359                 nsCOMPtr< nsIDOMWindow > window;
360                 nsresult result = progress->GetDOMWindow( getter_AddRefs( window ) );
361                 if ( result == NS_OK )
362                 {
363                         nsCOMPtr< nsIDOMEventTarget > target = do_QueryInterface( window );
364                         if ( target )
365                                 target->RemoveEventListener(NS_ConvertUTF8toUTF16( "click" ), this, PR_TRUE );
366                 };
367
368                 // set the listener to we can catch nsURIContentListener events
369                 if ( mWebBrowser )
370                 {
371                         mWebBrowser->SetParentURIContentListener( NS_STATIC_CAST( nsIURIContentListener*, this ) );
372                 };
373
374                 // emit event that navigation is beginning
375                 mStatusText = std::string( "Browser loaded" );
376                 LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), mStatusText );
377                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onNavigateBegin, event );
378
379                 // about to move to a different page so have to stop grabbing a page
380                 // but done one final grab in case the app doesn't ever call grabWindow again
381                 grabWindow( 0, 0, mBrowserWidth, mBrowserHeight );
382         };
383
384         if ( ( progressStateFlags & STATE_STOP ) && ( progressStateFlags & STATE_IS_WINDOW ) && ( status == NS_OK ) )
385         {
386                 // page load is complete so add listener that catches "click" events
387                 nsCOMPtr< nsIDOMWindow > window;
388                 nsresult result = progress->GetDOMWindow( getter_AddRefs( window ) );
389                 if ( result == NS_OK )
390                 {
391                         nsCOMPtr< nsIDOMEventTarget > target = do_QueryInterface( window );
392                         if ( target )
393                                 target->AddEventListener(NS_ConvertUTF8toUTF16( "click" ), this, PR_TRUE );
394                 };
395
396                 // pick up raw HTML response status code
397                 PRUint32 responseStatus = 0;
398                 if ( request )
399                 {
400                         nsCOMPtr< nsIHttpChannel > httpChannel = do_QueryInterface( request );
401                         if ( httpChannel )
402                         {
403                                 httpChannel->GetResponseStatus( &responseStatus );
404                         };
405                 };
406
407                 // emit event that navigation is finished
408                 mStatusText = std::string( "Done" );
409                 LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), mStatusText, (int)responseStatus );
410                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onNavigateComplete, event );
411
412                 // also set the flag here since back/forward navigation doesn't call progress change
413                 grabWindow( 0, 0, mBrowserWidth, mBrowserHeight );
414         };
415
416         if ( progressStateFlags & STATE_REDIRECTING )
417         {
418                 mStatusText = std::string( "Redirecting..." );
419         };
420
421         if ( progressStateFlags & STATE_TRANSFERRING )
422         {
423                 mStatusText = std::string( "Transferring..." );
424         };
425
426         if ( progressStateFlags & STATE_NEGOTIATING )
427         {
428                 mStatusText = std::string( "Negotiating..." );
429         };
430
431         LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), mStatusText );
432         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onStatusTextChange, event );
433
434         return NS_OK;
435 }
436
437 ////////////////////////////////////////////////////////////////////////////////
438 // call when the location changes - e.g. when a site redirects - emits event to consumer
439 // TODO: ought to check that this change is on the top frame and
440 // indicate this to the consumer of this class
441 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnLocationChange( nsIWebProgress* webProgress,
442                                                                                                                 nsIRequest* request,
443                                                                                                                         nsIURI* location )
444 {
445         if ( request )
446         {
447                 nsCOMPtr< nsIHttpChannel > http_channel = do_QueryInterface( request );
448                 if ( http_channel )
449                 {
450                         PRUint32 response_status = 0;
451                         http_channel->GetResponseStatus( &response_status );
452
453                         if ( response_status == 404 )
454                         {
455                                 if ( ! m404RedirectUrl.empty() )
456                                 {
457                                         if ( mWebNav )
458                                         {
459                                                 mWebNav->LoadURI( reinterpret_cast< const PRUnichar* >
460                                                         ( NS_ConvertUTF8toUTF16( m404RedirectUrl.c_str() ).get() ),
461                                                                 nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY,
462                                                                         nsnull, nsnull, nsnull );
463                                         };
464                                 };
465                         };
466                 };
467         };
468
469         nsCAutoString newURI;
470         location->GetSpec( newURI );
471
472         mCurrentUri = newURI.get();
473
474         LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri() );
475         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onLocationChange, event );
476
477         return NS_OK;
478 }
479
480 ////////////////////////////////////////////////////////////////////////////////
481 // change the background color that gets used between pages (usually white)
482 void LLEmbeddedBrowserWindow::setBackgroundColor( const PRUint8 redIn, const PRUint8 greenIn, const PRUint8 blueIn )
483 {
484         mBkgRed = redIn;
485         mBkgGreen = greenIn;
486         mBkgBlue = blueIn;
487 }
488
489 ////////////////////////////////////////////////////////////////////////////////
490 // change the caret color (we have different backgrounds to edit fields - black caret on black background == bad)
491 void LLEmbeddedBrowserWindow::setCaretColor( const PRUint8 redIn, const PRUint8 greenIn, const PRUint8 blueIn )
492 {
493         mCaretRed = redIn;
494         mCaretGreen = greenIn;
495         mCaretBlue = blueIn;
496 }
497
498 ////////////////////////////////////////////////////////////////////////////////
499 //
500 void LLEmbeddedBrowserWindow::setEnabled( PRBool enabledIn )
501 {
502         mEnabled = enabledIn;
503 }
504
505 ////////////////////////////////////////////////////////////////////////////////
506 // allow consumers of this class to observe events - add themselves as an observer
507 bool LLEmbeddedBrowserWindow::addObserver( LLEmbeddedBrowserWindowObserver* observerIn )
508 {
509         return mEventEmitter.addObserver( observerIn );
510 }
511
512 ////////////////////////////////////////////////////////////////////////////////
513 // allow consumers of this class to observe events - remove themselves as an observer
514 bool LLEmbeddedBrowserWindow::remObserver( LLEmbeddedBrowserWindowObserver* observerIn )
515 {
516         return mEventEmitter.remObserver( observerIn );
517 }
518
519 ////////////////////////////////////////////////////////////////////////////////
520 // used by observers of this class to get the current URI
521 const std::string& LLEmbeddedBrowserWindow::getCurrentUri()
522 {
523         return mCurrentUri;
524 }
525
526 ////////////////////////////////////////////////////////////////////////////////
527 // utility method that is used by observers to retrieve data after an event
528 const PRInt16 LLEmbeddedBrowserWindow::getPercentComplete()
529 {
530         return mPercentComplete;
531 }
532
533 ////////////////////////////////////////////////////////////////////////////////
534 // utility method that is used by observers to retrieve data after an event
535 const std::string& LLEmbeddedBrowserWindow::getStatusMsg()
536 {
537         return mStatusText;
538 }
539
540 ////////////////////////////////////////////////////////////////////////////////
541 // utility method that is used by observers to retrieve data after an event
542 const std::string& LLEmbeddedBrowserWindow::getClickLinkHref()
543 {
544         return mClickHref;
545 }
546
547 ////////////////////////////////////////////////////////////////////////////////
548 // utility method that is used by observers to retrieve data after an event
549 const std::string& LLEmbeddedBrowserWindow::getClickLinkTarget()
550 {
551         return mClickTarget;
552 }
553
554 ////////////////////////////////////////////////////////////////////////////////
555 // called when the status text is changed - emits event to consumer
556 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnStatusChange( nsIWebProgress* aWebProgress,
557                                                                                                                 nsIRequest* aRequest,
558                                                                                                                         nsresult aStatus,
559                                                                                                                                 const PRUnichar* aMessage )
560 {
561         mStatusText = std::string( NS_ConvertUTF16toUTF8( aMessage ).get() );
562
563         LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), mStatusText );
564         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onStatusTextChange, event );
565
566         return NS_OK;
567 }
568
569 ////////////////////////////////////////////////////////////////////////////////
570 // implement this if you want to do something when the security state changtes
571 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnSecurityChange( nsIWebProgress* aWebProgress,
572                                                                                                         nsIRequest* aRequest,
573                                                                                                                 PRUint32 state )
574 {
575         return NS_OK;
576 }
577
578 ////////////////////////////////////////////////////////////////////////////////
579 // render a page into memory and grab the window
580 // TODO: 0,0, browser width, browser height is always passed in right now
581 //       need to make this work with arbitrary rects (i.e. the dirty rect)
582 unsigned char* LLEmbeddedBrowserWindow::grabWindow( int xIn, int yIn, int widthIn, int heightIn )
583 {
584         // sanity check
585         if ( ! mWebBrowser )
586                 return 0;
587
588         // only grab the window if it's enabled
589         if ( ! mEnabled )
590                 return false;
591
592         // get the docshell
593         nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
594         if ( ! docShell )
595                 return PR_FALSE;
596
597
598         // get pres context
599         nsCOMPtr< nsPresContext > presContext;
600         nsresult result = docShell->GetPresContext( getter_AddRefs( presContext ) );
601         if ( NS_FAILED( result ) || ( ! presContext ) )
602                 return PR_FALSE;
603
604         // get view manager
605         nsIViewManager* viewManager = presContext->GetViewManager();
606         if ( ! viewManager )
607                 return PR_FALSE;
608
609         // get the view
610         nsIScrollableView* scrollableView = NULL;
611         viewManager->GetRootScrollableView( &scrollableView );
612         nsIView* view = NULL;
613         if ( scrollableView )
614                 scrollableView->GetScrolledView( view );
615         else
616                 viewManager->GetRootView( view );
617
618         // get the rectangle we want to render in twips (this looks odd but takees care of scrolling too)
619         nsRect rect = view->GetBounds() - view->GetPosition() - view->GetPosition();
620         if ( rect.IsEmpty() )
621                 return 0;
622
623         float p2t = presContext->PixelsToTwips();
624         rect.width = NSIntPixelsToTwips( widthIn, p2t );
625         rect.height = NSIntPixelsToTwips( heightIn, p2t );
626
627         // render the page
628         nsCOMPtr< nsIRenderingContext > context;
629         result = viewManager->RenderOffscreen( view, rect, PR_FALSE, PR_FALSE, NS_RGB( mBkgRed, mBkgGreen, mBkgBlue  ), getter_AddRefs( context ) );
630         if ( NS_FAILED( result ) )
631                 return 0;
632
633         // retrieve the surface we rendered to
634         nsIDrawingSurface* surface = nsnull;
635         context->GetDrawingSurface( &surface );
636         if ( ! surface )
637                 return 0;
638
639         // lock the surface and retrieve a pointer to the rendered data and current row span
640         PRUint8* data;
641         PRInt32 rowLen;
642         // sometime rowspan ! width in pixels * bytes per pixel so save row span value and use in application
643         result = surface->Lock( xIn, yIn, widthIn, heightIn, reinterpret_cast< void** >( &data ), &mBrowserRowSpan, &rowLen, NS_LOCK_SURFACE_READ_ONLY );
644         if ( NS_FAILED ( result ) )
645                 return 0;
646
647         // save row span - it *can* change during the life of the app
648         mBrowserDepth = rowLen / mBrowserWidth;
649
650         // create memory buffer here so it can be deleted and recreated elsewhere
651         if ( ! mPageBuffer )
652                 mPageBuffer = new unsigned char[ mBrowserRowSpan * mBrowserHeight ];
653
654         // save the pixels and optionally invert them
655         // (it's useful the SL client to get bitmaps that are inverted compared
656         // to the way that Mozilla renders them - allow to optionally flip
657         if ( mFlipBitmap )
658         {
659                 for( int y = mBrowserHeight - 1; y > -1; --y )
660                 {
661                         memcpy( mPageBuffer + y * mBrowserRowSpan,
662                                                 data + ( mBrowserHeight - y - 1 ) * mBrowserRowSpan,
663                                                         mBrowserRowSpan );
664                 };
665         }
666         else
667         {
668                 memcpy( mPageBuffer, data, mBrowserRowSpan * mBrowserHeight );
669         };
670
671         // release and destroy the surface we rendered to
672         surface->Unlock();
673         context->DestroyDrawingSurface( surface );
674
675         renderCaret();
676
677         return mPageBuffer;
678 }
679
680 ////////////////////////////////////////////////////////////////////////////////
681 // all this just to render a caret!
682 PRBool LLEmbeddedBrowserWindow::renderCaret()
683 {
684         nsCOMPtr< nsIWebBrowserFocus > focus = do_QueryInterface( mWebBrowser );
685         if ( ! focus )
686                 return NS_ERROR_FAILURE;
687
688         nsCOMPtr< nsIDOMElement > focusedElement;
689         focus->GetFocusedElement( getter_AddRefs( focusedElement ) );
690         if ( ! focusedElement )
691                 return NS_ERROR_FAILURE;
692
693         nsCOMPtr<nsIContent> focusedContent = do_QueryInterface( focusedElement );
694         if ( ! focusedContent )
695                 return NS_ERROR_FAILURE;
696
697         nsIPresShell* presShell = focusedContent->GetCurrentDoc()->GetShellAt( 0 );
698         if ( ! presShell )
699                 return NS_ERROR_FAILURE;
700
701         nsCOMPtr< nsICaret > caret;
702         presShell->GetCaret( getter_AddRefs( caret ) );
703         if ( ! caret )
704                 return NS_ERROR_FAILURE;
705
706         nsIFrame* frame = nsnull;
707         presShell->GetPrimaryFrameFor( focusedContent, &frame );
708         if ( ! frame )
709                 return NS_ERROR_FAILURE;
710
711         nsCOMPtr<nsISelectionController> selCtrl;
712         frame->GetSelectionController( presShell->GetPresContext(), getter_AddRefs( selCtrl ) );
713         if ( ! selCtrl )
714                 return NS_ERROR_FAILURE;
715
716         nsCOMPtr<nsISelection> selection;
717         selCtrl->GetSelection( nsISelectionController::SELECTION_NORMAL, getter_AddRefs( selection ) );
718         if ( ! selection )
719                 return NS_ERROR_FAILURE;
720
721         PRBool collapsed;
722         nsRect coords;
723         nsIView* caretView;
724         caret->GetCaretCoordinates( nsICaret::eTopLevelWindowCoordinates, selection, &coords, &collapsed, &caretView );
725         if ( ! caretView )
726                 return NS_ERROR_FAILURE;
727
728         float twips2Pixls = presShell->GetPresContext()->TwipsToPixels();
729
730         PRInt32 caretX = NSTwipsToIntPixels( coords.x, twips2Pixls );
731         PRInt32 caretY = NSTwipsToIntPixels( coords.y, twips2Pixls );
732         PRInt32 caretHeight = NSTwipsToIntPixels( coords.height, twips2Pixls );
733
734         if ( caretX > -1 && caretX < mBrowserWidth && caretY > -1 && caretY < mBrowserHeight )
735         {
736                 if ( mPageBuffer )
737                 {
738                         for( int y = 1; y < caretHeight - 1; ++y )
739                         {
740                                 PRInt32 base_pos = caretY + y;
741                                 if ( mFlipBitmap )
742                                         base_pos = mBrowserHeight - ( caretY + y );
743
744                                 // sometimes the caret seems valid when it really isn't - cap it to size of screen
745                                 if ( caretY + y + caretHeight < mBrowserHeight )
746                                 {
747                                         mPageBuffer[ base_pos * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 0 ] = mCaretBlue;
748                                         mPageBuffer[ base_pos * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 1 ] = mCaretGreen;
749                                         mPageBuffer[ base_pos * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 2 ] = mCaretRed;
750                                 };
751                         };
752                 };
753         };
754
755         return NS_OK;
756 }
757
758 ////////////////////////////////////////////////////////////////////////////////
759 // return the buffer that contains the rendered page
760 unsigned char* LLEmbeddedBrowserWindow::getPageBuffer()
761 {
762         return mPageBuffer;
763 }
764
765 ////////////////////////////////////////////////////////////////////////////////
766 //
767 PRInt16 LLEmbeddedBrowserWindow::getBrowserWidth()
768 {
769         return mBrowserWidth;
770 }
771
772 ////////////////////////////////////////////////////////////////////////////////
773 //
774 PRInt16 LLEmbeddedBrowserWindow::getBrowserHeight()
775 {
776         return mBrowserHeight;
777 }
778
779 ////////////////////////////////////////////////////////////////////////////////
780 //
781 PRInt16 LLEmbeddedBrowserWindow::getBrowserDepth()
782 {
783         return mBrowserDepth;
784 }
785
786 ////////////////////////////////////////////////////////////////////////////////
787 //
788 PRInt32 LLEmbeddedBrowserWindow::getBrowserRowSpan()
789 {
790         return mBrowserRowSpan;
791 }
792
793 ////////////////////////////////////////////////////////////////////////////////
794 //
795 PRBool LLEmbeddedBrowserWindow::navigateTo( const std::string uriIn )
796 {
797         if ( mWebNav )
798         {
799                 mWebNav->LoadURI( reinterpret_cast< const PRUnichar* >( NS_ConvertUTF8toUTF16( uriIn.c_str() ).get() ),
800                         nsIWebNavigation::LOAD_FLAGS_NONE,
801                                 nsnull, nsnull, nsnull );
802
803                 return PR_TRUE;
804         };
805
806         return PR_FALSE;
807 };
808
809 ////////////////////////////////////////////////////////////////////////////////
810 //
811 PRBool LLEmbeddedBrowserWindow::canNavigateBack()
812 {
813         if ( ! mWebNav )
814         {
815                 return PR_FALSE;
816         };
817
818         PRBool canGoBack = PR_FALSE;
819
820         nsresult result = mWebNav->GetCanGoBack( &canGoBack );
821         if ( NS_FAILED( result ) )
822         {
823                 return PR_FALSE;
824         };
825
826         return canGoBack;
827 };
828
829 ////////////////////////////////////////////////////////////////////////////////
830 //
831 void LLEmbeddedBrowserWindow::navigateStop()
832 {
833         if ( mWebNav )
834                 mWebNav->Stop( nsIWebNavigation::STOP_ALL );
835 };
836
837 ////////////////////////////////////////////////////////////////////////////////
838 //
839 void LLEmbeddedBrowserWindow::navigateBack()
840 {
841         if ( mWebNav )
842                 mWebNav->GoBack();
843 };
844
845 ////////////////////////////////////////////////////////////////////////////////
846 //
847 PRBool LLEmbeddedBrowserWindow::canNavigateForward()
848 {
849         if ( ! mWebNav )
850                 return PR_FALSE;
851
852         PRBool canGoForward = PR_FALSE;
853
854         nsresult result = mWebNav->GetCanGoForward( &canGoForward );
855         if ( NS_FAILED( result ) )
856         {
857                 return PR_FALSE;
858         };
859
860         return canGoForward;
861 };
862
863 ////////////////////////////////////////////////////////////////////////////////
864 //
865 void LLEmbeddedBrowserWindow::navigateForward()
866 {
867         if ( mWebNav )
868                 mWebNav->GoForward();
869 };
870
871 ////////////////////////////////////////////////////////////////////////////////
872 //
873 void LLEmbeddedBrowserWindow::navigateReload()
874 {
875         // maybe need a cache version of this too?
876         if ( mWebNav )
877                 mWebNav->Reload( nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE );
878 };
879
880 ////////////////////////////////////////////////////////////////////////////////
881 // set the size of the browser window
882 PRBool LLEmbeddedBrowserWindow::setSize( PRInt16 widthIn, PRInt16 heightIn )
883 {
884         if ( mBaseWindow )
885         {
886                 // if there is a buffer already, get rid of it (it will get created as required in grabWindow())
887                 if ( mPageBuffer )
888                 {
889                         delete[] mPageBuffer;
890                         mPageBuffer = 0;
891                 };
892
893                 // record new size (important: may change after grabWindow() is called);
894                 mBrowserWidth = widthIn;
895                 mBrowserHeight = heightIn;
896                 mBrowserRowSpan = mBrowserWidth * mBrowserDepth;
897
898                 // On the Mac, these calls do strange things to the main viewer window, and they don't seem necessary in any case.
899                 #ifdef WIN32
900                 // this is the actual OS (on Win32) Window so it needs to be hidden
901                 mBaseWindow->SetVisibility( PR_FALSE );
902
903                 // move WAY off screen (and in a place that makes the combobox hack work)
904                 mBaseWindow->SetPosition( 8000, -6000 );
905                 #endif
906
907                 // tell Mozilla about the new size
908                 mBaseWindow->SetSize( widthIn, heightIn, PR_FALSE );
909
910                 return PR_TRUE;
911         };
912
913         return PR_FALSE;
914 }
915
916 ////////////////////////////////////////////////////////////////////////////////
917 //
918 PRBool LLEmbeddedBrowserWindow::flipWindow( PRBool flip )
919 {
920         mFlipBitmap = flip;
921
922         return true;
923 }
924
925 ////////////////////////////////////////////////////////////////////////////////
926 // higher level mouse event
927 void LLEmbeddedBrowserWindow::mouseLeftDoubleClick( PRInt16 xPosIn, PRInt16 yPosIn )
928 {
929         // Internally Mozilla represents double-click as a 2-count mouse down event.
930         // TODO: support triple-click
931         const PRUint32 clickCount = 2;
932         sendMozillaMouseEvent( NS_MOUSE_LEFT_BUTTON_DOWN, xPosIn, yPosIn, clickCount );
933 }
934
935 ////////////////////////////////////////////////////////////////////////////////
936 // higher level mouse event
937 void LLEmbeddedBrowserWindow::mouseDown( PRInt16 xPosIn, PRInt16 yPosIn )
938 {
939         const PRUint32 clickCount = 1;
940         sendMozillaMouseEvent( NS_MOUSE_LEFT_BUTTON_DOWN, xPosIn, yPosIn, clickCount );
941 }
942
943 ////////////////////////////////////////////////////////////////////////////////
944 // higher level mouse event
945 void LLEmbeddedBrowserWindow::mouseUp( PRInt16 xPosIn, PRInt16 yPosIn )
946 {
947         const PRUint32 clickCount = 1;
948         sendMozillaMouseEvent( NS_MOUSE_LEFT_BUTTON_UP, xPosIn, yPosIn, clickCount );
949 }
950
951 ////////////////////////////////////////////////////////////////////////////////
952 // higher level mouse event
953 void LLEmbeddedBrowserWindow::mouseMove( PRInt16 xPosIn, PRInt16 yPosIn )
954 {
955         const PRUint32 clickCount = 1;  // ignored?
956         sendMozillaMouseEvent( NS_MOUSE_MOVE, xPosIn, yPosIn, clickCount );
957 }
958
959 ////////////////////////////////////////////////////////////////////////////////
960 // utility methods to set an error message so something else can look at it
961 void LLEmbeddedBrowserWindow::scrollByLines( PRInt16 linesIn )
962 {
963         if ( mWebBrowser )
964         {
965                 nsCOMPtr< nsIDOMWindow > window;
966                 nsresult result = mWebBrowser->GetContentDOMWindow( getter_AddRefs( window ) );
967
968                 if ( ! NS_FAILED( result ) && window )
969                 {
970                         result = window->ScrollByLines( linesIn );
971                 };
972         };
973 }
974
975 ////////////////////////////////////////////////////////////////////////////////
976 // synthesizes a mouse event and sends into the embedded instance
977 // eventIn - NS_MOUSE_LEFT_BUTTON_DOWN, NS_MOUSE_LEFT_BUTTON_UP, etc.
978 // xPosIn, yPosIn - coordinates (in browser window space)
979 // clickCountIn - use 1 for single click, 2 for double-click, etc.
980 PRBool LLEmbeddedBrowserWindow::sendMozillaMouseEvent( PRInt16 eventIn, PRInt16 xPosIn, PRInt16 yPosIn, PRUint32 clickCountIn )
981 {
982         if ( ! mEnabled )
983                 return PR_FALSE;
984
985         if ( ! mWebBrowser )
986                 return PR_FALSE;
987
988         nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
989         if ( ! docShell )
990                 return PR_FALSE;
991
992         nsCOMPtr< nsPresContext > presContext;
993         nsresult result = docShell->GetPresContext( getter_AddRefs( presContext ) );
994         if ( NS_FAILED( result ) || ( ! presContext ) )
995                 return PR_FALSE;
996
997         nsIViewManager* viewManager = presContext->GetViewManager();
998         if ( ! viewManager )
999                 return PR_FALSE;
1000
1001         nsIView* rootView;
1002         result = viewManager->GetRootView( rootView );
1003         if ( NS_FAILED( result ) || ( ! rootView ) )
1004                 return PR_FALSE;
1005
1006         nsCOMPtr< nsIWidget > widget = rootView->GetWidget();
1007         if ( ! widget )
1008                 return PR_FALSE;
1009
1010         nsMouseEvent mouseEvent( PR_TRUE, eventIn, widget, nsMouseEvent::eReal );
1011         mouseEvent.clickCount = clickCountIn;
1012         mouseEvent.isShift = 0;
1013         mouseEvent.isControl = 0;
1014         mouseEvent.isAlt = 0;
1015         mouseEvent.isMeta = 0;
1016         mouseEvent.widget = widget;
1017         mouseEvent.nativeMsg = nsnull;
1018         mouseEvent.point.x = xPosIn;
1019         mouseEvent.point.y = yPosIn;
1020         mouseEvent.refPoint.x = xPosIn;
1021         mouseEvent.refPoint.y = yPosIn;
1022         mouseEvent.flags = 0;
1023
1024         nsEventStatus status;
1025         result = viewManager->DispatchEvent( &mouseEvent, &status );
1026         if ( NS_FAILED( result ) )
1027                 return PR_FALSE;
1028
1029         return PR_TRUE;
1030 };
1031
1032 ////////////////////////////////////////////////////////////////////////////////
1033 // higher level keyboard functions
1034
1035 // accept a (mozilla-style) keycode
1036 void LLEmbeddedBrowserWindow::keyPress( PRInt16 keyCode )
1037 {
1038         sendMozillaKeyboardEvent( 0, keyCode );
1039 }
1040
1041 // accept keyboard input that's already been translated into a unicode char.
1042 void LLEmbeddedBrowserWindow::unicodeInput( PRUint32 uni_char )
1043 {
1044         sendMozillaKeyboardEvent( uni_char, 0 );
1045 }
1046
1047 ////////////////////////////////////////////////////////////////////////////////
1048 // synthesizes a keyboard event and sends into the embedded instance
1049 PRBool LLEmbeddedBrowserWindow::sendMozillaKeyboardEvent( PRUint32 uni_char, PRUint32 ns_vk_code )
1050 {
1051         if ( ! mEnabled )
1052                 return PR_FALSE;
1053
1054         if ( ! mWebBrowser )
1055                 return PR_FALSE;
1056
1057         nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
1058         if ( ! docShell )
1059                 return PR_FALSE;
1060
1061         nsCOMPtr< nsPresContext > presContext;
1062         docShell->GetPresContext( getter_AddRefs( presContext ) );
1063         if ( ! presContext )
1064                 return PR_FALSE;
1065
1066         nsIViewManager* viewManager = presContext->GetViewManager();
1067         if ( ! viewManager )
1068                 return PR_FALSE;
1069
1070         nsIView* rootView;
1071         viewManager->GetRootView( rootView );
1072         if ( ! rootView )
1073                 return PR_FALSE;
1074
1075         nsCOMPtr< nsIWidget > widget = rootView->GetWidget();
1076         if ( ! widget )
1077                 return PR_FALSE;
1078
1079         nsKeyEvent keyEvent( PR_TRUE, NS_KEY_PRESS, widget );
1080         keyEvent.keyCode = ns_vk_code;
1081         keyEvent.charCode = uni_char;
1082         keyEvent.isChar = uni_char ? PR_TRUE : PR_FALSE;
1083         keyEvent.isShift = 0;
1084         keyEvent.isControl = 0;
1085         keyEvent.isAlt = 0;
1086         keyEvent.isMeta = 0;
1087         keyEvent.widget = widget;
1088         keyEvent.nativeMsg = nsnull;
1089         keyEvent.point.x = 0;
1090         keyEvent.point.y = 0;
1091         keyEvent.refPoint.x = 0;
1092         keyEvent.refPoint.y = 0;
1093         keyEvent.flags = 0;
1094
1095         nsEventStatus status;
1096         nsresult result = viewManager->DispatchEvent( &keyEvent, &status );
1097         if ( NS_FAILED( result ) )
1098                 return PR_FALSE;
1099
1100         return PR_TRUE;
1101 }
1102
1103 ////////////////////////////////////////////////////////////////////////////////
1104 // override nsIWebBrowserChrome::HandleEvent ()
1105 NS_IMETHODIMP LLEmbeddedBrowserWindow::HandleEvent( nsIDOMEvent* anEvent )
1106 {
1107         nsCOMPtr< nsIDOMEventTarget > eventTarget;
1108         anEvent->GetTarget( getter_AddRefs( eventTarget ) );
1109
1110         nsCOMPtr<nsIDOMElement> linkElement ( do_QueryInterface ( eventTarget ) );
1111         if ( linkElement )
1112         {
1113                 // look for an href link
1114                 nsString name;
1115                 linkElement->GetAttribute( NS_ConvertUTF8toUTF16( "href" ), name );
1116                 mClickHref = std::string( NS_ConvertUTF16toUTF8( name ).get() );
1117
1118                 // look for a target element
1119                 linkElement->GetAttribute( NS_ConvertUTF8toUTF16( "target" ), name );
1120                 mClickTarget = std::string( NS_ConvertUTF16toUTF8( name ).get() );
1121
1122                 // if the href link contains something
1123                 if ( mClickHref.length() )
1124                 {
1125                         LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), mClickHref, mClickTarget );
1126                         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onClickLinkHref, event );
1127                 };
1128         };
1129
1130         return NS_OK;
1131 };
1132
1133 ////////////////////////////////////////////////////////////////////////////////
1134 // override nsIURIContentListener methods
1135 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnStartURIOpen( nsIURI *aURI, PRBool *_retval )
1136 {
1137         nsCAutoString newURI;
1138         aURI->GetSpec( newURI );
1139         std::string rawUri = newURI.get();
1140
1141         // are we navigating to a 'nofollow' link
1142         if ( mNoFollowScheme.length() && rawUri.substr( 0, mNoFollowScheme.length() ) == mNoFollowScheme )
1143         {
1144                 LLEmbeddedBrowserWindowEvent event( getWindowId(), rawUri, rawUri );
1145                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onClickLinkNoFollow, event );
1146
1147                 // tell browser we're handling things and don't follow link
1148                 *_retval = PR_TRUE;
1149         }
1150         else
1151         {
1152                 // tell browser to proceed as normal
1153                 *_retval = PR_FALSE;
1154         };
1155
1156         return NS_OK;
1157 }
1158
1159 ////////////////////////////////////////////////////////////////////////////////
1160 //
1161 void LLEmbeddedBrowserWindow::setNoFollowScheme( std::string schemeIn )
1162 {
1163         mNoFollowScheme = schemeIn;
1164 }
1165
1166 ////////////////////////////////////////////////////////////////////////////////
1167 //
1168 std::string LLEmbeddedBrowserWindow::getNoFollowScheme()
1169 {
1170         return mNoFollowScheme;
1171 }
1172
1173 ////////////////////////////////////////////////////////////////////////////////
1174 //
1175 NS_IMETHODIMP LLEmbeddedBrowserWindow::DoContent( const char *aContentType,
1176                                                                                                         PRBool aIsContentPreferred,
1177                                                                                                                 nsIRequest *aRequest,
1178                                                                                                                         nsIStreamListener **aContentHandler,
1179                                                                                                                                 PRBool *_retval )
1180 {
1181         return NS_ERROR_NOT_IMPLEMENTED;
1182 }
1183
1184 ////////////////////////////////////////////////////////////////////////////////
1185 //
1186 NS_IMETHODIMP LLEmbeddedBrowserWindow::IsPreferred( const char *aContentType,
1187                                                                                                                 char **aDesiredContentType,
1188                                                                                                                         PRBool *_retval )
1189 {
1190         // important (otherwise, links try to open in a new window and trigger the window watcher code)
1191         *_retval = PR_TRUE;
1192         return NS_OK;
1193 }
1194
1195 ////////////////////////////////////////////////////////////////////////////////
1196 //
1197 NS_IMETHODIMP LLEmbeddedBrowserWindow::CanHandleContent( const char *aContentType,
1198                                                                                                                         PRBool aIsContentPreferred,
1199                                                                                                                                 char **aDesiredContentType,
1200                                                                                                                                         PRBool *_retval )
1201 {
1202         return NS_ERROR_NOT_IMPLEMENTED;
1203 }
1204
1205 ////////////////////////////////////////////////////////////////////////////////
1206 //
1207 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetLoadCookie( nsISupports * *aLoadCookie )
1208 {
1209         return NS_ERROR_NOT_IMPLEMENTED;
1210 }
1211
1212 ////////////////////////////////////////////////////////////////////////////////
1213 //
1214 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetLoadCookie( nsISupports * aLoadCookie )
1215 {
1216         return NS_ERROR_NOT_IMPLEMENTED;
1217 }
1218
1219 ////////////////////////////////////////////////////////////////////////////////
1220 //
1221 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetParentContentListener( nsIURIContentListener** aParentContentListener )
1222 {
1223         return NS_ERROR_NOT_IMPLEMENTED;
1224 }
1225
1226 ////////////////////////////////////////////////////////////////////////////////
1227 //
1228 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetParentContentListener( nsIURIContentListener* aParentContentListener )
1229 {
1230         return NS_ERROR_NOT_IMPLEMENTED;
1231 }
1232
1233 ////////////////////////////////////////////////////////////////////////////////
1234 // give focus to the browser so that input keyboard events work
1235 void LLEmbeddedBrowserWindow::focusBrowser( PRBool focusBrowserIn )
1236 {
1237         if ( mWebBrowser )
1238         {
1239                 if ( focusBrowserIn )
1240                 {
1241                         nsCOMPtr< nsIWebBrowserFocus > focus( do_GetInterface( mWebBrowser ) );
1242                         focus->Activate();
1243                 }
1244                 else
1245                 {
1246                         nsCOMPtr< nsIWebBrowserFocus > focus( do_GetInterface( mWebBrowser ) );
1247                         focus->Deactivate();
1248                 };
1249         };
1250 }
1251
1252 ////////////////////////////////////////////////////////////////////////////////
1253 //
1254 void LLEmbeddedBrowserWindow::setWindowId( int windowIdIn )
1255 {
1256         mWindowId = windowIdIn;
1257 }
1258
1259 ////////////////////////////////////////////////////////////////////////////////
1260 //
1261 int LLEmbeddedBrowserWindow::getWindowId()
1262 {
1263         //printf("## Getting id for %p and it is %d\n", this, mWindowId );
1264
1265         return mWindowId;
1266 }
1267
1268 ////////////////////////////////////////////////////////////////////////////////
1269 // add / remove the toolkit (and therefore 'page changed') observer
1270 PRBool LLEmbeddedBrowserWindow::enableToolkitObserver( PRBool enableIn )
1271 {
1272         //TODO: AddObserver fails if I grab the toolkit this way.
1273         //static NS_DEFINE_CID(kNS_TOOLKIT_CID, NS_TOOLKIT_CID);
1274         //nsresult result1;
1275         //nsCOMPtr< nsIToolkit > toolkit = do_GetService( kNS_TOOLKIT_CID, &result1 );
1276         //if ( ( result1 == NS_OK ) && toolkit )
1277         //{
1278         //      if ( toolkit->AddObserver( this ) )
1279         //      {
1280         //              return true;
1281         //      };
1282         //};
1283         //return false;
1284
1285         // TODO: this is horrible but seems to work - need a better way to get the toolkit
1286         nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
1287         if ( ! docShell )
1288                 return false;
1289
1290         nsCOMPtr< nsPresContext > presContext;
1291         nsresult result = docShell->GetPresContext( getter_AddRefs( presContext ) );
1292         if ( NS_FAILED( result ) || ( ! presContext ) )
1293                 return false;
1294
1295         nsIViewManager* viewManager = presContext->GetViewManager();
1296         if ( ! viewManager )
1297                 return false;
1298
1299         nsIView* rootView;
1300         result = viewManager->GetRootView( rootView );
1301         if ( NS_FAILED( result ) || ( ! rootView ) )
1302                 return false;
1303
1304         nsCOMPtr< nsIWidget > widget = rootView->GetWidget();
1305         if ( ! widget )
1306                 return false;
1307
1308         nsCOMPtr< nsIToolkit > mToolkit = widget->GetToolkit();
1309         if ( ! mToolkit )
1310                 return false;
1311
1312         if ( enableIn )
1313                 mToolkit->AddObserver( this );
1314         else
1315                 mToolkit->RemoveObserver( this );
1316
1317         return true;
1318 }
1319
1320 ////////////////////////////////////////////////////////////////////////////////
1321 // something on the page changed - e.g. a new page loaded, scrolling, user
1322 // input or as the result of some kind of animation.
1323 // NOTE: we don't call grabWindow here as this can stall graphics apps -
1324 //       we merely pass back an event to the app and let it decide when/if
1325 //       to call grabWindow()
1326 NS_METHOD LLEmbeddedBrowserWindow::NotifyInvalidated( nsIWidget *aWidget, PRInt32 x, PRInt32 y, PRInt32 width, PRInt32 height )
1327 {
1328 //      printf("LLEmbeddedBrowserWindow::NotifyInvalidated(%p, %d, %d, %d, %d)\n", (void*)aWidget, (int)x, (int)y, (int)width, (int)height);
1329
1330         // try to match widget-window against ourselves to see if we need to update the texture
1331         // only works using native widgets (on Windows) at the moment - needs to be moved to platform agnostic code ASAP
1332         #ifdef WIN32
1333
1334         // this is horrible beyond words but it seems to work...
1335         // nsToolkit tells us that a widget changed and we need to see if it's this instance
1336         // so we can emit an event that causes the parent app to update the browser texture
1337         nsIWidget* mainWidget;
1338         mBaseWindow->GetMainWidget( &mainWidget );
1339
1340         HWND nativeWidget = (HWND)aWidget->GetNativeData( NS_NATIVE_WIDGET );
1341         HWND nativeWidgetChild = 0;
1342         while ( ::GetParent( nativeWidget ) )
1343         {
1344                 nativeWidgetChild = nativeWidget;
1345                 nativeWidget = ::GetParent( nativeWidget );
1346         };
1347
1348         if ( ( (HWND)mainWidget->GetNativeData( NS_NATIVE_WIDGET ) ) == nativeWidgetChild )
1349         {
1350                 LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), x, y, width, height );
1351                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onPageChanged, event );
1352         };
1353
1354         // other platforms will always update - desperately inefficient but you'll see something.
1355         #else
1356                 LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), x, y, width, height );
1357                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onPageChanged, event );
1358         #endif
1359
1360         return NS_OK;
1361 }
1362
1363 ////////////////////////////////////////////////////////////////////////////////
1364 //
1365 std::string LLEmbeddedBrowserWindow::evaluateJavascript( std::string scriptIn )
1366 {
1367         nsCOMPtr< nsIScriptGlobalObjectOwner > theGlobalObjectOwner( do_GetInterface( mWebBrowser ) );
1368
1369         if ( theGlobalObjectOwner )
1370         {
1371                 nsIScriptGlobalObject* theGlobalObject;
1372                 theGlobalObject = theGlobalObjectOwner->GetScriptGlobalObject();
1373
1374                 nsIScriptContext* theScriptContext = theGlobalObject->GetContext();
1375
1376                 PRBool IsUndefined;
1377                 nsString output;
1378                 nsresult result = theScriptContext->EvaluateString(NS_ConvertUTF8toUTF16(scriptIn.c_str()),
1379                    nsnull, nsnull, "", 1, nsnull, &output, &IsUndefined);
1380
1381                 if( NS_FAILED( result ) )
1382                         return "";
1383
1384                 return std::string( NS_ConvertUTF16toUTF8( output ).get() );
1385         }
1386
1387         return "";
1388 }
1389
1390 ////////////////////////////////////////////////////////////////////////////////
1391 //
1392 bool LLEmbeddedBrowserWindow::set404RedirectUrl( std::string redirect_url )
1393 {
1394         m404RedirectUrl = redirect_url;
1395
1396         return true;
1397 }
1398
1399 ////////////////////////////////////////////////////////////////////////////////
1400 //
1401 bool LLEmbeddedBrowserWindow::clr404RedirectUrl()
1402 {
1403         m404RedirectUrl = std::string( "" );
1404
1405         return true;
1406 }
1407
1408 // #define required by this file for LibXUL/Mozilla code to avoid crashes in their debug code
1409 #ifdef _DEBUG
1410         #ifdef WIN32
1411                 #undef DEBUG
1412         #endif
1413 #endif
Note: See TracBrowser for help on using the browser.