/*
 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"

#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatcher.h"
#include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/commands/typing_command.h"
#include "third_party/blink/renderer/core/editing/commands/undo_stack.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/editor.h"
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
#include "third_party/blink/renderer/core/editing/markers/suggestion_marker_properties.h"
#include "third_party/blink/renderer/core/editing/reveal_selection_scope.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/set_selection_options.h"
#include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
#include "third_party/blink/renderer/core/editing/state_machines/backward_code_point_state_machine.h"
#include "third_party/blink/renderer/core/editing/state_machines/forward_code_point_state_machine.h"
#include "third_party/blink/renderer/core/events/composition_event.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/input_mode_names.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"

namespace blink {

namespace {

void DispatchCompositionUpdateEvent(LocalFrame& frame, const String& text) {
  Element* target = frame.GetDocument()->FocusedElement();
  if (!target)
    return;

  CompositionEvent* event = CompositionEvent::Create(
      event_type_names::kCompositionupdate, frame.DomWindow(), text);
  target->DispatchEvent(*event);
}

void DispatchCompositionEndEvent(LocalFrame& frame, const String& text) {
  // Verify that the caller is using an EventQueueScope to suppress the input
  // event from being fired until the proper time (e.g. after applying an IME
  // selection update, if necesary).
  DCHECK(ScopedEventQueue::Instance()->ShouldQueueEvents());

  Element* target = frame.GetDocument()->FocusedElement();
  if (!target)
    return;

  CompositionEvent* event = CompositionEvent::Create(
      event_type_names::kCompositionend, frame.DomWindow(), text);
  EventDispatcher::DispatchScopedEvent(*target, *event);
}

bool NeedsIncrementalInsertion(const LocalFrame& frame,
                               const String& new_text) {
  // No need to apply incremental insertion if it doesn't support formated text.
  if (!frame.GetEditor().CanEditRichly())
    return false;

  // No need to apply incremental insertion if the old text (text to be
  // replaced) or the new text (text to be inserted) is empty.
  if (frame.SelectedText().IsEmpty() || new_text.IsEmpty())
    return false;

  return true;
}

void DispatchBeforeInputFromComposition(EventTarget* target,
                                        InputEvent::InputType input_type,
                                        const String& data) {
  if (!target)
    return;
  // TODO(editing-dev): Pass appropriate |ranges| after it's defined on spec.
  // http://w3c.github.io/editing/input-events.html#dom-inputevent-inputtype
  InputEvent* before_input_event = InputEvent::CreateBeforeInput(
      input_type, data, InputEvent::kNotCancelable,
      InputEvent::EventIsComposing::kIsComposing, nullptr);
  target->DispatchEvent(*before_input_event);
}

// Used to insert/replace text during composition update and confirm
// composition.
// Procedure:
//   1. Fire 'beforeinput' event for (TODO(editing-dev): deleted composed text)
//      and inserted text
//   2. Fire 'compositionupdate' event
//   3. Fire TextEvent and modify DOM
//   4. Fire 'input' event; dispatched by Editor::AppliedEditing()
void InsertTextDuringCompositionWithEvents(
    LocalFrame& frame,
    const String& text,
    TypingCommand::Options options,
    TypingCommand::TextCompositionType composition_type) {
  // Verify that the caller is using an EventQueueScope to suppress the input
  // event from being fired until the proper time (e.g. after applying an IME
  // selection update, if necesary).
  DCHECK(ScopedEventQueue::Instance()->ShouldQueueEvents());
  DCHECK(composition_type ==
             TypingCommand::TextCompositionType::kTextCompositionUpdate ||
         composition_type ==
             TypingCommand::TextCompositionType::kTextCompositionConfirm ||
         composition_type ==
             TypingCommand::TextCompositionType::kTextCompositionCancel)
      << "compositionType should be TextCompositionUpdate or "
         "TextCompositionConfirm  or TextCompositionCancel, but got "
      << static_cast<int>(composition_type);
  if (!frame.GetDocument())
    return;

  Element* target = frame.GetDocument()->FocusedElement();
  if (!target)
    return;

  DispatchBeforeInputFromComposition(
      target, InputEvent::InputType::kInsertCompositionText, text);

  // 'beforeinput' event handler may destroy document.
  if (!frame.GetDocument())
    return;

  DispatchCompositionUpdateEvent(frame, text);
  // 'compositionupdate' event handler may destroy document.
  if (!frame.GetDocument())
    return;

  // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
  // needs to be audited. see http://crbug.com/590369 for more details.
  frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();

  const bool is_incremental_insertion = NeedsIncrementalInsertion(frame, text);

  switch (composition_type) {
    case TypingCommand::TextCompositionType::kTextCompositionUpdate:
    case TypingCommand::TextCompositionType::kTextCompositionConfirm:
      // Calling |TypingCommand::insertText()| with empty text will result in an
      // incorrect ending selection. We need to delete selection first.
      // https://crbug.com/693481
      if (text.IsEmpty())
        TypingCommand::DeleteSelection(*frame.GetDocument(), 0);
      frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
      TypingCommand::InsertText(*frame.GetDocument(), text, options,
                                composition_type, is_incremental_insertion);
      break;
    case TypingCommand::TextCompositionType::kTextCompositionCancel:
      // TODO(editing-dev): Use TypingCommand::insertText after TextEvent was
      // removed. (Removed from spec since 2012)
      // See text_event.idl.
      frame.GetEventHandler().HandleTextInputEvent(text, nullptr,
                                                   kTextEventInputComposition);
      break;
    default:
      NOTREACHED();
  }
}

AtomicString GetInputModeAttribute(Element* element) {
  if (!element)
    return AtomicString();

  bool query_attribute = false;
  if (auto* input = ToHTMLInputElementOrNull(*element)) {
    query_attribute = input->SupportsInputModeAttribute();
  } else if (IsHTMLTextAreaElement(*element)) {
    query_attribute = true;
  } else {
    element->GetDocument().UpdateStyleAndLayoutTree();
    if (HasEditableStyle(*element))
      query_attribute = true;
  }

  if (!query_attribute)
    return AtomicString();

  // TODO(dtapuska): We may wish to restrict this to a yet to be proposed
  // <contenteditable> or <richtext> element Mozilla discussed at TPAC 2016.
  return element->FastGetAttribute(html_names::kInputmodeAttr).LowerASCII();
}

constexpr int kInvalidDeletionLength = -1;
constexpr bool IsInvalidDeletionLength(const int length) {
  return length == kInvalidDeletionLength;
}

int CalculateBeforeDeletionLengthsInCodePoints(
    const String& text,
    const int before_length_in_code_points,
    const int selection_start) {
  DCHECK_GE(before_length_in_code_points, 0);
  DCHECK_GE(selection_start, 0);
  DCHECK_LE(selection_start, static_cast<int>(text.length()));

  const UChar* u_text = text.Characters16();
  BackwardCodePointStateMachine backward_machine;
  int counter = before_length_in_code_points;
  int deletion_start = selection_start;
  while (counter > 0 && deletion_start > 0) {
    const TextSegmentationMachineState state =
        backward_machine.FeedPrecedingCodeUnit(u_text[deletion_start - 1]);
    // According to Android's InputConnection spec, we should do nothing if
    // |text| has invalid surrogate pair in the deletion range.
    if (state == TextSegmentationMachineState::kInvalid)
      return kInvalidDeletionLength;

    if (backward_machine.AtCodePointBoundary())
      --counter;
    --deletion_start;
  }
  if (!backward_machine.AtCodePointBoundary())
    return kInvalidDeletionLength;

  const int offset = backward_machine.GetBoundaryOffset();
  DCHECK_EQ(-offset, selection_start - deletion_start);
  return -offset;
}

int CalculateAfterDeletionLengthsInCodePoints(
    const String& text,
    const int after_length_in_code_points,
    const int selection_end) {
  DCHECK_GE(after_length_in_code_points, 0);
  DCHECK_GE(selection_end, 0);
  const int length = text.length();
  DCHECK_LE(selection_end, length);

  const UChar* u_text = text.Characters16();
  ForwardCodePointStateMachine forward_machine;
  int counter = after_length_in_code_points;
  int deletion_end = selection_end;
  while (counter > 0 && deletion_end < length) {
    const TextSegmentationMachineState state =
        forward_machine.FeedFollowingCodeUnit(u_text[deletion_end]);
    // According to Android's InputConnection spec, we should do nothing if
    // |text| has invalid surrogate pair in the deletion range.
    if (state == TextSegmentationMachineState::kInvalid)
      return kInvalidDeletionLength;

    if (forward_machine.AtCodePointBoundary())
      --counter;
    ++deletion_end;
  }
  if (!forward_machine.AtCodePointBoundary())
    return kInvalidDeletionLength;

  const int offset = forward_machine.GetBoundaryOffset();
  DCHECK_EQ(offset, deletion_end - selection_end);
  return offset;
}

Element* RootEditableElementOfSelection(const FrameSelection& frameSelection) {
  const SelectionInDOMTree& selection = frameSelection.GetSelectionInDOMTree();
  if (selection.IsNone())
    return nullptr;
  // To avoid update layout, we attempt to get root editable element from
  // a position where script/user specified.
  if (Element* editable = RootEditableElementOf(selection.Base()))
    return editable;

  // This is work around for applications assumes a position before editable
  // element as editable[1]
  // [1] http://crbug.com/712761

  // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets
  // needs to be audited. see http://crbug.com/590369 for more details.
  frameSelection.GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
  const VisibleSelection& visibleSeleciton =
      frameSelection.ComputeVisibleSelectionInDOMTree();
  return RootEditableElementOf(visibleSeleciton.Start());
}

std::pair<ContainerNode*, PlainTextRange> PlainTextRangeForEphemeralRange(
    const EphemeralRange& range) {
  if (range.IsNull())
    return {};
  ContainerNode* const editable =
      RootEditableElementOrTreeScopeRootNodeOf(range.StartPosition());
  DCHECK(editable);
  return std::make_pair(editable, PlainTextRange::Create(*editable, range));
}

int ComputeAutocapitalizeFlags(const Element* element) {
  const HTMLElement* const html_element = ToHTMLElementOrNull(element);
  if (!html_element)
    return 0;

  // We set the autocapitalization flag corresponding to the "used
  // autocapitalization hint" for the focused element:
  // https://html.spec.whatwg.org/multipage/interaction.html#used-autocapitalization-hint
  if (auto* input = ToHTMLInputElementOrNull(*html_element)) {
    const AtomicString& input_type = input->type();
    if (input_type == input_type_names::kEmail ||
        input_type == input_type_names::kUrl ||
        input_type == input_type_names::kPassword) {
      // The autocapitalize IDL attribute value is ignored for these input
      // types, so we set the None flag.
      return kWebTextInputFlagAutocapitalizeNone;
    }
  }

  int flags = 0;

  DEFINE_STATIC_LOCAL(const AtomicString, none, ("none"));
  DEFINE_STATIC_LOCAL(const AtomicString, characters, ("characters"));
  DEFINE_STATIC_LOCAL(const AtomicString, words, ("words"));
  DEFINE_STATIC_LOCAL(const AtomicString, sentences, ("sentences"));

  const AtomicString& autocapitalize = html_element->autocapitalize();
  if (autocapitalize == none) {
    flags |= kWebTextInputFlagAutocapitalizeNone;
  } else if (autocapitalize == characters) {
    flags |= kWebTextInputFlagAutocapitalizeCharacters;
  } else if (autocapitalize == words) {
    flags |= kWebTextInputFlagAutocapitalizeWords;
  } else if (autocapitalize == sentences || autocapitalize == "") {
    // Note: we tell the IME to enable autocapitalization for both the default
    // state ("") and the sentences states. We could potentially treat these
    // differently if we had a platform that supported autocapitalization but
    // didn't want to enable it unless explicitly requested by a web page, but
    // this so far has not been necessary.
    flags |= kWebTextInputFlagAutocapitalizeSentences;
  } else {
    NOTREACHED();
  }

  return flags;
}

}  // anonymous namespace

enum class InputMethodController::TypingContinuation { kContinue, kEnd };

InputMethodController* InputMethodController::Create(LocalFrame& frame) {
  return MakeGarbageCollected<InputMethodController>(frame);
}

InputMethodController::InputMethodController(LocalFrame& frame)
    : frame_(&frame), has_composition_(false) {}

InputMethodController::~InputMethodController() = default;

bool InputMethodController::IsAvailable() const {
  return LifecycleContext();
}

Document& InputMethodController::GetDocument() const {
  DCHECK(IsAvailable());
  return *LifecycleContext();
}

bool InputMethodController::HasComposition() const {
  return has_composition_ && !composition_range_->collapsed() &&
         composition_range_->IsConnected();
}

inline Editor& InputMethodController::GetEditor() const {
  return GetFrame().GetEditor();
}

void InputMethodController::Clear() {
  RemoveSuggestionMarkerInCompositionRange();

  has_composition_ = false;
  if (composition_range_) {
    composition_range_->setStart(&GetDocument(), 0);
    composition_range_->collapse(true);
  }
  GetDocument().Markers().RemoveMarkersOfTypes(
      DocumentMarker::MarkerTypes::Composition());
}

void InputMethodController::ContextDestroyed(Document*) {
  Clear();
  composition_range_ = nullptr;
}

void InputMethodController::DidAttachDocument(Document* document) {
  DCHECK(document);
  SetContext(document);
}

void InputMethodController::SelectComposition() const {
  const EphemeralRange range = CompositionEphemeralRange();
  if (range.IsNull())
    return;

  // The composition can start inside a composed character sequence, so we have
  // to override checks. See <http://bugs.webkit.org/show_bug.cgi?id=15781>

  // The SetSelectionOptions() parameter is necessary because without it,
  // FrameSelection::SetSelection() will actually call
  // SetShouldClearTypingStyle(true), which will cause problems applying
  // formatting during composition. See https://crbug.com/803278.
  GetFrame().Selection().SetSelection(
      SelectionInDOMTree::Builder().SetBaseAndExtent(range).Build(),
      SetSelectionOptions());
}

bool IsTextTooLongAt(const Position& position) {
  const Element* element = EnclosingTextControl(position);
  if (!element)
    return false;
  if (auto* input = ToHTMLInputElementOrNull(element))
    return input->TooLong();
  if (auto* textarea = ToHTMLTextAreaElementOrNull(element))
    return textarea->TooLong();
  return false;
}

bool InputMethodController::FinishComposingText(
    ConfirmCompositionBehavior confirm_behavior) {
  if (!HasComposition())
    return false;

  // If text is longer than maxlength, give input/textarea's handler a chance to
  // clamp the text by replacing the composition with the same value.
  const bool is_too_long = IsTextTooLongAt(composition_range_->StartPosition());

  // TODO(editing-dev): Use of UpdateStyleAndLayoutIgnorePendingStylesheets
  // needs to be audited. see http://crbug.com/590369 for more details.
  GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
  const String& composing = ComposingText();

  // Suppress input event (if we hit the is_too_long case) and compositionend
  // event until after we restore the original selection (to avoid clobbering a
  // selection update applied by an event handler).
  EventQueueScope scope;

  if (confirm_behavior == kKeepSelection) {
    // Do not dismiss handles even if we are moving selection, because we will
    // eventually move back to the old selection offsets.
    const bool is_handle_visible = GetFrame().Selection().IsHandleVisible();

    const PlainTextRange& old_offsets = GetSelectionOffsets();
    RevealSelectionScope reveal_selection_scope(GetFrame());

    if (is_too_long) {
      ignore_result(ReplaceComposition(ComposingText()));
    } else {
      Clear();
      DispatchCompositionEndEvent(GetFrame(), composing);
    }

    // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets
    // needs to be audited. see http://crbug.com/590369 for more details.
    GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();

    const EphemeralRange& old_selection_range =
        EphemeralRangeForOffsets(old_offsets);
    if (old_selection_range.IsNull())
      return false;
    const SelectionInDOMTree& selection =
        SelectionInDOMTree::Builder()
            .SetBaseAndExtent(old_selection_range)
            .Build();
    GetFrame().Selection().SetSelection(
        selection, SetSelectionOptions::Builder()
                       .SetShouldCloseTyping(true)
                       .SetShouldShowHandle(is_handle_visible)
                       .Build());
    return true;
  }

  PlainTextRange composition_range =
      PlainTextRangeForEphemeralRange(CompositionEphemeralRange()).second;
  if (composition_range.IsNull())
    return false;

  if (is_too_long) {
    // Don't move caret or dispatch compositionend event if
    // ReplaceComposition() fails.
    if (!ReplaceComposition(ComposingText()))
      return false;
  } else {
    Clear();
    DispatchCompositionEndEvent(GetFrame(), composing);
  }

  // Note: MoveCaret() occurs *before* the input and compositionend events are
  // dispatched, due to the use of ScopedEventQueue. This allows input and
  // compositionend event handlers to change the current selection without
  // it getting overwritten again.
  return MoveCaret(composition_range.End());
}

bool InputMethodController::CommitText(
    const String& text,
    const Vector<ImeTextSpan>& ime_text_spans,
    int relative_caret_position) {
  if (HasComposition()) {
    return ReplaceCompositionAndMoveCaret(text, relative_caret_position,
                                          ime_text_spans);
  }

  return InsertTextAndMoveCaret(text, relative_caret_position, ime_text_spans);
}

bool InputMethodController::ReplaceComposition(const String& text) {
  // Verify that the caller is using an EventQueueScope to suppress the input
  // event from being fired until the proper time (e.g. after applying an IME
  // selection update, if necesary).
  DCHECK(ScopedEventQueue::Instance()->ShouldQueueEvents());

  if (!HasComposition())
    return false;

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

  if (GetFrame()
          .Selection()
          .ComputeVisibleSelectionInDOMTreeDeprecated()
          .IsNone())
    return false;

  if (!IsAvailable())
    return false;

  Clear();

  InsertTextDuringCompositionWithEvents(
      GetFrame(), text, 0,
      TypingCommand::TextCompositionType::kTextCompositionConfirm);

  // textInput event handler might destroy document (input event is queued
  // until later).
  if (!IsAvailable())
    return false;

  // No DOM update after 'compositionend'.
  DispatchCompositionEndEvent(GetFrame(), text);

  return true;
}

// relativeCaretPosition is relative to the end of the text.
static int ComputeAbsoluteCaretPosition(int text_start,
                                        int text_length,
                                        int relative_caret_position) {
  return text_start + text_length + relative_caret_position;
}

void InputMethodController::AddImeTextSpans(
    const Vector<ImeTextSpan>& ime_text_spans,
    ContainerNode* base_element,
    unsigned offset_in_plain_chars) {
  for (const auto& ime_text_span : ime_text_spans) {
    unsigned ime_text_span_start =
        offset_in_plain_chars + ime_text_span.StartOffset();
    unsigned ime_text_span_end =
        offset_in_plain_chars + ime_text_span.EndOffset();

    EphemeralRange ephemeral_line_range =
        PlainTextRange(ime_text_span_start, ime_text_span_end)
            .CreateRange(*base_element);
    if (ephemeral_line_range.IsNull())
      continue;

    switch (ime_text_span.GetType()) {
      case ImeTextSpan::Type::kComposition:
        GetDocument().Markers().AddCompositionMarker(
            ephemeral_line_range, ime_text_span.UnderlineColor(),
            ime_text_span.Thickness(), ime_text_span.BackgroundColor());
        break;
      case ImeTextSpan::Type::kSuggestion:
      case ImeTextSpan::Type::kMisspellingSuggestion:
        const SuggestionMarker::SuggestionType suggestion_type =
            ime_text_span.GetType() == ImeTextSpan::Type::kMisspellingSuggestion
                ? SuggestionMarker::SuggestionType::kMisspelling
                : SuggestionMarker::SuggestionType::kNotMisspelling;

        // If spell-checking is disabled for an element, we ignore suggestion
        // markers used to mark misspelled words, but allow other ones (e.g.,
        // markers added by an IME to allow picking between multiple possible
        // words, none of which is necessarily misspelled).
        if (suggestion_type == SuggestionMarker::SuggestionType::kMisspelling &&
            !SpellChecker::IsSpellCheckingEnabledAt(
                ephemeral_line_range.StartPosition()))
          continue;

        GetDocument().Markers().AddSuggestionMarker(
            ephemeral_line_range,
            SuggestionMarkerProperties::Builder()
                .SetType(suggestion_type)
                .SetSuggestions(ime_text_span.Suggestions())
                .SetHighlightColor(ime_text_span.SuggestionHighlightColor())
                .SetUnderlineColor(ime_text_span.UnderlineColor())
                .SetThickness(ime_text_span.Thickness())
                .SetBackgroundColor(ime_text_span.BackgroundColor())
                .SetRemoveOnFinishComposing(
                    ime_text_span.NeedsRemovalOnFinishComposing())
                .Build());
        break;
    }
  }
}

bool InputMethodController::ReplaceCompositionAndMoveCaret(
    const String& text,
    int relative_caret_position,
    const Vector<ImeTextSpan>& ime_text_spans) {
  Element* root_editable_element =
      GetFrame()
          .Selection()
          .ComputeVisibleSelectionInDOMTreeDeprecated()
          .RootEditableElement();
  if (!root_editable_element)
    return false;
  DCHECK(HasComposition());
  PlainTextRange composition_range =
      PlainTextRange::Create(*root_editable_element, *composition_range_);
  if (composition_range.IsNull())
    return false;
  int text_start = composition_range.Start();

  // Suppress input and compositionend events until after we move the caret to
  // the new position.
  EventQueueScope scope;
  if (!ReplaceComposition(text))
    return false;

  // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
  // needs to be audited. see http://crbug.com/590369 for more details.
  GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();

  AddImeTextSpans(ime_text_spans, root_editable_element, text_start);

  int absolute_caret_position = ComputeAbsoluteCaretPosition(
      text_start, text.length(), relative_caret_position);
  return MoveCaret(absolute_caret_position);
}

bool InputMethodController::InsertText(const String& text) {
  if (DispatchBeforeInputInsertText(GetDocument().FocusedElement(), text) !=
      DispatchEventResult::kNotCanceled)
    return false;
  GetEditor().InsertText(text, nullptr);
  return true;
}

bool InputMethodController::InsertTextAndMoveCaret(
    const String& text,
    int relative_caret_position,
    const Vector<ImeTextSpan>& ime_text_spans) {
  PlainTextRange selection_range = GetSelectionOffsets();
  if (selection_range.IsNull())
    return false;
  int text_start = selection_range.Start();

  // Suppress input event until after we move the caret to the new position.
  EventQueueScope scope;

  // Don't fire events for a no-op operation.
  if (!text.IsEmpty() || selection_range.length() > 0) {
    if (!InsertText(text))
      return false;
  }

  Element* root_editable_element =
      GetFrame()
          .Selection()
          .ComputeVisibleSelectionInDOMTreeDeprecated()
          .RootEditableElement();
  if (root_editable_element) {
    AddImeTextSpans(ime_text_spans, root_editable_element, text_start);
  }

  int absolute_caret_position = ComputeAbsoluteCaretPosition(
      text_start, text.length(), relative_caret_position);
  return MoveCaret(absolute_caret_position);
}

void InputMethodController::CancelComposition() {
  if (!HasComposition())
    return;

  RevealSelectionScope reveal_selection_scope(GetFrame());

  if (GetFrame()
          .Selection()
          .ComputeVisibleSelectionInDOMTreeDeprecated()
          .IsNone())
    return;

  Clear();

  InsertTextDuringCompositionWithEvents(
      GetFrame(), g_empty_string, 0,
      TypingCommand::TextCompositionType::kTextCompositionCancel);
  // Event handler might destroy document.
  if (!IsAvailable())
    return;

  // An open typing command that disagrees about current selection would cause
  // issues with typing later on.
  TypingCommand::CloseTyping(frame_);

  // No DOM update after 'compositionend'.
  DispatchCompositionEndEvent(GetFrame(), g_empty_string);
}

bool InputMethodController::DispatchCompositionStartEvent(const String& text) {
  Element* target = GetDocument().FocusedElement();
  if (!target)
    return IsAvailable();

  CompositionEvent* event = CompositionEvent::Create(
      event_type_names::kCompositionstart, GetFrame().DomWindow(), text);
  target->DispatchEvent(*event);

  return IsAvailable();
}

void InputMethodController::SetComposition(
    const String& text,
    const Vector<ImeTextSpan>& ime_text_spans,
    int selection_start,
    int selection_end) {
  RevealSelectionScope reveal_selection_scope(GetFrame());

  // Updates styles before setting selection for composition to prevent
  // inserting the previous composition text into text nodes oddly.
  // See https://bugs.webkit.org/show_bug.cgi?id=46868
  GetDocument().UpdateStyleAndLayoutTree();

  SelectComposition();

  if (GetFrame()
          .Selection()
          .ComputeVisibleSelectionInDOMTreeDeprecated()
          .IsNone())
    return;

  Element* target = GetDocument().FocusedElement();
  if (!target)
    return;

  // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
  // needs to be audited. see http://crbug.com/590369 for more details.
  GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();

  PlainTextRange selected_range = CreateSelectionRangeForSetComposition(
      selection_start, selection_end, text.length());

  // Dispatch an appropriate composition event to the focused node.
  // We check the composition status and choose an appropriate composition event
  // since this function is used for three purposes:
  // 1. Starting a new composition.
  //    Send a compositionstart and a compositionupdate event when this function
  //    creates a new composition node, i.e. !hasComposition() &&
  //    !text.isEmpty().
  //    Sending a compositionupdate event at this time ensures that at least one
  //    compositionupdate event is dispatched.
  // 2. Updating the existing composition node.
  //    Send a compositionupdate event when this function updates the existing
  //    composition node, i.e. hasComposition() && !text.isEmpty().
  // 3. Canceling the ongoing composition.
  //    Send a compositionend event when function deletes the existing
  //    composition node, i.e. !hasComposition() && test.isEmpty().
  if (text.IsEmpty()) {
    // Suppress input and compositionend events until after we move the caret
    // to the new position.
    EventQueueScope scope;
    if (HasComposition()) {
      RevealSelectionScope reveal_selection_scope(GetFrame());
      // Do not attempt to apply IME selection offsets if ReplaceComposition()
      // fails (we compute the new range assuming the replacement will succeed).
      if (!ReplaceComposition(g_empty_string))
        return;
    } else {
      // It's weird to call |setComposition()| with empty text outside
      // composition, however some IME (e.g. Japanese IBus-Anthy) did this, so
      // we simply delete selection without sending extra events.
      if (!DeleteSelection())
        return;
    }

    // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets
    // needs to be audited. see http://crbug.com/590369 for more details.
    GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();

    SetEditableSelectionOffsets(selected_range);
    return;
  }

  // We should send a 'compositionstart' event only when the given text is not
  // empty because this function doesn't create a composition node when the text
  // is empty.
  if (!HasComposition() &&
      !DispatchCompositionStartEvent(GetFrame().SelectedText())) {
    return;
  }

  DCHECK(!text.IsEmpty());

  Clear();

  // Suppress input event until after we move the caret to the new position.
  EventQueueScope scope;
  InsertTextDuringCompositionWithEvents(GetFrame(), text,
                                        TypingCommand::kSelectInsertedText,
                                        TypingCommand::kTextCompositionUpdate);
  // Event handlers might destroy document.
  if (!IsAvailable())
    return;

  // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
  // needs to be audited. see http://crbug.com/590369 for more details.
  GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();

  // The undo stack could become empty if a JavaScript event handler calls
  // execCommand('undo') to pop elements off the stack. Or, the top element of
  // the stack could end up not corresponding to the TypingCommand. Make sure we
  // don't crash in these cases (it's unclear what the composition range should
  // be set to in these cases, so we don't worry too much about that).
  SelectionInDOMTree selection;
  if (GetEditor().GetUndoStack().CanUndo()) {
    const UndoStep* undo_step = *GetEditor().GetUndoStack().UndoSteps().begin();
    const SelectionForUndoStep& undo_selection = undo_step->EndingSelection();
    if (undo_selection.IsValidFor(GetDocument()))
      selection = undo_selection.AsSelection();
  }

  // Find out what node has the composition now.
  const Position base =
      MostForwardCaretPosition(selection.Base(), kCanSkipOverEditingBoundary);
  Node* base_node = base.AnchorNode();
  if (!base_node || !base_node->IsTextNode())
    return;

  const Position extent = selection.Extent();
  Node* extent_node = extent.AnchorNode();

  unsigned extent_offset = extent.ComputeOffsetInContainerNode();
  unsigned base_offset = base.ComputeOffsetInContainerNode();

  has_composition_ = true;
  if (!composition_range_)
    composition_range_ = Range::Create(GetDocument());
  composition_range_->setStart(base_node, base_offset);
  composition_range_->setEnd(extent_node, extent_offset);

  if (base_node->GetLayoutObject())
    base_node->GetLayoutObject()->SetShouldDoFullPaintInvalidation();

  // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
  // needs to be audited. see http://crbug.com/590369 for more details.
  GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();

  // We shouldn't close typing in the middle of setComposition.
  SetEditableSelectionOffsets(selected_range, TypingContinuation::kContinue);

  if (TypingCommand* const last_typing_command =
          TypingCommand::LastTypingCommandIfStillOpenForTyping(&GetFrame())) {
    // When we called InsertTextDuringCompositionWithEvents() with the
    // kSelectInsertedText flag, it set what is now the composition range as the
    // ending selection on the open TypingCommand. We now update it to the
    // current selection to fix two problems:
    //
    // 1. Certain operations, e.g. pressing enter on a physical keyboard on
    // Android, would otherwise incorrectly replace the composition range.
    //
    // 2. Using undo would cause text to be selected, even though we never
    // actually showed the selection to the user.
    TypingCommand::UpdateSelectionIfDifferentFromCurrentSelection(
        last_typing_command, &GetFrame());
  }

  // Even though we would've returned already if SetComposition() were called
  // with an empty string, the composition range could still be empty right now
  // due to Unicode grapheme cluster position normalization (e.g. if
  // SetComposition() were passed an extending character which doesn't allow a
  // grapheme cluster break immediately before.
  if (!HasComposition())
    return;

  if (ime_text_spans.IsEmpty()) {
    GetDocument().Markers().AddCompositionMarker(
        CompositionEphemeralRange(), Color::kTransparent,
        ws::mojom::ImeTextSpanThickness::kThin,
        LayoutTheme::GetTheme().PlatformDefaultCompositionBackgroundColor());
    return;
  }

  const std::pair<ContainerNode*, PlainTextRange>&
      root_element_and_plain_text_range =
          PlainTextRangeForEphemeralRange(CompositionEphemeralRange());
  AddImeTextSpans(ime_text_spans, root_element_and_plain_text_range.first,
                  root_element_and_plain_text_range.second.Start());
}

PlainTextRange InputMethodController::CreateSelectionRangeForSetComposition(
    int selection_start,
    int selection_end,
    size_t text_length) const {
  const int selection_offsets_start =
      static_cast<int>(GetSelectionOffsets().Start());
  const int start = selection_offsets_start + selection_start;
  const int end = selection_offsets_start + selection_end;
  return CreateRangeForSelection(start, end, text_length);
}

void InputMethodController::SetCompositionFromExistingText(
    const Vector<ImeTextSpan>& ime_text_spans,
    unsigned composition_start,
    unsigned composition_end) {
  Element* target = GetDocument().FocusedElement();
  if (!target)
    return;

  if (!HasComposition() && !DispatchCompositionStartEvent(""))
    return;

  Element* editable = GetFrame()
                          .Selection()
                          .ComputeVisibleSelectionInDOMTreeDeprecated()
                          .RootEditableElement();
  if (!editable)
    return;

  DCHECK(!GetDocument().NeedsLayoutTreeUpdate());

  const EphemeralRange range =
      PlainTextRange(composition_start, composition_end).CreateRange(*editable);
  if (range.IsNull())
    return;

  const Position start = range.StartPosition();
  if (RootEditableElementOf(start) != editable)
    return;

  const Position end = range.EndPosition();
  if (RootEditableElementOf(end) != editable)
    return;

  Clear();

  AddImeTextSpans(ime_text_spans, editable, composition_start);

  has_composition_ = true;
  if (!composition_range_)
    composition_range_ = Range::Create(GetDocument());
  composition_range_->setStart(range.StartPosition());
  composition_range_->setEnd(range.EndPosition());

  DispatchCompositionUpdateEvent(GetFrame(), ComposingText());
}

EphemeralRange InputMethodController::CompositionEphemeralRange() const {
  if (!HasComposition())
    return EphemeralRange();
  return EphemeralRange(composition_range_.Get());
}

String InputMethodController::ComposingText() const {
  DocumentLifecycle::DisallowTransitionScope disallow_transition(
      GetDocument().Lifecycle());
  return PlainText(
      CompositionEphemeralRange(),
      TextIteratorBehavior::Builder().SetEmitsOriginalText(true).Build());
}

PlainTextRange InputMethodController::GetSelectionOffsets() const {
  EphemeralRange range = FirstEphemeralRangeOf(
      GetFrame().Selection().ComputeVisibleSelectionInDOMTreeDeprecated());
  return PlainTextRangeForEphemeralRange(range).second;
}

EphemeralRange InputMethodController::EphemeralRangeForOffsets(
    const PlainTextRange& offsets) const {
  if (offsets.IsNull())
    return EphemeralRange();
  Element* root_editable_element =
      GetFrame()
          .Selection()
          .ComputeVisibleSelectionInDOMTreeDeprecated()
          .RootEditableElement();
  if (!root_editable_element)
    return EphemeralRange();

  DCHECK(!GetDocument().NeedsLayoutTreeUpdate());

  return offsets.CreateRange(*root_editable_element);
}

bool InputMethodController::SetSelectionOffsets(
    const PlainTextRange& selection_offsets) {
  return SetSelectionOffsets(selection_offsets, TypingContinuation::kEnd);
}

bool InputMethodController::SetSelectionOffsets(
    const PlainTextRange& selection_offsets,
    TypingContinuation typing_continuation) {
  const EphemeralRange range = EphemeralRangeForOffsets(selection_offsets);
  if (range.IsNull())
    return false;

  GetFrame().Selection().SetSelection(
      SelectionInDOMTree::Builder().SetBaseAndExtent(range).Build(),
      SetSelectionOptions::Builder()
          .SetShouldCloseTyping(typing_continuation == TypingContinuation::kEnd)
          .Build());
  return true;
}

bool InputMethodController::SetEditableSelectionOffsets(
    const PlainTextRange& selection_offsets) {
  return SetEditableSelectionOffsets(selection_offsets,
                                     TypingContinuation::kEnd);
}

bool InputMethodController::SetEditableSelectionOffsets(
    const PlainTextRange& selection_offsets,
    TypingContinuation typing_continuation) {
  if (!GetEditor().CanEdit())
    return false;
  return SetSelectionOffsets(selection_offsets, typing_continuation);
}

void InputMethodController::RemoveSuggestionMarkerInCompositionRange() {
  if (HasComposition()) {
    GetDocument().Markers().RemoveSuggestionMarkerInRangeOnFinish(
        EphemeralRangeInFlatTree(composition_range_.Get()));
  }
}

PlainTextRange InputMethodController::CreateRangeForSelection(
    int start,
    int end,
    size_t text_length) const {
  // In case of exceeding the left boundary.
  start = std::max(start, 0);
  end = std::max(end, start);

  Element* root_editable_element =
      GetFrame()
          .Selection()
          .ComputeVisibleSelectionInDOMTreeDeprecated()
          .RootEditableElement();
  if (!root_editable_element)
    return PlainTextRange();
  const EphemeralRange& range =
      EphemeralRange::RangeOfContents(*root_editable_element);
  if (range.IsNull())
    return PlainTextRange();

  const TextIteratorBehavior& behavior =
      TextIteratorBehavior::Builder()
          .SetEmitsObjectReplacementCharacter(true)
          .SetEmitsCharactersBetweenAllVisiblePositions(true)
          .Build();
  TextIterator it(range.StartPosition(), range.EndPosition(), behavior);

  int right_boundary = 0;
  for (; !it.AtEnd(); it.Advance())
    right_boundary += it.length();

  if (HasComposition())
    right_boundary -= composition_range_->GetText().length();

  right_boundary += text_length;

  // In case of exceeding the right boundary.
  start = std::min(start, right_boundary);
  end = std::min(end, right_boundary);

  return PlainTextRange(start, end);
}

bool InputMethodController::DeleteSelection() {
  if (!GetFrame().Selection().ComputeVisibleSelectionInDOMTree().IsRange())
    return true;

  Node* target = GetFrame().GetDocument()->FocusedElement();
  if (target) {
    DispatchBeforeInputEditorCommand(
        target, InputEvent::InputType::kDeleteContentBackward,
        TargetRangesForInputEvent(*target));

    // Frame could have been destroyed by the beforeinput event.
    if (!IsAvailable())
      return false;
  }

  TypingCommand::DeleteSelection(GetDocument());

  // Frame could have been destroyed by the input event.
  return IsAvailable();
}

bool InputMethodController::MoveCaret(int new_caret_position) {
  GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
  PlainTextRange selected_range =
      CreateRangeForSelection(new_caret_position, new_caret_position, 0);
  if (selected_range.IsNull())
    return false;
  return SetEditableSelectionOffsets(selected_range);
}

void InputMethodController::ExtendSelectionAndDelete(int before, int after) {
  if (!GetEditor().CanEdit())
    return;
  PlainTextRange selection_offsets(GetSelectionOffsets());
  if (selection_offsets.IsNull())
    return;

  // A common call of before=1 and after=0 will fail if the last character
  // is multi-code-word UTF-16, including both multi-16bit code-points and
  // Unicode combining character sequences of multiple single-16bit code-
  // points (officially called "compositions"). Try more until success.
  // http://crbug.com/355995
  //
  // FIXME: Note that this is not an ideal solution when this function is
  // called to implement "backspace". In that case, there should be some call
  // that will not delete a full multi-code-point composition but rather
  // only the last code-point so that it's possible for a user to correct
  // a composition without starting it from the beginning.
  // http://crbug.com/37993
  do {
    if (!SetSelectionOffsets(PlainTextRange(
            std::max(static_cast<int>(selection_offsets.Start()) - before, 0),
            selection_offsets.End() + after)))
      return;
    if (before == 0)
      break;
    ++before;
  } while (GetFrame()
                   .Selection()
                   .ComputeVisibleSelectionInDOMTreeDeprecated()
                   .Start() == GetFrame()
                                   .Selection()
                                   .ComputeVisibleSelectionInDOMTreeDeprecated()
                                   .End() &&
           before <= static_cast<int>(selection_offsets.Start()));
  // TODO(editing-dev): Find a way to distinguish Forward and Backward.
  ignore_result(DeleteSelection());
}

// TODO(yabinh): We should reduce the number of selectionchange events.
void InputMethodController::DeleteSurroundingText(int before, int after) {
  if (!GetEditor().CanEdit())
    return;
  const PlainTextRange selection_offsets(GetSelectionOffsets());
  if (selection_offsets.IsNull())
    return;
  Element* const root_editable_element =
      GetFrame()
          .Selection()
          .ComputeVisibleSelectionInDOMTreeDeprecated()
          .RootEditableElement();
  if (!root_editable_element)
    return;
  int selection_start = static_cast<int>(selection_offsets.Start());
  int selection_end = static_cast<int>(selection_offsets.End());

  // Select the text to be deleted before SelectionState::kStart.
  if (before > 0 && selection_start > 0) {
    // In case of exceeding the left boundary.
    const int start = std::max(selection_start - before, 0);

    const EphemeralRange& range =
        PlainTextRange(0, start).CreateRange(*root_editable_element);
    if (range.IsNull())
      return;
    const Position& position = range.EndPosition();

    // Adjust the start of selection for multi-code text(a grapheme cluster
    // contains more than one code point). TODO(yabinh): Adjustment should be
    // based on code point instead of grapheme cluster.
    const size_t diff = ComputeDistanceToLeftGraphemeBoundary(position);
    const int adjusted_start = start - static_cast<int>(diff);
    if (!SetSelectionOffsets(PlainTextRange(adjusted_start, selection_start)))
      return;
    if (!DeleteSelection())
      return;

    selection_end = selection_end - (selection_start - adjusted_start);
    selection_start = adjusted_start;
  }

  // Select the text to be deleted after SelectionState::kEnd.
  if (after > 0) {
    // Adjust the deleted range in case of exceeding the right boundary.
    const PlainTextRange range(0, selection_end + after);
    if (range.IsNull())
      return;
    const EphemeralRange& valid_range =
        range.CreateRange(*root_editable_element);
    if (valid_range.IsNull())
      return;
    const int end =
        PlainTextRange::Create(*root_editable_element, valid_range).End();
    const Position& position = valid_range.EndPosition();

    // Adjust the end of selection for multi-code text. TODO(yabinh): Adjustment
    // should be based on code point instead of grapheme cluster.
    const size_t diff = ComputeDistanceToRightGraphemeBoundary(position);
    const int adjusted_end = end + static_cast<int>(diff);
    if (!SetSelectionOffsets(PlainTextRange(selection_end, adjusted_end)))
      return;
    if (!DeleteSelection())
      return;
  }

  SetSelectionOffsets(PlainTextRange(selection_start, selection_end));
}

void InputMethodController::DeleteSurroundingTextInCodePoints(int before,
                                                              int after) {
  DCHECK_GE(before, 0);
  DCHECK_GE(after, 0);
  if (!GetEditor().CanEdit())
    return;
  const PlainTextRange selection_offsets(GetSelectionOffsets());
  if (selection_offsets.IsNull())
    return;
  Element* const root_editable_element =
      GetFrame().Selection().RootEditableElementOrDocumentElement();
  if (!root_editable_element)
    return;

  const TextIteratorBehavior& behavior =
      TextIteratorBehavior::Builder()
          .SetEmitsObjectReplacementCharacter(true)
          .Build();
  const String& text = PlainText(
      EphemeralRange::RangeOfContents(*root_editable_element), behavior);

  // 8-bit characters are Latin-1 characters, so the deletion lengths are
  // trivial.
  if (text.Is8Bit())
    return DeleteSurroundingText(before, after);

  const int selection_start = static_cast<int>(selection_offsets.Start());
  const int selection_end = static_cast<int>(selection_offsets.End());

  const int before_length =
      CalculateBeforeDeletionLengthsInCodePoints(text, before, selection_start);
  if (IsInvalidDeletionLength(before_length))
    return;
  const int after_length =
      CalculateAfterDeletionLengthsInCodePoints(text, after, selection_end);
  if (IsInvalidDeletionLength(after_length))
    return;

  return DeleteSurroundingText(before_length, after_length);
}

WebTextInputInfo InputMethodController::TextInputInfo() const {
  WebTextInputInfo info;
  if (!IsAvailable())
    return info;

  if (!GetFrame().Selection().IsAvailable()) {
    // plugins/mouse-capture-inside-shadow.html reaches here.
    return info;
  }
  Element* element = RootEditableElementOfSelection(GetFrame().Selection());
  if (!element)
    return info;

  info.input_mode = InputModeOfFocusedElement();
  info.type = TextInputType();
  info.flags = TextInputFlags();
  if (info.type == kWebTextInputTypeNone)
    return info;

  if (!GetFrame().GetEditor().CanEdit())
    return info;

  // TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
  // needs to be audited.  see http://crbug.com/590369 for more details.
  GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();

  DocumentLifecycle::DisallowTransitionScope disallow_transition(
      GetDocument().Lifecycle());

  // Emits an object replacement character for each replaced element so that
  // it is exposed to IME and thus could be deleted by IME on android.
  info.value = PlainText(EphemeralRange::RangeOfContents(*element),
                         TextIteratorBehavior::Builder()
                             .SetEmitsObjectReplacementCharacter(true)
                             .SetEmitsSpaceForNbsp(true)
                             .Build());

  if (info.value.IsEmpty())
    return info;

  EphemeralRange first_range = FirstEphemeralRangeOf(
      GetFrame().Selection().ComputeVisibleSelectionInDOMTreeDeprecated());
  PlainTextRange selection_plain_text_range =
      PlainTextRangeForEphemeralRange(first_range).second;
  if (selection_plain_text_range.IsNotNull()) {
    info.selection_start = selection_plain_text_range.Start();
    info.selection_end = selection_plain_text_range.End();
  }

  EphemeralRange range = CompositionEphemeralRange();
  PlainTextRange composition_plain_text_range =
      PlainTextRangeForEphemeralRange(range).second;
  if (composition_plain_text_range.IsNotNull()) {
    info.composition_start = composition_plain_text_range.Start();
    info.composition_end = composition_plain_text_range.End();
  }

  return info;
}

int InputMethodController::TextInputFlags() const {
  Element* element = GetDocument().FocusedElement();
  if (!element)
    return kWebTextInputFlagNone;

  int flags = 0;

  const AtomicString& autocomplete =
      element->getAttribute(html_names::kAutocompleteAttr);
  if (autocomplete == "on")
    flags |= kWebTextInputFlagAutocompleteOn;
  else if (autocomplete == "off")
    flags |= kWebTextInputFlagAutocompleteOff;

  const AtomicString& autocorrect =
      element->getAttribute(html_names::kAutocorrectAttr);
  if (autocorrect == "on")
    flags |= kWebTextInputFlagAutocorrectOn;
  else if (autocorrect == "off")
    flags |= kWebTextInputFlagAutocorrectOff;

  SpellcheckAttributeState spellcheck = element->GetSpellcheckAttributeState();
  if (spellcheck == kSpellcheckAttributeTrue)
    flags |= kWebTextInputFlagSpellcheckOn;
  else if (spellcheck == kSpellcheckAttributeFalse)
    flags |= kWebTextInputFlagSpellcheckOff;

  flags |= ComputeAutocapitalizeFlags(element);

  if (HTMLInputElement* input = ToHTMLInputElementOrNull(element)) {
    if (input->HasBeenPasswordField())
      flags |= kWebTextInputFlagHasBeenPasswordField;
  }

  return flags;
}

int InputMethodController::ComputeWebTextInputNextPreviousFlags() const {
  if (!IsAvailable())
    return kWebTextInputFlagNone;

  Element* const element = GetDocument().FocusedElement();
  if (!element)
    return kWebTextInputFlagNone;

  Page* page = GetDocument().GetPage();
  if (!page)
    return kWebTextInputFlagNone;

  int flags = kWebTextInputFlagNone;
  if (page->GetFocusController().NextFocusableElementInForm(
          element, kWebFocusTypeForward))
    flags |= kWebTextInputFlagHaveNextFocusableElement;

  if (page->GetFocusController().NextFocusableElementInForm(
          element, kWebFocusTypeBackward))
    flags |= kWebTextInputFlagHavePreviousFocusableElement;

  return flags;
}

WebTextInputMode InputMethodController::InputModeOfFocusedElement() const {
  AtomicString mode = GetInputModeAttribute(GetDocument().FocusedElement());

  if (mode.IsEmpty())
    return kWebTextInputModeDefault;
  if (mode == input_mode_names::kNone)
    return kWebTextInputModeNone;
  if (mode == input_mode_names::kText)
    return kWebTextInputModeText;
  if (mode == input_mode_names::kTel)
    return kWebTextInputModeTel;
  if (mode == input_mode_names::kUrl)
    return kWebTextInputModeUrl;
  if (mode == input_mode_names::kEmail)
    return kWebTextInputModeEmail;
  if (mode == input_mode_names::kNumeric)
    return kWebTextInputModeNumeric;
  if (mode == input_mode_names::kDecimal)
    return kWebTextInputModeDecimal;
  if (mode == input_mode_names::kSearch)
    return kWebTextInputModeSearch;
  return kWebTextInputModeDefault;
}

WebTextInputType InputMethodController::TextInputType() const {
  if (!GetFrame().Selection().IsAvailable()) {
    // "mouse-capture-inside-shadow.html" reaches here.
    return kWebTextInputTypeNone;
  }

  // It's important to preserve the equivalence of textInputInfo().type and
  // textInputType(), so perform the same rootEditableElement() existence check
  // here for consistency.
  if (!RootEditableElementOfSelection(GetFrame().Selection()))
    return kWebTextInputTypeNone;

  if (!IsAvailable())
    return kWebTextInputTypeNone;

  Element* element = GetDocument().FocusedElement();
  if (!element)
    return kWebTextInputTypeNone;

  if (auto* input = ToHTMLInputElementOrNull(*element)) {
    const AtomicString& type = input->type();

    if (input->IsDisabledOrReadOnly())
      return kWebTextInputTypeNone;

    if (type == input_type_names::kPassword)
      return kWebTextInputTypePassword;
    if (type == input_type_names::kSearch)
      return kWebTextInputTypeSearch;
    if (type == input_type_names::kEmail)
      return kWebTextInputTypeEmail;
    if (type == input_type_names::kNumber)
      return kWebTextInputTypeNumber;
    if (type == input_type_names::kTel)
      return kWebTextInputTypeTelephone;
    if (type == input_type_names::kUrl)
      return kWebTextInputTypeURL;
    if (type == input_type_names::kText)
      return kWebTextInputTypeText;

    return kWebTextInputTypeNone;
  }

  if (auto* textarea = ToHTMLTextAreaElementOrNull(*element)) {
    if (textarea->IsDisabledOrReadOnly())
      return kWebTextInputTypeNone;
    return kWebTextInputTypeTextArea;
  }

  if (element->IsHTMLElement()) {
    if (ToHTMLElement(element)->IsDateTimeFieldElement())
      return kWebTextInputTypeDateTimeField;
  }

  GetDocument().UpdateStyleAndLayoutTree();
  if (HasEditableStyle(*element))
    return kWebTextInputTypeContentEditable;

  return kWebTextInputTypeNone;
}

void InputMethodController::WillChangeFocus() {
  FinishComposingText(kKeepSelection);
}

void InputMethodController::Trace(blink::Visitor* visitor) {
  visitor->Trace(frame_);
  visitor->Trace(composition_range_);
  DocumentShutdownObserver::Trace(visitor);
}

}  // namespace blink
