原文地址: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。

例:

 void Chrome::invalidateWindow(const IntRect& updateRect, bool immediate)
{
m_client->invalidateWindow(updateRect, immediate);
} void Chrome::invalidateContentsAndWindow(const IntRect& updateRect, bool immediate)
{
m_client->invalidateContentsAndWindow(updateRect, immediate);
} void Chrome::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
{
m_client->invalidateContentsForSlowScroll(updateRect, immediate);
}

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需要实现的移植层代码。

例:

 void QWebPage::setView(QWidget* view)
{
if (this->view() == view)
return; d->view = view;
setViewportSize(view ? view->size() : QSize(, )); // If we have no client, we install a special client delegating
// the responsibility to the QWidget. This is the code path
// handling a.o. the "legacy" QWebView.
//
// If such a special delegate already exist, we substitute the view. if (d->client) {
if (d->client->isQWidgetClient())
static_cast<PageClientQWidget*>(d->client.get())->view = view;
return;
} if (view)
d->client = new PageClientQWidget(view, this);
}
 IntPoint ChromeClientQt::screenToWindow(const IntPoint& point) const
{
QWebPageClient* pageClient = platformPageClient();
if (!pageClient)
return point; QWidget* ownerWidget = pageClient->ownerWidget();
if (!ownerWidget)
return point; return ownerWidget->mapFromGlobal(point);
} PlatformPageClient ChromeClientQt::platformPageClient() const
{
return m_webPage->d->client.get();
}

3.    主要接口

3.1.       ChromeClientQt

 ChromeClientQt::ChromeClientQt(QWebPage* webPage)

描述:

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

代码:

 QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
: q(qq)
, page()
{
WebCore::InitializeLoggingChannelsIfNecessary(); //初始化环境变量 QT_WEBKIT_LOG 指定的log channel,xitongji
ScriptController::initializeThreading(); //初始化线程, 注意:必须在主线程里面调用。可以安全多次调用,可重入//仅仅初始化一次
WTF::initializeMainThread();
WebCore::SecurityOrigin::setLocalLoadPolicy(WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData);
WebPlatformStrategies::initialize(); Page::PageClients pageClients;
pageClients.chromeClient = new ChromeClientQt(q);
pageClients.contextMenuClient = new ContextMenuClientQt();
pageClients.editorClient = new EditorClientQt(q);
pageClients.dragClient = new DragClientQt(q);
pageClients.inspectorClient = new InspectorClientQt(q);
#if ENABLE(DEVICE_ORIENTATION)
pageClients.deviceOrientationClient = new DeviceOrientationClientQt(q);
pageClients.deviceMotionClient = new DeviceMotionClientQt(q);
#endif
#if ENABLE(CLIENT_BASED_GEOLOCATION)
if (QWebPagePrivate::drtRun)
pageClients.geolocationClient = new GeolocationClientMock();
else
pageClients.geolocationClient = new GeolocationClientQt(q);
#endif
page = new Page(pageClients);
page->setGroupName("Default Group");
......
}

3.2   windowRect

 virtual FloatRect windowRect();

描述:

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

代码:

 FloatRect ChromeClientQt::windowRect()
{
if (!platformPageClient())
return FloatRect();
return platformPageClient()->windowRect();
}

3.3     pageRect

 virtual FloatRect pageRect();

描述:

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

代码:

 FloatRect ChromeClientQt::pageRect()
{
if (!m_webPage)
return FloatRect();
return FloatRect(QRectF(QPointF(, ), m_webPage->viewportSize()));
}

3.4    createWindow

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

描述:

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

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

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

代码:

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

3.5     setToolbarsVisible

 setToolbarsVisible(bool visible);
bool toolbarsVisible();
void setStatusbarVisible(bool);
statusbarVisible();
setScrollbarsVisible(bool);
scrollbarsVisible();
setMenubarVisible(bool);
menubarVisible();

描述:

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

3.6      addMessageToConsole

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

描述:

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

代码:

 void ChromeClientQt::addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message,
unsigned int lineNumber, const String& sourceID)
{
QString x = message;
QString y = sourceID;
m_webPage->javaScriptConsoleMessage(x, lineNumber, y);
}

3.7   runJavaScriptAlert

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

描述:

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

代码:

 void ChromeClientQt::runJavaScriptAlert(Frame* f, const String& msg)
{
QString x = msg;
QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
m_webPage->javaScriptAlert(webFrame, x);
} bool ChromeClientQt::runJavaScriptConfirm(Frame* f, const String& msg)
{
QString x = msg;
QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
return m_webPage->javaScriptConfirm(webFrame, x);
} bool ChromeClientQt::runJavaScriptPrompt(Frame* f, const String& message, const String& defaultValue, String& result)
{
QString x = result;
QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
bool rc = m_webPage->javaScriptPrompt(webFrame, (QString)message, (QString)defaultValue, &x); // Fix up a quirk in the QInputDialog class. If no input happened the string should be empty
// but it is null. See https://bugs.webkit.org/show_bug.cgi?id=30914.
if (rc && x.isNull())
result = String("");
else
result = x; return rc;
}

3.8     setStatusbarText

 virtual void setStatusbarText(const String&);

描述:

设置状态条显示信心

代码:

 void ChromeClientQt::setStatusbarText(const String& msg)
{
QString x = msg;
emit m_webPage->statusBarMessage(x);
}

3.9    invalidateContentsAndWindow

 virtual void invalidateContentsAndWindow(const IntRect&, bool);

描述:

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

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

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

代码:

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

3.10  scroll

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

描述:

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

代码:

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

3.11  windowToScreen

 virtual IntPoint screenToWindow(const IntPoint&) const;
virtual IntRect windowToScreen(const IntRect&) const;

描述:

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

代码:

 IntRect ChromeClientQt::windowToScreen(const IntRect& rect) const
{
QWebPageClient* pageClient = platformPageClient();
if (!pageClient)
return rect; QWidget* ownerWidget = pageClient->ownerWidget();
if (!ownerWidget)
return rect; QRect screenRect(rect);
screenRect.translate(ownerWidget->mapToGlobal(QPoint(, ))); return screenRect;
} IntPoint ChromeClientQt::screenToWindow(const IntPoint& point) const
{
QWebPageClient* pageClient = platformPageClient();
if (!pageClient)
return point; QWidget* ownerWidget = pageClient->ownerWidget();
if (!ownerWidget)
return point; return ownerWidget->mapFromGlobal(point);
}

3.12  requestGeolocationPermissionForFrame

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

描述:

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

3.13  createPopupMenu

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

描述:

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

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

代码:

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

3.14  show

 virtual void show();

描述:

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

代码:

 void ChromeClientQt::show()
{
if (!m_webPage)
return;
QWidget* view = m_webPage->view();
if (!view)
return;
view->window()->show();
}

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. 投票系统开发总结struts2,jfreechart,cookie应用,以及前端技术

    struts2配置web.xml+struts.xml: <?xml version="1.0" encoding="UTF-8"?> <we ...

  2. Java-基础练习3

    1.编写一个Java程序,计算半径为3.0的圆周长和面积并输出结果.把圆周率π定义为常量,半径定义为变量,然后进行计算并输出结果. package com.java; public class zm ...

  3. (二)关于ajax那些事

    哈哈,今天突然兴起,想了想自己对ajax的了解,来这里叙述下.心情好,嘿嘿嘿 ajax是一种创建交互式网页应用的网页开发技术.就是在不重新加载页面的情况下,更新部分网页. ajax原理:ajax就是相 ...

  4. 第六章 应用层(DNS和http协议详解)

    序言 这是计算机网络基础的最后一篇博文了,大体的从物理层到最上层的应用层做了一个大概的了解,花了也有快1个月的时间了,在本章结尾会给你们我学习该课程的视频资料,我希望能帮到所有想学习想提高自己技术的同 ...

  5. 写hive db的两种方法

    方法1tmp_channel_hive_file="/tmp/tmp_channel_hive_file"tmp_channel_hive_file_new="/tmp/ ...

  6. .NET开发中经常用到的扩展方法

    整理一下自己经常用到的几个扩展方法,在实际项目中确实好用,节省了不少的工作量. 1  匿名对象转化 在WinForm中,如果涉及较长时间的操作,我们一般会用一个BackgroundWorker来做封装 ...

  7. AndroidStudio的一些坑

    以下环境为Android Studio 1.3.2,Gradle 2.7(as自带2.4,另下载的2.7) 编译时提示Multiple dex files define: Lcom/sina/weib ...

  8. 转:RTMPDump源代码分析

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

  9. xcode中嵌入framework(接入快用最新SDK遇到的问题)

      但xcode设置中并没有找到Embed Frameworks这个选项,使用以下方式添加 当遇到dyld: Library not loaded:xxxx  Reason: image not fo ...

  10. webRTC-实时流媒体的福音

    WebRTC是一项在浏览器内部进行实时视频和音频通信的技术,是谷歌2010年以6820万美元收购Global IP Solutions公司而获得的一项技术.[1] WebRTC实现了基于网页的视频会议 ...