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_) { |