/*
 * 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/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_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(
      EventTypeNames::compositionupdate, 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(
      EventTypeNames::compositionend, 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(chongz): 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(chongz): 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(chongz): Use TypingCommand::insertText after TextEvent was
      // removed. (Removed from spec since 2012)
      // See TextEvent.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(HTMLNames::inputmodeAttr).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 == InputTypeNames::email ||
        input_type == InputTypeNames::url ||
        input_type == InputTypeNames::password) {
      // 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 new 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() {
  has_composition_ = false;
  if (composition_range_) {
    composition_range_->setStart(&GetDocument(), 0);
    composition_range_->collapse(true);
  }
  GetDocument().Markers().RemoveMarkersOfTypes(DocumentMarker::kComposition);
}

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

void InputMethodController::DocumentAttached(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(size_t text_start,
                                        size_t 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())
                .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(
      EventTypeNames::compositionstart, 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,
        ui::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);
}

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(chongz): 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(HTMLNames::autocompleteAttr);
  if (autocomplete == "on")
    flags |= kWebTextInputFlagAutocompleteOn;
  else if (autocomplete == "off")
    flags |= kWebTextInputFlagAutocompleteOff;

  const AtomicString& autocorrect =
      element->getAttribute(HTMLNames::autocorrectAttr);
  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 {
  if (!RuntimeEnabledFeatures::InputModeAttributeEnabled())
    return kWebTextInputModeDefault;

  AtomicString mode = GetInputModeAttribute(GetDocument().FocusedElement());

  if (mode.IsEmpty())
    return kWebTextInputModeDefault;
  if (mode == InputModeNames::none)
    return kWebTextInputModeNone;
  if (mode == InputModeNames::text)
    return kWebTextInputModeText;
  if (mode == InputModeNames::tel)
    return kWebTextInputModeTel;
  if (mode == InputModeNames::url)
    return kWebTextInputModeUrl;
  if (mode == InputModeNames::email)
    return kWebTextInputModeEmail;
  if (mode == InputModeNames::numeric)
    return kWebTextInputModeNumeric;
  if (mode == InputModeNames::decimal)
    return kWebTextInputModeDecimal;
  if (mode == InputModeNames::search)
    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 == InputTypeNames::password)
      return kWebTextInputTypePassword;
    if (type == InputTypeNames::search)
      return kWebTextInputTypeSearch;
    if (type == InputTypeNames::email)
      return kWebTextInputTypeEmail;
    if (type == InputTypeNames::number)
      return kWebTextInputTypeNumber;
    if (type == InputTypeNames::tel)
      return kWebTextInputTypeTelephone;
    if (type == InputTypeNames::url)
      return kWebTextInputTypeURL;
    if (type == InputTypeNames::text)
      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
