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

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

Issue 2883163002: Un-insanify first-letter handling in TextIterator (to some degree) (Closed)
Patch Set: Tue May 16 16:31:00 PDT 2017 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 unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All
3 * rights reserved. 3 * rights reserved.
4 * Copyright (C) 2005 Alexey Proskuryakov. 4 * Copyright (C) 2005 Alexey Proskuryakov.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 #include "platform/fonts/Font.h" 55 #include "platform/fonts/Font.h"
56 #include "platform/wtf/text/CString.h" 56 #include "platform/wtf/text/CString.h"
57 #include "platform/wtf/text/StringBuilder.h" 57 #include "platform/wtf/text/StringBuilder.h"
58 58
59 namespace blink { 59 namespace blink {
60 60
61 using namespace HTMLNames; 61 using namespace HTMLNames;
62 62
63 namespace { 63 namespace {
64 64
65 const int kInvalidTextOffset = -1;
66
67 template <typename Strategy> 65 template <typename Strategy>
68 TextIteratorBehavior AdjustBehaviorFlags(const TextIteratorBehavior&); 66 TextIteratorBehavior AdjustBehaviorFlags(const TextIteratorBehavior&);
69 67
70 template <> 68 template <>
71 TextIteratorBehavior AdjustBehaviorFlags<EditingStrategy>( 69 TextIteratorBehavior AdjustBehaviorFlags<EditingStrategy>(
72 const TextIteratorBehavior& behavior) { 70 const TextIteratorBehavior& behavior) {
73 if (!behavior.ForSelectionToString()) 71 if (!behavior.ForSelectionToString())
74 return behavior; 72 return behavior;
75 return TextIteratorBehavior::Builder(behavior) 73 return TextIteratorBehavior::Builder(behavior)
76 .SetExcludeAutofilledValue(true) 74 .SetExcludeAutofilledValue(true)
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 text_box_(nullptr), 166 text_box_(nullptr),
169 remaining_text_box_(nullptr), 167 remaining_text_box_(nullptr),
170 first_letter_text_(nullptr), 168 first_letter_text_(nullptr),
171 last_text_node_(nullptr), 169 last_text_node_(nullptr),
172 last_text_node_ended_with_collapsed_space_(false), 170 last_text_node_ended_with_collapsed_space_(false),
173 sorted_text_boxes_position_(0), 171 sorted_text_boxes_position_(0),
174 behavior_(AdjustBehaviorFlags<Strategy>(behavior)), 172 behavior_(AdjustBehaviorFlags<Strategy>(behavior)),
175 handled_first_letter_(false), 173 handled_first_letter_(false),
176 should_stop_(false), 174 should_stop_(false),
177 handle_shadow_root_(false), 175 handle_shadow_root_(false),
178 first_letter_start_offset_(kInvalidTextOffset),
179 remaining_text_start_offset_(kInvalidTextOffset),
180 text_state_(behavior_) { 176 text_state_(behavior_) {
181 DCHECK(start.IsNotNull()); 177 DCHECK(start.IsNotNull());
182 DCHECK(end.IsNotNull()); 178 DCHECK(end.IsNotNull());
183 179
184 // TODO(dglazkov): TextIterator should not be created for documents that don't 180 // TODO(dglazkov): TextIterator should not be created for documents that don't
185 // have a frame, but it currently still happens in some cases. See 181 // have a frame, but it currently still happens in some cases. See
186 // http://crbug.com/591877 for details. 182 // http://crbug.com/591877 for details.
187 DCHECK(!start.GetDocument()->View() || 183 DCHECK(!start.GetDocument()->View() ||
188 !start.GetDocument()->View()->NeedsLayout()); 184 !start.GetDocument()->View()->NeedsLayout());
189 DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate()); 185 DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate());
190 186
191 if (start.CompareTo(end) > 0) { 187 if (start.CompareTo(end) > 0) {
192 Initialize(end.ComputeContainerNode(), end.ComputeOffsetInContainerNode(), 188 Initialize(end.ComputeContainerNode(), end.ComputeOffsetInContainerNode(),
193 start.ComputeContainerNode(), 189 start.ComputeContainerNode(),
194 start.ComputeOffsetInContainerNode()); 190 start.ComputeOffsetInContainerNode());
195 return; 191 return;
196 } 192 }
197 Initialize(start.ComputeContainerNode(), start.ComputeOffsetInContainerNode(), 193 Initialize(start.ComputeContainerNode(), start.ComputeOffsetInContainerNode(),
198 end.ComputeContainerNode(), end.ComputeOffsetInContainerNode()); 194 end.ComputeContainerNode(), end.ComputeOffsetInContainerNode());
199 } 195 }
200 196
201 template <typename Strategy> 197 template <typename Strategy>
202 bool TextIteratorAlgorithm<Strategy>::PrepareForFirstLetterInitialization() {
203 if (node_ != start_container_)
204 return false;
205
206 if (node_->getNodeType() != Node::kTextNode)
207 return false;
208
209 Text* text_node = ToText(node_);
210 LayoutText* layout_object = text_node->GetLayoutObject();
211 if (!layout_object || !layout_object->IsTextFragment())
212 return false;
213
214 LayoutTextFragment* text_fragment = ToLayoutTextFragment(layout_object);
215 if (!text_fragment->IsRemainingTextLayoutObject())
216 return false;
217
218 if (static_cast<unsigned>(start_offset_) >=
219 text_fragment->TextStartOffset()) {
220 remaining_text_start_offset_ =
221 start_offset_ - text_fragment->TextStartOffset();
222 } else {
223 first_letter_start_offset_ = start_offset_;
224 }
225 offset_ = 0;
226
227 return true;
228 }
229
230 template <typename Strategy>
231 bool TextIteratorAlgorithm<Strategy>::HasNotAdvancedToStartPosition() {
232 if (AtEnd())
233 return false;
234 if (remaining_text_start_offset_ == kInvalidTextOffset)
235 return false;
236 return node_ == start_container_;
237 }
238
239 template <typename Strategy>
240 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container, 198 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container,
241 int start_offset, 199 int start_offset,
242 Node* end_container, 200 Node* end_container,
243 int end_offset) { 201 int end_offset) {
244 DCHECK(start_container); 202 DCHECK(start_container);
245 DCHECK(end_container); 203 DCHECK(end_container);
246 204
247 // Remember the range - this does not change. 205 // Remember the range - this does not change.
248 start_container_ = start_container; 206 start_container_ = start_container;
249 start_offset_ = start_offset; 207 start_offset_ = start_offset;
(...skipping 13 matching lines...) Expand all
263 node_ = child; 221 node_ = child;
264 else if (!start_offset) 222 else if (!start_offset)
265 node_ = start_container; 223 node_ = start_container;
266 else 224 else
267 node_ = Strategy::NextSkippingChildren(*start_container); 225 node_ = Strategy::NextSkippingChildren(*start_container);
268 226
269 if (!node_) 227 if (!node_)
270 return; 228 return;
271 229
272 fully_clipped_stack_.SetUpFullyClippedStack(node_); 230 fully_clipped_stack_.SetUpFullyClippedStack(node_);
273 if (!PrepareForFirstLetterInitialization()) 231 offset_ = node_ == start_container_ ? start_offset_ : 0;
274 offset_ = node_ == start_container_ ? start_offset_ : 0;
275 iteration_progress_ = kHandledNone; 232 iteration_progress_ = kHandledNone;
276 233
277 // Calculate first out of bounds node. 234 // Calculate first out of bounds node.
278 past_end_node_ = end_container 235 past_end_node_ = end_container
279 ? PastLastNode<Strategy>(*end_container, end_offset) 236 ? PastLastNode<Strategy>(*end_container, end_offset)
280 : nullptr; 237 : nullptr;
281 238
282 // Identify the first run. 239 // Identify the first run.
283 Advance(); 240 Advance();
284
285 // The current design cannot start in a text node with arbitrary offset, if
286 // the node has :first-letter. Instead, we start with offset 0, and have extra
287 // advance() calls until we have moved to/past the starting position.
288 while (HasNotAdvancedToStartPosition())
289 Advance();
290
291 // Clear temporary data for initialization with :first-letter.
292 first_letter_start_offset_ = kInvalidTextOffset;
293 remaining_text_start_offset_ = kInvalidTextOffset;
294 } 241 }
295 242
296 template <typename Strategy> 243 template <typename Strategy>
297 TextIteratorAlgorithm<Strategy>::~TextIteratorAlgorithm() { 244 TextIteratorAlgorithm<Strategy>::~TextIteratorAlgorithm() {
298 if (!handle_shadow_root_) 245 if (!handle_shadow_root_)
299 return; 246 return;
300 Document* document = OwnerDocument(); 247 Document* document = OwnerDocument();
301 if (!document) 248 if (!document)
302 return; 249 return;
303 if (behavior_.ForInnerText()) 250 if (behavior_.ForInnerText())
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 EVisibility::kVisible; 504 EVisibility::kVisible;
558 } 505 }
559 506
560 template <typename Strategy> 507 template <typename Strategy>
561 bool TextIteratorAlgorithm<Strategy>::ShouldHandleFirstLetter( 508 bool TextIteratorAlgorithm<Strategy>::ShouldHandleFirstLetter(
562 const LayoutText& layout_text) const { 509 const LayoutText& layout_text) const {
563 if (handled_first_letter_) 510 if (handled_first_letter_)
564 return false; 511 return false;
565 if (!layout_text.IsTextFragment()) 512 if (!layout_text.IsTextFragment())
566 return false; 513 return false;
567 // TODO(xiaochengh): Handle the case where :first-letter has multiple chars, 514 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text);
568 // and eliminate the hack with first_letter/remaining_text_start_offset_. 515 return offset_ < static_cast<int>(text_fragment.TextStartOffset());
569 return !offset_;
570 } 516 }
571 517
572 template <typename Strategy> 518 template <typename Strategy>
573 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() { 519 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() {
574 if (ExcludesAutofilledValue()) { 520 if (ExcludesAutofilledValue()) {
575 TextControlElement* control = EnclosingTextControl(node_); 521 TextControlElement* control = EnclosingTextControl(node_);
576 // For security reason, we don't expose suggested value if it is 522 // For security reason, we don't expose suggested value if it is
577 // auto-filled. 523 // auto-filled.
578 if (control && control->IsAutofilled()) 524 if (control && control->IsAutofilled())
579 return true; 525 return true;
580 } 526 }
581 527
582 Text* text_node = ToText(node_); 528 Text* text_node = ToText(node_);
583 LayoutText* layout_object = text_node->GetLayoutObject(); 529 LayoutText* layout_object = text_node->GetLayoutObject();
584 530
585 last_text_node_ = text_node; 531 last_text_node_ = text_node;
586 String str = layout_object->GetText(); 532 String str = layout_object->GetText();
587 533
588 // handle pre-formatted text 534 // handle pre-formatted text
589 if (!layout_object->Style()->CollapseWhiteSpace()) { 535 if (!layout_object->Style()->CollapseWhiteSpace()) {
590 if (last_text_node_ended_with_collapsed_space_ && 536 if (last_text_node_ended_with_collapsed_space_ &&
591 HasVisibleTextNode(layout_object)) { 537 HasVisibleTextNode(layout_object)) {
592 if (behavior_.CollapseTrailingSpace()) { 538 if (behavior_.CollapseTrailingSpace()) {
593 if (offset_ > 0 && str[offset_ - 1] == ' ') { 539 if (offset_ > 0 && str[offset_ - 1] == ' ') {
594 SpliceBuffer(kSpaceCharacter, text_node, 0, offset_, offset_); 540 SpliceBuffer(kSpaceCharacter, text_node, 0, offset_, offset_);
Xiaocheng 2017/05/16 23:33:31 I don't think this line is reachable. I'll remove
595 return false; 541 return false;
596 } 542 }
597 } else { 543 } else {
598 SpliceBuffer(kSpaceCharacter, text_node, 0, offset_, offset_); 544 SpliceBuffer(kSpaceCharacter, text_node, 0, offset_, offset_);
599 return false; 545 return false;
600 } 546 }
601 } 547 }
602 if (ShouldHandleFirstLetter(*layout_object)) { 548 if (ShouldHandleFirstLetter(*layout_object)) {
603 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); 549 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object));
604 if (first_letter_text_) { 550 if (first_letter_text_) {
605 String first_letter = first_letter_text_->GetText(); 551 String first_letter = first_letter_text_->GetText();
606 EmitText(text_node, first_letter_text_, offset_, 552 const unsigned run_start = offset_;
607 offset_ + first_letter.length()); 553 const bool stops_in_first_letter =
554 text_node == end_container_ &&
555 end_offset_ <= static_cast<int>(first_letter.length());
556 const unsigned run_end =
557 stops_in_first_letter ? end_offset_ : first_letter.length();
558 EmitText(text_node, first_letter_text_, run_start, run_end);
608 first_letter_text_ = nullptr; 559 first_letter_text_ = nullptr;
609 text_box_ = 0; 560 text_box_ = 0;
610 return false; 561 offset_ = run_end;
562 return stops_in_first_letter;
611 } 563 }
564 // We are here only if the DOM and/or layout trees are broken.
565 NOTREACHED();
612 } 566 }
613 if (layout_object->Style()->Visibility() != EVisibility::kVisible && 567 if (layout_object->Style()->Visibility() != EVisibility::kVisible &&
614 !IgnoresStyleVisibility()) 568 !IgnoresStyleVisibility())
615 return false; 569 return false;
616 const unsigned run_start = offset_; 570 const unsigned run_start = offset_ - layout_object->TextStartOffset();
617 const unsigned str_length = str.length(); 571 const unsigned str_length = str.length();
618 const unsigned end = (text_node == end_container_) ? end_offset_ : INT_MAX; 572 const unsigned end = (text_node == end_container_)
573 ? end_offset_ - layout_object->TextStartOffset()
574 : INT_MAX;
619 const unsigned run_end = std::min(str_length, end); 575 const unsigned run_end = std::min(str_length, end);
620 576
621 if (run_start >= run_end) 577 if (run_start >= run_end)
622 return true; 578 return true;
623 579
624 EmitText(text_node, text_node->GetLayoutObject(), run_start, run_end); 580 EmitText(text_node, text_node->GetLayoutObject(), run_start, run_end);
625 return true; 581 return true;
626 } 582 }
627 583
628 if (layout_object->FirstTextBox()) 584 if (layout_object->FirstTextBox())
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 return subrun_end + 1; 647 return subrun_end + 1;
692 648
693 return subrun_end; 649 return subrun_end;
694 } 650 }
695 651
696 template <typename Strategy> 652 template <typename Strategy>
697 void TextIteratorAlgorithm<Strategy>::HandleTextBox() { 653 void TextIteratorAlgorithm<Strategy>::HandleTextBox() {
698 LayoutText* layout_object = first_letter_text_ 654 LayoutText* layout_object = first_letter_text_
699 ? first_letter_text_ 655 ? first_letter_text_
700 : ToLayoutText(node_->GetLayoutObject()); 656 : ToLayoutText(node_->GetLayoutObject());
657 const unsigned text_start_offset = layout_object->TextStartOffset();
701 658
702 if (layout_object->Style()->Visibility() != EVisibility::kVisible && 659 if (layout_object->Style()->Visibility() != EVisibility::kVisible &&
703 !IgnoresStyleVisibility()) { 660 !IgnoresStyleVisibility()) {
704 text_box_ = nullptr; 661 text_box_ = nullptr;
705 } else { 662 } else {
706 String str = layout_object->GetText(); 663 String str = layout_object->GetText();
707 const unsigned start = offset_; 664 // Start and end offsets in |str|, i.e., str[start..end - 1] should be
708 const unsigned end = (node_ == end_container_) 665 // emitted (after handling whitespace collapsing).
709 ? static_cast<unsigned>(end_offset_) 666 const unsigned start = offset_ - layout_object->TextStartOffset();
710 : INT_MAX; 667 const unsigned end =
668 (node_ == end_container_)
669 ? static_cast<unsigned>(end_offset_) - text_start_offset
670 : INT_MAX;
711 while (text_box_) { 671 while (text_box_) {
712 const unsigned text_box_start = text_box_->Start(); 672 const unsigned text_box_start = text_box_->Start();
713 const unsigned run_start = std::max(text_box_start, start); 673 const unsigned run_start = std::max(text_box_start, start);
714 674
715 // Check for collapsed space at the start of this run. 675 // Check for collapsed space at the start of this run.
716 InlineTextBox* first_text_box = 676 InlineTextBox* first_text_box =
717 layout_object->ContainsReversedText() 677 layout_object->ContainsReversedText()
718 ? (sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]) 678 ? (sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0])
719 : layout_object->FirstTextBox(); 679 : layout_object->FirstTextBox();
720 const bool need_space = last_text_node_ended_with_collapsed_space_ || 680 const bool need_space = last_text_node_ended_with_collapsed_space_ ||
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
765 // or a run of characters that does not include a newline. 725 // or a run of characters that does not include a newline.
766 // This effectively translates newlines to spaces without copying the 726 // This effectively translates newlines to spaces without copying the
767 // text. 727 // text.
768 if (str[run_start] == '\n') { 728 if (str[run_start] == '\n') {
769 // We need to preserve new lines in case of PreLine. 729 // We need to preserve new lines in case of PreLine.
770 // See bug crbug.com/317365. 730 // See bug crbug.com/317365.
771 if (layout_object->Style()->WhiteSpace() == EWhiteSpace::kPreLine) 731 if (layout_object->Style()->WhiteSpace() == EWhiteSpace::kPreLine)
772 SpliceBuffer('\n', node_, 0, run_start, run_start); 732 SpliceBuffer('\n', node_, 0, run_start, run_start);
773 else 733 else
774 SpliceBuffer(kSpaceCharacter, node_, 0, run_start, run_start + 1); 734 SpliceBuffer(kSpaceCharacter, node_, 0, run_start, run_start + 1);
775 offset_ = run_start + 1; 735 offset_ = text_start_offset + run_start + 1;
776 } else { 736 } else {
777 size_t subrun_end = str.find('\n', run_start); 737 size_t subrun_end = str.find('\n', run_start);
778 if (subrun_end == kNotFound || subrun_end > run_end) { 738 if (subrun_end == kNotFound || subrun_end > run_end) {
779 subrun_end = run_end; 739 subrun_end = run_end;
780 subrun_end = 740 subrun_end =
781 RestoreCollapsedTrailingSpace(next_text_box, subrun_end); 741 RestoreCollapsedTrailingSpace(next_text_box, subrun_end);
782 } 742 }
783 743
784 offset_ = subrun_end; 744 offset_ = text_start_offset + subrun_end;
785 EmitText(node_, layout_object, run_start, subrun_end); 745 EmitText(node_, layout_object, run_start, subrun_end);
786 } 746 }
787 747
788 // If we are doing a subrun that doesn't go to the end of the text box, 748 // If we are doing a subrun that doesn't go to the end of the text box,
789 // come back again to finish handling this text box; don't advance to 749 // come back again to finish handling this text box; don't advance to
790 // the next one. 750 // the next one.
791 if (static_cast<unsigned>(text_state_.PositionEndOffset()) < 751 if (static_cast<unsigned>(text_state_.PositionEndOffset()) <
792 text_box_end) 752 text_box_end)
793 return; 753 return;
794 754
(...skipping 27 matching lines...) Expand all
822 } 782 }
823 783
824 if (ShouldProceedToRemainingText()) { 784 if (ShouldProceedToRemainingText()) {
825 ProceedToRemainingText(); 785 ProceedToRemainingText();
826 HandleTextBox(); 786 HandleTextBox();
827 } 787 }
828 } 788 }
829 789
830 template <typename Strategy> 790 template <typename Strategy>
831 bool TextIteratorAlgorithm<Strategy>::ShouldProceedToRemainingText() const { 791 bool TextIteratorAlgorithm<Strategy>::ShouldProceedToRemainingText() const {
832 // TODO(xiaochengh): Handle the case where the iterator should stop in 792 if (text_box_ || !remaining_text_box_)
833 // :first-letter. 793 return false;
834 return !text_box_ && remaining_text_box_; 794 if (node_ != end_container_)
795 return true;
796 return offset_ < end_offset_;
835 } 797 }
836 798
837 template <typename Strategy> 799 template <typename Strategy>
838 void TextIteratorAlgorithm<Strategy>::ProceedToRemainingText() { 800 void TextIteratorAlgorithm<Strategy>::ProceedToRemainingText() {
839 text_box_ = remaining_text_box_; 801 text_box_ = remaining_text_box_;
840 remaining_text_box_ = 0; 802 remaining_text_box_ = 0;
841 first_letter_text_ = nullptr; 803 first_letter_text_ = nullptr;
842 // TODO(xiaochengh): |offset_| should be set to the starting offset of the 804 offset_ = ToLayoutText(node_->GetLayoutObject())->TextStartOffset();
843 // remaining text;
844 offset_ = 0;
845 } 805 }
846 806
847 template <typename Strategy> 807 template <typename Strategy>
848 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter( 808 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter(
849 LayoutTextFragment* layout_object) { 809 LayoutTextFragment* layout_object) {
850 handled_first_letter_ = true; 810 handled_first_letter_ = true;
851 811
852 if (!layout_object->IsRemainingTextLayoutObject()) 812 if (!layout_object->IsRemainingTextLayoutObject())
853 return; 813 return;
854 814
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after
1223 int text_end_offset) { 1183 int text_end_offset) {
1224 // Since m_lastTextNodeEndedWithCollapsedSpace seems better placed in 1184 // Since m_lastTextNodeEndedWithCollapsedSpace seems better placed in
1225 // TextIterator, but is always reset when we call spliceBuffer, we 1185 // TextIterator, but is always reset when we call spliceBuffer, we
1226 // wrap TextIteratorTextState::spliceBuffer() with this function. 1186 // wrap TextIteratorTextState::spliceBuffer() with this function.
1227 text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset, 1187 text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset,
1228 text_end_offset); 1188 text_end_offset);
1229 last_text_node_ended_with_collapsed_space_ = false; 1189 last_text_node_ended_with_collapsed_space_ = false;
1230 } 1190 }
1231 1191
1232 template <typename Strategy> 1192 template <typename Strategy>
1233 int TextIteratorAlgorithm<Strategy>::AdjustedStartForFirstLetter(
1234 const Node& text_node,
1235 const LayoutText& layout_object,
1236 int text_start_offset,
1237 int text_end_offset) {
1238 if (first_letter_start_offset_ == kInvalidTextOffset)
1239 return text_start_offset;
1240 if (text_node != start_container_)
1241 return text_start_offset;
1242 if (!layout_object.IsTextFragment())
1243 return text_start_offset;
1244 if (ToLayoutTextFragment(layout_object).IsRemainingTextLayoutObject())
1245 return text_start_offset;
1246 if (text_end_offset <= first_letter_start_offset_)
1247 return text_start_offset;
1248 int adjusted_offset = std::max(text_start_offset, first_letter_start_offset_);
1249 first_letter_start_offset_ = kInvalidTextOffset;
1250 return adjusted_offset;
1251 }
1252
1253 template <typename Strategy>
1254 int TextIteratorAlgorithm<Strategy>::AdjustedStartForRemainingText(
1255 const Node& text_node,
1256 const LayoutText& layout_object,
1257 int text_start_offset,
1258 int text_end_offset) {
1259 if (remaining_text_start_offset_ == kInvalidTextOffset)
1260 return text_start_offset;
1261 if (text_node != start_container_)
1262 return text_start_offset;
1263 if (!layout_object.IsTextFragment())
1264 return text_start_offset;
1265 if (!ToLayoutTextFragment(layout_object).IsRemainingTextLayoutObject())
1266 return text_start_offset;
1267 if (text_end_offset <= remaining_text_start_offset_)
1268 return text_start_offset;
1269 int adjusted_offset =
1270 std::max(text_start_offset, remaining_text_start_offset_);
1271 remaining_text_start_offset_ = kInvalidTextOffset;
1272 return adjusted_offset;
1273 }
1274
1275 template <typename Strategy>
1276 void TextIteratorAlgorithm<Strategy>::EmitText(Node* text_node, 1193 void TextIteratorAlgorithm<Strategy>::EmitText(Node* text_node,
1277 LayoutText* layout_object, 1194 LayoutText* layout_object,
1278 int text_start_offset, 1195 int text_start_offset,
1279 int text_end_offset) { 1196 int text_end_offset) {
1280 text_start_offset = AdjustedStartForFirstLetter(
1281 *text_node, *layout_object, text_start_offset, text_end_offset);
1282 text_start_offset = AdjustedStartForRemainingText(
1283 *text_node, *layout_object, text_start_offset, text_end_offset);
1284 // Since m_lastTextNodeEndedWithCollapsedSpace seems better placed in 1197 // Since m_lastTextNodeEndedWithCollapsedSpace seems better placed in
1285 // TextIterator, but is always reset when we call spliceBuffer, we 1198 // TextIterator, but is always reset when we call spliceBuffer, we
1286 // wrap TextIteratorTextState::spliceBuffer() with this function. 1199 // wrap TextIteratorTextState::spliceBuffer() with this function.
1287 text_state_.EmitText(text_node, layout_object, text_start_offset, 1200 text_state_.EmitText(text_node, layout_object, text_start_offset,
1288 text_end_offset); 1201 text_end_offset);
1289 last_text_node_ended_with_collapsed_space_ = false; 1202 last_text_node_ended_with_collapsed_space_ = false;
1290 } 1203 }
1291 1204
1292 template <typename Strategy> 1205 template <typename Strategy>
1293 EphemeralRangeTemplate<Strategy> TextIteratorAlgorithm<Strategy>::Range() 1206 EphemeralRangeTemplate<Strategy> TextIteratorAlgorithm<Strategy>::Range()
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
1467 String PlainText(const EphemeralRangeInFlatTree& range, 1380 String PlainText(const EphemeralRangeInFlatTree& range,
1468 const TextIteratorBehavior& behavior) { 1381 const TextIteratorBehavior& behavior) {
1469 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); 1382 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior);
1470 } 1383 }
1471 1384
1472 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; 1385 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>;
1473 template class CORE_TEMPLATE_EXPORT 1386 template class CORE_TEMPLATE_EXPORT
1474 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; 1387 TextIteratorAlgorithm<EditingInFlatTreeStrategy>;
1475 1388
1476 } // namespace blink 1389 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698