OLD | NEW |
---|---|
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 Loading... | |
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 TextIteratorTextNodeHandler::TextIteratorTextNodeHandler( | |
156 const TextIteratorBehavior& behavior, | |
157 TextIteratorTextState* text_state) | |
158 : behavior_(behavior), text_state_(*text_state) {} | |
159 | |
155 template <typename Strategy> | 160 template <typename Strategy> |
156 TextIteratorAlgorithm<Strategy>::TextIteratorAlgorithm( | 161 TextIteratorAlgorithm<Strategy>::TextIteratorAlgorithm( |
157 const PositionTemplate<Strategy>& start, | 162 const PositionTemplate<Strategy>& start, |
158 const PositionTemplate<Strategy>& end, | 163 const PositionTemplate<Strategy>& end, |
159 const TextIteratorBehavior& behavior) | 164 const TextIteratorBehavior& behavior) |
160 : offset_(0), | 165 : start_container_(nullptr), |
161 start_container_(nullptr), | |
162 start_offset_(0), | 166 start_offset_(0), |
163 end_container_(nullptr), | 167 end_container_(nullptr), |
164 end_offset_(0), | 168 end_offset_(0), |
165 needs_another_newline_(false), | 169 needs_another_newline_(false), |
166 text_box_(nullptr), | |
167 remaining_text_box_(nullptr), | |
168 first_letter_text_(nullptr), | |
169 last_text_node_(nullptr), | 170 last_text_node_(nullptr), |
170 last_text_node_ended_with_collapsed_space_(false), | |
171 sorted_text_boxes_position_(0), | |
172 behavior_(AdjustBehaviorFlags<Strategy>(behavior)), | 171 behavior_(AdjustBehaviorFlags<Strategy>(behavior)), |
173 needs_handle_pre_formatted_text_node_(false), | |
174 handled_first_letter_(false), | |
175 should_stop_(false), | 172 should_stop_(false), |
176 handle_shadow_root_(false), | 173 handle_shadow_root_(false), |
177 text_state_(behavior_) { | 174 text_state_(behavior_), |
175 text_node_handler_(behavior_, &text_state_) { | |
178 DCHECK(start.IsNotNull()); | 176 DCHECK(start.IsNotNull()); |
179 DCHECK(end.IsNotNull()); | 177 DCHECK(end.IsNotNull()); |
180 | 178 |
181 // TODO(dglazkov): TextIterator should not be created for documents that don't | 179 // 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 | 180 // have a frame, but it currently still happens in some cases. See |
183 // http://crbug.com/591877 for details. | 181 // http://crbug.com/591877 for details. |
184 DCHECK(!start.GetDocument()->View() || | 182 DCHECK(!start.GetDocument()->View() || |
185 !start.GetDocument()->View()->NeedsLayout()); | 183 !start.GetDocument()->View()->NeedsLayout()); |
186 DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate()); | 184 DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate()); |
187 | 185 |
188 if (start.CompareTo(end) > 0) { | 186 if (start.CompareTo(end) > 0) { |
189 Initialize(end.ComputeContainerNode(), end.ComputeOffsetInContainerNode(), | 187 Initialize(end.ComputeContainerNode(), end.ComputeOffsetInContainerNode(), |
190 start.ComputeContainerNode(), | 188 start.ComputeContainerNode(), |
191 start.ComputeOffsetInContainerNode()); | 189 start.ComputeOffsetInContainerNode()); |
192 return; | 190 return; |
193 } | 191 } |
194 Initialize(start.ComputeContainerNode(), start.ComputeOffsetInContainerNode(), | 192 Initialize(start.ComputeContainerNode(), start.ComputeOffsetInContainerNode(), |
195 end.ComputeContainerNode(), end.ComputeOffsetInContainerNode()); | 193 end.ComputeContainerNode(), end.ComputeOffsetInContainerNode()); |
196 } | 194 } |
197 | 195 |
196 void TextIteratorTextNodeHandler::Initialize(Node* start_container, | |
197 int start_offset, | |
198 Node* end_container, | |
199 int end_offset) { | |
200 // This function should be called only once. | |
201 DCHECK(!start_container_); | |
yosin_UTC9
2017/05/29 09:12:59
nit: Please add DCHECK(start_container) and DCHECK
Xiaocheng
2017/05/30 03:01:49
This has been DCHECKed in TI::Initialize.
| |
202 DCHECK_EQ(start_offset_, 0); | |
203 DCHECK(!end_container_); | |
204 DCHECK_EQ(end_offset_, 0); | |
205 | |
206 start_container_ = start_container; | |
207 start_offset_ = start_offset; | |
208 end_container_ = end_container; | |
209 end_offset_ = end_offset; | |
210 } | |
211 | |
198 template <typename Strategy> | 212 template <typename Strategy> |
199 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container, | 213 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container, |
200 int start_offset, | 214 int start_offset, |
201 Node* end_container, | 215 Node* end_container, |
202 int end_offset) { | 216 int end_offset) { |
203 DCHECK(start_container); | 217 DCHECK(start_container); |
204 DCHECK(end_container); | 218 DCHECK(end_container); |
205 | 219 |
220 text_node_handler_.Initialize(start_container, start_offset, end_container, | |
221 end_offset); | |
222 | |
206 // Remember the range - this does not change. | 223 // Remember the range - this does not change. |
207 start_container_ = start_container; | 224 start_container_ = start_container; |
208 start_offset_ = start_offset; | 225 start_offset_ = start_offset; |
209 end_container_ = end_container; | 226 end_container_ = end_container; |
210 end_offset_ = end_offset; | 227 end_offset_ = end_offset; |
211 end_node_ = | 228 end_node_ = |
212 end_container && !end_container->IsCharacterDataNode() && end_offset > 0 | 229 end_container && !end_container->IsCharacterDataNode() && end_offset > 0 |
213 ? Strategy::ChildAt(*end_container, end_offset - 1) | 230 ? Strategy::ChildAt(*end_container, end_offset - 1) |
214 : nullptr; | 231 : nullptr; |
215 | 232 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
257 | 274 |
258 template <typename Strategy> | 275 template <typename Strategy> |
259 bool TextIteratorAlgorithm<Strategy>::IsInsideAtomicInlineElement() const { | 276 bool TextIteratorAlgorithm<Strategy>::IsInsideAtomicInlineElement() const { |
260 if (AtEnd() || length() != 1 || !node_) | 277 if (AtEnd() || length() != 1 || !node_) |
261 return false; | 278 return false; |
262 | 279 |
263 LayoutObject* layout_object = node_->GetLayoutObject(); | 280 LayoutObject* layout_object = node_->GetLayoutObject(); |
264 return layout_object && layout_object->IsAtomicInlineLevel(); | 281 return layout_object && layout_object->IsAtomicInlineLevel(); |
265 } | 282 } |
266 | 283 |
267 template <typename Strategy> | 284 bool TextIteratorTextNodeHandler::HandleRemainingTextRuns() { |
268 bool TextIteratorAlgorithm<Strategy>::HandleRemainingTextRuns() { | |
269 if (ShouldProceedToRemainingText()) | 285 if (ShouldProceedToRemainingText()) |
270 ProceedToRemainingText(); | 286 ProceedToRemainingText(); |
271 // Handle remembered text box | 287 // Handle remembered text box |
272 if (text_box_) { | 288 if (text_box_) { |
273 HandleTextBox(); | 289 HandleTextBox(); |
274 return text_state_.PositionNode(); | 290 return text_state_.PositionNode(); |
275 } | 291 } |
276 // Handle remembered pre-formatted text node. | 292 // Handle remembered pre-formatted text node. |
277 if (!needs_handle_pre_formatted_text_node_) | 293 if (!needs_handle_pre_formatted_text_node_) |
278 return false; | 294 return false; |
(...skipping 21 matching lines...) Expand all Loading... | |
300 // line break begins. | 316 // line break begins. |
301 // FIXME: It would be cleaner if we emitted two newlines during the last | 317 // FIXME: It would be cleaner if we emitted two newlines during the last |
302 // iteration, instead of using m_needsAnotherNewline. | 318 // iteration, instead of using m_needsAnotherNewline. |
303 Node* last_child = Strategy::LastChild(*node_); | 319 Node* last_child = Strategy::LastChild(*node_); |
304 Node* base_node = last_child ? last_child : node_.Get(); | 320 Node* base_node = last_child ? last_child : node_.Get(); |
305 SpliceBuffer('\n', Strategy::Parent(*base_node), base_node, 1, 1); | 321 SpliceBuffer('\n', Strategy::Parent(*base_node), base_node, 1, 1); |
306 needs_another_newline_ = false; | 322 needs_another_newline_ = false; |
307 return; | 323 return; |
308 } | 324 } |
309 | 325 |
310 if (HandleRemainingTextRuns()) | 326 if (text_node_handler_.HandleRemainingTextRuns()) |
311 return; | 327 return; |
312 | 328 |
313 while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) { | 329 while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) { |
314 if (!should_stop_ && StopsOnFormControls() && | 330 if (!should_stop_ && StopsOnFormControls() && |
315 HTMLFormControlElement::EnclosingFormControlElement(node_)) | 331 HTMLFormControlElement::EnclosingFormControlElement(node_)) |
316 should_stop_ = true; | 332 should_stop_ = true; |
317 | 333 |
318 // if the range ends at offset 0 of an element, represent the | 334 // 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 | 335 // position, but not the content, of that element e.g. if the |
320 // node is a blockflow element, emit a newline that | 336 // node is a blockflow element, emit a newline that |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
504 return false; | 520 return false; |
505 | 521 |
506 DCHECK(fragment->GetFirstLetterPseudoElement()); | 522 DCHECK(fragment->GetFirstLetterPseudoElement()); |
507 LayoutObject* pseudo_element_layout_object = | 523 LayoutObject* pseudo_element_layout_object = |
508 fragment->GetFirstLetterPseudoElement()->GetLayoutObject(); | 524 fragment->GetFirstLetterPseudoElement()->GetLayoutObject(); |
509 return pseudo_element_layout_object && | 525 return pseudo_element_layout_object && |
510 pseudo_element_layout_object->Style()->Visibility() == | 526 pseudo_element_layout_object->Style()->Visibility() == |
511 EVisibility::kVisible; | 527 EVisibility::kVisible; |
512 } | 528 } |
513 | 529 |
514 template <typename Strategy> | 530 bool TextIteratorTextNodeHandler::ShouldHandleFirstLetter( |
515 bool TextIteratorAlgorithm<Strategy>::ShouldHandleFirstLetter( | |
516 const LayoutText& layout_text) const { | 531 const LayoutText& layout_text) const { |
517 if (handled_first_letter_) | 532 if (handled_first_letter_) |
518 return false; | 533 return false; |
519 if (!layout_text.IsTextFragment()) | 534 if (!layout_text.IsTextFragment()) |
520 return false; | 535 return false; |
521 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text); | 536 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text); |
522 return offset_ < static_cast<int>(text_fragment.TextStartOffset()); | 537 return offset_ < static_cast<int>(text_fragment.TextStartOffset()); |
523 } | 538 } |
524 | 539 |
525 template <typename Strategy> | 540 void TextIteratorTextNodeHandler::HandlePreFormattedTextNode() { |
526 void TextIteratorAlgorithm<Strategy>::HandlePreFormattedTextNode() { | |
527 // TODO(xiaochengh): Get rid of repeated computation of these fields. | 541 // TODO(xiaochengh): Get rid of repeated computation of these fields. |
528 LayoutText* const layout_object = text_node_->GetLayoutObject(); | 542 LayoutText* const layout_object = text_node_->GetLayoutObject(); |
529 const String str = layout_object->GetText(); | 543 const String str = layout_object->GetText(); |
530 | 544 |
531 needs_handle_pre_formatted_text_node_ = false; | 545 needs_handle_pre_formatted_text_node_ = false; |
532 | 546 |
533 if (last_text_node_ended_with_collapsed_space_ && | 547 if (last_text_node_ended_with_collapsed_space_ && |
534 HasVisibleTextNode(layout_object)) { | 548 HasVisibleTextNode(layout_object)) { |
535 if (!behavior_.CollapseTrailingSpace() || | 549 if (!behavior_.CollapseTrailingSpace() || |
536 (offset_ > 0 && str[offset_ - 1] == ' ')) { | 550 (offset_ > 0 && str[offset_ - 1] == ' ')) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
585 TextControlElement* control = EnclosingTextControl(node_); | 599 TextControlElement* control = EnclosingTextControl(node_); |
586 // For security reason, we don't expose suggested value if it is | 600 // For security reason, we don't expose suggested value if it is |
587 // auto-filled. | 601 // auto-filled. |
588 if (control && control->IsAutofilled()) | 602 if (control && control->IsAutofilled()) |
589 return true; | 603 return true; |
590 } | 604 } |
591 | 605 |
592 DCHECK_NE(last_text_node_, node_) | 606 DCHECK_NE(last_text_node_, node_) |
593 << "We should never call HandleTextNode on the same node twice"; | 607 << "We should never call HandleTextNode on the same node twice"; |
594 last_text_node_ = ToText(node_); | 608 last_text_node_ = ToText(node_); |
609 return text_node_handler_.HandleTextNode(ToText(node_)); | |
610 } | |
595 | 611 |
596 text_node_ = ToText(node_); | 612 bool TextIteratorTextNodeHandler::HandleTextNode(Text* node) { |
613 text_node_ = node; | |
597 offset_ = text_node_ == start_container_ ? start_offset_ : 0; | 614 offset_ = text_node_ == start_container_ ? start_offset_ : 0; |
598 handled_first_letter_ = false; | 615 handled_first_letter_ = false; |
599 first_letter_text_ = nullptr; | 616 first_letter_text_ = nullptr; |
600 | 617 |
601 LayoutText* layout_object = text_node_->GetLayoutObject(); | 618 LayoutText* layout_object = text_node_->GetLayoutObject(); |
602 String str = layout_object->GetText(); | 619 String str = layout_object->GetText(); |
603 | 620 |
604 // handle pre-formatted text | 621 // handle pre-formatted text |
605 if (!layout_object->Style()->CollapseWhiteSpace()) { | 622 if (!layout_object->Style()->CollapseWhiteSpace()) { |
606 HandlePreFormattedTextNode(); | 623 HandlePreFormattedTextNode(); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
639 InlineTextBox::CompareByStart); | 656 InlineTextBox::CompareByStart); |
640 sorted_text_boxes_position_ = 0; | 657 sorted_text_boxes_position_ = 0; |
641 text_box_ = sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]; | 658 text_box_ = sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]; |
642 } | 659 } |
643 | 660 |
644 HandleTextBox(); | 661 HandleTextBox(); |
645 return true; | 662 return true; |
646 } | 663 } |
647 | 664 |
648 // Restore the collapsed space for copy & paste. See http://crbug.com/318925 | 665 // Restore the collapsed space for copy & paste. See http://crbug.com/318925 |
649 template <typename Strategy> | 666 size_t TextIteratorTextNodeHandler::RestoreCollapsedTrailingSpace( |
650 size_t TextIteratorAlgorithm<Strategy>::RestoreCollapsedTrailingSpace( | |
651 InlineTextBox* next_text_box, | 667 InlineTextBox* next_text_box, |
652 size_t subrun_end) { | 668 size_t subrun_end) { |
653 if (next_text_box || !text_box_->Root().NextRootBox() || | 669 if (next_text_box || !text_box_->Root().NextRootBox() || |
654 text_box_->Root().LastChild() != text_box_) | 670 text_box_->Root().LastChild() != text_box_) |
655 return subrun_end; | 671 return subrun_end; |
656 | 672 |
657 const String& text = text_node_->GetLayoutObject()->GetText(); | 673 const String& text = text_node_->GetLayoutObject()->GetText(); |
658 if (text.EndsWith(' ') == 0 || subrun_end != text.length() - 1 || | 674 if (text.EndsWith(' ') == 0 || subrun_end != text.length() - 1 || |
659 text[subrun_end - 1] == ' ') | 675 text[subrun_end - 1] == ' ') |
660 return subrun_end; | 676 return subrun_end; |
661 | 677 |
662 // If there is the leading space in the next line, we don't need to restore | 678 // If there is the leading space in the next line, we don't need to restore |
663 // the trailing space. | 679 // the trailing space. |
664 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div> | 680 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div> |
665 InlineBox* first_box_of_next_line = | 681 InlineBox* first_box_of_next_line = |
666 text_box_->Root().NextRootBox()->FirstChild(); | 682 text_box_->Root().NextRootBox()->FirstChild(); |
667 if (!first_box_of_next_line) | 683 if (!first_box_of_next_line) |
668 return subrun_end + 1; | 684 return subrun_end + 1; |
669 Node* first_node_of_next_line = | 685 Node* first_node_of_next_line = |
670 first_box_of_next_line->GetLineLayoutItem().GetNode(); | 686 first_box_of_next_line->GetLineLayoutItem().GetNode(); |
671 if (!first_node_of_next_line || | 687 if (!first_node_of_next_line || |
672 first_node_of_next_line->nodeValue()[0] != ' ') | 688 first_node_of_next_line->nodeValue()[0] != ' ') |
673 return subrun_end + 1; | 689 return subrun_end + 1; |
674 | 690 |
675 return subrun_end; | 691 return subrun_end; |
676 } | 692 } |
677 | 693 |
678 template <typename Strategy> | 694 void TextIteratorTextNodeHandler::HandleTextBox() { |
679 void TextIteratorAlgorithm<Strategy>::HandleTextBox() { | |
680 LayoutText* layout_object = | 695 LayoutText* layout_object = |
681 first_letter_text_ ? first_letter_text_ : text_node_->GetLayoutObject(); | 696 first_letter_text_ ? first_letter_text_ : text_node_->GetLayoutObject(); |
682 const unsigned text_start_offset = layout_object->TextStartOffset(); | 697 const unsigned text_start_offset = layout_object->TextStartOffset(); |
683 | 698 |
684 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 699 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
685 !IgnoresStyleVisibility()) { | 700 !IgnoresStyleVisibility()) { |
686 text_box_ = nullptr; | 701 text_box_ = nullptr; |
687 } else { | 702 } else { |
688 String str = layout_object->GetText(); | 703 String str = layout_object->GetText(); |
689 // Start and end offsets in |str|, i.e., str[start..end - 1] should be | 704 // Start and end offsets in |str|, i.e., str[start..end - 1] should be |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
807 ++sorted_text_boxes_position_; | 822 ++sorted_text_boxes_position_; |
808 } | 823 } |
809 } | 824 } |
810 | 825 |
811 if (ShouldProceedToRemainingText()) { | 826 if (ShouldProceedToRemainingText()) { |
812 ProceedToRemainingText(); | 827 ProceedToRemainingText(); |
813 HandleTextBox(); | 828 HandleTextBox(); |
814 } | 829 } |
815 } | 830 } |
816 | 831 |
817 template <typename Strategy> | 832 bool TextIteratorTextNodeHandler::ShouldProceedToRemainingText() const { |
818 bool TextIteratorAlgorithm<Strategy>::ShouldProceedToRemainingText() const { | |
819 if (text_box_ || !remaining_text_box_) | 833 if (text_box_ || !remaining_text_box_) |
820 return false; | 834 return false; |
821 if (text_node_ != end_container_) | 835 if (text_node_ != end_container_) |
822 return true; | 836 return true; |
823 return offset_ < end_offset_; | 837 return offset_ < end_offset_; |
824 } | 838 } |
825 | 839 |
826 template <typename Strategy> | 840 void TextIteratorTextNodeHandler::ProceedToRemainingText() { |
827 void TextIteratorAlgorithm<Strategy>::ProceedToRemainingText() { | |
828 text_box_ = remaining_text_box_; | 841 text_box_ = remaining_text_box_; |
829 remaining_text_box_ = 0; | 842 remaining_text_box_ = 0; |
830 first_letter_text_ = nullptr; | 843 first_letter_text_ = nullptr; |
831 offset_ = text_node_->GetLayoutObject()->TextStartOffset(); | 844 offset_ = text_node_->GetLayoutObject()->TextStartOffset(); |
832 } | 845 } |
833 | 846 |
834 template <typename Strategy> | 847 void TextIteratorTextNodeHandler::HandleTextNodeFirstLetter( |
835 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter( | |
836 LayoutTextFragment* layout_object) { | 848 LayoutTextFragment* layout_object) { |
837 handled_first_letter_ = true; | 849 handled_first_letter_ = true; |
838 | 850 |
839 if (!layout_object->IsRemainingTextLayoutObject()) | 851 if (!layout_object->IsRemainingTextLayoutObject()) |
840 return; | 852 return; |
841 | 853 |
842 FirstLetterPseudoElement* first_letter_element = | 854 FirstLetterPseudoElement* first_letter_element = |
843 layout_object->GetFirstLetterPseudoElement(); | 855 layout_object->GetFirstLetterPseudoElement(); |
844 if (!first_letter_element) | 856 if (!first_letter_element) |
845 return; | 857 return; |
(...skipping 20 matching lines...) Expand all Loading... | |
866 | 878 |
867 // FIXME: Add isSVGImageElement. | 879 // FIXME: Add isSVGImageElement. |
868 if (isHTMLImageElement(element)) | 880 if (isHTMLImageElement(element)) |
869 return true; | 881 return true; |
870 if (isHTMLInputElement(ToHTMLElement(*node)) && | 882 if (isHTMLInputElement(ToHTMLElement(*node)) && |
871 toHTMLInputElement(*node).type() == InputTypeNames::image) | 883 toHTMLInputElement(*node).type() == InputTypeNames::image) |
872 return true; | 884 return true; |
873 return false; | 885 return false; |
874 } | 886 } |
875 | 887 |
876 template <typename Strategy> | 888 bool TextIteratorTextNodeHandler::FixLeadingWhiteSpaceForReplacedElement( |
877 bool TextIteratorAlgorithm<Strategy>::FixLeadingWhiteSpaceForReplacedElement( | |
878 Node* parent) { | 889 Node* parent) { |
879 // This is a hacky way for white space fixup in legacy layout. With LayoutNG, | 890 // This is a hacky way for white space fixup in legacy layout. With LayoutNG, |
880 // we can get rid of this function. | 891 // we can get rid of this function. |
881 | 892 |
882 if (behavior_.CollapseTrailingSpace()) { | 893 if (behavior_.CollapseTrailingSpace()) { |
883 if (text_node_) { | 894 if (text_node_) { |
884 String str = text_node_->GetLayoutObject()->GetText(); | 895 String str = text_node_->GetLayoutObject()->GetText(); |
885 if (last_text_node_ended_with_collapsed_space_ && offset_ > 0 && | 896 if (last_text_node_ended_with_collapsed_space_ && offset_ > 0 && |
886 str[offset_ - 1] == ' ') { | 897 str[offset_ - 1] == ' ') { |
887 SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1); | 898 SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1); |
(...skipping 17 matching lines...) Expand all Loading... | |
905 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 916 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
906 !IgnoresStyleVisibility()) | 917 !IgnoresStyleVisibility()) |
907 return false; | 918 return false; |
908 | 919 |
909 if (EmitsObjectReplacementCharacter()) { | 920 if (EmitsObjectReplacementCharacter()) { |
910 SpliceBuffer(kObjectReplacementCharacter, Strategy::Parent(*node_), node_, | 921 SpliceBuffer(kObjectReplacementCharacter, Strategy::Parent(*node_), node_, |
911 0, 1); | 922 0, 1); |
912 return true; | 923 return true; |
913 } | 924 } |
914 | 925 |
915 DCHECK_EQ(last_text_node_, text_node_); | 926 DCHECK_EQ(last_text_node_, text_node_handler_.GetNode()); |
916 if (last_text_node_) { | 927 if (last_text_node_) { |
917 if (FixLeadingWhiteSpaceForReplacedElement( | 928 if (text_node_handler_.FixLeadingWhiteSpaceForReplacedElement( |
918 Strategy::Parent(*last_text_node_))) | 929 Strategy::Parent(*last_text_node_))) |
919 return false; | 930 return false; |
920 } | 931 } |
921 | 932 |
922 if (EntersTextControls() && layout_object->IsTextControl()) { | 933 if (EntersTextControls() && layout_object->IsTextControl()) { |
923 // The shadow tree should be already visited. | 934 // The shadow tree should be already visited. |
924 return true; | 935 return true; |
925 } | 936 } |
926 | 937 |
927 if (EmitsCharactersBetweenAllVisiblePositions()) { | 938 if (EmitsCharactersBetweenAllVisiblePositions()) { |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1209 1, 1); | 1220 1, 1); |
1210 } | 1221 } |
1211 } | 1222 } |
1212 | 1223 |
1213 // If nothing was emitted, see if we need to emit a space. | 1224 // If nothing was emitted, see if we need to emit a space. |
1214 if (!text_state_.PositionNode() && ShouldEmitSpaceBeforeAndAfterNode(node_)) | 1225 if (!text_state_.PositionNode() && ShouldEmitSpaceBeforeAndAfterNode(node_)) |
1215 SpliceBuffer(kSpaceCharacter, Strategy::Parent(*base_node), base_node, 1, | 1226 SpliceBuffer(kSpaceCharacter, Strategy::Parent(*base_node), base_node, 1, |
1216 1); | 1227 1); |
1217 } | 1228 } |
1218 | 1229 |
1219 template <typename Strategy> | 1230 void TextIteratorTextNodeHandler::ResetCollapsedWhiteSpaceFixup() { |
1220 void TextIteratorAlgorithm<Strategy>::ResetCollapsedWhiteSpaceFixup() { | |
1221 // This is a hacky way for white space fixup in legacy layout. With LayoutNG, | 1231 // This is a hacky way for white space fixup in legacy layout. With LayoutNG, |
1222 // we can get rid of this function. | 1232 // we can get rid of this function. |
1223 last_text_node_ended_with_collapsed_space_ = false; | 1233 last_text_node_ended_with_collapsed_space_ = false; |
1224 } | 1234 } |
1225 | 1235 |
1226 template <typename Strategy> | 1236 template <typename Strategy> |
1227 void TextIteratorAlgorithm<Strategy>::SpliceBuffer(UChar c, | 1237 void TextIteratorAlgorithm<Strategy>::SpliceBuffer(UChar c, |
1228 Node* text_node, | 1238 Node* text_node, |
1229 Node* offset_base_node, | 1239 Node* offset_base_node, |
1230 int text_start_offset, | 1240 int text_start_offset, |
1231 int text_end_offset) { | 1241 int text_end_offset) { |
1232 text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset, | 1242 text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset, |
1233 text_end_offset); | 1243 text_end_offset); |
1244 text_node_handler_.ResetCollapsedWhiteSpaceFixup(); | |
1245 } | |
1246 | |
1247 void TextIteratorTextNodeHandler::SpliceBuffer(UChar c, | |
1248 Node* text_node, | |
1249 Node* offset_base_node, | |
1250 int text_start_offset, | |
1251 int text_end_offset) { | |
1252 text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset, | |
1253 text_end_offset); | |
1234 ResetCollapsedWhiteSpaceFixup(); | 1254 ResetCollapsedWhiteSpaceFixup(); |
1235 } | 1255 } |
1236 | 1256 |
1237 template <typename Strategy> | 1257 void TextIteratorTextNodeHandler::EmitText(Node* text_node, |
1238 void TextIteratorAlgorithm<Strategy>::EmitText(Node* text_node, | 1258 LayoutText* layout_object, |
1239 LayoutText* layout_object, | 1259 int text_start_offset, |
1240 int text_start_offset, | 1260 int text_end_offset) { |
1241 int text_end_offset) { | |
1242 text_state_.EmitText(text_node, layout_object, text_start_offset, | 1261 text_state_.EmitText(text_node, layout_object, text_start_offset, |
1243 text_end_offset); | 1262 text_end_offset); |
1244 ResetCollapsedWhiteSpaceFixup(); | 1263 ResetCollapsedWhiteSpaceFixup(); |
1245 } | 1264 } |
1246 | 1265 |
1247 template <typename Strategy> | 1266 template <typename Strategy> |
1248 EphemeralRangeTemplate<Strategy> TextIteratorAlgorithm<Strategy>::Range() | 1267 EphemeralRangeTemplate<Strategy> TextIteratorAlgorithm<Strategy>::Range() |
1249 const { | 1268 const { |
1250 // use the current run information, if we have it | 1269 // use the current run information, if we have it |
1251 if (text_state_.PositionNode()) { | 1270 if (text_state_.PositionNode()) { |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1422 String PlainText(const EphemeralRangeInFlatTree& range, | 1441 String PlainText(const EphemeralRangeInFlatTree& range, |
1423 const TextIteratorBehavior& behavior) { | 1442 const TextIteratorBehavior& behavior) { |
1424 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); | 1443 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); |
1425 } | 1444 } |
1426 | 1445 |
1427 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; | 1446 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; |
1428 template class CORE_TEMPLATE_EXPORT | 1447 template class CORE_TEMPLATE_EXPORT |
1429 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; | 1448 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; |
1430 | 1449 |
1431 } // namespace blink | 1450 } // namespace blink |
OLD | NEW |