コード例 #1
0
TEST_F(InputMethodControllerTest, DeleteBySettingEmptyComposition)
{
    HTMLInputElement* input = toHTMLInputElement(
        insertHTMLElement("<input id='sample'>", "sample"));

    input->setValue("foo ");
    controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
    EXPECT_STREQ("foo ", input->value().utf8().data());
    controller().extendSelectionAndDelete(0, 0);
    EXPECT_STREQ("foo ", input->value().utf8().data());

    input->setValue("foo ");
    controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
    EXPECT_STREQ("foo ", input->value().utf8().data());
    controller().extendSelectionAndDelete(1, 0);
    EXPECT_STREQ("foo", input->value().utf8().data());

    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, 3, Color(255, 0, 0), false, 0));
    controller().setCompositionFromExistingText(underlines, 0, 3);

    controller().setComposition(String(""), underlines, 0, 3);

    EXPECT_STREQ("", input->value().utf8().data());
}
コード例 #2
0
TEST_F(InputMethodControllerTest, CompositionFireBeforeInput)
{
    document().settings()->setScriptEnabled(true);
    Element* editable = insertHTMLElement("<div id='sample' contentEditable='true'></div>", "sample");
    Element* script = document().createElement("script", ASSERT_NO_EXCEPTION);
    script->setInnerHTML(
        "document.getElementById('sample').addEventListener('beforeinput', function(event) {"
        "    document.title = `beforeinput.isComposing:${event.isComposing};`;"
        "});"
        "document.getElementById('sample').addEventListener('input', function(event) {"
        "    document.title += `input.isComposing:${event.isComposing};`;"
        "});",
        ASSERT_NO_EXCEPTION);
    document().body()->appendChild(script, ASSERT_NO_EXCEPTION);
    document().view()->updateAllLifecyclePhases();

    // Simulate composition in the |contentEditable|.
    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0));
    editable->focus();

    document().setTitle(emptyString());
    controller().setComposition("foo", underlines, 0, 3);
    EXPECT_STREQ("beforeinput.isComposing:true;input.isComposing:true;", document().title().utf8().data());

    document().setTitle(emptyString());
    controller().confirmComposition();
    // Last 'beforeinput' should also be inside composition scope.
    EXPECT_STREQ("beforeinput.isComposing:true;input.isComposing:true;", document().title().utf8().data());
}
コード例 #3
0
TEST_F(InputMethodControllerTest, SetCompositionForInputWithDifferentNewCursorPositions)
{
    HTMLInputElement* input = toHTMLInputElement(
        insertHTMLElement("<input id='sample'>", "sample"));

    input->setValue("hello");
    controller().setEditableSelectionOffsets(PlainTextRange(2, 2));
    EXPECT_STREQ("hello", input->value().utf8().data());
    EXPECT_EQ(2u, controller().getSelectionOffsets().start());
    EXPECT_EQ(2u, controller().getSelectionOffsets().end());

    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0));

    // The cursor exceeds left boundary.
    // "*heABllo", where * stands for cursor.
    controller().setComposition("AB", underlines, -100, -100);
    EXPECT_STREQ("heABllo", input->value().utf8().data());
    EXPECT_EQ(0u, controller().getSelectionOffsets().start());
    EXPECT_EQ(0u, controller().getSelectionOffsets().end());

    // The cursor is on left boundary.
    // "*heABllo".
    controller().setComposition("AB", underlines, -2, -2);
    EXPECT_STREQ("heABllo", input->value().utf8().data());
    EXPECT_EQ(0u, controller().getSelectionOffsets().start());
    EXPECT_EQ(0u, controller().getSelectionOffsets().end());

    // The cursor is before the composing text.
    // "he*ABllo".
    controller().setComposition("AB", underlines, 0, 0);
    EXPECT_STREQ("heABllo", input->value().utf8().data());
    EXPECT_EQ(2u, controller().getSelectionOffsets().start());
    EXPECT_EQ(2u, controller().getSelectionOffsets().end());

    // The cursor is after the composing text.
    // "heAB*llo".
    controller().setComposition("AB", underlines, 2, 2);
    EXPECT_STREQ("heABllo", input->value().utf8().data());
    EXPECT_EQ(4u, controller().getSelectionOffsets().start());
    EXPECT_EQ(4u, controller().getSelectionOffsets().end());

    // The cursor is on right boundary.
    // "heABllo*".
    controller().setComposition("AB", underlines, 5, 5);
    EXPECT_STREQ("heABllo", input->value().utf8().data());
    EXPECT_EQ(7u, controller().getSelectionOffsets().start());
    EXPECT_EQ(7u, controller().getSelectionOffsets().end());

    // The cursor exceeds right boundary.
    // "heABllo*".
    controller().setComposition("AB", underlines, 100, 100);
    EXPECT_STREQ("heABllo", input->value().utf8().data());
    EXPECT_EQ(7u, controller().getSelectionOffsets().start());
    EXPECT_EQ(7u, controller().getSelectionOffsets().end());
}
コード例 #4
0
TEST_F(InputMethodControllerTest, SetCompositionFromExistingTextWithInvalidOffsets)
{
    insertHTMLElement("<div id='sample' contenteditable='true'>test</div>", "sample");

    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(7, 8, Color(255, 0, 0), false, 0));
    controller().setCompositionFromExistingText(underlines, 7, 8);

    EXPECT_FALSE(controller().compositionRange());
}
コード例 #5
0
void WebViewInputMethodFilter::setPreedit(String newPreedit, int cursorOffset)
{
    Frame* frame = focusedOrMainFrame();
    if (!frame || !frame->editor().canEdit())
        return;

    // TODO: We should parse the PangoAttrList that we get from the IM context here.
    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, newPreedit.length(), Color(1, 1, 1), false));
    frame->editor().setComposition(newPreedit, underlines, m_cursorOffset, m_cursorOffset);
}
コード例 #6
0
TEST_F(InputMethodControllerTest, ConfirmPasswordComposition)
{
    HTMLInputElement* input = toHTMLInputElement(
        insertHTMLElement("<input id='sample' type='password' size='24'>", "sample"));

    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0));
    controller().setComposition("foo", underlines, 0, 3);
    controller().confirmComposition();

    EXPECT_STREQ("foo", input->value().utf8().data());
}
コード例 #7
0
TEST_F(InputMethodControllerTest, SelectionOnConfirmExistingText)
{
    insertHTMLElement(
        "<div id='sample' contenteditable='true'>hello world</div>", "sample");

    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0));
    controller().setCompositionFromExistingText(underlines, 0, 5);

    controller().confirmComposition();
    EXPECT_EQ(0, frame().selection().start().computeOffsetInContainerNode());
    EXPECT_EQ(0, frame().selection().end().computeOffsetInContainerNode());
}
コード例 #8
0
void InputMethodFilter::updatePreedit()
{
#if ENABLE(API_TESTS)
    if (m_testingMode) {
        logSetPreeditForTesting();
        return;
    }
#endif
    // FIXME: We should parse the PangoAttrList that we get from the IM context here.
    m_page->setComposition(m_preedit, Vector<CompositionUnderline>{ CompositionUnderline(0, m_preedit.length(), Color(1, 1, 1), false) },
        m_cursorOffset, m_cursorOffset, 0 /* replacement start */, 0 /* replacement end */);
    m_preeditChanged = false;
}
コード例 #9
0
static void imContextPreeditChanged(GtkIMContext* context, EditorClient* client)
{
    Frame* frame = core(static_cast<WebKitWebView*>(client->webView()))->focusController()->focusedOrMainFrame();
    if (!frame || !frame->editor()->canEdit())
        return;

    // We ignore the provided PangoAttrList for now.
    GOwnPtr<gchar> newPreedit(0);
    gtk_im_context_get_preedit_string(context, &newPreedit.outPtr(), 0, 0);

    String preeditString = String::fromUTF8(newPreedit.get());
    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
    frame->editor()->setComposition(preeditString, underlines, 0, 0);
}
コード例 #10
0
TEST_F(InputMethodControllerTest, SetCompositionFromExistingText)
{
    Element* div = insertHTMLElement(
        "<div id='sample' contenteditable='true'>hello world</div>", "sample");

    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0));
    controller().setCompositionFromExistingText(underlines, 0, 5);

    Range* range = controller().compositionRange();
    EXPECT_EQ(0, range->startOffset());
    EXPECT_EQ(5, range->endOffset());

    PlainTextRange plainTextRange(PlainTextRange::create(*div, *range));
    EXPECT_EQ(0u, plainTextRange.start());
    EXPECT_EQ(5u, plainTextRange.end());
}
コード例 #11
0
void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
{
    InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);

    if (!inputMethodContext->m_view->page()->focusedFrame() || !inputMethodContext->m_focused)
        return;

    char* buffer = 0;
    ecore_imf_context_preedit_string_get(context, &buffer, 0);
    if (!buffer)
        return;

    String preeditString = String::fromUTF8(buffer);
    free(buffer);
    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
    inputMethodContext->m_view->page()->setComposition(preeditString, underlines, 0);
}
コード例 #12
0
TEST_F(InputMethodControllerTest, SetCompositionFromExistingTextWithCollapsedWhiteSpace)
{
    // Creates a div with one leading new line char. The new line char is hidden
    // from the user and IME, but is visible to InputMethodController.
    Element* div = insertHTMLElement(
        "<div id='sample' contenteditable='true'>\nhello world</div>", "sample");

    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0));
    controller().setCompositionFromExistingText(underlines, 0, 5);

    Range* range = controller().compositionRange();
    EXPECT_EQ(1, range->startOffset());
    EXPECT_EQ(6, range->endOffset());

    PlainTextRange plainTextRange(PlainTextRange::create(*div, *range));
    EXPECT_EQ(0u, plainTextRange.start());
    EXPECT_EQ(5u, plainTextRange.end());
}
コード例 #13
0
static void imContextPreeditChanged(GtkIMContext* context, EditorClient* client)
{
    Frame* frame = core(client->m_webView)->focusController()->focusedOrMainFrame();
    Editor* editor = frame->editor();

    gchar* preedit = NULL;
    gint cursorPos = 0;
    // We ignore the provided PangoAttrList for now.
    gtk_im_context_get_preedit_string(context, &preedit, NULL, &cursorPos);
    String preeditString = String::fromUTF8(preedit);
    g_free(preedit);

    // setComposition() will replace the user selection if passed an empty
    // preedit. We don't want this to happen.
    if (preeditString.isEmpty() && !editor->hasComposition())
        return;

    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
    editor->setComposition(preeditString, underlines, cursorPos, 0);
}
コード例 #14
0
void InputMethodFilter::handleKeyboardEventWithCompositionResults(GdkEventKey* event, ResultsToSend resultsToSend, EventFakedForComposition faked)
{
#if ENABLE(API_TESTS)
    if (m_testingMode) {
        logHandleKeyboardEventWithCompositionResultsForTesting(event, resultsToSend, faked);
        return;
    }
#endif

    if (m_filterKeyEventCompletionHandler) {
        m_filterKeyEventCompletionHandler(CompositionResults(CompositionResults::WillSendCompositionResultsSoon), faked);
        m_filterKeyEventCompletionHandler = nullptr;
    } else
        m_page->handleKeyboardEvent(NativeWebKeyboardEvent(reinterpret_cast<GdkEvent*>(event), CompositionResults(CompositionResults::WillSendCompositionResultsSoon), faked, Vector<String>()));
    if (resultsToSend & Composition && !m_confirmedComposition.isNull())
        m_page->confirmComposition(m_confirmedComposition, -1, 0);

    if (resultsToSend & Preedit && !m_preedit.isNull()) {
        m_page->setComposition(m_preedit, Vector<CompositionUnderline>{ CompositionUnderline(0, m_preedit.length(), Color(1, 1, 1), false) },
            m_cursorOffset, m_cursorOffset, 0 /* replacement start */, 0 /* replacement end */);
    }
}
コード例 #15
0
TEST_F(InputMethodControllerTest, SetCompositionForContentEditableWithDifferentNewCursorPositions)
{
    // There are 7 nodes and 5+1+5+1+3+4+3 characters: "hello", '\n', "world", "\n", "012", "3456", "789".
    Element* div = insertHTMLElement(
        "<div id='sample' contenteditable='true'>"
        "hello"
        "<div id='sample2' contenteditable='true'>world"
        "<p>012<b>3456</b><i>789</i></p>"
        "</div>"
        "</div>",
        "sample");

    controller().setEditableSelectionOffsets(PlainTextRange(17, 17));
    EXPECT_STREQ("hello\nworld\n0123456789", div->innerText().utf8().data());
    EXPECT_EQ(17u, controller().getSelectionOffsets().start());
    EXPECT_EQ(17u, controller().getSelectionOffsets().end());

    Vector<CompositionUnderline> underlines;
    underlines.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0));

    // The cursor exceeds left boundary.
    // "*hello\nworld\n01234AB56789", where * stands for cursor.
    controller().setComposition("AB", underlines, -100, -100);
    EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data());
    EXPECT_EQ(0u, controller().getSelectionOffsets().start());
    EXPECT_EQ(0u, controller().getSelectionOffsets().end());

    // The cursor is on left boundary.
    // "*hello\nworld\n01234AB56789".
    controller().setComposition("AB", underlines, -17, -17);
    EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data());
    EXPECT_EQ(0u, controller().getSelectionOffsets().start());
    EXPECT_EQ(0u, controller().getSelectionOffsets().end());

    // The cursor is in the 1st node.
    // "he*llo\nworld\n01234AB56789".
    controller().setComposition("AB", underlines, -15, -15);
    EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data());
    EXPECT_EQ(2u, controller().getSelectionOffsets().start());
    EXPECT_EQ(2u, controller().getSelectionOffsets().end());

    // The cursor is on right boundary of the 1st node.
    // "hello*\nworld\n01234AB56789".
    controller().setComposition("AB", underlines, -12, -12);
    EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data());
    EXPECT_EQ(5u, controller().getSelectionOffsets().start());
    EXPECT_EQ(5u, controller().getSelectionOffsets().end());

    // The cursor is on right boundary of the 2nd node.
    // "hello\n*world\n01234AB56789".
    controller().setComposition("AB", underlines, -11, -11);
    EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data());
    EXPECT_EQ(6u, controller().getSelectionOffsets().start());
    EXPECT_EQ(6u, controller().getSelectionOffsets().end());

    // The cursor is on right boundary of the 3rd node.
    // "hello\nworld*\n01234AB56789".
    controller().setComposition("AB", underlines, -6, -6);
    EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data());
    EXPECT_EQ(11u, controller().getSelectionOffsets().start());
    EXPECT_EQ(11u, controller().getSelectionOffsets().end());

    // The cursor is on right boundary of the 4th node.
    // "hello\nworld\n*01234AB56789".
    controller().setComposition("AB", underlines, -5, -5);
    EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data());
    EXPECT_EQ(12u, controller().getSelectionOffsets().start());
    EXPECT_EQ(12u, controller().getSelectionOffsets().end());

    // The cursor is before the composing text.
    // "hello\nworld\n01234*AB56789".
    controller().setComposition("AB", underlines, 0, 0);
    EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data());
    EXPECT_EQ(17u, controller().getSelectionOffsets().start());
    EXPECT_EQ(17u, controller().getSelectionOffsets().end());

    // The cursor is after the composing text.
    // "hello\nworld\n01234AB*56789".
    controller().setComposition("AB", underlines, 2, 2);
    EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data());
    EXPECT_EQ(19u, controller().getSelectionOffsets().start());
    EXPECT_EQ(19u, controller().getSelectionOffsets().end());

    // The cursor is on right boundary.
    // "hello\nworld\n01234AB56789*".
    controller().setComposition("AB", underlines, 7, 7);
    EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data());
    EXPECT_EQ(24u, controller().getSelectionOffsets().start());
    EXPECT_EQ(24u, controller().getSelectionOffsets().end());

    // The cursor exceeds right boundary.
    // "hello\nworld\n01234AB56789*".
    controller().setComposition("AB", underlines, 100, 100);
    EXPECT_STREQ("hello\nworld\n01234AB56789", div->innerText().utf8().data());
    EXPECT_EQ(24u, controller().getSelectionOffsets().start());
    EXPECT_EQ(24u, controller().getSelectionOffsets().end());
}
コード例 #16
0
void QtWebPageEventHandler::handleInputMethodEvent(QInputMethodEvent* ev)
{
    QString commit = ev->commitString();
    QString composition = ev->preeditString();

    int replacementStart = ev->replacementStart();
    int replacementLength = ev->replacementLength();

    // NOTE: We might want to handle events of one char as special
    // and resend them as key events to make web site completion work.

    int cursorPositionWithinComposition = 0;

    Vector<CompositionUnderline> underlines;

    for (int i = 0; i < ev->attributes().size(); ++i) {
        const QInputMethodEvent::Attribute& attr = ev->attributes().at(i);
        switch (attr.type) {
        case QInputMethodEvent::TextFormat: {
            if (composition.isEmpty())
                break;

            QTextCharFormat textCharFormat = attr.value.value<QTextFormat>().toCharFormat();
            QColor qcolor = textCharFormat.underlineColor();
            Color color = makeRGBA(qcolor.red(), qcolor.green(), qcolor.blue(), qcolor.alpha());
            int start = qMin(attr.start, (attr.start + attr.length));
            int end = qMax(attr.start, (attr.start + attr.length));
            underlines.append(CompositionUnderline(start, end, color, false));
            break;
        }
        case QInputMethodEvent::Cursor:
            if (attr.length)
                cursorPositionWithinComposition = attr.start;
            break;
        // Selection is handled further down.
        default: break;
        }
    }

    if (composition.isEmpty()) {
        int selectionStart = -1;
        int selectionLength = 0;
        for (int i = 0; i < ev->attributes().size(); ++i) {
            const QInputMethodEvent::Attribute& attr = ev->attributes().at(i);
            if (attr.type == QInputMethodEvent::Selection) {
                selectionStart = attr.start;
                selectionLength = attr.length;

                ASSERT(selectionStart >= 0);
                ASSERT(selectionLength >= 0);
                break;
            }
        }

        m_webPageProxy->confirmComposition(commit, selectionStart, selectionLength);
    } else {
        ASSERT(cursorPositionWithinComposition >= 0);
        ASSERT(replacementStart >= 0);

        m_webPageProxy->setComposition(composition, underlines,
            cursorPositionWithinComposition, cursorPositionWithinComposition,
            replacementStart, replacementLength);
    }

    ev->accept();
}