| Index: third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp | 
| diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp | 
| index e4bf6aeffaf43c2e7c4fd68178a07ba42be38811..d786b02ab5eebd5ae8879c4176be1b47d3fc8830 100644 | 
| --- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp | 
| +++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp | 
| @@ -6,10 +6,13 @@ | 
|  | 
| #include <algorithm> | 
| #include "core/dom/FirstLetterPseudoElement.h" | 
| +#include "core/editing/VisibleUnits.h" | 
| #include "core/editing/iterators/TextIteratorTextState.h" | 
| #include "core/layout/LayoutTextFragment.h" | 
| #include "core/layout/line/InlineTextBox.h" | 
| #include "core/layout/line/RootInlineBox.h" | 
| +#include "core/layout/ng/inline/ng_inline_node.h" | 
| +#include "core/layout/ng/layout_ng_block_flow.h" | 
|  | 
| namespace blink { | 
|  | 
| @@ -24,6 +27,11 @@ DEFINE_TRACE(TextIteratorTextNodeHandler) { | 
| } | 
|  | 
| bool TextIteratorTextNodeHandler::HandleRemainingTextRuns() { | 
| +  if (ng_block_flow_) { | 
| +    HandleTextNodeInNGBlockFlow(*ng_block_flow_); | 
| +    return text_state_->PositionNode(); | 
| +  } | 
| + | 
| if (ShouldProceedToRemainingText()) | 
| ProceedToRemainingText(); | 
| // Handle remembered text box | 
| @@ -120,18 +128,62 @@ void TextIteratorTextNodeHandler::HandlePreFormattedTextNode() { | 
| EmitText(text_node_, text_node_->GetLayoutObject(), run_start, run_end); | 
| } | 
|  | 
| +void TextIteratorTextNodeHandler::HandleTextNodeInNGBlockFlow( | 
| +    const LayoutNGBlockFlow& block) { | 
| +  if (block != ng_block_flow_) { | 
| +    mapping_result_ = NGInlineNode(const_cast<LayoutNGBlockFlow*>(&block)) | 
| +                          .BuildOffsetMapping(); | 
| +    ng_block_flow_ = █ | 
| +  } | 
| + | 
| +  const LayoutObject* layout_object = | 
| +      AssociatedLayoutObjectOf(*text_node_, offset_); | 
| + | 
| +  // Skip invisible content. | 
| +  if (layout_object->Style()->Display() == EDisplay::kNone || | 
| +      (layout_object->Style()->Visibility() != EVisibility::kVisible && | 
| +       !IgnoresStyleVisibility())) { | 
| +    offset_ = end_offset_; | 
| +    return; | 
| +  } | 
| + | 
| +  while (offset_ < end_offset_ && !text_state_->PositionNode()) { | 
| +    const NGOffsetMappingUnit* unit = | 
| +        mapping_result_.GetMappingUnitForDOMOffset(*text_node_, offset_); | 
| +    // No more text on this node to emit. | 
| +    if (!unit || static_cast<unsigned>(offset_) == unit->dom_end) { | 
| +      offset_ = end_offset_; | 
| +      return; | 
| +    } | 
| + | 
| +    const unsigned run_end = | 
| +        std::min(static_cast<unsigned>(end_offset_), unit->dom_end); | 
| +    if (unit->type == NGOffsetMappingUnitType::kCollapsed) { | 
| +      offset_ = run_end; | 
| +      continue; | 
| +    } | 
| + | 
| +    // TODO(xiaochengh): Handle EmitsOriginalText. | 
| + | 
| +    String string = | 
| +        NGInlineNode(const_cast<LayoutNGBlockFlow*>(ng_block_flow_)).Text(); | 
| +    if (behavior_.EmitsSpaceForNbsp()) | 
| +      string.Replace(kNoBreakSpaceCharacter, kSpaceCharacter); | 
| +    const unsigned text_content_start = unit->DOMToTextContentOffset(offset_); | 
| +    const unsigned text_content_end = unit->DOMToTextContentOffset(run_end); | 
| +    text_state_->EmitText(text_node_, offset_, run_end, string, | 
| +                          text_content_start, text_content_end); | 
| +    offset_ = run_end; | 
| +    return; | 
| +  } | 
| +} | 
| + | 
| void TextIteratorTextNodeHandler::HandleTextNodeInRange(Text* node, | 
| int start_offset, | 
| int end_offset) { | 
| DCHECK(node); | 
| DCHECK_GE(start_offset, 0); | 
| - | 
| -  // TODO(editing-dev): Add the following DCHECK once we stop assuming equal | 
| -  // number of code units in DOM string and LayoutText::GetText(). Currently | 
| -  // violated by | 
| -  // - external/wpt/innerText/getter.html | 
| -  // - fast/css/case-transform.html | 
| -  // DCHECK_LE(end_offset, static_cast<int>(node->data().length())); | 
| +  DCHECK_LE(end_offset, static_cast<int>(node->data().length())); | 
|  | 
| // TODO(editing-dev): Stop passing in |start_offset == end_offset|. | 
| DCHECK_LE(start_offset, end_offset); | 
| @@ -143,6 +195,13 @@ void TextIteratorTextNodeHandler::HandleTextNodeInRange(Text* node, | 
| first_letter_text_ = nullptr; | 
|  | 
| LayoutText* layout_object = text_node_->GetLayoutObject(); | 
| +  const LayoutBox* enclosing_box = layout_object->EnclosingBox(); | 
| +  if (enclosing_box && enclosing_box->IsLayoutNGBlockFlow()) { | 
| +    HandleTextNodeInNGBlockFlow(ToLayoutNGBlockFlow(*enclosing_box)); | 
| +    return; | 
| +  } | 
| +  ng_block_flow_ = nullptr; | 
| + | 
| String str = layout_object->GetText(); | 
|  | 
| // handle pre-formatted text | 
| @@ -189,9 +248,7 @@ void TextIteratorTextNodeHandler::HandleTextNodeInRange(Text* node, | 
|  | 
| void TextIteratorTextNodeHandler::HandleTextNodeStartFrom(Text* node, | 
| int start_offset) { | 
| -  HandleTextNodeInRange(node, start_offset, | 
| -                        node->GetLayoutObject()->TextStartOffset() + | 
| -                            node->GetLayoutObject()->GetText().length()); | 
| +  HandleTextNodeInRange(node, start_offset, node->data().length()); | 
| } | 
|  | 
| void TextIteratorTextNodeHandler::HandleTextNodeEndAt(Text* node, | 
| @@ -411,6 +468,8 @@ bool TextIteratorTextNodeHandler::FixLeadingWhiteSpaceForReplacedElement( | 
| Node* parent) { | 
| // This is a hacky way for white space fixup in legacy layout. With LayoutNG, | 
| // we can get rid of this function. | 
| +  if (ng_block_flow_) | 
| +    return false; | 
|  | 
| if (behavior_.CollapseTrailingSpace()) { | 
| if (text_node_) { | 
|  |