原文地址: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();
}

最新文章

  1. IIS访问共享文件详解
  2. 5. UIView
  3. 在发送ajax请求时加时间戳或者随机数去除js缓存
  4. 日常总结——JSP篇(补)
  5. 不要怂,就是GAN (生成式对抗网络) (一)
  6. CSS3魔法堂:认识@font-face和Font Icon
  7. Excel 操作类
  8. wap网站seo如何优化呢?
  9. spring aop expression简单说明
  10. [BZOJ 2178] 圆的面积并 【Simpson积分】
  11. Android学习笔记--存储方案(SharedPreference、文件IO)
  12. 【iOS】彩虹渐变色 的 Swift 实现
  13. MJRefresh在UITableView中的使用
  14. Eclipse 项目导入 Studio Debug运行卡死在进入界面
  15. Redisson入门
  16. C++ Primer 有感(标准库类型)
  17. Linux:ftp服务本地用户,虚拟用户配置
  18. python版本的简单贪吃蛇
  19. mybatis查询修改同时操作
  20. Oracle HAVING子句 - 转

热门文章

  1. MongoDB与.NET结合使用二(安全)
  2. [BTS] SQL Adapter. New transaction cannot enlist in the specified transaction coordinator
  3. [BTS] Faulting application name: BTSNTSvc.exe, version: 3.9.469.0, time stamp: 0x4c547e09
  4. JS几种数组遍历方式以及性能分析对比
  5. [Java拾遗二]Tomact及Http 部分总结.
  6. NodeJS-图片上传(Express)
  7. 修改JSONArray里所有key的值
  8. Eclipse崩溃后无法启动的问题解决
  9. RFID 读写器 Reader Writer Cloner
  10. Asp.net WebApi + EF 单元测试架构 DbContext一站到底