webkit.org 中有一篇文章讲述how to load frame,下面结合qt的demobrowser来讲述一下这个过程。

第一个流程: browser.exe 启动后默认加载的homepage这个过程是怎样的?

1.   WebView *webView = new WebView; // tabwidget  中

创建一个webview,注意这儿webview是自己的代码,它派生自qwebview

2.    webView->webPage = new WebPage ; // webview 中

webview创建一个webpage, 这儿webpage是派生自qwebpage

3.    qwebpage的构造函数中 d(new QWebPagePrivate(this)) , 其中d 是QWebPagePrivate*

4. QWebPagePrivate::QWebPagePrivate(QWebPage *qq) 构造中

a) 记录了QWebPage*

b) 初始化了jsc线程环境

c) 设置本地加载安全选项

d) create ChromeClientQt   chromeClient = new ChromeClientQt(q);

这儿ChromeClientQt  派生自 ChromeClient

这儿ChromeClient 应该是webkit定义的一个必须实现的接口,用以实现ui的一些细节。

chromeclientqt 还有一个eventloop变量,QEventLoop.

e) contextMenuClient = new ContextMenuClientQt(); // chromeclient 类似

f) 最重要的是,创建了Page对象

page = new Page(chromeClient, contextMenuClient, editorClient,

new DragClientQt(q), new InspectorClientQt(q), 0, 0);

这个对象按照我的理解,应该是webkit意义上的一个网页的root。

之前看到的qtwebview,qtwebpage都只是外部包装。

这儿可以看到webkit的一个重要设计,也可以成为依赖注入,即webkit将那些具体实现抽象为一些接口,

具体表现为Page的构造函数的参数,即这些是有特定的webkitport来提供实现体的,当page需要做一些具体操作时候都通过这些接口发生呼叫。

从这些接口,基本上夜可以看出被剥离出去的实现是   外观展示方面的比如chromeclientqt,上下文菜单的contextmenuqt,拖拽的,调试的等等。

举例来说常用的js函数的alert 最终在浏览器环境下,最终呼叫的是通过chromeclient实现体内的实现。

4.1. 进入Page的构造。 page对象仔细观察发现是个非常庞大的对象,它具有很多逻辑在里面:

a) 构造了一个Chrome对象,注意这个对象是个proxy对象,它的具体实现是采用了chromeclientqt。

而这个对象又实现了一个HostWnd接口, 当然这个接口最终的实现是通过chromeclientqt来实现的,

这个手法,首先通过HostWnd定义了一个Page运行需要一个宿主窗口,并且定义了它的行为; 第二通过       外部的实现注入了具体的ChromeClient的实现。所以代码中比较多见,

void Chrome::invalidateWindow(const IntRect& updateRect, bool immediate)

{

//m_client is a ChromeClient* impl by ChromeClientQt

m_client->invalidateWindow(updateRect, immediate);

}

另外的contextmenuclient,editorclient也类似,不过有一点不同,它们没有专门再写一个雷比如叫做editclient 然后再使用editclientqt的impl转发,我看了下代码,原因应该是chromeclient or chrom承担的ui业务相对更多,所以chrome这个类似实际上在转发呼叫impl的同时部分逻辑也做过写额外处理。

即完全使用impl不能完成。

b)创建了一个setting对象

c) 调试,插件行为的一些处理

4.2 将当前page加入history ? 这个有待后续深入研究。

后续就是创建一个frame了,所以从这点上来说也大致可以看出webkit的结构,貌似是page ---》 frame;

5. QWebFrame *QWebPage::mainFrame()被触发

6. void QWebPagePrivate::createMainFrame()

7. 这个时候一个临时对象QWebFrameData 出现了

void QWebPagePrivate::createMainFrame()

{

if (!mainFrame) {

QWebFrameData frameData(page);

mainFrame = new QWebFrame(q, &frameData);

emit q->frameCreated(mainFrame);

}

}

7.1 创建了一个frameloaderclient;

frameLoaderClient = new FrameLoaderClientQt();

从webkit的文档,大致可以看到一个frameloader需要做的事情

a) 下载

b) 创建documentloader

c) 还有很多,后续继续观察

7.2    // 创建一个frame

frame = Frame::create(page, ownerElement, frameLoaderClient);

这是一个重要过程,因为frame对象本身很重要.

Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)

手法和之前创建page类似,也将和加载,下载等细节操作impl 给了frameloaderclient;

先来看看frame的几个重要成员

Page* m_page;

mutable FrameTree m_treeNode;

mutable FrameLoader m_loader;

mutable RedirectScheduler m_redirectScheduler;

mutable RefPtrm_domWindow;

HashSetm_liveFormerWindows;

HTMLFrameOwnerElement* m_ownerElement;

RefPtrm_view;

RefPtrm_doc;

ScriptController m_script;

我们大致可以推断,webkit中的frame实际上至少具有

a) 内置一个frametree,这个后续可以继续观察。

b) 有一个frameloader ,后续观察

c) 有一个domwindow属于这个frame

d) 有一个ownerelement,现在还不知道干嘛的

e) 有一个frameview ,现在不知道?

f) document 貌似属于frame

读到这儿,我强烈想继续指导frame,page,doc,view 这些是如何关系,如何关联?

7.2.1   if (!ownerElement) {

page->setMainFrame(this);

本测试用例中,ownerelement为null;所以为page设置了mainframe;

所以貌似可以做出一个推断,page 其实只有一个mainframe,这个貌似也能从page的代码得到佐证;

另外frame本身则可以含有一个frametree,这个后续继续观察? 至少page和frame的关系这儿可以得到验证。

7.3  mainFrame = new QWebFrame(q, &frameData);

frameData含有了一个frame,这儿qtwebpageprivate的

void QWebPagePrivate::createMainFrame()

{

if (!mainFrame) {

QWebFrameData frameData(page);

mainFrame = new QWebFrame(q, &frameData);

emit q->frameCreated(mainFrame);

}

}

QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)

: QObject(parent)

, d(new QWebFramePrivate)

{

d->page = parent;

d->init(this, frameData);

if (!frameData->url.isEmpty()) {

WebCore::ResourceRequest request(frameData->url, frameData->referrer);

d->frame->loader()->load(request, frameData->name, false);

}

}

从这儿qt貌似确实将qewebpage作为qwebframe的parent呵呵,又验证了page确实含有frame;

QWebFramePrivate  这个对象的用法在qt的部分qwebXXX都有类似用法。。。

7.3.1d->init(this, frameData);

a) 设置了frameloaderclient的qwebframe,webframe两个对象

这个过程中由于qwebframe就绪了,所以设置了一些关注qwebframe的signal

b) 对frame执行init操作

void FrameLoader::init()

frameloader在webkit的文档中有描述 "The FrameLoader is in charge of loading documents into Frames."

// Document loaders for the three phases of frame loading. Note that while

// a new request is being loaded, the old document loader may still be referenced.

// E.g. while a new request is in the "policy" state, the old document loader may

// be consulted in particular as it makes sense to imply certain settings on the new loader.

RefPtrm_documentLoader;

RefPtrm_provisionalDocumentLoader;

RefPtrm_policyDocumentLoader;

setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, "")), SubstituteData()).get());

setProvisionalDocumentLoader(m_policyDocumentLoader.get());

setState(FrameStateProvisional);

之后最终呼叫 (这个和具体的操作相关,至少目前这个首次打开新页面是如此)

void FrameLoader::transitionToCommitted(PassRefPtrcachedPage)

{ ....

setDocumentLoader(m_provisionalDocumentLoader.get());

setProvisionalDocumentLoader(0);

setState(FrameStateCommittedPage);

...

}

这样documentloader进入一个commited..,触发进入.

void FrameLoaderClientQt::transitionToCommittedForNewPage()

... void Frame::createView(const IntSize& viewportSize,

从这个角度推测,貌似frame确实和一个view关联...

setView(0);

RefPtrframeView;

if (isMainFrame) {

frameView = FrameView::create(this, viewportSize);

frameView->setFixedLayoutSize(fixedLayoutSize);

frameView->setUseFixedLayout(useFixedLayout);

} else

frameView = FrameView::create(this);

frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);

setView(frameView);

从上面这段代码来看,创建了一个mainframeview。。。

并且将它设置为当前frame的view

而frameview 的父类是scrollview,因此可以理解为这个view还确实是ui含义上的一个视图。

frameview创建之后,这个view已经和frame关联完成。

之后的frameloader::init 创建了document对象

void FrameLoader::init()

d ) void Document::attach()

RenderView 在这个过程中创建,具体细节以后再说。

e) void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin) 的继续执行导致

....   m_frame->domWindow()->setURL(document->url());

........ m_domWindow = DOMWindow::create(const_cast(this));

从而使得domwindow对象被创建.

整体上来说,第一阶段就是创建page,frame,view,document 等的关系,即将对象先建立起来。

第二阶段: void WebView::loadUrl(const QUrl &url)

{

m_initialUrl = url;

load(url);

}

// 从阅读browser代码,发现貌似有些效率问题

1. 在首次创建webview之后,会触发如上所述的一系列构建page,frame,document,loader等的过程,并且不管是否本次过程用户是否需要访问url,都一致使用about:blank, 所以整个过程进行了两次相当于。

自己写了一个简单的html, 通过抓包来观察过程。。。

/span>

"">

New Web Project

alert("defer");

/*window.onload = function()

{

alert("onload");

}*/

描述的过程。

第一个过程: bool DocumentLoader::startLoadingMainResource(unsigned long identifier)

最后:

发送出如下信息..

GET /test.html HTTP/1.1

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN) AppleWebKit/533.3 (KHTML, like Gecko) demobrowser/0.1 Safari/533.3

Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5

Connection: Keep-Alive

Accept-Encoding: gzip

Accept-Language: zh-CN,en,*

Host: 10.1.173.6

然后服务端返回了test.html 的content。

/span>

"">

New Web Project

alert("defer");

/*window.onload = function()

{

alert("onload");

}*/

这个就是mainresourceloader下载下来的。。。。

注意哦,这个时候全局的js函数还没有机会执行。。。。

通过上面这张图,可以看到在mainresourceloader拿到html content之后,开始初始化scriptcontrol.

之后依然在主线程中,全局的alert得到了机会执行。。。。

不过很悲剧的是我自己编译的qtwebkitd.dll  在添加alert之后会导致gui重入引起的crash,release编译的就没有问题,现在还不知道为什么,所以先注释掉了alert,继续观察subresourceloader。。

果然如愿看到了subresourceloader1的启动, 大致来说是html 下载完之后触发的。

更加精确来说应该是 html下载完成,内嵌的js得到执行后;

之后开始现在嵌入的资源,比如图片,脚本;  因此诸如dojo。addonload 这种通知这个时候肯定还发布出来,因为嵌入的js文件还没有开始下载;

整理一下思路:

1. html 内容下载

2. html内的内嵌js执行

3. 开始下载html ref的脚本和image等其他资源

4. 这些js下载之后也得到机会执行; 比如dojo.addonload 回调

5. 素有的外部资源下载结束,那么 window.onload 的到机会执行

另外如果通过firebug观察,会发现有个domcontentready的事件.

再仔细研究下

看看新的代码

dojo.registerModulePath("com","/js");

// 全局运行环境对象

var globalAdapter;

alert("enter");

window.addEventListener('DOMContentLoaded', domloaded, false);

function domloaded()

{

alert("domloaded");

}

function onLoad()

{

alert("onload");

}

dojo.addOnLoad(function()

{

alert("addonload");

})

function onUnload()

{

}

global ctx page, just for debug purpose

1. firebug首先看到的是enter 这个alert弹出,注意这个时候

这个时候发现,css,2个js,一个html都已经下载了,而alert也弹出来了,不过domcontentload事件还没有触发 。

事实上即使将 css文件放到body后面,在enter弹出来时候它也已经下载或者下载中了。

但是后面那张图片却还没有下载。

2.  越过enter这个elert

发现dojo的addonload被调用了,图片也下载了,且显示domcontentloaded完成。

因此貌似可以得出一个结论,内嵌的非外链的js 貌似较image下载先。

然后我做了个测试,将alert enter,移动到图片的代码后面,就发现alert出来时候,图片也下载了。

因此大概可以看出html文件被下载后,webkit应该对js,css样式做了优化处理,可以得以异步立刻下载,而图片还是需要等待之前的js执行完成。

domcontentload必须在所有js执行完成后才会触发。

3. 之后出现domcontentload的alert ,以及onload的alert

结合一些文档,domcontentload 和window.onload的区别是前者dom解析完成即可,后者需要等待外部图片等。

通过上面几个例子大致可以看出webkit加载执行这些页面的特征。

下面再通过debug 方式看看具体的事件,加深了解。

1. mainresource 加载完成后

可以看到mainresourceload后,就开始了解析过程 。。

第一个被解析到的就是dojojs这个文件 。。。。

通过firebug实际上我们之前执导当第一个elert("enter")执行的时候,其他js貌似也“同时”被下载了;

通过debug qtwebkit发现,具体加载流程和firefox4有区别,firefox4的优化更加好。

经过观察,发现qtwbebkit的具体执行流同firefox4还略有差别。

下面做一个例子,了解一下js的环境是如何准备起来的?

total

alert("enter");

因为之前的例子已经说明了:

1. 整个html文件下来

2. webkit 执行parsehtml,然后非内嵌的全局js得到执行机会。

下面再debugger中观察。。。

1.  果然如前

在收到数据后parse,然后检测到script标签,然后开始执行这个脚本。

从阅读代码来看,webkit的HTMLTokenizer 类具有执行脚本的方法。

经过一段复杂的判断,比如判断是否处于viewsource mode,是否脚本后跟了frameset 标签等,最后终于开始执行脚本。。。

state = scriptExecution(ScriptSourceCode(scriptString, m_doc->frame() ? m_doc->frame()->document()->url() : KURL(), startLine), state);

这个scriptstring 就是 alert("enter");

这儿webkit引入了一个类叫做ScriptSourceCode , 这个类实际上貌似在整个webkit范畴内表示“scriptcode”。。。

ScriptSourceCode(const String& source, const KURL& url = KURL(), int startLine = 1)

: m_provider(StringSourceProvider::create(source, url.isNull() ? String() : url.string()))

, m_code(m_provider, startLine)

, m_url(url)

{

}

接着看到ScriptSourceCode 实际上将主要工作托管给了StringSourceProvider.

再接下去看到

ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode)

{

return evaluateInWorld(sourceCode, mainThreadNormalWorld());

}

执行脚本call到了这儿,貌似在执行sourcecode的时候,一定要和一个“world”关联起来。

想想js必须要和context 关联,因此先然为这个world就是context吧,呵呵。。

DOMWrapperWorld 就是这个world?

这儿可以大概看看这个"world" 表示啥?

DOMWrapperWorld* mainThreadNormalWorld()

{

ASSERT(isMainThread());

static DOMWrapperWorld* cachedNormalWorld = normalWorld(*JSDOMWindow::commonJSGlobalData());

return cachedNormalWorld;

}

至少从这个代码上来看,dom世界是的js还确实只能在主线程中执行。

webworks是如何工作的或许以后可以看看 。

JSGlobalData* JSDOMWindowBase::commonJSGlobalData()

{

ASSERT(isMainThread());

static JSGlobalData* globalData = 0;

if (!globalData) {

globalData = JSGlobalData::createLeaked().releaseRef();

globalData->timeoutChecker.setTimeoutInterval(10000); // 10 seconds

#ifndef NDEBUG

globalData->mainThreadOnly = true;

#endif

globalData->clientData = new WebCoreJSClientData(globalData);

}

return globalData;

}

DOMWrapperWorld* normalWorld(JSC::JSGlobalData& globalData)

{

JSGlobalData::ClientData* clientData = globalData.clientData;

ASSERT(clientData);

return static_cast(clientData)->normalWorld();

}

WebCoreJSClientData(JSC::JSGlobalData* globalData)

: m_normalWorld(DOMWrapperWorld::create(globalData, true))

{

m_worldSet.add(m_normalWorld.get());

}

globaldata 实际是一个JSGlobalData ..

同时返回的DOMWrapperWorld* 实际上是 WebCoreJSClientData 创建。

最后执行到..

exec->globalData().timeoutChecker.start();

Completion comp = JSC::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), jsSourceCode, shell);

exec->globalData().timeoutChecker.stop();

这样大致可以看到dom 如何 同js 进行交互。

如果我们将目光放得高层一些,会发现存在如下的结构。。。

webcore , javascriptcore  它们实际上是两个相对独立的组件。 特别在chrome v8也是一个独立的js 引擎。

那么为了让webcore 或者说 html dom 和js 很好的结合起来,又引入了。。。

webcore/bindings 这个目录下的对象就是充当了webcore和javascriptcore的birdge。。。

我们可以看到scriptcontroller , ScriptValue, jshtmlXXX 很多对象。

因此如果要将qtwebkit使用v8估计只要让这个bridge 能够很好的port 到v8思路应该是如此。

qt android webview,qt browser 加载一个webview过程相关推荐

  1. Android ListView避免多线程加载一个同一资源

    当我们的ListView中的Item包含图片,而且这些图片是同一资源,我们用多线程去加载图片,这时候可能就发生了这种情况. 比如线程是人,第一个人去做加载图片到缓存的工作,还没做好时第二个人要这同一张 ...

  2. android webview静态方法,android – 将静态HTML加载到Webview中

    在这一点上,这变得非常令人沮丧..一切看起来都是正确的但我在webview区域中得到"网页不可用". file:/// android_assets/test.html上的网页可能 ...

  3. 浏览器加载一个页面过程,本地的html文件的加载过程

    打开一个本地文件 读取返回给网页 import flask app=flask.Flask(__name__) @app.route('/index') def miaomiao():with ope ...

  4. Qt文档阅读笔记-加载HeightMap(高度图)构造3D地形图

    Qt文档阅读笔记-加载HeightMap(高度图)构造3D地形图 QHeightMapSurfaceDataProxy:是Q3DSurface的一个基本代理类. 他是专门加载高度图. 高度图是没有X, ...

  5. Android Native APP开发笔记:使用WebView控件加载网页

    文章目录 目的 基础使用 处理网页导航 加载本地网页 Web和Native之间交互 调试Web应用 处理页面重绘 总结 目的 WebView是一个比较常用的控件,功能上也比较单一,就是用来加载网页的, ...

  6. QT中main函数中加载外部字体:OTF

    QT中main函数中加载外部字体:OTF 我们开发的程序中,如果想使用外部下载的开源字体,同时保证在软件发布时,程序字体能保证和开发者环境下一致,且不想通过安装字体方式实现字体跟随软件时,我们需要在代 ...

  7. android webview gettitle,Android-webview加载网页去除标题

    在进行app开发时,我们会经常遇到webview加载一个网址的情况,但是仅仅是webview.loadUrl()并不能满足我们的需求,因为一般网页上面都有一个标题,,标题的颜色和我们的app风格可能整 ...

  8. Android 自定义WebView 实现可以加载缓存数据

    1.自定义WebView说明 1.1.这个WebView可以加载缓存的数据.(需要后端配合,将html转换成一个字符串,主要是图片要用特殊格式) 1.2.注入了图片链接,为了方便点击webView中的 ...

  9. android web canvas,HTML5 - Canvas无法在Android WebView的第一次加载时渲染

    我正在开发基于HTML5画布的游戏,该游戏在现有应用程序的WebView中运行.在第一次运行游戏时,它会在后台成功加载,所有日志都表明它已准备就绪并正在运行.但是,WebView中不显示任何内容.如果 ...

最新文章

  1. Data - 深入浅出学统计 - 上篇
  2. MS UC 2013-0-虚拟机-标准化-部署-2-模板机-制作-2-设置-虚拟机
  3. EF optimize the perfermance
  4. Firefox 插件解决 LeetCode 海外版自动跳转到中文版问题
  5. 字符串操作 c语言,C语言字符串操作(示例代码)
  6. java testwhileidle_DBCP踩坑(二):连接池检查testWhileIdle失效
  7. com 名字对象(3)使用IMoniker
  8. python第九十一天----第十六周作业
  9. [LeetCode] Surrounded Regions, Solution
  10. Android上Sensor移植的总结
  11. 2014-08-06 小代码,大道理
  12. caffe调参经验资料文章
  13. _OFF方法包含EC依赖的情况,笔记本禁用独显的方法(通过修改DSDT和SSDT)
  14. 【整理】3dsMax中毒了怎么办
  15. 91位图和bigemap大地图的区别
  16. 二进制与十六进制的转换
  17. GPU显卡服务器有什么作用,可应用哪些方面呢
  18. 余压监控系统在高层民用建筑的应用
  19. RGB(三色)灯配置常用颜色数据,用法讲解,基于C语言的程序讲解,七彩渐变程序讲解
  20. WebGIS期末复习

热门文章

  1. pandas 根据两列数据筛选dataframe
  2. storm如何集成kafka
  3. 函数名,函数体,返回值,参数
  4. torch7框架 深度学习(1)
  5. Spring:延迟初始化
  6. Android数据储存之SharedPreferences总结
  7. [转]Windows Shell编程 第十五章【来源:http://blog.csdn.net/wangqiulin123456/article/details/7988016】...
  8. mfc连接mysql增删改查_java实现mysql数据库增删改查
  9. python学习笔记全过程_Python学习笔记一(Hello World)
  10. python数据可视化代码_Python实现简单的数据可视化