原文地址:http://blog.csdn.net/dlmu2001/article/details/6208241

摘要: 浏览器的GUI接口分成两种,一种是控件的绘制,另一种则是同应用息息相关的窗口交互操作。本文主要介绍的是后一种,在WebKit里面,称之为宿主窗口。

Chrome类为WebKit内核定义了一系列的宿主窗口相关的操作接口,并最终在不同的实现中由ChromeClient类的派生类来实现,比如,在Qt里面的ChromeClientQt类。

本文将介绍Chrome类在WebKit中的作用,以及在移植WebKit的时候,如何来实现 ChromeClient类。

1.    Chrome类在WebKit中的作用

浏览器的定义,特意查了百度百科,我综合一下,比较好的解释可能是这样,”浏览器是Web/Wap服务的客户端浏览程序,可向Web/Wap服务器发送各种请求,并对服务器发回的超文本信息和各种多媒体数据格式进行解释、显示和播放,并让用户与此些文件互动“。

从上面这个定义里面,我简单提炼出了浏览器需要的几个功能件:发送请求(http),解释超文本信息和各种多媒体数据(解析),显示和播放这些信息(排版,渲染,以及可能存在的插件),互动(交互)。这几个模块里面,同平台GUI相关的是排版、渲染和互动。而Chrome类就是WebCore内核渲染网页以及互动所需的并定义出来会由移植实现的同平台相关的接口,这个接口不包括控件的渲染。ChromeClient的具体实现(比如ChromeClientQt),则是移植对这些接口的实现。如果以MVC的角度来看,Chrome就是V,当然WebKit并非MVC的架构。

2.    类关系

Chrome是对应于Page的,每个Page都会在构造函数中创建一个Chrome对象,并将对象指针赋值给Page类的 m_chrome成员

Chrome类继承自HostWindow类,HostWindow类定义了宿主窗口必须实现的一系列接口,包括刷窗口(及内容),滚动,窗口相对坐标和屏幕坐标之间的相互转换等接口。

HostWindow是个抽象类,没有构造函数,无法实例化,Chrome通过继承对这个类进行了实现

在类Chrome的实现中,通过了组合的方式,将具体的实现委托给了ChromeClient。

例:

  1. void Chrome::invalidateWindow(const IntRect& updateRect, bool immediate)
  2. {
  3. m_client->invalidateWindow(updateRect, immediate);
  4. }
  5.  
  6. void Chrome::invalidateContentsAndWindow(const IntRect& updateRect, bool immediate)
  7. {
  8. m_client->invalidateContentsAndWindow(updateRect, immediate);
  9. }
  10.  
  11. void Chrome::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
  12. {
  13. m_client->invalidateContentsForSlowScroll(updateRect, immediate);
  14. }

ChromeClient也是抽象接口类,没有构造函数,必须在porting的时候,进行继承,由不同的移植依托自己的平台进行实现。

以Qt移植为例,由ChromeClientQt类来最终实现(google的Chrome分支主要由 ChromeClientImp类实现)

而在ChromeClientQt的具体实现中,很多又是通过Page类的内部QwebPageClient类数据成员(client)提供的接口来实现的。

同样的,QWebPageClient是抽象接口类,无法实例化,通过继承类PageClientQWidget来实现。

而PageClientQWidget的实现又最终通过qwebview来实现,这个过程有点绕弯弯。。。

PageClientQWidget的实例化在QwebPage::setView接口中完成。

在代码结构上,ChromeClientQt.cpp 和 PageClientQt.cpp都位于WebKit/qt/WebCoreSupport目录下,表明他们是为了实现WebCore需要实现的移植层代码。

例:

  1. void QWebPage::setView(QWidget* view)
  2. {
  3. if (this->view() == view)
  4. return;
  5.  
  6. d->view = view;
  7. setViewportSize(view ? view->size() : QSize(, ));
  8.  
  9. // If we have no client, we install a special client delegating
  10. // the responsibility to the QWidget. This is the code path
  11. // handling a.o. the "legacy" QWebView.
  12. //
  13. // If such a special delegate already exist, we substitute the view.
  14.  
  15. if (d->client) {
  16. if (d->client->isQWidgetClient())
  17. static_cast<PageClientQWidget*>(d->client.get())->view = view;
  18. return;
  19. }
  20.  
  21. if (view)
  22. d->client = new PageClientQWidget(view, this);
  23. }
  1. IntPoint ChromeClientQt::screenToWindow(const IntPoint& point) const
  2. {
  3. QWebPageClient* pageClient = platformPageClient();
  4. if (!pageClient)
  5. return point;
  6.  
  7. QWidget* ownerWidget = pageClient->ownerWidget();
  8. if (!ownerWidget)
  9. return point;
  10.  
  11. return ownerWidget->mapFromGlobal(point);
  12. }
  13.  
  14. PlatformPageClient ChromeClientQt::platformPageClient() const
  15. {
  16. return m_webPage->d->client.get();
  17. }

3.    主要接口

3.1.       ChromeClientQt

  1. ChromeClientQt::ChromeClientQt(QWebPage* webPage)

描述:

构造函数,以QWebPage为依赖对象创建。一般在创建Page对象前调用这个构造函数实例化ChromeClientQt,并以之为参数创建Page对象

代码:

  1. QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
  2. : q(qq)
  3. , page()
  4. {
  5. WebCore::InitializeLoggingChannelsIfNecessary(); //初始化环境变量 QT_WEBKIT_LOG 指定的log channel,xitongji
  6. ScriptController::initializeThreading(); //初始化线程, 注意:必须在主线程里面调用。可以安全多次调用,可重入//仅仅初始化一次
  7. WTF::initializeMainThread();
  8. WebCore::SecurityOrigin::setLocalLoadPolicy(WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData);
  9. WebPlatformStrategies::initialize();
  10.  
  11. Page::PageClients pageClients;
  12. pageClients.chromeClient = new ChromeClientQt(q);
  13. pageClients.contextMenuClient = new ContextMenuClientQt();
  14. pageClients.editorClient = new EditorClientQt(q);
  15. pageClients.dragClient = new DragClientQt(q);
  16. pageClients.inspectorClient = new InspectorClientQt(q);
  17. #if ENABLE(DEVICE_ORIENTATION)
  18. pageClients.deviceOrientationClient = new DeviceOrientationClientQt(q);
  19. pageClients.deviceMotionClient = new DeviceMotionClientQt(q);
  20. #endif
  21. #if ENABLE(CLIENT_BASED_GEOLOCATION)
  22. if (QWebPagePrivate::drtRun)
  23. pageClients.geolocationClient = new GeolocationClientMock();
  24. else
  25. pageClients.geolocationClient = new GeolocationClientQt(q);
  26. #endif
  27. page = new Page(pageClients);
  28. page->setGroupName("Default Group");
  29. ......
  30. }

3.2   windowRect

  1. virtual FloatRect windowRect();

描述:

获得当前浏览器窗口区域的大小,这个区域不止包括显示区域,还包括状态条,菜单栏,工具栏等等

代码:

  1. FloatRect ChromeClientQt::windowRect()
  2. {
  3. if (!platformPageClient())
  4. return FloatRect();
  5. return platformPageClient()->windowRect();
  6. }

3.3     pageRect

  1. virtual FloatRect pageRect();

描述:

获取显示区域的大小,在排版的时候会经常调用

代码:

  1. FloatRect ChromeClientQt::pageRect()
  2. {
  3. if (!m_webPage)
  4. return FloatRect();
  5. return FloatRect(QRectF(QPointF(, ), m_webPage->viewportSize()));
  6. }

3.4    createWindow

  1. virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&);

描述:

创建一个窗口。一般是在新建一个新窗口或者tab页的时候调用。

一个新窗口的创建意味着会有一个qwebview的创建和qwebpage的创建。窗口创建成功以后,还要在qwebframe主帧中发起网页请求。

这个接口在诸多移植中非常重要。

代码:

  1. Page* ChromeClientQt::createWindow(Frame*, const FrameLoadRequest& request, const WindowFeatures& features, const NavigationAction&)
  2. {
  3. QWebPage* newPage = m_webPage->createWindow(features.dialog ? QWebPage::WebModalDialog : QWebPage::WebBrowserWindow);
  4. if (!newPage)
  5. return ;
  6.  
  7. // A call to QWebPage::mainFrame() implicitly creates the main frame.
  8. // Make sure it exists, as WebCore expects it when returning from this call.
  9. newPage->mainFrame();
  10. return newPage->d->page;
  11. }

3.5     setToolbarsVisible

  1. setToolbarsVisible(bool visible);
  2. bool toolbarsVisible();
  3. void setStatusbarVisible(bool);
  4. statusbarVisible();
  5. setScrollbarsVisible(bool);
  6. scrollbarsVisible();
  7. setMenubarVisible(bool);
  8. menubarVisible();

描述:

这些接口用来设置这些区域的显示与否

3.6      addMessageToConsole

  1. virtual void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, unsigned int lineNumber, const String& sourceID);

描述:

很多浏览器都在提供了javascript控制台工具,方便开发人员进行调试,这个接口 就是要把信息在控制台中打印出来

代码:

  1. void ChromeClientQt::addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message,
  2. unsigned int lineNumber, const String& sourceID)
  3. {
  4. QString x = message;
  5. QString y = sourceID;
  6. m_webPage->javaScriptConsoleMessage(x, lineNumber, y);
  7. }

3.7   runJavaScriptAlert

  1. virtual void runJavaScriptAlert(Frame*, const String&);
  2. virtual bool runJavaScriptConfirm(Frame*, const String&);
  3. virtual bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result);

描述:

用来实现javascript中的alert框,确认框,提示框。完成同用户的交互。

代码:

  1. void ChromeClientQt::runJavaScriptAlert(Frame* f, const String& msg)
  2. {
  3. QString x = msg;
  4. QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
  5. m_webPage->javaScriptAlert(webFrame, x);
  6. }
  7.  
  8. bool ChromeClientQt::runJavaScriptConfirm(Frame* f, const String& msg)
  9. {
  10. QString x = msg;
  11. QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
  12. return m_webPage->javaScriptConfirm(webFrame, x);
  13. }
  14.  
  15. bool ChromeClientQt::runJavaScriptPrompt(Frame* f, const String& message, const String& defaultValue, String& result)
  16. {
  17. QString x = result;
  18. QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
  19. bool rc = m_webPage->javaScriptPrompt(webFrame, (QString)message, (QString)defaultValue, &x);
  20.  
  21. // Fix up a quirk in the QInputDialog class. If no input happened the string should be empty
  22. // but it is null. See https://bugs.webkit.org/show_bug.cgi?id=30914.
  23. if (rc && x.isNull())
  24. result = String("");
  25. else
  26. result = x;
  27.  
  28. return rc;
  29. }

3.8     setStatusbarText

  1. virtual void setStatusbarText(const String&);

描述:

设置状态条显示信心

代码:

  1. void ChromeClientQt::setStatusbarText(const String& msg)
  2. {
  3. QString x = msg;
  4. emit m_webPage->statusBarMessage(x);
  5. }

3.9    invalidateContentsAndWindow

  1. virtual void invalidateContentsAndWindow(const IntRect&, bool);

描述:

非常重要的一个移植接口,用来刷屏(包含内容和窗体)。

一般情况下,平台趋向于一个异步的调用(并不马上调用),也就是说,可能多次的invalidateContentsAndWindow调用的结果才导致一次屏幕的刷新。

第二个bool类型的参数用来表示是否立即进行屏幕刷新,不过很多移植都不对这个参数进行支持

代码:

  1. void ChromeClientQt::invalidateContentsAndWindow(const IntRect& windowRect, bool immediate)
  2. {
  3. // No double buffer, so only update the QWidget if content changed.
  4. if (platformPageClient()) {
  5. QRect rect(windowRect);
  6. rect = rect.intersected(QRect(QPoint(, ), m_webPage->viewportSize()));
  7. if (!rect.isEmpty())
  8. platformPageClient()->update(rect);
  9. }
  10. QMetaObject::invokeMethod(m_webPage, "repaintRequested", Qt::QueuedConnection, Q_ARG(QRect, windowRect));
  11.  
  12. // FIXME: There is no "immediate" support for window painting. This should be done always whenever the flag
  13. // is set.
  14. }

3.10  scroll

  1. virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect);

描述:

滚动支持。移植一般调用native widget缺省的scroll功能来实现这个接口

代码:

  1. void ChromeClientQt::scroll(const IntSize& delta, const IntRect& scrollViewRect, const IntRect&)
  2. {
  3. if (platformPageClient())
  4. platformPageClient()->scroll(delta.width(), delta.height(), scrollViewRect);
  5. emit m_webPage->scrollRequested(delta.width(), delta.height(), scrollViewRect);
  6. }

3.11  windowToScreen

  1. virtual IntPoint screenToWindow(const IntPoint&) const;
  2. virtual IntRect windowToScreen(const IntRect&) const;

描述:

非常重要的移植接口,用来实现基于控件或者小窗口的相对坐标和屏幕坐标之间的转换。在排版的时候,会经常用到这两个转换

代码:

  1. IntRect ChromeClientQt::windowToScreen(const IntRect& rect) const
  2. {
  3. QWebPageClient* pageClient = platformPageClient();
  4. if (!pageClient)
  5. return rect;
  6.  
  7. QWidget* ownerWidget = pageClient->ownerWidget();
  8. if (!ownerWidget)
  9. return rect;
  10.  
  11. QRect screenRect(rect);
  12. screenRect.translate(ownerWidget->mapToGlobal(QPoint(, )));
  13.  
  14. return screenRect;
  15. }
  16.  
  17. IntPoint ChromeClientQt::screenToWindow(const IntPoint& point) const
  18. {
  19. QWebPageClient* pageClient = platformPageClient();
  20. if (!pageClient)
  21. return point;
  22.  
  23. QWidget* ownerWidget = pageClient->ownerWidget();
  24. if (!ownerWidget)
  25. return point;
  26.  
  27. return ownerWidget->mapFromGlobal(point);
  28. }

3.12  requestGeolocationPermissionForFrame

  1. virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*) { }
  2. virtual void cancelGeolocationPermissionRequestForFrame(Frame*, Geolocation*) { }

描述:

在Geolocation(基于浏览器的地理定位技术)的时候,浏览器在调用Geolocation API获取你的地理位置之前,会有一个用户确认,这两个接口就是用来实现这个确认以及确认的取消

3.13  createPopupMenu

  1. virtual PassRefPtr<PopupMenu> createPopupMenu(PopupMenuClient*) const;

描述:

在webkit中,网页中的下拉框(select+option)并不是作为一个控件来实现的,而是结合画 input,画下来三角 和弹出选项来实现。

这两个接口就是用来弹出选项的。画框和input则在 RenderThemeQt中实现

代码:

  1. PassRefPtr<PopupMenu> ChromeClientQt::createPopupMenu(PopupMenuClient* client) const
  2. {
  3. return adoptRef(new PopupMenuQt(client, this));
  4. }

3.14  show

  1. virtual void show();

描述:

用来显示窗体和内容,立即执行刷屏

代码:

  1. void ChromeClientQt::show()
  2. {
  3. if (!m_webPage)
  4. return;
  5. QWidget* view = m_webPage->view();
  6. if (!view)
  7. return;
  8. view->window()->show();
  9. }

WebKit中的Chrome 和 ChromeClient的更多相关文章

  1. webkit中DOM 事件有多少

    webkit中DOM 事件有多少 目前客户端javascript中大量的工作就是处理浏览器,用户触发的各种事件,下面是webkit中这些事件的集合,有一些时常见的,标准规定的,而另一些则是webkit ...

  2. popstate事件在低版本webkit中的调用

    popstate是H5的history系列中的事件,但是在低版本的webkit中会自动触发.H5中的history api是不会使页面发生跳转的,只是操作地址栏和响应的state属性而已,而且是手动操 ...

  3. React中禁止chrome填充密码表单

    当 input 的 type="password" 时,chrome浏览器会以 type="password" 为标识记住输入的用户名和密码, 如果chrome ...

  4. 转-使用 CefSharp 在 C# App 中嵌入 Chrome 浏览器

    使用 CefSharp 在 C# App 中嵌入 Chrome 浏览器 2016-09-23    分类:.NET开发.编程开发.首页精华0人评论 分享到:更多3 本文由码农网 – 小峰原创翻译,转载 ...

  5. 使用CefSharp在.Net程序中嵌入Chrome浏览器(二)——参数设置

    在实现了.Net程序中嵌入Chrome浏览器后,下一步的个性化操作就是加入一些设置了,在前面的文章中,我们可以看到在使用Chrome控件前,有如下一个操作: var setting = new Cef ...

  6. JavaScript事件在WebKit中的处理流程研究

    本文主要探讨了JavaScript事件在WebKit中的注冊和触发机制. JS事件有两种注冊方式: 通过DOM节点的属性加入或者通过node.addEventListener()函数注冊: 通过DOM ...

  7. robot framework笔记(二):在RF中自定义chrome启动参数

    (一)在RF中自定义chrome启动参数 这里主要是实现下面2个功能 1.禁用chrome正受自动测试软件控制的提示 2.设置默认的下载路径(一些导出.下载类的功能,将文件下载到指定路径下) 自定义一 ...

  8. vue中解决chrome浏览器自动播放音频 和MP3语音打包到线上

    一.vue中解决chrome浏览器自动播放音频 需求 有新订单的时候,页面自动语音提示和弹出提示框: 问题 chrome浏览器在18年4月起,就在桌面浏览器全面禁止了音视频的自动播放功能.严格地来说, ...

  9. webkit中获取用户选择文本和编程设定选择文本

    一.需求背景 在 Android 应用中,内嵌一个 WebView,希望捕获用户点击事件,通过 javascript 判断用户点击的是否英文单词,如果是则将被点击单词发给应用做进一步处理,并实用 ja ...

随机推荐

  1. atitit js 开发工具 ide的代码结构显示(func list) outline总结

    atitit js 开发工具 ide的代码结构显示(func list) outline总结 eclips环境::4.3.1 #-------需要一个js开发工具,可以显示outline或者代码结构显 ...

  2. paip.http 404错误 的解决

    paip.http 404错误 的解决 错误原因 1.查看web服务器log...看是否错误... 2.使用了spring 或者struts 等等mvc框架,但是设置错误.. 3.web服务器使用了配 ...

  3. 盘点mysql中容易被我们误会的地方

    引语:mysql作为数据库的一大主力军,到处存在于我们各种系统中,相信大家都不陌生!但是,你知道你能用不代表你知道细节,那我们就来盘点盘点其中一些我们平时不太注意的地方,一来为了有趣,二来为了不让自己 ...

  4. LR11.0 下载及破解

    1. 把loadrunner相关程序全部退出:2. 用LR8.0中的mlr5lprg.dll.lm70.dll覆盖LR安装目录下“bin”文件夹中的对应文件:3. 清理注册表(不清理的话,在添加lic ...

  5. text-size-adjust属性

    在慕课上无意中看到-webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%;这两段代码,居然发现自己完全不理解,然后就去问度娘了,以下是一些 ...

  6. 转:RTMPDump源代码分析

    0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...

  7. 实用的ajaxfileupload插件

    一.ajaxFileUpload是一个异步上传文件的jQuery插件. 传一个不知道什么版本的上来,以后不用到处找了. 语法:$.ajaxFileUpload([options]) options参数 ...

  8. 旧手机作为USB无线网卡使用(分享WIFI、蓝牙连接)

    首先开启手机的WIFI或者蓝牙功能,建立访问互联网的连接,然后设置-更多-网络共享与便携热点,打开安卓手机USB网络共享功能,即可在计算机上通过手机(无电话卡.数据卡)访问互联网.而且此时手机一直在充 ...

  9. 让Asp.Net WebAPI支持OData查询,排序,过滤。

    让Asp.Net WebAPI支持OData后,就能支持在url中直接输入排序,过滤条件了. 一.创建Asp.Net WebAPI项目: 二.使用NuGet安装Asp.Net WebAPI 2.2和O ...

  10. ReactiveCocoa与Functional Reactive Programming

    转自 http://blog.leezhong.com/ios/2013/06/19/frp-reactivecocoa.html Functional Reactive Programming(以下 ...