|
—
本帖被 XChinux 执行加亮操作(2016-04-20)
—
qt5.6上的webEngine暂时无法用gcc编译,也没法用在android上,用了很多办法都没法用jni来调用android java的webview,无奈之下用QTextBrowser实现一个最简单的仅支持HTML4子集的Web浏览器,QTextBrowser是没有网络读取功能的,我添加一个网络下载函数,用QtConcurrent异步加载,再用正则表达式解析img标签,然后signal把QTextDocument呈现出来。 这是原型代码,写得比较草率,有兴趣的可以扩展一下QTextBrowser/QTextDocument的源代码得到更多的HTML/CSS渲染效果 - #ifndef QHTMLBROWSER_H
- #define QHTMLBROWSER_H
- //** for more information, please refer to http://www.one-lab.net
- #include <QtConcurrent>
- #include <QtNetwork/QtNetwork>
- #include <QTextBrowser>
- #include <QTextDocument>
- #include <QMap>
- #include <QRegExp>
- #include <QCryptographicHash>
- #include <QApplication>
- class QHtmlBrowser : public QObject
- {
- Q_OBJECT
-
- private:
- QTextBrowser* mBrowser;
- QString mUrl;
- QMap<QString, QByteArray> mResources;
- signals:
- void loadFinished();
- public slots:
- void onLoadFinished();
- void onRequestUrl(const QUrl& url);
- public:
- ~QHtmlBrowser();
- explicit QHtmlBrowser(QTextBrowser* browser);
- void load(const QString& url);
- void addResource(const QString& key, const QByteArray& bytes);
- };
- #endif // QHTMLBROWSER_H
- #include "qhtmlbrowser.h"
- //** for more information, please refer to http://www.one-lab.net
- #define hit_ext(p) \
- else if (src.endsWith(#p, Qt::CaseInsensitive)) \
- ext = #p
- #define index_tag "index"
- #define images_tag "images://"
- QString setUrl(QUrl& parentUrl, const QString& path)
- {
- QString srcUrl;
- QString hostPath = parentUrl.host();
- if (parentUrl.port() != 80)
- hostPath += ":" + QString::number(parentUrl.port());
- hostPath += parentUrl.path();
- int pos = hostPath.lastIndexOf('/');
- if (pos > -1)
- hostPath = hostPath.left(pos);
- srcUrl = hostPath + "/" + path;
- while (srcUrl.contains("//"))
- srcUrl.replace("//", "/");
- srcUrl = "http://" + srcUrl;
- return srcUrl;
- }
- void downloadHtml(QHtmlBrowser* browser, const QString& urlPath, int timeoutSeconds)
- {
- QNetworkAccessManager network;
- QNetworkRequest request;
- QUrl url(urlPath);
- request.setUrl(url);
- QByteArray requestContent = urlPath.toUtf8();
- request.setHeader(QNetworkRequest::ContentLengthHeader, requestContent.length());
- bool timeout = false;
- if (QNetworkReply* reply = network.get(request))
- {
- QDateTime stamp = QDateTime::currentDateTime();
- while (reply->isRunning())
- {
- QApplication::processEvents();
- if (stamp.secsTo(QDateTime::currentDateTime()) > timeoutSeconds)
- {
- reply->abort();
- timeout = true;
- break;
- }
- }
- if (!timeout)
- {
- QString content = QString::fromUtf8(reply->readAll());
- QRegExp imgTagRegex("\\<img[^\\>]*src\\s*=\\s*\"([^\"]*)\"[^\\>]*\\>", Qt::CaseInsensitive);
- imgTagRegex.setMinimal(true);
- QStringList imgSrcList;
- QStringList imgTagList;
- int offset = 0;
- while( (offset = imgTagRegex.indexIn(content, offset)) != -1){
- offset += imgTagRegex.matchedLength();
- imgTagList.append(imgTagRegex.cap(0));
- imgSrcList.append(imgTagRegex.cap(1));
- }
- QString srcUrl;
- QString resourcePrefix(images_tag);
- QString ext;
- int index = -1;
- foreach(QString src, imgSrcList)
- {
- index++;
- srcUrl.clear();
- if (src.startsWith("http://", Qt::CaseInsensitive))
- srcUrl = src;
- else
- {
- if (0){}
- hit_ext(.png);
- hit_ext(.jpeg);
- hit_ext(.jpg);
- hit_ext(.gif);
- else continue;
- if (src.startsWith("://") || src.startsWith("file://", Qt::CaseInsensitive)) continue;
- srcUrl = setUrl(url, src);
- request.setUrl(srcUrl);
- requestContent = srcUrl.toUtf8();
- request.setHeader(QNetworkRequest::ContentLengthHeader, requestContent.length());
- QCryptographicHash hash(QCryptographicHash::Md5);
- if (QNetworkReply* itemReply = network.get(request))
- {
- timeout = false;
- stamp = QDateTime::currentDateTime();
- while (itemReply->isRunning())
- {
- QApplication::processEvents();
- if (stamp.secsTo(QDateTime::currentDateTime()) > timeoutSeconds)
- {
- itemReply->abort();
- timeout = true;
- break;
- }
- }
- if (timeout)
- {
- delete itemReply;
- continue;
- }
- QString imgFile = resourcePrefix + "/";
- hash.addData(srcUrl.toUtf8());
- foreach(char c, hash.result())
- {
- int cInt = (int)c;
- if (cInt < 10)
- imgFile += "0" + QString::number(cInt, 16).left(1);
- else
- imgFile += QString::number(cInt, 16).left(2);
- }
- imgFile += ext;
- QString target = imgTagList[index];
- target.replace(src, imgFile);
- browser->addResource(imgFile, itemReply->readAll());
- content.replace(imgTagList[index], target);
- delete itemReply;
- }
- }
- }
- browser->addResource(index_tag, content.toUtf8());
- }
- delete reply;
- emit browser->loadFinished();
- }
- }
- void QHtmlBrowser::onLoadFinished()
- {
- QTextDocument* document = new QTextDocument(mBrowser);
- if (mResources.contains(index_tag))
- {
- foreach(QString key, mResources.keys())
- {
- if (key.startsWith(images_tag))
- document->addResource(QTextDocument::ImageResource, key, QVariant(mResources[key]));
- }
- document->setHtml(QString::fromUtf8(mResources[index_tag]));
- mBrowser->setDocument(document);
- }
- }
- QHtmlBrowser::~QHtmlBrowser()
- {
- }
- QHtmlBrowser::QHtmlBrowser(QTextBrowser* browser) : QObject(browser)
- {
- mBrowser = browser;
- mBrowser->setReadOnly(true);
- mBrowser->setContextMenuPolicy(Qt::NoContextMenu);
- mBrowser->setAcceptRichText(true);
- mBrowser->setAutoFormatting(QTextEdit::AutoAll);
- connect(this, SIGNAL(loadFinished()), SLOT(onLoadFinished()));
- connect(mBrowser, SIGNAL(anchorClicked(QUrl)), SLOT(onRequestUrl(QUrl)));
- }
- void QHtmlBrowser::onRequestUrl(const QUrl& url)
- {
- QUrl currentUrl(mUrl);
- QString requestingUrl = setUrl(currentUrl, url.toString());
- load(requestingUrl);
- }
- void QHtmlBrowser::load(const QString &url)
- {
- mUrl = url;
- QtConcurrent::run(downloadHtml, this, url, 30);
- }
- void QHtmlBrowser::addResource(const QString &key, const QByteArray &bytes)
- {
- if (mResources.contains(key))
- mResources[key] = bytes;
- else
- mResources.insert(key, bytes);
- }
|