zoukankan      html  css  js  c++  java
  • 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: 同编辑功能相关,比如拷贝、剪切、删除等操作。

  • 相关阅读:
    OSVERSIONINFOEX structure
    VS系列开发工具发展概述
    VS2008与QT4.6集成
    windows nt service 框架
    Rair
    如何在进程之间共享内核对象
    GOOGLE
    如何获取错误消息说明使用 FormatMessage API
    EnableDebugPriv;
    汇编语言资料
  • 原文地址:https://www.cnblogs.com/lfsblack/p/5417266.html
Copyright © 2011-2022 走看看