bool InputMethodController::confirmCompositionOrInsertText(const String& text, ConfirmCompositionBehavior confirmBehavior)
{
    if (!hasComposition()) {
        if (!text.length())
            return false;
        editor().insertText(text, 0);
        return true;
    }

    if (text.length()) {
        confirmComposition(text);
        return true;
    }

    if (confirmBehavior == DoNotKeepSelection)
        return confirmComposition(composingText(), DoNotKeepSelection);

    SelectionOffsetsScope selectionOffsetsScope(this);
    return confirmComposition();
}
bool InputMethodController::confirmComposition(const String& text, ConfirmCompositionBehavior confirmBehavior)
{
    if (!hasComposition())
        return false;

    Optional<Editor::RevealSelectionScope> revealSelectionScope;
    if (confirmBehavior == KeepSelection)
        revealSelectionScope.emplace(&editor());

    // If the composition was set from existing text and didn't change, then
    // there's nothing to do here (and we should avoid doing anything as that
    // may clobber multi-node styled text).
    if (!m_isDirty && composingText() == text) {
        clear();
        return true;
    }

    // Select the text that will be deleted or replaced.
    selectComposition();

    if (frame().selection().isNone())
        return false;

    dispatchCompositionEndEvent(frame(), text);

    if (!frame().document())
        return false;

    // If text is empty, then delete the old composition here. If text is
    // non-empty, InsertTextCommand::input will delete the old composition with
    // an optimized replace operation.
    if (text.isEmpty())
        TypingCommand::deleteSelection(*frame().document(), 0);

    clear();

    insertTextForConfirmedComposition(text);

    return true;
}
bool InputMethodController::confirmComposition()
{
    return confirmComposition(composingText());
}