WebKit內核分析之Page

參考地址:http://blog.csdn.net/dlmu2001/article/details/6213377java

注:本系列博客是在原博主博客基礎上增長了本身的理解和片斷,能夠看源博文得到清晰的結構web

 

摘要:瀏覽器的請求通常是以頁面請求爲單位,當用戶經過網址輸入一個URL,瀏覽器就開始一個頁面請求。而一個頁面請求可能包含一到多個頁面子幀,以及圖片、CSS和插件等派生子資源。Page類就是用來對應這樣的頁面請求。Page類是WebKit中很是重要的類,它就像內核對外的一個聚合器。chrome

 

1.    概述

      瀏覽器的請求通常是以頁面請求爲單位,當用戶經過網址輸入一個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     }

 

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: 同編輯功能相關,好比拷貝、剪切、刪除等操做。

相關文章
相關標籤/搜索