/*
 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
 * Copyright (C) 2009, 2010, 2011 Google Inc. All rights reserved.
 *
 * 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/commands/replace_selection_command.h"

#include "base/macros.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/css/css_property_value_set.h"
#include "third_party/blink/renderer/core/css/css_style_declaration.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/document_fragment.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/commands/apply_style_command.h"
#include "third_party/blink/renderer/core/editing/commands/break_blockquote_command.h"
#include "third_party/blink/renderer/core/editing/commands/delete_selection_options.h"
#include "third_party/blink/renderer/core/editing/commands/editing_commands_utilities.h"
#include "third_party/blink/renderer/core/editing/commands/simplify_markup_command.h"
#include "third_party/blink/renderer/core/editing/commands/smart_replace.h"
#include "third_party/blink/renderer/core/editing/editing_style.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/iterators/text_iterator.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/serializers/html_interchange.h"
#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/editing/visible_units.h"
#include "third_party/blink/renderer/core/events/before_text_inserted_event.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/core/html/html_br_element.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html/html_li_element.h"
#include "third_party/blink/renderer/core/html/html_quote_element.h"
#include "third_party/blink/renderer/core/html/html_span_element.h"
#include "third_party/blink/renderer/core/html_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_text.h"
#include "third_party/blink/renderer/core/svg/svg_style_element.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"

namespace blink {

// --- ReplacementFragment helper class

class ReplacementFragment final {
  STACK_ALLOCATED();

 public:
  ReplacementFragment(Document*, DocumentFragment*, const VisibleSelection&);
  ReplacementFragment(const ReplacementFragment&) = delete;
  ReplacementFragment& operator=(const ReplacementFragment&) = delete;

  Node* FirstChild() const;
  Node* LastChild() const;

  bool IsEmpty() const;

  bool HasInterchangeNewlineAtStart() const {
    return has_interchange_newline_at_start_;
  }
  bool HasInterchangeNewlineAtEnd() const {
    return has_interchange_newline_at_end_;
  }

  void RemoveNode(Node*);
  void RemoveNodePreservingChildren(ContainerNode*);

 private:
  HTMLElement* InsertFragmentForTestRendering(Element* root_editable_element);
  void RemoveUnrenderedNodes(ContainerNode*);
  void RestoreAndRemoveTestRenderingNodesToFragment(Element*);
  void RemoveInterchangeNodes(ContainerNode*);

  void InsertNodeBefore(Node*, Node* ref_node);

  Document* document_;
  DocumentFragment* fragment_;
  bool has_interchange_newline_at_start_;
  bool has_interchange_newline_at_end_;
};

static bool IsInterchangeHTMLBRElement(const Node* node) {
  DEFINE_STATIC_LOCAL(String, interchange_newline_class_string,
                      (AppleInterchangeNewline));
  auto* html_br_element = DynamicTo<HTMLBRElement>(node);
  if (!html_br_element ||
      html_br_element->getAttribute(html_names::kClassAttr) !=
          interchange_newline_class_string)
    return false;
  UseCounter::Count(node->GetDocument(),
                    WebFeature::kEditingAppleInterchangeNewline);
  return true;
}

static Position PositionAvoidingPrecedingNodes(Position pos) {
  // If we're already on a break, it's probably a placeholder and we shouldn't
  // change our position.
  if (EditingIgnoresContent(*pos.AnchorNode()))
    return pos;

  // We also stop when changing block flow elements because even though the
  // visual position is the same.  E.g.,
  //   <div>foo^</div>^
  // The two positions above are the same visual position, but we want to stay
  // in the same block.
  Element* enclosing_block_element = EnclosingBlock(pos.ComputeContainerNode());
  for (Position next_position = pos;
       next_position.ComputeContainerNode() != enclosing_block_element;
       pos = next_position) {
    if (LineBreakExistsAtPosition(pos))
      break;

    if (pos.ComputeContainerNode()->NonShadowBoundaryParentNode())
      next_position = Position::InParentAfterNode(*pos.ComputeContainerNode());

    if (next_position == pos ||
        EnclosingBlock(next_position.ComputeContainerNode()) !=
            enclosing_block_element ||
        CreateVisiblePosition(pos).DeepEquivalent() !=
            CreateVisiblePosition(next_position).DeepEquivalent())
      break;
  }
  return pos;
}

ReplacementFragment::ReplacementFragment(Document* document,
                                         DocumentFragment* fragment,
                                         const VisibleSelection& selection)
    : document_(document),
      fragment_(fragment),
      has_interchange_newline_at_start_(false),
      has_interchange_newline_at_end_(false) {
  if (!document_)
    return;
  if (!fragment_ || !fragment_->HasChildren())
    return;

  TRACE_EVENT0("blink", "ReplacementFragment constructor");
  Element* editable_root = selection.RootEditableElement();
  DCHECK(editable_root);
  if (!editable_root)
    return;

  document_->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

  Element* shadow_ancestor_element;
  if (editable_root->IsInShadowTree())
    shadow_ancestor_element = editable_root->OwnerShadowHost();
  else
    shadow_ancestor_element = editable_root;

  if (!editable_root->GetAttributeEventListener(
          event_type_names::kWebkitBeforeTextInserted)
      // FIXME: Remove these checks once textareas and textfields actually
      // register an event handler.
      &&
      !(shadow_ancestor_element && shadow_ancestor_element->GetLayoutObject() &&
        shadow_ancestor_element->GetLayoutObject()
            ->IsTextControlIncludingNG()) &&
      HasRichlyEditableStyle(*editable_root)) {
    RemoveInterchangeNodes(fragment_);
    return;
  }

  if (!HasRichlyEditableStyle(*editable_root)) {
    bool is_plain_text = true;
    for (Node& node : NodeTraversal::ChildrenOf(*fragment_)) {
      if (IsInterchangeHTMLBRElement(&node) && &node == fragment_->lastChild())
        continue;
      if (!node.IsTextNode()) {
        is_plain_text = false;
        break;
      }
    }
    // We don't need TestRendering for plain-text editing + plain-text
    // insertion.
    if (is_plain_text) {
      RemoveInterchangeNodes(fragment_);
      String original_text = fragment_->textContent();
      auto* event =
          MakeGarbageCollected<BeforeTextInsertedEvent>(original_text);
      editable_root->DispatchEvent(*event);
      if (original_text != event->GetText()) {
        fragment_ = CreateFragmentFromText(
            selection.ToNormalizedEphemeralRange(), event->GetText());
        RemoveInterchangeNodes(fragment_);
      }
      return;
    }
  }

  HTMLElement* holder = InsertFragmentForTestRendering(editable_root);
  if (!holder) {
    RemoveInterchangeNodes(fragment_);
    return;
  }

  const EphemeralRange range =
      CreateVisibleSelection(
          SelectionInDOMTree::Builder().SelectAllChildren(*holder).Build())
          .ToNormalizedEphemeralRange();
  const TextIteratorBehavior& behavior = TextIteratorBehavior::Builder()
                                             .SetEmitsOriginalText(true)
                                             .SetIgnoresStyleVisibility(true)
                                             .Build();
  const String& text = PlainText(range, behavior);

  RemoveInterchangeNodes(holder);
  RemoveUnrenderedNodes(holder);
  RestoreAndRemoveTestRenderingNodesToFragment(holder);

  // Give the root a chance to change the text.
  auto* evt = MakeGarbageCollected<BeforeTextInsertedEvent>(text);
  editable_root->DispatchEvent(*evt);
  if (text != evt->GetText() || !HasRichlyEditableStyle(*editable_root)) {
    RestoreAndRemoveTestRenderingNodesToFragment(holder);

    // TODO(editing-dev): Use of UpdateStyleAndLayout
    // needs to be audited.  See http://crbug.com/590369 for more details.
    document->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

    fragment_ = CreateFragmentFromText(selection.ToNormalizedEphemeralRange(),
                                       evt->GetText());
    if (!fragment_->HasChildren())
      return;

    holder = InsertFragmentForTestRendering(editable_root);
    RemoveInterchangeNodes(holder);
    RemoveUnrenderedNodes(holder);
    RestoreAndRemoveTestRenderingNodesToFragment(holder);
  }
}

bool ReplacementFragment::IsEmpty() const {
  return (!fragment_ || !fragment_->HasChildren()) &&
         !has_interchange_newline_at_start_ && !has_interchange_newline_at_end_;
}

Node* ReplacementFragment::FirstChild() const {
  return fragment_ ? fragment_->firstChild() : nullptr;
}

Node* ReplacementFragment::LastChild() const {
  return fragment_ ? fragment_->lastChild() : nullptr;
}

void ReplacementFragment::RemoveNodePreservingChildren(ContainerNode* node) {
  if (!node)
    return;

  while (Node* n = node->firstChild()) {
    RemoveNode(n);
    InsertNodeBefore(n, node);
  }
  RemoveNode(node);
}

void ReplacementFragment::RemoveNode(Node* node) {
  if (!node)
    return;

  ContainerNode* parent = node->NonShadowBoundaryParentNode();
  if (!parent)
    return;

  parent->RemoveChild(node);
}

void ReplacementFragment::InsertNodeBefore(Node* node, Node* ref_node) {
  if (!node || !ref_node)
    return;

  ContainerNode* parent = ref_node->NonShadowBoundaryParentNode();
  if (!parent)
    return;

  parent->InsertBefore(node, ref_node);
}

HTMLElement* ReplacementFragment::InsertFragmentForTestRendering(
    Element* root_editable_element) {
  TRACE_EVENT0("blink", "ReplacementFragment::insertFragmentForTestRendering");
  DCHECK(document_);
  HTMLElement* holder = CreateDefaultParagraphElement(*document_);

  holder->AppendChild(fragment_);
  root_editable_element->AppendChild(holder);

  // TODO(editing-dev): Hoist this call to the call sites.
  document_->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

  return holder;
}

void ReplacementFragment::RestoreAndRemoveTestRenderingNodesToFragment(
    Element* holder) {
  if (!holder)
    return;

  while (Node* node = holder->firstChild()) {
    holder->RemoveChild(node);
    fragment_->AppendChild(node);
  }

  RemoveNode(holder);
}

void ReplacementFragment::RemoveUnrenderedNodes(ContainerNode* holder) {
  HeapVector<Member<Node>> unrendered;

  for (Node& node : NodeTraversal::DescendantsOf(*holder)) {
    if (!IsNodeRendered(node) && !IsTableStructureNode(&node))
      unrendered.push_back(&node);
  }

  for (auto& node : unrendered)
    RemoveNode(node);
}

void ReplacementFragment::RemoveInterchangeNodes(ContainerNode* container) {
  has_interchange_newline_at_start_ = false;
  has_interchange_newline_at_end_ = false;

  // Interchange newlines at the "start" of the incoming fragment must be
  // either the first node in the fragment or the first leaf in the fragment.
  Node* node = container->firstChild();
  while (node) {
    if (IsInterchangeHTMLBRElement(node)) {
      has_interchange_newline_at_start_ = true;
      RemoveNode(node);
      break;
    }
    node = node->firstChild();
  }
  if (!container->HasChildren())
    return;
  // Interchange newlines at the "end" of the incoming fragment must be
  // either the last node in the fragment or the last leaf in the fragment.
  node = container->lastChild();
  while (node) {
    if (IsInterchangeHTMLBRElement(node)) {
      has_interchange_newline_at_end_ = true;
      RemoveNode(node);
      break;
    }
    node = node->lastChild();
  }
}

inline void ReplaceSelectionCommand::InsertedNodes::RespondToNodeInsertion(
    Node& node) {
  if (!first_node_inserted_)
    first_node_inserted_ = &node;

  last_node_inserted_ = &node;
}

inline void
ReplaceSelectionCommand::InsertedNodes::WillRemoveNodePreservingChildren(
    Node& node) {
  if (first_node_inserted_ == node)
    first_node_inserted_ = NodeTraversal::Next(node);
  if (last_node_inserted_ == node)
    last_node_inserted_ = node.lastChild()
                              ? node.lastChild()
                              : NodeTraversal::NextSkippingChildren(node);
  if (ref_node_ == node)
    ref_node_ = NodeTraversal::Next(node);
}

inline void ReplaceSelectionCommand::InsertedNodes::WillRemoveNode(Node& node) {
  if (first_node_inserted_ == node && last_node_inserted_ == node) {
    first_node_inserted_ = nullptr;
    last_node_inserted_ = nullptr;
  } else if (first_node_inserted_ == node) {
    first_node_inserted_ =
        NodeTraversal::NextSkippingChildren(*first_node_inserted_);
  } else if (last_node_inserted_ == node) {
    last_node_inserted_ =
        NodeTraversal::PreviousAbsoluteSibling(*last_node_inserted_);
  }
  if (node.contains(ref_node_))
    ref_node_ = NodeTraversal::NextSkippingChildren(node);
}

inline void ReplaceSelectionCommand::InsertedNodes::DidReplaceNode(
    Node& node,
    Node& new_node) {
  if (first_node_inserted_ == node)
    first_node_inserted_ = &new_node;
  if (last_node_inserted_ == node)
    last_node_inserted_ = &new_node;
  if (ref_node_ == node)
    ref_node_ = &new_node;
}

ReplaceSelectionCommand::ReplaceSelectionCommand(
    Document& document,
    DocumentFragment* fragment,
    CommandOptions options,
    InputEvent::InputType input_type)
    : CompositeEditCommand(document),
      select_replacement_(options & kSelectReplacement),
      smart_replace_(options & kSmartReplace),
      match_style_(options & kMatchStyle),
      document_fragment_(fragment),
      prevent_nesting_(options & kPreventNesting),
      moving_paragraph_(options & kMovingParagraph),
      input_type_(input_type),
      sanitize_fragment_(options & kSanitizeFragment),
      should_merge_end_(false) {}

static bool HasMatchingQuoteLevel(VisiblePosition end_of_existing_content,
                                  VisiblePosition end_of_inserted_content) {
  Position existing = end_of_existing_content.DeepEquivalent();
  Position inserted = end_of_inserted_content.DeepEquivalent();
  bool is_inside_mail_blockquote = EnclosingNodeOfType(
      inserted, IsMailHTMLBlockquoteElement, kCanCrossEditingBoundary);
  return is_inside_mail_blockquote && (NumEnclosingMailBlockquotes(existing) ==
                                       NumEnclosingMailBlockquotes(inserted));
}

bool ReplaceSelectionCommand::ShouldMergeStart(
    bool selection_start_was_start_of_paragraph,
    bool fragment_has_interchange_newline_at_start,
    bool selection_start_was_inside_mail_blockquote) {
  if (moving_paragraph_)
    return false;

  VisiblePosition start_of_inserted_content =
      PositionAtStartOfInsertedContent();
  VisiblePosition prev = PreviousPositionOf(start_of_inserted_content,
                                            kCannotCrossEditingBoundary);
  if (prev.IsNull())
    return false;

  // When we have matching quote levels, its ok to merge more frequently.
  // For a successful merge, we still need to make sure that the inserted
  // content starts with the beginning of a paragraph. And we should only merge
  // here if the selection start was inside a mail blockquote. This prevents
  // against removing a blockquote from newly pasted quoted content that was
  // pasted into an unquoted position. If that unquoted position happens to be
  // right after another blockquote, we don't want to merge and risk stripping a
  // valid block (and newline) from the pasted content.
  if (IsStartOfParagraph(start_of_inserted_content) &&
      selection_start_was_inside_mail_blockquote &&
      HasMatchingQuoteLevel(prev, PositionAtEndOfInsertedContent()))
    return true;

  return !selection_start_was_start_of_paragraph &&
         !fragment_has_interchange_newline_at_start &&
         IsStartOfParagraph(start_of_inserted_content) &&
         !IsA<HTMLBRElement>(
             *start_of_inserted_content.DeepEquivalent().AnchorNode()) &&
         ShouldMerge(start_of_inserted_content, prev);
}

bool ReplaceSelectionCommand::ShouldMergeEnd(
    bool selection_end_was_end_of_paragraph) {
  VisiblePosition end_of_inserted_content(PositionAtEndOfInsertedContent());
  VisiblePosition next =
      NextPositionOf(end_of_inserted_content, kCannotCrossEditingBoundary);
  if (next.IsNull())
    return false;

  return !selection_end_was_end_of_paragraph &&
         IsEndOfParagraph(end_of_inserted_content) &&
         !IsA<HTMLBRElement>(
             *end_of_inserted_content.DeepEquivalent().AnchorNode()) &&
         ShouldMerge(end_of_inserted_content, next);
}

static bool IsHTMLHeaderElement(const Node* a) {
  const auto* element = DynamicTo<HTMLElement>(a);
  if (!element)
    return false;

  return element->HasTagName(html_names::kH1Tag) ||
         element->HasTagName(html_names::kH2Tag) ||
         element->HasTagName(html_names::kH3Tag) ||
         element->HasTagName(html_names::kH4Tag) ||
         element->HasTagName(html_names::kH5Tag) ||
         element->HasTagName(html_names::kH6Tag);
}

static bool HaveSameTagName(Element* a, Element* b) {
  return a && b && a->tagName() == b->tagName();
}

bool ReplaceSelectionCommand::ShouldMerge(const VisiblePosition& source,
                                          const VisiblePosition& destination) {
  if (source.IsNull() || destination.IsNull())
    return false;

  Node* source_node = source.DeepEquivalent().AnchorNode();
  Node* destination_node = destination.DeepEquivalent().AnchorNode();
  Element* source_block = EnclosingBlock(source_node);
  Element* destination_block = EnclosingBlock(destination_node);
  return source_block &&
         (!source_block->HasTagName(html_names::kBlockquoteTag) ||
          IsMailHTMLBlockquoteElement(source_block)) &&
         EnclosingListChild(source_block) ==
             EnclosingListChild(destination_node) &&
         EnclosingTableCell(source.DeepEquivalent()) ==
             EnclosingTableCell(destination.DeepEquivalent()) &&
         (!IsHTMLHeaderElement(source_block) ||
          HaveSameTagName(source_block, destination_block))
         // Don't merge to or from a position before or after a block because it
         // would be a no-op and cause infinite recursion.
         && !IsEnclosingBlock(source_node) &&
         !IsEnclosingBlock(destination_node);
}

// Style rules that match just inserted elements could change their appearance,
// like a div inserted into a document with div { display:inline; }.
void ReplaceSelectionCommand::RemoveRedundantStylesAndKeepStyleSpanInline(
    InsertedNodes& inserted_nodes,
    EditingState* editing_state) {
  Node* past_end_node = inserted_nodes.PastLastLeaf();
  Node* next = nullptr;
  for (Node* node = inserted_nodes.FirstNodeInserted();
       node && node != past_end_node; node = next) {
    // FIXME: <rdar://problem/5371536> Style rules that match pasted content can
    // change it's appearance

    next = NodeTraversal::Next(*node);
    if (!node->IsStyledElement())
      continue;

    auto* element = To<Element>(node);

    const CSSPropertyValueSet* inline_style = element->InlineStyle();
    EditingStyle* new_inline_style =
        MakeGarbageCollected<EditingStyle>(inline_style);
    if (inline_style) {
      auto* html_element = DynamicTo<HTMLElement>(element);
      if (html_element) {
        Vector<QualifiedName> attributes;
        DCHECK(html_element);

        if (new_inline_style->ConflictsWithImplicitStyleOfElement(
                html_element)) {
          // e.g. <b style="font-weight: normal;"> is converted to <span
          // style="font-weight: normal;">
          element = ReplaceElementWithSpanPreservingChildrenAndAttributes(
              html_element);
          inline_style = element->InlineStyle();
          inserted_nodes.DidReplaceNode(*html_element, *element);
        } else if (new_inline_style
                       ->ExtractConflictingImplicitStyleOfAttributes(
                           html_element,
                           EditingStyle::kPreserveWritingDirection, nullptr,
                           attributes,
                           EditingStyle::kDoNotExtractMatchingStyle)) {
          // e.g. <font size="3" style="font-size: 20px;"> is converted to <font
          // style="font-size: 20px;">
          for (wtf_size_t i = 0; i < attributes.size(); i++)
            RemoveElementAttribute(html_element, attributes[i]);
        }
      }

      ContainerNode* context = element->parentNode();

      // If Mail wraps the fragment with a Paste as Quotation blockquote, or if
      // you're pasting into a quoted region, styles from blockquoteNode are
      // allowed to override those from the source document, see
      // <rdar://problem/4930986> and <rdar://problem/5089327>.
      auto* blockquote_element =
          !context
              ? To<HTMLQuoteElement>(context)
              : To<HTMLQuoteElement>(EnclosingNodeOfType(
                    Position::FirstPositionInNode(*context),
                    IsMailHTMLBlockquoteElement, kCanCrossEditingBoundary));

      // EditingStyle::removeStyleFromRulesAndContext() uses StyleResolver,
      // which requires clean style.
      // TODO(editing-dev): There is currently no way to update style without
      // updating layout. We might want to have updateLifcycleToStyleClean()
      // similar to FrameView::updateLifecylceToLayoutClean() in Document.
      GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

      if (blockquote_element)
        new_inline_style->RemoveStyleFromRulesAndContext(
            element, GetDocument().documentElement());

      new_inline_style->RemoveStyleFromRulesAndContext(element, context);
    }

    if (!inline_style || new_inline_style->IsEmpty()) {
      if (IsStyleSpanOrSpanWithOnlyStyleAttribute(element) ||
          IsEmptyFontTag(element, kAllowNonEmptyStyleAttribute)) {
        inserted_nodes.WillRemoveNodePreservingChildren(*element);
        RemoveNodePreservingChildren(element, editing_state);
        if (editing_state->IsAborted())
          return;
        continue;
      }
      RemoveElementAttribute(element, html_names::kStyleAttr);
    } else if (new_inline_style->Style()->PropertyCount() !=
               inline_style->PropertyCount()) {
      SetNodeAttribute(element, html_names::kStyleAttr,
                       AtomicString(new_inline_style->Style()->AsText()));
    }

    GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

    // FIXME: Tolerate differences in id, class, and style attributes.
    if (element->parentNode() && IsNonTableCellHTMLBlockElement(element) &&
        AreIdenticalElements(*element, *element->parentNode()) &&
        VisiblePosition::FirstPositionInNode(*element->parentNode())
                .DeepEquivalent() ==
            VisiblePosition::FirstPositionInNode(*element).DeepEquivalent() &&
        VisiblePosition::LastPositionInNode(*element->parentNode())
                .DeepEquivalent() ==
            VisiblePosition::LastPositionInNode(*element).DeepEquivalent()) {
      inserted_nodes.WillRemoveNodePreservingChildren(*element);
      RemoveNodePreservingChildren(element, editing_state);
      if (editing_state->IsAborted())
        return;
      continue;
    }

    if (element->parentNode() &&
        HasRichlyEditableStyle(*element->parentNode()) &&
        HasRichlyEditableStyle(*element)) {
      RemoveElementAttribute(element, html_names::kContenteditableAttr);
    }
  }
}

static bool IsProhibitedParagraphChild(const AtomicString& name) {
  // https://dvcs.w3.org/hg/editing/raw-file/57abe6d3cb60/editing.html#prohibited-paragraph-child
  DEFINE_STATIC_LOCAL(
      HashSet<AtomicString>, elements,
      ({
          html_names::kAddressTag.LocalName(),
          html_names::kArticleTag.LocalName(),
          html_names::kAsideTag.LocalName(),
          html_names::kBlockquoteTag.LocalName(),
          html_names::kCaptionTag.LocalName(),
          html_names::kCenterTag.LocalName(),
          html_names::kColTag.LocalName(),
          html_names::kColgroupTag.LocalName(),
          html_names::kDdTag.LocalName(),
          html_names::kDetailsTag.LocalName(),
          html_names::kDirTag.LocalName(),
          html_names::kDivTag.LocalName(),
          html_names::kDlTag.LocalName(),
          html_names::kDtTag.LocalName(),
          html_names::kFieldsetTag.LocalName(),
          html_names::kFigcaptionTag.LocalName(),
          html_names::kFigureTag.LocalName(),
          html_names::kFooterTag.LocalName(),
          html_names::kFormTag.LocalName(),
          html_names::kH1Tag.LocalName(),
          html_names::kH2Tag.LocalName(),
          html_names::kH3Tag.LocalName(),
          html_names::kH4Tag.LocalName(),
          html_names::kH5Tag.LocalName(),
          html_names::kH6Tag.LocalName(),
          html_names::kHeaderTag.LocalName(),
          html_names::kHgroupTag.LocalName(),
          html_names::kHrTag.LocalName(),
          html_names::kLiTag.LocalName(),
          html_names::kListingTag.LocalName(),
          html_names::kMainTag.LocalName(),  // Missing in the specification.
          html_names::kMenuTag.LocalName(),
          html_names::kNavTag.LocalName(),
          html_names::kOlTag.LocalName(),
          html_names::kPTag.LocalName(),
          html_names::kPlaintextTag.LocalName(),
          html_names::kPreTag.LocalName(),
          html_names::kSectionTag.LocalName(),
          html_names::kSummaryTag.LocalName(),
          html_names::kTableTag.LocalName(),
          html_names::kTbodyTag.LocalName(),
          html_names::kTdTag.LocalName(),
          html_names::kTfootTag.LocalName(),
          html_names::kThTag.LocalName(),
          html_names::kTheadTag.LocalName(),
          html_names::kTrTag.LocalName(),
          html_names::kUlTag.LocalName(),
          html_names::kXmpTag.LocalName(),
      }));
  return elements.Contains(name);
}

void ReplaceSelectionCommand::
    MakeInsertedContentRoundTrippableWithHTMLTreeBuilder(
        const InsertedNodes& inserted_nodes,
        EditingState* editing_state) {
  Node* past_end_node = inserted_nodes.PastLastLeaf();
  Node* next = nullptr;
  for (Node* node = inserted_nodes.FirstNodeInserted();
       node && node != past_end_node; node = next) {
    next = NodeTraversal::Next(*node);

    auto* element = DynamicTo<HTMLElement>(node);
    if (!element)
      continue;
    // moveElementOutOfAncestor() in a previous iteration might have failed,
    // and |node| might have been detached from the document tree.
    if (!node->isConnected())
      continue;

    if (IsProhibitedParagraphChild(element->localName())) {
      if (HTMLElement* paragraph_element =
              To<HTMLElement>(EnclosingElementWithTag(
                  Position::InParentBeforeNode(*element), html_names::kPTag))) {
        MoveElementOutOfAncestor(element, paragraph_element, editing_state);
        if (editing_state->IsAborted())
          return;
      }
    }

    if (IsHTMLHeaderElement(element)) {
      if (auto* header_element = To<HTMLElement>(HighestEnclosingNodeOfType(
              Position::InParentBeforeNode(*element), IsHTMLHeaderElement))) {
        MoveElementOutOfAncestor(element, header_element, editing_state);
        if (editing_state->IsAborted())
          return;
      }
    }
  }
}

void ReplaceSelectionCommand::MoveElementOutOfAncestor(
    Element* element,
    Element* ancestor,
    EditingState* editing_state) {
  DCHECK(element);
  if (!HasEditableStyle(*ancestor->parentNode()))
    return;

  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
  VisiblePosition position_at_end_of_node =
      CreateVisiblePosition(LastPositionInOrAfterNode(*element));
  VisiblePosition last_position_in_paragraph =
      VisiblePosition::LastPositionInNode(*ancestor);
  if (position_at_end_of_node.DeepEquivalent() ==
      last_position_in_paragraph.DeepEquivalent()) {
    RemoveNode(element, editing_state);
    if (editing_state->IsAborted())
      return;
    if (ancestor->nextSibling())
      InsertNodeBefore(element, ancestor->nextSibling(), editing_state);
    else
      AppendNode(element, ancestor->parentNode(), editing_state);
    if (editing_state->IsAborted())
      return;
  } else {
    Node* node_to_split_to = SplitTreeToNode(element, ancestor, true);
    RemoveNode(element, editing_state);
    if (editing_state->IsAborted())
      return;
    InsertNodeBefore(element, node_to_split_to, editing_state);
    if (editing_state->IsAborted())
      return;
  }
  if (!ancestor->HasChildren())
    RemoveNode(ancestor, editing_state);
}

static inline bool NodeHasVisibleLayoutText(Text& text) {
  return text.GetLayoutObject() &&
         text.GetLayoutObject()->ResolvedTextLength() > 0;
}

void ReplaceSelectionCommand::RemoveUnrenderedTextNodesAtEnds(
    InsertedNodes& inserted_nodes) {
  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

  auto* last_leaf_inserted = DynamicTo<Text>(inserted_nodes.LastLeafInserted());
  if (last_leaf_inserted && !NodeHasVisibleLayoutText(*last_leaf_inserted) &&
      !EnclosingElementWithTag(FirstPositionInOrBeforeNode(*last_leaf_inserted),
                               html_names::kSelectTag) &&
      !EnclosingElementWithTag(FirstPositionInOrBeforeNode(*last_leaf_inserted),
                               html_names::kScriptTag)) {
    inserted_nodes.WillRemoveNode(*last_leaf_inserted);
    // Removing a Text node won't dispatch synchronous events.
    RemoveNode(last_leaf_inserted, ASSERT_NO_EDITING_ABORT);
  }

  // We don't have to make sure that firstNodeInserted isn't inside a select or
  // script element, because it is a top level node in the fragment and the user
  // can't insert into those elements.
  auto* first_node_inserted =
      DynamicTo<Text>(inserted_nodes.FirstNodeInserted());
  if (first_node_inserted) {
    GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
    if (!NodeHasVisibleLayoutText(*first_node_inserted)) {
      inserted_nodes.WillRemoveNode(*first_node_inserted);
      // Removing a Text node won't dispatch synchronous events.
      RemoveNode(first_node_inserted, ASSERT_NO_EDITING_ABORT);
    }
  }
}

VisiblePosition ReplaceSelectionCommand::PositionAtEndOfInsertedContent()
    const {
  // TODO(editing-dev): Hoist the call and change it into a DCHECK.
  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
  // TODO(yosin): We should set |end_of_inserted_content_| not in SELECT
  // element, since contents of SELECT elements, e.g. OPTION, OPTGROUP, are
  // not editable, or SELECT element is an atomic on editing.
  auto* enclosing_select = To<HTMLSelectElement>(EnclosingElementWithTag(
      end_of_inserted_content_, html_names::kSelectTag));
  if (enclosing_select) {
    return CreateVisiblePosition(LastPositionInOrAfterNode(*enclosing_select));
  }
  if (end_of_inserted_content_.IsOrphan())
    return VisiblePosition();
  return CreateVisiblePosition(end_of_inserted_content_);
}

VisiblePosition ReplaceSelectionCommand::PositionAtStartOfInsertedContent()
    const {
  // TODO(editing-dev): Hoist the call and change it into a DCHECK.
  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
  if (start_of_inserted_content_.IsOrphan())
    return VisiblePosition();
  return CreateVisiblePosition(start_of_inserted_content_);
}

static void RemoveHeadContents(ReplacementFragment& fragment) {
  Node* next = nullptr;
  for (Node* node = fragment.FirstChild(); node; node = next) {
    if (IsA<HTMLBaseElement>(*node) || IsA<HTMLLinkElement>(*node) ||
        IsA<HTMLMetaElement>(*node) || IsA<HTMLStyleElement>(*node) ||
        IsA<HTMLTitleElement>(*node) || IsA<SVGStyleElement>(*node)) {
      next = NodeTraversal::NextSkippingChildren(*node);
      fragment.RemoveNode(node);
    } else {
      next = NodeTraversal::Next(*node);
    }
  }
}

static bool FollowBlockElementStyle(const Node* node) {
  const auto* element = DynamicTo<HTMLElement>(node);
  if (!element)
    return false;
  // When content is inserted into an empty block, use the original style
  // instead of the block style.
  if (!node->firstChild())
    return false;
  // A block with a placeholder BR appears the same as an empty block.
  if (node->firstChild() == node->lastChild() &&
      IsA<HTMLBRElement>(node->firstChild())) {
    return false;
  }

  return IsListItem(node) || IsTableCell(node) ||
         element->HasTagName(html_names::kPreTag) ||
         element->HasTagName(html_names::kH1Tag) ||
         element->HasTagName(html_names::kH2Tag) ||
         element->HasTagName(html_names::kH3Tag) ||
         element->HasTagName(html_names::kH4Tag) ||
         element->HasTagName(html_names::kH5Tag) ||
         element->HasTagName(html_names::kH6Tag);
}

// Remove style spans before insertion if they are unnecessary.  It's faster
// because we'll avoid doing a layout.
static void HandleStyleSpansBeforeInsertion(ReplacementFragment& fragment,
                                            const Position& insertion_pos) {
  Node* top_node = fragment.FirstChild();
  if (!IsA<HTMLSpanElement>(top_node))
    return;

  // Handling the case where we are doing Paste as Quotation or pasting into
  // quoted content is more complicated (see handleStyleSpans) and doesn't
  // receive the optimization.
  if (EnclosingNodeOfType(FirstPositionInOrBeforeNode(*top_node),
                          IsMailHTMLBlockquoteElement,
                          kCanCrossEditingBoundary))
    return;

  // Remove style spans to follow the styles of parent block element when
  // |fragment| becomes a part of it. See bugs http://crbug.com/226941 and
  // http://crbug.com/335955.
  auto* wrapping_style_span = To<HTMLSpanElement>(top_node);
  const Node* node = insertion_pos.AnchorNode();
  // |node| can be an inline element like <br> under <li>
  // e.g.) editing/execCommand/switch-list-type.html
  //       editing/deleting/backspace-merge-into-block.html
  if (IsInline(node)) {
    node = EnclosingBlock(insertion_pos.AnchorNode());
    if (!node)
      return;
  }

  if (FollowBlockElementStyle(node)) {
    fragment.RemoveNodePreservingChildren(wrapping_style_span);
    return;
  }

  EditingStyle* style_at_insertion_pos = MakeGarbageCollected<EditingStyle>(
      insertion_pos.ParentAnchoredEquivalent());
  String style_text = style_at_insertion_pos->Style()->AsText();

  // FIXME: This string comparison is a naive way of comparing two styles.
  // We should be taking the diff and check that the diff is empty.
  if (style_text != wrapping_style_span->getAttribute(html_names::kStyleAttr))
    return;

  fragment.RemoveNodePreservingChildren(wrapping_style_span);
}

void ReplaceSelectionCommand::MergeEndIfNeeded(EditingState* editing_state) {
  if (!should_merge_end_)
    return;

  VisiblePosition start_of_inserted_content(PositionAtStartOfInsertedContent());
  VisiblePosition end_of_inserted_content(PositionAtEndOfInsertedContent());

  // Bail to avoid infinite recursion.
  if (moving_paragraph_) {
    NOTREACHED();
    return;
  }

  // Merging two paragraphs will destroy the moved one's block styles.  Always
  // move the end of inserted forward to preserve the block style of the
  // paragraph already in the document, unless the paragraph to move would
  // include the what was the start of the selection that was pasted into, so
  // that we preserve that paragraph's block styles.
  bool merge_forward =
      !(InSameParagraph(start_of_inserted_content, end_of_inserted_content) &&
        !IsStartOfParagraph(start_of_inserted_content));

  VisiblePosition destination = merge_forward
                                    ? NextPositionOf(end_of_inserted_content)
                                    : end_of_inserted_content;
  // TODO(editing-dev): Stop storing VisiblePositions through mutations.
  // See crbug.com/648949 for details.
  VisiblePosition start_of_paragraph_to_move =
      merge_forward ? StartOfParagraph(end_of_inserted_content)
                    : NextPositionOf(end_of_inserted_content);

  // Merging forward could result in deleting the destination anchor node.
  // To avoid this, we add a placeholder node before the start of the paragraph.
  if (EndOfParagraph(start_of_paragraph_to_move).DeepEquivalent() ==
      destination.DeepEquivalent()) {
    auto* placeholder = MakeGarbageCollected<HTMLBRElement>(GetDocument());
    InsertNodeBefore(placeholder,
                     start_of_paragraph_to_move.DeepEquivalent().AnchorNode(),
                     editing_state);
    if (editing_state->IsAborted())
      return;

    // TODO(editing-dev): Use of UpdateStyleAndLayout()
    // needs to be audited.  See http://crbug.com/590369 for more details.
    GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

    destination = VisiblePosition::BeforeNode(*placeholder);
    start_of_paragraph_to_move = CreateVisiblePosition(
        start_of_paragraph_to_move.ToPositionWithAffinity());
  }

  MoveParagraph(start_of_paragraph_to_move,
                EndOfParagraph(start_of_paragraph_to_move), destination,
                editing_state);
  if (editing_state->IsAborted())
    return;

  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

  // Merging forward will remove end_of_inserted_content from the document.
  if (merge_forward) {
    const VisibleSelection& visible_selection = EndingVisibleSelection();
    if (start_of_inserted_content_.IsOrphan()) {
      start_of_inserted_content_ =
          visible_selection.VisibleStart().DeepEquivalent();
    }
    end_of_inserted_content_ = visible_selection.VisibleEnd().DeepEquivalent();
    // If we merged text nodes, end_of_inserted_content_ could be null. If
    // this is the case, we use start_of_inserted_content_.
    if (end_of_inserted_content_.IsNull())
      end_of_inserted_content_ = start_of_inserted_content_;
  }
}

static Node* EnclosingInline(Node* node) {
  while (ContainerNode* parent = node->parentNode()) {
    if (IsBlockFlowElement(*parent) || IsA<HTMLBodyElement>(*parent))
      return node;
    // Stop if any previous sibling is a block.
    for (Node* sibling = node->previousSibling(); sibling;
         sibling = sibling->previousSibling()) {
      if (IsBlockFlowElement(*sibling))
        return node;
    }
    node = parent;
  }
  return node;
}

static bool IsInlineHTMLElementWithStyle(const Node* node) {
  // We don't want to skip over any block elements.
  if (IsEnclosingBlock(node))
    return false;

  const auto* element = DynamicTo<HTMLElement>(node);
  if (!element)
    return false;

  // We can skip over elements whose class attribute is
  // one of our internal classes.
  return EditingStyle::ElementIsStyledSpanOrHTMLEquivalent(element);
}

static inline HTMLElement*
ElementToSplitToAvoidPastingIntoInlineElementsWithStyle(
    const Position& insertion_pos) {
  Element* containing_block =
      EnclosingBlock(insertion_pos.ComputeContainerNode());
  return To<HTMLElement>(HighestEnclosingNodeOfType(
      insertion_pos, IsInlineHTMLElementWithStyle, kCannotCrossEditingBoundary,
      containing_block));
}

void ReplaceSelectionCommand::SetUpStyle(const VisibleSelection& selection) {
  // We can skip matching the style if the selection is plain text.
  // TODO(editing-dev): Use IsEditablePosition instead of using UserModify
  // directly.
  if ((selection.Start().AnchorNode()->GetLayoutObject() &&
       selection.Start()
               .AnchorNode()
               ->GetLayoutObject()
               ->Style()
               ->UserModify() == EUserModify::kReadWritePlaintextOnly) &&
      (selection.End().AnchorNode()->GetLayoutObject() &&
       selection.End().AnchorNode()->GetLayoutObject()->Style()->UserModify() ==
           EUserModify::kReadWritePlaintextOnly))
    match_style_ = false;

  if (match_style_) {
    insertion_style_ = MakeGarbageCollected<EditingStyle>(selection.Start());
    insertion_style_->MergeTypingStyle(&GetDocument());
  }
}

void ReplaceSelectionCommand::InsertParagraphSeparatorIfNeeds(
    const VisibleSelection& selection,
    const ReplacementFragment& fragment,
    EditingState* editing_state) {
  const VisiblePosition visible_start = selection.VisibleStart();
  const VisiblePosition visible_end = selection.VisibleEnd();

  const bool selection_end_was_end_of_paragraph = IsEndOfParagraph(visible_end);
  const bool selection_start_was_start_of_paragraph =
      IsStartOfParagraph(visible_start);

  Element* const enclosing_block_of_visible_start =
      EnclosingBlock(visible_start.DeepEquivalent().AnchorNode());

  const bool start_is_inside_mail_blockquote = EnclosingNodeOfType(
      selection.Start(), IsMailHTMLBlockquoteElement, kCanCrossEditingBoundary);
  const bool selection_is_plain_text = !IsRichlyEditablePosition(selection.Base());
  Element* const current_root = selection.RootEditableElement();

  if ((selection_start_was_start_of_paragraph &&
       selection_end_was_end_of_paragraph &&
       !start_is_inside_mail_blockquote) ||
      enclosing_block_of_visible_start == current_root ||
      IsListItem(enclosing_block_of_visible_start) || selection_is_plain_text) {
    prevent_nesting_ = false;
  }

  if (selection.IsRange()) {
    // When the end of the selection being pasted into is at the end of a
    // paragraph, and that selection spans multiple blocks, not merging may
    // leave an empty line.
    // When the start of the selection being pasted into is at the start of a
    // block, not merging will leave hanging block(s).
    // Merge blocks if the start of the selection was in a Mail blockquote,
    // since we handle that case specially to prevent nesting.
    bool merge_blocks_after_delete = start_is_inside_mail_blockquote ||
                                     IsEndOfParagraph(visible_end) ||
                                     IsStartOfBlock(visible_start);
    // FIXME: We should only expand to include fully selected special elements
    // if we are copying a selection and pasting it on top of itself.
    if (!DeleteSelection(editing_state, DeleteSelectionOptions::Builder()
                                            .SetMergeBlocksAfterDelete(
                                                merge_blocks_after_delete)
                                            .SetSanitizeMarkup(true)
                                            .Build()))
      return;
    if (fragment.HasInterchangeNewlineAtStart()) {
      GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
      VisiblePosition start_after_delete =
          EndingVisibleSelection().VisibleStart();
      if (IsEndOfParagraph(start_after_delete) &&
          !IsStartOfParagraph(start_after_delete) &&
          !IsEndOfEditableOrNonEditableContent(start_after_delete)) {
        SetEndingSelection(SelectionForUndoStep::From(
            SelectionInDOMTree::Builder()
                .Collapse(NextPositionOf(start_after_delete).DeepEquivalent())
                .Build()));
      } else {
        InsertParagraphSeparator(editing_state);
      }
      if (editing_state->IsAborted())
        return;
    }
  } else {
    DCHECK(selection.IsCaret());
    if (fragment.HasInterchangeNewlineAtStart()) {
      const VisiblePosition next =
          NextPositionOf(visible_start, kCannotCrossEditingBoundary);
      if (IsEndOfParagraph(visible_start) &&
          !IsStartOfParagraph(visible_start) && next.IsNotNull()) {
        SetEndingSelection(
            SelectionForUndoStep::From(SelectionInDOMTree::Builder()
                                           .Collapse(next.DeepEquivalent())
                                           .Build()));
      } else {
        InsertParagraphSeparator(editing_state);
        if (editing_state->IsAborted())
          return;
        GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
      }
    }
    // We split the current paragraph in two to avoid nesting the blocks from
    // the fragment inside the current block.
    //
    // For example, paste
    //   <div>foo</div><div>bar</div><div>baz</div>
    // into
    //   <div>x^x</div>
    // where ^ is the caret.
    //
    // As long as the div styles are the same, visually you'd expect:
    //   <div>xbar</div><div>bar</div><div>bazx</div>
    // not
    //   <div>xbar<div>bar</div><div>bazx</div></div>
    // Don't do this if the selection started in a Mail blockquote.
    const VisiblePosition visible_start_position =
        EndingVisibleSelection().VisibleStart();
    if (prevent_nesting_ && !start_is_inside_mail_blockquote &&
        !IsEndOfParagraph(visible_start_position) &&
        !IsStartOfParagraph(visible_start_position)) {
      InsertParagraphSeparator(editing_state);
      if (editing_state->IsAborted())
        return;
      GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
      SetEndingSelection(SelectionForUndoStep::From(
          SelectionInDOMTree::Builder()
              .Collapse(
                  PreviousPositionOf(EndingVisibleSelection().VisibleStart())
                      .DeepEquivalent())
              .Build()));
    }
  }
}

void ReplaceSelectionCommand::DoApply(EditingState* editing_state) {
  TRACE_EVENT0("blink", "ReplaceSelectionCommand::doApply");
  const VisibleSelection& selection = EndingVisibleSelection();

  // ReplaceSelectionCommandTest.CrashWithNoSelection hits below abort
  // condition.
  ABORT_EDITING_COMMAND_IF(selection.IsNone());
  ABORT_EDITING_COMMAND_IF(!selection.IsValidFor(GetDocument()));

  if (!selection.RootEditableElement())
    return;

  ReplacementFragment fragment(&GetDocument(), document_fragment_.Get(),
                               selection);
  bool trivial_replace_result = PerformTrivialReplace(fragment, editing_state);
  if (editing_state->IsAborted())
    return;
  if (trivial_replace_result)
    return;

  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

  SetUpStyle(selection);
  Element* const current_root = selection.RootEditableElement();
  const bool start_is_inside_mail_blockquote = EnclosingNodeOfType(
      selection.Start(), IsMailHTMLBlockquoteElement, kCanCrossEditingBoundary);
  const bool selection_is_plain_text =
      !IsRichlyEditablePosition(selection.Base());
  const bool selection_end_was_end_of_paragraph =
      IsEndOfParagraph(selection.VisibleEnd());
  const bool selection_start_was_start_of_paragraph =
      IsStartOfParagraph(selection.VisibleStart());
  InsertParagraphSeparatorIfNeeds(selection, fragment, editing_state);
  if (editing_state->IsAborted())
    return;

  Position insertion_pos = EndingVisibleSelection().Start();
  // We don't want any of the pasted content to end up nested in a Mail
  // blockquote, so first break out of any surrounding Mail blockquotes. Unless
  // we're inserting in a table, in which case breaking the blockquote will
  // prevent the content from actually being inserted in the table.
  if (EnclosingNodeOfType(insertion_pos, IsMailHTMLBlockquoteElement,
                          kCanCrossEditingBoundary) &&
      prevent_nesting_ &&
      !(EnclosingNodeOfType(insertion_pos, &IsTableStructureNode))) {
    ApplyCommandToComposite(
        MakeGarbageCollected<BreakBlockquoteCommand>(GetDocument()),
        editing_state);
    if (editing_state->IsAborted())
      return;
    // This will leave a br between the split.
    Node* br = EndingVisibleSelection().Start().AnchorNode();
    DCHECK(IsA<HTMLBRElement>(br)) << br;
    // Insert content between the two blockquotes, but remove the br (since it
    // was just a placeholder).
    insertion_pos = Position::InParentBeforeNode(*br);
    RemoveNode(br, editing_state);
    if (editing_state->IsAborted())
      return;
  }

  // Inserting content could cause whitespace to collapse, e.g. inserting
  // <div>foo</div> into hello^ world.
  PrepareWhitespaceAtPositionForSplit(insertion_pos);

  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

  // If the downstream node has been removed there's no point in continuing.
  if (!MostForwardCaretPosition(insertion_pos).AnchorNode())
    return;

  // NOTE: This would be an incorrect usage of downstream() if downstream() were
  // changed to mean the last position after p that maps to the same visible
  // position as p (since in the case where a br is at the end of a block and
  // collapsed away, there are positions after the br which map to the same
  // visible position as [br, 0]).
  auto* end_br = DynamicTo<HTMLBRElement>(
      *MostForwardCaretPosition(insertion_pos).AnchorNode());
  VisiblePosition original_vis_pos_before_end_br;
  if (end_br) {
    original_vis_pos_before_end_br =
        PreviousPositionOf(VisiblePosition::BeforeNode(*end_br));
  }

  Element* enclosing_block_of_insertion_pos =
      EnclosingBlock(insertion_pos.AnchorNode());

  // Adjust |enclosingBlockOfInsertionPos| to prevent nesting.
  // If the start was in a Mail blockquote, we will have already handled
  // adjusting |enclosingBlockOfInsertionPos| above.
  if (prevent_nesting_ && enclosing_block_of_insertion_pos &&
      enclosing_block_of_insertion_pos != current_root &&
      !IsTableCell(enclosing_block_of_insertion_pos) &&
      !start_is_inside_mail_blockquote) {
    VisiblePosition visible_insertion_pos =
        CreateVisiblePosition(insertion_pos);
    if (IsEndOfBlock(visible_insertion_pos) &&
        !(IsStartOfBlock(visible_insertion_pos) &&
          fragment.HasInterchangeNewlineAtEnd()))
      insertion_pos =
          Position::InParentAfterNode(*enclosing_block_of_insertion_pos);
    else if (IsStartOfBlock(visible_insertion_pos))
      insertion_pos =
          Position::InParentBeforeNode(*enclosing_block_of_insertion_pos);
  }

  // Paste at start or end of link goes outside of link.
  insertion_pos =
      PositionAvoidingSpecialElementBoundary(insertion_pos, editing_state);
  if (editing_state->IsAborted())
    return;

  // FIXME: Can this wait until after the operation has been performed?  There
  // doesn't seem to be any work performed after this that queries or uses the
  // typing style.
  if (LocalFrame* frame = GetDocument().GetFrame())
    frame->GetEditor().ClearTypingStyle();

  RemoveHeadContents(fragment);

  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

  // We don't want the destination to end up inside nodes that weren't selected.
  // To avoid that, we move the position forward without changing the visible
  // position so we're still at the same visible location, but outside of
  // preceding tags.
  insertion_pos = PositionAvoidingPrecedingNodes(insertion_pos);

  // Paste into run of tabs splits the tab span.
  insertion_pos = PositionOutsideTabSpan(insertion_pos);

  HandleStyleSpansBeforeInsertion(fragment, insertion_pos);

  // We're finished if there is nothing to add.
  if (fragment.IsEmpty() || !fragment.FirstChild())
    return;

  // If we are not trying to match the destination style we prefer a position
  // that is outside inline elements that provide style.
  // This way we can produce a less verbose markup.
  // We can skip this optimization for fragments not wrapped in one of
  // our style spans and for positions inside list items
  // since insertAsListItems already does the right thing.
  if (!match_style_ && !EnclosingList(insertion_pos.ComputeContainerNode())) {
    auto* text_node = DynamicTo<Text>(insertion_pos.ComputeContainerNode());
    if (text_node && insertion_pos.OffsetInContainerNode() &&
        !insertion_pos.AtLastEditingPositionForNode()) {
      SplitTextNode(text_node, insertion_pos.OffsetInContainerNode());
      insertion_pos =
          Position::FirstPositionInNode(*insertion_pos.ComputeContainerNode());
    }

    if (HTMLElement* element_to_split_to =
            ElementToSplitToAvoidPastingIntoInlineElementsWithStyle(
                insertion_pos)) {
      if (insertion_pos.ComputeContainerNode() !=
          element_to_split_to->parentNode()) {
        Node* split_start = insertion_pos.ComputeNodeAfterPosition();
        if (!split_start)
          split_start = insertion_pos.ComputeContainerNode();
        Node* node_to_split_to =
            SplitTreeToNode(split_start, element_to_split_to->parentNode());
        insertion_pos = Position::InParentBeforeNode(*node_to_split_to);
      }
    }
  }

  // FIXME: When pasting rich content we're often prevented from heading down
  // the fast path by style spans.  Try again here if they've been removed.

  // 1) Insert the content.
  // 2) Remove redundant styles and style tags, this inner <b> for example:
  // <b>foo <b>bar</b> baz</b>.
  // 3) Merge the start of the added content with the content before the
  //    position being pasted into.
  // 4) Do one of the following:
  //    a) expand the last br if the fragment ends with one and it collapsed,
  //    b) merge the last paragraph of the incoming fragment with the paragraph
  //       that contained the end of the selection that was pasted into, or
  //    c) handle an interchange newline at the end of the incoming fragment.
  // 5) Add spaces for smart replace.
  // 6) Select the replacement if requested, and match style if requested.

  InsertedNodes inserted_nodes;
  inserted_nodes.SetRefNode(fragment.FirstChild());
  DCHECK(inserted_nodes.RefNode());
  Node* node = inserted_nodes.RefNode()->nextSibling();

  fragment.RemoveNode(inserted_nodes.RefNode());

  Element* block_start = EnclosingBlock(insertion_pos.AnchorNode());
  if ((IsHTMLListElement(inserted_nodes.RefNode()) ||
       (IsHTMLListElement(inserted_nodes.RefNode()->firstChild()))) &&
      block_start && block_start->GetLayoutObject()->IsListItemIncludingNG() &&
      HasEditableStyle(*block_start->parentNode())) {
    inserted_nodes.SetRefNode(InsertAsListItems(
        To<HTMLElement>(inserted_nodes.RefNode()), block_start, insertion_pos,
        inserted_nodes, editing_state));
    if (editing_state->IsAborted())
      return;
  } else {
    InsertNodeAt(inserted_nodes.RefNode(), insertion_pos, editing_state);
    if (editing_state->IsAborted())
      return;
    inserted_nodes.RespondToNodeInsertion(*inserted_nodes.RefNode());
  }

  // Mutation events (bug 22634) may have already removed the inserted content
  if (!inserted_nodes.RefNode()->isConnected())
    return;

  bool plain_text_fragment = IsPlainTextMarkup(inserted_nodes.RefNode());

  while (node) {
    Node* next = node->nextSibling();
    fragment.RemoveNode(node);
    InsertNodeAfter(node, inserted_nodes.RefNode(), editing_state);
    if (editing_state->IsAborted())
      return;
    inserted_nodes.RespondToNodeInsertion(*node);

    // Mutation events (bug 22634) may have already removed the inserted content
    if (!node->isConnected())
      return;

    inserted_nodes.SetRefNode(node);
    if (node && plain_text_fragment)
      plain_text_fragment = IsPlainTextMarkup(node);
    node = next;
  }

  if (IsRichlyEditablePosition(insertion_pos)) {
    RemoveUnrenderedTextNodesAtEnds(inserted_nodes);
    ABORT_EDITING_COMMAND_IF(!inserted_nodes.RefNode());
  }

  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

  // Mutation events (bug 20161) may have already removed the inserted content
  if (!inserted_nodes.FirstNodeInserted() ||
      !inserted_nodes.FirstNodeInserted()->isConnected())
    return;

  // Scripts specified in javascript protocol may remove
  // |enclosingBlockOfInsertionPos| during insertion, e.g. <iframe
  // src="javascript:...">
  if (enclosing_block_of_insertion_pos &&
      !enclosing_block_of_insertion_pos->isConnected())
    enclosing_block_of_insertion_pos = nullptr;

  VisiblePosition start_of_inserted_content = CreateVisiblePosition(
      FirstPositionInOrBeforeNode(*inserted_nodes.FirstNodeInserted()));

  // We inserted before the enclosingBlockOfInsertionPos to prevent nesting, and
  // the content before the enclosingBlockOfInsertionPos wasn't in its own block
  // and didn't have a br after it, so the inserted content ended up in the same
  // paragraph.
  if (!start_of_inserted_content.IsNull() && enclosing_block_of_insertion_pos &&
      insertion_pos.AnchorNode() ==
          enclosing_block_of_insertion_pos->parentNode() &&
      (unsigned)insertion_pos.ComputeEditingOffset() <
          enclosing_block_of_insertion_pos->NodeIndex() &&
      !IsStartOfParagraph(start_of_inserted_content)) {
    InsertNodeAt(MakeGarbageCollected<HTMLBRElement>(GetDocument()),
                 start_of_inserted_content.DeepEquivalent(), editing_state);
    if (editing_state->IsAborted())
      return;
  }

  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
  if (end_br &&
      (plain_text_fragment ||
       (ShouldRemoveEndBR(end_br, original_vis_pos_before_end_br) &&
        !(fragment.HasInterchangeNewlineAtEnd() && selection_is_plain_text)))) {
    ContainerNode* parent = end_br->parentNode();
    inserted_nodes.WillRemoveNode(*end_br);
    ABORT_EDITING_COMMAND_IF(!inserted_nodes.RefNode());
    RemoveNode(end_br, editing_state);
    if (editing_state->IsAborted())
      return;
    if (Node* node_to_remove = HighestNodeToRemoveInPruning(parent)) {
      inserted_nodes.WillRemoveNode(*node_to_remove);
      ABORT_EDITING_COMMAND_IF(!inserted_nodes.RefNode());
      RemoveNode(node_to_remove, editing_state);
      if (editing_state->IsAborted())
        return;
    }
  }

  MakeInsertedContentRoundTrippableWithHTMLTreeBuilder(inserted_nodes,
                                                       editing_state);
  if (editing_state->IsAborted())
    return;

  {
    // TODO(dominicc): refNode may not be connected, for example in
    // web_tests/editing/inserting/insert-table-in-paragraph-crash.html .
    // Refactor this so there's a relationship between the conditions
    // where refNode is dereferenced and refNode is connected.
    bool ref_node_was_connected = inserted_nodes.RefNode()->isConnected();
    RemoveRedundantStylesAndKeepStyleSpanInline(inserted_nodes, editing_state);
    if (editing_state->IsAborted())
      return;
    DCHECK_EQ(inserted_nodes.RefNode()->isConnected(), ref_node_was_connected)
        << inserted_nodes.RefNode();
  }

  if (sanitize_fragment_ && inserted_nodes.FirstNodeInserted()) {
    ApplyCommandToComposite(
        MakeGarbageCollected<SimplifyMarkupCommand>(
            GetDocument(), inserted_nodes.FirstNodeInserted(),
            inserted_nodes.PastLastLeaf()),
        editing_state);
    if (editing_state->IsAborted())
      return;
  }

  // Setup |start_of_inserted_content_| and |end_of_inserted_content_|.
  // This should be the last two lines of code that access insertedNodes.
  // TODO(editing-dev): The {First,Last}NodeInserted() nullptr checks may be
  // unnecessary. Investigate.
  start_of_inserted_content_ =
      inserted_nodes.FirstNodeInserted()
          ? FirstPositionInOrBeforeNode(*inserted_nodes.FirstNodeInserted())
          : Position();
  end_of_inserted_content_ =
      inserted_nodes.LastLeafInserted()
          ? LastPositionInOrAfterNode(*inserted_nodes.LastLeafInserted())
          : Position();

  // Determine whether or not we should merge the end of inserted content with
  // what's after it before we do the start merge so that the start merge
  // doesn't effect our decision.
  should_merge_end_ = ShouldMergeEnd(selection_end_was_end_of_paragraph);

  if (ShouldMergeStart(selection_start_was_start_of_paragraph,
                       fragment.HasInterchangeNewlineAtStart(),
                       start_is_inside_mail_blockquote)) {
    VisiblePosition start_of_paragraph_to_move =
        PositionAtStartOfInsertedContent();
    VisiblePosition destination =
        PreviousPositionOf(start_of_paragraph_to_move);

    // Helpers for making the VisiblePositions valid again after DOM changes.
    PositionWithAffinity start_of_paragraph_to_move_position =
        start_of_paragraph_to_move.ToPositionWithAffinity();
    PositionWithAffinity destination_position =
        destination.ToPositionWithAffinity();

    // We need to handle the case where we need to merge the end
    // but our destination node is inside an inline that is the last in the
    // block.
    // We insert a placeholder before the newly inserted content to avoid being
    // merged into the inline.
    Node* destination_node = destination.DeepEquivalent().AnchorNode();
    if (should_merge_end_ &&
        destination_node != EnclosingInline(destination_node) &&
        EnclosingInline(destination_node)->nextSibling()) {
      InsertNodeBefore(MakeGarbageCollected<HTMLBRElement>(GetDocument()),
                       inserted_nodes.RefNode(), editing_state);
      if (editing_state->IsAborted())
        return;
    }

    // Merging the the first paragraph of inserted content with the content that
    // came before the selection that was pasted into would also move content
    // after the selection that was pasted into if: only one paragraph was being
    // pasted, and it was not wrapped in a block, the selection that was pasted
    // into ended at the end of a block and the next paragraph didn't start at
    // the start of a block.
    // Insert a line break just after the inserted content to separate it from
    // what comes after and prevent that from happening.
    VisiblePosition end_of_inserted_content = PositionAtEndOfInsertedContent();
    if (StartOfParagraph(end_of_inserted_content).DeepEquivalent() ==
        start_of_paragraph_to_move_position.GetPosition()) {
      InsertNodeAt(MakeGarbageCollected<HTMLBRElement>(GetDocument()),
                   end_of_inserted_content.DeepEquivalent(), editing_state);
      if (editing_state->IsAborted())
        return;
      // Mutation events (bug 22634) triggered by inserting the <br> might have
      // removed the content we're about to move
      if (!start_of_paragraph_to_move_position.IsConnected())
        return;
    }

    GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

    // Making the two VisiblePositions valid again.
    start_of_paragraph_to_move =
        CreateVisiblePosition(start_of_paragraph_to_move_position);
    destination = CreateVisiblePosition(destination_position);

    // FIXME: Maintain positions for the start and end of inserted content
    // instead of keeping nodes.  The nodes are only ever used to create
    // positions where inserted content starts/ends.
    MoveParagraph(start_of_paragraph_to_move,
                  EndOfParagraph(start_of_paragraph_to_move), destination,
                  editing_state);
    if (editing_state->IsAborted())
      return;

    GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
    const VisibleSelection& visible_selection_of_insterted_content =
        EndingVisibleSelection();
    start_of_inserted_content_ = MostForwardCaretPosition(
        visible_selection_of_insterted_content.VisibleStart().DeepEquivalent());
    if (end_of_inserted_content_.IsOrphan()) {
      end_of_inserted_content_ = MostBackwardCaretPosition(
          visible_selection_of_insterted_content.VisibleEnd().DeepEquivalent());
    }
  }

  Position last_position_to_select;
  if (fragment.HasInterchangeNewlineAtEnd()) {
    VisiblePosition end_of_inserted_content = PositionAtEndOfInsertedContent();
    VisiblePosition next =
        NextPositionOf(end_of_inserted_content, kCannotCrossEditingBoundary);

    if (selection_end_was_end_of_paragraph ||
        !IsEndOfParagraph(end_of_inserted_content) || next.IsNull()) {
      if (TextControlElement* text_control =
              EnclosingTextControl(current_root)) {
        if (!inserted_nodes.LastLeafInserted()->nextSibling()) {
          InsertNodeAfter(text_control->CreatePlaceholderBreakElement(),
                          inserted_nodes.LastLeafInserted(), editing_state);
          if (editing_state->IsAborted())
            return;
        }
        SetEndingSelection(SelectionForUndoStep::From(
            SelectionInDOMTree::Builder()
                .Collapse(
                    Position::AfterNode(*inserted_nodes.LastLeafInserted()))
                .Build()));
        // Select up to the paragraph separator that was added.
        last_position_to_select =
            EndingVisibleSelection().VisibleStart().DeepEquivalent();
      } else if (!IsStartOfParagraph(end_of_inserted_content)) {
        SetEndingSelection(SelectionForUndoStep::From(
            SelectionInDOMTree::Builder()
                .Collapse(end_of_inserted_content.DeepEquivalent())
                .Build()));
        Element* enclosing_block_element = EnclosingBlock(
            end_of_inserted_content.DeepEquivalent().AnchorNode());
        if (IsListItem(enclosing_block_element)) {
          auto* new_list_item =
              MakeGarbageCollected<HTMLLIElement>(GetDocument());
          InsertNodeAfter(new_list_item, enclosing_block_element,
                          editing_state);
          if (editing_state->IsAborted())
            return;
          SetEndingSelection(SelectionForUndoStep::From(
              SelectionInDOMTree::Builder()
                  .Collapse(Position::FirstPositionInNode(*new_list_item))
                  .Build()));
        } else {
          // Use a default paragraph element (a plain div) for the empty
          // paragraph, using the last paragraph block's style seems to annoy
          // users.
          InsertParagraphSeparator(
              editing_state, true,
              !start_is_inside_mail_blockquote &&
                  HighestEnclosingNodeOfType(
                      end_of_inserted_content.DeepEquivalent(),
                      IsMailHTMLBlockquoteElement, kCannotCrossEditingBoundary,
                      inserted_nodes.FirstNodeInserted()->parentNode()));
          if (editing_state->IsAborted())
            return;
        }

        GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

        // Select up to the paragraph separator that was added.
        last_position_to_select =
            EndingVisibleSelection().VisibleStart().DeepEquivalent();
        UpdateNodesInserted(last_position_to_select.AnchorNode());
      }
    } else {
      // Select up to the beginning of the next paragraph.
      last_position_to_select = MostForwardCaretPosition(next.DeepEquivalent());
    }
  } else {
    MergeEndIfNeeded(editing_state);
    if (editing_state->IsAborted())
      return;
  }

  if (ShouldPerformSmartReplace()) {
    AddSpacesForSmartReplace(editing_state);
    if (editing_state->IsAborted())
      return;
  }

  // If we are dealing with a fragment created from plain text
  // no style matching is necessary.
  if (plain_text_fragment)
    match_style_ = false;

  CompleteHTMLReplacement(last_position_to_select, editing_state);
}

bool ReplaceSelectionCommand::ShouldRemoveEndBR(
    HTMLBRElement* end_br,
    const VisiblePosition& original_vis_pos_before_end_br) {
  if (!end_br || !end_br->isConnected())
    return false;

  VisiblePosition visible_pos = VisiblePosition::BeforeNode(*end_br);

  // Don't remove the br if nothing was inserted.
  if (PreviousPositionOf(visible_pos).DeepEquivalent() ==
      original_vis_pos_before_end_br.DeepEquivalent())
    return false;

  // Remove the br if it is collapsed away and so is unnecessary.
  if (!GetDocument().InNoQuirksMode() && IsEndOfBlock(visible_pos) &&
      !IsStartOfParagraph(visible_pos))
    return true;

  // A br that was originally holding a line open should be displaced by
  // inserted content or turned into a line break.
  // A br that was originally acting as a line break should still be acting as a
  // line break, not as a placeholder.
  return IsStartOfParagraph(visible_pos) && IsEndOfParagraph(visible_pos);
}

bool ReplaceSelectionCommand::ShouldPerformSmartReplace() const {
  if (!smart_replace_)
    return false;

  TextControlElement* text_control =
      EnclosingTextControl(PositionAtStartOfInsertedContent().DeepEquivalent());
  auto* html_input_element = DynamicTo<HTMLInputElement>(text_control);
  if (html_input_element &&
      html_input_element->type() == input_type_names::kPassword)
    return false;  // Disable smart replace for password fields.

  return true;
}

static bool IsCharacterSmartReplaceExemptConsideringNonBreakingSpace(
    UChar32 character,
    bool previous_character) {
  return IsCharacterSmartReplaceExempt(
      character == kNoBreakSpaceCharacter ? ' ' : character,
      previous_character);
}

void ReplaceSelectionCommand::AddSpacesForSmartReplace(
    EditingState* editing_state) {
  VisiblePosition end_of_inserted_content = PositionAtEndOfInsertedContent();
  Position end_upstream =
      MostBackwardCaretPosition(end_of_inserted_content.DeepEquivalent());
  Node* end_node = end_upstream.ComputeNodeBeforePosition();
  auto* end_text_node = DynamicTo<Text>(end_node);
  int end_offset = end_text_node ? end_text_node->length() : 0;
  if (end_upstream.IsOffsetInAnchor()) {
    end_node = end_upstream.ComputeContainerNode();
    end_offset = end_upstream.OffsetInContainerNode();
  }

  bool needs_trailing_space =
      !IsEndOfParagraph(end_of_inserted_content) &&
      !IsCharacterSmartReplaceExemptConsideringNonBreakingSpace(
          CharacterAfter(end_of_inserted_content), false);
  if (needs_trailing_space && end_node) {
    bool collapse_white_space =
        !end_node->GetLayoutObject() ||
        end_node->GetLayoutObject()->Style()->CollapseWhiteSpace();
    end_text_node = DynamicTo<Text>(end_node);
    if (end_text_node) {
      InsertTextIntoNode(end_text_node, end_offset,
                         collapse_white_space ? NonBreakingSpaceString() : " ");
      if (end_of_inserted_content_.ComputeContainerNode() == end_node)
        end_of_inserted_content_ = Position(
            end_node, end_of_inserted_content_.OffsetInContainerNode() + 1);
    } else {
      Text* node = GetDocument().CreateEditingTextNode(
          collapse_white_space ? NonBreakingSpaceString() : " ");
      InsertNodeAfter(node, end_node, editing_state);
      if (editing_state->IsAborted())
        return;
      // Make sure that |UpdateNodesInserted| does not change
      // |start_of_inserted_content|.
      DCHECK(start_of_inserted_content_.IsNotNull());
      UpdateNodesInserted(node);
    }
  }

  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

  VisiblePosition start_of_inserted_content =
      PositionAtStartOfInsertedContent();
  Position start_downstream =
      MostForwardCaretPosition(start_of_inserted_content.DeepEquivalent());
  Node* start_node = start_downstream.ComputeNodeAfterPosition();
  unsigned start_offset = 0;
  if (start_downstream.IsOffsetInAnchor()) {
    start_node = start_downstream.ComputeContainerNode();
    start_offset = start_downstream.OffsetInContainerNode();
  }

  bool needs_leading_space =
      !IsStartOfParagraph(start_of_inserted_content) &&
      !IsCharacterSmartReplaceExemptConsideringNonBreakingSpace(
          CharacterBefore(start_of_inserted_content), true);
  if (needs_leading_space && start_node) {
    bool collapse_white_space =
        !start_node->GetLayoutObject() ||
        start_node->GetLayoutObject()->Style()->CollapseWhiteSpace();
    if (auto* start_text_node = DynamicTo<Text>(start_node)) {
      InsertTextIntoNode(start_text_node, start_offset,
                         collapse_white_space ? NonBreakingSpaceString() : " ");
      if (end_of_inserted_content_.ComputeContainerNode() == start_node &&
          end_of_inserted_content_.OffsetInContainerNode())
        end_of_inserted_content_ = Position(
            start_node, end_of_inserted_content_.OffsetInContainerNode() + 1);
    } else {
      Text* node = GetDocument().CreateEditingTextNode(
          collapse_white_space ? NonBreakingSpaceString() : " ");
      // Don't UpdateNodesInserted. Doing so would set end_of_inserted_content_
      // to be the node containing the leading space, but
      // end_of_inserted_content_ issupposed to mark the end of pasted content.
      InsertNodeBefore(node, start_node, editing_state);
      if (editing_state->IsAborted())
        return;
      start_of_inserted_content_ = Position::FirstPositionInNode(*node);
    }
  }
}

void ReplaceSelectionCommand::CompleteHTMLReplacement(
    const Position& last_position_to_select,
    EditingState* editing_state) {
  Position start = PositionAtStartOfInsertedContent().DeepEquivalent();
  Position end = PositionAtEndOfInsertedContent().DeepEquivalent();

  // Mutation events may have deleted start or end
  if (start.IsNotNull() && !start.IsOrphan() && end.IsNotNull() &&
      !end.IsOrphan()) {
    // FIXME (11475): Remove this and require that the creator of the fragment
    // to use nbsps.
    RebalanceWhitespaceAt(start);
    RebalanceWhitespaceAt(end);

    if (match_style_) {
      DCHECK(insertion_style_);
      // Since |ApplyStyle()| changes contents of anchor node of |start| and
      // |end|, we should relocate them.
      auto* const range =
          MakeGarbageCollected<Range>(GetDocument(), start, end);
      ApplyStyle(insertion_style_.Get(), start, end, editing_state);
      start = range->StartPosition();
      end = range->EndPosition();
      range->Dispose();
      if (editing_state->IsAborted())
        return;
    }

    if (last_position_to_select.IsNotNull())
      end = last_position_to_select;

    MergeTextNodesAroundPosition(start, end, editing_state);
    if (editing_state->IsAborted())
      return;
  } else if (last_position_to_select.IsNotNull()) {
    start = end = last_position_to_select;
  } else {
    return;
  }

  start_of_inserted_range_ = start;
  end_of_inserted_range_ = end;

  if (select_replacement_) {
    SetEndingSelection(SelectionForUndoStep::From(
        SelectionInDOMTree::Builder()
            .SetBaseAndExtentDeprecated(start, end)
            .Build()));
    return;
  }

  if (end.IsNotNull()) {
    SetEndingSelection(SelectionForUndoStep::From(
        SelectionInDOMTree::Builder()
            .Collapse(end)
            .Build()));
    return;
  }
  SetEndingSelection(SelectionForUndoStep());
}

void ReplaceSelectionCommand::MergeTextNodesAroundPosition(
    Position& position,
    Position& position_only_to_be_updated,
    EditingState* editing_state) {
  bool position_is_offset_in_anchor = position.IsOffsetInAnchor();
  bool position_only_to_be_updated_is_offset_in_anchor =
      position_only_to_be_updated.IsOffsetInAnchor();
  Text* text = nullptr;
  auto* container_text_node = DynamicTo<Text>(position.ComputeContainerNode());
  if (position_is_offset_in_anchor && container_text_node) {
    text = container_text_node;
  } else if (auto* before =
                 DynamicTo<Text>(position.ComputeNodeBeforePosition())) {
    text = before;
  } else if (auto* after =
                 DynamicTo<Text>(position.ComputeNodeAfterPosition())) {
    text = after;
  }

  if (!text)
    return;

  // Merging Text nodes causes an additional layout. We'd like to skip it if the
  // editable text is huge.
  // TODO(tkent): 1024 was chosen by my intuition.  We need data.
  const unsigned kMergeSizeLimit = 1024;
  bool has_incomplete_surrogate =
      text->data().length() >= 1 &&
      (U16_IS_TRAIL(text->data()[0]) ||
       U16_IS_LEAD(text->data()[text->data().length() - 1]));
  if (!has_incomplete_surrogate && text->data().length() > kMergeSizeLimit)
    return;
  if (auto* previous = DynamicTo<Text>(text->previousSibling())) {
    if (has_incomplete_surrogate ||
        previous->data().length() <= kMergeSizeLimit) {
      InsertTextIntoNode(text, 0, previous->data());

      if (position_is_offset_in_anchor) {
        position =
            Position(position.ComputeContainerNode(),
                     previous->length() + position.OffsetInContainerNode());
      } else {
        position = ComputePositionForNodeRemoval(position, *previous);
      }

      if (position_only_to_be_updated_is_offset_in_anchor) {
        if (position_only_to_be_updated.ComputeContainerNode() == text)
          position_only_to_be_updated = Position(
              text, previous->length() +
                        position_only_to_be_updated.OffsetInContainerNode());
        else if (position_only_to_be_updated.ComputeContainerNode() == previous)
          position_only_to_be_updated = Position(
              text, position_only_to_be_updated.OffsetInContainerNode());
      } else {
        position_only_to_be_updated = ComputePositionForNodeRemoval(
            position_only_to_be_updated, *previous);
      }

      RemoveNode(previous, editing_state);
      if (editing_state->IsAborted())
        return;
    }
  }
  if (auto* next = DynamicTo<Text>(text->nextSibling())) {
    if (!has_incomplete_surrogate && next->data().length() > kMergeSizeLimit)
      return;
    unsigned original_length = text->length();
    InsertTextIntoNode(text, original_length, next->data());

    if (!position_is_offset_in_anchor)
      position = ComputePositionForNodeRemoval(position, *next);

    if (position_only_to_be_updated_is_offset_in_anchor &&
        position_only_to_be_updated.ComputeContainerNode() == next) {
      position_only_to_be_updated = Position(
          text, original_length +
                    position_only_to_be_updated.OffsetInContainerNode());
    } else {
      position_only_to_be_updated =
          ComputePositionForNodeRemoval(position_only_to_be_updated, *next);
    }

    RemoveNode(next, editing_state);
    if (editing_state->IsAborted())
      return;
  }
}

InputEvent::InputType ReplaceSelectionCommand::GetInputType() const {
  // |ReplaceSelectionCommand| could be used with Paste, Drag&Drop,
  // InsertFragment and |TypingCommand|.
  // 1. Paste, Drag&Drop, InsertFragment should rely on correct |input_type_|.
  // 2. |TypingCommand| will supply the |GetInputType()|, so |input_type_| could
  //    default to |InputType::kNone|.
  return input_type_;
}

// If the user is inserting a list into an existing list, instead of nesting the
// list, we put the list items into the existing list.
Node* ReplaceSelectionCommand::InsertAsListItems(HTMLElement* list_element,
                                                 Element* insertion_block,
                                                 const Position& insert_pos,
                                                 InsertedNodes& inserted_nodes,
                                                 EditingState* editing_state) {
  while (list_element->HasOneChild() &&
         IsHTMLListElement(list_element->firstChild()))
    list_element = To<HTMLElement>(list_element->firstChild());

  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
  bool is_start = IsStartOfParagraph(CreateVisiblePosition(insert_pos));
  bool is_end = IsEndOfParagraph(CreateVisiblePosition(insert_pos));
  bool is_middle = !is_start && !is_end;
  Node* last_node = insertion_block;

  // If we're in the middle of a list item, we should split it into two separate
  // list items and insert these nodes between them.
  if (is_middle) {
    int text_node_offset = insert_pos.OffsetInContainerNode();
    auto* text_node = DynamicTo<Text>(insert_pos.AnchorNode());
    if (text_node && text_node_offset > 0)
      SplitTextNode(text_node, text_node_offset);
    SplitTreeToNode(insert_pos.AnchorNode(), last_node, true);
  }

  while (Node* list_item = list_element->firstChild()) {
    list_element->RemoveChild(list_item, ASSERT_NO_EXCEPTION);
    if (is_start || is_middle) {
      InsertNodeBefore(list_item, last_node, editing_state);
      if (editing_state->IsAborted())
        return nullptr;
      inserted_nodes.RespondToNodeInsertion(*list_item);
    } else if (is_end) {
      InsertNodeAfter(list_item, last_node, editing_state);
      if (editing_state->IsAborted())
        return nullptr;
      inserted_nodes.RespondToNodeInsertion(*list_item);
      last_node = list_item;
    } else {
      NOTREACHED();
    }
  }
  if (is_start || is_middle) {
    if (Node* node = last_node->previousSibling())
      return node;
  }
  return last_node;
}

void ReplaceSelectionCommand::UpdateNodesInserted(Node* node) {
  if (!node)
    return;

  if (start_of_inserted_content_.IsNull())
    start_of_inserted_content_ = FirstPositionInOrBeforeNode(*node);

  end_of_inserted_content_ =
      LastPositionInOrAfterNode(NodeTraversal::LastWithinOrSelf(*node));
}

// During simple pastes, where we're just pasting a text node into a run of
// text, we insert the text node directly into the text node that holds the
// selection.  This is much faster than the generalized code in
// ReplaceSelectionCommand, and works around
// <https://bugs.webkit.org/show_bug.cgi?id=6148> since we don't split text
// nodes.
bool ReplaceSelectionCommand::PerformTrivialReplace(
    const ReplacementFragment& fragment,
    EditingState* editing_state) {
  if (!fragment.FirstChild() || fragment.FirstChild() != fragment.LastChild() ||
      !fragment.FirstChild()->IsTextNode())
    return false;

  // FIXME: Would be nice to handle smart replace in the fast path.
  if (smart_replace_ || fragment.HasInterchangeNewlineAtStart() ||
      fragment.HasInterchangeNewlineAtEnd())
    return false;

  // e.g. when "bar" is inserted after "foo" in <div><u>foo</u></div>, "bar"
  // should not be underlined.
  if (ElementToSplitToAvoidPastingIntoInlineElementsWithStyle(
          EndingVisibleSelection().Start()))
    return false;

  // TODO(editing-dev): Use of UpdateStyleAndLayout
  // needs to be audited.  See http://crbug.com/590369 for more details.
  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

  Node* node_after_insertion_pos =
      MostForwardCaretPosition(EndingSelection().End()).AnchorNode();
  auto* text_node = To<Text>(fragment.FirstChild());
  // Our fragment creation code handles tabs, spaces, and newlines, so we don't
  // have to worry about those here.

  Position start = EndingVisibleSelection().Start();
  Position end = ReplaceSelectedTextInNode(text_node->data());
  if (end.IsNull())
    return false;

  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);

  if (node_after_insertion_pos && node_after_insertion_pos->parentNode() &&
      IsA<HTMLBRElement>(*node_after_insertion_pos) &&
      ShouldRemoveEndBR(
          To<HTMLBRElement>(node_after_insertion_pos),
          VisiblePosition::BeforeNode(*node_after_insertion_pos))) {
    RemoveNodeAndPruneAncestors(node_after_insertion_pos, editing_state);
    if (editing_state->IsAborted())
      return false;
  }

  start_of_inserted_range_ = start;
  end_of_inserted_range_ = end;

  SetEndingSelection(SelectionForUndoStep::From(
      SelectionInDOMTree::Builder()
          .SetBaseAndExtentDeprecated(select_replacement_ ? start : end, end)
          .Build()));

  return true;
}

bool ReplaceSelectionCommand::IsReplaceSelectionCommand() const {
  return true;
}

EphemeralRange ReplaceSelectionCommand::InsertedRange() const {
  return EphemeralRange(start_of_inserted_range_, end_of_inserted_range_);
}

void ReplaceSelectionCommand::Trace(Visitor* visitor) const {
  visitor->Trace(start_of_inserted_content_);
  visitor->Trace(end_of_inserted_content_);
  visitor->Trace(insertion_style_);
  visitor->Trace(document_fragment_);
  visitor->Trace(start_of_inserted_range_);
  visitor->Trace(end_of_inserted_range_);
  CompositeEditCommand::Trace(visitor);
}

}  // namespace blink
