如何嵌入Gecko引擎

本文介绍了如何下载Mozilla的cvs代码并选择xulrunner进行编译,以实现Gecko引擎的正确嵌入。重点在于理解nsCOMPtr和nsWeakPtr的使用,以及通过libxpcomglue库简化初始化过程。同时,由于Gecko内部管理窗口使用gtk,因此需要使用GtkWindow作为容器,再将其嵌入到QT控件中。
AI助手已提取文章相关产品:
由于工作需要,研究了一下gecko的引擎嵌入的问题,花了三天多的时间,总算成功让gecko在Gtk控件下正确显示网页了。其实并不复杂,如果能找对正确的做法。基本思路是:
  • 下载mozilla的cvs代码。参考moziila官方的说明。这里重要的是要选择checkout xulrunner。我在多次尝试后,发现只有xulrunner能够正常的运行自己写的demo和embedding的demo,当然官方提供的TestGtkEmbed在browser下跑时也会有问题,如果不想走弯路,xulrunner是正确的选择。.mozconfig参考如下:
    ff_topsrc=/mnt/sda2/devel/mozilla
    . ${ff_topsrc}/xulrunner/config/mozconfig
    mk_add_options MOZ_OBJDIR
    =${ff_topsrc}/xulrunner-build
    ac_add_options --enable-application
    =xulrunner
    ac_add_options --enable-optimize
    ac_add_options --enable-default-toolkit
    =cairo-gtk2
    ac_add_options --enable-xft
    ac_add_options --enable-shared
    ac_add_options --disable-static
    ac_add_options --enable-
    debug
    ac_add_options --enable-libxul
    ac_add_options --disable-tests
  • 编译xulrunner。编译的.mozconfig文件中记得按照xulrunner编写,必须enable libxul。
编译完成后,你可以在编译目录(MOZ_OBJDIR)下找到所有需要的嵌入依赖的库和头文件,官方的称呼大概是GRE。以下是一个最简单的demo参考,可以正确编译和运行。我在embeding/config目录下make showbuild得到makefile的框架,然后根据需要做了一下修改。估计不需要这么麻烦,现在也懒得管了。
Makefile如下:
MOZ_ROOT=/mnt/sda2/devel/mozilla/xulrunner-build
LDFLAGS
=-lpthread  -Wl,-rpath -Wl,${MOZ_ROOT}/dist/bin/ -Wl,-rpath -Wl,${MOZ_ROOT}/dist/lib 
-L
${MOZ_ROOT}/dist/lib/ -lxpcom -lnspr4
CXXFLAGS
= -ggdb -fno-rtti -fno-exceptions -Wall -Wconversion -Wpointer-arith -Wcast-align
-Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor -Wno-long-long -pedantic
-fshort-wchar -pthread -pipe  -DNDEBUG -DTRIMMED -O -I
/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include
-I
/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0
-I
/usr/lib/glib-2.0/include -I/usr/include/freetype2 -I/usr/include/libpng12
COMPILE_CFLAGS
= -I ${MOZ_ROOT}/dist/include/system_wrappers
-include 
/mnt/sda2/devel/mozilla/config/gcc_hidden.h -DMOZILLA_STRICT_API
-DOSTYPE
="Linux2.6.22" -DOSARCH=Linux  -I ${MOZ_ROOT}/dist/include/xpcom
-I
${MOZ_ROOT}/dist/include/intl -I${MOZ_ROOT}/dist/include/embedcomponents
-I
${MOZ_ROOT}/dist/include   -I${MOZ_ROOT}/dist/include/embed_base
-I
${MOZ_ROOT}/dist/include/nspr -I${MOZ_ROOT}/dist/include/gtkembedmoz
-DMOZ_PNG_READ -DMOZ_PNG_WRITE   -I
${MOZ_ROOT}/dist/sdk/include
-Wall -W -Wno-unused -Wpointer-arith -Wcast-align -Wno-long-long -pedantic
-pthread -pipe  -DNDEBUG -DTRIMMED -O   -include 
${MOZ_ROOT}/mozilla-config.h
-DMOZILLA_CLIENT

all: test

test: test
.o
    g
++ -o test $(LDFLAGS) `pkg-config --libs gtk+-2.0` test.o ${MOZ_ROOT}/embedding/base/libembed_base_s.${MOZ_ROOT}/xpcom/glue/standalone/libxpcomglue.a

${MOZ_ROOT}/embedding/base/libembed_base_s.a

test
.o: test.cpp
        g
++ -c $(CXXFLAGS) $(COMPILE_CFLAGS) `pkg-config --cflags gtk+-2.0` test.cpp

clean:
        rm *
.o test


test.cpp如下:
#include "nsXPCOM.h"
#include 
"nscore.h"
#include 
"nsEmbedAPI.h"
#include 
"nsWeakReference.h"
#include 
"nsIWebBrowserChrome.h"
#include 
"nsIEmbeddingSiteWindow.h"
#include 
"nsCOMPtr.h"
#include 
"nsIInterfaceRequestor.h"
#include 
"nsEmbedString.h"
#include 
"nsIWebBrowser.h"
#include 
"widget/nsIBaseWindow.h"
#include 
"nsEmbedCID.h"
#include 
"nsComponentManagerUtils.h"
#include 
"nsIWebProgressListener.h"
#include 
"docshell/nsIWebNavigation.h"
#include 
"docshell/nsIDocShellTreeItem.h"
#include 
<iostream>
#include 
<gtk/gtk.h>

using namespace std;

class SillyBrowser: public nsIWebBrowserChrome,
                                        
public nsIEmbeddingSiteWindow,
                                        
public nsIInterfaceRequestor
{
public:
        SillyBrowser();
        
~SillyBrowser();

        NS_DECL_ISUPPORTS
        NS_DECL_NSIWEBBROWSERCHROME
        NS_DECL_NSIEMBEDDINGSITEWINDOW

        NS_DECL_NSIINTERFACEREQUESTOR

        GtkWidget
* getMainWindow();
  
void init(nsIWebBrowser *aWebBrowser);
private:
  GtkWidget 
*_mainWindow;
  nsCOMPtr<nsIWebBrowser> _webBrowser;
  nsCOMPtr
<nsIBaseWindow> _baseWindow;
}
;


class ProgressListener: public nsIWebProgressListener,
                     
public nsSupportsWeakReference // this is xpcom glue
{
public:
  ProgressListener();
  
~ProgressListener();

  NS_DECL_ISUPPORTS
  NS_DECL_NSIWEBPROGRESSLISTENER

}
;

NS_IMPL_ISUPPORTS3(SillyBrowser, nsIWebBrowserChrome,
                                   nsIEmbeddingSiteWindow, nsIInterfaceRequestor)

SillyBrowser::SillyBrowser()
{
  _mainWindow 
= gtk_window_new( GTK_WINDOW_TOPLEVEL );
  g_signal_connect( G_OBJECT(_mainWindow), 
"delete_event",
                                   gtk_main_quit, NULL );

  gtk_widget_set_size_request( _mainWindow, 600400 );
}


SillyBrowser::
~SillyBrowser()
{
  gtk_widget_destroy( _mainWindow );
}


void SillyBrowser::init(nsIWebBrowser *aWebBrowser)
{
  _webBrowser 
= aWebBrowser;
}


GtkWidget
* SillyBrowser::getMainWindow()
{
  
return (GtkWidget*)_mainWindow;
}


NS_IMETHODIMP SillyBrowser::GetInterface(
const nsIID &aIID, void** aInstancePtr)
{
  nsresult rv;
  rv 
= QueryInterface(aIID, aInstancePtr);
  
if ( NS_FAILED(rv) || *aInstancePtr ) {
        nsCOMPtr
<nsIInterfaceRequestor> ir = do_QueryInterface(_webBrowser);
        
return ir->GetInterface(aIID, aInstancePtr);
  }


  
return rv;
}


NS_IMPL_ISUPPORTS2(ProgressListener, nsIWebProgressListener, nsISupportsWeakReference)

ProgressListener::ProgressListener()
{

}


ProgressListener::
~ProgressListener()
{

}


//----------------- nsiwebprogresslistener ------------------------------//
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in nsresult aStatus); */
NS_IMETHODIMP ProgressListener::OnStateChange(nsIWebProgress 
*aWebProgress,
                                nsIRequest 
*aRequest, PRUint32 aStateFlags, nsresult aStatus)
{
    cout 
<< __FUNCTION__ << " called. ";
        cout 
<< " current state is " << (unsigned)aStateFlags << endl;
    
return NS_OK;
}


/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP ProgressListener::OnProgressChange(nsIWebProgress 
*aWebProgress,
            nsIRequest 
*aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress,
            PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
{
    cout 
<< __FUNCTION__ << " called. ";
    
return NS_OK;
}


/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI aLocation); */
NS_IMETHODIMP ProgressListener::OnLocationChange(nsIWebProgress 
*aWebProgress,
            nsIRequest 
*aRequest, nsIURI *aLocation)
{
    cout 
<< __FUNCTION__ << " called. ";
    
return NS_OK;
}


/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
NS_IMETHODIMP ProgressListener::OnStatusChange(nsIWebProgress 
*aWebProgress,
            nsIRequest 
*aRequest, nsresult aStatus, const PRUnichar *aMessage)
{
    cout 
<< __FUNCTION__ << " called. ";
    
return NS_OK;
}


/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aState); */
NS_IMETHODIMP ProgressListener::OnSecurityChange(nsIWebProgress 
*aWebProgress,
                                                nsIRequest 
*aRequest, PRUint32 aState)
{
    cout 
<< __FUNCTION__ << " called. ";
    
return NS_OK;
}


//---------------------

/* void setStatus (in unsigned long statusType, in wstring status); */
NS_IMETHODIMP SillyBrowser::SetStatus(PRUint32 statusType, 
const PRUnichar *status)
{
  cout 
<< __FUNCTION__ << " called. ";
    
return NS_OK;
}


/* attribute nsIWebBrowser webBrowser; */
NS_IMETHODIMP SillyBrowser::GetWebBrowser(nsIWebBrowser 
* *aWebBrowser)
{
  cout 
<< __FUNCTION__ << " called. ";
  
*aWebBrowser = _webBrowser;
  NS_IF_ADDREF(
*aWebBrowser);
  
return NS_OK;
}


NS_IMETHODIMP SillyBrowser::SetWebBrowser(nsIWebBrowser 
* aWebBrowser)
{
  cout 
<< __FUNCTION__ << " called. ";
  _webBrowser 
= aWebBrowser;
  
return NS_OK;
}


/* attribute unsigned long chromeFlags; */
NS_IMETHODIMP SillyBrowser::GetChromeFlags(PRUint32 
*aChromeFlags)
{
  cout 
<< __FUNCTION__ << " called. ";
  
return NS_OK;
}

NS_IMETHODIMP SillyBrowser::SetChromeFlags(PRUint32 aChromeFlags)
{
  cout 
<< __FUNCTION__ << " called. ";
  
return NS_OK;
}


/* void destroyBrowserWindow (); */
NS_IMETHODIMP SillyBrowser::DestroyBrowserWindow()
{
  cout 
<< __FUNCTION__ << " called. ";
  
return NS_OK;
}


/* void sizeBrowserTo (in long aCX, in long aCY); */
NS_IMETHODIMP SillyBrowser::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY)
{
  cout 
<< __FUNCTION__ << " called. ";
  
return NS_OK;
}


/* void showAsModal (); */
NS_IMETHODIMP SillyBrowser::ShowAsModal()
{
  cout 
<< __FUNCTION__ << " called. ";
  
return NS_OK;
}


/* boolean isWindowModal (); */
NS_IMETHODIMP SillyBrowser::IsWindowModal(PRBool 
*_retval)
{
  cout 
<< __FUNCTION__ << " called. ";
  
return NS_OK;
}


/* void exitModalEventLoop (in nsresult aStatus); */
NS_IMETHODIMP SillyBrowser::ExitModalEventLoop(nsresult aStatus)
{

  cout 
<< __FUNCTION__ << " called. ";
  
return NS_OK;
}



/* void setDimensions (in unsigned long flags, in long x, in long y, in long cx, in long cy); */
NS_IMETHODIMP SillyBrowser::SetDimensions(PRUint32 flags, PRInt32 x, PRInt32 y,
                                       PRInt32 cx, PRInt32 cy)
{
  cout 
<< __FUNCTION__ << " called. ";
  
return NS_OK;
}


/* void getDimensions (in unsigned long flags, out long x, out long y, out long cx, out long cy); */
NS_IMETHODIMP SillyBrowser::GetDimensions(PRUint32 flags, PRInt32 
*x, PRInt32 *y,
                                         PRInt32 
*cx, PRInt32 *cy)
{
  cout 
<< __FUNCTION__ << " called. ";
  
return NS_OK;
}


/* void setFocus (); */
NS_IMETHODIMP SillyBrowser::SetFocus()
{
  cout 
<< __FUNCTION__ << " called. ";
  
return NS_OK;
}


/* attribute boolean visibility; */
NS_IMETHODIMP SillyBrowser::GetVisibility(PRBool 
*aVisibility)
{
  cout 
<< __FUNCTION__ << " called. ";
  
*aVisibility = GTK_WIDGET_VISIBLE( _mainWindow );
  
if ( *aVisibility == PR_FALSE )
        cout 
<< __FUNCTION__ << ": not visible. ";
  
else
        cout 
<< __FUNCTION__ << ": visible. ";
  return NS_OK;
}


NS_IMETHODIMP SillyBrowser::SetVisibility(PRBool aVisibility)
{
  cout 
<< __FUNCTION__ << " called. ";
  
if ( aVisibility == PR_TRUE ) {
        gtk_widget_show_all( (GtkWidget*)_mainWindow );
  }
 else
        gtk_widget_hide( (GtkWidget
*)_mainWindow );
  
return NS_OK;
}


/* attribute wstring title; */
NS_IMETHODIMP SillyBrowser::GetTitle(PRUnichar 
* *aTitle)
{
  cout 
<< __FUNCTION__ << " called. ";
  
return NS_OK;
}


NS_IMETHODIMP SillyBrowser::SetTitle(
const PRUnichar * aTitle)
{
  cout 
<< __FUNCTION__ << " called. ";
  gtk_window_set_title( (GtkWindow
*)_mainWindow, (char*)aTitle );
  
return NS_OK;
}


/* [noscript] readonly attribute voidPtr siteWindow; */
NS_IMETHODIMP SillyBrowser::GetSiteWindow(
void * *aSiteWindow)
{
  cout 
<< __FUNCTION__ << " called. ";
  
*aSiteWindow = static_cast<void*>(_mainWindow);
  
return NS_OK;
}


int main(int argc, char *argv[])
{
  gtk_init(
&argc, &argv);

  cout 
<< "start embedding ";
  
char *curDir = nsnull;
  
if ( argc > 1 )
        curDir 
= argv[1];
  nsresult rv;

  rv 
= NS_InitEmbedding( nsnull, nsnull );
  
if ( NS_FAILED(rv) ) {
        cerr 
<< "init embed failed. ";
        exit(
-1);
  }

  cout 
<< "success init embed. ";

  nsCOMPtr
<nsIBaseWindow> baseWindow;
  nsCOMPtr
<nsIWebBrowser> webBrowser;
  SillyBrowser 
*pSillyBrowser = new SillyBrowser();
  ProgressListener 
*pProgressListener = new ProgressListener();


  webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID, &rv);
  
if (NS_FAILED(rv)) return rv;
  cout 
<< "webBrowser created. ";

  pSillyBrowser
->init( webBrowser );
  pSillyBrowser
->AddRef();

  rv = webBrowser->SetContainerWindow((nsIWebBrowserChrome*)pSillyBrowser);
  
if (NS_FAILED(rv)) return rv;
  nsCOMPtr
<nsIDocShellTreeItem> item = do_QueryInterface(webBrowser);
  item
->SetItemType( nsIDocShellTreeItem::typeContentWrapper );

  baseWindow 
= do_QueryInterface(webBrowser, &rv);
  
if ( NS_FAILED(rv) ) return rv;
  cout 
<< "baseWindow queried. ";

  GtkWidget 
*= pSillyBrowser->getMainWindow();
  rv 
= baseWindow->InitWindow((void*)w, nsnull,
                                                          
00600400 );
  
if (NS_FAILED(rv)) return rv;
  cout 
<< "InitWindow success. ";
  rv 
= baseWindow->Create();
  
if (NS_FAILED(rv)) return rv;
  cout 
<< "baseWindow Create success. ";
  nsCOMPtr
<nsISupportsWeakReference> supportWeak = (nsISupportsWeakReference*)pProgressListener;
  nsCOMPtr
<nsIWeakReference> weakRef;
  supportWeak
->GetWeakReference( getter_AddRefs(weakRef) );

 
  webBrowser->AddWebBrowserListener(weakRef, NS_GET_IID(nsIWebProgressListener));

  baseWindow
->SetVisibility( PR_TRUE );

  nsCOMPtr
<nsIWebNavigation> webNav( do_QueryInterface(webBrowser, &rv) );
  
if ( NS_FAILED(rv) ) return rv;
  cout 
<< " get nsIWebNavigation success. ";

  PRUnichar uniURL[] 
= {
        
'w','w','w','.','s','i','n','a','.','c','o','m',''
  }
;
  
char asciiURI[] = "http://www.google.com";
  nsString nsURI 
= NS_ConvertUTF8toUTF16( asciiURI, strlen(asciiURI) );
  
if(webNav)
        webNav
->LoadURI(nsURI.get(),
                                         nsIWebNavigation::LOAD_FLAGS_NONE, 
// Load flags
                                         nsnull,                            // Referring URI
                                         nsnull,                            // Post data
                                         nsnull);
  cout 
<< "load uri success. ";
  gtk_widget_show( w );
  gtk_main();

  rv 
= NS_TermEmbedding();
   
if ( NS_FAILED(rv) ) {
        cerr 
<< "term embed failed. ";
        exit(
-1);
  }


   
return 0;
}


有几个关键问题是:
  1. 我的目的是将gecko嵌入QT中,但是后来发现gecko的nsIBaseWindow在内部管理的窗口是gtk句柄的,因此你是没法直接使用Qt或者其他的非Gtk控件作为容器父控件的。所以正确的做法是用一个GtkWindow作为容器,然后再将此控件嵌入QT的控件中。
  2. 正确理解nsCOMPtr、nsWeakPtr等对象管理方法。错误的使用可能导致莫名奇妙的问题。
  3. 更好的方法也可以是使用mozilla提供的libxpcomglue来作嵌入的初始化,它将帮组用户找到正确的GRE。
  4. 如果要运行TestGtkEmbed,记住要export GRE_HOME=${MOZ_OBJDIR}/dist/bin/ 来指定GRE的目录。没有这一步,会提示说找不到GRE。然后在此目录使用./run-mozilla.sh ./TestGetEmbed运行测试。

您可能感兴趣的与本文相关内容

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值