diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2016-05-10 16:58:00 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2016-05-10 16:58:12 +0200 |
commit | e5157941181f6bb5e906377e68af9bbe2ab55795 (patch) | |
tree | e0f109b51e8faa44cb36ca2ac95d8cd1b4387be2 | |
parent | c2f7f09974959c252a5e2879adfffe6356543fff (diff) | |
parent | 023168cf91dc7ac11ced1b6a60ca7aa248987810 (diff) |
Merge remote-tracking branch 'origin/5.7' into dev
Change-Id: I02117cbd7ad655005b70daa97fd9db7b0918a5d1
63 files changed, 1076 insertions, 497 deletions
diff --git a/examples/webenginewidgets/demobrowser/browserapplication.cpp b/examples/webenginewidgets/demobrowser/browserapplication.cpp index 0d5c54199..26764b93c 100644 --- a/examples/webenginewidgets/demobrowser/browserapplication.cpp +++ b/examples/webenginewidgets/demobrowser/browserapplication.cpp @@ -136,11 +136,7 @@ BrowserApplication::BrowserApplication(int &argc, char **argv) socket.connectToServer(serverName); if (socket.waitForConnected(500)) { QTextStream stream(&socket); - QStringList args = QCoreApplication::arguments(); - if (args.count() > 1) - stream << args.last(); - else - stream << QString(); + stream << getCommandLineUrlArgument(); stream.flush(); socket.waitForBytesWritten(); return; @@ -255,11 +251,13 @@ void BrowserApplication::postLaunch() // newMainWindow() needs to be called in main() for this to happen if (m_mainWindows.count() > 0) { - QStringList args = QCoreApplication::arguments(); - if (args.count() > 1) - mainWindow()->loadPage(args.last()); - else + const QString url = getCommandLineUrlArgument(); + if (!url.isEmpty()) { + mainWindow()->loadPage(url); + } else { mainWindow()->slotHome(); + } + } BrowserApplication::historyManager(); } @@ -421,6 +419,19 @@ void BrowserApplication::installTranslator(const QString &name) QApplication::installTranslator(translator); } +QString BrowserApplication::getCommandLineUrlArgument() const +{ + const QStringList args = QCoreApplication::arguments(); + if (args.count() > 1) { + const QString lastArg = args.last(); + const bool isValidUrl = QUrl::fromUserInput(lastArg).isValid(); + if (isValidUrl) + return lastArg; + } + + return QString(); +} + #if defined(Q_OS_OSX) bool BrowserApplication::event(QEvent* event) { diff --git a/examples/webenginewidgets/demobrowser/browserapplication.h b/examples/webenginewidgets/demobrowser/browserapplication.h index f509c67f7..5c75d41b3 100644 --- a/examples/webenginewidgets/demobrowser/browserapplication.h +++ b/examples/webenginewidgets/demobrowser/browserapplication.h @@ -119,6 +119,7 @@ private slots: private: void clean(); void installTranslator(const QString &name); + QString getCommandLineUrlArgument() const; static HistoryManager *s_historyManager; static DownloadManager *s_downloadManager; diff --git a/examples/webenginewidgets/demobrowser/edittreeview.cpp b/examples/webenginewidgets/demobrowser/edittreeview.cpp index 763fbec5c..f4c9a0d70 100644 --- a/examples/webenginewidgets/demobrowser/edittreeview.cpp +++ b/examples/webenginewidgets/demobrowser/edittreeview.cpp @@ -49,6 +49,8 @@ ****************************************************************************/ #include "edittreeview.h" +#include "browserapplication.h" +#include "history.h" #include <QtGui/QKeyEvent> @@ -73,13 +75,12 @@ void EditTreeView::removeOne() if (!model()) return; QModelIndex ci = currentIndex(); - int row = ci.row(); - model()->removeRow(row, ci.parent()); + BrowserApplication::historyManager()->removeHistoryEntry(model()->data(ci,HistoryModel::UrlStringRole).toString()); } void EditTreeView::removeAll() { if (!model()) return; - model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex()); + BrowserApplication::historyManager()->clear(); } diff --git a/examples/webenginewidgets/demobrowser/history.cpp b/examples/webenginewidgets/demobrowser/history.cpp index aaab44ac8..188490aca 100644 --- a/examples/webenginewidgets/demobrowser/history.cpp +++ b/examples/webenginewidgets/demobrowser/history.cpp @@ -101,7 +101,7 @@ HistoryManager::~HistoryManager() m_saveTimer->saveIfNeccessary(); } -QList<HistoryItem> HistoryManager::history() const +QList<HistoryItem> &HistoryManager::history() { return m_history; } @@ -120,6 +120,15 @@ void HistoryManager::addHistoryEntry(const QString &url) addHistoryItem(item); } +void HistoryManager::removeHistoryEntry(const QString &url) +{ + QUrl cleanUrl(url); + cleanUrl.setPassword(QString()); + cleanUrl.setHost(cleanUrl.host().toLower()); + HistoryItem item(cleanUrl.toString(), QDateTime::currentDateTime()); + removeHistoryItem(item); +} + void HistoryManager::setHistory(const QList<HistoryItem> &history, bool loadedAndSorted) { m_history = history; @@ -173,7 +182,7 @@ void HistoryManager::checkForExpired() } if (nextTimeout > 0) break; - HistoryItem item = m_history.takeLast(); + const HistoryItem& item = m_history.last(); // remove from saved file also m_lastSavedUrl = QString(); emit entryRemoved(item); @@ -188,12 +197,21 @@ void HistoryManager::addHistoryItem(const HistoryItem &item) if (BrowserApplication::instance()->privateBrowsing()) return; - m_history.prepend(item); emit entryAdded(item); if (m_history.count() == 1) checkForExpired(); } +void HistoryManager::removeHistoryItem(const HistoryItem &item) +{ + for (int i = m_history.count() - 1 ; i >= 0; --i) { + if (item.url == m_history.at(i).url) { + //delete all related entries with that url + emit entryRemoved(m_history.at(i)); + } + } +} + void HistoryManager::updateHistoryItem(const QUrl &url, const QString &title) { for (int i = 0; i < m_history.count(); ++i) { @@ -224,7 +242,6 @@ void HistoryManager::setHistoryLimit(int limit) void HistoryManager::clear() { - m_history.clear(); m_lastSavedUrl = QString(); emit historyReset(); m_saveTimer->changeOccurred(); @@ -374,10 +391,10 @@ HistoryModel::HistoryModel(HistoryManager *history, QObject *parent) connect(m_history, SIGNAL(historyReset()), this, SLOT(historyReset())); connect(m_history, SIGNAL(entryRemoved(HistoryItem)), - this, SLOT(historyReset())); + this, SLOT(entryRemoved(HistoryItem))); connect(m_history, SIGNAL(entryAdded(HistoryItem)), - this, SLOT(entryAdded())); + this, SLOT(entryAdded(HistoryItem))); connect(m_history, SIGNAL(entryUpdated(int)), this, SLOT(entryUpdated(int))); } @@ -385,15 +402,26 @@ HistoryModel::HistoryModel(HistoryManager *history, QObject *parent) void HistoryModel::historyReset() { beginResetModel(); + m_history->history().clear(); endResetModel(); } -void HistoryModel::entryAdded() +void HistoryModel::entryAdded(const HistoryItem &item) { beginInsertRows(QModelIndex(), 0, 0); + m_history->history().prepend(item); endInsertRows(); } +void HistoryModel::entryRemoved(const HistoryItem &item) +{ + int index = m_history->history().indexOf(item); + Q_ASSERT(index > -1); + beginRemoveRows(QModelIndex(),index, index); + m_history->history().takeAt(index); + endRemoveRows(); +} + void HistoryModel::entryUpdated(int offset) { QModelIndex idx = index(offset, 0); @@ -468,12 +496,9 @@ bool HistoryModel::removeRows(int row, int count, const QModelIndex &parent) return false; int lastRow = row + count - 1; beginRemoveRows(parent, row, lastRow); - QList<HistoryItem> lst = m_history->history(); + QList<HistoryItem> &lst = m_history->history(); for (int i = lastRow; i >= row; --i) lst.removeAt(i); - disconnect(m_history, SIGNAL(historyReset()), this, SLOT(historyReset())); - m_history->setHistory(lst); - connect(m_history, SIGNAL(historyReset()), this, SLOT(historyReset())); endRemoveRows(); return true; } @@ -664,8 +689,6 @@ TreeProxyModel::TreeProxyModel(QObject *parent) : QSortFilterProxyModel(parent) bool TreeProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { - if (!source_parent.isValid()) - return true; return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } @@ -678,14 +701,16 @@ HistoryDialog::HistoryDialog(QWidget *parent, HistoryManager *setHistory) : QDia tree->setUniformRowHeights(true); tree->setSelectionBehavior(QAbstractItemView::SelectRows); tree->setTextElideMode(Qt::ElideMiddle); - QAbstractItemModel *model = history->historyTreeModel(); + QAbstractItemModel *model = history->historyFilterModel(); TreeProxyModel *proxyModel = new TreeProxyModel(this); connect(search, SIGNAL(textChanged(QString)), proxyModel, SLOT(setFilterFixedString(QString))); connect(removeButton, SIGNAL(clicked()), tree, SLOT(removeOne())); - connect(removeAllButton, SIGNAL(clicked()), history, SLOT(clear())); + connect(removeAllButton, SIGNAL(clicked()), tree, SLOT(removeAll())); proxyModel->setSourceModel(model); + proxyModel->setFilterKeyColumn(1); tree->setModel(proxyModel); + tree->setSortingEnabled(true); tree->setExpanded(proxyModel->index(0, 0), true); tree->setAlternatingRowColors(true); QFontMetrics fm(font()); @@ -739,25 +764,13 @@ HistoryFilterModel::HistoryFilterModel(QAbstractItemModel *sourceModel, QObject setSourceModel(sourceModel); } -int HistoryFilterModel::historyLocation(const QString &url) const -{ - load(); - if (!m_historyHash.contains(url)) - return 0; - return sourceModel()->rowCount() - m_historyHash.value(url); -} - -QVariant HistoryFilterModel::data(const QModelIndex &index, int role) const -{ - return QAbstractProxyModel::data(index, role); -} - void HistoryFilterModel::setSourceModel(QAbstractItemModel *newSourceModel) { + beginResetModel(); if (sourceModel()) { disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset())); disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), - this, SLOT(dataChanged(QModelIndex,QModelIndex))); + this, SLOT(sourceDataChanged(QModelIndex,QModelIndex))); disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(sourceRowsInserted(QModelIndex,int,int))); disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), @@ -767,7 +780,6 @@ void HistoryFilterModel::setSourceModel(QAbstractItemModel *newSourceModel) QAbstractProxyModel::setSourceModel(newSourceModel); if (sourceModel()) { - m_loaded = false; connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset())); connect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(sourceDataChanged(QModelIndex,QModelIndex))); @@ -776,6 +788,8 @@ void HistoryFilterModel::setSourceModel(QAbstractItemModel *newSourceModel) connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(sourceRowsRemoved(QModelIndex,int,int))); } + load(); + endResetModel(); } void HistoryFilterModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) @@ -790,14 +804,13 @@ QVariant HistoryFilterModel::headerData(int section, Qt::Orientation orientation void HistoryFilterModel::sourceReset() { - m_loaded = false; beginResetModel(); + load(); endResetModel(); } int HistoryFilterModel::rowCount(const QModelIndex &parent) const { - load(); if (parent.isValid()) return 0; return m_historyHash.count(); @@ -810,14 +823,12 @@ int HistoryFilterModel::columnCount(const QModelIndex &parent) const QModelIndex HistoryFilterModel::mapToSource(const QModelIndex &proxyIndex) const { - load(); int sourceRow = sourceModel()->rowCount() - proxyIndex.internalId(); return sourceModel()->index(sourceRow, proxyIndex.column()); } QModelIndex HistoryFilterModel::mapFromSource(const QModelIndex &sourceIndex) const { - load(); QString url = sourceIndex.data(HistoryModel::UrlStringRole).toString(); if (!m_historyHash.contains(url)) return QModelIndex(); @@ -843,7 +854,6 @@ QModelIndex HistoryFilterModel::mapFromSource(const QModelIndex &sourceIndex) co QModelIndex HistoryFilterModel::index(int row, int column, const QModelIndex &parent) const { - load(); if (row < 0 || row >= rowCount(parent) || column < 0 || column >= columnCount(parent)) return QModelIndex(); @@ -858,8 +868,6 @@ QModelIndex HistoryFilterModel::parent(const QModelIndex &) const void HistoryFilterModel::load() const { - if (m_loaded) - return; m_sourceRow.clear(); m_historyHash.clear(); m_historyHash.reserve(sourceModel()->rowCount()); @@ -871,15 +879,12 @@ void HistoryFilterModel::load() const m_historyHash[url] = sourceModel()->rowCount() - i; } } - m_loaded = true; } void HistoryFilterModel::sourceRowsInserted(const QModelIndex &parent, int start, int end) { Q_ASSERT(start == end && start == 0); Q_UNUSED(end); - if (!m_loaded) - return; QModelIndex idx = sourceModel()->index(start, 0, parent); QString url = idx.data(HistoryModel::UrlStringRole).toString(); if (m_historyHash.contains(url)) { @@ -1184,6 +1189,7 @@ bool HistoryTreeModel::removeRows(int row, int count, const QModelIndex &parent) void HistoryTreeModel::setSourceModel(QAbstractItemModel *newSourceModel) { + beginResetModel(); if (sourceModel()) { disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset())); disconnect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(sourceReset())); @@ -1191,6 +1197,8 @@ void HistoryTreeModel::setSourceModel(QAbstractItemModel *newSourceModel) this, SLOT(sourceRowsInserted(QModelIndex,int,int))); disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(sourceRowsRemoved(QModelIndex,int,int))); + disconnect(sourceModel(), &QAbstractItemModel::dataChanged, this, + &HistoryTreeModel::sourceDataChanged); } QAbstractProxyModel::setSourceModel(newSourceModel); @@ -1202,9 +1210,9 @@ void HistoryTreeModel::setSourceModel(QAbstractItemModel *newSourceModel) this, SLOT(sourceRowsInserted(QModelIndex,int,int))); connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(sourceRowsRemoved(QModelIndex,int,int))); + connect(sourceModel(), &QAbstractItemModel::dataChanged, this, + &HistoryTreeModel::sourceDataChanged); } - - beginResetModel(); endResetModel(); } @@ -1293,3 +1301,10 @@ void HistoryTreeModel::sourceRowsRemoved(const QModelIndex &parent, int start, i endRemoveRows(); } } + +void HistoryTreeModel::sourceDataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight, + const QVector<int> roles) +{ + emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles); +} diff --git a/examples/webenginewidgets/demobrowser/history.h b/examples/webenginewidgets/demobrowser/history.h index 0ae5a7bf7..6d7da5e6d 100644 --- a/examples/webenginewidgets/demobrowser/history.h +++ b/examples/webenginewidgets/demobrowser/history.h @@ -103,14 +103,16 @@ public: ~HistoryManager(); bool historyContains(const QString &url) const; + void addHistoryEntry(const QString &url); + void removeHistoryEntry(const QString &url); void updateHistoryItem(const QUrl &url, const QString &title); int historyLimit() const; void setHistoryLimit(int limit); - QList<HistoryItem> history() const; + QList<HistoryItem>& history(); void setHistory(const QList<HistoryItem> &history, bool loadedAndSorted = false); // History manager keeps around these models for use by the completer and other classes @@ -128,6 +130,7 @@ private slots: protected: void addHistoryItem(const HistoryItem &item); + void removeHistoryItem(const HistoryItem &item); private: void load(); @@ -149,7 +152,8 @@ class HistoryModel : public QAbstractTableModel public slots: void historyReset(); - void entryAdded(); + void entryAdded(const HistoryItem &item); + void entryRemoved(const HistoryItem &item); void entryUpdated(int offset); public: @@ -185,7 +189,6 @@ public: inline bool historyContains(const QString &url) const { load(); return m_historyHash.contains(url); } - int historyLocation(const QString &url) const; QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; QModelIndex mapToSource(const QModelIndex &proxyIndex) const; @@ -196,7 +199,6 @@ public: QModelIndex index(int, int, const QModelIndex& = QModelIndex()) const; QModelIndex parent(const QModelIndex& index= QModelIndex()) const; bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; private slots: void sourceReset(); @@ -314,7 +316,8 @@ private slots: void sourceReset(); void sourceRowsInserted(const QModelIndex &parent, int start, int end); void sourceRowsRemoved(const QModelIndex &parent, int start, int end); - + void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, + const QVector<int> roles); private: int sourceDateRow(int row) const; mutable QList<int> m_sourceRowCache; diff --git a/examples/webenginewidgets/demobrowser/tabwidget.cpp b/examples/webenginewidgets/demobrowser/tabwidget.cpp index 3b56d115b..e684d3757 100644 --- a/examples/webenginewidgets/demobrowser/tabwidget.cpp +++ b/examples/webenginewidgets/demobrowser/tabwidget.cpp @@ -782,6 +782,9 @@ void TabWidget::webViewUrlChanged(const QUrl &url) int index = webViewIndex(webView); if (-1 != index) { m_tabBar->setTabData(index, url); + HistoryManager *manager = BrowserApplication::historyManager(); + if (url.isValid()) + manager->addHistoryEntry(url.toString()); } emit tabsChanged(); } diff --git a/examples/webenginewidgets/simplebrowser/webview.cpp b/examples/webenginewidgets/simplebrowser/webview.cpp index 24835b10b..9a5a75092 100644 --- a/examples/webenginewidgets/simplebrowser/webview.cpp +++ b/examples/webenginewidgets/simplebrowser/webview.cpp @@ -79,8 +79,11 @@ WebView::WebView(QWidget *parent) status = tr("Render process killed"); break; } - QMessageBox::critical(window(), status, tr("Render process exited with code: %1").arg(statusCode)); - QTimer::singleShot(0, [this] { reload(); }); + QMessageBox::StandardButton btn = QMessageBox::question(window(), status, + tr("Render process exited with code: %1\n" + "Do you want to reload the page ?").arg(statusCode)); + if (btn == QMessageBox::Yes) + QTimer::singleShot(0, [this] { reload(); }); }); } diff --git a/src/3rdparty b/src/3rdparty -Subproject ba40ed24a6d23e606397b650a7982b0998dbeaf +Subproject 46f522d613bb77600ed3a85580ff84ee9802e21 diff --git a/src/core/api/qtwebenginecoreglobal.cpp b/src/core/api/qtwebenginecoreglobal.cpp index 8f004777f..f5d1e6d39 100644 --- a/src/core/api/qtwebenginecoreglobal.cpp +++ b/src/core/api/qtwebenginecoreglobal.cpp @@ -79,9 +79,11 @@ QWEBENGINE_PRIVATE_EXPORT void initialize() return; } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 1)) // Bail out silently if the user did not construct a QGuiApplication. if (!qobject_cast<QGuiApplication *>(app)) return; +#endif if (app->thread() != QThread::currentThread()) { qFatal("QtWebEngine::initialize() must be called from the Qt gui thread."); diff --git a/src/core/browser_context_adapter.cpp b/src/core/browser_context_adapter.cpp index e0f933562..ba9d671ae 100644 --- a/src/core/browser_context_adapter.cpp +++ b/src/core/browser_context_adapter.cpp @@ -151,6 +151,8 @@ QWebEngineUrlRequestInterceptor *BrowserContextAdapter::requestInterceptor() void BrowserContextAdapter::setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) { m_requestInterceptor = interceptor; + if (m_browserContext->url_request_getter_.get()) + m_browserContext->url_request_getter_->updateRequestInterceptor(); } void BrowserContextAdapter::addClient(BrowserContextAdapterClient *adapterClient) @@ -466,15 +468,6 @@ void BrowserContextAdapter::clearHttpCache() m_browserContext->url_request_getter_->clearHttpCache(); } -QStringList BrowserContextAdapter::spellCheckLanguages(const QStringList &acceptLanguages) -{ -#if defined(ENABLE_SPELLCHECK) - return m_browserContext->spellCheckLanguages(acceptLanguages); -#else - return QStringList(); -#endif -} - void BrowserContextAdapter::setSpellCheckLanguage(const QString &language) { #if defined(ENABLE_SPELLCHECK) diff --git a/src/core/browser_context_qt.cpp b/src/core/browser_context_qt.cpp index 5b3115530..1c326fb83 100644 --- a/src/core/browser_context_qt.cpp +++ b/src/core/browser_context_qt.cpp @@ -47,6 +47,7 @@ #include "ssl_host_state_delegate_qt.h" #include "type_conversion.h" #include "url_request_context_getter_qt.h" +#include "web_engine_library_info.h" #include "base/time/time.h" #include "content/public/browser/browser_thread.h" @@ -54,6 +55,7 @@ #include "net/proxy/proxy_config_service.h" #if defined(ENABLE_SPELLCHECK) +#include "base/base_paths.h" #include "base/prefs/pref_member.h" #include "base/prefs/pref_service.h" #include "base/prefs/testing_pref_store.h" @@ -78,12 +80,9 @@ BrowserContextQt::BrowserContextQt(BrowserContextAdapter *adapter) scoped_refptr<PrefRegistrySimple> registry(new PrefRegistrySimple()); // Initial spellcheck settings - std::string spellcheckLang = QLocale().bcp47Name().toStdString(); - base::ListValue *dictionaries = new base::ListValue; - dictionaries->AppendString(spellcheckLang); - registry->RegisterListPref(prefs::kSpellCheckDictionaries, dictionaries); - registry->RegisterStringPref(prefs::kAcceptLanguages, spellcheckLang); - registry->RegisterStringPref(prefs::kSpellCheckDictionary, spellcheckLang); + registry->RegisterListPref(prefs::kSpellCheckDictionaries, new base::ListValue()); + registry->RegisterStringPref(prefs::kAcceptLanguages, std::string()); + registry->RegisterStringPref(prefs::kSpellCheckDictionary, std::string()); registry->RegisterBooleanPref(prefs::kSpellCheckUseSpellingService, false); registry->RegisterBooleanPref(prefs::kEnableContinuousSpellcheck, false); registry->RegisterBooleanPref(prefs::kEnableAutoSpellCorrect, false); @@ -201,22 +200,12 @@ net::URLRequestContextGetter *BrowserContextQt::CreateRequestContext(content::Pr return url_request_getter_.get(); } - #if defined(ENABLE_SPELLCHECK) -QStringList BrowserContextQt::spellCheckLanguages(const QStringList& acceptedLanguages) +void BrowserContextQt::failedToLoadDictionary(const std::string &language) { - QStringList result; -#if !defined(OS_MACOSX) // no SpellcheckService::GetSpellCheckLanguages - m_prefService->SetString(prefs::kAcceptLanguages,acceptedLanguages.join(",").toStdString()); - - std::vector<std::string> vec; - SpellcheckService::GetSpellCheckLanguages(this, &vec); - - for (std::vector<std::string>::iterator it = vec.begin(); it != vec.end(); ++it) { - result << QString::fromStdString(*it); - } -#endif - return result; + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + qWarning() << "Could not load dictionary for:" << toQt(language) << endl + << "Make sure that correct bdic file is in:" << toQt(WebEngineLibraryInfo::getPath(base::DIR_APP_DICTIONARIES).value()); } void BrowserContextQt::setSpellCheckLanguage(const QString &language) diff --git a/src/core/browser_context_qt.h b/src/core/browser_context_qt.h index 08ac05fd4..e2156f147 100644 --- a/src/core/browser_context_qt.h +++ b/src/core/browser_context_qt.h @@ -92,7 +92,7 @@ public: BrowserContextAdapter *adapter() { return m_adapter; } #if defined(ENABLE_SPELLCHECK) - QStringList spellCheckLanguages(const QStringList &acceptLanguages); + void failedToLoadDictionary(const std::string& language) override; void setSpellCheckLanguage(const QString &language); QString spellCheckLanguage() const; void setSpellCheckEnabled(bool enabled); diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index 09df6b48d..3e6a9eac0 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -13,7 +13,6 @@ include(core_common.pri) DEFINES += QT_NO_KEYWORDS \ QT_USE_QSTRINGBUILDER \ Q_FORWARD_DECLARE_OBJC_CLASS=QT_FORWARD_DECLARE_CLASS \ - QTWEBENGINEPROCESS_NAME=\\\"$$QTWEBENGINEPROCESS_NAME\\\" \ QTWEBENGINECORE_VERSION_STR=\\\"$$MODULE_VERSION\\\" \ BUILDING_CHROMIUM diff --git a/src/core/favicon_manager.cpp b/src/core/favicon_manager.cpp index 5568e6eb5..be8d17725 100644 --- a/src/core/favicon_manager.cpp +++ b/src/core/favicon_manager.cpp @@ -52,9 +52,6 @@ #include "third_party/skia/include/core/SkPixelRef.h" #include "ui/gfx/geometry/size.h" -#include <QtCore/QUrl> -#include <QtGui/QIcon> - namespace QtWebEngineCore { static inline bool isResourceUrl(const QUrl &url) @@ -139,6 +136,11 @@ void FaviconManagerPrivate::downloadPendingRequests() void FaviconManagerPrivate::storeIcon(int id, const QIcon &icon) { Q_Q(FaviconManager); + + // Icon download has been interrupted + if (m_inProgressRequests.isEmpty()) + return; + Q_ASSERT(m_inProgressRequests.contains(id)); QUrl requestUrl = m_inProgressRequests[id]; @@ -169,31 +171,18 @@ void FaviconManagerPrivate::storeIcon(int id, const QIcon &icon) } m_inProgressRequests.remove(id); - if (m_inProgressRequests.isEmpty()) - propagateIcon(); -} - -void FaviconManagerPrivate::propagateIcon() const -{ - Q_Q(const FaviconManager); + if (m_inProgressRequests.isEmpty()) { + WebEngineSettings *settings = m_viewClient->webEngineSettings(); + bool touchIconsEnabled = settings->testAttribute(WebEngineSettings::TouchIconsEnabled); - WebEngineSettings *settings = m_viewClient->webEngineSettings(); - bool touchIconsEnabled = settings->testAttribute(WebEngineSettings::TouchIconsEnabled); - - QUrl iconUrl; - const QList<FaviconInfo> &faviconInfoList = q->getFaviconInfoList(true /* candidates only */); - - unsigned bestArea = 0; - for (auto it = faviconInfoList.cbegin(), end = faviconInfoList.cend(); it != end; ++it) { - if (!touchIconsEnabled && it->type != FaviconInfo::Favicon) - continue; - - if (it->isValid() && bestArea < area(it->size)) { - iconUrl = it->url; - bestArea = area(it->size); - } + q->generateCandidateIcon(touchIconsEnabled); + const QUrl &iconUrl = q->candidateIconUrl(touchIconsEnabled); + propagateIcon(iconUrl); } +} +void FaviconManagerPrivate::propagateIcon(const QUrl &iconUrl) const +{ content::NavigationEntry *entry = m_webContents->GetController().GetVisibleEntry(); if (entry) { content::FaviconStatus &favicon = entry->GetFavicon(); @@ -205,7 +194,7 @@ void FaviconManagerPrivate::propagateIcon() const } FaviconManager::FaviconManager(FaviconManagerPrivate *d) - : m_hasCandidate(false) + : m_candidateCount(0) { Q_ASSERT(d); d_ptr.reset(d); @@ -220,6 +209,10 @@ FaviconManager::~FaviconManager() QIcon FaviconManager::getIcon(const QUrl &url) const { Q_D(const FaviconManager); + + if (url.isEmpty()) + return m_candidateIcon; + if (!d->m_icons.contains(url)) return QIcon(); @@ -281,7 +274,7 @@ void FaviconManager::update(const QList<FaviconInfo> &candidates) void FaviconManager::updateCandidates(const QList<FaviconInfo> &candidates) { - m_hasCandidate = candidates.count(); + m_candidateCount = candidates.count(); for (FaviconInfo candidateFaviconInfo : candidates) { const QUrl &candidateUrl = candidateFaviconInfo.url; @@ -298,14 +291,71 @@ void FaviconManager::updateCandidates(const QList<FaviconInfo> &candidates) void FaviconManager::resetCandidates() { - m_hasCandidate = false; + Q_D(FaviconManager); + + // Interrupt in progress icon downloads + d->m_pendingRequests.clear(); + d->m_inProgressRequests.clear(); + + m_candidateCount = 0; + m_candidateIcon = QIcon(); for (auto it = m_faviconInfoMap.begin(), end = m_faviconInfoMap.end(); it != end; ++it) it->candidate = false; } bool FaviconManager::hasCandidate() const { - return m_hasCandidate; + return (m_candidateCount > 0); +} + +QUrl FaviconManager::candidateIconUrl(bool touchIconsEnabled) const +{ + QUrl iconUrl; + const QList<FaviconInfo> &faviconInfoList = getFaviconInfoList(true /* candidates only */); + + unsigned bestArea = 0; + for (auto it = faviconInfoList.cbegin(), end = faviconInfoList.cend(); it != end; ++it) { + if (!touchIconsEnabled && it->type != FaviconInfo::Favicon) + continue; + + if (it->isValid() && bestArea < area(it->size)) { + iconUrl = it->url; + bestArea = area(it->size); + } + } + + return iconUrl; +} + +void FaviconManager::generateCandidateIcon(bool touchIconsEnabled) +{ + Q_ASSERT(m_candidateCount); + + m_candidateIcon = QIcon(); + const QList<FaviconInfo> &faviconInfoList = getFaviconInfoList(true /* candidates only */); + + for (auto it = faviconInfoList.cbegin(), end = faviconInfoList.cend(); it != end; ++it) { + if (!touchIconsEnabled && it->type != FaviconInfo::Favicon) + continue; + + if (!it->isValid() || !it->isDownloaded()) + continue; + + const QIcon &icon = getIcon(it->url); + + if (!it->multiSize) { + if (!m_candidateIcon.availableSizes().contains(it->size)) + m_candidateIcon.addPixmap(icon.pixmap(it->size)); + + continue; + } + + const auto sizes = icon.availableSizes(); + for (const QSize &size : sizes) { + if (!m_candidateIcon.availableSizes().contains(size)) + m_candidateIcon.addPixmap(icon.pixmap(size)); + } + } } @@ -323,6 +373,7 @@ FaviconInfo::FaviconInfo(const FaviconInfo &other) , type(other.type) , size(other.size) , candidate(other.candidate) + , multiSize(other.multiSize) { } diff --git a/src/core/favicon_manager.h b/src/core/favicon_manager.h index dc702a0da..e351831c2 100644 --- a/src/core/favicon_manager.h +++ b/src/core/favicon_manager.h @@ -46,6 +46,7 @@ #include <QtCore/QObject> #include <QtCore/QSize> #include <QtCore/QUrl> +#include <QtGui/QIcon> #include "web_engine_settings.h" @@ -85,7 +86,7 @@ class QWEBENGINE_EXPORT FaviconManager : public QObject { public: ~FaviconManager(); - QIcon getIcon(const QUrl &) const; + QIcon getIcon(const QUrl &url = QUrl()) const; FaviconInfo getFaviconInfo(const QUrl &) const; QList<FaviconInfo> getFaviconInfoList(bool) const; @@ -97,8 +98,12 @@ private: void resetCandidates(); bool hasCandidate() const; + QUrl candidateIconUrl(bool touchIconsEnabled) const; + void generateCandidateIcon(bool touchIconsEnabled); + QMap<QUrl, FaviconInfo> m_faviconInfoMap; - bool m_hasCandidate; + int m_candidateCount; + QIcon m_candidateIcon; Q_DISABLE_COPY(FaviconManager) Q_DECLARE_PRIVATE(FaviconManager) diff --git a/src/core/favicon_manager_p.h b/src/core/favicon_manager_p.h index 80a012474..e2a49dbc7 100644 --- a/src/core/favicon_manager_p.h +++ b/src/core/favicon_manager_p.h @@ -87,7 +87,7 @@ public: void iconDownloadFinished(int, int, const GURL &, const std::vector<SkBitmap> &, const std::vector<gfx::Size> &); void storeIcon(int, const QIcon &); void downloadPendingRequests(); - void propagateIcon() const; + void propagateIcon(const QUrl &) const; content::WebContents *m_webContents; WebContentsAdapterClient *m_viewClient; diff --git a/src/core/gyp_run.pro b/src/core/gyp_run.pro index f7fca8fa8..2e2422dce 100644 --- a/src/core/gyp_run.pro +++ b/src/core/gyp_run.pro @@ -16,7 +16,8 @@ cross_compile { mac: include(config/mac_osx.pri) win32: include(config/windows.pri) } - +GYP_CONFIG += qtwe_process_name_debug=$$QTWEBENGINEPROCESS_NAME_DEBUG +GYP_CONFIG += qtwe_process_name_release=$$QTWEBENGINEPROCESS_NAME_RELEASE GYP_CONFIG += disable_glibcxx_debug=1 !webcore_debug: GYP_CONFIG += remove_webcore_debug_symbols=1 !v8base_debug: GYP_CONFIG += remove_v8base_debug_symbols=1 diff --git a/src/core/network_delegate_qt.cpp b/src/core/network_delegate_qt.cpp index b1a2faf8d..ff0e8320c 100644 --- a/src/core/network_delegate_qt.cpp +++ b/src/core/network_delegate_qt.cpp @@ -90,7 +90,6 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, const net::C { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_ASSERT(m_requestContextGetter); - Q_ASSERT(m_requestContextGetter->m_browserContext); const content::ResourceRequestInfo *resourceInfo = content::ResourceRequestInfo::ForRequest(request); @@ -104,7 +103,7 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, const net::C const QUrl qUrl = toQt(request->url()); - QWebEngineUrlRequestInterceptor* interceptor = m_requestContextGetter->m_browserContext->requestInterceptor(); + QWebEngineUrlRequestInterceptor* interceptor = m_requestContextGetter->m_requestInterceptor; if (interceptor) { QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType) , static_cast<QWebEngineUrlRequestInfo::NavigationType>(navigationType) diff --git a/src/core/qtwebengine.gypi b/src/core/qtwebengine.gypi index 7ed12cadb..4077431b1 100644 --- a/src/core/qtwebengine.gypi +++ b/src/core/qtwebengine.gypi @@ -8,7 +8,7 @@ 'dependencies': [ '<(chromium_src_dir)/base/base.gyp:base', '<(chromium_src_dir)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', - '<(chromium_src_dir)/chrome/tools/convert_dict/convert_dict.gyp:convert_dict', + '<(chromium_src_dir)/chrome/tools/convert_dict/convert_dict.gyp:convert_dict_lib', '<(chromium_src_dir)/components/components.gyp:devtools_discovery', '<(chromium_src_dir)/components/components.gyp:devtools_http_handler', '<(chromium_src_dir)/components/components.gyp:error_page_renderer', diff --git a/src/core/qtwebengine_extras.gypi b/src/core/qtwebengine_extras.gypi index a5de08b55..229421efa 100644 --- a/src/core/qtwebengine_extras.gypi +++ b/src/core/qtwebengine_extras.gypi @@ -63,6 +63,28 @@ 'defines': [ 'TOOLKIT_QT', ], + 'configurations': { + 'Debug': { + 'defines': [ + 'QTWEBENGINEPROCESS_NAME="<(qtwe_process_name_debug)"' + ], + }, + 'Debug_x64': { + 'defines': [ + 'QTWEBENGINEPROCESS_NAME="<(qtwe_process_name_debug)"' + ], + }, + 'Release': { + 'defines': [ + 'QTWEBENGINEPROCESS_NAME="<(qtwe_process_name_release)"' + ], + }, + 'Release_x64': { + 'defines': [ + 'QTWEBENGINEPROCESS_NAME="<(qtwe_process_name_release)"' + ], + }, + }, }, 'conditions': [ [ 'qt_os=="embedded_linux"', { diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp index afbb66b95..579e33b66 100644 --- a/src/core/url_request_context_getter_qt.cpp +++ b/src/core/url_request_context_getter_qt.cpp @@ -91,14 +91,23 @@ using content::BrowserThread; URLRequestContextGetterQt::URLRequestContextGetterQt(QSharedPointer<BrowserContextAdapter> browserContext, content::ProtocolHandlerMap *protocolHandlers, content::URLRequestInterceptorScopedVector request_interceptors) : m_ignoreCertificateErrors(false) + , m_mutex(QMutex::Recursive) + , m_contextInitialized(false) + , m_updateAllStorage(false) + , m_updateCookieStore(false) + , m_updateHttpCache(false) + , m_updateJobFactory(true) + , m_updateUserAgent(false) , m_browserContext(browserContext) , m_baseJobFactory(0) , m_cookieDelegate(new CookieMonsterDelegateQt()) , m_requestInterceptors(std::move(request_interceptors)) { std::swap(m_protocolHandlers, *protocolHandlers); - m_cookieDelegate->setClient(m_browserContext->cookieStore()); + QMutexLocker lock(&m_mutex); + m_cookieDelegate->setClient(browserContext->cookieStore()); + setFullConfiguration(browserContext); updateStorageSettings(); } @@ -108,6 +117,23 @@ URLRequestContextGetterQt::~URLRequestContextGetterQt() delete m_proxyConfigService.fetchAndStoreAcquire(0); } + +void URLRequestContextGetterQt::setFullConfiguration(QSharedPointer<BrowserContextAdapter> browserContext) +{ + if (!browserContext) + return; + + m_requestInterceptor = browserContext->requestInterceptor(); + m_persistentCookiesPolicy = browserContext->persistentCookiesPolicy(); + m_cookiesPath = browserContext->cookiesPath(); + m_httpAcceptLanguage = browserContext->httpAcceptLanguage(); + m_httpUserAgent = browserContext->httpUserAgent(); + m_httpCacheType = browserContext->httpCacheType(); + m_httpCachePath = browserContext->httpCachePath(); + m_httpCacheMaxSize = browserContext->httpCacheMaxSize(); + m_customUrlSchemes = browserContext->customUrlSchemes(); +} + net::URLRequestContext *URLRequestContextGetterQt::GetURLRequestContext() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); @@ -117,8 +143,10 @@ net::URLRequestContext *URLRequestContextGetterQt::GetURLRequestContext() m_networkDelegate.reset(new NetworkDelegateQt(this)); m_urlRequestContext->set_network_delegate(m_networkDelegate.get()); - generateStorage(); + QMutexLocker lock(&m_mutex); + generateAllStorage(); generateJobFactory(); + m_contextInitialized = true; } return m_urlRequestContext.get(); @@ -127,24 +155,31 @@ net::URLRequestContext *URLRequestContextGetterQt::GetURLRequestContext() void URLRequestContextGetterQt::updateStorageSettings() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - // m_proxyConfigService having a non-null value is used to indicate - // storage is already being updated. - if (!m_proxyConfigService.loadAcquire()) { + + QMutexLocker lock(&m_mutex); + setFullConfiguration(m_browserContext.toStrongRef()); + + if (!m_updateAllStorage) { + m_updateAllStorage = true; // We must create the proxy config service on the UI loop on Linux because it // must synchronously run on the glib message loop. This will be passed to // the URLRequestContextStorage on the IO thread in GetURLRequestContext(). - m_proxyConfigService.storeRelease(new ProxyConfigServiceQt(net::ProxyService::CreateSystemProxyConfigService( - content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), - content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE) - ))); - if (m_storage) { - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateStorage, this)); - } + Q_ASSERT(m_proxyConfigService == 0); + m_proxyConfigService = + new ProxyConfigServiceQt( + net::ProxyService::CreateSystemProxyConfigService( + content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), + content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE) + )); + if (m_contextInitialized) + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&URLRequestContextGetterQt::generateAllStorage, this)); } } void URLRequestContextGetterQt::cancelAllUrlRequests() { + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_ASSERT(m_urlRequestContext); std::set<const net::URLRequest*>* url_requests = m_urlRequestContext->url_requests(); @@ -158,6 +193,17 @@ void URLRequestContextGetterQt::cancelAllUrlRequests() } +void URLRequestContextGetterQt::generateAllStorage() +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + QMutexLocker lock(&m_mutex); + generateStorage(); + generateCookieStore(); + generateUserAgent(); + generateHttpCache(); + m_updateAllStorage = false; +} + void URLRequestContextGetterQt::generateStorage() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); @@ -175,8 +221,6 @@ void URLRequestContextGetterQt::generateStorage() net::ProxyConfigService *proxyConfigService = m_proxyConfigService.fetchAndStoreAcquire(0); Q_ASSERT(proxyConfigService); - generateCookieStore(); - generateUserAgent(); m_storage->set_channel_id_service(scoped_ptr<net::ChannelIDService>(new net::ChannelIDService( new net::DefaultChannelIDStore(NULL), @@ -207,16 +251,20 @@ void URLRequestContextGetterQt::generateStorage() // Give |m_storage| ownership at the end in case it's |mapped_host_resolver|. m_storage->set_host_resolver(std::move(host_resolver)); - - generateHttpCache(); } void URLRequestContextGetterQt::updateCookieStore() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - // Do not trigger an update if another is already triggered, or we are not yet initialized. - if (m_urlRequestContext && !m_proxyConfigService && !m_updateCookieStore.fetchAndStoreRelaxed(1)) - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateCookieStore, this)); + QMutexLocker lock(&m_mutex); + m_httpAcceptLanguage = m_browserContext.data()->httpAcceptLanguage(); + m_httpUserAgent = m_browserContext.data()->httpUserAgent(); + + if (m_contextInitialized && !m_updateAllStorage && !m_updateCookieStore) { + m_updateCookieStore = true; + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&URLRequestContextGetterQt::generateCookieStore, this)); + } } void URLRequestContextGetterQt::generateCookieStore() @@ -224,14 +272,16 @@ void URLRequestContextGetterQt::generateCookieStore() Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_ASSERT(m_urlRequestContext); Q_ASSERT(m_storage); - m_updateCookieStore = 0; + + QMutexLocker lock(&m_mutex); + m_updateCookieStore = false; // Unset it first to get a chance to destroy and flush the old cookie store before opening a new on possibly the same file. m_storage->set_cookie_store(0); m_cookieDelegate->setCookieMonster(0); net::CookieStore* cookieStore = 0; - switch (m_browserContext->persistentCookiesPolicy()) { + switch (m_persistentCookiesPolicy) { case BrowserContextAdapter::NoPersistentCookies: cookieStore = content::CreateCookieStore(content::CookieStoreConfig( @@ -244,7 +294,7 @@ void URLRequestContextGetterQt::generateCookieStore() case BrowserContextAdapter::AllowPersistentCookies: cookieStore = content::CreateCookieStore(content::CookieStoreConfig( - toFilePath(m_browserContext->cookiesPath()), + toFilePath(m_cookiesPath), content::CookieStoreConfig::PERSISTANT_SESSION_COOKIES, NULL, m_cookieDelegate.get()) @@ -253,7 +303,7 @@ void URLRequestContextGetterQt::generateCookieStore() case BrowserContextAdapter::ForcePersistentCookies: cookieStore = content::CreateCookieStore(content::CookieStoreConfig( - toFilePath(m_browserContext->cookiesPath()), + toFilePath(m_cookiesPath), content::CookieStoreConfig::RESTORED_SESSION_COOKIES, NULL, m_cookieDelegate.get()) @@ -270,9 +320,15 @@ void URLRequestContextGetterQt::generateCookieStore() void URLRequestContextGetterQt::updateUserAgent() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - // Do not trigger an update if all storage settings are already being updated - if (m_urlRequestContext && !m_proxyConfigService) - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateUserAgent, this)); + QMutexLocker lock(&m_mutex); + m_httpAcceptLanguage = m_browserContext.data()->httpAcceptLanguage(); + m_httpUserAgent = m_browserContext.data()->httpUserAgent(); + + if (m_contextInitialized && !m_updateAllStorage && !m_updateUserAgent) { + m_updateUserAgent = true; + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&URLRequestContextGetterQt::generateUserAgent, this)); + } } void URLRequestContextGetterQt::generateUserAgent() @@ -281,26 +337,48 @@ void URLRequestContextGetterQt::generateUserAgent() Q_ASSERT(m_urlRequestContext); Q_ASSERT(m_storage); + QMutexLocker lock(&m_mutex); + m_updateUserAgent = true; + m_storage->set_http_user_agent_settings(scoped_ptr<net::HttpUserAgentSettings>( - new net::StaticHttpUserAgentSettings(m_browserContext->httpAcceptLanguage().toStdString(), m_browserContext->httpUserAgent().toStdString()))); + new net::StaticHttpUserAgentSettings(m_httpAcceptLanguage.toStdString(), m_httpUserAgent.toStdString()))); } void URLRequestContextGetterQt::updateHttpCache() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - // Do not trigger a new update if another is already triggered - if (m_urlRequestContext && !m_proxyConfigService && !m_updateHttpCache.fetchAndStoreRelaxed(1)) - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateHttpCache, this)); + QMutexLocker lock(&m_mutex); + m_httpCacheType = m_browserContext.data()->httpCacheType(); + m_httpCachePath = m_browserContext.data()->httpCachePath(); + m_httpCacheMaxSize = m_browserContext.data()->httpCacheMaxSize(); + + if (m_contextInitialized && !m_updateAllStorage && !m_updateHttpCache) { + m_updateHttpCache = true; + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&URLRequestContextGetterQt::generateHttpCache, this)); + } } void URLRequestContextGetterQt::updateJobFactory() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + QMutexLocker lock(&m_mutex); + m_customUrlSchemes = m_browserContext.data()->customUrlSchemes(); - if (m_urlRequestContext && !m_updateJobFactory.fetchAndStoreRelaxed(1)) + if (m_contextInitialized && !m_updateJobFactory) { + m_updateJobFactory = true; content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestContextGetterQt::regenerateJobFactory, - this, m_browserContext->customUrlSchemes())); + base::Bind(&URLRequestContextGetterQt::regenerateJobFactory, this)); + } +} + +void URLRequestContextGetterQt::updateRequestInterceptor() +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + QMutexLocker lock(&m_mutex); + m_requestInterceptor = m_browserContext.data()->requestInterceptor(); + + // We in this case do not need to regenerate any Chromium classes. } static bool doNetworkSessionParamsMatch(const net::HttpNetworkSession::Params &first, const net::HttpNetworkSession::Params &second) @@ -355,15 +433,18 @@ void URLRequestContextGetterQt::generateHttpCache() Q_ASSERT(m_urlRequestContext); Q_ASSERT(m_storage); + QMutexLocker lock(&m_mutex); + m_updateHttpCache = false; + net::HttpCache::DefaultBackend* main_backend = 0; - switch (m_browserContext->httpCacheType()) { + switch (m_httpCacheType) { case BrowserContextAdapter::MemoryHttpCache: main_backend = new net::HttpCache::DefaultBackend( net::MEMORY_CACHE, net::CACHE_BACKEND_DEFAULT, base::FilePath(), - m_browserContext->httpCacheMaxSize(), + m_httpCacheMaxSize, BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE) ); break; @@ -372,8 +453,8 @@ void URLRequestContextGetterQt::generateHttpCache() new net::HttpCache::DefaultBackend( net::DISK_CACHE, net::CACHE_BACKEND_DEFAULT, - toFilePath(m_browserContext->httpCachePath()), - m_browserContext->httpCacheMaxSize(), + toFilePath(m_httpCachePath), + m_httpCacheMaxSize, BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE) ); break; @@ -393,7 +474,6 @@ void URLRequestContextGetterQt::generateHttpCache() cache = new net::HttpCache(m_httpNetworkSession.get(), scoped_ptr<net::HttpCache::DefaultBackend>(main_backend), false); m_storage->set_http_transaction_factory(scoped_ptr<net::HttpCache>(cache)); - m_updateHttpCache = 0; } void URLRequestContextGetterQt::clearHttpCache() @@ -419,6 +499,9 @@ void URLRequestContextGetterQt::generateJobFactory() Q_ASSERT(m_urlRequestContext); Q_ASSERT(!m_jobFactory); + QMutexLocker lock(&m_mutex); + m_updateJobFactory = false; + scoped_ptr<net::URLRequestJobFactoryImpl> jobFactory(new net::URLRequestJobFactoryImpl()); { @@ -437,7 +520,7 @@ void URLRequestContextGetterQt::generateJobFactory() jobFactory->SetProtocolHandler(url::kFtpScheme, scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(new net::FtpProtocolHandler(new net::FtpNetworkLayer(m_urlRequestContext->host_resolver())))); - m_installedCustomSchemes = m_browserContext->customUrlSchemes(); + m_installedCustomSchemes = m_customUrlSchemes; Q_FOREACH (const QByteArray &scheme, m_installedCustomSchemes) { jobFactory->SetProtocolHandler(scheme.toStdString(), scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(new CustomProtocolHandler(m_browserContext))); } @@ -457,22 +540,24 @@ void URLRequestContextGetterQt::generateJobFactory() m_urlRequestContext->set_job_factory(m_jobFactory.get()); } -void URLRequestContextGetterQt::regenerateJobFactory(const QList<QByteArray> customSchemes) +void URLRequestContextGetterQt::regenerateJobFactory() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); Q_ASSERT(m_urlRequestContext); Q_ASSERT(m_jobFactory); Q_ASSERT(m_baseJobFactory); - m_updateJobFactory.storeRelease(0); - if (customSchemes == m_installedCustomSchemes) + QMutexLocker lock(&m_mutex); + m_updateJobFactory = false; + + if (m_customUrlSchemes == m_installedCustomSchemes) return; Q_FOREACH (const QByteArray &scheme, m_installedCustomSchemes) { m_baseJobFactory->SetProtocolHandler(scheme.toStdString(), nullptr); } - m_installedCustomSchemes = customSchemes; + m_installedCustomSchemes = m_customUrlSchemes; Q_FOREACH (const QByteArray &scheme, m_installedCustomSchemes) { m_baseJobFactory->SetProtocolHandler(scheme.toStdString(), scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(new CustomProtocolHandler(m_browserContext))); } diff --git a/src/core/url_request_context_getter_qt.h b/src/core/url_request_context_getter_qt.h index 7078c7a44..eca956ea6 100644 --- a/src/core/url_request_context_getter_qt.h +++ b/src/core/url_request_context_getter_qt.h @@ -55,9 +55,10 @@ #include "cookie_monster_delegate_qt.h" #include "network_delegate_qt.h" +#include "browser_context_adapter.h" -#include <QtCore/qglobal.h> #include <QtCore/qatomic.h> +#include <QtCore/qmutex.h> #include <QtCore/qsharedpointer.h> namespace net { @@ -67,8 +68,7 @@ class ProxyConfigService; namespace QtWebEngineCore { -class BrowserContextAdapter; - +// FIXME: This class should be split into a URLRequestContextGetter and a ProfileIOData, similar to what chrome does. class URLRequestContextGetterQt : public net::URLRequestContextGetter { public: URLRequestContextGetterQt(QSharedPointer<BrowserContextAdapter> browserContext, content::ProtocolHandlerMap *protocolHandlers, content::URLRequestInterceptorScopedVector request_interceptors); @@ -83,26 +83,36 @@ public: void updateHttpCache(); void clearHttpCache(); void updateJobFactory(); + void updateRequestInterceptor(); private: virtual ~URLRequestContextGetterQt(); // Called on the IO thread: + void generateAllStorage(); void generateStorage(); void generateCookieStore(); void generateHttpCache(); void generateUserAgent(); void generateJobFactory(); - void regenerateJobFactory(const QList<QByteArray> customSchemes); + void regenerateJobFactory(); void clearCurrentCacheBackend(); void cancelAllUrlRequests(); net::HttpNetworkSession::Params generateNetworkSessionParams(); + void setFullConfiguration(QSharedPointer<BrowserContextAdapter> browserContext); + bool m_ignoreCertificateErrors; - QAtomicInt m_updateCookieStore; - QAtomicInt m_updateHttpCache; - QAtomicInt m_updateJobFactory; - QSharedPointer<BrowserContextAdapter> m_browserContext; + + QMutex m_mutex; + bool m_contextInitialized; + bool m_updateAllStorage; + bool m_updateCookieStore; + bool m_updateHttpCache; + bool m_updateJobFactory; + bool m_updateUserAgent; + + QWeakPointer<BrowserContextAdapter> m_browserContext; content::ProtocolHandlerMap m_protocolHandlers; QAtomicPointer<net::ProxyConfigService> m_proxyConfigService; @@ -115,7 +125,20 @@ private: scoped_refptr<CookieMonsterDelegateQt> m_cookieDelegate; content::URLRequestInterceptorScopedVector m_requestInterceptors; scoped_ptr<net::HttpNetworkSession> m_httpNetworkSession; + QList<QByteArray> m_installedCustomSchemes; + QWebEngineUrlRequestInterceptor* m_requestInterceptor; + + // Configuration values to setup URLRequestContext in IO thread, copied from browserContext + // FIXME: Should later be moved to a separate ProfileIOData class. + BrowserContextAdapter::PersistentCookiesPolicy m_persistentCookiesPolicy; + QString m_cookiesPath; + QString m_httpAcceptLanguage; + QString m_httpUserAgent; + BrowserContextAdapter::HttpCacheType m_httpCacheType; + QString m_httpCachePath; + int m_httpCacheMaxSize; + QList<QByteArray> m_customUrlSchemes; friend class NetworkDelegateQt; }; diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 116cd704e..82d21696c 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -520,6 +520,7 @@ void WebContentsAdapter::setContent(const QByteArray &data, const QString &mimeT params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; d->webContents->GetController().LoadURLWithParams(params); d->webContents->Focus(); + d->webContents->Unselect(); } void WebContentsAdapter::save() diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp index a67bce94c..2de3d39ff 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -211,20 +211,12 @@ QString dictionariesPath() #if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) return getResourcesPath(frameworkBundle()) % QLatin1String("/qtwebengine_dictionaries"); #else - static bool initialized = false; - static QString potentialDictionariesPath = QLibraryInfo::location(QLibraryInfo::DataPath) % QDir::separator() % QLatin1String("qtwebengine_dictionaries"); + // first local path + static QString potentialDictionariesPath = QCoreApplication::applicationDirPath() % QDir::separator() % QLatin1String("qtwebengine_dictionaries"); - if (!initialized) { - initialized = true; - if (!QFileInfo::exists(potentialDictionariesPath)) { - qWarning("Installed Qt WebEngine dictionaries directory not found at location %s. Trying application directory...", qPrintable(potentialDictionariesPath)); - potentialDictionariesPath = QCoreApplication::applicationDirPath() % QDir::separator() % QLatin1String("qtwebengine_dictionaries"); - } - if (!QFileInfo::exists(potentialDictionariesPath)) { - qWarning("Qt WebEngine dictionaries directory not found at location %s. Trying fallback directory... Spellcheck MAY NOT work.", qPrintable(potentialDictionariesPath)); - potentialDictionariesPath = fallbackDir(); - } - } + // now global one + if (!QFileInfo::exists(potentialDictionariesPath)) + potentialDictionariesPath = QLibraryInfo::location(QLibraryInfo::DataPath) % QDir::separator() % QLatin1String("qtwebengine_dictionaries"); return potentialDictionariesPath; #endif diff --git a/src/process/process.pro b/src/process/process.pro index cdda429e7..cd60b1f91 100644 --- a/src/process/process.pro +++ b/src/process/process.pro @@ -16,6 +16,8 @@ win32 { load(qt_app) +contains(QT_CONFIG, build_all): CONFIG += build_all + contains(QT_CONFIG, qt_framework) { # Deploy the QtWebEngineProcess app bundle into the QtWebEngineCore framework. DESTDIR = $$MODULE_BASE_OUTDIR/lib/QtWebEngineCore.framework/Versions/5/Helpers diff --git a/src/src.pro b/src/src.pro index 6a6a6abb8..64c1703fe 100644 --- a/src/src.pro +++ b/src/src.pro @@ -17,6 +17,13 @@ SUBDIRS += core \ webengine_experimental_plugin \ plugins +# allow only desktop builds of qwebengine_convert_dict +# osx does not use hunspell +!contains(WEBENGINE_CONFIG, no_spellcheck):!osx:!cross_compile { + SUBDIRS += qwebengine_convert_dict + qwebengine_convert_dict.subdir = tools/qwebengine_convert_dict + qwebengine_convert_dict.depends = core +} isQMLTestSupportApiEnabled() { webengine_testsupport_plugin.subdir = webengine/plugin/testsupport diff --git a/src/tools/qwebengine_convert_dict/main.cpp b/src/tools/qwebengine_convert_dict/main.cpp new file mode 100644 index 000000000..2142b5f0d --- /dev/null +++ b/src/tools/qwebengine_convert_dict/main.cpp @@ -0,0 +1,183 @@ +/****************************************************************************** +** This is just slightly modified version of convert_dict.cc +** chromium/chrome/tools/convert_dict/convert_dict.cc +** +** Original work: +** Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +** Modified work: +** Copyright (C) 2016 The Qt Company Ltd. +** +** Use of this source code is governed by a BSD-style license that can be +** found in the LICENSE file. +** +** This tool converts Hunspell .aff/.dic pairs to a combined binary dictionary +** format (.bdic). This format is more compact, and can be more efficiently +** read by the client application. +** +******************************************************************************/ + +#include <base/at_exit.h> +#include <base/files/file_path.h> +#include <base/files/file_util.h> +#include <base/i18n/icu_util.h> +#include <build/build_config.h> +#include <chrome/tools/convert_dict/aff_reader.h> +#include <chrome/tools/convert_dict/dic_reader.h> +#include <third_party/hunspell/google/bdict_reader.h> +#include <third_party/hunspell/google/bdict_writer.h> +#include <base/path_service.h> + +#include <QTextStream> +#include <QLibraryInfo> +#include <QDir> + +// see also src/core/type_conversion.h +inline base::FilePath::StringType toFilePathString(const QString &str) +{ +#if defined(Q_OS_WIN) + return QDir::toNativeSeparators(str).toStdWString(); +#else + return str.toStdString(); +#endif +} + +inline base::FilePath toFilePath(const QString &str) +{ + return base::FilePath(toFilePathString(str)); +} + +inline QString toQt(const base::string16 &string) +{ +#if defined(OS_WIN) + return QString::fromStdWString(string.data()); +#else + return QString::fromUtf16(string.data()); +#endif +} + +inline QString toQt(const std::string &string) +{ + return QString::fromStdString(string); +} + +// Compares the given word list with the serialized trie to make sure they +// are the same. +inline bool VerifyWords(const convert_dict::DicReader::WordList& org_words, + const std::string& serialized, QTextStream& out) +{ + hunspell::BDictReader reader; + if (!reader.Init(reinterpret_cast<const unsigned char*>(serialized.data()), + serialized.size())) { + out << "BDict is invalid" << endl; + return false; + } + hunspell::WordIterator iter = reader.GetAllWordIterator(); + + int affix_ids[hunspell::BDict::MAX_AFFIXES_PER_WORD]; + + static const int buf_size = 128; + char buf[buf_size]; + for (size_t i = 0; i < org_words.size(); i++) { + int affix_matches = iter.Advance(buf, buf_size, affix_ids); + if (affix_matches == 0) { + out << "Found the end before we expected" << endl; + return false; + } + + if (org_words[i].first != buf) { + out << "Word doesn't match, word #" << buf << endl; + return false; + } + + if (affix_matches != static_cast<int>(org_words[i].second.size())) { + out << "Different number of affix indices, word #" << buf << endl; + return false; + } + + // Check the individual affix indices. + for (size_t affix_index = 0; affix_index < org_words[i].second.size(); + affix_index++) { + if (affix_ids[affix_index] != org_words[i].second[affix_index]) { + out << "Index doesn't match, word #" << buf << endl; + return false; + } + } + } + + return true; +} + +int main(int argc, char *argv[]) +{ + QTextStream out(stdout); + + if (argc != 3) { + QTextStream out(stdout); + out << "Usage: qwebengine_convert_dict <dic file> <bdic file>\n\nExample:\n" + "qwebengine_convert_dict ./en-US.dic ./en-US.bdic\nwill read en-US.dic, " + "en-US.dic_delta, and en-US.aff from the current directory and generate " + "en-US.bdic\n" << endl; + return 1; + } + + PathService::Override(base::DIR_QT_LIBRARY_DATA, + toFilePath(QLibraryInfo::location(QLibraryInfo::DataPath) % + QLatin1String("/resources"))); + + base::AtExitManager exit_manager; + base::i18n::InitializeICU(); + + base::FilePath file_in_path = toFilePath(argv[1]); + base::FilePath file_out_path = toFilePath(argv[2]); + base::FilePath aff_path = file_in_path.ReplaceExtension(FILE_PATH_LITERAL(".aff")); + + out << "Reading " << toQt(aff_path.value()) << endl; + convert_dict::AffReader aff_reader(aff_path); + + if (!aff_reader.Read()) { + out << "Unable to read the aff file." << endl; + return 1; + } + + base::FilePath dic_path = file_in_path.ReplaceExtension(FILE_PATH_LITERAL(".dic")); + out << "Reading " << toQt(dic_path.value()) << endl; + + // DicReader will also read the .dic_delta file. + convert_dict::DicReader dic_reader(dic_path); + if (!dic_reader.Read(&aff_reader)) { + out << "Unable to read the dic file." << endl; + return 1; + } + + hunspell::BDictWriter writer; + writer.SetComment(aff_reader.comments()); + writer.SetAffixRules(aff_reader.affix_rules()); + writer.SetAffixGroups(aff_reader.GetAffixGroups()); + writer.SetReplacements(aff_reader.replacements()); + writer.SetOtherCommands(aff_reader.other_commands()); + writer.SetWords(dic_reader.words()); + + out << "Serializing..." << endl; + + std::string serialized = writer.GetBDict(); + + out << "Verifying..." << endl; + + if (!VerifyWords(dic_reader.words(), serialized, out)) { + out << "ERROR converting, the dictionary does not check out OK." << endl; + return 1; + } + + out << "Writing " << toQt(file_out_path.value()) << endl; + FILE *out_file = base::OpenFile(file_out_path, "wb"); + if (!out_file) { + out << "ERROR writing file" << endl; + return 1; + } + size_t written = fwrite(&serialized[0], 1, serialized.size(), out_file); + Q_ASSERT(written == serialized.size()); + base::CloseFile(out_file); + out << "Success. Dictionary converted." << endl; + return 0; +} + diff --git a/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro b/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro new file mode 100644 index 000000000..de125cc76 --- /dev/null +++ b/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro @@ -0,0 +1,22 @@ +option(host_build) + +# Look for linking information produced by gyp for our target according to core_generated.gyp +!include($$OUT_PWD/../../core/$$getConfigDir()/QtWebEngineCore_linking.pri) { + error("Could not find the linking information that gyp should have generated.") +} +# remove object files from linking information +OBJECTS = + +# Fixme: -Werror=unused-parameter in core +QMAKE_CXXFLAGS_WARN_ON = + +# Issue with some template compliation, smb smart should look at it +win32: DEFINES += NOMINMAX + +CHROMIUM_SRC_DIR = $$QTWEBENGINE_ROOT/$$getChromiumSrcDir() +INCLUDEPATH += $$CHROMIUM_SRC_DIR + +SOURCES += \ + main.cpp + +load(qt_tool) diff --git a/src/webengine/api/qquickwebenginecontextmenudata.cpp b/src/webengine/api/qquickwebenginecontextmenudata.cpp index 221b42245..684903ec0 100644 --- a/src/webengine/api/qquickwebenginecontextmenudata.cpp +++ b/src/webengine/api/qquickwebenginecontextmenudata.cpp @@ -170,30 +170,6 @@ bool QQuickWebEngineContextMenuData::isContentEditable() const return d ? d->isEditable : false; } -/*! - \qmlproperty QString WebEngineDownloadItem::misspelledWord - - If the context is a word considered misspelled by the spell-checker, returns the misspelled word. -*/ -QString QQuickWebEngineContextMenuData::misspelledWord() const -{ - if (d) - return d->misspelledWord; - return QString(); -} - -/*! - \qmlproperty QStringList WebEngineDownloadItem::spellCheckerSuggestions - - If the context is a word considered misspelled by the spell-checker, returns a list of suggested replacements. -*/ -QStringList QQuickWebEngineContextMenuData::spellCheckerSuggestions() const -{ - if (d) - return d->spellCheckerSuggestions; - return QStringList(); -} - void QQuickWebEngineContextMenuData::update(const QtWebEngineCore::WebEngineContextMenuData &update) { const QQuickWebEngineContextMenuData old(d); @@ -222,12 +198,6 @@ void QQuickWebEngineContextMenuData::update(const QtWebEngineCore::WebEngineCont if (isContentEditable() != old.isContentEditable()) Q_EMIT isContentEditableChanged(); - - if (misspelledWord() != old.misspelledWord()) - Q_EMIT misspelledWordChanged(); - - if (spellCheckerSuggestions() != old.spellCheckerSuggestions()) - Q_EMIT spellCheckerSuggestionsChanged(); } QQuickWebEngineContextMenuData::QQuickWebEngineContextMenuData(const QQuickWebEngineContextMenuDataPrivate *p, QObject *parent) diff --git a/src/webengine/api/qquickwebenginecontextmenudata_p.h b/src/webengine/api/qquickwebenginecontextmenudata_p.h index 0989eaa5a..aa081cbe6 100644 --- a/src/webengine/api/qquickwebenginecontextmenudata_p.h +++ b/src/webengine/api/qquickwebenginecontextmenudata_p.h @@ -92,8 +92,6 @@ public: Q_PROPERTY(QUrl mediaUrl READ mediaUrl NOTIFY mediaUrlChanged) Q_PROPERTY(MediaType mediaType READ mediaType NOTIFY mediaTypeChanged) Q_PROPERTY(bool isContentEditable READ isContentEditable NOTIFY isContentEditableChanged) - Q_PROPERTY(QString misspelledWord READ misspelledWord NOTIFY misspelledWordChanged) - Q_PROPERTY(QStringList spellCheckerSuggestions READ spellCheckerSuggestions NOTIFY spellCheckerSuggestionsChanged) bool isValid() const; @@ -105,9 +103,6 @@ public: MediaType mediaType() const; bool isContentEditable() const; - QString misspelledWord() const; - QStringList spellCheckerSuggestions() const; - Q_SIGNALS: void isValidChanged(); void positionChanged(); @@ -117,8 +112,6 @@ Q_SIGNALS: void mediaUrlChanged(); void mediaTypeChanged(); void isContentEditableChanged(); - void misspelledWordChanged(); - void spellCheckerSuggestionsChanged(); private: void update(const QtWebEngineCore::WebEngineContextMenuData &update); diff --git a/src/webengine/api/qquickwebenginefaviconprovider.cpp b/src/webengine/api/qquickwebenginefaviconprovider.cpp index c41ec5a07..fe8436d6c 100644 --- a/src/webengine/api/qquickwebenginefaviconprovider.cpp +++ b/src/webengine/api/qquickwebenginefaviconprovider.cpp @@ -121,12 +121,13 @@ QPixmap QQuickWebEngineFaviconProvider::requestPixmap(const QString &id, QSize * return QPixmap(); FaviconManager *faviconManager = view->d_ptr->adapter->faviconManager(); - Q_ASSERT(faviconManager); - const QIcon &icon = faviconManager->getIcon(iconUrl); + Q_ASSERT(faviconManager); + const FaviconInfo &faviconInfo = faviconManager->getFaviconInfo(iconUrl); + const QIcon &icon = faviconManager->getIcon(faviconInfo.candidate ? QUrl() : iconUrl); Q_ASSERT(!icon.isNull()); - const QSize &bestSize = faviconManager->getFaviconInfo(iconUrl).size; + const QSize &bestSize = faviconInfo.size; // If source size is not specified, use the best quality if (!requestedSize.isValid()) { diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index d7a84c106..c1f8f3179 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -613,95 +613,6 @@ QQuickWebEngineProfile *QQuickWebEngineProfile::defaultProfile() } /*! - \qmlmethod void QQuickWebEngineProfile::availableDictionaries() - - Returns the subset of \a languages supported by the spell checker. - Checks whether the spell checker dictionary is installed for the specified - language from the \a languages list. If the dictionary file is missing - or corrupted, the language is removed from the returned list. - - \since QtWebEngine 1.3 -*/ - -/*! - Returns the subset of \a languages supported by the spell checker. - Checks whether the spell checker dictionary is installed for the specified - language from the \a languages list. If the dictionary file is missing - or corrupted, the language is removed from the returned list. - - \since QtWebEngine 1.3 -*/ -QStringList QQuickWebEngineProfile::availableDictionaries(const QStringList &languages) -{ - const Q_D(QQuickWebEngineProfile); - return d->browserContext()->spellCheckLanguages(languages); -} - -/*! - \property QQuickWebEngineProfile::spellCheckLanguage - \brief the language used by the spell checker. - - \since QtWebEngine 1.3 -*/ - -/*! - \qmlproperty QString WebEngineProfile::spellCheckLanguage - - This property holds the language used by the spell checker. - - \since QtWebEngine 1.3 -*/ -void QQuickWebEngineProfile::setSpellCheckLanguage(const QString &language) -{ - Q_D(QQuickWebEngineProfile); - if (language != d->browserContext()->spellCheckLanguage()) { - d->browserContext()->setSpellCheckLanguage(language); - emit spellCheckLanguageChanged(); - } -} - -/*! - \since 5.7 - - Returns the language used by the spell checker. -*/ -QString QQuickWebEngineProfile::spellCheckLanguage() const -{ - const Q_D(QQuickWebEngineProfile); - return d->browserContext()->spellCheckLanguage(); -} - -/*! - \property QQuickWebEngineProfile::spellCheckEnabled - \brief whether the web engine spell checker is enabled. - - \since QtWebEngine 1.3 -*/ - -/*! - \qmlproperty QString WebEngineProfile::spellCheckEnabled - - This property holds whether the web engine spell checker is enabled. - - \since QtWebEngine 1.3 -*/ -void QQuickWebEngineProfile::setSpellCheckEnabled(bool enable) -{ - Q_D(QQuickWebEngineProfile); - if (enable != isSpellCheckEnabled()) { - d->browserContext()->setSpellCheckEnabled(enable); - emit spellCheckEnabledChanged(); - } -} - -bool QQuickWebEngineProfile::isSpellCheckEnabled() const -{ - const Q_D(QQuickWebEngineProfile); - return d->browserContext()->isSpellCheckEnabled(); -} - -/*! - Returns the cookie store for this profile. */ QWebEngineCookieStore *QQuickWebEngineProfile::cookieStore() const diff --git a/src/webengine/api/qquickwebengineprofile.h b/src/webengine/api/qquickwebengineprofile.h index 8d120d10e..4f9684a86 100644 --- a/src/webengine/api/qquickwebengineprofile.h +++ b/src/webengine/api/qquickwebengineprofile.h @@ -71,8 +71,6 @@ class Q_WEBENGINE_EXPORT QQuickWebEngineProfile : public QObject { Q_PROPERTY(QString httpAcceptLanguage READ httpAcceptLanguage WRITE setHttpAcceptLanguage NOTIFY httpAcceptLanguageChanged FINAL REVISION 1) Q_PROPERTY(PersistentCookiesPolicy persistentCookiesPolicy READ persistentCookiesPolicy WRITE setPersistentCookiesPolicy NOTIFY persistentCookiesPolicyChanged FINAL) Q_PROPERTY(int httpCacheMaximumSize READ httpCacheMaximumSize WRITE setHttpCacheMaximumSize NOTIFY httpCacheMaximumSizeChanged FINAL) - Q_PROPERTY(QString spellCheckLanguage READ spellCheckLanguage WRITE setSpellCheckLanguage NOTIFY spellCheckLanguageChanged FINAL REVISION 2) - Q_PROPERTY(bool spellCheckEnabled READ isSpellCheckEnabled WRITE setSpellCheckEnabled NOTIFY spellCheckEnabledChanged FINAL REVISION 2) public: QQuickWebEngineProfile(QObject *parent = Q_NULLPTR); @@ -131,12 +129,6 @@ public: void clearHttpCache(); - Q_REVISION(2) Q_INVOKABLE QStringList availableDictionaries(const QStringList &languages); - Q_REVISION(2) void setSpellCheckLanguage(const QString &language); - Q_REVISION(2) QString spellCheckLanguage() const; - Q_REVISION(2) void setSpellCheckEnabled(bool enabled); - Q_REVISION(2) bool isSpellCheckEnabled() const; - static QQuickWebEngineProfile *defaultProfile(); Q_SIGNALS: @@ -149,8 +141,6 @@ Q_SIGNALS: void persistentCookiesPolicyChanged(); void httpCacheMaximumSizeChanged(); Q_REVISION(1) void httpAcceptLanguageChanged(); - Q_REVISION(2) void spellCheckLanguageChanged(); - Q_REVISION(2) void spellCheckEnabledChanged(); void downloadRequested(QQuickWebEngineDownloadItem *download); void downloadFinished(QQuickWebEngineDownloadItem *download); diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index f265ccfb6..1b1dcec25 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -202,16 +202,7 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu // Populate our menu MenuItemHandler *item = 0; - if (contextMenuData.isContentEditable() && !contextMenuData.spellCheckerSuggestions().isEmpty()) { - const QPointer<QQuickWebEngineView> qRef(q); - for (int i=0; i < contextMenuData.spellCheckerSuggestions().count() && i < 4; i++) { - item = new MenuItemHandler(menu); - QString replacement = contextMenuData.spellCheckerSuggestions().at(i); - QObject::connect(item, &MenuItemHandler::triggered, [qRef, replacement] { qRef->replaceMisspelledWord(replacement); }); - ui()->addMenuItem(item, replacement); - } - ui()->addMenuSeparator(menu); - } + if (!data.linkText.isEmpty() && data.linkUrl.isValid()) { item = new MenuItemHandler(menu); QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::OpenLinkInThisWindow); }); @@ -1237,12 +1228,6 @@ void QQuickWebEngineView::printToPdf(const QJSValue &callback, PrintedPageSizeId d->m_callbacks.insert(requestId, callback); } -void QQuickWebEngineView::replaceMisspelledWord(const QString &replacement) -{ - Q_D(QQuickWebEngineView); - d->adapter->replaceMisspelling(replacement); -} - bool QQuickWebEngineView::isFullScreen() const { Q_D(const QQuickWebEngineView); diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 843e34f42..d287b46ca 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -471,8 +471,6 @@ public Q_SLOTS: Q_REVISION(2) void triggerWebAction(WebAction action); Q_REVISION(3) void printToPdf(const QString &filePath, PrintedPageSizeId pageSizeId = PrintedPageSizeId::A4, PrintedPageOrientation orientation = PrintedPageOrientation::Portrait); Q_REVISION(3) void printToPdf(const QJSValue &callback, PrintedPageSizeId pageSizeId = PrintedPageSizeId::A4, PrintedPageOrientation orientation = PrintedPageOrientation::Portrait); - Q_REVISION(3) void replaceMisspelledWord(const QString &replacement); - private Q_SLOTS: void lazyInitialize(); diff --git a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc index dec9d0407..4bb449016 100644 --- a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc +++ b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc @@ -46,6 +46,8 @@ \section1 Building Qt WebEngine from Source + Static builds are not supported. + The requirements for building Qt 5 modules from source are listed separately for each supported platform: @@ -58,13 +60,63 @@ In addition, the following tools are required for building the \l {Qt WebEngine} module: \list - \li Windows: Visual Studio 2013 or Visual Studio 2015 - \li Linux: Clang or GCC version 4.7 or later - \li OS X: Xcode version 5.1 or later on OS X 10.9 or later + \li \l {All Platforms} + \li \l {Windows} + \li \l {Linux} + \li \l {OS X} + \endlist + + The tests for skipping the Qt WebEngine build are located in the + \c qtwebengine repository, in the \c tools\qmake\mkspecs subdirectory. + They can be found by searching for \c skipBuild. + + \section2 All Platforms + + On all platforms, the following tools are required: + + \list + \li \l Python 2.7 or later + \li Bison, Flex + \li GPerf + \endlist + + \section2 Windows + + On Windows, Visual Studio 2013 or Visual Studio 2015 is required. + + \section2 Linux + + On Linux, Clang or GCC version 4.7 or later is required. + + Qt WebEngine requires \c pkg-config to detect most of its dependencies. The + following \c pkg-config files are required: + + \list + \li \c dbus-1 + \li \c fontconfig \endlist + If Qt was configured for \c xcb, the following \c pkg-config files are also + required: + + \list + \li \c libdrm + \li \c xcomposite + \li \c xcursor + \li \c xi + \li \c xrandr + \li \c xscrnsaver + \li \c xtst + \endlist + + Further, development packages for \c khr and \c libcap need to be installed. + + \section2 OS X + + On OS X, Xcode version 5.1 or later on OS X 10.9 or later is required. + \note Qt WebEngine cannot be built for the 32-bit mode of OS X (using the - macx-clang-32 mkspec). + \c macx-clang-32 \c mkspec). \section1 Pepper Plugin API Support diff --git a/src/webengine/doc/src/webengineview.qdoc b/src/webengine/doc/src/webengineview.qdoc index a070140c7..444f0f398 100644 --- a/src/webengine/doc/src/webengineview.qdoc +++ b/src/webengine/doc/src/webengineview.qdoc @@ -215,10 +215,17 @@ \qml Image { id: appIcon + sourceSize: Qt.size(32, 32) source: webView.icon != "" ? webView.icon : "fallbackFavicon.png"; // ... } \endqml + + Specifying the \c{sourceSize} property of the \c{Image} element informs + the Qt WebEngine's favicon provider about the requested size. The + favicon provider tries to find the best fit among the web page candidate + icons. If \c{sourceSize} property is not specified, the provider provides + the icon with the largest resolution. */ /*! @@ -1042,7 +1049,7 @@ This signal is emitted when the page's audio is (un)muted using audioMuted property. \note Not to be confused with a specific HTML5 audio / video element being muted. - \sa audioMuted + \sa audioMuted, recentlyAudibleChanged */ /*! @@ -1050,7 +1057,7 @@ \brief Returns the current page's audible state (audio was recently played, or not). \since QtWebEngine 1.3 \readonly - \sa audioMuted + \sa audioMuted, recentlyAudibleChanged */ /*! @@ -1064,6 +1071,20 @@ Also if the audio is paused, this signal is emitted with an approximate \b{two-second delay}, from the moment the audio is paused. + This signal is also emitted for Flash plugin audio. + + If a web page contains two videos that are started in sequence, this signal + gets emitted only once, for the first video to generate sound. After both + videos are stopped, the signal is emitted upon the last sound generated. + This means that the signal is emitted both when any kind of sound is + generated and when everything is completely silent within a web page, + regardless of the number of audio streams. + + Spurious signal emissions might also happen. For example, when sound is + stopped, this signal gets emitted first with a value of \c true, and then + with a value of \c false. Further, when audio starts playing, the signal is + emitted twice with a value of \c true. + \sa recentlyAudible */ diff --git a/src/webenginewidgets/api/qwebenginecontextmenudata.cpp b/src/webenginewidgets/api/qwebenginecontextmenudata.cpp index 17a562ea1..c7019977b 100644 --- a/src/webenginewidgets/api/qwebenginecontextmenudata.cpp +++ b/src/webenginewidgets/api/qwebenginecontextmenudata.cpp @@ -187,26 +187,6 @@ bool QWebEngineContextMenuData::isContentEditable() const } /*! - If the context is a word considered misspelled by the spell-checker, returns the misspelled word. -*/ -QString QWebEngineContextMenuData::misspelledWord() const -{ - if (d) - return d->misspelledWord; - return QString(); -} - -/*! - If the context is a word considered misspelled by the spell-checker, returns a list of suggested replacements. -*/ -QStringList QWebEngineContextMenuData::spellCheckerSuggestions() const -{ - if (d) - return d->spellCheckerSuggestions; - return QStringList(); -} - -/*! \internal */ QWebEngineContextMenuData &QWebEngineContextMenuData::operator=(const QWebEngineContextDataPrivate &priv) diff --git a/src/webenginewidgets/api/qwebenginecontextmenudata.h b/src/webenginewidgets/api/qwebenginecontextmenudata.h index fd1080eec..4bea34ee0 100644 --- a/src/webenginewidgets/api/qwebenginecontextmenudata.h +++ b/src/webenginewidgets/api/qwebenginecontextmenudata.h @@ -76,8 +76,6 @@ public: QUrl mediaUrl() const; MediaType mediaType() const; bool isContentEditable() const; - QString misspelledWord() const; - QStringList spellCheckerSuggestions() const; private: void reset(); diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 447c53ba9..0e7f02f16 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -151,7 +151,7 @@ void QWebEnginePagePrivate::iconChanged(const QUrl &url) return; iconUrl = url; Q_EMIT q->iconUrlChanged(iconUrl); - Q_EMIT q->iconChanged(adapter->faviconManager()->getIcon(iconUrl)); + Q_EMIT q->iconChanged(adapter->faviconManager()->getIcon()); } void QWebEnginePagePrivate::loadProgressChanged(int progress) @@ -1098,22 +1098,6 @@ void QWebEnginePage::triggerAction(WebAction action, bool) } } -/*! - * \since 5.7 - * Replace the current misspelled word with \a replacement. - * - * The current misspelled word can be found in QWebEngineContextMenuData::misspelledWord(), - * and suggested replacements in QWebEngineContextMenuData::spellCheckerSuggestions(). - * - * \sa contextMenuData(), - */ - -void QWebEnginePage::replaceMisspelledWord(const QString &replacement) -{ - Q_D(QWebEnginePage); - d->adapter->replaceMisspelling(replacement); -} - void QWebEnginePage::findText(const QString &subString, FindFlags options, const QWebEngineCallback<bool> &resultCallback) { Q_D(QWebEnginePage); @@ -1292,18 +1276,6 @@ QMenu *QWebEnginePage::createStandardContextMenu() QAction *action = 0; const WebEngineContextMenuData &contextMenuData = *d->contextData.d; - if (contextMenuData.isEditable && !contextMenuData.spellCheckerSuggestions.isEmpty()) { - QPointer<QWebEnginePage> thisRef(this); - for (int i=0; i < contextMenuData.spellCheckerSuggestions.count() && i < 4; i++) { - QAction *action = new QAction(menu); - QString replacement = contextMenuData.spellCheckerSuggestions.at(i); - QObject::connect(action, &QAction::triggered, [thisRef, replacement] { if (thisRef) thisRef->replaceMisspelledWord(replacement); }); - action->setText(replacement); - menu->addAction(action); - } - menu->addSeparator(); - } - if (!contextMenuData.linkText.isEmpty() && contextMenuData.linkUrl.isValid()) { action = QWebEnginePage::action(OpenLinkInThisWindow); action->setText(tr("Follow Link")); @@ -1506,7 +1478,9 @@ QUrl QWebEnginePage::iconUrl() const \brief the icon associated with the page currently viewed \since 5.7 - By default, this property contains a null icon. + By default, this property contains a null icon. If the web page specifies more than one icon, + the \c{icon} property encapsulates the available candidate icons in a single, + scalable \c{QIcon}. \sa iconChanged(), iconUrl(), iconUrlChanged() */ @@ -1517,7 +1491,7 @@ QIcon QWebEnginePage::icon() const if (d->iconUrl.isEmpty()) return QIcon(); - return d->adapter->faviconManager()->getIcon(d->iconUrl); + return d->adapter->faviconManager()->getIcon(); } qreal QWebEnginePage::zoomFactor() const diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index 7b99270c0..0c6450d20 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -206,8 +206,6 @@ public: #endif virtual void triggerAction(WebAction action, bool checked = false); - void replaceMisspelledWord(const QString &replacement); - virtual bool event(QEvent*); #ifdef Q_QDOC void findText(const QString &subString, FindFlags options = 0); diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index 2dab0aa08..664323034 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -556,68 +556,6 @@ QWebEngineProfile *QWebEngineProfile::defaultProfile() } /*! - \since 5.7 - - Returns the subset of \a languages supported by the spell checker. - - Checks whether the spell checker dictionary is installed for the specified - language from the \a languages list. If the dictionary file is missing - or corrupted, the language is removed from the returned list. - - \sa setSpellCheckLanguage() -*/ -QStringList QWebEngineProfile::availableDictionaries(const QStringList &languages) -{ - const Q_D(QWebEngineProfile); - return d->browserContext()->spellCheckLanguages(languages); -} - -/*! - \since 5.7 - - Sets the current \a language for the spell checker. -*/ -void QWebEngineProfile::setSpellCheckLanguage(const QString &language) -{ - Q_D(QWebEngineProfile); - d->browserContext()->setSpellCheckLanguage(language); -} - -/*! - \since 5.7 - - Returns the language used by the spell checker. -*/ -QString QWebEngineProfile::spellCheckLanguage() const -{ - const Q_D(QWebEngineProfile); - return d->browserContext()->spellCheckLanguage(); -} - -/*! - \since 5.7 - - Enables spell checker if \a enable is \c true, otherwise disables it. - \sa isSpellCheckEnabled() - */ -void QWebEngineProfile::setSpellCheckEnabled(bool enable) -{ - Q_D(QWebEngineProfile); - d->browserContext()->setSpellCheckEnabled(enable); -} -/*! - \since 5.7 - - Returns \c true if the spell checker is enabled; otherwise returns \c false. - \sa setSpellCheckEnabled() - */ -bool QWebEngineProfile::isSpellCheckEnabled() const -{ - const Q_D(QWebEngineProfile); - return d->browserContext()->isSpellCheckEnabled(); -} - -/*! Returns the default settings for all pages in this profile. */ QWebEngineSettings *QWebEngineProfile::settings() const diff --git a/src/webenginewidgets/api/qwebengineprofile.h b/src/webenginewidgets/api/qwebengineprofile.h index 9c473eee9..22a913fb2 100644 --- a/src/webenginewidgets/api/qwebengineprofile.h +++ b/src/webenginewidgets/api/qwebengineprofile.h @@ -121,12 +121,6 @@ public: void clearHttpCache(); - QStringList availableDictionaries(const QStringList &languages); - void setSpellCheckLanguage(const QString &language); - QString spellCheckLanguage() const; - void setSpellCheckEnabled(bool enabled); - bool isSpellCheckEnabled() const; - static QWebEngineProfile *defaultProfile(); Q_SIGNALS: diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 396e6950d..6171391e3 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -321,6 +321,7 @@ bool QWebEngineView::event(QEvent *ev) void QWebEngineView::contextMenuEvent(QContextMenuEvent *event) { QMenu *menu = page()->createStandardContextMenu(); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(event->globalPos()); } diff --git a/tests/auto/quick/qmltests/data/favicon-candidates-gray.html b/tests/auto/quick/qmltests/data/favicon-candidates-gray.html new file mode 100644 index 000000000..3cbc4a4c3 --- /dev/null +++ b/tests/auto/quick/qmltests/data/favicon-candidates-gray.html @@ -0,0 +1,29 @@ +<html> + <head> + <title>Gray Candidate Favicons Test</title> + <link rel="shortcut icon" href="icons/gray16.png" /> + <link rel="shortcut icon" href="icons/gray32.png" /> + <link rel="shortcut icon" href="icons/gray64.png" /> + <link rel="shortcut icon" href="icons/gray128.png" /> + <link rel="shortcut icon" href="icons/gray255.png" /> + </head> + <body> + <h1>Gray Candidate Favicons Test</h1> + <table style="width:100%"> + <tr> + <td align="center"><img src="icons/gray16.png" height="16" width="16" /></td> + <td align="center"><img src="icons/gray32.png" height="32" width="32" /></td> + <td align="center"><img src="icons/gray64.png" height="64" width="64" /></td> + <td align="center"><img src="icons/gray128.png" height="128" width="128" /></td> + <td align="center"><img src="icons/gray255.png" height="255" width="255" /></td> + </tr> + <tr> + <td align="center">16x16</td> + <td align="center">32x32</td> + <td align="center">64x64</td> + <td align="center">128x128</td> + <td align="center">255x255</td> + </tr> + </table> + </body> +</html> diff --git a/tests/auto/quick/qmltests/data/favicon-multi-gray.html b/tests/auto/quick/qmltests/data/favicon-multi-gray.html index d6ac0909f..9b9b7432d 100644 --- a/tests/auto/quick/qmltests/data/favicon-multi-gray.html +++ b/tests/auto/quick/qmltests/data/favicon-multi-gray.html @@ -5,5 +5,21 @@ </head> <body> <h1>Gray Multi-sized Favicon Test</h1> + <table style="width:100%"> + <tr> + <td align="center"><img src="icons/gray16.png" height="16" width="16" /></td> + <td align="center"><img src="icons/gray32.png" height="32" width="32" /></td> + <td align="center"><img src="icons/gray64.png" height="64" width="64" /></td> + <td align="center"><img src="icons/gray128.png" height="128" width="128" /></td> + <td align="center"><img src="icons/gray255.png" height="255" width="255" /></td> + </tr> + <tr> + <td align="center">16x16</td> + <td align="center">32x32</td> + <td align="center">64x64</td> + <td align="center">128x128</td> + <td align="center">255x255</td> + </tr> + </table> </body> </html> diff --git a/tests/auto/quick/qmltests/data/icons/gray128.png b/tests/auto/quick/qmltests/data/icons/gray128.png Binary files differnew file mode 100644 index 000000000..bf1cfaba0 --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/gray128.png diff --git a/tests/auto/quick/qmltests/data/icons/gray16.png b/tests/auto/quick/qmltests/data/icons/gray16.png Binary files differnew file mode 100644 index 000000000..2a1a91a76 --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/gray16.png diff --git a/tests/auto/quick/qmltests/data/icons/gray255.png b/tests/auto/quick/qmltests/data/icons/gray255.png Binary files differnew file mode 100644 index 000000000..549169551 --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/gray255.png diff --git a/tests/auto/quick/qmltests/data/icons/gray32.png b/tests/auto/quick/qmltests/data/icons/gray32.png Binary files differnew file mode 100644 index 000000000..b269a528f --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/gray32.png diff --git a/tests/auto/quick/qmltests/data/icons/gray64.png b/tests/auto/quick/qmltests/data/icons/gray64.png Binary files differnew file mode 100644 index 000000000..e02559e5b --- /dev/null +++ b/tests/auto/quick/qmltests/data/icons/gray64.png diff --git a/tests/auto/quick/qmltests/data/tst_favicon.qml b/tests/auto/quick/qmltests/data/tst_favicon.qml index e959f19be..633859add 100644 --- a/tests/auto/quick/qmltests/data/tst_favicon.qml +++ b/tests/auto/quick/qmltests/data/tst_favicon.qml @@ -261,16 +261,26 @@ TestWebEngineView { function test_faviconProvider_data() { return [ - { tag: "8x8", size: 8, value: 16 }, - { tag: "16x16", size: 16, value: 16 }, - { tag: "17x17", size: 17, value: 32 }, - { tag: "31x31", size: 31, value: 32 }, - { tag: "32x32", size: 32, value: 32 }, - { tag: "33x33", size: 33, value: 64 }, - { tag: "64x64", size: 64, value: 64 }, - { tag: "128x128", size: 128, value: 128 }, - { tag: "255x255", size: 255, value: 255 }, - { tag: "256x256", size: 256, value: 255 }, + { tag: "multi 8x8", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 8, value: 16 }, + { tag: "multi 16x16", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 16, value: 16 }, + { tag: "multi 17x17", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 17, value: 32 }, + { tag: "multi 31x31", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 31, value: 32 }, + { tag: "multi 32x32", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 32, value: 32 }, + { tag: "multi 33x33", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 33, value: 64 }, + { tag: "multi 64x64", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 64, value: 64 }, + { tag: "multi 128x128", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 128, value: 128 }, + { tag: "multi 255x255", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 255, value: 255 }, + { tag: "multi 256x256", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 256, value: 255 }, + { tag: "candidate 8x8", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 8, value: 16 }, + { tag: "candidate 16x16", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 16, value: 16 }, + { tag: "candidate 17x17", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 17, value: 32 }, + { tag: "candidate 31x31", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 31, value: 32 }, + { tag: "candidate 32x32", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 32, value: 32 }, + { tag: "candidate 33x33", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 33, value: 64 }, + { tag: "candidate 64x64", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 64, value: 64 }, + { tag: "candidate 128x128", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 128, value: 128 }, + { tag: "candidate 255x255", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 255, value: 255 }, + { tag: "candidate 256x256", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 256, value: 255 }, ]; } @@ -287,8 +297,7 @@ TestWebEngineView { compare(iconChangedSpy.count, 0) - var url = Qt.resolvedUrl("favicon-multi-gray.html") - webEngineView.url = url + webEngineView.url = row.url verify(webEngineView.waitForLoadSucceeded()) iconChangedSpy.wait() diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index b8f0f7df1..64f7414ce 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -16,6 +16,7 @@ OTHER_FILES += \ $$PWD/data/directoryupload.html \ $$PWD/data/favicon.html \ $$PWD/data/favicon2.html \ + $$PWD/data/favicon-candidates-gray.html \ $$PWD/data/favicon-misc.html \ $$PWD/data/favicon-multi.html \ $$PWD/data/favicon-multi-gray.html \ @@ -65,6 +66,11 @@ OTHER_FILES += \ $$PWD/data/tst_settings.qml \ $$PWD/data/tst_keyboardModifierMapping.qml \ $$PWD/data/icons/favicon.png \ + $$PWD/data/icons/gray128.png \ + $$PWD/data/icons/gray16.png \ + $$PWD/data/icons/gray255.png \ + $$PWD/data/icons/gray32.png \ + $$PWD/data/icons/gray64.png \ $$PWD/data/icons/grayicons.ico \ $$PWD/data/icons/small-favicon.png \ $$PWD/data/icons/qt144.png \ diff --git a/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp b/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp index b9ce0c33b..38311cad2 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp +++ b/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp @@ -55,6 +55,7 @@ private Q_SLOTS: void bestFavicon(); void touchIcon(); void multiIcon(); + void candidateIcon(); void downloadIconsDisabled_data(); void downloadIconsDisabled(); void downloadTouchIconsEnabled_data(); @@ -323,9 +324,8 @@ void tst_QWebEngineFaviconManager::bestFavicon() icon = m_page->icon(); QVERIFY(!icon.isNull()); - QCOMPARE(icon.availableSizes().count(), 1); - iconSize = icon.availableSizes().first(); - QCOMPARE(iconSize, QSize(144, 144)); + QVERIFY(icon.availableSizes().count() >= 1); + QVERIFY(icon.availableSizes().contains(QSize(144, 144))); } void tst_QWebEngineFaviconManager::touchIcon() @@ -376,6 +376,33 @@ void tst_QWebEngineFaviconManager::multiIcon() QVERIFY(icon.availableSizes().contains(QSize(64, 64))); } +void tst_QWebEngineFaviconManager::candidateIcon() +{ + if (!QDir(TESTS_SOURCE_DIR).exists()) + W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll); + + QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); + QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); + QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); + + QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/favicon-shortcut.html")); + m_page->load(url); + + QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(iconUrlChangedSpy.count(), 1); + QTRY_COMPARE(iconChangedSpy.count(), 1); + + QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); + QCOMPARE(m_page->iconUrl(), iconUrl); + QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/icons/qt144.png"))); + + const QIcon &icon = m_page->icon(); + QVERIFY(!icon.isNull()); + QCOMPARE(icon.availableSizes().count(), 2); + QVERIFY(icon.availableSizes().contains(QSize(32, 32))); + QVERIFY(icon.availableSizes().contains(QSize(144, 144))); +} + void tst_QWebEngineFaviconManager::downloadIconsDisabled_data() { QTest::addColumn<QUrl>("url"); @@ -442,9 +469,8 @@ void tst_QWebEngineFaviconManager::downloadTouchIconsEnabled() const QIcon &icon = m_page->icon(); QVERIFY(!icon.isNull()); - QCOMPARE(icon.availableSizes().count(), 1); - QSize iconSize = icon.availableSizes().first(); - QCOMPARE(iconSize, expectedIconSize); + QVERIFY(icon.availableSizes().count() >= 1); + QVERIFY(icon.availableSizes().contains(expectedIconSize)); } QTEST_MAIN(tst_QWebEngineFaviconManager) diff --git a/tests/auto/widgets/qwebenginespellcheck/dict/en-US.aff b/tests/auto/widgets/qwebenginespellcheck/dict/en-US.aff new file mode 100644 index 000000000..ff8185771 --- /dev/null +++ b/tests/auto/widgets/qwebenginespellcheck/dict/en-US.aff @@ -0,0 +1,5 @@ +SET UTF-8 +TRY esianrtolcdugmphbyfvkwzqESIANRTOLCDUGMPHBYFVKWZQ + +PFX Q Y 1 +PFX Q 0 q . diff --git a/tests/auto/widgets/qwebenginespellcheck/dict/en-US.dic b/tests/auto/widgets/qwebenginespellcheck/dict/en-US.dic new file mode 100644 index 000000000..3d4ecdfa4 --- /dev/null +++ b/tests/auto/widgets/qwebenginespellcheck/dict/en-US.dic @@ -0,0 +1,11 @@ +10 +he/Q +I/Q +it/Q +love/Q +loves/Q +qt/Q +she/Q +they/Q +we/Q +you/Q diff --git a/tests/auto/widgets/qwebenginespellcheck/qwebenginespellcheck.pro b/tests/auto/widgets/qwebenginespellcheck/qwebenginespellcheck.pro new file mode 100644 index 000000000..437aad937 --- /dev/null +++ b/tests/auto/widgets/qwebenginespellcheck/qwebenginespellcheck.pro @@ -0,0 +1,22 @@ +include(../tests.pri) + +DISTFILES += \ + dict/en-US.dic \ + dict/en-US.aff + +qtPrepareTool(CONVERT_TOOL, qwebengine_convert_dict) + +debug_and_release { + CONFIG(debug, debug|release): DICTIONARIES_DIR = debug/qtwebengine_dictionaries + else: DICTIONARIES_DIR = release/qtwebengine_dictionaries +} else { + DICTIONARIES_DIR = qtwebengine_dictionaries +} + +dict.files = $$PWD/dict/en-US.dic +dictoolbuild.input = dict.files +dictoolbuild.output = $${DICTIONARIES_DIR}/${QMAKE_FILE_BASE}.bdic +dictoolbuild.commands = $${CONVERT_TOOL} ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT} +dictoolbuild.name = Build ${QMAKE_FILE_IN_BASE} +dictoolbuild.CONFIG = no_link target_predeps +QMAKE_EXTRA_COMPILERS += dictoolbuild diff --git a/tests/auto/widgets/qwebenginespellcheck/resources/index.html b/tests/auto/widgets/qwebenginespellcheck/resources/index.html new file mode 100644 index 000000000..520979244 --- /dev/null +++ b/tests/auto/widgets/qwebenginespellcheck/resources/index.html @@ -0,0 +1,36 @@ +<html> + <head> + <script type="text/javascript"> + function makeEditable() + { + document.getElementsByClassName('textarea')[0].contentEditable = true; + } + + function text() + { + return document.getElementsByClassName('textarea')[0].innerHTML; + } + + function findWordPosition(text,word) + { + var divElement = document.getElementsByClassName('textarea')[0]; + divElement.innerHTML = text; + var regex = new RegExp(word,'g'); + divElement.innerHTML = divElement.innerHTML.replace(regex, '<span id="word">' + word + '</span>'); + var spanElement = document.getElementById('word'); + var rect = spanElement.getBoundingClientRect(); + var array = new Array(); + array.push(rect.left); + array.push(rect.top); + array.push(rect.right - rect.left); + array.push(rect.bottom - rect.top); + divElement.innerHTML = ""; + return array; + } + </script> + </head> + <body> + <div class="textarea" style="width:300px; height:200px; border: 1px solid #ccc"></div> + </body> +</html> + diff --git a/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp b/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp new file mode 100644 index 000000000..2dfe3305d --- /dev/null +++ b/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "util.h" +#include <QtTest/QtTest> +#include <QtWebEngineWidgets/qwebenginecontextmenudata.h> +#include <QtWebEngineWidgets/qwebengineprofile.h> +#include <QtWebEngineWidgets/qwebenginepage.h> +#include <QtWebEngineWidgets/qwebengineview.h> + +class WebView : public QWebEngineView +{ + Q_OBJECT +public: + void activateMenu(const QPoint &position) + { + QTest::mouseMove(focusWidget(), position); + QTest::mousePress(focusWidget(), Qt::RightButton, 0, position); + QContextMenuEvent evcont(QContextMenuEvent::Mouse, position, mapToGlobal(position)); + event(&evcont); + } + + const QWebEngineContextMenuData& data() + { + return m_data; + } + +signals: + void menuReady(); + +protected: + void contextMenuEvent(QContextMenuEvent *) + { + m_data = page()->contextMenuData(); + emit menuReady(); + } +private: + QWebEngineContextMenuData m_data; +}; + +class tst_QWebEngineSpellcheck : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void init(); + void cleanup(); + void initTestCase(); + void spellCheckLanguage(); + void spellCheckEnabled(); + void spellcheck(); + +private: + void load(); + WebView *m_view; +}; + +void tst_QWebEngineSpellcheck::initTestCase() +{ + QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); + QVERIFY(profile); + QVERIFY(!profile->isSpellCheckEnabled()); + QVERIFY(profile->spellCheckLanguage().isEmpty()); +} + +void tst_QWebEngineSpellcheck::init() +{ + QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); + profile->setSpellCheckEnabled(false); + profile->setSpellCheckLanguage(QString::null); + m_view = new WebView(); +} + +void tst_QWebEngineSpellcheck::load() +{ + m_view->page()->load(QUrl("qrc:///resources/index.html")); + m_view->show(); + waitForSignal(m_view->page(), SIGNAL(loadFinished(bool))); +} + +void tst_QWebEngineSpellcheck::cleanup() +{ + delete m_view; +} + +void tst_QWebEngineSpellcheck::spellCheckLanguage() +{ + QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); + QVERIFY(profile); + profile->setSpellCheckLanguage("en-US"); + QVERIFY(profile->spellCheckLanguage() == "en-US"); +} + +void tst_QWebEngineSpellcheck::spellCheckEnabled() +{ + QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); + QVERIFY(profile); + profile->setSpellCheckEnabled(true); + QVERIFY(profile->isSpellCheckEnabled()); +} + +void tst_QWebEngineSpellcheck::spellcheck() +{ + QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); + QVERIFY(profile); + profile->setSpellCheckLanguage("en-US"); + profile->setSpellCheckEnabled(true); + load(); + + // make textarea editable + evaluateJavaScriptSync(m_view->page(), "makeEditable();"); + + // calcuate position of misspelled word + QVariantList list = evaluateJavaScriptSync(m_view->page(), "findWordPosition('I lovee Qt ....','lovee');").toList(); + QRect rect(list[0].value<int>(),list[1].value<int>(),list[2].value<int>(),list[3].value<int>()); + + //type text, spellchecker needs time + QTest::mouseMove(m_view->focusWidget(), QPoint(20,20)); + QTest::mousePress(m_view->focusWidget(), Qt::LeftButton, 0, QPoint(20,20)); + QString text("I lovee Qt ...."); + for (int i = 0; i < text.length(); i++) { + QTest::keyClicks(m_view->focusWidget(), text.at(i)); + QTest::qWait(60); + } + + // make sure text is there + QString result = evaluateJavaScriptSync(m_view->page(), "text();").toString(); + QVERIFY(result == text); + + // open menu on misspelled word + m_view->activateMenu(rect.center()); + waitForSignal(m_view, SIGNAL(menuReady())); + + // check if menu is valid + QVERIFY(m_view->data().isValid()); + QVERIFY(m_view->data().isContentEditable()); + + // check misspelled word + QVERIFY(m_view->data().misspelledWord() == "lovee"); + + // check suggestions + QStringList expected {"love", "loves"}; + QVERIFY(m_view->data().spellCheckerSuggestions() == expected); + + // check replace word + m_view->page()->replaceMisspelledWord("love"); + text = "I love Qt ...."; + result = evaluateJavaScriptSync(m_view->page(), "text();").toString(); + QVERIFY(result == text); +} + +QTEST_MAIN(tst_QWebEngineSpellcheck) +#include "tst_qwebenginespellcheck.moc" diff --git a/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.qrc b/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.qrc new file mode 100644 index 000000000..505b932c7 --- /dev/null +++ b/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>resources/index.html</file> + </qresource> +</RCC> diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro index 6c516b38f..7543a4382 100644 --- a/tests/auto/widgets/widgets.pro +++ b/tests/auto/widgets/widgets.pro @@ -13,6 +13,11 @@ SUBDIRS += \ qwebenginesettings \ qwebengineview +# QTBUG-53135, osx does not use hunspell +!contains(WEBENGINE_CONFIG, no_spellcheck):!osx:!cross_compile { + SUBDIRS += qwebenginespellcheck +} + qtHaveModule(positioning) { SUBDIRS += positionplugin qwebenginepage.depends = positionplugin diff --git a/tools/qmake/mkspecs/features/configure.prf b/tools/qmake/mkspecs/features/configure.prf index 0dfb67a84..679b282b3 100644 --- a/tools/qmake/mkspecs/features/configure.prf +++ b/tools/qmake/mkspecs/features/configure.prf @@ -64,6 +64,9 @@ defineTest(runConfigure) { } } + # Spellcheck support is moved to dev + WEBENGINE_CONFIG += no_spellcheck + isEmpty(skipBuildReason): { cache(CONFIG, add, $$list(webengine_successfully_configured)) !isEmpty(WEBENGINE_CONFIG) { @@ -71,6 +74,7 @@ defineTest(runConfigure) { export(WEBENGINE_CONFIG) } } + } # This is called from default_post, at which point we've also parsed diff --git a/tools/qmake/mkspecs/features/default_pre.prf b/tools/qmake/mkspecs/features/default_pre.prf index cb0625c2e..27aded013 100644 --- a/tools/qmake/mkspecs/features/default_pre.prf +++ b/tools/qmake/mkspecs/features/default_pre.prf @@ -4,7 +4,17 @@ QTWEBENGINE_ROOT = $$replace(PWD, /tools/qmake/mkspecs/features$,) # We depend on libc++ to build chromium so our macosx-version-min has to be 10.7 QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 -QTWEBENGINEPROCESS_NAME = QtWebEngineProcess +QTWEBENGINEPROCESS_NAME_RELEASE = QtWebEngineProcess +debug_and_release { + QTWEBENGINEPROCESS_NAME_DEBUG = $$join(QTWEBENGINEPROCESS_NAME_RELEASE,,,d) +} else { + QTWEBENGINEPROCESS_NAME_DEBUG = $$QTWEBENGINEPROCESS_NAME_RELEASE +} +build_pass:CONFIG(debug, debug|release) { + QTWEBENGINEPROCESS_NAME = $$QTWEBENGINEPROCESS_NAME_DEBUG +} else { + QTWEBENGINEPROCESS_NAME = $$QTWEBENGINEPROCESS_NAME_RELEASE +} # Location of sync.profile MODULE_BASE_DIR = $$QTWEBENGINE_ROOT |