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

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

Issue 2903693005: Introduce a wrapper class to handle text node in TextIterator (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 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 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 145
146 bool IsRenderedAsTable(const Node* node) { 146 bool IsRenderedAsTable(const Node* node) {
147 if (!node || !node->IsElementNode()) 147 if (!node || !node->IsElementNode())
148 return false; 148 return false;
149 LayoutObject* layout_object = node->GetLayoutObject(); 149 LayoutObject* layout_object = node->GetLayoutObject();
150 return layout_object && layout_object->IsTable(); 150 return layout_object && layout_object->IsTable();
151 } 151 }
152 152
153 } // namespace 153 } // namespace
154 154
155 TextNodeContentExtractor::TextNodeContentExtractor(
156 const TextIteratorBehavior& behavior,
157 TextIteratorTextState& text_state)
158 : start_offset_(0),
yosin_UTC9 2017/05/25 06:44:09 Initialization of member variables should be done
159 end_offset_(0),
160 offset_(0),
161 text_box_(nullptr),
162 needs_handle_pre_formatted_text_node_(false),
163 handled_first_letter_(false),
164 remaining_text_box_(nullptr),
165 first_letter_text_(nullptr),
166 last_text_node_ended_with_collapsed_space_(false),
167 sorted_text_boxes_position_(0),
168 behavior_(behavior),
169 text_state_(text_state) {}
170
155 template <typename Strategy> 171 template <typename Strategy>
156 TextIteratorAlgorithm<Strategy>::TextIteratorAlgorithm( 172 TextIteratorAlgorithm<Strategy>::TextIteratorAlgorithm(
157 const PositionTemplate<Strategy>& start, 173 const PositionTemplate<Strategy>& start,
158 const PositionTemplate<Strategy>& end, 174 const PositionTemplate<Strategy>& end,
159 const TextIteratorBehavior& behavior) 175 const TextIteratorBehavior& behavior)
160 : offset_(0), 176 : start_container_(nullptr),
161 start_container_(nullptr),
162 start_offset_(0), 177 start_offset_(0),
163 end_container_(nullptr), 178 end_container_(nullptr),
164 end_offset_(0), 179 end_offset_(0),
165 needs_another_newline_(false), 180 needs_another_newline_(false),
166 text_box_(nullptr),
167 remaining_text_box_(nullptr),
168 first_letter_text_(nullptr),
169 last_text_node_(nullptr), 181 last_text_node_(nullptr),
170 last_text_node_ended_with_collapsed_space_(false),
171 sorted_text_boxes_position_(0),
172 behavior_(AdjustBehaviorFlags<Strategy>(behavior)), 182 behavior_(AdjustBehaviorFlags<Strategy>(behavior)),
173 needs_handle_pre_formatted_text_node_(false),
174 handled_first_letter_(false),
175 should_stop_(false), 183 should_stop_(false),
176 handle_shadow_root_(false), 184 handle_shadow_root_(false),
177 text_state_(behavior_) { 185 text_state_(behavior_),
186 text_extractor_(behavior_, text_state_) {
178 DCHECK(start.IsNotNull()); 187 DCHECK(start.IsNotNull());
179 DCHECK(end.IsNotNull()); 188 DCHECK(end.IsNotNull());
180 189
181 // TODO(dglazkov): TextIterator should not be created for documents that don't 190 // TODO(dglazkov): TextIterator should not be created for documents that don't
182 // have a frame, but it currently still happens in some cases. See 191 // have a frame, but it currently still happens in some cases. See
183 // http://crbug.com/591877 for details. 192 // http://crbug.com/591877 for details.
184 DCHECK(!start.GetDocument()->View() || 193 DCHECK(!start.GetDocument()->View() ||
185 !start.GetDocument()->View()->NeedsLayout()); 194 !start.GetDocument()->View()->NeedsLayout());
186 DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate()); 195 DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate());
187 196
188 if (start.CompareTo(end) > 0) { 197 if (start.CompareTo(end) > 0) {
189 Initialize(end.ComputeContainerNode(), end.ComputeOffsetInContainerNode(), 198 Initialize(end.ComputeContainerNode(), end.ComputeOffsetInContainerNode(),
190 start.ComputeContainerNode(), 199 start.ComputeContainerNode(),
191 start.ComputeOffsetInContainerNode()); 200 start.ComputeOffsetInContainerNode());
192 return; 201 return;
193 } 202 }
194 Initialize(start.ComputeContainerNode(), start.ComputeOffsetInContainerNode(), 203 Initialize(start.ComputeContainerNode(), start.ComputeOffsetInContainerNode(),
195 end.ComputeContainerNode(), end.ComputeOffsetInContainerNode()); 204 end.ComputeContainerNode(), end.ComputeOffsetInContainerNode());
196 } 205 }
197 206
207 void TextNodeContentExtractor::SetBoundaries(Node* start_container,
208 int start_offset,
209 Node* end_container,
210 int end_offset) {
211 start_container_ = start_container;
212 start_offset_ = start_offset;
213 end_container_ = end_container;
214 end_offset_ = end_offset;
215 }
216
198 template <typename Strategy> 217 template <typename Strategy>
199 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container, 218 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container,
200 int start_offset, 219 int start_offset,
201 Node* end_container, 220 Node* end_container,
202 int end_offset) { 221 int end_offset) {
203 DCHECK(start_container); 222 DCHECK(start_container);
204 DCHECK(end_container); 223 DCHECK(end_container);
205 224
225 text_extractor_.SetBoundaries(start_container, start_offset, end_container,
226 end_offset);
227
206 // Remember the range - this does not change. 228 // Remember the range - this does not change.
207 start_container_ = start_container; 229 start_container_ = start_container;
208 start_offset_ = start_offset; 230 start_offset_ = start_offset;
209 end_container_ = end_container; 231 end_container_ = end_container;
210 end_offset_ = end_offset; 232 end_offset_ = end_offset;
211 end_node_ = 233 end_node_ =
212 end_container && !end_container->IsCharacterDataNode() && end_offset > 0 234 end_container && !end_container->IsCharacterDataNode() && end_offset > 0
213 ? Strategy::ChildAt(*end_container, end_offset - 1) 235 ? Strategy::ChildAt(*end_container, end_offset - 1)
214 : nullptr; 236 : nullptr;
215 237
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 279
258 template <typename Strategy> 280 template <typename Strategy>
259 bool TextIteratorAlgorithm<Strategy>::IsInsideAtomicInlineElement() const { 281 bool TextIteratorAlgorithm<Strategy>::IsInsideAtomicInlineElement() const {
260 if (AtEnd() || length() != 1 || !node_) 282 if (AtEnd() || length() != 1 || !node_)
261 return false; 283 return false;
262 284
263 LayoutObject* layout_object = node_->GetLayoutObject(); 285 LayoutObject* layout_object = node_->GetLayoutObject();
264 return layout_object && layout_object->IsAtomicInlineLevel(); 286 return layout_object && layout_object->IsAtomicInlineLevel();
265 } 287 }
266 288
267 template <typename Strategy> 289 bool TextNodeContentExtractor::HandleRemainingTextRuns() {
268 bool TextIteratorAlgorithm<Strategy>::HandleRemainingTextRuns() {
269 if (ShouldProceedToRemainingText()) 290 if (ShouldProceedToRemainingText())
270 ProceedToRemainingText(); 291 ProceedToRemainingText();
271 // handle remembered text box 292 // handle remembered text box
272 if (text_box_) { 293 if (text_box_) {
273 HandleTextBox(); 294 HandleTextBox();
274 return text_state_.PositionNode(); 295 return text_state_.PositionNode();
275 } 296 }
276 if (needs_handle_pre_formatted_text_node_) { 297 if (needs_handle_pre_formatted_text_node_) {
277 HandlePreFormattedTextNode(); 298 HandlePreFormattedTextNode();
278 return text_state_.PositionNode(); 299 return text_state_.PositionNode();
(...skipping 21 matching lines...) Expand all
300 // line break begins. 321 // line break begins.
301 // FIXME: It would be cleaner if we emitted two newlines during the last 322 // FIXME: It would be cleaner if we emitted two newlines during the last
302 // iteration, instead of using m_needsAnotherNewline. 323 // iteration, instead of using m_needsAnotherNewline.
303 Node* last_child = Strategy::LastChild(*node_); 324 Node* last_child = Strategy::LastChild(*node_);
304 Node* base_node = last_child ? last_child : node_.Get(); 325 Node* base_node = last_child ? last_child : node_.Get();
305 SpliceBuffer('\n', Strategy::Parent(*base_node), base_node, 1, 1); 326 SpliceBuffer('\n', Strategy::Parent(*base_node), base_node, 1, 1);
306 needs_another_newline_ = false; 327 needs_another_newline_ = false;
307 return; 328 return;
308 } 329 }
309 330
310 if (HandleRemainingTextRuns()) 331 if (text_extractor_.HandleRemainingTextRuns())
311 return; 332 return;
312 333
313 while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) { 334 while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) {
314 if (!should_stop_ && StopsOnFormControls() && 335 if (!should_stop_ && StopsOnFormControls() &&
315 HTMLFormControlElement::EnclosingFormControlElement(node_)) 336 HTMLFormControlElement::EnclosingFormControlElement(node_))
316 should_stop_ = true; 337 should_stop_ = true;
317 338
318 // if the range ends at offset 0 of an element, represent the 339 // if the range ends at offset 0 of an element, represent the
319 // position, but not the content, of that element e.g. if the 340 // position, but not the content, of that element e.g. if the
320 // node is a blockflow element, emit a newline that 341 // node is a blockflow element, emit a newline that
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 return false; 525 return false;
505 526
506 DCHECK(fragment->GetFirstLetterPseudoElement()); 527 DCHECK(fragment->GetFirstLetterPseudoElement());
507 LayoutObject* pseudo_element_layout_object = 528 LayoutObject* pseudo_element_layout_object =
508 fragment->GetFirstLetterPseudoElement()->GetLayoutObject(); 529 fragment->GetFirstLetterPseudoElement()->GetLayoutObject();
509 return pseudo_element_layout_object && 530 return pseudo_element_layout_object &&
510 pseudo_element_layout_object->Style()->Visibility() == 531 pseudo_element_layout_object->Style()->Visibility() ==
511 EVisibility::kVisible; 532 EVisibility::kVisible;
512 } 533 }
513 534
514 template <typename Strategy> 535 bool TextNodeContentExtractor::ShouldHandleFirstLetter(
515 bool TextIteratorAlgorithm<Strategy>::ShouldHandleFirstLetter(
516 const LayoutText& layout_text) const { 536 const LayoutText& layout_text) const {
517 if (handled_first_letter_) 537 if (handled_first_letter_)
518 return false; 538 return false;
519 if (!layout_text.IsTextFragment()) 539 if (!layout_text.IsTextFragment())
520 return false; 540 return false;
521 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text); 541 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text);
522 return offset_ < static_cast<int>(text_fragment.TextStartOffset()); 542 return offset_ < static_cast<int>(text_fragment.TextStartOffset());
523 } 543 }
524 544
525 template <typename Strategy> 545 void TextNodeContentExtractor::HandlePreFormattedTextNode() {
526 void TextIteratorAlgorithm<Strategy>::HandlePreFormattedTextNode() {
527 // TODO(xiaochengh): Get rid of repeated computation of these fields. 546 // TODO(xiaochengh): Get rid of repeated computation of these fields.
528 LayoutText* const layout_object = text_node_->GetLayoutObject(); 547 LayoutText* const layout_object = text_node_->GetLayoutObject();
529 const String str = layout_object->GetText(); 548 const String str = layout_object->GetText();
530 549
531 needs_handle_pre_formatted_text_node_ = false; 550 needs_handle_pre_formatted_text_node_ = false;
532 551
533 if (last_text_node_ended_with_collapsed_space_) { 552 if (last_text_node_ended_with_collapsed_space_) {
534 last_text_node_ended_with_collapsed_space_ = false; 553 last_text_node_ended_with_collapsed_space_ = false;
535 if (HasVisibleTextNode(layout_object)) { 554 if (HasVisibleTextNode(layout_object)) {
536 if (!behavior_.CollapseTrailingSpace() || 555 if (!behavior_.CollapseTrailingSpace() ||
537 (offset_ > 0 && str[offset_ - 1] == ' ')) { 556 (offset_ > 0 && str[offset_ - 1] == ' ')) {
538 SpliceBuffer(kSpaceCharacter, text_node_, 0, offset_, offset_); 557 text_state_.SpliceBuffer(kSpaceCharacter, text_node_, 0, offset_,
558 offset_);
539 needs_handle_pre_formatted_text_node_ = true; 559 needs_handle_pre_formatted_text_node_ = true;
540 return; 560 return;
541 } 561 }
542 } 562 }
543 } 563 }
544 if (ShouldHandleFirstLetter(*layout_object)) { 564 if (ShouldHandleFirstLetter(*layout_object)) {
545 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); 565 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object));
546 if (first_letter_text_) { 566 if (first_letter_text_) {
547 const String first_letter = first_letter_text_->GetText(); 567 const String first_letter = first_letter_text_->GetText();
548 const unsigned run_start = offset_; 568 const unsigned run_start = offset_;
549 const bool stops_in_first_letter = 569 const bool stops_in_first_letter =
550 text_node_ == end_container_ && 570 text_node_ == end_container_ &&
551 end_offset_ <= static_cast<int>(first_letter.length()); 571 end_offset_ <= static_cast<int>(first_letter.length());
552 const unsigned run_end = 572 const unsigned run_end =
553 stops_in_first_letter ? end_offset_ : first_letter.length(); 573 stops_in_first_letter ? end_offset_ : first_letter.length();
554 EmitText(text_node_, first_letter_text_, run_start, run_end); 574 text_state_.EmitText(text_node_, first_letter_text_, run_start, run_end);
555 first_letter_text_ = nullptr; 575 first_letter_text_ = nullptr;
556 text_box_ = 0; 576 text_box_ = 0;
557 offset_ = run_end; 577 offset_ = run_end;
558 if (!stops_in_first_letter) 578 if (!stops_in_first_letter)
559 needs_handle_pre_formatted_text_node_ = true; 579 needs_handle_pre_formatted_text_node_ = true;
560 return; 580 return;
561 } 581 }
562 // We are here only if the DOM and/or layout trees are broken. 582 // We are here only if the DOM and/or layout trees are broken.
563 // For robustness, we should stop processing this node. 583 // For robustness, we should stop processing this node.
564 NOTREACHED(); 584 NOTREACHED();
565 return; 585 return;
566 } 586 }
567 if (layout_object->Style()->Visibility() != EVisibility::kVisible && 587 if (layout_object->Style()->Visibility() != EVisibility::kVisible &&
568 !IgnoresStyleVisibility()) 588 !IgnoresStyleVisibility())
569 return; 589 return;
570 DCHECK_GE(static_cast<unsigned>(offset_), layout_object->TextStartOffset()); 590 DCHECK_GE(static_cast<unsigned>(offset_), layout_object->TextStartOffset());
571 const unsigned run_start = offset_ - layout_object->TextStartOffset(); 591 const unsigned run_start = offset_ - layout_object->TextStartOffset();
572 const unsigned str_length = str.length(); 592 const unsigned str_length = str.length();
573 const unsigned end = (text_node_ == end_container_) 593 const unsigned end = (text_node_ == end_container_)
574 ? end_offset_ - layout_object->TextStartOffset() 594 ? end_offset_ - layout_object->TextStartOffset()
575 : str_length; 595 : str_length;
576 const unsigned run_end = std::min(str_length, end); 596 const unsigned run_end = std::min(str_length, end);
577 597
578 if (run_start >= run_end) 598 if (run_start >= run_end)
579 return; 599 return;
580 600
581 EmitText(text_node_, text_node_->GetLayoutObject(), run_start, run_end); 601 text_state_.EmitText(text_node_, text_node_->GetLayoutObject(), run_start,
602 run_end);
582 } 603 }
583 604
584 template <typename Strategy> 605 template <typename Strategy>
585 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() { 606 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() {
586 if (ExcludesAutofilledValue()) { 607 if (ExcludesAutofilledValue()) {
587 TextControlElement* control = EnclosingTextControl(node_); 608 TextControlElement* control = EnclosingTextControl(node_);
588 // For security reason, we don't expose suggested value if it is 609 // For security reason, we don't expose suggested value if it is
589 // auto-filled. 610 // auto-filled.
590 if (control && control->IsAutofilled()) 611 if (control && control->IsAutofilled())
591 return true; 612 return true;
592 } 613 }
593 614
594 DCHECK_NE(last_text_node_, node_) 615 DCHECK_NE(last_text_node_, node_)
595 << "We should never call HandleTextNode on the same node twice"; 616 << "We should never call HandleTextNode on the same node twice";
596 last_text_node_ = ToText(node_); 617 last_text_node_ = ToText(node_);
618 return text_extractor_.HandleTextNode(ToText(node_));
619 }
597 620
598 text_node_ = ToText(node_); 621 bool TextNodeContentExtractor::HandleTextNode(Text* node) {
622 text_node_ = node;
599 offset_ = text_node_ == start_container_ ? start_offset_ : 0; 623 offset_ = text_node_ == start_container_ ? start_offset_ : 0;
600 handled_first_letter_ = false; 624 handled_first_letter_ = false;
601 first_letter_text_ = nullptr; 625 first_letter_text_ = nullptr;
602 626
603 LayoutText* layout_object = text_node_->GetLayoutObject(); 627 LayoutText* layout_object = text_node_->GetLayoutObject();
604 String str = layout_object->GetText(); 628 String str = layout_object->GetText();
605 629
606 // handle pre-formatted text 630 // handle pre-formatted text
607 if (!layout_object->Style()->CollapseWhiteSpace()) { 631 if (!layout_object->Style()->CollapseWhiteSpace()) {
608 HandlePreFormattedTextNode(); 632 HandlePreFormattedTextNode();
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
641 InlineTextBox::CompareByStart); 665 InlineTextBox::CompareByStart);
642 sorted_text_boxes_position_ = 0; 666 sorted_text_boxes_position_ = 0;
643 text_box_ = sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]; 667 text_box_ = sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0];
644 } 668 }
645 669
646 HandleTextBox(); 670 HandleTextBox();
647 return true; 671 return true;
648 } 672 }
649 673
650 // Restore the collapsed space for copy & paste. See http://crbug.com/318925 674 // Restore the collapsed space for copy & paste. See http://crbug.com/318925
651 template <typename Strategy> 675 size_t TextNodeContentExtractor::RestoreCollapsedTrailingSpace(
652 size_t TextIteratorAlgorithm<Strategy>::RestoreCollapsedTrailingSpace(
653 InlineTextBox* next_text_box, 676 InlineTextBox* next_text_box,
654 size_t subrun_end) { 677 size_t subrun_end) {
655 if (next_text_box || !text_box_->Root().NextRootBox() || 678 if (next_text_box || !text_box_->Root().NextRootBox() ||
656 text_box_->Root().LastChild() != text_box_) 679 text_box_->Root().LastChild() != text_box_)
657 return subrun_end; 680 return subrun_end;
658 681
659 const String& text = text_node_->GetLayoutObject()->GetText(); 682 const String& text = text_node_->GetLayoutObject()->GetText();
660 if (text.EndsWith(' ') == 0 || subrun_end != text.length() - 1 || 683 if (text.EndsWith(' ') == 0 || subrun_end != text.length() - 1 ||
661 text[subrun_end - 1] == ' ') 684 text[subrun_end - 1] == ' ')
662 return subrun_end; 685 return subrun_end;
663 686
664 // If there is the leading space in the next line, we don't need to restore 687 // If there is the leading space in the next line, we don't need to restore
665 // the trailing space. 688 // the trailing space.
666 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div> 689 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div>
667 InlineBox* first_box_of_next_line = 690 InlineBox* first_box_of_next_line =
668 text_box_->Root().NextRootBox()->FirstChild(); 691 text_box_->Root().NextRootBox()->FirstChild();
669 if (!first_box_of_next_line) 692 if (!first_box_of_next_line)
670 return subrun_end + 1; 693 return subrun_end + 1;
671 Node* first_node_of_next_line = 694 Node* first_node_of_next_line =
672 first_box_of_next_line->GetLineLayoutItem().GetNode(); 695 first_box_of_next_line->GetLineLayoutItem().GetNode();
673 if (!first_node_of_next_line || 696 if (!first_node_of_next_line ||
674 first_node_of_next_line->nodeValue()[0] != ' ') 697 first_node_of_next_line->nodeValue()[0] != ' ')
675 return subrun_end + 1; 698 return subrun_end + 1;
676 699
677 return subrun_end; 700 return subrun_end;
678 } 701 }
679 702
680 template <typename Strategy> 703 void TextNodeContentExtractor::HandleTextBox() {
681 void TextIteratorAlgorithm<Strategy>::HandleTextBox() {
682 LayoutText* layout_object = 704 LayoutText* layout_object =
683 first_letter_text_ ? first_letter_text_ : text_node_->GetLayoutObject(); 705 first_letter_text_ ? first_letter_text_ : text_node_->GetLayoutObject();
684 const unsigned text_start_offset = layout_object->TextStartOffset(); 706 const unsigned text_start_offset = layout_object->TextStartOffset();
685 707
686 if (layout_object->Style()->Visibility() != EVisibility::kVisible && 708 if (layout_object->Style()->Visibility() != EVisibility::kVisible &&
687 !IgnoresStyleVisibility()) { 709 !IgnoresStyleVisibility()) {
688 text_box_ = nullptr; 710 text_box_ = nullptr;
689 } else { 711 } else {
690 String str = layout_object->GetText(); 712 String str = layout_object->GetText();
691 // Start and end offsets in |str|, i.e., str[start..end - 1] should be 713 // Start and end offsets in |str|, i.e., str[start..end - 1] should be
(...skipping 17 matching lines...) Expand all
709 text_box_start == run_start && run_start > 0); 731 text_box_start == run_start && run_start > 0);
710 last_text_node_ended_with_collapsed_space_ = false; 732 last_text_node_ended_with_collapsed_space_ = false;
711 if (need_space && 733 if (need_space &&
712 !layout_object->Style()->IsCollapsibleWhiteSpace( 734 !layout_object->Style()->IsCollapsibleWhiteSpace(
713 text_state_.LastCharacter()) && 735 text_state_.LastCharacter()) &&
714 text_state_.LastCharacter()) { 736 text_state_.LastCharacter()) {
715 if (run_start > 0 && str[run_start - 1] == ' ') { 737 if (run_start > 0 && str[run_start - 1] == ' ') {
716 unsigned space_run_start = run_start - 1; 738 unsigned space_run_start = run_start - 1;
717 while (space_run_start > 0 && str[space_run_start - 1] == ' ') 739 while (space_run_start > 0 && str[space_run_start - 1] == ' ')
718 --space_run_start; 740 --space_run_start;
719 EmitText(text_node_, layout_object, space_run_start, 741 text_state_.EmitText(text_node_, layout_object, space_run_start,
yosin_UTC9 2017/05/25 06:44:09 Let's introduce TextNodeContentExtract::EmitText()
Xiaocheng 2017/05/25 23:47:58 Done.
720 space_run_start + 1); 742 space_run_start + 1);
721 } else { 743 } else {
722 SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start, run_start); 744 text_state_.SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start,
yosin_UTC9 2017/05/25 06:44:09 Let's introduce TextNodeContentExtract::SpliceBuff
Xiaocheng 2017/05/25 23:47:58 Done.
745 run_start);
723 } 746 }
724 return; 747 return;
725 } 748 }
726 const unsigned text_box_end = text_box_start + text_box_->Len(); 749 const unsigned text_box_end = text_box_start + text_box_->Len();
727 const unsigned run_end = std::min(text_box_end, end); 750 const unsigned run_end = std::min(text_box_end, end);
728 751
729 // Determine what the next text box will be, but don't advance yet 752 // Determine what the next text box will be, but don't advance yet
730 InlineTextBox* next_text_box = nullptr; 753 InlineTextBox* next_text_box = nullptr;
731 if (layout_object->ContainsReversedText()) { 754 if (layout_object->ContainsReversedText()) {
732 if (sorted_text_boxes_position_ + 1 < sorted_text_boxes_.size()) 755 if (sorted_text_boxes_position_ + 1 < sorted_text_boxes_.size())
(...skipping 17 matching lines...) Expand all
750 773
751 if (run_start < run_end) { 774 if (run_start < run_end) {
752 // Handle either a single newline character (which becomes a space), 775 // Handle either a single newline character (which becomes a space),
753 // or a run of characters that does not include a newline. 776 // or a run of characters that does not include a newline.
754 // This effectively translates newlines to spaces without copying the 777 // This effectively translates newlines to spaces without copying the
755 // text. 778 // text.
756 if (str[run_start] == '\n') { 779 if (str[run_start] == '\n') {
757 // We need to preserve new lines in case of PreLine. 780 // We need to preserve new lines in case of PreLine.
758 // See bug crbug.com/317365. 781 // See bug crbug.com/317365.
759 if (layout_object->Style()->WhiteSpace() == EWhiteSpace::kPreLine) { 782 if (layout_object->Style()->WhiteSpace() == EWhiteSpace::kPreLine) {
760 SpliceBuffer('\n', text_node_, 0, run_start, run_start); 783 text_state_.SpliceBuffer('\n', text_node_, 0, run_start, run_start);
761 } else { 784 } else {
762 SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start, 785 text_state_.SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start,
763 run_start + 1); 786 run_start + 1);
764 } 787 }
765 offset_ = text_start_offset + run_start + 1; 788 offset_ = text_start_offset + run_start + 1;
766 } else { 789 } else {
767 size_t subrun_end = str.find('\n', run_start); 790 size_t subrun_end = str.find('\n', run_start);
768 if (subrun_end == kNotFound || subrun_end > run_end) { 791 if (subrun_end == kNotFound || subrun_end > run_end) {
769 subrun_end = run_end; 792 subrun_end = run_end;
770 subrun_end = 793 subrun_end =
771 RestoreCollapsedTrailingSpace(next_text_box, subrun_end); 794 RestoreCollapsedTrailingSpace(next_text_box, subrun_end);
772 } 795 }
773 796
774 offset_ = text_start_offset + subrun_end; 797 offset_ = text_start_offset + subrun_end;
775 EmitText(text_node_, layout_object, run_start, subrun_end); 798 text_state_.EmitText(text_node_, layout_object, run_start,
799 subrun_end);
776 } 800 }
777 801
778 // If we are doing a subrun that doesn't go to the end of the text box, 802 // If we are doing a subrun that doesn't go to the end of the text box,
779 // come back again to finish handling this text box; don't advance to 803 // come back again to finish handling this text box; don't advance to
780 // the next one. 804 // the next one.
781 if (static_cast<unsigned>(text_state_.PositionEndOffset()) < 805 if (static_cast<unsigned>(text_state_.PositionEndOffset()) <
782 text_box_end) 806 text_box_end)
783 return; 807 return;
784 808
785 if (behavior_.DoesNotEmitSpaceBeyondRangeEnd()) { 809 if (behavior_.DoesNotEmitSpaceBeyondRangeEnd()) {
(...skipping 24 matching lines...) Expand all
810 ++sorted_text_boxes_position_; 834 ++sorted_text_boxes_position_;
811 } 835 }
812 } 836 }
813 837
814 if (ShouldProceedToRemainingText()) { 838 if (ShouldProceedToRemainingText()) {
815 ProceedToRemainingText(); 839 ProceedToRemainingText();
816 HandleTextBox(); 840 HandleTextBox();
817 } 841 }
818 } 842 }
819 843
820 template <typename Strategy> 844 bool TextNodeContentExtractor::ShouldProceedToRemainingText() const {
821 bool TextIteratorAlgorithm<Strategy>::ShouldProceedToRemainingText() const {
822 if (text_box_ || !remaining_text_box_) 845 if (text_box_ || !remaining_text_box_)
823 return false; 846 return false;
824 if (text_node_ != end_container_) 847 if (text_node_ != end_container_)
825 return true; 848 return true;
826 return offset_ < end_offset_; 849 return offset_ < end_offset_;
827 } 850 }
828 851
829 template <typename Strategy> 852 void TextNodeContentExtractor::ProceedToRemainingText() {
830 void TextIteratorAlgorithm<Strategy>::ProceedToRemainingText() {
831 text_box_ = remaining_text_box_; 853 text_box_ = remaining_text_box_;
832 remaining_text_box_ = 0; 854 remaining_text_box_ = 0;
833 first_letter_text_ = nullptr; 855 first_letter_text_ = nullptr;
834 offset_ = text_node_->GetLayoutObject()->TextStartOffset(); 856 offset_ = text_node_->GetLayoutObject()->TextStartOffset();
835 } 857 }
836 858
837 template <typename Strategy> 859 void TextNodeContentExtractor::HandleTextNodeFirstLetter(
838 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter(
839 LayoutTextFragment* layout_object) { 860 LayoutTextFragment* layout_object) {
840 handled_first_letter_ = true; 861 handled_first_letter_ = true;
841 862
842 if (!layout_object->IsRemainingTextLayoutObject()) 863 if (!layout_object->IsRemainingTextLayoutObject())
843 return; 864 return;
844 865
845 FirstLetterPseudoElement* first_letter_element = 866 FirstLetterPseudoElement* first_letter_element =
846 layout_object->GetFirstLetterPseudoElement(); 867 layout_object->GetFirstLetterPseudoElement();
847 if (!first_letter_element) 868 if (!first_letter_element)
848 return; 869 return;
(...skipping 20 matching lines...) Expand all
869 890
870 // FIXME: Add isSVGImageElement. 891 // FIXME: Add isSVGImageElement.
871 if (isHTMLImageElement(element)) 892 if (isHTMLImageElement(element))
872 return true; 893 return true;
873 if (isHTMLInputElement(ToHTMLElement(*node)) && 894 if (isHTMLInputElement(ToHTMLElement(*node)) &&
874 toHTMLInputElement(*node).type() == InputTypeNames::image) 895 toHTMLInputElement(*node).type() == InputTypeNames::image)
875 return true; 896 return true;
876 return false; 897 return false;
877 } 898 }
878 899
879 template <typename Strategy> 900 bool TextNodeContentExtractor::FixLeadingWhiteSpaceForReplacedElement(
880 bool TextIteratorAlgorithm<Strategy>::FixLeadingWhiteSpaceForReplacedElement(
881 Node* parent) { 901 Node* parent) {
882 if (!last_text_node_ended_with_collapsed_space_) 902 if (!last_text_node_ended_with_collapsed_space_)
883 return false; 903 return false;
884 last_text_node_ended_with_collapsed_space_ = false; 904 last_text_node_ended_with_collapsed_space_ = false;
885 905
886 if (!behavior_.CollapseTrailingSpace()) { 906 if (!behavior_.CollapseTrailingSpace()) {
887 SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1); 907 text_state_.SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1);
888 return true; 908 return true;
889 } 909 }
890 if (text_node_) { 910 if (text_node_) {
891 const String str = text_node_->GetLayoutObject()->GetText(); 911 const String str = text_node_->GetLayoutObject()->GetText();
892 if (offset_ > 0 && str[offset_ - 1] == ' ') { 912 if (offset_ > 0 && str[offset_ - 1] == ' ') {
893 SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1); 913 text_state_.SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1);
894 return true; 914 return true;
895 } 915 }
896 } 916 }
897 917
898 return false; 918 return false;
899 } 919 }
900 920
901 template <typename Strategy> 921 template <typename Strategy>
902 bool TextIteratorAlgorithm<Strategy>::HandleReplacedElement() { 922 bool TextIteratorAlgorithm<Strategy>::HandleReplacedElement() {
903 if (fully_clipped_stack_.Top()) 923 if (fully_clipped_stack_.Top())
904 return false; 924 return false;
905 925
906 LayoutObject* layout_object = node_->GetLayoutObject(); 926 LayoutObject* layout_object = node_->GetLayoutObject();
907 if (layout_object->Style()->Visibility() != EVisibility::kVisible && 927 if (layout_object->Style()->Visibility() != EVisibility::kVisible &&
908 !IgnoresStyleVisibility()) 928 !IgnoresStyleVisibility())
909 return false; 929 return false;
910 930
911 if (EmitsObjectReplacementCharacter()) { 931 if (EmitsObjectReplacementCharacter()) {
912 SpliceBuffer(kObjectReplacementCharacter, Strategy::Parent(*node_), node_, 932 SpliceBuffer(kObjectReplacementCharacter, Strategy::Parent(*node_), node_,
913 0, 1); 933 0, 1);
914 return true; 934 return true;
915 } 935 }
916 936
917 if (last_text_node_) { 937 if (last_text_node_) {
918 if (FixLeadingWhiteSpaceForReplacedElement( 938 if (text_extractor_.FixLeadingWhiteSpaceForReplacedElement(
919 Strategy::Parent(*last_text_node_))) 939 Strategy::Parent(*last_text_node_)))
920 return false; 940 return false;
921 } 941 }
922 942
923 if (EntersTextControls() && layout_object->IsTextControl()) { 943 if (EntersTextControls() && layout_object->IsTextControl()) {
924 // The shadow tree should be already visited. 944 // The shadow tree should be already visited.
925 return true; 945 return true;
926 } 946 }
927 947
928 if (EmitsCharactersBetweenAllVisiblePositions()) { 948 if (EmitsCharactersBetweenAllVisiblePositions()) {
(...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after
1420 String PlainText(const EphemeralRangeInFlatTree& range, 1440 String PlainText(const EphemeralRangeInFlatTree& range,
1421 const TextIteratorBehavior& behavior) { 1441 const TextIteratorBehavior& behavior) {
1422 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); 1442 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior);
1423 } 1443 }
1424 1444
1425 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; 1445 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>;
1426 template class CORE_TEMPLATE_EXPORT 1446 template class CORE_TEMPLATE_EXPORT
1427 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; 1447 TextIteratorAlgorithm<EditingInFlatTreeStrategy>;
1428 1448
1429 } // namespace blink 1449 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698