WebKit内核分析之Page
参考地址:http://blog.csdn.net/dlmu2001/article/details/6213377
注:本系列博客是在原博主博客基础上增加了自己的理解和片段,可以看源博文获得清晰的结构
摘要:浏览器的请求一般是以页面请求为单位,当用户通过网址输入一个URL,浏览器就开始一个页面请求。而一个页面请求可能包含一到多个页面子帧,以及图片、CSS和插件等派生子资源。Page类就是用来对应这样的页面请求。Page类是WebKit中非常重要的类,它就像内核对外的一个聚合器。
1. 概述
浏览器的请求一般是以页面请求为单位,当用户通过网址输入一个URL,浏览器就开始一个页面请求。而一个页面请求可能包含有一到多个子帧,以及图片、CSS和插件等派生子资源。Page类就是用来对应这样的页面请求。前进后退,导航,编辑,右键菜单,设置,Inspector等这些用户参与的动作,大部分是同Page相关的。而标记语言解析、排版、加载则更多的同Frame相关
我们通过几个图来看Qt移植中Page类同应用之间的关系。
QWebPage通过QWebPagePrivate维护Page类的指针,并在QWebPagePrivate的构造函数中实例化Page对象。QWebPage类通过之后的createMainFrame调用实例化QWebFrame,而在QWebFrameData的构造函数中,以Page指针为参数调用了 Frame::create创建出 Frame对象
1,QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
: q(qq)
, page()
, mainFrame()
#ifndef QT_NO_UNDOSTACK
, undoStack()
#endif
, insideOpenCall(false)
, m_totalBytes()
, m_bytesReceived()
, clickCausedFocus(false)
, networkManager()
, forwardUnsupportedContent(false)
, smartInsertDeleteEnabled(true)
, selectTrailingWhitespaceEnabled(false)
, linkPolicy(QWebPage::DontDelegateLinks)
, viewportSize(QSize(, ))
, pixelRatio()
#ifndef QT_NO_CONTEXTMENU
, currentContextMenu()
#endif
, settings()
, useFixedLayout(false)
, pluginFactory()
, inspectorFrontend()
, inspector()
, inspectorIsInternalOnly(false)
, m_lastDropAction(Qt::IgnoreAction)
{
WebCore::InitializeLoggingChannelsIfNecessary(); //初始化环境变量 QT_WEBKIT_LOG 指定的log channel,xitongji
ScriptController::initializeThreading(); //初始化线程, 注意:必须在主线程里面调用。可以安全多次调用,可重入//仅仅初始化一次
WTF::initializeMainThread();
WebCore::SecurityOrigin::setLocalLoadPolicy(WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData); WebPlatformStrategies::initialize(); #if USE(QTKIT)
InitWebCoreSystemInterface();
#endif 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); // By default each page is put into their own unique page group, which affects popup windows
// and visited links. Page groups (per process only) is a feature making it possible to use
// separate settings for each group, so that for instance an integrated browser/email reader
// can use different settings for displaying HTML pages and HTML email. To make QtWebKit work
// as expected out of the box, we use a default group similar to what other ports are doing.
page->setGroupName("Default Group"); #if ENABLE(CLIENT_BASED_GEOLOCATION)
// In case running in DumpRenderTree mode set the controller to mock provider.
if (QWebPagePrivate::drtRun)
static_cast<GeolocationClientMock*>(pageClients.geolocationClient)->setController(page->geolocationController());
#endif
settings = new QWebSettings(page->settings()); history.d = new QWebHistoryPrivate(static_cast<WebCore::BackForwardListImpl*>(page->backForwardList()));
memset(actions, , sizeof(actions)); PageGroup::setShouldTrackVisitedLinks(true); #if ENABLE(NOTIFICATIONS)
NotificationPresenterClientQt::notificationPresenter()->addClient();
#endif
}
2, QWebPagePrivate::createMainFrame()
void QWebPagePrivate::createMainFrame()
{
if (!mainFrame) {
QWebFrameData frameData(page);
5 mainFrame = new QWebFrame(q, &frameData); emit q->frameCreated(mainFrame);
}
}
3,QWebFrameData::QWebFrameData
QWebFrameData::QWebFrameData(WebCore::Page* parentPage, WebCore::Frame* parentFrame,
WebCore::HTMLFrameOwnerElement* ownerFrameElement,
const WTF::String& frameName)
: name(frameName)
, ownerElement(ownerFrameElement)
, page(parentPage)
, allowsScrolling(true)
, marginWidth()
, marginHeight()
{
frameLoaderClient = new FrameLoaderClientQt();
frame = Frame::create(page, ownerElement, frameLoaderClient); // FIXME: All of the below should probably be moved over into WebCore
frame->tree()->setName(name);
if (parentFrame)
parentFrame->tree()->appendChild(frame);
}
Page类通过组合其他类的方式,实现了很多功能,Page类本身并没有多少代码。
类成员结构:
class Page {
WTF_MAKE_NONCOPYABLE(Page);
friend class Settings;
public:
static void scheduleForcedStyleRecalcForAllPages(); // It is up to the platform to ensure that non-null clients are provided where required.
struct PageClients {
WTF_MAKE_NONCOPYABLE(PageClients); WTF_MAKE_FAST_ALLOCATED;
public:
PageClients();
~PageClients(); ChromeClient* chromeClient;
ContextMenuClient* contextMenuClient;
EditorClient* editorClient;
DragClient* dragClient;
InspectorClient* inspectorClient;
OwnPtr<PluginHalterClient> pluginHalterClient;
GeolocationClient* geolocationClient;
DeviceMotionClient* deviceMotionClient;
DeviceOrientationClient* deviceOrientationClient;
RefPtr<BackForwardList> backForwardClient;
SpeechInputClient* speechInputClient;
MediaStreamClient* mediaStreamClient;
}; Page(PageClients&);
~Page(); enum ViewMode {
ViewModeInvalid,
ViewModeWindowed,
ViewModeFloating,
ViewModeFullscreen,
ViewModeMaximized,
ViewModeMinimized
}; private:
OwnPtr<Chrome> m_chrome;
OwnPtr<SelectionController> m_dragCaretController; #if ENABLE(ACCELERATED_2D_CANVAS)
RefPtr<SharedGraphicsContext3D> m_sharedGraphicsContext3D;
#endif #if ENABLE(DRAG_SUPPORT)
OwnPtr<DragController> m_dragController;
#endif
OwnPtr<FocusController> m_focusController;
#if ENABLE(CONTEXT_MENUS)
OwnPtr<ContextMenuController> m_contextMenuController;
#endif
#if ENABLE(INSPECTOR)
OwnPtr<InspectorController> m_inspectorController;
#endif
#if ENABLE(CLIENT_BASED_GEOLOCATION)
OwnPtr<GeolocationController> m_geolocationController;
#endif
#if ENABLE(DEVICE_ORIENTATION)
OwnPtr<DeviceMotionController> m_deviceMotionController;
OwnPtr<DeviceOrientationController> m_deviceOrientationController;
#endif
#if ENABLE(MEDIA_STREAM)
OwnPtr<MediaStreamController> m_mediaStreamController;
#endif
#if ENABLE(INPUT_SPEECH)
SpeechInputClient* m_speechInputClient;
OwnPtr<SpeechInput> m_speechInput;
#endif
OwnPtr<Settings> m_settings;
OwnPtr<ProgressTracker> m_progress; OwnPtr<BackForwardController> m_backForwardController;
RefPtr<Frame> m_mainFrame; mutable RefPtr<PluginData> m_pluginData; RefPtr<RenderTheme> m_theme; EditorClient* m_editorClient; int m_frameCount;
String m_groupName;
bool m_openedByDOM; bool m_tabKeyCyclesThroughElements;
bool m_defersLoading; bool m_inLowQualityInterpolationMode;
bool m_cookieEnabled;
bool m_areMemoryCacheClientCallsEnabled;
float m_mediaVolume; bool m_javaScriptURLsAreAllowed; String m_userStyleSheetPath;
mutable String m_userStyleSheet;
mutable bool m_didLoadUserStyleSheet;
mutable time_t m_userStyleSheetModificationTime; OwnPtr<PageGroup> m_singlePageGroup;
PageGroup* m_group; JSC::Debugger* m_debugger; double m_customHTMLTokenizerTimeDelay;
int m_customHTMLTokenizerChunkSize; bool m_canStartMedia; OwnPtr<PluginHalter> m_pluginHalter; #if ENABLE(DOM_STORAGE)
RefPtr<StorageNamespace> m_sessionStorage;
#endif #if ENABLE(NOTIFICATIONS)
NotificationPresenter* m_notificationPresenter;
#endif ViewMode m_viewMode; ViewportArguments m_viewportArguments; double m_minimumTimerInterval; OwnPtr<ScrollableAreaSet> m_scrollableAreaSet; bool m_isEditable;
}
2. 类关系
2.1 PageGroup
PageGroup并不是用来对Page进行管理的,而是设计用来将一些具有共同的属性或者设置的Page编成组的,以方便对这些属性进行管理。
目前这些属性包括 localStorage的属性, indexDB,User Script,User StyleSheet等。最常见的同PageGroup相关的操作是维护已访问链接(如addVisitedLink等接口)。根据理解,假设webkit内核之上假设多个应用(浏览器是一个应用),比较可能得是,一个应用独立一个PageGroup。这里同多tab页没有关系,多tab页属于同一个PageGroup。原博主曾在maining group上就这个问题咨询过,一位RIM的同学给我举了一个例子,比如基于webkit的邮件程序,一方面他可能调用基于webkit的setting哟很大可能不一样,他们就使用不同的PageGroup
PageGroup中有这个Group已经安装并且使用的User Script和User StyleSheet的集合,一般在网页解析完毕后,这些User Script和User StyleSheet会插入到Document中
PageGroup中还维护了Local Storage和IndexDB相关的设置,比如他们的Path,上限等,通过GroupSettings类实现
PageGroup创建以后,每次创建一个新的Page对象,会通过addPage接口加入到这个PageGroup的m_pages中。
每次有导航行为发生的时候,会调用 addVisitedLink来将URL加入到已访问链接中。如果浏览器要跟踪已访问的接口,则在初始化的时候必须调用PageGroup::setShouldTrackVisitedLinks,且参数为true。此处shouldTrackVisitedLinks是一个静态的全局变量,也就是说,所有应用维护一样的行为(一个应用将其设置为false,会影响到其他同样基于此核的应用)?
Page类中维护了PageGroup指针,并提供了group接口,这是个lazy接口,如果m_group不存在,会调用InitGroup来创建一个。对于Page类来说,如果没有设置GroupName,则在初始化的时候会生成一个空的GroupName的PageGroup,由m_singlePageGroup维护,并把指针赋给m_group,如果以非空的名字调用了setGroupName,则会重新创建PageGroup,此时这个PageGroup由m_group来维护。
2.2 Setting
WebCore中的设置相关的类,浏览器应用的不少配置、选项同该类相关,Qt移植中,应用在创建Page对象后,会根据Page::settings来实例化QWebSetting
2.3 Chrome
原生窗口接口类,参考原博主文章"WebKit中的Chrome和ChromeClient"
2.4 其它
SelectionController 负责管理Page中的选取操作,绝大部分选取操作是基于Frame的,只有在Frame额Selection为空的时候,对焦点游标的绘制工作才会使用到Page类的SelectionController
SharedGraphicsContext3D: 共享3D图形上下文,为了优化2D显示而加入。在加速2D canvas中,引入的DrawingBuffer的概念,SharedGraphicsContext3D提供了createDrawingBuffer来创建DrawingBuffer
DragController: 拖拽控制器。 Chrome的超级拖拽功能同这个相关?此后博主会求证
FocusController: 焦点控制器。 考虑到焦点会在各个frame之间切换,所以由Page类维护焦点控制器最合适不过
ContextMenuController:右键下来菜单控制器
InspectorController: Inspector控制器,浏览器中的很多开发工具都同这个类相关
GeolocationController: 定位服务控制器
DeviceMotionController:设备移动控制器
DeviceOrientationController: 设备方向控制器
SpeechInputClient: 语音输入client
ProgressTracker: 进度跟踪
BackForwardController: 前进后退操作控制
Frame:一个Page由至少一个主帧和若干个其他子帧构成
HistoryItem:历史记录
PluginData:插件相关,未来可能同PluginDatabase类合并。主要是初始化Plugin的信息
PluginHalter: 用来控制Plugin的停止和重新开始
RenderTheme:这个类提供了控件的渲染和绘制接口。Qt移植中,RenderThemeQt是RenderTheme接口的具体实现
EditorClient: 同编辑功能相关,比如拷贝、剪切、删除等操作。
WebKit内核分析之Page的更多相关文章
- webkit内核分析之 Frame
参考地址:http://blog.csdn.net/dlmu2001/article/details/6164873 1. 描述 Frame类是WebCore内核同应用之间联系的一个重要的类.它 ...
- WebKit内核分析之FrameLoader
参考地址:http://blog.csdn.net/dlmu2001/article/details/6168545 FrameLoader类负责一个Frame的加载,在Frame的流程中起到非常重要 ...
- [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析
[WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285 ...
- css3中-moz、-ms、-webkit,-o分别代表的意思,以及微信浏览器内核分析
这种方式在业界上统称:识别码.前缀 //-ms代表[ie]内核识别码 //-moz代表火狐[firefox]内核识别码 //-webkit代表谷歌[chrome]/苹果[safari]内核识别码 // ...
- Linux内核分析(五)----字符设备驱动实现
原文:Linux内核分析(五)----字符设备驱动实现 Linux内核分析(五) 昨天我们对linux内核的子系统进行简单的认识,今天我们正式进入驱动的开发,我们今后的学习为了避免大家没有硬件的缺陷, ...
- PostgreSQL内核分析——BTree索引
文中附图参考至<PostgreSQL数据库内核分析> (一)概念描述 B+树是一种索引数据结构,其一个特征在于非叶子节点用于描述索引,而叶子节点指向具体的数据存储位置.在PostgreSQ ...
- 【WebKit内核 CEF3 】 第一篇:下载分支代码并本地编译
关于CEF Chromium Embedded Framework 简单说就是 WebKit内核的 对外绑定. 当前主流浏览器内核 一.Trident内核代表产品Internet Explorer ...
- linux内核分析作业8:理解进程调度时机跟踪分析进程调度与进程切换的过程
1. 实验目的 选择一个系统调用(13号系统调用time除外),系统调用列表,使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 分析汇编代码调用系统调用的工作过程,特别是参数的传递的方 ...
- Linux内核分析作业7:Linux内核如何装载和启动一个可执行程序
1.可执行文件的格式 在 Linux 平台下主要有以下三种可执行文件格式: 1.a.out(assembler and link editor output 汇编器和链接编辑器的输出) ...
随机推荐
- 【转】关于Mahalanobis距离的笔记
Mahalanobis距离是用来度量一个点P和一个分布D之间的距离,它是衡量点P与分布D的均值之间存在多少个标准差的一个多维泛化版本. 如果P就位于分布D的均值处,则该距离为0:该距离随着P的偏离均值 ...
- javascript中对象函数继承的概念
什么是函数对象?这个对象既是通常意义上的对象,又可以加上括号直接执行的函数. 产生函数对象的方式有两种:1.通过function关键字产生:var fn = function(){};2.实例化Fun ...
- 《Effective STL中文版》前言
<Effective STL中文版>前言 我第一次写关于STL(Standard Template Library,标准模板库)的介绍是在1995 年,当时我在More Effec ...
- javaweb学习总结(七)——HttpServletResponse对象(一)
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象.request和response对象即然代表请求和响应,那我们要 ...
- Python包的相对导入时出现错误的解决方法
在练习Python中package的相对导入时,即 from . import XXX 或者 from .. import XXX 时会遇到这样两个错误: SystemError: Parent mo ...
- nodejs gearman redis
export NODE_PATH=/root/gearman-1.1.2/node_modulesnpm install gearmanodenpm install redis w.js var re ...
- Windows server 2008 R2充当路由器实现网络的互联(转)
1.路由器的工作原理 当IP子网中的一台主机发送IP分组给同一IP子网的另一台主机时,它将直接把IP分组送到网络上,对方就能收到.而要送给不同IP子网上的主机时,它要 选择一个能到达目的子网上的路由器 ...
- Autosizer应用程序窗口控制工具
Autosizer是一个系统辅助软件,窗口控制工具,它能指定程序窗口的大小位置置顶等,可以将窗口最大化,最小化,比如在需要截图的时候可以讲窗口设定大小640*480,然后用FSCapture捕捉活动窗 ...
- [Aaronyang] 写给自己的WPF4.5 笔记21 [3d课 2/4]
1. 当然复杂的3d模型我们是可以通过更专业的工具做出来,然后导入项目中,我们只是方便演示,选择简单的图形. Tip: 关于摄像机的NearPlaneDistance和FarPlaneDistance ...
- 在JS中设置Select和radio选中
<select id="Gender" name="Gender"> <option value="1">男< ...