前面只发布了QWebView的代码,并没有具体的解释过load()函数。在这里补充上。
2012.10.19 于济南
先贴上两个load的源码,分别命名为load1、load2,方便下文论述:
load1:
void QWebFrame::load(const QUrl &url)
{
// The load() overload ensures that the url is absolute.
load(QNetworkRequest(url));
}
load2:
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::DeleteOperation:
request.setHTTPMethod("DELETE");
break;
case QNetworkAccessManager::CustomOperation:
request.setHTTPMethod(req.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray().constData());
break;
case QNetworkAccessManager::UnknownOperation:
// eh?
break;
}
QVariant cacheLoad = req.attribute(QNetworkRequest::CacheLoadControlAttribute);
if (cacheLoad.isValid()) {
bool ok;
uint cacheLoadValue = cacheLoad.toUInt(&ok);
if (ok)
request.setCachePolicy(cacheLoadControlToCachePolicy(cacheLoadValue));
}
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, false);
if (d->parentFrame())
d->page->d->insideOpenCall = false;
}
先看load1的内容。入口形参为const QUrl url,对于形参使用const定义,是为了在程序中不修改此形参的值,只使用此值,简单的说,这种形参就是输入参数,运行完此段程序,此形参的值并不发生变化。那么使用此url做了些什么呢?可以看到此函数只有一行,load(QNetworkRequest (url));,调用了此类(QWebFrame)中的一个load()函数。在C++中,可以根据入口形参类型及个数等自动匹配重载函数。那么我们需要知道这个入口形参的类型是否跟下面的load2的形参类型相同,也就是:这个load()是否就是调用的下文形参较多的那个load()。
为了查找实参类型,我们需要找到QNetworkRequest,位于src/network/access/目录中,qnetworkrequest.cpp。
QNetworkRequest::QNetworkRequest(const QUrl &url)
: d(new QNetworkRequestPrivate)
{
d->url = url;
}
QNetworkRequest::QNetworkRequest(const QNetworkRequest &other)
: d(other.d)
{
}
可以看到,类QNetworkRequest有两个构造函数,重载了。对应于我们调用的这个,匹配的是第一种,入口形参为url的那个。
我们看到,第一个构造函数,自带初始化d = new QNetworkRequestPrivate。类QNetworkRequestPrivate是类QNetworkRequest的友元类,位于此cpp文件的上方,类的构造函数的定义放在了类的声明内部,看起来比较长。而d就是此类的一个实例,通过d的初始化可以看出来,也可以去qnetworkrequest_p.h中去看。此类中就定义了一个QUrl类型的url变量。所以就有了上述d->url = url;语句。
上面寻找qnetworkrequest的步骤比较多余。。。
我们知道,构造函数是没有返回类型的,那么通过构造函数,运行出来的是什么呢?其实对于load1,我们可以这样写:
QNetworkRequest *myInstance;
myInstance = new QNetworkRequest(url);
load(myInstance);
看出来了吧,构造函数运行出来的,就是这个类的实例,只不过没有具体的名字而已。通过这里,我们就可以看出了,load1的入口形参就是一个类型为QNetworkRequest的变量,正好对应于load2的第一个形参类型。我们知道,在C++中,实参的个数可以少于形参,前提是多出来的形参有默认的赋值,我们来看一下load2的声明:
void load(const QNetworkRequest &request,
QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
const QByteArray &body = QByteArray());
可以看到,除了第一个参数外,后面两个形参均已经赋了默认值,这样在调用的时候,后两个参数就可以省略不写了,符合C++的语法规范。
从上面的叙述中,我们就可以确定,load1中调用的load(),就是load2。下面我们只要分析load2就行了。
函数一开始,又出现了d,综合多个类(像QWebFrame、QWebPage、QNetworkRequest等)来看,d是每个类友元类(类名+Private)的实例,仅限类内部调用,私有,不是全局变量。例如在类QWebFrame中,调用QWebPagePrivate的d,需要:d->page->d->...,其中page是QWebFrame中的成员变量,类型为QWebPage。关于这里出现的if操作,就先跳过了。
语句:QUrl url = ensureAbsoluteUrl(req.url());
先看这个函数ensureAbsoluteUrl(),字面意思可以看出:确保绝对Url。这需要先了解一下http协议的知识。http/1.1 中规定,浏览器所请求资源(URL)的确定可以有四种方式,其中一种就是由Request-URI直接确定,叫做绝对URI。看看这两者之间是否有联系。F2找到函数定义:
static inline QUrl ensureAbsoluteUrl(const QUrl &url)
{
if (!url.isValid() || !url.isRelative())
return url;
// This contains the URL with absolute path but without
// the query and the fragment part.
QUrl baseUrl = QUrl::fromLocalFile(QFileInfo(url.toLocalFile()).absoluteFilePath());
// The path is removed so the query and the fragment parts are there.
QString pathRemoved = url.toString(QUrl::RemovePath);
QUrl toResolve(pathRemoved);
return baseUrl.resolved(toResolve);
}
这个函数的作用是:如果url不是relative的(relative就是没有http://的网址),则返回此url;换句话说,如果url是绝对的(absolute),则不对此url做其他操作,直接返回此url。至于valid与下面的其他操作暂时先不讨论,目测就是没有http时就给加上。
再看load2的下一条语句:
WebCore::ResourceRequest request(url);
需要找到这个类,位置:src\3rdparty\webkit\Source\WebCore\platform\network\qt\ResourceRequest.h。