home *** CD-ROM | disk | FTP | other *** search
- ////////////////////////////////////////////////////////////////////////////////
- //
- // uBrowser - a program that illustrates one way of embedding the
- // Mozilla Gecko (tm) Rendering Engine in an application, grabbing the
- // rendered output and displaying it on the surface of a 3D polygon as
- // texture in an OpenGL (tm) application.
- //
- // uBrowser is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation; either version 2 of the License, or
- // (at your option) any later version.
- //
- // uBrowser is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with uBrowser; if not, write to the Free Software
- // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- //
- // Original code: Copyright 2005 Linden Research Inc.
- // http://www.lindenlab.com
- //
- // Primary author and site maintainer: Callum Prentice (callum@ubrowser.com)
- //
- // See contributors.txt or http://ubrowser.com for a list of contributors
- // without whose generous donation of time and effort, this application
- // would not have been possible.
- //
- ////////////////////////////////////////////////////////////////////////////////
- #include "embeddedbrowser.h"
-
- // annoying, harmless warning we can't get rid of in MSVC.net
- // (no matching operator delete found; memory will not be freed if initialization throws an exception)
- #pragma warning ( disable : 4291 )
-
- #include "nsCWebBrowser.h"
- #include "nsGUIEvent.h"
- #include "nsICaret.h"
- #include "nsIContent.h"
- #include "nsIDOMDocument.h"
- #include "nsIDOMElement.h"
- #include "nsIDOMWindow.h"
- #include "nsIDocShell.h"
- #include "nsIDocShellTreeItem.h"
- #include "nsIDocument.h"
- #include "nsIFrame.h"
- #include "nsIInterfaceRequestorUtils.h"
- #include "nsIScrollableView.h"
- #include "nsISelection.h"
- #include "nsISelectionController.h"
- #include "nsIWebBrowserChrome.h"
- #include "nsIWebBrowserChromeFocus.h"
- #include "nsIWebBrowserFocus.h"
- #include "nsPresContext.h"
- #include "nsProfileDirServiceProvider.h"
- #include "nsXPCOMGlue.h"
- #include "nsXULAppAPI.h"
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- embeddedBrowser::embeddedBrowser() :
- mEmbeddedBrowserWindow( 0 ),
- mWebBrowser( nsnull ),
- mBaseWindow( nsnull ),
- mWebNav( nsnull ),
- mBrowserWidth( 0 ),
- mBrowserHeight( 0 ),
- mBrowserDepth( 4 ),
- mPageBuffer( 0 ),
- mErrorMessage( "" )
- {
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- embeddedBrowser::~embeddedBrowser()
- {
- if ( mEmbeddedBrowserWindow )
- {
- mEmbeddedBrowserWindow->Release();
- mEmbeddedBrowserWindow = nsnull;
- };
-
- if ( mWebNav )
- {
- mWebNav->Stop ( nsIWebNavigation::STOP_ALL );
- mWebNav = nsnull;
- };
-
- if ( mBaseWindow )
- {
- mBaseWindow->Destroy();
- mBaseWindow = nsnull;
- };
-
- mWebBrowser = nsnull;
-
- if ( mPageBuffer )
- {
- delete[] mPageBuffer;
- mPageBuffer = 0;
- };
-
- XRE_TermEmbedding();
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- PRBool embeddedBrowser::init( std::string appBaseDir, PRInt16 browserWidthIn, PRInt16 browserHeightIn )
- {
- mBrowserWidth = browserWidthIn;
- mBrowserHeight = browserHeightIn;
-
- std::string appDir( appBaseDir );
- std::string xulRuntimeDir( appBaseDir );
- std::string profileDir( appBaseDir );
-
- nsCOMPtr< nsILocalFile > xuldir;
- nsresult result = NS_NewNativeLocalFile( nsCString( xulRuntimeDir.c_str() ), PR_FALSE, getter_AddRefs( xuldir ) );
- if ( NS_FAILED( result ) )
- {
- setErrorMessage( "NS_NewNativeLocalFile failed(xuldir)" );
- return PR_FALSE;
- };
-
- nsCOMPtr< nsILocalFile > appdir;
- result = NS_NewNativeLocalFile( nsCString( appDir.c_str() ), PR_FALSE, getter_AddRefs( appdir ) );
- if ( NS_FAILED( result ) )
- {
- setErrorMessage( "NS_NewNativeLocalFile failed(appdir)" );
- return PR_FALSE;
- };
-
- result = XRE_InitEmbedding( xuldir, appdir, nsnull, nsnull, 0 );
- if ( NS_FAILED( result ) )
- {
- setErrorMessage( "XRE_InitEmbedding failed" );
- return PR_FALSE;
- };
-
- nsCOMPtr< nsILocalFile > appDataDir;
- NS_NewNativeLocalFile( nsDependentCString( profileDir.c_str() ), PR_TRUE, getter_AddRefs( appDataDir ) );
-
- // this probably ought to be a parameter!
- appDataDir->Append( NS_LITERAL_STRING( "xreprofile" ) );
- nsCOMPtr< nsILocalFile > localAppDataDir( do_QueryInterface( appDataDir ) );
-
- nsCOMPtr< nsProfileDirServiceProvider > locProvider;
- NS_NewProfileDirServiceProvider( PR_TRUE, getter_AddRefs( locProvider ) );
- if ( ! locProvider )
- {
- setErrorMessage( "NS_NewProfileDirServiceProvider failed" );
- XRE_TermEmbedding();
- return PR_FALSE;
- };
-
- result = locProvider->Register();
- if ( NS_FAILED( result ) )
- {
- setErrorMessage( "locProvider->Register() failed" );
- XRE_TermEmbedding();
- return PR_FALSE;
- };
-
- result = locProvider->SetProfileDir( localAppDataDir );
- if ( NS_FAILED( result ) )
- {
- setErrorMessage( "locProvider->SetProfileDir() failed" );
- XRE_TermEmbedding();
- return PR_FALSE;
- };
-
- return PR_TRUE;
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- PRBool embeddedBrowser::createWindow( void* browserWindowHandleIn )
- {
- nsresult result = NS_OK;
-
- mWebBrowser = do_CreateInstance( NS_WEBBROWSER_CONTRACTID, &result );
- if ( NS_FAILED( result ) || ! mWebBrowser )
- {
- setErrorMessage( "mWebBrowser = do_CreateInstance( NS_WEBBROWSER_CONTRACTID, &result ) failed" );
- return PR_FALSE;
- };
-
- mWebNav = do_QueryInterface( mWebBrowser, &result );
- if ( NS_FAILED( result ) || ! mWebNav )
- {
- setErrorMessage( "mWebNav = do_QueryInterface( mWebBrowser, &result ) failed" );
- return PR_FALSE;
- };
-
-
- mEmbeddedBrowserWindow = new embeddedBrowserWindow;
- if( mEmbeddedBrowserWindow == nsnull )
- {
- setErrorMessage( "unable to create an instance on the embedded browser window" );
- return PR_FALSE;
- };
-
- mEmbeddedBrowserWindow->Init( this, mWebBrowser );
- mEmbeddedBrowserWindow->AddRef();
-
- ///// NOT SURE IF WE NEED THIS SetWebBrowser( mWebBrowser );
-
- mWebBrowser->SetContainerWindow( NS_STATIC_CAST( nsIWebBrowserChrome*, mEmbeddedBrowserWindow ) );
-
- nsCOMPtr< nsIDocShellTreeItem > dsti = do_QueryInterface( mWebBrowser );
- dsti->SetItemType( nsIDocShellTreeItem::typeContentWrapper );
-
- mBaseWindow = do_QueryInterface( mWebBrowser, &result );
- if ( NS_FAILED( result ) || ! mBaseWindow )
- {
- setErrorMessage( "mBaseWindow = do_QueryInterface( mWebBrowser, &result ) failed" );
- return PR_FALSE;
- };
-
- result = mBaseWindow->InitWindow( browserWindowHandleIn, nsnull, 0, 0, mBrowserWidth , mBrowserHeight );
- if ( NS_FAILED( result ) )
- {
- setErrorMessage( "mBaseWindow->InitWindow( ... ) failed" );
- return PR_FALSE;
- };
-
- result = mBaseWindow->Create();
- if ( NS_FAILED( result ) )
- {
- setErrorMessage( "mBaseWindow->Create() failed" );
- return PR_FALSE;
- };
-
- nsWeakPtr weakling( do_GetWeakReference( NS_STATIC_CAST( nsIWebProgressListener*, mEmbeddedBrowserWindow ) ) );
- mWebBrowser->AddWebBrowserListener( weakling, NS_GET_IID( nsIWebProgressListener ) );
-
- mBaseWindow->SetVisibility( PR_FALSE );
- mBaseWindow->SetPosition( 8000, -6000 );
-
- return PR_TRUE;
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- // change the size of the browser
- PRBool embeddedBrowser::setSize( PRInt16 widthIn, PRInt16 heightIn, PRBool repaintIn )
- {
- if ( mBaseWindow )
- {
- // if there is a buffer already, get rid of it (it will get created as required in grabWindow())
- if ( mPageBuffer )
- {
- delete[] mPageBuffer;
- mPageBuffer = 0;
- };
-
- // record new size
- mBrowserWidth = widthIn;
- mBrowserHeight = heightIn;
-
- // tell Mozilla about the new size
- mBaseWindow->SetSize( widthIn, heightIn, repaintIn );
-
- return PR_TRUE;
- };
-
- return PR_FALSE;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // give focus to the browser so that input keyboard events work
- void embeddedBrowser::focusBrowser( PRBool focusBrowserIn )
- {
- if ( focusBrowserIn )
- {
- nsCOMPtr< nsIWebBrowserFocus > focus( do_GetInterface( mWebBrowser ) );
- focus->Activate();
- }
- else
- {
- nsCOMPtr< nsIWebBrowserFocus > focus( do_GetInterface( mWebBrowser ) );
- focus->Deactivate();
- };
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- PRBool embeddedBrowser::navigateTo( const std::string uriIn )
- {
- if ( mWebNav )
- {
- mWebNav->LoadURI( reinterpret_cast< const PRUnichar* >( NS_ConvertUTF8toUTF16( uriIn.c_str() ).get() ),
- nsIWebNavigation::LOAD_FLAGS_NONE,
- nsnull, nsnull, nsnull );
-
- return PR_TRUE;
- };
-
- return PR_FALSE;
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- PRBool embeddedBrowser::canNavigateBack()
- {
- if ( ! mWebNav )
- return PR_FALSE;
-
- PRBool canGoBack = PR_FALSE;
-
- nsresult result = mWebNav->GetCanGoBack( &canGoBack );
- if ( NS_FAILED( result ) )
- {
- return PR_FALSE;
- };
-
- return canGoBack;
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void embeddedBrowser::navigateStop()
- {
- if ( mWebNav )
- mWebNav->Stop( nsIWebNavigation::STOP_ALL );
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void embeddedBrowser::navigateBack()
- {
- if ( mWebNav )
- mWebNav->GoBack();
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- PRBool embeddedBrowser::canNavigateForward()
- {
- if ( ! mWebNav )
- return PR_FALSE;
-
- PRBool canGoForward = PR_FALSE;
-
- nsresult result = mWebNav->GetCanGoForward( &canGoForward );
- if ( NS_FAILED( result ) )
- {
- return PR_FALSE;
- };
-
- return canGoForward;
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void embeddedBrowser::navigateForward()
- {
- if ( mWebNav )
- mWebNav->GoForward();
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- // return the buffer that contains the rendered page
- const unsigned char* embeddedBrowser::getPageBuffer()
- {
- return mPageBuffer;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // higher level mouse event
- void embeddedBrowser::mouseDown( PRInt16 xPosIn, PRInt16 yPosIn )
- {
- sendMozillaMouseEvent( NS_MOUSE_LEFT_BUTTON_DOWN, xPosIn, yPosIn );
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // higher level mouse event
- void embeddedBrowser::mouseUp( PRInt16 xPosIn, PRInt16 yPosIn )
- {
- sendMozillaMouseEvent( NS_MOUSE_LEFT_BUTTON_UP, xPosIn, yPosIn );
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // higher level mouse event
- void embeddedBrowser::mouseMove( PRInt16 xPosIn, PRInt16 yPosIn )
- {
-
- sendMozillaMouseEvent( NS_MOUSE_MOVE, xPosIn, yPosIn );
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // utility methods to set an error message so something else can look at it
- void embeddedBrowser::setErrorMessage( std::string errMessageIn )
- {
- mErrorMessage = errMessageIn;
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- // utility methods to get an error message that was set earlier
- const std::string& embeddedBrowser::getErrorMessage()
- {
- return mErrorMessage;
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- // synthesizes a mouse event and sends into the embedded instance
- PRBool embeddedBrowser::sendMozillaMouseEvent( PRInt16 eventIn, PRInt16 xPosIn, PRInt16 yPosIn )
- {
- nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
- if ( ! docShell )
- return PR_FALSE;
-
- nsCOMPtr< nsPresContext > presContext;
- nsresult result = docShell->GetPresContext( getter_AddRefs( presContext ) );
- if ( NS_FAILED( result ) || ( ! presContext ) )
- return PR_FALSE;
-
- nsIViewManager* viewManager = presContext->GetViewManager();
- if ( ! viewManager )
- return PR_FALSE;
-
- nsIView* rootView;
- result = viewManager->GetRootView( rootView );
- if ( NS_FAILED( result ) || ( ! rootView ) )
- return PR_FALSE;
-
- nsCOMPtr< nsIWidget > widget = rootView->GetWidget();
- if ( ! widget )
- return PR_FALSE;
-
- nsMouseEvent mouseEvent( PR_TRUE, eventIn, widget, nsMouseEvent::eReal );
- mouseEvent.clickCount = 1;
- mouseEvent.isShift = 0;
- mouseEvent.isControl = 0;
- mouseEvent.isAlt = 0;
- mouseEvent.isMeta = 0;
- mouseEvent.widget = widget;
- mouseEvent.nativeMsg = nsnull;
- mouseEvent.point.x = xPosIn;
- mouseEvent.point.y = yPosIn;
- mouseEvent.refPoint.x = xPosIn;
- mouseEvent.refPoint.y = yPosIn;
- mouseEvent.flags = 0;
-
- nsEventStatus status;
- result = viewManager->DispatchEvent( &mouseEvent, &status );
- if ( NS_FAILED( result ) )
- return PR_FALSE;
-
- return PR_TRUE;
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- // higher level keyboard function
- void embeddedBrowser::keyPress( PRInt16 keyCode )
- {
- sendMozillaKeyboardEvent( 0, keyCode );
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // synthesizes a keyboard event and sends into the embedded instance
- PRBool embeddedBrowser::sendMozillaKeyboardEvent( PRUint32 keyIn, PRUint32 ns_vk_code )
- {
- nsresult result = NS_OK;
-
- nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
- if ( ! docShell )
- return PR_FALSE;
-
- nsCOMPtr< nsPresContext > presContext;
- docShell->GetPresContext( getter_AddRefs( presContext ) );
- if ( ! presContext )
- return PR_FALSE;
-
- nsIViewManager* viewManager = presContext->GetViewManager();
- if ( ! viewManager )
- return PR_FALSE;
-
- nsIView* rootView;
- viewManager->GetRootView( rootView );
- if ( ! rootView )
- return PR_FALSE;
-
- nsCOMPtr< nsIWidget > widget = rootView->GetWidget();
- if ( ! widget )
- return PR_FALSE;
-
- nsKeyEvent keyEvent( PR_TRUE, NS_KEY_PRESS, widget );
- keyEvent.keyCode = ns_vk_code;
- keyEvent.charCode = keyIn;
- keyEvent.isChar = PR_TRUE;
- keyEvent.isShift = 0;
- keyEvent.isControl = 0;
- keyEvent.isAlt = 0;
- keyEvent.isMeta = 0;
- keyEvent.widget = widget;
- keyEvent.nativeMsg = nsnull;
- keyEvent.point.x = 0;
- keyEvent.point.y = 0;
- keyEvent.refPoint.x = 0;
- keyEvent.refPoint.y = 0;
- keyEvent.flags = 0;
-
- nsEventStatus status;
- result = viewManager->DispatchEvent( &keyEvent, &status );
- if ( NS_FAILED( result ) )
- return PR_FALSE;
-
- return PR_TRUE;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // all this just to render a caret!
- PRBool embeddedBrowser::renderCaret()
- {
- nsCOMPtr< nsIWebBrowserFocus > focus = do_QueryInterface( mWebBrowser );
-
- nsCOMPtr< nsIDOMElement > focusedElement;
- focus->GetFocusedElement( getter_AddRefs( focusedElement ) );
- if ( ! focusedElement )
- return NS_ERROR_FAILURE;
-
- nsCOMPtr<nsIContent> focusedContent = do_QueryInterface( focusedElement );
-
- nsCOMPtr< nsIDOMWindow > domWindow;
- mWebBrowser->GetContentDOMWindow( getter_AddRefs( domWindow ) );
- if ( ! domWindow )
- return NS_ERROR_FAILURE;
-
- nsCOMPtr< nsIDOMDocument > domDocument;
- domWindow->GetDocument( getter_AddRefs( domDocument ) );
- if ( ! domDocument )
- return NS_ERROR_FAILURE;
-
- nsCOMPtr< nsIDocument> document = do_QueryInterface( domDocument );
- if ( ! document )
- return NS_ERROR_FAILURE;
-
- nsIPresShell* presShell = document->GetShellAt( 0 );
- if ( ! presShell )
- return NS_ERROR_FAILURE;
-
- nsCOMPtr< nsICaret > caret;
- presShell->GetCaret( getter_AddRefs( caret ) );
-
- nsIFrame* frame = nsnull;
- presShell->GetPrimaryFrameFor( focusedContent, &frame );
- if ( ! frame )
- return NS_ERROR_FAILURE;
-
- nsCOMPtr<nsISelectionController> selCtrl;
- frame->GetSelectionController( presShell->GetPresContext(), getter_AddRefs( selCtrl ) );
-
- nsCOMPtr<nsISelection> selection;
- selCtrl->GetSelection( nsISelectionController::SELECTION_NORMAL, getter_AddRefs( selection ) );
-
- PRBool collapsed;
- nsRect coords;
- nsIView* caretView;
- caret->GetCaretCoordinates( nsICaret::eTopLevelWindowCoordinates, selection, &coords, &collapsed, &caretView );
-
- float twips2Pixls = presShell->GetPresContext()->TwipsToPixels();
-
- PRInt32 caretX = NSTwipsToIntPixels( coords.x, twips2Pixls );
- PRInt32 caretY = NSTwipsToIntPixels( coords.y, twips2Pixls );
- PRInt32 caretHeight = NSTwipsToIntPixels( coords.height, twips2Pixls );
-
- if ( caretX > -1 && caretX < mBrowserWidth && caretY > -1 && caretY < mBrowserHeight )
- {
- if ( mPageBuffer )
- {
- for( int y = 1; y < caretHeight - 1; ++y )
- {
- mPageBuffer[ ( caretY + y ) * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 0 ] = 0;
- mPageBuffer[ ( caretY + y ) * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 1 ] = 0;
- mPageBuffer[ ( caretY + y ) * getBrowserRowSpan() + ( caretX + 1 ) * mBrowserDepth + 2 ] = 0;
- };
- };
- };
-
- return NS_OK;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // grabs the window and writes it to a chunk of memory
- PRBool embeddedBrowser::grabWindow()
- {
- nsCOMPtr< nsIDocShell > docShell = do_GetInterface( mWebBrowser );
- if ( ! docShell )
- return PR_FALSE;
-
- nsCOMPtr< nsPresContext > presContext;
- nsresult result = docShell->GetPresContext( getter_AddRefs( presContext ) );
- if ( NS_FAILED( result ) || ( ! presContext ) )
- return PR_FALSE;
-
- nsIViewManager* viewManager = presContext->GetViewManager();
- if ( ! viewManager )
- return PR_FALSE;
-
- nsIScrollableView* scrollableView;
- viewManager->GetRootScrollableView( &scrollableView );
-
- nsIView* view;
- if ( scrollableView )
- scrollableView->GetScrolledView( view );
- else
- viewManager->GetRootView( view );
-
- nsRect rect = view->GetBounds() - view->GetPosition() - view->GetPosition();
- if ( rect.IsEmpty() )
- return NS_ERROR_FAILURE;
-
- float p2t = presContext->PixelsToTwips();
- rect.width = NSIntPixelsToTwips( mBrowserWidth, p2t );
- rect.height = NSIntPixelsToTwips( mBrowserHeight, p2t );
-
- nsCOMPtr< nsIRenderingContext > context;
- result = viewManager->RenderOffscreen( view, rect, PR_FALSE, PR_FALSE, NS_RGB( 255, 255, 255 ), getter_AddRefs( context ) );
- if ( NS_FAILED( result ) )
- return NS_ERROR_FAILURE;
-
- nsIDrawingSurface* surface = nsnull;
- context->GetDrawingSurface( &surface );
- if ( ! surface )
- return NS_ERROR_FAILURE;
-
- float t2p = presContext->TwipsToPixels();
- PRInt32 width = NSTwipsToIntPixels( rect.width, t2p );
- PRInt32 height = NSTwipsToIntPixels( rect.height, t2p );
-
- PRUint8* data;
- PRInt32 rowLen;
-
- // sometime rowspan ! width in pixels * bytes per pixel so save row span value and use in application
- result = surface->Lock( 0, 0, width, height, reinterpret_cast< void** >( &data ), &mBrowserRowSpan, &rowLen, NS_LOCK_SURFACE_READ_ONLY );
- if ( NS_FAILED ( result ) )
- return NS_ERROR_FAILURE;
-
- PRUint32 bytesPerPix = rowLen / width;
- nsPixelFormat format;
- surface->GetPixelFormat( &format );
- mBrowserDepth = bytesPerPix;
-
- // create it here so it can be deleted and recreated elsewhere
- if ( ! mPageBuffer )
- mPageBuffer = new unsigned char[ mBrowserRowSpan * mBrowserHeight ];
-
- memcpy( mPageBuffer, data, mBrowserRowSpan * mBrowserHeight );
-
- surface->Unlock();
- context->DestroyDrawingSurface( surface );
-
- renderCaret();
-
- return NS_OK;
- }