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)
1 QWebPagePrivate::QWebPagePrivate(QWebPage *qq) 2 : q(qq) 3 , page(0) 4 , mainFrame(0) 5 #ifndef QT_NO_UNDOSTACK 6 , undoStack(0) 7 #endif 8 , insideOpenCall(false) 9 , m_totalBytes(0) 10 , m_bytesReceived() 11 , clickCausedFocus(false) 12 , networkManager(0) 13 , forwardUnsupportedContent(false) 14 , smartInsertDeleteEnabled(true) 15 , selectTrailingWhitespaceEnabled(false) 16 , linkPolicy(QWebPage::DontDelegateLinks) 17 , viewportSize(QSize(0, 0)) 18 , pixelRatio(1) 19 #ifndef QT_NO_CONTEXTMENU 20 , currentContextMenu(0) 21 #endif 22 , settings(0) 23 , useFixedLayout(false) 24 , pluginFactory(0) 25 , inspectorFrontend(0) 26 , inspector(0) 27 , inspectorIsInternalOnly(false) 28 , m_lastDropAction(Qt::IgnoreAction) 29 { 30 WebCore::InitializeLoggingChannelsIfNecessary(); //初始化环境变量 QT_WEBKIT_LOG 指定的log channel,xitongji 31 ScriptController::initializeThreading(); //初始化线程, 注意:必须在主线程里面调用。可以安全多次调用,可重入//仅仅初始化一次 32 WTF::initializeMainThread(); 33 WebCore::SecurityOrigin::setLocalLoadPolicy(WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData); 34 35 WebPlatformStrategies::initialize(); 36 37 #if USE(QTKIT) 38 InitWebCoreSystemInterface(); 39 #endif 40 41 Page::PageClients pageClients; 42 pageClients.chromeClient = new ChromeClientQt(q); 43 pageClients.contextMenuClient = new ContextMenuClientQt(); 44 pageClients.editorClient = new EditorClientQt(q); 45 pageClients.dragClient = new DragClientQt(q); 46 pageClients.inspectorClient = new InspectorClientQt(q); 47 #if ENABLE(DEVICE_ORIENTATION) 48 pageClients.deviceOrientationClient = new DeviceOrientationClientQt(q); 49 pageClients.deviceMotionClient = new DeviceMotionClientQt(q); 50 #endif 51 #if ENABLE(CLIENT_BASED_GEOLOCATION) 52 if (QWebPagePrivate::drtRun) 53 pageClients.geolocationClient = new GeolocationClientMock(); 54 else 55 pageClients.geolocationClient = new GeolocationClientQt(q); 56 #endif 57 page = new Page(pageClients); 58 59 // By default each page is put into their own unique page group, which affects popup windows 60 // and visited links. Page groups (per process only) is a feature making it possible to use 61 // separate settings for each group, so that for instance an integrated browser/email reader 62 // can use different settings for displaying HTML pages and HTML email. To make QtWebKit work 63 // as expected out of the box, we use a default group similar to what other ports are doing. 64 page->setGroupName("Default Group"); 65 66 #if ENABLE(CLIENT_BASED_GEOLOCATION) 67 // In case running in DumpRenderTree mode set the controller to mock provider. 68 if (QWebPagePrivate::drtRun) 69 static_cast<GeolocationClientMock*>(pageClients.geolocationClient)->setController(page->geolocationController()); 70 #endif 71 settings = new QWebSettings(page->settings()); 72 73 history.d = new QWebHistoryPrivate(static_cast<WebCore::BackForwardListImpl*>(page->backForwardList())); 74 memset(actions, 0, sizeof(actions)); 75 76 PageGroup::setShouldTrackVisitedLinks(true); 77 78 #if ENABLE(NOTIFICATIONS) 79 NotificationPresenterClientQt::notificationPresenter()->addClient(); 80 #endif 81 }
2, QWebPagePrivate::createMainFrame()
1 void QWebPagePrivate::createMainFrame() 2 { 3 if (!mainFrame) { 4 QWebFrameData frameData(page); 5 mainFrame = new QWebFrame(q, &frameData); 6 7 emit q->frameCreated(mainFrame); 8 } 9 }
3,QWebFrameData::QWebFrameData
1 QWebFrameData::QWebFrameData(WebCore::Page* parentPage, WebCore::Frame* parentFrame, 2 WebCore::HTMLFrameOwnerElement* ownerFrameElement, 3 const WTF::String& frameName) 4 : name(frameName) 5 , ownerElement(ownerFrameElement) 6 , page(parentPage) 7 , allowsScrolling(true) 8 , marginWidth(0) 9 , marginHeight(0) 10 { 11 frameLoaderClient = new FrameLoaderClientQt(); 12 frame = Frame::create(page, ownerElement, frameLoaderClient); 13 14 // FIXME: All of the below should probably be moved over into WebCore 15 frame->tree()->setName(name); 16 if (parentFrame) 17 parentFrame->tree()->appendChild(frame); 18 }
Page类通过组合其他类的方式,实现了很多功能,Page类本身并没有多少代码。
类成员结构:
1 class Page { 2 WTF_MAKE_NONCOPYABLE(Page); 3 friend class Settings; 4 public: 5 static void scheduleForcedStyleRecalcForAllPages(); 6 7 // It is up to the platform to ensure that non-null clients are provided where required. 8 struct PageClients { 9 WTF_MAKE_NONCOPYABLE(PageClients); WTF_MAKE_FAST_ALLOCATED; 10 public: 11 PageClients(); 12 ~PageClients(); 13 14 ChromeClient* chromeClient; 15 ContextMenuClient* contextMenuClient; 16 EditorClient* editorClient; 17 DragClient* dragClient; 18 InspectorClient* inspectorClient; 19 OwnPtr<PluginHalterClient> pluginHalterClient; 20 GeolocationClient* geolocationClient; 21 DeviceMotionClient* deviceMotionClient; 22 DeviceOrientationClient* deviceOrientationClient; 23 RefPtr<BackForwardList> backForwardClient; 24 SpeechInputClient* speechInputClient; 25 MediaStreamClient* mediaStreamClient; 26 }; 27 28 Page(PageClients&); 29 ~Page(); 30 31 enum ViewMode { 32 ViewModeInvalid, 33 ViewModeWindowed, 34 ViewModeFloating, 35 ViewModeFullscreen, 36 ViewModeMaximized, 37 ViewModeMinimized 38 }; 39 40 private: 41 OwnPtr<Chrome> m_chrome; 42 OwnPtr<SelectionController> m_dragCaretController; 43 44 #if ENABLE(ACCELERATED_2D_CANVAS) 45 RefPtr<SharedGraphicsContext3D> m_sharedGraphicsContext3D; 46 #endif 47 48 #if ENABLE(DRAG_SUPPORT) 49 OwnPtr<DragController> m_dragController; 50 #endif 51 OwnPtr<FocusController> m_focusController; 52 #if ENABLE(CONTEXT_MENUS) 53 OwnPtr<ContextMenuController> m_contextMenuController; 54 #endif 55 #if ENABLE(INSPECTOR) 56 OwnPtr<InspectorController> m_inspectorController; 57 #endif 58 #if ENABLE(CLIENT_BASED_GEOLOCATION) 59 OwnPtr<GeolocationController> m_geolocationController; 60 #endif 61 #if ENABLE(DEVICE_ORIENTATION) 62 OwnPtr<DeviceMotionController> m_deviceMotionController; 63 OwnPtr<DeviceOrientationController> m_deviceOrientationController; 64 #endif 65 #if ENABLE(MEDIA_STREAM) 66 OwnPtr<MediaStreamController> m_mediaStreamController; 67 #endif 68 #if ENABLE(INPUT_SPEECH) 69 SpeechInputClient* m_speechInputClient; 70 OwnPtr<SpeechInput> m_speechInput; 71 #endif 72 OwnPtr<Settings> m_settings; 73 OwnPtr<ProgressTracker> m_progress; 74 75 OwnPtr<BackForwardController> m_backForwardController; 76 RefPtr<Frame> m_mainFrame; 77 78 mutable RefPtr<PluginData> m_pluginData; 79 80 RefPtr<RenderTheme> m_theme; 81 82 EditorClient* m_editorClient; 83 84 int m_frameCount; 85 String m_groupName; 86 bool m_openedByDOM; 87 88 bool m_tabKeyCyclesThroughElements; 89 bool m_defersLoading; 90 91 bool m_inLowQualityInterpolationMode; 92 bool m_cookieEnabled; 93 bool m_areMemoryCacheClientCallsEnabled; 94 float m_mediaVolume; 95 96 bool m_javaScriptURLsAreAllowed; 97 98 String m_userStyleSheetPath; 99 mutable String m_userStyleSheet; 100 mutable bool m_didLoadUserStyleSheet; 101 mutable time_t m_userStyleSheetModificationTime; 102 103 OwnPtr<PageGroup> m_singlePageGroup; 104 PageGroup* m_group; 105 106 JSC::Debugger* m_debugger; 107 108 double m_customHTMLTokenizerTimeDelay; 109 int m_customHTMLTokenizerChunkSize; 110 111 bool m_canStartMedia; 112 113 OwnPtr<PluginHalter> m_pluginHalter; 114 115 #if ENABLE(DOM_STORAGE) 116 RefPtr<StorageNamespace> m_sessionStorage; 117 #endif 118 119 #if ENABLE(NOTIFICATIONS) 120 NotificationPresenter* m_notificationPresenter; 121 #endif 122 123 ViewMode m_viewMode; 124 125 ViewportArguments m_viewportArguments; 126 127 double m_minimumTimerInterval; 128 129 OwnPtr<ScrollableAreaSet> m_scrollableAreaSet; 130 131 bool m_isEditable; 132 }
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: 同编辑功能相关,比如拷贝、剪切、删除等操作。