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 汇编器和链接编辑器的输出) ...
随机推荐
- 如何在ASP.NET中用C#将XML转换成JSON
本文旨在介绍如果通过C#将获取到的XML文档转换成对应的JSON格式字符串,然后将其输出到页面前端,以供JavaScript代码解析使用.或许你可以直接利用JavaScript代码通过Ajax的方式来 ...
- CentOS下搭建NFS服务器总结
环境介绍: . 服务器: 192.168.0.100 . 客户机: 192.168.0.101 安装软件包: . 服务器和客户机都要安装nfs 和 rpcbind 软件包: yum -y instal ...
- android eclipse关联源码,以及源码(代码)以及jar查看软件
1.eclipse关联源码 步骤一:自已百度下载相应版本的源码,我这里是4.2也就是API=17的版本. 步骤二:找到你安装sdk的目录, G:\Program Files\adt-bundle-wi ...
- Android Application 对象介绍
What is Application Application和Actovotu,Service一样是android框架的一个系统组件,当android程序启动时系统会创建一个 application ...
- 一些新的web性能优化技术
1.IconFont:图标字体,这是近年来新流行的一种以字体代替图片的技术.它可以适应任何分辨率而不会出现图片模糊问题,与图片相比它具有更小的容量,更高的灵活性(像字体一样可以设置图标大小.颜色.透明 ...
- Struts2入门3 深入学习
Struts2入门3 深入学习 处理结果和异常 前言: Struts学习的差不多了,还有最后的一点就收官了就是结果处理和异常处理.前面学习Struts主要围绕就是Action以及struts.xml配 ...
- 解决中64位Win7系统上PLSQL无法连接ORACLE的方法(PLSQL无法识别ORACLE_HOME的配置)
最近新安装了64位的Win7系统,工作中需要用oracle数据库,而数据库是公司IT的DBA进行管理和维护的. 我们只需要连接上去进行使用就可以了,于是我就在自己的机器上安装了oracle clien ...
- 使用Excel制作万年历(可打印)
先来看看A4纸打印效果,其他功能后续继续完善中. 年份数据字典(农历节日) 农历节日表 年度 春节 元宵节 龙抬头 端午节 六月六 七月七 七月十五 仲秋节 除夕 2010年02月14日 2010年0 ...
- git stash恢复
今天下午在使用Git命令进行代码管理时,因为自己一时疏忽直接把自己一天的劳动成果给弄丢了,这还了得,吓死宝宝了.真的,相信有代码丢失的朋友肯定能体会我当时的心情,不能体会我心情的那就祝你们也丢次代码, ...
- 电子病历,到底是用BS还是CS
电子病历,到底是用BS还是CS 袁永福 2014-8-19 前言:前几天下午去开发医疗软件的S公司,旁听了他们的内部技术讨论会议.他们目前的电子病历是B/S架构,会上一群人讨论起用C/S重构电子病历系 ...