參考地址:http://blog.csdn.net/dlmu2001/article/details/6213377java
注:本系列博客是在原博主博客基礎上增長了本身的理解和片斷,能夠看源博文得到清晰的結構web
摘要:瀏覽器的請求通常是以頁面請求爲單位,當用戶經過網址輸入一個URL,瀏覽器就開始一個頁面請求。而一個頁面請求可能包含一到多個頁面子幀,以及圖片、CSS和插件等派生子資源。Page類就是用來對應這樣的頁面請求。Page類是WebKit中很是重要的類,它就像內核對外的一個聚合器。chrome
瀏覽器的請求通常是以頁面請求爲單位,當用戶經過網址輸入一個URL,瀏覽器就開始一個頁面請求。而一個頁面請求可能包含有一到多個子幀,以及圖片、CSS和插件等派生子資源。Page類就是用來對應這樣的頁面請求。前進後退,導航,編輯,右鍵菜單,設置,Inspector等這些用戶參與的動做,大部分是同Page相關的。而標記語言解析、排版、加載則更多的同Frame相關canvas
咱們經過幾個圖來看Qt移植中Page類同應用之間的關係。windows
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()cookie
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::QWebFrameDatasession
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類自己並無多少代碼。app
類成員結構:
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 }
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來維護。
WebCore中的設置相關的類,瀏覽器應用的很多配置、選項同該類相關,Qt移植中,應用在建立Page對象後,會根據Page::settings來實例化QWebSetting
原生窗口接口類,參考原博主文章"WebKit中的Chrome和ChromeClient"
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: 同編輯功能相關,好比拷貝、剪切、刪除等操做。