diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp | 565 | ||||
-rw-r--r-- | tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp | 385 |
2 files changed, 385 insertions, 565 deletions
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 4d073e94c..b03418aea 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -120,8 +120,6 @@ private Q_SLOTS: void testLocalStorageVisibility(); void testEnablePersistentStorage(); void consoleOutput(); - void inputMethods_data(); - void inputMethods(); void errorPageExtension(); void errorPageExtensionLoadFinished(); void userAgentNewlineStripping(); @@ -1631,569 +1629,6 @@ void tst_QWebEnginePage::backActionUpdate() QVERIFY(action->isEnabled()); } -void tst_QWebEnginePage::inputMethods_data() -{ - QTest::addColumn<QString>("viewType"); - QTest::newRow("QWebEngineView") << "QWebEngineView"; - QTest::newRow("QGraphicsWebView") << "QGraphicsWebView"; -} - -#if defined(QWEBENGINEPAGE_INPUTMETHODQUERY) -static void clickOnPage(QWebEnginePage* page, const QPoint& position) -{ - QMouseEvent evpres(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); - page->event(&evpres); - QMouseEvent evrel(QEvent::MouseButtonRelease, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); - page->event(&evrel); -} -#endif - -void tst_QWebEnginePage::inputMethods() -{ -#if !defined(QWEBENGINEPAGE_INPUTMETHODQUERY) - QSKIP("QWEBENGINEPAGE_INPUTMETHODQUERY"); -#else - QFETCH(QString, viewType); - QWebEnginePage* page = new QWebEnginePage; - QObject* view = 0; - QScopedPointer<QObject> container(0); - if (viewType == "QWebEngineView") { - QWebEngineView* wv = new QWebEngineView; - wv->setPage(page); - view = wv; - container.reset(view); - } else if (viewType == "QGraphicsWebView") { - QGraphicsWebView* wv = new QGraphicsWebView; - wv->setPage(page); - view = wv; - - QGraphicsView* gv = new QGraphicsView; - QGraphicsScene* scene = new QGraphicsScene(gv); - gv->setScene(scene); - scene->addItem(wv); - wv->setGeometry(QRect(0, 0, 500, 500)); - - container.reset(gv); - } else - QVERIFY2(false, "Unknown view type"); - - page->settings()->setFontFamily(QWebEngineSettings::SerifFont, page->settings()->fontFamily(QWebEngineSettings::FixedFont)); - page->setHtml("<html><body>" \ - "<input type='text' id='input1' style='font-family: serif' value='' maxlength='20'/><br>" \ - "<input type='password'/>" \ - "</body></html>"); - page->mainFrame()->setFocus(); - - TestInputContext testContext; - - QWebEngineElementCollection inputs = page->mainFrame()->documentElement().findAll("input"); - QPoint textInputCenter = inputs.at(0).geometry().center(); - - clickOnPage(page, textInputCenter); - - //ImMicroFocus - QVariant variant = page->inputMethodQuery(Qt::ImMicroFocus); - QVERIFY(inputs.at(0).geometry().contains(variant.toRect().topLeft())); - - // We assigned the serif font famility to be the same as the fixef font family. - // Then test ImFont on a serif styled element, we should get our fixef font family. - variant = page->inputMethodQuery(Qt::ImFont); - QFont font = variant.value<QFont>(); - QCOMPARE(page->settings()->fontFamily(QWebEngineSettings::FixedFont), font.family()); - - QList<QInputMethodEvent::Attribute> inputAttributes; - - //Insert text. - { - QInputMethodEvent eventText("QtWebEngine", inputAttributes); - QSignalSpy signalSpy(page, SIGNAL(microFocusChanged())); - page->event(&eventText); - QCOMPARE(signalSpy.count(), 0); - } - - { - QInputMethodEvent eventText("", inputAttributes); - eventText.setCommitString(QString("QtWebEngine"), 0, 0); - page->event(&eventText); - } - - //ImMaximumTextLength - variant = page->inputMethodQuery(Qt::ImMaximumTextLength); - QCOMPARE(20, variant.toInt()); - - //Set selection - inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 3, 2, QVariant()); - QInputMethodEvent eventSelection("",inputAttributes); - page->event(&eventSelection); - - //ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - int anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 3); - - //ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - int cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 5); - - //ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - QString selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("eb")); - - //Set selection with negative length - inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 6, -5, QVariant()); - QInputMethodEvent eventSelection3("",inputAttributes); - page->event(&eventSelection3); - - //ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 1); - - //ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 6); - - //ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("tWebK")); - - //ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - QString value = variant.value<QString>(); - QCOMPARE(value, QString("QtWebEngine")); - - { - QList<QInputMethodEvent::Attribute> attributes; - // Clear the selection, so the next test does not clear any contents. - QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); - attributes.append(newSelection); - QInputMethodEvent event("composition", attributes); - page->event(&event); - } - - // A ongoing composition should not change the surrounding text before it is committed. - variant = page->inputMethodQuery(Qt::ImSurroundingText); - value = variant.value<QString>(); - QCOMPARE(value, QString("QtWebEngine")); - - // Cancel current composition first - inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); - QInputMethodEvent eventSelection4("", inputAttributes); - page->event(&eventSelection4); - - // START - Tests for Selection when the Editor is NOT in Composition mode - - // LEFT to RIGHT selection - // Deselect the selection by sending MouseButtonPress events - // This moves the current cursor to the end of the text - clickOnPage(page, textInputCenter); - - { - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event(QString(), attributes); - event.setCommitString("XXX", 0, 0); - page->event(&event); - event.setCommitString(QString(), -2, 2); // Erase two characters. - page->event(&event); - event.setCommitString(QString(), -1, 1); // Erase one character. - page->event(&event); - variant = page->inputMethodQuery(Qt::ImSurroundingText); - value = variant.value<QString>(); - QCOMPARE(value, QString("QtWebEngine")); - } - - //Move to the start of the line - page->triggerAction(QWebEnginePage::MoveToStartOfLine); - - QKeyEvent keyRightEventPress(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier); - QKeyEvent keyRightEventRelease(QEvent::KeyRelease, Qt::Key_Right, Qt::NoModifier); - - //Move 2 characters RIGHT - for (int j = 0; j < 2; ++j) { - page->event(&keyRightEventPress); - page->event(&keyRightEventRelease); - } - - //Select to the end of the line - page->triggerAction(QWebEnginePage::SelectEndOfLine); - - //ImAnchorPosition QtWebEngine - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 2); - - //ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 8); - - //ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("WebKit")); - - //RIGHT to LEFT selection - //Deselect the selection (this moves the current cursor to the end of the text) - clickOnPage(page, textInputCenter); - - //ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 8); - - //ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 8); - - //ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("")); - - QKeyEvent keyLeftEventPress(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier); - QKeyEvent keyLeftEventRelease(QEvent::KeyRelease, Qt::Key_Left, Qt::NoModifier); - - //Move 2 characters LEFT - for (int i = 0; i < 2; ++i) { - page->event(&keyLeftEventPress); - page->event(&keyLeftEventRelease); - } - - //Select to the start of the line - page->triggerAction(QWebEnginePage::SelectStartOfLine); - - //ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 6); - - //ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 0); - - //ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("QtWebK")); - - //END - Tests for Selection when the Editor is not in Composition mode - - page->setHtml("<html><body>" \ - "<input type='text' id='input4' value='QtWebEngine inputMethod'/>" \ - "</body></html>"); - evaluateJavaScriptSync(page, "var inputEle = document.getElementById('input4'); inputEle.focus(); inputEle.select();"); - - // Clear the selection, also cancel the ongoing composition if there is one. - { - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); - attributes.append(newSelection); - QInputMethodEvent event("", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("")); - - variant = page->inputMethodQuery(Qt::ImSurroundingText); - QString surroundingValue = variant.value<QString>(); - QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 0); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 0); - - // 1. Insert a character to the beginning of the line. - // Send temporary text, which makes the editor has composition 'm'. - { - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event("m", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value<QString>(); - QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 0); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 0); - - // Send temporary text, which makes the editor has composition 'n'. - { - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event("n", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value<QString>(); - QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 0); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 0); - - // Send commit text, which makes the editor conforms composition. - { - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event("", attributes); - event.setCommitString("o"); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value<QString>(); - QCOMPARE(surroundingValue, QString("oQtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 1); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 1); - - // 2. insert a character to the middle of the line. - // Send temporary text, which makes the editor has composition 'd'. - { - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event("d", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value<QString>(); - QCOMPARE(surroundingValue, QString("oQtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 1); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 1); - - // Send commit text, which makes the editor conforms composition. - { - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event("", attributes); - event.setCommitString("e"); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value<QString>(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 2); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 2); - - // 3. Insert a character to the end of the line. - page->triggerAction(QWebEnginePage::MoveToEndOfLine); - - // Send temporary text, which makes the editor has composition 't'. - { - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event("t", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value<QString>(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 22); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 22); - - // Send commit text, which makes the editor conforms composition. - { - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event("", attributes); - event.setCommitString("t"); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value<QString>(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethodt")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 23); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 23); - - // 4. Replace the selection. - page->triggerAction(QWebEnginePage::SelectPreviousWord); - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("inputMethodt")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value<QString>(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethodt")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 11); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 23); - - // Send temporary text, which makes the editor has composition 'w'. - { - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event("w", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value<QString>(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine ")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 11); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 11); - - // Send commit text, which makes the editor conforms composition. - { - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event("", attributes); - event.setCommitString("2"); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value<QString>(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value<QString>(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine 2")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 12); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 12); -#endif -} - void tst_QWebEnginePage::protectBindingsRuntimeObjectsFromCollector() { #if !defined(QWEBENGINEPAGE_CREATEPLUGIN) diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index a6138c59d..82e50409d 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -97,8 +97,11 @@ private Q_SLOTS: void postData(); void softwareInputPanel(); + void inputMethods(); + void textSelection(); void hiddenText(); void emptyInputMethodEvent(); + void imeComposition(); void newlineInTextarea(); }; @@ -1341,6 +1344,24 @@ static QPoint elementCenter(QWebEnginePage *page, const QString &id) return QPoint(rectList.at(0).toInt(), rectList.at(1).toInt()); } +static QRect elementGeometry(QWebEnginePage *page, const QString &id) +{ + const QString jsCode( + "(function() {" + " var elem = document.getElementById('" + id + "');" + " var rect = elem.getBoundingClientRect();" + " return [rect.left, rect.top, rect.right, rect.bottom];" + "})()"); + QVariantList coords = evaluateJavaScriptSync(page, jsCode).toList(); + + if (coords.count() != 4) { + qWarning("elementGeometry faield."); + return QRect(); + } + + return QRect(coords[0].toInt(), coords[1].toInt(), coords[2].toInt(), coords[3].toInt()); +} + void tst_QWebEngineView::softwareInputPanel() { TestInputContext testContext; @@ -1398,6 +1419,183 @@ void tst_QWebEngineView::softwareInputPanel() QVERIFY(!testContext.isInputPanelVisible()); } +void tst_QWebEngineView::inputMethods() +{ + QWebEngineView view; + view.show(); + + QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged())); + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.settings()->setFontFamily(QWebEngineSettings::SerifFont, view.settings()->fontFamily(QWebEngineSettings::FixedFont)); + view.setHtml("<html><body>" + " <input type='text' id='input1' style='font-family: serif' value='' maxlength='20' size='50'/>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + + QPoint textInputCenter = elementCenter(view.page(), "input1"); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); + + // ImCursorRectangle + QVariant variant = view.focusProxy()->inputMethodQuery(Qt::ImCursorRectangle); + QVERIFY(elementGeometry(view.page(), "input1").contains(variant.toRect().topLeft())); + + // We assigned the serif font family to be the same as the fixed font family. + // Then test ImFont on a serif styled element, we should get our fixed font family. + variant = view.focusProxy()->inputMethodQuery(Qt::ImFont); + QFont font = variant.value<QFont>(); + QEXPECT_FAIL("", "UNIMPLEMENTED: RenderWidgetHostViewQt::inputMethodQuery(Qt::ImFont)", Continue); + QCOMPARE(view.settings()->fontFamily(QWebEngineSettings::FixedFont), font.family()); + + QList<QInputMethodEvent::Attribute> inputAttributes; + + // Insert text + { + QString text = QStringLiteral("QtWebEngine"); + QInputMethodEvent eventText(text, inputAttributes); + QApplication::sendEvent(view.focusProxy(), &eventText); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), text); + QCOMPARE(selectionChangedSpy.count(), 0); + } + + { + QString text = QStringLiteral("QtWebEngine"); + QInputMethodEvent eventText("", inputAttributes); + eventText.setCommitString(text, 0, 0); + QApplication::sendEvent(view.focusProxy(), &eventText); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), text); + QCOMPARE(selectionChangedSpy.count(), 0); + } + + // ImMaximumTextLength + QEXPECT_FAIL("", "UNIMPLEMENTED: RenderWidgetHostViewQt::inputMethodQuery(Qt::ImMaximumTextLength)", Continue); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImMaximumTextLength).toInt(), 20); + + // Set selection + inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 3, 2, QVariant()); + QInputMethodEvent eventSelection1("", inputAttributes); + + QApplication::sendEvent(view.focusProxy(), &eventSelection1); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 1); + + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 3); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 5); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("eb")); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine")); + + // Set selection with negative length + inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 6, -5, QVariant()); + QInputMethodEvent eventSelection2("", inputAttributes); + QApplication::sendEvent(view.focusProxy(), &eventSelection2); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 2); + + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 1); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 6); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("tWebE")); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine")); + + QList<QInputMethodEvent::Attribute> attributes; + // Clear the selection, so the next test does not clear any contents. + QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); + attributes.append(newSelection); + QInputMethodEvent eventComposition("composition", attributes); + QApplication::sendEvent(view.focusProxy(), &eventComposition); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 3); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); + + // An ongoing composition should not change the surrounding text before it is committed. + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine")); + + // Cancel current composition first + inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); + QInputMethodEvent eventSelection3("", inputAttributes); + QApplication::sendEvent(view.focusProxy(), &eventSelection3); + + // Cancelling composition should not clear the surrounding text + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine")); +} + +void tst_QWebEngineView::textSelection() +{ + QWebEngineView view; + view.show(); + + QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged())); + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.setHtml("<html><body>" + " <input type='text' id='input1' value='QtWebEngine' size='50'/>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + + // Tests for Selection when the Editor is NOT in Composition mode + + // LEFT to RIGHT selection + // Mouse click event moves the current cursor to the end of the text + QPoint textInputCenter = elementCenter(view.page(), "input1"); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 11); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 11); + // There was no selection to be changed by the click + QCOMPARE(selectionChangedSpy.count(), 0); + + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event(QString(), attributes); + event.setCommitString("XXX", 0, 0); + QApplication::sendEvent(view.focusProxy(), &event); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngineXXX")); + + event.setCommitString(QString(), -2, 2); // Erase two characters. + QApplication::sendEvent(view.focusProxy(), &event); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngineX")); + + event.setCommitString(QString(), -1, 1); // Erase one character. + QApplication::sendEvent(view.focusProxy(), &event); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine")); + + // Move to the start of the line + QTest::keyClick(view.focusProxy(), Qt::Key_Home); + + // Move 2 characters RIGHT + for (int j = 0; j < 2; ++j) + QTest::keyClick(view.focusProxy(), Qt::Key_Right); + + // Select to the end of the line + QTest::keyClick(view.focusProxy(), Qt::Key_End, Qt::ShiftModifier); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 1); + + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 2); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 11); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("WebEngine")); + + // RIGHT to LEFT selection + // Deselect the selection (this moves the current cursor to the end of the text) + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 2); + + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 11); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 11); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); + + // Move 2 characters LEFT + for (int i = 0; i < 2; ++i) + QTest::keyClick(view.focusProxy(), Qt::Key_Left); + + // Select to the start of the line + QTest::keyClick(view.focusProxy(), Qt::Key_Home, Qt::ShiftModifier); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 3); + + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 9); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 0); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("QtWebEngi")); +} + void tst_QWebEngineView::hiddenText() { QWebEngineView view; @@ -1451,6 +1649,193 @@ void tst_QWebEngineView::emptyInputMethodEvent() QCOMPARE(inputValue, QString("QtWebEngine")); } +void tst_QWebEngineView::imeComposition() +{ + QWebEngineView view; + view.show(); + + QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged())); + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.setHtml("<html><body>" + " <input type='text' id='input1' value='QtWebEngine inputMethod'/>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(!evaluateJavaScriptSync(view.page(), "window.getSelection().toString()").toString().isEmpty()); + + QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue); + QVERIFY(selectionChangedSpy.wait(100)); + QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue); + QCOMPARE(selectionChangedSpy.count(), 1); + + // Clear the selection, also cancel the ongoing composition if there is one. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); + attributes.append(newSelection); + QInputMethodEvent event("", attributes); + QApplication::sendEvent(view.focusProxy(), &event); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "window.getSelection().toString()").toString().isEmpty()); + + QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue); + QVERIFY(selectionChangedSpy.wait(100)); + QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue); + QCOMPARE(selectionChangedSpy.count(), 2); + } + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine inputMethod")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 0); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 0); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); + + selectionChangedSpy.clear(); + + + // 1. Insert a character to the beginning of the line. + // Send temporary text, which makes the editor has composition 'm'. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("m", attributes); + QApplication::sendEvent(view.focusProxy(), &event); + } + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine inputMethod")); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 0); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 0); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); + QCOMPARE(selectionChangedSpy.count(), 0); + + // Send temporary text, which makes the editor has composition 'n'. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("n", attributes); + QApplication::sendEvent(view.focusProxy(), &event); + } + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("QtWebEngine inputMethod")); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 0); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 0); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); + QCOMPARE(selectionChangedSpy.count(), 0); + + // Send commit text, which makes the editor conforms composition. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("o"); + QApplication::sendEvent(view.focusProxy(), &event); + } + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oQtWebEngine inputMethod")); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 1); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 1); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); + QCOMPARE(selectionChangedSpy.count(), 0); + + + // 2. insert a character to the middle of the line. + // Send temporary text, which makes the editor has composition 'd'. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("d", attributes); + QApplication::sendEvent(view.focusProxy(), &event); + } + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oQtWebEngine inputMethod")); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 1); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 1); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); + QCOMPARE(selectionChangedSpy.count(), 0); + + // Send commit text, which makes the editor conforms composition. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("e"); + QApplication::sendEvent(view.focusProxy(), &event); + } + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oeQtWebEngine inputMethod")); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 2); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 2); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); + QCOMPARE(selectionChangedSpy.count(), 0); + + + // 3. Insert a character to the end of the line. + QTest::keyClick(view.focusProxy(), Qt::Key_End); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 25); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 25); + + // Send temporary text, which makes the editor has composition 't'. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("t", attributes); + QApplication::sendEvent(view.focusProxy(), &event); + } + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oeQtWebEngine inputMethod")); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 25); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 25); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); + QCOMPARE(selectionChangedSpy.count(), 0); + + // Send commit text, which makes the editor conforms composition. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("t"); + QApplication::sendEvent(view.focusProxy(), &event); + } + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oeQtWebEngine inputMethodt")); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 26); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 26); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); + QCOMPARE(selectionChangedSpy.count(), 0); + + + // 4. Replace the selection. +#ifndef Q_OS_MACOS + QTest::keyClick(view.focusProxy(), Qt::Key_Left, Qt::ShiftModifier | Qt::ControlModifier); +#else + QTest::keyClick(view.focusProxy(), Qt::Key_Left, Qt::ShiftModifier | Qt::AltModifier); +#endif + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 1); + + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oeQtWebEngine inputMethodt")); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 14); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 26); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("inputMethodt")); + + // Send temporary text, which makes the editor has composition 'w'. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("w", attributes); + QApplication::sendEvent(view.focusProxy(), &event); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "window.getSelection().toString()").toString().isEmpty()); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("oeQtWebEngine w")); + + QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue); + QVERIFY(selectionChangedSpy.wait(100)); + QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue); + QCOMPARE(selectionChangedSpy.count(), 2); + } + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oeQtWebEngine ")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 14); + QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 14); + QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue); + QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); + + // Send commit text, which makes the editor conforms composition. + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("2"); + QApplication::sendEvent(view.focusProxy(), &event); + } + // There is no text selection to be changed at this point thus we can't wait for selectionChanged signal. + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("oeQtWebEngine 2")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 15); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 15); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QString("")); +} + void tst_QWebEngineView::newlineInTextarea() { QWebEngineView view; |