root/trunk/llmozlib2/llembeddedbrowserwindow.cpp

Revision 8, 42.6 kB (checked in by rob.linden, 2 years ago)

Latest internal snapshot
Last Changed Rev: 80909
Last Changed Date: 2008-02-27 15:08:55 -0800 (Wed, 27 Feb 2008)

  • 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( 0x0 ),
119         mCaretGreen( 0x0 ),
120         mCaretBlue( 0x0 ),
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         // get pres context
598         nsCOMPtr< nsPresContext > presContext;
599         nsresult result = docShell->GetPresContext( getter_AddRefs( presContext ) );
600         if ( NS_FAILED( result ) || ( ! presContext ) )
601                 return PR_FALSE;
602
603         // get view manager
604         nsIViewManager* viewManager = presContext->GetViewManager();
605         if ( ! viewManager )
606                 return PR_FALSE;
607
608         // get the view
609         nsIScrollableView* scrollableView = NULL;
610         viewManager->GetRootScrollableView( &scrollableView );
611         nsIView* view = NULL;
612         if ( scrollableView )
613                 scrollableView->GetScrolledView( view );
614         else
615                 viewManager->GetRootView( view );
616
617         // get the rectangle we want to render in twips (this looks odd but takees care of scrolling too)
618         nsRect rect = view->GetBounds() - view->GetPosition() - view->GetPosition();
619         if ( rect.IsEmpty() )
620                 return 0;
621
622         float p2t = presContext->PixelsToTwips();
623         rect.width = NSIntPixelsToTwips( widthIn, p2t );
624         rect.height = NSIntPixelsToTwips( heightIn, p2t );
625
626         // render the page
627         nsCOMPtr< nsIRenderingContext > context;
628         result = viewManager->RenderOffscreen( view, rect, PR_FALSE, PR_FALSE, NS_RGB( mBkgRed, mBkgGreen, mBkgBlue  ), getter_AddRefs( context ) );
629         if ( NS_FAILED( result ) )
630                 return 0;
631
632         // retrieve the surface we rendered to
633         nsIDrawingSurface* surface = nsnull;
634         context->GetDrawingSurface( &surface );
635         if ( ! surface )
636                 return 0;
637
638         // lock the surface and retrieve a pointer to the rendered data and current row span
639         PRUint8* data;
640         PRInt32 rowLen;
641         // sometime rowspan ! width in pixels * bytes per pixel so save row span value and use in application
642         result = surface->Lock( xIn, yIn, widthIn, heightIn, reinterpret_cast< void** >( &data ), &mBrowserRowSpan, &rowLen, NS_LOCK_SURFACE_READ_ONLY );
643         if ( NS_FAILED ( result ) )
644                 return 0;
645
646         // save row span - it *can* change during the life of the app
647         mBrowserDepth = rowLen / mBrowserWidth;
648
649         // create memory buffer here so it can be deleted and recreated elsewhere
650         if ( ! mPageBuffer )
651                 mPageBuffer = new unsigned char[ mBrowserRowSpan * mBrowserHeight ];
652
653         // save the pixels and optionally invert them
654         // (it's useful the SL client to get bitmaps that are inverted compared
655         // to the way that Mozilla renders them - allow to optionally flip
656         if ( mFlipBitmap )
657         {
658                 for( int y = mBrowserHeight - 1; y > -1; --y )
659                 {
660                         memcpy( mPageBuffer + y * mBrowserRowSpan,
661                                                 data + ( mBrowserHeight - y - 1 ) * mBrowserRowSpan,
662                                                         mBrowserRowSpan );
663                 };
664         }
665         else
666         {
667                 memcpy( mPageBuffer, data, mBrowserRowSpan * mBrowserHeight );
668         };
669
670         // release and destroy the surface we rendered to
671         surface->Unlock();
672         context->DestroyDrawingSurface( surface );
673
674         renderCaret();
675
676         return mPageBuffer;
677 }
678
679 ////////////////////////////////////////////////////////////////////////////////
680 // all this just to render a caret!
681 PRBool LLEmbeddedBrowserWindow::renderCaret()
682 {
683         nsCOMPtr< nsIWebBrowserFocus > focus = do_QueryInterface( mWebBrowser );
684
685         nsCOMPtr< nsIDOMElement > focusedElement;
686         focus->GetFocusedElement( getter_AddRefs( focusedElement ) );
687         if ( ! focusedElement )
688                 return NS_ERROR_FAILURE;
689
690         nsCOMPtr<nsIContent> focusedContent = do_QueryInterface( focusedElement );
691
692         nsCOMPtr< nsIDOMWindow > domWindow;
693         mWebBrowser->GetContentDOMWindow( getter_AddRefs( domWindow ) );
694         if ( ! domWindow )
695                 return NS_ERROR_FAILURE;
696
697         nsCOMPtr< nsIDOMDocument > domDocument;
698         domWindow->GetDocument( getter_AddRefs( domDocument ) );
699         if ( ! domDocument )
700                 return NS_ERROR_FAILURE;
701
702         nsCOMPtr< nsIDocument> document = do_QueryInterface( domDocument );
703         if ( ! document )
704                 return NS_ERROR_FAILURE;
705
706         nsIPresShell* presShell = document->GetShellAt( 0 );
707         if ( ! presShell )
708                 return NS_ERROR_FAILURE;
709
710         nsCOMPtr< nsICaret > caret;
711         presShell->GetCaret( getter_AddRefs( caret ) );
712
713         nsIFrame* frame = nsnull;
714         presShell->GetPrimaryFrameFor( focusedContent, &frame );
715         if ( ! frame )
716                 return NS_ERROR_FAILURE;
717
718         nsCOMPtr<nsISelectionController> selCtrl;
719         frame->GetSelectionController( presShell->GetPresContext(), getter_AddRefs( selCtrl ) );
720
721         nsCOMPtr<nsISelection> selection;
722         selCtrl->GetSelection( nsISelectionController::SELECTION_NORMAL, getter_AddRefs( selection ) );
723
724         PRBool collapsed;
725         nsRect coords;
726         nsIView* caretView;
727         caret->GetCaretCoordinates( nsICaret::eTopLevelWindowCoordinates, selection, &coords, &collapsed, &caretView );
728
729         float twips2Pixls = presShell->GetPresContext()->TwipsToPixels();
730
731         PRInt32 caretX = NSTwipsToIntPixels( coords.x, twips2Pixls );
732         PRInt32 caretY = NSTwipsToIntPixels( coords.y, twips2Pixls );
733         PRInt32 caretHeight = NSTwipsToIntPixels( coords.height, twips2Pixls );
734
735         if ( caretX > -1 && caretX < mBrowserWidth && caretY > -1 && caretY < mBrowserHeight )
736         {
737                 if ( mPageBuffer )
738                 {
739                         for( int y = 1; y < caretHeight - 1; ++y )
740                         {
741                                 PRInt32 base_pos = caretY + y;
742                                 if ( mFlipBitmap )
743                                         base_pos = mBrowserHeight - ( caretY + y );
744
745                                 // sometimes the caret seems valid when it really isn't - cap it to size of screen
746                                 if ( caretY + y + caretHeight < mBrowserHeight )
747                                 {
748                                         mPageBuffer[ base_pos * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 0 ] = mCaretBlue;
749                                         mPageBuffer[ base_pos * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 1 ] = mCaretGreen;
750                                         mPageBuffer[ base_pos * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 2 ] = mCaretRed;
751                                 };
752                         };
753                 };
754         };
755
756         return NS_OK;
757 }
758
759 ////////////////////////////////////////////////////////////////////////////////
760 // return the buffer that contains the rendered page
761 unsigned char* LLEmbeddedBrowserWindow::getPageBuffer()
762 {
763         return mPageBuffer;
764 }
765
766 ////////////////////////////////////////////////////////////////////////////////
767 //
768 PRInt16 LLEmbeddedBrowserWindow::getBrowserWidth()
769 {
770         return mBrowserWidth;
771 }
772
773 ////////////////////////////////////////////////////////////////////////////////
774 //
775 PRInt16 LLEmbeddedBrowserWindow::getBrowserHeight()
776 {
777         return mBrowserHeight;
778 }
779
780 ////////////////////////////////////////////////////////////////////////////////
781 //
782 PRInt16 LLEmbeddedBrowserWindow::getBrowserDepth()
783 {
784         return mBrowserDepth;
785 }
786
787 ////////////////////////////////////////////////////////////////////////////////
788 //
789 PRInt32 LLEmbeddedBrowserWindow::getBrowserRowSpan()
790 {
791         return mBrowserRowSpan;
792 }
793
794 ////////////////////////////////////////////////////////////////////////////////
795 //
796 PRBool LLEmbeddedBrowserWindow::navigateTo( const std::string uriIn )
797 {
798         if ( mWebNav )
799         {
800                 mWebNav->LoadURI( reinterpret_cast< const PRUnichar* >( NS_ConvertUTF8toUTF16( uriIn.c_str() ).get() ),
801                         nsIWebNavigation::LOAD_FLAGS_NONE,
802                                 nsnull, nsnull, nsnull );
803
804                 return PR_TRUE;
805         };
806
807         return PR_FALSE;
808 };
809
810 ////////////////////////////////////////////////////////////////////////////////
811 //
812 PRBool LLEmbeddedBrowserWindow::canNavigateBack()
813 {
814         if ( ! mWebNav )
815         {
816                 return PR_FALSE;
817         };
818
819         PRBool canGoBack = PR_FALSE;
820
821         nsresult result = mWebNav->GetCanGoBack( &canGoBack );
822         if ( NS_FAILED( result ) )
823         {
824                 return PR_FALSE;
825         };
826
827         return canGoBack;
828 };
829
830 ////////////////////////////////////////////////////////////////////////////////
831 //
832 void LLEmbeddedBrowserWindow::navigateStop()
833 {
834         if ( mWebNav )
835                 mWebNav->Stop( nsIWebNavigation::STOP_ALL );
836 };
837
838 ////////////////////////////////////////////////////////////////////////////////
839 //
840 void LLEmbeddedBrowserWindow::navigateBack()
841 {
842         if ( mWebNav )
843                 mWebNav->GoBack();
844 };
845
846 ////////////////////////////////////////////////////////////////////////////////
847 //
848 PRBool LLEmbeddedBrowserWindow::canNavigateForward()
849 {
850         if ( ! mWebNav )
851                 return PR_FALSE;
852
853         PRBool canGoForward = PR_FALSE;
854
855         nsresult result = mWebNav->GetCanGoForward( &canGoForward );
856         if ( NS_FAILED( result ) )
857         {
858                 return PR_FALSE;
859         };
860
861         return canGoForward;
862 };
863
864 ////////////////////////////////////////////////////////////////////////////////
865 //
866 void LLEmbeddedBrowserWindow::navigateForward()
867 {
868         if ( mWebNav )
869                 mWebNav->GoForward();
870 };
871
872 ////////////////////////////////////////////////////////////////////////////////
873 // set the size of the browser window
874 PRBool LLEmbeddedBrowserWindow::setSize( PRInt16 widthIn, PRInt16 heightIn )
875 {
876         if ( mBaseWindow )
877         {
878                 // if there is a buffer already, get rid of it (it will get created as required in grabWindow())
879                 if ( mPageBuffer )
880                 {
881                         delete[] mPageBuffer;
882                         mPageBuffer = 0;
883                 };
884
885                 // record new size (important: may change after grabWindow() is called);
886                 mBrowserWidth = widthIn;
887                 mBrowserHeight = heightIn;
888                 mBrowserRowSpan = mBrowserWidth * mBrowserDepth;
889
890                 // On the Mac, these calls do strange things to the main viewer window, and they don't seem necessary in any case.
891                 #ifdef WIN32
892                 // this is the actual OS (on Win32) Window so it needs to be hidden
893                 mBaseWindow->SetVisibility( PR_FALSE );
894
895                 // move WAY off screen (and in a place that makes the combobox hack work)
896                 mBaseWindow->SetPosition( 8000, -6000 );
897                 #endif
898
899                 // tell Mozilla about the new size
900                 mBaseWindow->SetSize( widthIn, heightIn, PR_FALSE );
901
902                 return PR_TRUE;
903         };
904
905         return PR_FALSE;
906 }
907
908 ////////////////////////////////////////////////////////////////////////////////
909 //
910 PRBool LLEmbeddedBrowserWindow::flipWindow( PRBool flip )
911 {
912         mFlipBitmap = flip;
913
914         return true;
915 }
916
917 ////////////////////////////////////////////////////////////////////////////////
918 // higher level mouse event
919 void LLEmbeddedBrowserWindow::mouseLeftDoubleClick( PRInt16 xPosIn, PRInt16 yPosIn )
920 {
921         // Internally Mozilla represents double-click as a 2-count mouse down event.
922         // TODO: support triple-click
923         const PRUint32 clickCount = 2;
924         sendMozillaMouseEvent( NS_MOUSE_LEFT_BUTTON_DOWN, xPosIn, yPosIn, clickCount );
925 }
926
927 ////////////////////////////////////////////////////////////////////////////////
928 // higher level mouse event
929 void LLEmbeddedBrowserWindow::mouseDown( PRInt16 xPosIn, PRInt16 yPosIn )
930 {
931         const PRUint32 clickCount = 1;
932         sendMozillaMouseEvent( NS_MOUSE_LEFT_BUTTON_DOWN, xPosIn, yPosIn, clickCount );
933 }
934
935 ////////////////////////////////////////////////////////////////////////////////
936 // higher level mouse event
937 void LLEmbeddedBrowserWindow::mouseUp( PRInt16 xPosIn, PRInt16 yPosIn )
938 {
939         const PRUint32 clickCount = 1;
940         sendMozillaMouseEvent( NS_MOUSE_LEFT_BUTTON_UP, xPosIn, yPosIn, clickCount );
941 }
942
943 ////////////////////////////////////////////////////////////////////////////////
944 // higher level mouse event
945 void LLEmbeddedBrowserWindow::mouseMove( PRInt16 xPosIn, PRInt16 yPosIn )
946 {
947         const PRUint32 clickCount = 1;  // ignored?
948         sendMozillaMouseEvent( NS_MOUSE_MOVE, xPosIn, yPosIn, clickCount );
949 }
950
951 ////////////////////////////////////////////////////////////////////////////////
952 // utility methods to set an error message so something else can look at it
953 void LLEmbeddedBrowserWindow::scrollByLines( PRInt16 linesIn )
954 {
955         if ( mWebBrowser )
956         {
957                 nsCOMPtr< nsIDOMWindow > window;
958                 nsresult result = mWebBrowser->GetContentDOMWindow( getter_AddRefs( window ) );
959
960                 if ( ! NS_FAILED( result ) && window )
961                 {
962                         result = window->ScrollByLines( linesIn );
963                 };
964         };
965 }
966
967 ////////////////////////////////////////////////////////////////////////////////
968 // synthesizes a mouse event and sends into the embedded instance
969 // eventIn - NS_MOUSE_LEFT_BUTTON_DOWN, NS_MOUSE_LEFT_BUTTON_UP, etc.
970 // xPosIn, yPosIn - coordinates (in browser window space)
971 // clickCountIn - use 1 for single click, 2 for double-click, etc.
972 PRBool LLEmbeddedBrowserWindow::sendMozillaMouseEvent( PRInt16 eventIn, PRInt16 xPosIn, PRInt16 yPosIn, PRUint32 clickCountIn )
973 {
974         if ( ! mEnabled )
975                 return PR_FALSE;
976
977         if ( ! mWebBrowser )
978                 return PR_FALSE;
979
980         nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
981         if ( ! docShell )
982                 return PR_FALSE;
983
984         nsCOMPtr< nsPresContext > presContext;
985         nsresult result = docShell->GetPresContext( getter_AddRefs( presContext ) );
986         if ( NS_FAILED( result ) || ( ! presContext ) )
987                 return PR_FALSE;
988
989         nsIViewManager* viewManager = presContext->GetViewManager();
990         if ( ! viewManager )
991                 return PR_FALSE;
992
993         nsIView* rootView;
994         result = viewManager->GetRootView( rootView );
995         if ( NS_FAILED( result ) || ( ! rootView ) )
996                 return PR_FALSE;
997
998         nsCOMPtr< nsIWidget > widget = rootView->GetWidget();
999         if ( ! widget )
1000                 return PR_FALSE;
1001
1002         nsMouseEvent mouseEvent( PR_TRUE, eventIn, widget, nsMouseEvent::eReal );
1003         mouseEvent.clickCount = clickCountIn;
1004         mouseEvent.isShift = 0;
1005         mouseEvent.isControl = 0;
1006         mouseEvent.isAlt = 0;
1007         mouseEvent.isMeta = 0;
1008         mouseEvent.widget = widget;
1009         mouseEvent.nativeMsg = nsnull;
1010         mouseEvent.point.x = xPosIn;
1011         mouseEvent.point.y = yPosIn;
1012         mouseEvent.refPoint.x = xPosIn;
1013         mouseEvent.refPoint.y = yPosIn;
1014         mouseEvent.flags = 0;
1015
1016         nsEventStatus status;
1017         result = viewManager->DispatchEvent( &mouseEvent, &status );
1018         if ( NS_FAILED( result ) )
1019                 return PR_FALSE;
1020
1021         return PR_TRUE;
1022 };
1023
1024 ////////////////////////////////////////////////////////////////////////////////
1025 // higher level keyboard functions
1026
1027 // accept a (mozilla-style) keycode
1028 void LLEmbeddedBrowserWindow::keyPress( PRInt16 keyCode )
1029 {
1030         sendMozillaKeyboardEvent( 0, keyCode );
1031 }
1032
1033 // accept keyboard input that's already been translated into a unicode char.
1034 void LLEmbeddedBrowserWindow::unicodeInput( PRUint32 uni_char )
1035 {
1036         sendMozillaKeyboardEvent( uni_char, 0 );
1037 }
1038
1039 ////////////////////////////////////////////////////////////////////////////////
1040 // synthesizes a keyboard event and sends into the embedded instance
1041 PRBool LLEmbeddedBrowserWindow::sendMozillaKeyboardEvent( PRUint32 uni_char, PRUint32 ns_vk_code )
1042 {
1043         if ( ! mEnabled )
1044                 return PR_FALSE;
1045
1046         if ( ! mWebBrowser )
1047                 return PR_FALSE;
1048
1049         nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
1050         if ( ! docShell )
1051                 return PR_FALSE;
1052
1053         nsCOMPtr< nsPresContext > presContext;
1054         docShell->GetPresContext( getter_AddRefs( presContext ) );
1055         if ( ! presContext )
1056                 return PR_FALSE;
1057
1058         nsIViewManager* viewManager = presContext->GetViewManager();
1059         if ( ! viewManager )
1060                 return PR_FALSE;
1061
1062         nsIView* rootView;
1063         viewManager->GetRootView( rootView );
1064         if ( ! rootView )
1065                 return PR_FALSE;
1066
1067         nsCOMPtr< nsIWidget > widget = rootView->GetWidget();
1068         if ( ! widget )
1069                 return PR_FALSE;
1070
1071         nsKeyEvent keyEvent( PR_TRUE, NS_KEY_PRESS, widget );
1072         keyEvent.keyCode = ns_vk_code;
1073         keyEvent.charCode = uni_char;
1074         keyEvent.isChar = uni_char ? PR_TRUE : PR_FALSE;
1075         keyEvent.isShift = 0;
1076         keyEvent.isControl = 0;
1077         keyEvent.isAlt = 0;
1078         keyEvent.isMeta = 0;
1079         keyEvent.widget = widget;
1080         keyEvent.nativeMsg = nsnull;
1081         keyEvent.point.x = 0;
1082         keyEvent.point.y = 0;
1083         keyEvent.refPoint.x = 0;
1084         keyEvent.refPoint.y = 0;
1085         keyEvent.flags = 0;
1086
1087         nsEventStatus status;
1088         nsresult result = viewManager->DispatchEvent( &keyEvent, &status );
1089         if ( NS_FAILED( result ) )
1090                 return PR_FALSE;
1091
1092         return PR_TRUE;
1093 }
1094
1095 ////////////////////////////////////////////////////////////////////////////////
1096 // override nsIWebBrowserChrome::HandleEvent ()
1097 NS_IMETHODIMP LLEmbeddedBrowserWindow::HandleEvent( nsIDOMEvent* anEvent )
1098 {
1099         nsCOMPtr< nsIDOMEventTarget > eventTarget;
1100         anEvent->GetTarget( getter_AddRefs( eventTarget ) );
1101
1102         nsCOMPtr<nsIDOMElement> linkElement ( do_QueryInterface ( eventTarget ) );
1103         if ( linkElement )
1104         {
1105                 // look for an href link
1106                 nsString name;
1107                 linkElement->GetAttribute( NS_ConvertUTF8toUTF16( "href" ), name );
1108                 mClickHref = std::string( NS_ConvertUTF16toUTF8( name ).get() );
1109
1110                 // look for a target element
1111                 linkElement->GetAttribute( NS_ConvertUTF8toUTF16( "target" ), name );
1112                 mClickTarget = std::string( NS_ConvertUTF16toUTF8( name ).get() );
1113
1114                 // if the href link contains something
1115                 if ( mClickHref.length() )
1116                 {
1117                         LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), mClickHref, mClickTarget );
1118                         mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onClickLinkHref, event );
1119                 };
1120         };
1121
1122         return NS_OK;
1123 };
1124
1125 ////////////////////////////////////////////////////////////////////////////////
1126 // override nsIURIContentListener methods
1127 NS_IMETHODIMP LLEmbeddedBrowserWindow::OnStartURIOpen( nsIURI *aURI, PRBool *_retval )
1128 {
1129         nsCAutoString newURI;
1130         aURI->GetSpec( newURI );
1131         std::string rawUri = newURI.get();
1132
1133         // are we navigating to a 'nofollow' link
1134         if ( mNoFollowScheme.length() && rawUri.substr( 0, mNoFollowScheme.length() ) == mNoFollowScheme )
1135         {
1136                 LLEmbeddedBrowserWindowEvent event( getWindowId(), rawUri, rawUri );
1137                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onClickLinkNoFollow, event );
1138
1139                 // tell browser we're handling things and don't follow link
1140                 *_retval = PR_TRUE;
1141         }
1142         else
1143         {
1144                 // tell browser to proceed as normal
1145                 *_retval = PR_FALSE;
1146         };
1147
1148         return NS_OK;
1149 }
1150
1151 ////////////////////////////////////////////////////////////////////////////////
1152 //
1153 void LLEmbeddedBrowserWindow::setNoFollowScheme( std::string schemeIn )
1154 {
1155         mNoFollowScheme = schemeIn;
1156 }
1157
1158 ////////////////////////////////////////////////////////////////////////////////
1159 //
1160 std::string LLEmbeddedBrowserWindow::getNoFollowScheme()
1161 {
1162         return mNoFollowScheme;
1163 }
1164
1165 ////////////////////////////////////////////////////////////////////////////////
1166 //
1167 NS_IMETHODIMP LLEmbeddedBrowserWindow::DoContent( const char *aContentType,
1168                                                                                                         PRBool aIsContentPreferred,
1169                                                                                                                 nsIRequest *aRequest,
1170                                                                                                                         nsIStreamListener **aContentHandler,
1171                                                                                                                                 PRBool *_retval )
1172 {
1173         return NS_ERROR_NOT_IMPLEMENTED;
1174 }
1175
1176 ////////////////////////////////////////////////////////////////////////////////
1177 //
1178 NS_IMETHODIMP LLEmbeddedBrowserWindow::IsPreferred( const char *aContentType,
1179                                                                                                                 char **aDesiredContentType,
1180                                                                                                                         PRBool *_retval )
1181 {
1182         // important (otherwise, links try to open in a new window and trigger the window watcher code)
1183         *_retval = PR_TRUE;
1184         return NS_OK;
1185 }
1186
1187 ////////////////////////////////////////////////////////////////////////////////
1188 //
1189 NS_IMETHODIMP LLEmbeddedBrowserWindow::CanHandleContent( const char *aContentType,
1190                                                                                                                         PRBool aIsContentPreferred,
1191                                                                                                                                 char **aDesiredContentType,
1192                                                                                                                                         PRBool *_retval )
1193 {
1194         return NS_ERROR_NOT_IMPLEMENTED;
1195 }
1196
1197 ////////////////////////////////////////////////////////////////////////////////
1198 //
1199 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetLoadCookie( nsISupports * *aLoadCookie )
1200 {
1201         return NS_ERROR_NOT_IMPLEMENTED;
1202 }
1203
1204 ////////////////////////////////////////////////////////////////////////////////
1205 //
1206 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetLoadCookie( nsISupports * aLoadCookie )
1207 {
1208         return NS_ERROR_NOT_IMPLEMENTED;
1209 }
1210
1211 ////////////////////////////////////////////////////////////////////////////////
1212 //
1213 NS_IMETHODIMP LLEmbeddedBrowserWindow::GetParentContentListener( nsIURIContentListener** aParentContentListener )
1214 {
1215         return NS_ERROR_NOT_IMPLEMENTED;
1216 }
1217
1218 ////////////////////////////////////////////////////////////////////////////////
1219 //
1220 NS_IMETHODIMP LLEmbeddedBrowserWindow::SetParentContentListener( nsIURIContentListener* aParentContentListener )
1221 {
1222         return NS_ERROR_NOT_IMPLEMENTED;
1223 }
1224
1225 ////////////////////////////////////////////////////////////////////////////////
1226 // give focus to the browser so that input keyboard events work
1227 void LLEmbeddedBrowserWindow::focusBrowser( PRBool focusBrowserIn )
1228 {
1229         if ( mWebBrowser )
1230         {
1231                 if ( focusBrowserIn )
1232                 {
1233                         nsCOMPtr< nsIWebBrowserFocus > focus( do_GetInterface( mWebBrowser ) );
1234                         focus->Activate();
1235                 }
1236                 else
1237                 {
1238                         nsCOMPtr< nsIWebBrowserFocus > focus( do_GetInterface( mWebBrowser ) );
1239                         focus->Deactivate();
1240                 };
1241         };
1242 }
1243
1244 ////////////////////////////////////////////////////////////////////////////////
1245 //
1246 void LLEmbeddedBrowserWindow::setWindowId( int windowIdIn )
1247 {
1248         mWindowId = windowIdIn;
1249 }
1250
1251 ////////////////////////////////////////////////////////////////////////////////
1252 //
1253 int LLEmbeddedBrowserWindow::getWindowId()
1254 {
1255         //printf("## Getting id for %p and it is %d\n", this, mWindowId );
1256
1257         return mWindowId;
1258 }
1259
1260 ////////////////////////////////////////////////////////////////////////////////
1261 // add / remove the toolkit (and therefore 'page changed') observer
1262 PRBool LLEmbeddedBrowserWindow::enableToolkitObserver( PRBool enableIn )
1263 {
1264         //TODO: AddObserver fails if I grab the toolkit this way.
1265         //static NS_DEFINE_CID(kNS_TOOLKIT_CID, NS_TOOLKIT_CID);
1266         //nsresult result1;
1267         //nsCOMPtr< nsIToolkit > toolkit = do_GetService( kNS_TOOLKIT_CID, &result1 );
1268         //if ( ( result1 == NS_OK ) && toolkit )
1269         //{
1270         //      if ( toolkit->AddObserver( this ) )
1271         //      {
1272         //              return true;
1273         //      };
1274         //};
1275         //return false;
1276
1277         // TODO: this is horrible but seems to work - need a better way to get the toolkit
1278         nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
1279         if ( ! docShell )
1280                 return false;
1281
1282         nsCOMPtr< nsPresContext > presContext;
1283         nsresult result = docShell->GetPresContext( getter_AddRefs( presContext ) );
1284         if ( NS_FAILED( result ) || ( ! presContext ) )
1285                 return false;
1286
1287         nsIViewManager* viewManager = presContext->GetViewManager();
1288         if ( ! viewManager )
1289                 return false;
1290
1291         nsIView* rootView;
1292         result = viewManager->GetRootView( rootView );
1293         if ( NS_FAILED( result ) || ( ! rootView ) )
1294                 return false;
1295
1296         nsCOMPtr< nsIWidget > widget = rootView->GetWidget();
1297         if ( ! widget )
1298                 return false;
1299
1300         nsCOMPtr< nsIToolkit > mToolkit = widget->GetToolkit();
1301         if ( ! mToolkit )
1302                 return false;
1303
1304         if ( enableIn )
1305                 mToolkit->AddObserver( this );
1306         else
1307                 mToolkit->RemoveObserver( this );
1308
1309         return true;
1310 }
1311
1312 ////////////////////////////////////////////////////////////////////////////////
1313 // something on the page changed - e.g. a new page loaded, scrolling, user
1314 // input or as the result of some kind of animation.
1315 // NOTE: we don't call grabWindow here as this can stall graphics apps -
1316 //       we merely pass back an event to the app and let it decide when/if
1317 //       to call grabWindow()
1318 NS_METHOD LLEmbeddedBrowserWindow::NotifyInvalidated( nsIWidget *aWidget, PRInt32 x, PRInt32 y, PRInt32 width, PRInt32 height )
1319 {
1320 //      printf("LLEmbeddedBrowserWindow::NotifyInvalidated(%p, %d, %d, %d, %d)\n", (void*)aWidget, (int)x, (int)y, (int)width, (int)height);
1321
1322         // try to match widget-window against ourselves to see if we need to update the texture
1323         // only works using native widgets (on Windows) at the moment - needs to be moved to platform agnostic code ASAP
1324         #ifdef WIN32
1325
1326         // this is horrible beyond words but it seems to work...
1327         // nsToolkit tells us that a widget changed and we need to see if it's this instance
1328         // so we can emit an event that causes the parent app to update the browser texture
1329         nsIWidget* mainWidget;
1330         mBaseWindow->GetMainWidget( &mainWidget );
1331
1332         HWND nativeWidget = (HWND)aWidget->GetNativeData( NS_NATIVE_WIDGET );
1333         HWND nativeWidgetChild;
1334         while ( ::GetParent( nativeWidget ) )
1335         {
1336                 nativeWidgetChild = nativeWidget;
1337                 nativeWidget = ::GetParent( nativeWidget );
1338         };
1339
1340         if ( ( (HWND)mainWidget->GetNativeData( NS_NATIVE_WIDGET ) ) == nativeWidgetChild )
1341         {
1342                 LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), x, y, width, height );
1343                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onPageChanged, event );
1344         };
1345
1346         // other platforms will always update - desperately inefficient but you'll see something.
1347         #else
1348                 LLEmbeddedBrowserWindowEvent event( getWindowId(), getCurrentUri(), x, y, width, height );
1349                 mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onPageChanged, event );
1350         #endif
1351
1352         return NS_OK;
1353 }
1354
1355 ////////////////////////////////////////////////////////////////////////////////
1356 //
1357 std::string LLEmbeddedBrowserWindow::evaluateJavascript( std::string scriptIn )
1358 {
1359         nsCOMPtr< nsIScriptGlobalObjectOwner > theGlobalObjectOwner( do_GetInterface( mWebBrowser ) );
1360
1361         if ( theGlobalObjectOwner )
1362         {
1363                 nsIScriptGlobalObject* theGlobalObject;
1364                 theGlobalObject = theGlobalObjectOwner->GetScriptGlobalObject();
1365
1366                 nsIScriptContext* theScriptContext = theGlobalObject->GetContext();
1367
1368                 PRBool IsUndefined;
1369                 nsString output;
1370                 nsresult result = theScriptContext->EvaluateString(NS_ConvertUTF8toUTF16(scriptIn.c_str()),
1371                    nsnull, nsnull, "", 1, nsnull, &output, &IsUndefined);
1372
1373                 if( NS_FAILED( result ) )
1374                         return "";
1375
1376                 return std::string( NS_ConvertUTF16toUTF8( output ).get() );
1377         }
1378
1379         return "";
1380 }
1381
1382 ////////////////////////////////////////////////////////////////////////////////
1383 //
1384 bool LLEmbeddedBrowserWindow::set404RedirectUrl( std::string redirect_url )
1385 {
1386         m404RedirectUrl = redirect_url;
1387
1388         return true;
1389 }
1390
1391 ////////////////////////////////////////////////////////////////////////////////
1392 //
1393 bool LLEmbeddedBrowserWindow::clr404RedirectUrl()
1394 {
1395         m404RedirectUrl = std::string( "" );
1396
1397         return true;
1398 }
1399
1400 // #define required by this file for LibXUL/Mozilla code to avoid crashes in their debug code
1401 #ifdef _DEBUG
1402         #ifdef WIN32
1403                 #undef DEBUG
1404         #endif
1405 #endif
Note: See TracBrowser for help on using the browser.