Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(211)

Unified Diff: third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp

Issue 2894263003: WIP TextIterator with clean collapsed whitespace handling (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/editing/iterators/TextIterator.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
index b5f765cbb5ad0760cd763ee29975d0df08b657f1..38b3da71dfb4ce36d3759f735310ad4a078693a5 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -68,22 +68,13 @@ TextIteratorBehavior AdjustBehaviorFlags(const TextIteratorBehavior&);
template <>
TextIteratorBehavior AdjustBehaviorFlags<EditingStrategy>(
const TextIteratorBehavior& behavior) {
- if (!behavior.ForSelectionToString())
- return behavior;
- return TextIteratorBehavior::Builder(behavior)
- .SetExcludeAutofilledValue(true)
- .Build();
+ return behavior;
}
template <>
TextIteratorBehavior AdjustBehaviorFlags<EditingInFlatTreeStrategy>(
const TextIteratorBehavior& behavior) {
- return TextIteratorBehavior::Builder(behavior)
- .SetExcludeAutofilledValue(behavior.ForSelectionToString() ||
- behavior.ExcludeAutofilledValue())
- .SetEntersOpenShadowRoots(false)
- .SetEntersTextControls(false)
- .Build();
+ return behavior;
}
// Checks if |advance()| skips the descendants of |node|, which is the case if
@@ -247,12 +238,6 @@ TextIteratorAlgorithm<Strategy>::~TextIteratorAlgorithm() {
Document* document = OwnerDocument();
if (!document)
return;
- if (behavior_.ForInnerText())
- UseCounter::Count(document, UseCounter::kInnerTextWithShadowTree);
- if (behavior_.ForSelectionToString())
- UseCounter::Count(document, UseCounter::kSelectionToStringWithShadowTree);
- if (behavior_.ForWindowFind())
- UseCounter::Count(document, UseCounter::kWindowFindWithShadowTree);
}
template <typename Strategy>
@@ -265,10 +250,19 @@ bool TextIteratorAlgorithm<Strategy>::IsInsideAtomicInlineElement() const {
}
template <typename Strategy>
+bool TextIteratorAlgorithm<Strategy>::MayHaveMoreTextRuns() const {
+ if (text_box_)
+ return true;
+ return false;
+}
+
+template <typename Strategy>
void TextIteratorAlgorithm<Strategy>::Advance() {
if (should_stop_)
return;
+ LOG(ERROR) << "TextIterator::Advance";
+
if (node_)
DCHECK(!node_->GetDocument().NeedsLayoutTreeUpdate()) << node_;
@@ -292,17 +286,13 @@ void TextIteratorAlgorithm<Strategy>::Advance() {
if (ShouldProceedToRemainingText())
ProceedToRemainingText();
// handle remembered text box
- if (text_box_) {
- HandleTextBox();
+ if (MayHaveMoreTextRuns()) {
+ HandleNextTextRun();
if (text_state_.PositionNode())
return;
}
while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) {
- if (!should_stop_ && StopsOnFormControls() &&
- HTMLFormControlElement::EnclosingFormControlElement(node_))
- should_stop_ = true;
-
// if the range ends at offset 0 of an element, represent the
// position, but not the content, of that element e.g. if the
// node is a blockflow element, emit a newline that
@@ -328,34 +318,11 @@ void TextIteratorAlgorithm<Strategy>::Advance() {
} else {
// Enter author shadow roots, from youngest, if any and if necessary.
if (iteration_progress_ < kHandledOpenShadowRoots) {
- if (EntersOpenShadowRoots() && node_->IsElementNode() &&
- ToElement(node_)->openShadowRoot()) {
- ShadowRoot* youngest_shadow_root = ToElement(node_)->openShadowRoot();
- DCHECK(youngest_shadow_root->GetType() == ShadowRootType::V0 ||
- youngest_shadow_root->GetType() == ShadowRootType::kOpen);
- node_ = youngest_shadow_root;
- iteration_progress_ = kHandledNone;
- ++shadow_depth_;
- fully_clipped_stack_.PushFullyClippedState(node_);
- continue;
- }
-
iteration_progress_ = kHandledOpenShadowRoots;
}
// Enter user-agent shadow root, if necessary.
if (iteration_progress_ < kHandledUserAgentShadowRoot) {
- if (EntersTextControls() && layout_object->IsTextControl()) {
- ShadowRoot* user_agent_shadow_root =
- ToElement(node_)->UserAgentShadowRoot();
- DCHECK(user_agent_shadow_root->GetType() ==
- ShadowRootType::kUserAgent);
- node_ = user_agent_shadow_root;
- iteration_progress_ = kHandledNone;
- ++shadow_depth_;
- fully_clipped_stack_.PushFullyClippedState(node_);
- continue;
- }
iteration_progress_ = kHandledUserAgentShadowRoot;
}
@@ -365,7 +332,7 @@ void TextIteratorAlgorithm<Strategy>::Advance() {
if (layout_object->IsText() &&
node_->getNodeType() ==
Node::kTextNode) { // FIXME: What about kCdataSectionNode?
- if (!fully_clipped_stack_.Top() || IgnoresStyleVisibility())
+ if (!fully_clipped_stack_.Top())
handled_node = HandleTextNode();
} else if (layout_object &&
(layout_object->IsImage() || layout_object->IsLayoutPart() ||
@@ -497,15 +464,48 @@ bool TextIteratorAlgorithm<Strategy>::ShouldHandleFirstLetter(
}
template <typename Strategy>
-bool TextIteratorAlgorithm<Strategy>::HandleTextNode() {
- if (ExcludesAutofilledValue()) {
- TextControlElement* control = EnclosingTextControl(node_);
- // For security reason, we don't expose suggested value if it is
- // auto-filled.
- if (control && control->IsAutofilled())
- return true;
+bool TextIteratorAlgorithm<Strategy>::HandlePreFormattedTextNode() {
+ Text* text_node = ToText(node_);
+ LayoutText* layout_object = text_node->GetLayoutObject();
+ String str = layout_object->GetText();
+
+ if (ShouldHandleFirstLetter(*layout_object)) {
+ HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object));
+ if (first_letter_text_) {
+ String first_letter = first_letter_text_->GetText();
+ const unsigned run_start = offset_;
+ const bool stops_in_first_letter =
+ text_node == end_container_ &&
+ end_offset_ <= static_cast<int>(first_letter.length());
+ const unsigned run_end =
+ stops_in_first_letter ? end_offset_ : first_letter.length();
+ EmitText(text_node, first_letter_text_, run_start, run_end);
+ first_letter_text_ = nullptr;
+ text_box_ = 0;
+ offset_ = run_end;
+ return stops_in_first_letter;
+ }
+ // We are here only if the DOM and/or layout trees are broken.
+ NOTREACHED();
}
+ if (layout_object->Style()->Visibility() != EVisibility::kVisible)
+ return false;
+ const unsigned run_start = offset_ - layout_object->TextStartOffset();
+ const unsigned str_length = str.length();
+ const unsigned end = (text_node == end_container_)
+ ? end_offset_ - layout_object->TextStartOffset()
+ : INT_MAX;
+ const unsigned run_end = std::min(str_length, end);
+
+ if (run_start >= run_end)
+ return true;
+ EmitText(text_node, text_node->GetLayoutObject(), run_start, run_end);
+ return true;
+}
+
+template <typename Strategy>
+bool TextIteratorAlgorithm<Strategy>::HandleTextNode() {
Text* text_node = ToText(node_);
LayoutText* layout_object = text_node->GetLayoutObject();
@@ -513,64 +513,28 @@ bool TextIteratorAlgorithm<Strategy>::HandleTextNode() {
String str = layout_object->GetText();
// handle pre-formatted text
- if (!layout_object->Style()->CollapseWhiteSpace()) {
- if (ShouldHandleFirstLetter(*layout_object)) {
- HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object));
- if (first_letter_text_) {
- String first_letter = first_letter_text_->GetText();
- const unsigned run_start = offset_;
- const bool stops_in_first_letter =
- text_node == end_container_ &&
- end_offset_ <= static_cast<int>(first_letter.length());
- const unsigned run_end =
- stops_in_first_letter ? end_offset_ : first_letter.length();
- EmitText(text_node, first_letter_text_, run_start, run_end);
- first_letter_text_ = nullptr;
- text_box_ = 0;
- offset_ = run_end;
- return stops_in_first_letter;
- }
- // We are here only if the DOM and/or layout trees are broken.
- NOTREACHED();
- }
- if (layout_object->Style()->Visibility() != EVisibility::kVisible &&
- !IgnoresStyleVisibility())
- return false;
- const unsigned run_start = offset_ - layout_object->TextStartOffset();
- const unsigned str_length = str.length();
- const unsigned end = (text_node == end_container_)
- ? end_offset_ - layout_object->TextStartOffset()
- : INT_MAX;
- const unsigned run_end = std::min(str_length, end);
-
- if (run_start >= run_end)
- return true;
-
- EmitText(text_node, text_node->GetLayoutObject(), run_start, run_end);
- return true;
- }
+ if (!layout_object->Style()->CollapseWhiteSpace())
+ return HandlePreFormattedTextNode();
- if (layout_object->FirstTextBox())
+ if (layout_object->FirstTextBox()) {
text_box_ = layout_object->FirstTextBox();
+ LOG(ERROR) << "text_box_ set to: " << str.Substring(text_box_->Start(), text_box_->Len());
+ }
- const bool should_handle_first_letter =
- ShouldHandleFirstLetter(*layout_object);
- if (should_handle_first_letter)
+ if (ShouldHandleFirstLetter(*layout_object)) {
HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object));
+ if (first_letter_text_) {
+ layout_object = first_letter_text_;
+ str = layout_object->GetText();
+ }
+ }
- if (!layout_object->FirstTextBox() && str.length() > 0 &&
- !should_handle_first_letter) {
- if (layout_object->Style()->Visibility() != EVisibility::kVisible &&
- !IgnoresStyleVisibility())
+ if (!layout_object->FirstTextBox() && str.length() > 0) {
+ if (layout_object->Style()->Visibility() != EVisibility::kVisible)
return false;
- last_text_node_ended_with_collapsed_space_ =
- true; // entire block is collapsed space
return true;
}
- if (first_letter_text_)
- layout_object = first_letter_text_;
-
// Used when text boxes are out of order (Hebrew/Arabic w/ embeded LTR text)
if (layout_object->ContainsReversedText()) {
sorted_text_boxes_.clear();
@@ -584,175 +548,96 @@ bool TextIteratorAlgorithm<Strategy>::HandleTextNode() {
text_box_ = sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0];
}
- HandleTextBox();
+ // The current algorithm always sets |text_box_| to the first InlineTextBox
+ // under |layout_object|, regardless of the value of |offset_|. This may not
+ // be very efficient.
+ // There can be collapsed whitespace before |text_box_| that needs handling.
+ HandleNextTextRun();
return true;
}
-// Restore the collapsed space for copy & paste. See http://crbug.com/318925
template <typename Strategy>
-size_t TextIteratorAlgorithm<Strategy>::RestoreCollapsedTrailingSpace(
- InlineTextBox* next_text_box,
- size_t subrun_end) {
- if (next_text_box || !text_box_->Root().NextRootBox() ||
- text_box_->Root().LastChild() != text_box_)
- return subrun_end;
-
- const String& text = ToLayoutText(node_->GetLayoutObject())->GetText();
- if (text.EndsWith(' ') == 0 || subrun_end != text.length() - 1 ||
- text[subrun_end - 1] == ' ')
- return subrun_end;
-
- // If there is the leading space in the next line, we don't need to restore
- // the trailing space.
- // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div>
- InlineBox* first_box_of_next_line =
- text_box_->Root().NextRootBox()->FirstChild();
- if (!first_box_of_next_line)
- return subrun_end + 1;
- Node* first_node_of_next_line =
- first_box_of_next_line->GetLineLayoutItem().GetNode();
- if (!first_node_of_next_line ||
- first_node_of_next_line->nodeValue()[0] != ' ')
- return subrun_end + 1;
-
- return subrun_end;
-}
+void TextIteratorAlgorithm<Strategy>::ProceedToNextTextBox() {
+ InlineTextBox* next_text_box = nullptr;
-template <typename Strategy>
-void TextIteratorAlgorithm<Strategy>::HandleTextBox() {
LayoutText* layout_object = first_letter_text_
? first_letter_text_
: ToLayoutText(node_->GetLayoutObject());
const unsigned text_start_offset = layout_object->TextStartOffset();
+ const unsigned end =
+ (node_ == end_container_)
+ ? static_cast<unsigned>(end_offset_) - text_start_offset
+ : INT_MAX;
- if (layout_object->Style()->Visibility() != EVisibility::kVisible &&
- !IgnoresStyleVisibility()) {
- text_box_ = nullptr;
+ if (layout_object->ContainsReversedText()) {
+ if (sorted_text_boxes_position_ + 1 < sorted_text_boxes_.size())
+ next_text_box = sorted_text_boxes_[sorted_text_boxes_position_ + 1];
} else {
- String str = layout_object->GetText();
- // Start and end offsets in |str|, i.e., str[start..end - 1] should be
- // emitted (after handling whitespace collapsing).
- const unsigned start = offset_ - layout_object->TextStartOffset();
- const unsigned end =
- (node_ == end_container_)
- ? static_cast<unsigned>(end_offset_) - text_start_offset
- : INT_MAX;
- while (text_box_) {
- const unsigned text_box_start = text_box_->Start();
- const unsigned run_start = std::max(text_box_start, start);
-
- // Check for collapsed space at the start of this run.
- InlineTextBox* first_text_box =
- layout_object->ContainsReversedText()
- ? (sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0])
- : layout_object->FirstTextBox();
- const bool need_space = last_text_node_ended_with_collapsed_space_ ||
- (text_box_ == first_text_box &&
- text_box_start == run_start && run_start > 0);
- if (need_space &&
- !layout_object->Style()->IsCollapsibleWhiteSpace(
- text_state_.LastCharacter()) &&
- text_state_.LastCharacter()) {
- if (last_text_node_ == node_ && run_start > 0 &&
- str[run_start - 1] == ' ') {
- unsigned space_run_start = run_start - 1;
- while (space_run_start > 0 && str[space_run_start - 1] == ' ')
- --space_run_start;
- EmitText(node_, layout_object, space_run_start, space_run_start + 1);
- } else {
- SpliceBuffer(kSpaceCharacter, node_, 0, run_start, run_start);
- }
- return;
- }
- const unsigned text_box_end = text_box_start + text_box_->Len();
- const unsigned run_end = std::min(text_box_end, end);
-
- // Determine what the next text box will be, but don't advance yet
- InlineTextBox* next_text_box = nullptr;
- if (layout_object->ContainsReversedText()) {
- if (sorted_text_boxes_position_ + 1 < sorted_text_boxes_.size())
- next_text_box = sorted_text_boxes_[sorted_text_boxes_position_ + 1];
- } else {
- next_text_box = text_box_->NextTextBox();
- }
+ next_text_box = text_box_->NextTextBox();
+ }
+ if (next_text_box && next_text_box->Start() >= end)
+ next_text_box = nullptr;
- // FIXME: Based on the outcome of crbug.com/446502 it's possible we can
- // remove this block. The reason we new it now is because BIDI and
- // FirstLetter seem to have different ideas of where things can split.
- // FirstLetter takes the punctuation + first letter, and BIDI will
- // split out the punctuation and possibly reorder it.
- if (next_text_box &&
- !(next_text_box->GetLineLayoutItem().IsEqual(layout_object))) {
- text_box_ = 0;
- return;
- }
- DCHECK(!next_text_box ||
- next_text_box->GetLineLayoutItem().IsEqual(layout_object));
-
- if (run_start < run_end) {
- // Handle either a single newline character (which becomes a space),
- // or a run of characters that does not include a newline.
- // This effectively translates newlines to spaces without copying the
- // text.
- if (str[run_start] == '\n') {
- // We need to preserve new lines in case of PreLine.
- // See bug crbug.com/317365.
- if (layout_object->Style()->WhiteSpace() == EWhiteSpace::kPreLine)
- SpliceBuffer('\n', node_, 0, run_start, run_start);
- else
- SpliceBuffer(kSpaceCharacter, node_, 0, run_start, run_start + 1);
- offset_ = text_start_offset + run_start + 1;
- } else {
- size_t subrun_end = str.find('\n', run_start);
- if (subrun_end == kNotFound || subrun_end > run_end) {
- subrun_end = run_end;
- subrun_end =
- RestoreCollapsedTrailingSpace(next_text_box, subrun_end);
- }
+ DCHECK(!next_text_box ||
+ next_text_box->GetLineLayoutItem().IsEqual(layout_object));
- offset_ = text_start_offset + subrun_end;
- EmitText(node_, layout_object, run_start, subrun_end);
- }
+ text_box_ = next_text_box;
+ if (text_box_)
+ LOG(ERROR) << "text_box_ set to: " << layout_object->GetText().Substring(text_box_->Start(), text_box_->Len());
+ else
+ LOG(ERROR) << "text_box_ set to null";
+ if (layout_object->ContainsReversedText())
+ ++sorted_text_boxes_position_;
+ return;
+}
- // If we are doing a subrun that doesn't go to the end of the text box,
- // come back again to finish handling this text box; don't advance to
- // the next one.
- if (static_cast<unsigned>(text_state_.PositionEndOffset()) <
- text_box_end)
- return;
+template <typename Strategy>
+void TextIteratorAlgorithm<Strategy>::HandleNextTextRun() {
+ HandleTextBox();
+}
- if (behavior_.DoesNotEmitSpaceBeyondRangeEnd()) {
- // If the subrun went to the text box end and this end is also the end
- // of the range, do not advance to the next text box and do not
- // generate a space, just stop.
- if (text_box_end == end) {
- text_box_ = nullptr;
- return;
- }
- }
+template <typename Strategy>
+void TextIteratorAlgorithm<Strategy>::HandleTextBox() {
+ LayoutText* layout_object = first_letter_text_
+ ? first_letter_text_
+ : ToLayoutText(node_->GetLayoutObject());
+ // We are emitting content of text node |node_|, starting from DOM offset |offset_|.
+ // |layout_object| is the LayoutText from which text should be emitted.
+ // |text_box_| is an InlineTextBox under |layout_object|, and all visible text
+ // before |text_box_| has been emitted.
- // Advance and return
- const unsigned next_run_start =
- next_text_box ? next_text_box->Start() : str.length();
- if (next_run_start > run_end)
- last_text_node_ended_with_collapsed_space_ =
- true; // collapsed space between runs or at the end
-
- text_box_ = next_text_box;
- if (layout_object->ContainsReversedText())
- ++sorted_text_boxes_position_;
- return;
- }
- // Advance and continue
- text_box_ = next_text_box;
- if (layout_object->ContainsReversedText())
- ++sorted_text_boxes_position_;
+ const unsigned text_start_offset = layout_object->TextStartOffset();
+
+ String str = layout_object->GetText();
+ LOG(ERROR) << "HandleTextBox: " << str << "@" << offset_;
+ // Start and end offsets in |str|, i.e., str[start..end - 1] should be
+ // emitted (after handling whitespace collapsing).
+ const unsigned start = offset_ - layout_object->TextStartOffset();
+ const unsigned end =
+ (node_ == end_container_)
+ ? static_cast<unsigned>(end_offset_) - text_start_offset
+ : INT_MAX;
+ while (text_box_) {
+ const unsigned text_box_start = text_box_->Start();
+ const unsigned text_box_end = text_box_start + text_box_->Len();
+ const unsigned run_start = std::max(text_box_start, start);
+ const unsigned run_end = std::min(text_box_end, end);
+ LOG(ERROR) << "Checking text box: " << str.Substring(run_start, run_end - run_start);
+
+ if (run_start < run_end) {
+ offset_ = text_start_offset + run_end;
+ EmitText(node_, layout_object, run_start, run_end);
+ ProceedToNextTextBox();
+ return;
}
+
+ // Advance and continue
+ ProceedToNextTextBox();
}
if (ShouldProceedToRemainingText()) {
ProceedToRemainingText();
- HandleTextBox();
+ HandleNextTextRun();
}
}
@@ -787,8 +672,7 @@ void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter(
return;
LayoutObject* pseudo_layout_object = first_letter_element->GetLayoutObject();
- if (pseudo_layout_object->Style()->Visibility() != EVisibility::kVisible &&
- !IgnoresStyleVisibility())
+ if (pseudo_layout_object->Style()->Visibility() != EVisibility::kVisible)
return;
LayoutObject* first_letter = pseudo_layout_object->SlowFirstChild();
@@ -821,37 +705,11 @@ bool TextIteratorAlgorithm<Strategy>::HandleReplacedElement() {
return false;
LayoutObject* layout_object = node_->GetLayoutObject();
- if (layout_object->Style()->Visibility() != EVisibility::kVisible &&
- !IgnoresStyleVisibility())
+ if (layout_object->Style()->Visibility() != EVisibility::kVisible)
return false;
- if (EmitsObjectReplacementCharacter()) {
- SpliceBuffer(kObjectReplacementCharacter, Strategy::Parent(*node_), node_,
- 0, 1);
- return true;
- }
-
- if (EntersTextControls() && layout_object->IsTextControl()) {
- // The shadow tree should be already visited.
- return true;
- }
-
- if (EmitsCharactersBetweenAllVisiblePositions()) {
- // We want replaced elements to behave like punctuation for boundary
- // finding, and to simply take up space for the selection preservation
- // code in moveParagraphs, so we use a comma.
- SpliceBuffer(',', Strategy::Parent(*node_), node_, 0, 1);
- return true;
- }
-
text_state_.UpdateForReplacedElement(node_);
- if (EmitsImageAltText() && TextIterator::SupportsAltText(node_)) {
- text_state_.EmitAltText(node_);
- if (text_state_.length())
- return true;
- }
-
return true;
}
@@ -871,14 +729,12 @@ bool TextIteratorAlgorithm<Strategy>::ShouldEmitTabBeforeNode(Node* node) {
template <typename Strategy>
bool TextIteratorAlgorithm<Strategy>::ShouldEmitNewlineForNode(
- Node* node,
- bool emits_original_text) {
+ Node* node, bool) {
LayoutObject* layout_object = node->GetLayoutObject();
if (layout_object ? !layout_object->IsBR() : !isHTMLBRElement(node))
return false;
- return emits_original_text || !(node->IsInShadowTree() &&
- isHTMLInputElement(*node->OwnerShadowHost()));
+ return !(node->IsInShadowTree() && isHTMLInputElement(*node->OwnerShadowHost()));
}
static bool ShouldEmitNewlinesBeforeAndAfterNode(Node& node) {
@@ -973,9 +829,6 @@ static bool ShouldEmitExtraNewlineForNode(Node* node) {
// container) or as we hit it (if it's atomic).
template <typename Strategy>
bool TextIteratorAlgorithm<Strategy>::ShouldRepresentNodeOffsetZero() {
- if (EmitsCharactersBetweenAllVisiblePositions() && IsRenderedAsTable(node_))
- return true;
-
// Leave element positioned flush with start of a paragraph
// (e.g. do not insert tab before a table cell at the start of a paragraph)
if (text_state_.LastCharacter() == '\n')
@@ -1044,8 +897,7 @@ template <typename Strategy>
bool TextIteratorAlgorithm<Strategy>::ShouldEmitSpaceBeforeAndAfterNode(
Node* node) {
return IsRenderedAsTable(node) &&
- (node->GetLayoutObject()->IsInline() ||
- EmitsCharactersBetweenAllVisiblePositions());
+ (node->GetLayoutObject()->IsInline());
}
template <typename Strategy>
@@ -1071,11 +923,8 @@ void TextIteratorAlgorithm<Strategy>::RepresentNodeOffsetZero() {
template <typename Strategy>
bool TextIteratorAlgorithm<Strategy>::HandleNonTextNode() {
- if (ShouldEmitNewlineForNode(node_, EmitsOriginalText()))
+ if (ShouldEmitNewlineForNode(node_))
SpliceBuffer('\n', Strategy::Parent(*node_), node_, 0, 1);
- else if (EmitsCharactersBetweenAllVisiblePositions() &&
- node_->GetLayoutObject() && node_->GetLayoutObject()->IsHR())
- SpliceBuffer(kSpaceCharacter, Strategy::Parent(*node_), node_, 0, 1);
else
RepresentNodeOffsetZero();
@@ -1137,9 +986,9 @@ void TextIteratorAlgorithm<Strategy>::SpliceBuffer(UChar c,
// Since m_lastTextNodeEndedWithCollapsedSpace seems better placed in
// TextIterator, but is always reset when we call spliceBuffer, we
// wrap TextIteratorTextState::spliceBuffer() with this function.
+ LOG(ERROR) << "SpliceBuffer: " << c;
text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset,
text_end_offset);
- last_text_node_ended_with_collapsed_space_ = false;
}
template <typename Strategy>
@@ -1150,9 +999,9 @@ void TextIteratorAlgorithm<Strategy>::EmitText(Node* text_node,
// Since m_lastTextNodeEndedWithCollapsedSpace seems better placed in
// TextIterator, but is always reset when we call spliceBuffer, we
// wrap TextIteratorTextState::spliceBuffer() with this function.
+ LOG(ERROR) << "EmitText: " << layout_object->GetText().Substring(text_start_offset, text_end_offset - text_start_offset);
text_state_.EmitText(text_node, layout_object, text_start_offset,
text_end_offset);
- last_text_node_ended_with_collapsed_space_ = false;
}
template <typename Strategy>
@@ -1303,6 +1152,8 @@ static String CreatePlainText(const EphemeralRangeTemplate<Strategy>& range,
DocumentLifecycle::DisallowTransitionScope disallow_transition(
range.StartPosition().GetDocument()->Lifecycle());
+ LOG(ERROR) << "CreatePlainText start";
+
TextIteratorAlgorithm<Strategy> it(range.StartPosition(), range.EndPosition(),
behavior);
@@ -1316,8 +1167,12 @@ static String CreatePlainText(const EphemeralRangeTemplate<Strategy>& range,
StringBuilder builder;
builder.ReserveCapacity(kInitialCapacity);
- for (; !it.AtEnd(); it.Advance())
+ for (; !it.AtEnd(); it.Advance()) {
it.GetText().AppendTextToStringBuilder(builder);
+ LOG(ERROR) << "Current builder: " << builder.ToString();
+ }
+
+ LOG(ERROR) << "CreatePlainText done: " << builder.ToString();
if (builder.IsEmpty())
return g_empty_string;
« no previous file with comments | « third_party/WebKit/Source/core/editing/iterators/TextIterator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698