diff options
-rw-r--r-- | examples/widgets/browser/browsermainwindow.cpp | 17 | ||||
-rw-r--r-- | examples/widgets/browser/browsermainwindow.h | 1 | ||||
-rw-r--r-- | src/core/web_contents_adapter.cpp | 25 | ||||
-rw-r--r-- | src/core/web_contents_adapter.h | 2 | ||||
-rw-r--r-- | src/core/web_contents_adapter_client.h | 1 | ||||
-rw-r--r-- | src/core/web_contents_delegate_qt.cpp | 9 | ||||
-rw-r--r-- | src/core/web_contents_delegate_qt.h | 1 | ||||
-rw-r--r-- | src/webengine/api/qquickwebengineview_p_p.h | 1 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebenginepage.cpp | 43 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebenginepage.h | 5 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebenginepage_p.h | 10 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebengineview.cpp | 5 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebengineview.h | 2 | ||||
-rw-r--r-- | tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp | 38 | ||||
-rw-r--r-- | tests/auto/widgets/util.h | 7 |
15 files changed, 146 insertions, 21 deletions
diff --git a/examples/widgets/browser/browsermainwindow.cpp b/examples/widgets/browser/browsermainwindow.cpp index 319e2d4c2..3cee14e9e 100644 --- a/examples/widgets/browser/browsermainwindow.cpp +++ b/examples/widgets/browser/browsermainwindow.cpp @@ -325,7 +325,6 @@ void BrowserMainWindow::setupMenu() m_tabWidget->addWebAction(m_paste, QWebEnginePage::Paste); editMenu->addSeparator(); -#if defined(QWEBENGINEPAGE_FINDTEXT) QAction *m_find = editMenu->addAction(tr("&Find")); m_find->setShortcuts(QKeySequence::Find); connect(m_find, SIGNAL(triggered()), this, SLOT(slotEditFind())); @@ -339,7 +338,6 @@ void BrowserMainWindow::setupMenu() m_findPrevious->setShortcuts(QKeySequence::FindPrevious); connect(m_findPrevious, SIGNAL(triggered()), this, SLOT(slotEditFindPrevious())); editMenu->addSeparator(); -#endif editMenu->addAction(tr("&Preferences"), this, SLOT(slotPreferences()), tr("Ctrl+,")); @@ -557,6 +555,12 @@ void BrowserMainWindow::updateStatusbarActionText(bool visible) m_viewStatusbar->setText(!visible ? tr("Show Status Bar") : tr("Hide Status Bar")); } +void BrowserMainWindow::handleFindTextResult(bool found) +{ + if (!found) + slotUpdateStatusbar(tr("\"%1\" not found.").arg(m_lastSearch)); +} + void BrowserMainWindow::updateToolbarActionText(bool visible) { m_viewToolbar->setText(!visible ? tr("Show Toolbar") : tr("Hide Toolbar")); @@ -746,7 +750,6 @@ void BrowserMainWindow::closeEvent(QCloseEvent *event) void BrowserMainWindow::slotEditFind() { -#if defined(QWEBENGINEPAGE_FINDTEXT) if (!currentTab()) return; bool ok; @@ -755,28 +758,22 @@ void BrowserMainWindow::slotEditFind() m_lastSearch, &ok); if (ok && !search.isEmpty()) { m_lastSearch = search; - if (!currentTab()->findText(m_lastSearch)) - slotUpdateStatusbar(tr("\"%1\" not found.").arg(m_lastSearch)); + currentTab()->findText(m_lastSearch, 0, invoke(this, &BrowserMainWindow::handleFindTextResult)); } -#endif } void BrowserMainWindow::slotEditFindNext() { -#if defined(QWEBENGINEPAGE_FINDTEXT) if (!currentTab() && !m_lastSearch.isEmpty()) return; currentTab()->findText(m_lastSearch); -#endif } void BrowserMainWindow::slotEditFindPrevious() { -#if defined(QWEBENGINEPAGE_FINDTEXT) if (!currentTab() && !m_lastSearch.isEmpty()) return; currentTab()->findText(m_lastSearch, QWebEnginePage::FindBackward); -#endif } void BrowserMainWindow::slotViewZoomIn() diff --git a/examples/widgets/browser/browsermainwindow.h b/examples/widgets/browser/browsermainwindow.h index 2ad5ab62e..3c3df9117 100644 --- a/examples/widgets/browser/browsermainwindow.h +++ b/examples/widgets/browser/browsermainwindow.h @@ -137,6 +137,7 @@ private: void setupMenu(); void setupToolBar(); void updateStatusbarActionText(bool visible); + void handleFindTextResult(bool found); private: QToolBar *m_navigationBar; diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 82d6ed26f..be68e6ef4 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -59,6 +59,7 @@ #include "content/public/common/renderer_preferences.h" #include "content/public/common/url_constants.h" #include "ui/shell_dialogs/selected_file_info.h" +#include "third_party/WebKit/public/web/WebFindOptions.h" #include <QDir> #include <QGuiApplication> @@ -173,6 +174,7 @@ public: scoped_ptr<QtRenderViewObserverHost> renderViewObserverHost; WebContentsAdapterClient *adapterClient; quint64 lastRequestId; + QString lastSearchedString; }; WebContentsAdapterPrivate::WebContentsAdapterPrivate(WebContentsAdapterClient::RenderingMode renderingMode) @@ -429,6 +431,29 @@ quint64 WebContentsAdapter::fetchDocumentInnerText() return d->lastRequestId; } +quint64 WebContentsAdapter::findText(const QString &subString, bool caseSensitively, bool findBackward) +{ + Q_D(WebContentsAdapter); + WebKit::WebFindOptions options; + options.forward = !findBackward; + options.matchCase = caseSensitively; + options.findNext = subString == d->lastSearchedString; + d->lastSearchedString = subString; + + // Find already allows a request ID as input, but only as an int. + // Use the same counter but mod it to MAX_INT, this keeps the same likeliness of request ID clashing. + int shrunkRequestId = ++d->lastRequestId & 0x7fffffff; + d->webContents->GetRenderViewHost()->Find(shrunkRequestId, toString16(subString), options); + return shrunkRequestId; +} + +void WebContentsAdapter::stopFinding() +{ + Q_D(WebContentsAdapter); + d->lastSearchedString = QString(); + d->webContents->GetRenderViewHost()->StopFinding(content::STOP_FIND_ACTION_CLEAR_SELECTION); +} + void WebContentsAdapter::wasShown() { Q_D(WebContentsAdapter); diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 56e39ba32..4cef56103 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -89,6 +89,8 @@ public: quint64 runJavaScriptCallbackResult(const QString &javaScript, const QString &xPath); quint64 fetchDocumentMarkup(); quint64 fetchDocumentInnerText(); + quint64 findText(const QString &subString, bool caseSensitively, bool findBackward); + void stopFinding(); void wasShown(); void wasHidden(); diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 778446a12..f56e31a71 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -136,6 +136,7 @@ public: virtual void didRunJavaScript(quint64 requestId, const QVariant& result) = 0; virtual void didFetchDocumentMarkup(quint64 requestId, const QString& result) = 0; virtual void didFetchDocumentInnerText(quint64 requestId, const QString& result) = 0; + virtual void didFindText(quint64 requestId, int matchCount) = 0; virtual void passOnFocus(bool reverse) = 0; virtual void javaScriptConsoleMessage(int level, const QString& message, int lineNumber, const QString& sourceID) = 0; }; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 16ec54afd..c0b050de6 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -166,3 +166,12 @@ bool WebContentsDelegateQt::AddMessageToConsole(content::WebContents *source, in m_viewClient->javaScriptConsoleMessage(static_cast<int>(level), toQt(message), static_cast<int>(line_no), toQt(source_id)); return false; } + +void WebContentsDelegateQt::FindReply(content::WebContents *source, int request_id, int number_of_matches, const gfx::Rect& selection_rect, int active_match_ordinal, bool final_update) +{ + Q_UNUSED(source) + Q_UNUSED(selection_rect) + Q_UNUSED(active_match_ordinal) + if (final_update) + m_viewClient->didFindText(request_id, number_of_matches); +} diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 460bb9ec2..4c8701945 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -77,6 +77,7 @@ public: virtual bool IsFullscreenForTabOrPending(const content::WebContents* web_contents) const Q_DECL_OVERRIDE; virtual void RunFileChooser(content::WebContents *, const content::FileChooserParams ¶ms) Q_DECL_OVERRIDE; virtual bool AddMessageToConsole(content::WebContents* source, int32 level, const string16& message, int32 line_no, const string16& source_id) Q_DECL_OVERRIDE; + virtual void FindReply(content::WebContents *source, int request_id, int number_of_matches, const gfx::Rect& selection_rect, int active_match_ordinal, bool final_update) Q_DECL_OVERRIDE; private: WebContentsAdapterClient *m_viewClient; diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index a36eb327c..ce8b64001 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -141,6 +141,7 @@ public: virtual void didRunJavaScript(quint64, const QVariant&) Q_DECL_OVERRIDE { } virtual void didFetchDocumentMarkup(quint64, const QString&) Q_DECL_OVERRIDE { } virtual void didFetchDocumentInnerText(quint64, const QString&) Q_DECL_OVERRIDE { } + virtual void didFindText(quint64, int) Q_DECL_OVERRIDE { } virtual void passOnFocus(bool reverse) Q_DECL_OVERRIDE; virtual void javaScriptConsoleMessage(int level, const QString& message, int lineNumber, const QString& sourceID) Q_DECL_OVERRIDE; diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 760a8eff7..ca1c203dd 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -57,6 +57,9 @@ CallbackDirectory::~CallbackDirectory() case CallbackSharedDataPointer::String: (*sharedPtr.stringCallback)(QString()); break; + case CallbackSharedDataPointer::Bool: + (*sharedPtr.boolCallback)(false); + break; default: Q_UNREACHABLE(); } @@ -73,6 +76,11 @@ void CallbackDirectory::registerCallback(quint64 requestId, const QExplicitlySha m_callbackMap.insert(requestId, CallbackSharedDataPointer(callback.data())); } +void CallbackDirectory::registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<BoolCallback> &callback) +{ + m_callbackMap.insert(requestId, CallbackSharedDataPointer(callback.data())); +} + void CallbackDirectory::invoke(quint64 requestId, const QVariant &result) { CallbackSharedDataPointer sharedPtr = m_callbackMap.take(requestId); @@ -91,6 +99,15 @@ void CallbackDirectory::invoke(quint64 requestId, const QString &result) } } +void CallbackDirectory::invoke(quint64 requestId, bool result) +{ + CallbackSharedDataPointer sharedPtr = m_callbackMap.take(requestId); + if (sharedPtr) { + Q_ASSERT(sharedPtr.type == CallbackSharedDataPointer::Bool); + (*sharedPtr.boolCallback)(result); + } +} + void CallbackDirectory::CallbackSharedDataPointer::doRef() { switch (type) { @@ -102,6 +119,9 @@ void CallbackDirectory::CallbackSharedDataPointer::doRef() case String: stringCallback->ref.ref(); break; + case Bool: + boolCallback->ref.ref(); + break; } } @@ -118,6 +138,10 @@ void CallbackDirectory::CallbackSharedDataPointer::doDeref() if (!stringCallback->ref.deref()) delete stringCallback; break; + case Bool: + if (!boolCallback->ref.deref()) + delete boolCallback; + break; } } @@ -251,6 +275,11 @@ void QWebEnginePagePrivate::didFetchDocumentInnerText(quint64 requestId, const Q m_callbacks.invoke(requestId, result); } +void QWebEnginePagePrivate::didFindText(quint64 requestId, int matchCount) +{ + m_callbacks.invoke(requestId, matchCount > 0); +} + void QWebEnginePagePrivate::updateAction(QWebEnginePage::WebAction action) const { #ifdef QT_NO_ACTION @@ -414,6 +443,20 @@ void QWebEnginePage::triggerAction(WebAction action, bool) } } +void QWebEnginePage::findText(const QString &subString, FindFlags options, const QWebEngineCallback<bool> &resultCallback) +{ + Q_D(QWebEnginePage); + if (subString.isEmpty()) { + d->adapter->stopFinding(); + if (resultCallback.d) + (*resultCallback.d)(false); + } else { + quint64 requestId = d->adapter->findText(subString, options & FindCaseSensitively, options & FindBackward); + if (resultCallback.d) + d->m_callbacks.registerCallback(requestId, resultCallback.d); + } +} + void QWebEnginePage::setViewportSize(const QSize &size) const { Q_UNUSED(size) diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index f89115579..aac37bc99 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -76,6 +76,7 @@ class QWebEngineCallback { public: template <typename F> QWebEngineCallback(F f) : d(new QtWebEnginePrivate::QWebEngineCallbackPrivate<T, F>(f)) { } + QWebEngineCallback() { } private: QExplicitlySharedDataPointer<QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> > d; friend class QWebEnginePage; @@ -249,8 +250,6 @@ public: enum FindFlag { FindBackward = 1, FindCaseSensitively = 2, - FindWrapsAroundDocument = 4, - HighlightAllOccurrences = 8 }; Q_DECLARE_FLAGS(FindFlags, FindFlag) @@ -368,7 +367,7 @@ public: QVariant inputMethodQuery(Qt::InputMethodQuery property) const; - bool findText(const QString &subString, FindFlags options = 0); + void findText(const QString &subString, FindFlags options = 0, const QWebEngineCallback<bool> &resultCallback = QWebEngineCallback<bool>()); void setForwardUnsupportedContent(bool forward); bool forwardUnsupportedContent() const; diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index e6113b795..ed21c3816 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -62,27 +62,33 @@ class CallbackDirectory { public: typedef QtWebEnginePrivate::QWebEngineCallbackPrivateBase<const QVariant&> VariantCallback; typedef QtWebEnginePrivate::QWebEngineCallbackPrivateBase<const QString&> StringCallback; + typedef QtWebEnginePrivate::QWebEngineCallbackPrivateBase<bool> BoolCallback; ~CallbackDirectory(); void registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<VariantCallback> &callback); void registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<StringCallback> &callback); + void registerCallback(quint64 requestId, const QExplicitlySharedDataPointer<BoolCallback> &callback); void invoke(quint64 requestId, const QVariant &result); void invoke(quint64 requestId, const QString &result); + void invoke(quint64 requestId, bool result); private: struct CallbackSharedDataPointer { enum { None, Variant, - String + String, + Bool } type; union { VariantCallback *variantCallback; StringCallback *stringCallback; + BoolCallback *boolCallback; }; CallbackSharedDataPointer() : type(None) { } CallbackSharedDataPointer(VariantCallback *callback) : type(Variant), variantCallback(callback) { callback->ref.ref(); } CallbackSharedDataPointer(StringCallback *callback) : type(String), stringCallback(callback) { callback->ref.ref(); } + CallbackSharedDataPointer(BoolCallback *callback) : type(Bool), boolCallback(callback) { callback->ref.ref(); } CallbackSharedDataPointer(const CallbackSharedDataPointer &other) : type(other.type), variantCallback(other.variantCallback) { doRef(); } ~CallbackSharedDataPointer() { doDeref(); } operator bool () const { return type != None; } @@ -125,8 +131,8 @@ public: virtual void didRunJavaScript(quint64 requestId, const QVariant& result) Q_DECL_OVERRIDE; virtual void didFetchDocumentMarkup(quint64 requestId, const QString& result) Q_DECL_OVERRIDE; virtual void didFetchDocumentInnerText(quint64 requestId, const QString& result) Q_DECL_OVERRIDE; + virtual void didFindText(quint64 requestId, int matchCount) Q_DECL_OVERRIDE; virtual void passOnFocus(bool reverse) Q_DECL_OVERRIDE { Q_UNUSED(reverse); }; - virtual void javaScriptConsoleMessage(int level, const QString& message, int lineNumber, const QString& sourceID) Q_DECL_OVERRIDE; void updateAction(QWebEnginePage::WebAction) const; diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index e5237bc72..3d884f464 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -177,6 +177,11 @@ void QWebEngineView::triggerPageAction(QWebEnginePage::WebAction action, bool ch page()->triggerAction(action, checked); } +void QWebEngineView::findText(const QString &subString, QWebEnginePage::FindFlags options, const QWebEngineCallback<bool> &resultCallback) +{ + page()->findText(subString, options, resultCallback); +} + void QWebEngineView::stop() { page()->triggerAction(QWebEnginePage::Stop); diff --git a/src/webenginewidgets/api/qwebengineview.h b/src/webenginewidgets/api/qwebengineview.h index 46b144d14..836e61be3 100644 --- a/src/webenginewidgets/api/qwebengineview.h +++ b/src/webenginewidgets/api/qwebengineview.h @@ -105,7 +105,7 @@ public: void setRenderHints(QPainter::RenderHints hints); void setRenderHint(QPainter::RenderHint hint, bool enabled = true); - bool findText(const QString& subString, QWebEnginePage::FindFlags options = 0); + void findText(const QString &subString, QWebEnginePage::FindFlags options = 0, const QWebEngineCallback<bool> &resultCallback = QWebEngineCallback<bool>()); virtual QSize sizeHint() const { return QSize(800, 600); } diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index d6f154e5e..bb07e2e00 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -173,6 +173,7 @@ private Q_SLOTS: void showModalDialog(); void testStopScheduledPageRefresh(); void findText(); + void findTextResult(); void supportedContentType(); // [Qt] tst_QWebEnginePage::infiniteLoopJS() timeouts with DFG JIT // https://bugs.webkit.org/show_bug.cgi?id=79040 @@ -3187,26 +3188,53 @@ void tst_QWebEnginePage::testStopScheduledPageRefresh() void tst_QWebEnginePage::findText() { -#if !defined(QWEBENGINEPAGE_FINDTEXT) - QSKIP("QWEBENGINEPAGE_FINDTEXT"); -#else m_view->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>")); +#if defined(QWEBENGINEPAGE_TRIGGERACTION_SELECTALL) m_page->triggerAction(QWebEnginePage::SelectAll); QVERIFY(!m_page->selectedText().isEmpty()); QVERIFY(!m_page->selectedHtml().isEmpty()); +#endif m_page->findText(""); QVERIFY(m_page->selectedText().isEmpty()); +#if defined(QWEBENGINEPAGE_SELECTEDHTML) QVERIFY(m_page->selectedHtml().isEmpty()); +#endif QStringList words = (QStringList() << "foo" << "bar"); foreach (QString subString, words) { - m_page->findText(subString, QWebEnginePage::FindWrapsAroundDocument); + m_page->findText(subString); + QEXPECT_FAIL("", "Unsupported: findText only highlights and doesn't update the selection.", Continue); QCOMPARE(m_page->selectedText(), subString); +#if defined(QWEBENGINEPAGE_SELECTEDHTML) QVERIFY(m_page->selectedHtml().contains(subString)); +#endif m_page->findText(""); QVERIFY(m_page->selectedText().isEmpty()); +#if defined(QWEBENGINEPAGE_SELECTEDHTML) QVERIFY(m_page->selectedHtml().isEmpty()); - } #endif + } +} + +void tst_QWebEnginePage::findTextResult() +{ + // findText will abort in blink if the view has an empty size. + m_view->resize(800, 600); + m_view->show(); + + QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); + m_view->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>")); + QTRY_COMPARE(loadSpy.count(), 1); + + QCOMPARE(findTextSync(m_page, ""), false); + + QStringList words = (QStringList() << "foo" << "bar"); + foreach (QString subString, words) { + QCOMPARE(findTextSync(m_page, subString), true); + QCOMPARE(findTextSync(m_page, ""), false); + } + + QCOMPARE(findTextSync(m_page, "blahhh"), false); + QCOMPARE(findTextSync(m_page, ""), false); } static QString getMimeTypeForExtension(const QString &ext) diff --git a/tests/auto/widgets/util.h b/tests/auto/widgets/util.h index 0b146aedc..035578358 100644 --- a/tests/auto/widgets/util.h +++ b/tests/auto/widgets/util.h @@ -142,6 +142,13 @@ static inline QString toHtmlSync(QWebEnginePage *page) return spy.waitForResult(); } +static inline bool findTextSync(QWebEnginePage *page, const QString &subString) +{ + CallbackSpy<bool> spy; + page->findText(subString, 0, spy.ref()); + return spy.waitForResult(); +} + static inline QVariant evaluateJavaScriptSync(QWebEnginePage *page, const QString &script) { CallbackSpy<QVariant> spy; |