| 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::SetBoundaries(Node* start_container, |
| 197 int start_offset, |
| 198 Node* end_container, |
| 199 int end_offset) { |
| 200 start_container_ = start_container; |
| 201 start_offset_ = start_offset; |
| 202 end_container_ = end_container; |
| 203 end_offset_ = end_offset; |
| 204 } |
| 205 |
| 198 template <typename Strategy> | 206 template <typename Strategy> |
| 199 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container, | 207 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container, |
| 200 int start_offset, | 208 int start_offset, |
| 201 Node* end_container, | 209 Node* end_container, |
| 202 int end_offset) { | 210 int end_offset) { |
| 203 DCHECK(start_container); | 211 DCHECK(start_container); |
| 204 DCHECK(end_container); | 212 DCHECK(end_container); |
| 205 | 213 |
| 214 // TODO(xiaochengh): There is no need to pass the entire range. Instead, we |
| 215 // can pass the start and end offsets when calling HandleTextNode(). |
| 216 text_node_handler_.SetBoundaries(start_container, start_offset, end_container, |
| 217 end_offset); |
| 218 |
| 206 // Remember the range - this does not change. | 219 // Remember the range - this does not change. |
| 207 start_container_ = start_container; | 220 start_container_ = start_container; |
| 208 start_offset_ = start_offset; | 221 start_offset_ = start_offset; |
| 209 end_container_ = end_container; | 222 end_container_ = end_container; |
| 210 end_offset_ = end_offset; | 223 end_offset_ = end_offset; |
| 211 end_node_ = | 224 end_node_ = |
| 212 end_container && !end_container->IsCharacterDataNode() && end_offset > 0 | 225 end_container && !end_container->IsCharacterDataNode() && end_offset > 0 |
| 213 ? Strategy::ChildAt(*end_container, end_offset - 1) | 226 ? Strategy::ChildAt(*end_container, end_offset - 1) |
| 214 : nullptr; | 227 : nullptr; |
| 215 | 228 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 | 270 |
| 258 template <typename Strategy> | 271 template <typename Strategy> |
| 259 bool TextIteratorAlgorithm<Strategy>::IsInsideAtomicInlineElement() const { | 272 bool TextIteratorAlgorithm<Strategy>::IsInsideAtomicInlineElement() const { |
| 260 if (AtEnd() || length() != 1 || !node_) | 273 if (AtEnd() || length() != 1 || !node_) |
| 261 return false; | 274 return false; |
| 262 | 275 |
| 263 LayoutObject* layout_object = node_->GetLayoutObject(); | 276 LayoutObject* layout_object = node_->GetLayoutObject(); |
| 264 return layout_object && layout_object->IsAtomicInlineLevel(); | 277 return layout_object && layout_object->IsAtomicInlineLevel(); |
| 265 } | 278 } |
| 266 | 279 |
| 267 template <typename Strategy> | 280 bool TextIteratorTextNodeHandler::HandleRemainingTextRuns() { |
| 268 bool TextIteratorAlgorithm<Strategy>::HandleRemainingTextRuns() { | |
| 269 if (ShouldProceedToRemainingText()) | 281 if (ShouldProceedToRemainingText()) |
| 270 ProceedToRemainingText(); | 282 ProceedToRemainingText(); |
| 271 // Handle remembered text box | 283 // Handle remembered text box |
| 272 if (text_box_) { | 284 if (text_box_) { |
| 273 HandleTextBox(); | 285 HandleTextBox(); |
| 274 return text_state_.PositionNode(); | 286 return text_state_->PositionNode(); |
| 275 } | 287 } |
| 276 // Handle remembered pre-formatted text node. | 288 // Handle remembered pre-formatted text node. |
| 277 if (!needs_handle_pre_formatted_text_node_) | 289 if (!needs_handle_pre_formatted_text_node_) |
| 278 return false; | 290 return false; |
| 279 HandlePreFormattedTextNode(); | 291 HandlePreFormattedTextNode(); |
| 280 return text_state_.PositionNode(); | 292 return text_state_->PositionNode(); |
| 281 } | 293 } |
| 282 | 294 |
| 283 template <typename Strategy> | 295 template <typename Strategy> |
| 284 void TextIteratorAlgorithm<Strategy>::Advance() { | 296 void TextIteratorAlgorithm<Strategy>::Advance() { |
| 285 if (should_stop_) | 297 if (should_stop_) |
| 286 return; | 298 return; |
| 287 | 299 |
| 288 if (node_) | 300 if (node_) |
| 289 DCHECK(!node_->GetDocument().NeedsLayoutTreeUpdate()) << node_; | 301 DCHECK(!node_->GetDocument().NeedsLayoutTreeUpdate()) << node_; |
| 290 | 302 |
| 291 text_state_.ResetRunInformation(); | 303 text_state_.ResetRunInformation(); |
| 292 | 304 |
| 293 // TODO(xiaochengh): Wrap the following code into HandleRememberedProgress(). | 305 // TODO(xiaochengh): Wrap the following code into HandleRememberedProgress(). |
| 294 | 306 |
| 295 // handle remembered node that needed a newline after the text node's newline | 307 // handle remembered node that needed a newline after the text node's newline |
| 296 if (needs_another_newline_) { | 308 if (needs_another_newline_) { |
| 297 // Emit the extra newline, and position it *inside* m_node, after m_node's | 309 // Emit the extra newline, and position it *inside* m_node, after m_node's |
| 298 // contents, in case it's a block, in the same way that we position the | 310 // contents, in case it's a block, in the same way that we position the |
| 299 // first newline. The range for the emitted newline should start where the | 311 // first newline. The range for the emitted newline should start where the |
| 300 // line break begins. | 312 // line break begins. |
| 301 // FIXME: It would be cleaner if we emitted two newlines during the last | 313 // FIXME: It would be cleaner if we emitted two newlines during the last |
| 302 // iteration, instead of using m_needsAnotherNewline. | 314 // iteration, instead of using m_needsAnotherNewline. |
| 303 Node* last_child = Strategy::LastChild(*node_); | 315 Node* last_child = Strategy::LastChild(*node_); |
| 304 Node* base_node = last_child ? last_child : node_.Get(); | 316 Node* base_node = last_child ? last_child : node_.Get(); |
| 305 SpliceBuffer('\n', Strategy::Parent(*base_node), base_node, 1, 1); | 317 SpliceBuffer('\n', Strategy::Parent(*base_node), base_node, 1, 1); |
| 306 needs_another_newline_ = false; | 318 needs_another_newline_ = false; |
| 307 return; | 319 return; |
| 308 } | 320 } |
| 309 | 321 |
| 310 if (HandleRemainingTextRuns()) | 322 if (text_node_handler_.HandleRemainingTextRuns()) |
| 311 return; | 323 return; |
| 312 | 324 |
| 313 while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) { | 325 while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) { |
| 314 if (!should_stop_ && StopsOnFormControls() && | 326 if (!should_stop_ && StopsOnFormControls() && |
| 315 HTMLFormControlElement::EnclosingFormControlElement(node_)) | 327 HTMLFormControlElement::EnclosingFormControlElement(node_)) |
| 316 should_stop_ = true; | 328 should_stop_ = true; |
| 317 | 329 |
| 318 // if the range ends at offset 0 of an element, represent the | 330 // 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 | 331 // position, but not the content, of that element e.g. if the |
| 320 // node is a blockflow element, emit a newline that | 332 // 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; | 516 return false; |
| 505 | 517 |
| 506 DCHECK(fragment->GetFirstLetterPseudoElement()); | 518 DCHECK(fragment->GetFirstLetterPseudoElement()); |
| 507 LayoutObject* pseudo_element_layout_object = | 519 LayoutObject* pseudo_element_layout_object = |
| 508 fragment->GetFirstLetterPseudoElement()->GetLayoutObject(); | 520 fragment->GetFirstLetterPseudoElement()->GetLayoutObject(); |
| 509 return pseudo_element_layout_object && | 521 return pseudo_element_layout_object && |
| 510 pseudo_element_layout_object->Style()->Visibility() == | 522 pseudo_element_layout_object->Style()->Visibility() == |
| 511 EVisibility::kVisible; | 523 EVisibility::kVisible; |
| 512 } | 524 } |
| 513 | 525 |
| 514 template <typename Strategy> | 526 bool TextIteratorTextNodeHandler::ShouldHandleFirstLetter( |
| 515 bool TextIteratorAlgorithm<Strategy>::ShouldHandleFirstLetter( | |
| 516 const LayoutText& layout_text) const { | 527 const LayoutText& layout_text) const { |
| 517 if (handled_first_letter_) | 528 if (handled_first_letter_) |
| 518 return false; | 529 return false; |
| 519 if (!layout_text.IsTextFragment()) | 530 if (!layout_text.IsTextFragment()) |
| 520 return false; | 531 return false; |
| 521 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text); | 532 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text); |
| 522 return offset_ < static_cast<int>(text_fragment.TextStartOffset()); | 533 return offset_ < static_cast<int>(text_fragment.TextStartOffset()); |
| 523 } | 534 } |
| 524 | 535 |
| 525 template <typename Strategy> | 536 void TextIteratorTextNodeHandler::HandlePreFormattedTextNode() { |
| 526 void TextIteratorAlgorithm<Strategy>::HandlePreFormattedTextNode() { | |
| 527 // TODO(xiaochengh): Get rid of repeated computation of these fields. | 537 // TODO(xiaochengh): Get rid of repeated computation of these fields. |
| 528 LayoutText* const layout_object = text_node_->GetLayoutObject(); | 538 LayoutText* const layout_object = text_node_->GetLayoutObject(); |
| 529 const String str = layout_object->GetText(); | 539 const String str = layout_object->GetText(); |
| 530 | 540 |
| 531 needs_handle_pre_formatted_text_node_ = false; | 541 needs_handle_pre_formatted_text_node_ = false; |
| 532 | 542 |
| 533 if (last_text_node_ended_with_collapsed_space_ && | 543 if (last_text_node_ended_with_collapsed_space_ && |
| 534 HasVisibleTextNode(layout_object)) { | 544 HasVisibleTextNode(layout_object)) { |
| 535 if (!behavior_.CollapseTrailingSpace() || | 545 if (!behavior_.CollapseTrailingSpace() || |
| 536 (offset_ > 0 && str[offset_ - 1] == ' ')) { | 546 (offset_ > 0 && str[offset_ - 1] == ' ')) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 585 TextControlElement* control = EnclosingTextControl(node_); | 595 TextControlElement* control = EnclosingTextControl(node_); |
| 586 // For security reason, we don't expose suggested value if it is | 596 // For security reason, we don't expose suggested value if it is |
| 587 // auto-filled. | 597 // auto-filled. |
| 588 if (control && control->IsAutofilled()) | 598 if (control && control->IsAutofilled()) |
| 589 return true; | 599 return true; |
| 590 } | 600 } |
| 591 | 601 |
| 592 DCHECK_NE(last_text_node_, node_) | 602 DCHECK_NE(last_text_node_, node_) |
| 593 << "We should never call HandleTextNode on the same node twice"; | 603 << "We should never call HandleTextNode on the same node twice"; |
| 594 last_text_node_ = ToText(node_); | 604 last_text_node_ = ToText(node_); |
| 605 return text_node_handler_.HandleTextNode(ToText(node_)); |
| 606 } |
| 595 | 607 |
| 596 text_node_ = ToText(node_); | 608 bool TextIteratorTextNodeHandler::HandleTextNode(Text* node) { |
| 609 text_node_ = node; |
| 597 offset_ = text_node_ == start_container_ ? start_offset_ : 0; | 610 offset_ = text_node_ == start_container_ ? start_offset_ : 0; |
| 598 handled_first_letter_ = false; | 611 handled_first_letter_ = false; |
| 599 first_letter_text_ = nullptr; | 612 first_letter_text_ = nullptr; |
| 600 | 613 |
| 601 LayoutText* layout_object = text_node_->GetLayoutObject(); | 614 LayoutText* layout_object = text_node_->GetLayoutObject(); |
| 602 String str = layout_object->GetText(); | 615 String str = layout_object->GetText(); |
| 603 | 616 |
| 604 // handle pre-formatted text | 617 // handle pre-formatted text |
| 605 if (!layout_object->Style()->CollapseWhiteSpace()) { | 618 if (!layout_object->Style()->CollapseWhiteSpace()) { |
| 606 HandlePreFormattedTextNode(); | 619 HandlePreFormattedTextNode(); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 InlineTextBox::CompareByStart); | 652 InlineTextBox::CompareByStart); |
| 640 sorted_text_boxes_position_ = 0; | 653 sorted_text_boxes_position_ = 0; |
| 641 text_box_ = sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]; | 654 text_box_ = sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]; |
| 642 } | 655 } |
| 643 | 656 |
| 644 HandleTextBox(); | 657 HandleTextBox(); |
| 645 return true; | 658 return true; |
| 646 } | 659 } |
| 647 | 660 |
| 648 // Restore the collapsed space for copy & paste. See http://crbug.com/318925 | 661 // Restore the collapsed space for copy & paste. See http://crbug.com/318925 |
| 649 template <typename Strategy> | 662 size_t TextIteratorTextNodeHandler::RestoreCollapsedTrailingSpace( |
| 650 size_t TextIteratorAlgorithm<Strategy>::RestoreCollapsedTrailingSpace( | |
| 651 InlineTextBox* next_text_box, | 663 InlineTextBox* next_text_box, |
| 652 size_t subrun_end) { | 664 size_t subrun_end) { |
| 653 if (next_text_box || !text_box_->Root().NextRootBox() || | 665 if (next_text_box || !text_box_->Root().NextRootBox() || |
| 654 text_box_->Root().LastChild() != text_box_) | 666 text_box_->Root().LastChild() != text_box_) |
| 655 return subrun_end; | 667 return subrun_end; |
| 656 | 668 |
| 657 const String& text = text_node_->GetLayoutObject()->GetText(); | 669 const String& text = text_node_->GetLayoutObject()->GetText(); |
| 658 if (text.EndsWith(' ') == 0 || subrun_end != text.length() - 1 || | 670 if (text.EndsWith(' ') == 0 || subrun_end != text.length() - 1 || |
| 659 text[subrun_end - 1] == ' ') | 671 text[subrun_end - 1] == ' ') |
| 660 return subrun_end; | 672 return subrun_end; |
| 661 | 673 |
| 662 // If there is the leading space in the next line, we don't need to restore | 674 // If there is the leading space in the next line, we don't need to restore |
| 663 // the trailing space. | 675 // the trailing space. |
| 664 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div> | 676 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div> |
| 665 InlineBox* first_box_of_next_line = | 677 InlineBox* first_box_of_next_line = |
| 666 text_box_->Root().NextRootBox()->FirstChild(); | 678 text_box_->Root().NextRootBox()->FirstChild(); |
| 667 if (!first_box_of_next_line) | 679 if (!first_box_of_next_line) |
| 668 return subrun_end + 1; | 680 return subrun_end + 1; |
| 669 Node* first_node_of_next_line = | 681 Node* first_node_of_next_line = |
| 670 first_box_of_next_line->GetLineLayoutItem().GetNode(); | 682 first_box_of_next_line->GetLineLayoutItem().GetNode(); |
| 671 if (!first_node_of_next_line || | 683 if (!first_node_of_next_line || |
| 672 first_node_of_next_line->nodeValue()[0] != ' ') | 684 first_node_of_next_line->nodeValue()[0] != ' ') |
| 673 return subrun_end + 1; | 685 return subrun_end + 1; |
| 674 | 686 |
| 675 return subrun_end; | 687 return subrun_end; |
| 676 } | 688 } |
| 677 | 689 |
| 678 template <typename Strategy> | 690 void TextIteratorTextNodeHandler::HandleTextBox() { |
| 679 void TextIteratorAlgorithm<Strategy>::HandleTextBox() { | |
| 680 LayoutText* layout_object = | 691 LayoutText* layout_object = |
| 681 first_letter_text_ ? first_letter_text_ : text_node_->GetLayoutObject(); | 692 first_letter_text_ ? first_letter_text_ : text_node_->GetLayoutObject(); |
| 682 const unsigned text_start_offset = layout_object->TextStartOffset(); | 693 const unsigned text_start_offset = layout_object->TextStartOffset(); |
| 683 | 694 |
| 684 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 695 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
| 685 !IgnoresStyleVisibility()) { | 696 !IgnoresStyleVisibility()) { |
| 686 text_box_ = nullptr; | 697 text_box_ = nullptr; |
| 687 } else { | 698 } else { |
| 688 String str = layout_object->GetText(); | 699 String str = layout_object->GetText(); |
| 689 // Start and end offsets in |str|, i.e., str[start..end - 1] should be | 700 // Start and end offsets in |str|, i.e., str[start..end - 1] should be |
| (...skipping 10 matching lines...) Expand all Loading... |
| 700 // Check for collapsed space at the start of this run. | 711 // Check for collapsed space at the start of this run. |
| 701 InlineTextBox* first_text_box = | 712 InlineTextBox* first_text_box = |
| 702 layout_object->ContainsReversedText() | 713 layout_object->ContainsReversedText() |
| 703 ? (sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]) | 714 ? (sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]) |
| 704 : layout_object->FirstTextBox(); | 715 : layout_object->FirstTextBox(); |
| 705 const bool need_space = last_text_node_ended_with_collapsed_space_ || | 716 const bool need_space = last_text_node_ended_with_collapsed_space_ || |
| 706 (text_box_ == first_text_box && | 717 (text_box_ == first_text_box && |
| 707 text_box_start == run_start && run_start > 0); | 718 text_box_start == run_start && run_start > 0); |
| 708 if (need_space && | 719 if (need_space && |
| 709 !layout_object->Style()->IsCollapsibleWhiteSpace( | 720 !layout_object->Style()->IsCollapsibleWhiteSpace( |
| 710 text_state_.LastCharacter()) && | 721 text_state_->LastCharacter()) && |
| 711 text_state_.LastCharacter()) { | 722 text_state_->LastCharacter()) { |
| 712 if (run_start > 0 && str[run_start - 1] == ' ') { | 723 if (run_start > 0 && str[run_start - 1] == ' ') { |
| 713 unsigned space_run_start = run_start - 1; | 724 unsigned space_run_start = run_start - 1; |
| 714 while (space_run_start > 0 && str[space_run_start - 1] == ' ') | 725 while (space_run_start > 0 && str[space_run_start - 1] == ' ') |
| 715 --space_run_start; | 726 --space_run_start; |
| 716 EmitText(text_node_, layout_object, space_run_start, | 727 EmitText(text_node_, layout_object, space_run_start, |
| 717 space_run_start + 1); | 728 space_run_start + 1); |
| 718 } else { | 729 } else { |
| 719 SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start, run_start); | 730 SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start, run_start); |
| 720 } | 731 } |
| 721 return; | 732 return; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 768 RestoreCollapsedTrailingSpace(next_text_box, subrun_end); | 779 RestoreCollapsedTrailingSpace(next_text_box, subrun_end); |
| 769 } | 780 } |
| 770 | 781 |
| 771 offset_ = text_start_offset + subrun_end; | 782 offset_ = text_start_offset + subrun_end; |
| 772 EmitText(text_node_, layout_object, run_start, subrun_end); | 783 EmitText(text_node_, layout_object, run_start, subrun_end); |
| 773 } | 784 } |
| 774 | 785 |
| 775 // If we are doing a subrun that doesn't go to the end of the text box, | 786 // If we are doing a subrun that doesn't go to the end of the text box, |
| 776 // come back again to finish handling this text box; don't advance to | 787 // come back again to finish handling this text box; don't advance to |
| 777 // the next one. | 788 // the next one. |
| 778 if (static_cast<unsigned>(text_state_.PositionEndOffset()) < | 789 if (static_cast<unsigned>(text_state_->PositionEndOffset()) < |
| 779 text_box_end) | 790 text_box_end) |
| 780 return; | 791 return; |
| 781 | 792 |
| 782 if (behavior_.DoesNotEmitSpaceBeyondRangeEnd()) { | 793 if (behavior_.DoesNotEmitSpaceBeyondRangeEnd()) { |
| 783 // If the subrun went to the text box end and this end is also the end | 794 // If the subrun went to the text box end and this end is also the end |
| 784 // of the range, do not advance to the next text box and do not | 795 // of the range, do not advance to the next text box and do not |
| 785 // generate a space, just stop. | 796 // generate a space, just stop. |
| 786 if (text_box_end == end) { | 797 if (text_box_end == end) { |
| 787 text_box_ = nullptr; | 798 text_box_ = nullptr; |
| 788 return; | 799 return; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 807 ++sorted_text_boxes_position_; | 818 ++sorted_text_boxes_position_; |
| 808 } | 819 } |
| 809 } | 820 } |
| 810 | 821 |
| 811 if (ShouldProceedToRemainingText()) { | 822 if (ShouldProceedToRemainingText()) { |
| 812 ProceedToRemainingText(); | 823 ProceedToRemainingText(); |
| 813 HandleTextBox(); | 824 HandleTextBox(); |
| 814 } | 825 } |
| 815 } | 826 } |
| 816 | 827 |
| 817 template <typename Strategy> | 828 bool TextIteratorTextNodeHandler::ShouldProceedToRemainingText() const { |
| 818 bool TextIteratorAlgorithm<Strategy>::ShouldProceedToRemainingText() const { | |
| 819 if (text_box_ || !remaining_text_box_) | 829 if (text_box_ || !remaining_text_box_) |
| 820 return false; | 830 return false; |
| 821 if (text_node_ != end_container_) | 831 if (text_node_ != end_container_) |
| 822 return true; | 832 return true; |
| 823 return offset_ < end_offset_; | 833 return offset_ < end_offset_; |
| 824 } | 834 } |
| 825 | 835 |
| 826 template <typename Strategy> | 836 void TextIteratorTextNodeHandler::ProceedToRemainingText() { |
| 827 void TextIteratorAlgorithm<Strategy>::ProceedToRemainingText() { | |
| 828 text_box_ = remaining_text_box_; | 837 text_box_ = remaining_text_box_; |
| 829 remaining_text_box_ = 0; | 838 remaining_text_box_ = 0; |
| 830 first_letter_text_ = nullptr; | 839 first_letter_text_ = nullptr; |
| 831 offset_ = text_node_->GetLayoutObject()->TextStartOffset(); | 840 offset_ = text_node_->GetLayoutObject()->TextStartOffset(); |
| 832 } | 841 } |
| 833 | 842 |
| 834 template <typename Strategy> | 843 void TextIteratorTextNodeHandler::HandleTextNodeFirstLetter( |
| 835 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter( | |
| 836 LayoutTextFragment* layout_object) { | 844 LayoutTextFragment* layout_object) { |
| 837 handled_first_letter_ = true; | 845 handled_first_letter_ = true; |
| 838 | 846 |
| 839 if (!layout_object->IsRemainingTextLayoutObject()) | 847 if (!layout_object->IsRemainingTextLayoutObject()) |
| 840 return; | 848 return; |
| 841 | 849 |
| 842 FirstLetterPseudoElement* first_letter_element = | 850 FirstLetterPseudoElement* first_letter_element = |
| 843 layout_object->GetFirstLetterPseudoElement(); | 851 layout_object->GetFirstLetterPseudoElement(); |
| 844 if (!first_letter_element) | 852 if (!first_letter_element) |
| 845 return; | 853 return; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 866 | 874 |
| 867 // FIXME: Add isSVGImageElement. | 875 // FIXME: Add isSVGImageElement. |
| 868 if (isHTMLImageElement(element)) | 876 if (isHTMLImageElement(element)) |
| 869 return true; | 877 return true; |
| 870 if (isHTMLInputElement(ToHTMLElement(*node)) && | 878 if (isHTMLInputElement(ToHTMLElement(*node)) && |
| 871 toHTMLInputElement(*node).type() == InputTypeNames::image) | 879 toHTMLInputElement(*node).type() == InputTypeNames::image) |
| 872 return true; | 880 return true; |
| 873 return false; | 881 return false; |
| 874 } | 882 } |
| 875 | 883 |
| 876 template <typename Strategy> | 884 bool TextIteratorTextNodeHandler::FixLeadingWhiteSpaceForReplacedElement( |
| 877 bool TextIteratorAlgorithm<Strategy>::FixLeadingWhiteSpaceForReplacedElement( | |
| 878 Node* parent) { | 885 Node* parent) { |
| 879 // This is a hacky way for white space fixup in legacy layout. With LayoutNG, | 886 // This is a hacky way for white space fixup in legacy layout. With LayoutNG, |
| 880 // we can get rid of this function. | 887 // we can get rid of this function. |
| 881 | 888 |
| 882 if (behavior_.CollapseTrailingSpace()) { | 889 if (behavior_.CollapseTrailingSpace()) { |
| 883 if (text_node_) { | 890 if (text_node_) { |
| 884 String str = text_node_->GetLayoutObject()->GetText(); | 891 String str = text_node_->GetLayoutObject()->GetText(); |
| 885 if (last_text_node_ended_with_collapsed_space_ && offset_ > 0 && | 892 if (last_text_node_ended_with_collapsed_space_ && offset_ > 0 && |
| 886 str[offset_ - 1] == ' ') { | 893 str[offset_ - 1] == ' ') { |
| 887 SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1); | 894 SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 905 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 912 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
| 906 !IgnoresStyleVisibility()) | 913 !IgnoresStyleVisibility()) |
| 907 return false; | 914 return false; |
| 908 | 915 |
| 909 if (EmitsObjectReplacementCharacter()) { | 916 if (EmitsObjectReplacementCharacter()) { |
| 910 SpliceBuffer(kObjectReplacementCharacter, Strategy::Parent(*node_), node_, | 917 SpliceBuffer(kObjectReplacementCharacter, Strategy::Parent(*node_), node_, |
| 911 0, 1); | 918 0, 1); |
| 912 return true; | 919 return true; |
| 913 } | 920 } |
| 914 | 921 |
| 915 DCHECK_EQ(last_text_node_, text_node_); | 922 DCHECK_EQ(last_text_node_, text_node_handler_.GetNode()); |
| 916 if (last_text_node_) { | 923 if (last_text_node_) { |
| 917 if (FixLeadingWhiteSpaceForReplacedElement( | 924 if (text_node_handler_.FixLeadingWhiteSpaceForReplacedElement( |
| 918 Strategy::Parent(*last_text_node_))) | 925 Strategy::Parent(*last_text_node_))) |
| 919 return false; | 926 return false; |
| 920 } | 927 } |
| 921 | 928 |
| 922 if (EntersTextControls() && layout_object->IsTextControl()) { | 929 if (EntersTextControls() && layout_object->IsTextControl()) { |
| 923 // The shadow tree should be already visited. | 930 // The shadow tree should be already visited. |
| 924 return true; | 931 return true; |
| 925 } | 932 } |
| 926 | 933 |
| 927 if (EmitsCharactersBetweenAllVisiblePositions()) { | 934 if (EmitsCharactersBetweenAllVisiblePositions()) { |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1209 1, 1); | 1216 1, 1); |
| 1210 } | 1217 } |
| 1211 } | 1218 } |
| 1212 | 1219 |
| 1213 // If nothing was emitted, see if we need to emit a space. | 1220 // If nothing was emitted, see if we need to emit a space. |
| 1214 if (!text_state_.PositionNode() && ShouldEmitSpaceBeforeAndAfterNode(node_)) | 1221 if (!text_state_.PositionNode() && ShouldEmitSpaceBeforeAndAfterNode(node_)) |
| 1215 SpliceBuffer(kSpaceCharacter, Strategy::Parent(*base_node), base_node, 1, | 1222 SpliceBuffer(kSpaceCharacter, Strategy::Parent(*base_node), base_node, 1, |
| 1216 1); | 1223 1); |
| 1217 } | 1224 } |
| 1218 | 1225 |
| 1219 template <typename Strategy> | 1226 void TextIteratorTextNodeHandler::ResetCollapsedWhiteSpaceFixup() { |
| 1220 void TextIteratorAlgorithm<Strategy>::ResetCollapsedWhiteSpaceFixup() { | |
| 1221 // This is a hacky way for white space fixup in legacy layout. With LayoutNG, | 1227 // This is a hacky way for white space fixup in legacy layout. With LayoutNG, |
| 1222 // we can get rid of this function. | 1228 // we can get rid of this function. |
| 1223 last_text_node_ended_with_collapsed_space_ = false; | 1229 last_text_node_ended_with_collapsed_space_ = false; |
| 1224 } | 1230 } |
| 1225 | 1231 |
| 1226 template <typename Strategy> | 1232 template <typename Strategy> |
| 1227 void TextIteratorAlgorithm<Strategy>::SpliceBuffer(UChar c, | 1233 void TextIteratorAlgorithm<Strategy>::SpliceBuffer(UChar c, |
| 1228 Node* text_node, | 1234 Node* text_node, |
| 1229 Node* offset_base_node, | 1235 Node* offset_base_node, |
| 1230 int text_start_offset, | 1236 int text_start_offset, |
| 1231 int text_end_offset) { | 1237 int text_end_offset) { |
| 1232 text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset, | 1238 text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset, |
| 1233 text_end_offset); | 1239 text_end_offset); |
| 1240 text_node_handler_.ResetCollapsedWhiteSpaceFixup(); |
| 1241 } |
| 1242 |
| 1243 void TextIteratorTextNodeHandler::SpliceBuffer(UChar c, |
| 1244 Node* text_node, |
| 1245 Node* offset_base_node, |
| 1246 int text_start_offset, |
| 1247 int text_end_offset) { |
| 1248 text_state_->SpliceBuffer(c, text_node, offset_base_node, text_start_offset, |
| 1249 text_end_offset); |
| 1234 ResetCollapsedWhiteSpaceFixup(); | 1250 ResetCollapsedWhiteSpaceFixup(); |
| 1235 } | 1251 } |
| 1236 | 1252 |
| 1237 template <typename Strategy> | 1253 void TextIteratorTextNodeHandler::EmitText(Node* text_node, |
| 1238 void TextIteratorAlgorithm<Strategy>::EmitText(Node* text_node, | 1254 LayoutText* layout_object, |
| 1239 LayoutText* layout_object, | 1255 int text_start_offset, |
| 1240 int text_start_offset, | 1256 int text_end_offset) { |
| 1241 int text_end_offset) { | 1257 text_state_->EmitText(text_node, layout_object, text_start_offset, |
| 1242 text_state_.EmitText(text_node, layout_object, text_start_offset, | 1258 text_end_offset); |
| 1243 text_end_offset); | |
| 1244 ResetCollapsedWhiteSpaceFixup(); | 1259 ResetCollapsedWhiteSpaceFixup(); |
| 1245 } | 1260 } |
| 1246 | 1261 |
| 1247 template <typename Strategy> | 1262 template <typename Strategy> |
| 1248 EphemeralRangeTemplate<Strategy> TextIteratorAlgorithm<Strategy>::Range() | 1263 EphemeralRangeTemplate<Strategy> TextIteratorAlgorithm<Strategy>::Range() |
| 1249 const { | 1264 const { |
| 1250 // use the current run information, if we have it | 1265 // use the current run information, if we have it |
| 1251 if (text_state_.PositionNode()) { | 1266 if (text_state_.PositionNode()) { |
| 1252 return EphemeralRangeTemplate<Strategy>(StartPositionInCurrentContainer(), | 1267 return EphemeralRangeTemplate<Strategy>(StartPositionInCurrentContainer(), |
| 1253 EndPositionInCurrentContainer()); | 1268 EndPositionInCurrentContainer()); |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1422 String PlainText(const EphemeralRangeInFlatTree& range, | 1437 String PlainText(const EphemeralRangeInFlatTree& range, |
| 1423 const TextIteratorBehavior& behavior) { | 1438 const TextIteratorBehavior& behavior) { |
| 1424 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); | 1439 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); |
| 1425 } | 1440 } |
| 1426 | 1441 |
| 1427 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; | 1442 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; |
| 1428 template class CORE_TEMPLATE_EXPORT | 1443 template class CORE_TEMPLATE_EXPORT |
| 1429 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; | 1444 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; |
| 1430 | 1445 |
| 1431 } // namespace blink | 1446 } // namespace blink |
| OLD | NEW |