QT分析之WebKit(三)

摘要:
QT分析的WebKit(III)分三个阶段分析QWebView:初始化、HTML解析和页面显示。相对URL指的是没有http://or https://prefix.看第一句中的呼叫。这意味着从QUrl到KURL的转变。;清除;//清除最后一个数据并为这个load_frame-˃script()-˃updatePlatformScriptObjects()准备ifm;//在Windows平台上,这是一个空函数ifdispatchWindowObjectAvailable();m_ needsClear=真;m_ isComplete=假;m_ didCallImplicitClose=假;m_isLoadingMainResource=true;m_isDisplayingInitialEmptyDocument=m_创建InitialemptyDocument;KURLref;参考设置用户;参考setPass;参考setRef;m_outgoingReferer=参考。字符串();m_ URL=URL;RefPtr<Document>文档;if(!m_isDisplayingInitialEmptyDocument&&m_client-˃shouldUsePluginDocument)document=插件文档::创建;elsedocument=DOM实现::createDocument;//创建DOM文件,m_ResponseMMEType因实体而异。
QT分析之WebKit(三)

分三个阶段对QWebView进行分析:初始化(获取数据)、HTML解析、页面显示。从QT自带的文档中可以知道:

QWebView -> QWebPage => QWebFrame(一个QWebPage含多个QWebFrame)

在界面中选择了Open URL,输入URL之后,调用的是:void MainWindow::openUrl()

void MainWindow::openUrl()
{
bool ok;
QString url = QInputDialog::getText(this, tr("Enter a URL"),
tr("URL:"), QLineEdit::Normal, "http://", &ok);

if (ok && !url.isEmpty()) {
centralWidget->webView->setUrl(url);
}
}

调用的是QWebView::setUrl()

void QWebView::setUrl(const QUrl &url)
{
page()->mainFrame()->setUrl(url);
}

其中page()是获取QWebPage指针,QWebPage::mainFrame()获取的是QWebFrame指针。

所以调用的是:QWebFrame::setUrl()

void QWebFrame::setUrl(const QUrl &url)
{
d->frame->loader()->begin(ensureAbsoluteUrl(url));
d->frame->loader()->end();
load(ensureAbsoluteUrl(url));
}

ensureAbsoluteUrl()函数作用是,确保URL是绝对URL(完整URL)。所谓相对URL是指没有输入http://或者https://等前缀的web地址。先看第一句的调用。其中隐含了从QUrl到KURL的变换。

void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
{
// We need to take a reference to the security origin because |clear|
// might destroy the document that owns it.
RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;

bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
clear(resetScripting, resetScripting);// 清除上一次的数据,为本次装载准备
if (resetScripting)
m_frame->script()->updatePlatformScriptObjects();// 在Windows平台下,这是空函数
if (dispatch)
dispatchWindowObjectAvailable();

m_needsClear = true;
m_isComplete = false;
m_didCallImplicitClose = false;
m_isLoadingMainResource = true;
m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;

KURL ref(url);
ref.setUser(String());
ref.setPass(String());
ref.setRef(String());
m_outgoingReferrer = ref.string();
m_URL = url;

RefPtr<Document> document;
if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
document = PluginDocument::create(m_frame);
else
document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());// 创建DOM文件,m_responseMIMEType不同实体不同。

// 如果是"text/html"创建HTMLDocument实体;"application/xhtml+xml"创建Document实体

// 如果是"application/x-ftp-directory"则是FTPDirectoryDocument实体

// text/vnd.wap.wml 对应 WMLDocument 实体(无线)

// "application/pdf" /"text/plain" 对应 PluginDocument实体

// 如果是MediaPlayer::supportsType(type),创建的是MediaDocument实体

// "image/svg+xml" 对应 SVGDocument实体
m_frame->setDocument(document);

document->setURL(m_URL);
if (m_decoder)
document->setDecoder(m_decoder.get());
if (forcedSecurityOrigin)
document->setSecurityOrigin(forcedSecurityOrigin.get());

m_frame->domWindow()->setURL(document->url());
m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());

updatePolicyBaseURL();// 更新排布策略的基础URL

Settings* settings = document->settings();
document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());

if (m_documentLoader) {
String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
if (!dnsPrefetchControl.isEmpty())
document->parseDNSPrefetchControlHeader(dnsPrefetchControl);
}

#if FRAME_LOADS_USER_STYLESHEET
KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL();
if (!userStyleSheet.isEmpty())
m_frame->setUserStyleSheetLocation(userStyleSheet);
#endif

restoreDocumentState();

document->implicitOpen();

if (m_frame->view())
m_frame->view()->setContentsSize(IntSize());

#if USE(LOW_BANDWIDTH_DISPLAY)
// Low bandwidth display is a first pass display without external resources
// used to give an instant visual feedback. We currently only enable it for
// HTML documents in the top frame.
if (document->isHTMLDocument() && !m_frame->tree()->parent() && m_useLowBandwidthDisplay) {
m_pendingSourceInLowBandwidthDisplay = String();
m_finishedParsingDuringLowBandwidthDisplay = false;
m_needToSwitchOutLowBandwidthDisplay = false;
document->setLowBandwidthDisplay(true);
}
#endif
}

看其中document->implicitOpen()的代码:

void Document::implicitOpen()
{
cancelParsing();

clear();
m_tokenizer = createTokenizer();
setParsing(true);
}

Tokenizer *HTMLDocument::createTokenizer()
{
bool reportErrors = false;
if (frame())
if (Page* page = frame()->page())
reportErrors = page->inspectorController()->windowVisible();

return new HTMLTokenizer(this, reportErrors);
}

新创建的HTMLTokenizer对象,就是HTML的解析器。

回到QWebFrame::setUrl()的第二句:d->frame->loader()->end();

只是把上次未完的解析停止:

void FrameLoader::endIfNotLoadingMainResource()
{
if (m_isLoadingMainResource || !m_frame->page())
return;

//http://bugs.webkit.org/show_bug.cgi?id=10854
// The frame's last ref may be removed and it can be deleted by checkCompleted(),
// so we'll add a protective refcount
RefPtr<Frame> protector(m_frame);

// make sure nothing's left in there
if (m_frame->document()) {
write(0, 0, true);
m_frame->document()->finishParsing();

} else
// WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
// WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
// become true. An example is when a subframe is a pure text doc, and that subframe is the
// last one to complete.
checkCompleted();
}

再来看QWebFrame::setUrl()的第三句:load(ensureAbsoluteUrl(url));

void QWebFrame::load(const QUrl &url)
{
load(QNetworkRequest(ensureAbsoluteUrl(url)));
}

新建一个QNetworkRequest对象,然后调用

void load(const QNetworkRequest &request,
QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
const QByteArray &body = QByteArray());
看其代码:

void QWebFrame::load(const QNetworkRequest &req,
QNetworkAccessManager::Operation operation,
const QByteArray &body)
{
if (d->parentFrame())
d->page->d->insideOpenCall = true;

QUrl url = ensureAbsoluteUrl(req.url());

WebCore::ResourceRequest request(url);

switch (operation) {
case QNetworkAccessManager::HeadOperation:
request.setHTTPMethod("HEAD");
break;
case QNetworkAccessManager::GetOperation:
request.setHTTPMethod("GET");
break;
case QNetworkAccessManager::PutOperation:
request.setHTTPMethod("PUT");
break;
case QNetworkAccessManager::PostOperation:
request.setHTTPMethod("POST");
break;
case QNetworkAccessManager::UnknownOperation:
// eh?
break;
}

QList<QByteArray> httpHeaders = req.rawHeaderList();
for (int i = 0; i < httpHeaders.size(); ++i) {
const QByteArray &headerName = httpHeaders.at(i);
request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName)));
}

if (!body.isEmpty())
request.setHTTPBody(WebCore::FormData::create(body.constData(), body.size()));

d->frame->loader()->load(request);

if (d->parentFrame())
d->page->d->insideOpenCall = false;
}

看关键的FrameLoader::load()

void FrameLoader::load(const ResourceRequest& request)
{
load(request, SubstituteData());
}

void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData)
{
if (m_inStopAllLoaders)
return;
// FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
m_loadType = FrameLoadTypeStandard;
load(m_client->createDocumentLoader(request, substituteData).get());
}

上面m_client对应的是FrameLoaderClientQt实体,m_client->createDocumentLoader()创建的是DocumentLoader对象。进一步看FrameLoader::load(DocumentLoader *)的代码:

void FrameLoader::load(DocumentLoader* newDocumentLoader)
{
ResourceRequest& r = newDocumentLoader->request();
addExtraFieldsToMainResourceRequest(r);
FrameLoadType type;

if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
r.setCachePolicy(ReloadIgnoringCacheData);
type = FrameLoadTypeSame;
} else
type = FrameLoadTypeStandard;

if (m_documentLoader)
newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
// When we loading alternate content for an unreachable URL that we're
// visiting in the history list, we treat it as a reload so the history list
// is appropriately maintained.
//
// FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ...
// shouldn't a more explicit type of reload be defined, that means roughly
// "load without affecting history" ?
if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
ASSERT(type == FrameLoadTypeStandard);
type = FrameLoadTypeReload;
}

loadWithDocumentLoader(newDocumentLoader, type, 0);
}

来自:http://hi.baidu.com/jakmax/blog/item/e43f56b11ff40958082302b1.html

免责声明:文章转载自《QT分析之WebKit(三)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SQL转Linq工具的使用——Linqer 4.6drawRoundRect方法:绘制圆角矩形下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Django之无名分组,有名分组

在Django 2.0版本之前,在urls,py文件中,用url设定视图函数 urlpatterns = [ url(r'login/',views.login), ] 其中第一个参数是正则匹配,如下代码,输入http://127.0.0.1:8000/login,出现的是login页面,但是输入login2,出现的还是login页面,这是因为Djan...

简单基于OPENGL的三维CAD框架(1)工具类

在vc++中有CDC类,同样也可以开发基于OPENGL的OPenGLDC类,这样可以像调用CDC类一样调用OPenGLDC类 首先给出两个工具类,点类和向量类 typedef struct tagVector3D {double dx;double dy;double dz;} VECTOR3D; class CVector3D : public VECT...

Django中CSS加载background url('')问题

Django中CSS加载background url('')问题 在django中, 默认CSS中如果有 background url('images/a.jpg') 这类的属性,会被django当成URL来解析 这样会造成找不到该文件的问题。 所以为了解决这个问题,首先需要配置setting.py, 配置STATICFILES_DIRS STATIC...

python嵌入C++ boost.python如何在C++中调用含有不定长参数tuple变量和关键字参数dict变量的函数

    这个问题是在我尝试利用pygraphviz嵌入我的C++代码绘制二叉树的时候发现的.找了半天资料,这里我把几种常用的C++调用 PYTHON利用 boost.python 的方法作一个总结,希望能让别人少走弯路,因为有些内容还找不到中文文档,虽然都不难但是开始摸索 还是费时间的.     我个人认为boost.python真的是非常的COOL,基...

CSS之纯CSS画的基本图形(矩形、圆形、三角形、多边形、爱心、八卦等)

图形包括基本的矩形、圆形、椭圆、三角形、多边形,也包括稍微复杂一点的爱心、钻石、阴阳八卦等。当然有一些需要用到CSS3的属性,所以在你打开这篇文章的时候,我希望你用的是firefox或者chrome,当然IE也能看一部分的。那好,下面就一起来看看我们是如何用纯CSS来画这些图形的,如果你也觉得很震撼,推荐给你的朋友吧。 1、正方形 最终效果: CSS...

Qt Meta Object System-元对象系统

研一的时候开始使用Qt,感觉用Qt开发图形界面比MFC的一套框架来方便的多。后来由于项目的需要,也没有再接触Qt了。现在要重新拾起来,于是要从基础学起。 Now,开始学习Qt事件处理机制。 元对象系统的构成 QObject为所有需要利用元对象系统的对象提供一个基类。 Q_OBJECT宏,在类的声明体内激活meta-object功能,比如动态属性、信号和槽...