diff options
11 files changed, 211 insertions, 24 deletions
diff --git a/src/webengine/api/qquickwebenginetestsupport.cpp b/src/webengine/api/qquickwebenginetestsupport.cpp index a946cc0e4..41f374766 100644 --- a/src/webengine/api/qquickwebenginetestsupport.cpp +++ b/src/webengine/api/qquickwebenginetestsupport.cpp @@ -62,8 +62,48 @@ void QQuickWebEngineErrorPage::loadStarted(const QUrl &provisionalUrl) Q_EMIT loadingChanged(&loadRequest); } + +QQuickWebEngineTestInputContext::QQuickWebEngineTestInputContext() + : m_visible(false) +{ +} + +QQuickWebEngineTestInputContext::~QQuickWebEngineTestInputContext() +{ + release(); +} + +void QQuickWebEngineTestInputContext::create() +{ + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = this; +} + +void QQuickWebEngineTestInputContext::release() +{ + QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = 0; +} + +void QQuickWebEngineTestInputContext::showInputPanel() +{ + m_visible = true; +} + +void QQuickWebEngineTestInputContext::hideInputPanel() +{ + m_visible = false; +} + +bool QQuickWebEngineTestInputContext::isInputPanelVisible() const +{ + return m_visible; +} + + QQuickWebEngineTestSupport::QQuickWebEngineTestSupport() - : m_errorPage(new QQuickWebEngineErrorPage()) + : m_errorPage(new QQuickWebEngineErrorPage) + , m_testInputContext(new QQuickWebEngineTestInputContext) { } @@ -72,6 +112,11 @@ QQuickWebEngineErrorPage *QQuickWebEngineTestSupport::errorPage() const return m_errorPage.data(); } +QQuickWebEngineTestInputContext *QQuickWebEngineTestSupport::testInputContext() const +{ + return m_testInputContext.data(); +} + QT_END_NAMESPACE #include "moc_qquickwebenginetestsupport_p.cpp" diff --git a/src/webengine/api/qquickwebenginetestsupport_p.h b/src/webengine/api/qquickwebenginetestsupport_p.h index cca8d1df4..a84d00307 100644 --- a/src/webengine/api/qquickwebenginetestsupport_p.h +++ b/src/webengine/api/qquickwebenginetestsupport_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qinputmethod_p.h> #include <private/qtwebengineglobal_p.h> #include <QObject> @@ -73,13 +74,33 @@ Q_SIGNALS: void loadingChanged(QQuickWebEngineLoadRequest *loadRequest); }; +class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineTestInputContext : public QPlatformInputContext { + Q_OBJECT + +public: + QQuickWebEngineTestInputContext(); + ~QQuickWebEngineTestInputContext(); + + Q_INVOKABLE void create(); + Q_INVOKABLE void release(); + + virtual void showInputPanel(); + virtual void hideInputPanel(); + virtual bool isInputPanelVisible() const; + +private: + bool m_visible; +}; + class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineTestSupport : public QObject { Q_OBJECT Q_PROPERTY(QQuickWebEngineErrorPage *errorPage READ errorPage CONSTANT FINAL) + Q_PROPERTY(QQuickWebEngineTestInputContext *testInputContext READ testInputContext CONSTANT FINAL) public: QQuickWebEngineTestSupport(); QQuickWebEngineErrorPage *errorPage() const; + QQuickWebEngineTestInputContext *testInputContext() const; Q_SIGNALS: void windowCloseRejected(); @@ -87,6 +108,7 @@ Q_SIGNALS: private: QScopedPointer<QQuickWebEngineErrorPage> m_errorPage; + QScopedPointer<QQuickWebEngineTestInputContext> m_testInputContext; }; QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 68a290df9..bf3ea955c 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -873,8 +873,7 @@ QQuickWebEngineView::QQuickWebEngineView(QQuickItem *parent) Q_D(QQuickWebEngineView); d->q_ptr = this; this->setActiveFocusOnTab(true); - this->setFlags(QQuickItem::ItemIsFocusScope | QQuickItem::ItemAcceptsInputMethod - | QQuickItem::ItemAcceptsDrops); + this->setFlags(QQuickItem::ItemIsFocusScope | QQuickItem::ItemAcceptsDrops); #ifndef QT_NO_ACCESSIBILITY QQuickAccessibleAttached *accessible = QQuickAccessibleAttached::qmlAttachedProperties(this); diff --git a/src/webengine/plugin/testsupport/plugin.cpp b/src/webengine/plugin/testsupport/plugin.cpp index 9352e3666..c7eda2405 100644 --- a/src/webengine/plugin/testsupport/plugin.cpp +++ b/src/webengine/plugin/testsupport/plugin.cpp @@ -58,6 +58,8 @@ public: qmlRegisterType<QQuickWebEngineTestSupport>(uri, 1, 0, "WebEngineTestSupport"); qmlRegisterUncreatableType<QQuickWebEngineErrorPage>(uri, 1, 0, "WebEngineErrorPage", tr("Cannot create a separate instance of WebEngineErrorPage")); + qmlRegisterUncreatableType<QQuickWebEngineTestInputContext>(uri, 1, 0, "TestInputContext", + tr("Cannot create a separate instance of WebEngineErrorPage")); } }; diff --git a/src/webengine/plugin/testsupport/testsupport.pro b/src/webengine/plugin/testsupport/testsupport.pro index 1a45ad56a..2804635f8 100644 --- a/src/webengine/plugin/testsupport/testsupport.pro +++ b/src/webengine/plugin/testsupport/testsupport.pro @@ -4,7 +4,7 @@ TARGETPATH = QtWebEngine/testsupport IMPORT_VERSION = 1.0 QT += webengine qml quick -QT_PRIVATE += webengine-private +QT_PRIVATE += webengine-private gui-private INCLUDEPATH += $$QTWEBENGINE_ROOT/src/core $$QTWEBENGINE_ROOT/src/webengine $$QTWEBENGINE_ROOT/src/webengine/api diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp index 749a2e0d8..86f3aaa64 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -228,14 +228,15 @@ void RenderWidgetHostViewQtDelegateQuick::resize(int width, int height) void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVisible) { - if (qApp->inputMethod()->isVisible() == editorVisible) - return; + setFlag(QQuickItem::ItemAcceptsInputMethod, editorVisible); + + if (parentItem()) + parentItem()->setFlag(QQuickItem::ItemAcceptsInputMethod, editorVisible); - if (parentItem() && parentItem()->flags() & QQuickItem::ItemAcceptsInputMethod) { + if (qApp->inputMethod()->isVisible() != editorVisible) { qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); qApp->inputMethod()->setVisible(editorVisible); } - } bool RenderWidgetHostViewQtDelegateQuick::event(QEvent *event) diff --git a/tests/auto/quick/qmltests/data/tst_inputMethod.qml b/tests/auto/quick/qmltests/data/tst_inputMethod.qml new file mode 100644 index 000000000..c09a8bdd9 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_inputMethod.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtTest 1.0 +import QtWebEngine 1.4 +import QtWebEngine.testsupport 1.0 + +TestWebEngineView { + id: webEngineView + width: 200 + height: 400 + + testSupport: WebEngineTestSupport { } + + TestCase { + name: "WebEngineViewInputMethod" + when: windowShown + + function init() { + testSupport.testInputContext.create(); + } + + function cleanup() { + testSupport.testInputContext.release(); + } + + function test_softwareInputPanel() { + verify(!Qt.inputMethod.visible); + webEngineView.loadHtml( + "<html><body>" + + " <form><input id='textInput' type='text' /></form>" + + "</body></html"); + verify(webEngineView.waitForLoadSucceeded()); + + verify(!getActiveElementId()); + verify(!Qt.inputMethod.visible); + + // Show input panel + webEngineView.runJavaScript("document.getElementById('textInput').focus()"); + webEngineView.verifyElementHasFocus("textInput"); + tryVerify(function() { return Qt.inputMethod.visible; }); + + // Hide input panel + webEngineView.runJavaScript("document.getElementById('textInput').blur()"); + verify(!getActiveElementId()); + tryVerify(function() { return !Qt.inputMethod.visible; }); + } + } +} + diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index 40fba4512..3973ede14 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -52,6 +52,7 @@ OTHER_FILES += \ $$PWD/data/tst_focusOnNavigation.qml \ $$PWD/data/tst_formValidation.qml \ $$PWD/data/tst_geopermission.qml \ + $$PWD/data/tst_inputMethod.qml \ $$PWD/data/tst_javaScriptDialogs.qml \ $$PWD/data/tst_linkHovered.qml \ $$PWD/data/tst_loadFail.qml \ diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index 49f1a0f2a..8af5a2808 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -437,50 +437,69 @@ void tst_QQuickWebEngineView::transparentWebEngineViews() void tst_QQuickWebEngineView::inputMethod() { -#if !defined(QQUICKWEBENGINEVIEW_ITEMACCEPTSINPUTMETHOD) - QSKIP("QQUICKWEBENGINEVIEW_ITEMACCEPTSINPUTMETHOD"); -#else + m_window->show(); + QTRY_VERIFY(qApp->focusObject()); + QQuickItem *input; + QQuickWebEngineView *view = webEngineView(); view->setUrl(urlFromTestPath("html/inputmethod.html")); QVERIFY(waitForLoadSucceeded(view)); + input = qobject_cast<QQuickItem *>(qApp->focusObject()); + QVERIFY(!input->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); QVERIFY(!view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); + runJavaScript("document.getElementById('inputField').focus();"); + QTRY_COMPARE(activeElementId(view), QStringLiteral("inputField")); + input = qobject_cast<QQuickItem *>(qApp->focusObject()); + QTRY_VERIFY(input->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); QVERIFY(view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); + runJavaScript("document.getElementById('inputField').blur();"); + QTRY_VERIFY(activeElementId(view).isEmpty()); + input = qobject_cast<QQuickItem *>(qApp->focusObject()); + QTRY_VERIFY(!input->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); QVERIFY(!view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); -#endif } void tst_QQuickWebEngineView::inputMethodHints() { -#if !defined(QQUICKWEBENGINEVIEW_ITEMACCEPTSINPUTMETHOD) - QSKIP("QQUICKWEBENGINEVIEW_ITEMACCEPTSINPUTMETHOD"); -#else - QQuickWebEngineView *view = webEngineView(); + m_window->show(); + QTRY_VERIFY(qApp->focusObject()); + QQuickItem *input; + QQuickWebEngineView *view = webEngineView(); view->setUrl(urlFromTestPath("html/inputmethod.html")); QVERIFY(waitForLoadSucceeded(view)); + // Initialize input fields with values to check input method query is being updated. + runJavaScript("document.getElementById('emailInputField').value = 'a@b.com';"); + runJavaScript("document.getElementById('editableDiv').innerText = 'bla';"); + // Setting focus on an input element results in an element in its shadow tree becoming the focus node. // Input hints should not be set from this shadow tree node but from the input element itself. runJavaScript("document.getElementById('emailInputField').focus();"); + QTRY_COMPARE(activeElementId(view), QStringLiteral("emailInputField")); + input = qobject_cast<QQuickItem *>(qApp->focusObject()); + QTRY_COMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("a@b.com")); + QVERIFY(input->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); QVERIFY(view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); QInputMethodQueryEvent query(Qt::ImHints); - QGuiApplication::sendEvent(view, &query); - Qt::InputMethodHints hints(query.value(Qt::ImHints).toUInt() & Qt::ImhExclusiveInputMask); - QCOMPARE(hints, Qt::ImhEmailCharactersOnly); + QGuiApplication::sendEvent(input, &query); + QTRY_COMPARE(Qt::InputMethodHints(query.value(Qt::ImHints).toUInt() & Qt::ImhExclusiveInputMask), Qt::ImhEmailCharactersOnly); // The focus of an editable DIV is given directly to it, so no shadow root element // is necessary. This tests the WebPage::editorState() method ability to get the // right element without breaking. runJavaScript("document.getElementById('editableDiv').focus();"); + QTRY_COMPARE(activeElementId(view), QStringLiteral("editableDiv")); + input = qobject_cast<QQuickItem *>(qApp->focusObject()); + QTRY_COMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("bla")); + QVERIFY(input->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); QVERIFY(view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); query = QInputMethodQueryEvent(Qt::ImHints); - QGuiApplication::sendEvent(view, &query); - hints = Qt::InputMethodHints(query.value(Qt::ImHints).toUInt()); - QCOMPARE(hints, Qt::ImhNone); -#endif + QGuiApplication::sendEvent(input, &query); + QTRY_COMPARE(Qt::InputMethodHints(query.value(Qt::ImHints).toUInt()), Qt::ImhPreferLowercase | Qt::ImhMultiLine); } void tst_QQuickWebEngineView::setZoomFactor() diff --git a/tests/auto/quick/qquickwebengineviewgraphics/qquickwebengineviewgraphics.pro b/tests/auto/quick/qquickwebengineviewgraphics/qquickwebengineviewgraphics.pro index 9471def00..2a2155e44 100644 --- a/tests/auto/quick/qquickwebengineviewgraphics/qquickwebengineviewgraphics.pro +++ b/tests/auto/quick/qquickwebengineviewgraphics/qquickwebengineviewgraphics.pro @@ -1,4 +1,4 @@ include(../tests.pri) CONFIG -= testcase # remove, once this passes in the CI exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc -QT_PRIVATE += webengine-private +QT_PRIVATE += webengine-private gui-private diff --git a/tests/auto/quick/shared/util.h b/tests/auto/quick/shared/util.h index dce0afb8e..98f19bd49 100644 --- a/tests/auto/quick/shared/util.h +++ b/tests/auto/quick/shared/util.h @@ -142,4 +142,26 @@ inline QString bodyInnerText(QQuickWebEngineView *webEngineView) return arguments.at(1).toString(); } +inline QString activeElementId(QQuickWebEngineView *webEngineView) +{ + qRegisterMetaType<QQuickWebEngineView::JavaScriptConsoleMessageLevel>("JavaScriptConsoleMessageLevel"); + QSignalSpy consoleMessageSpy(webEngineView, &QQuickWebEngineView::javaScriptConsoleMessage); + + webEngineView->runJavaScript( + "if (document.activeElement == null)" + " console.log('');" + "else" + " console.log(document.activeElement.id);" + ); + + if (!consoleMessageSpy.wait()) + return QString(); + + QList<QVariant> arguments = consoleMessageSpy.takeFirst(); + if (static_cast<QQuickWebEngineView::JavaScriptConsoleMessageLevel>(arguments.at(0).toInt()) != QQuickWebEngineView::InfoMessageLevel) + return QString(); + + return arguments.at(1).toString(); +} + #endif /* UTIL_H */ |