| 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 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 // line break begins. | 335 // line break begins. |
| 336 // FIXME: It would be cleaner if we emitted two newlines during the last | 336 // FIXME: It would be cleaner if we emitted two newlines during the last |
| 337 // iteration, instead of using m_needsAnotherNewline. | 337 // iteration, instead of using m_needsAnotherNewline. |
| 338 Node* last_child = Strategy::LastChild(*node_); | 338 Node* last_child = Strategy::LastChild(*node_); |
| 339 Node* base_node = last_child ? last_child : node_.Get(); | 339 Node* base_node = last_child ? last_child : node_.Get(); |
| 340 SpliceBuffer('\n', Strategy::Parent(*base_node), base_node, 1, 1); | 340 SpliceBuffer('\n', Strategy::Parent(*base_node), base_node, 1, 1); |
| 341 needs_another_newline_ = false; | 341 needs_another_newline_ = false; |
| 342 return; | 342 return; |
| 343 } | 343 } |
| 344 | 344 |
| 345 if (!text_box_ && remaining_text_box_) { | 345 if (ShouldProceedToRemainingText()) |
| 346 text_box_ = remaining_text_box_; | 346 ProceedToRemainingText(); |
| 347 remaining_text_box_ = 0; | |
| 348 first_letter_text_ = nullptr; | |
| 349 offset_ = 0; | |
| 350 } | |
| 351 // handle remembered text box | 347 // handle remembered text box |
| 352 if (text_box_) { | 348 if (text_box_) { |
| 353 HandleTextBox(); | 349 HandleTextBox(); |
| 354 if (text_state_.PositionNode()) | 350 if (text_state_.PositionNode()) |
| 355 return; | 351 return; |
| 356 } | 352 } |
| 357 | 353 |
| 358 while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) { | 354 while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) { |
| 359 if (!should_stop_ && StopsOnFormControls() && | 355 if (!should_stop_ && StopsOnFormControls() && |
| 360 HTMLFormControlElement::EnclosingFormControlElement(node_)) | 356 HTMLFormControlElement::EnclosingFormControlElement(node_)) |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 | 551 |
| 556 DCHECK(fragment->GetFirstLetterPseudoElement()); | 552 DCHECK(fragment->GetFirstLetterPseudoElement()); |
| 557 LayoutObject* pseudo_element_layout_object = | 553 LayoutObject* pseudo_element_layout_object = |
| 558 fragment->GetFirstLetterPseudoElement()->GetLayoutObject(); | 554 fragment->GetFirstLetterPseudoElement()->GetLayoutObject(); |
| 559 return pseudo_element_layout_object && | 555 return pseudo_element_layout_object && |
| 560 pseudo_element_layout_object->Style()->Visibility() == | 556 pseudo_element_layout_object->Style()->Visibility() == |
| 561 EVisibility::kVisible; | 557 EVisibility::kVisible; |
| 562 } | 558 } |
| 563 | 559 |
| 564 template <typename Strategy> | 560 template <typename Strategy> |
| 561 bool TextIteratorAlgorithm<Strategy>::ShouldHandleFirstLetter( |
| 562 const LayoutText& layout_text) const { |
| 563 if (handled_first_letter_) |
| 564 return false; |
| 565 if (!layout_text.IsTextFragment()) |
| 566 return false; |
| 567 // TODO(xiaochengh): Handle the case where :first-letter has multiple chars, |
| 568 // and eliminate the hack with first_letter/remaining_text_start_offset_. |
| 569 return !offset_; |
| 570 } |
| 571 |
| 572 template <typename Strategy> |
| 565 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() { | 573 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() { |
| 566 if (ExcludesAutofilledValue()) { | 574 if (ExcludesAutofilledValue()) { |
| 567 TextControlElement* control = EnclosingTextControl(node_); | 575 TextControlElement* control = EnclosingTextControl(node_); |
| 568 // For security reason, we don't expose suggested value if it is | 576 // For security reason, we don't expose suggested value if it is |
| 569 // auto-filled. | 577 // auto-filled. |
| 570 if (control && control->IsAutofilled()) | 578 if (control && control->IsAutofilled()) |
| 571 return true; | 579 return true; |
| 572 } | 580 } |
| 573 | 581 |
| 574 Text* text_node = ToText(node_); | 582 Text* text_node = ToText(node_); |
| 575 LayoutText* layout_object = text_node->GetLayoutObject(); | 583 LayoutText* layout_object = text_node->GetLayoutObject(); |
| 576 | 584 |
| 577 last_text_node_ = text_node; | 585 last_text_node_ = text_node; |
| 578 String str = layout_object->GetText(); | 586 String str = layout_object->GetText(); |
| 579 | 587 |
| 580 // handle pre-formatted text | 588 // handle pre-formatted text |
| 581 if (!layout_object->Style()->CollapseWhiteSpace()) { | 589 if (!layout_object->Style()->CollapseWhiteSpace()) { |
| 582 int run_start = offset_; | |
| 583 if (last_text_node_ended_with_collapsed_space_ && | 590 if (last_text_node_ended_with_collapsed_space_ && |
| 584 HasVisibleTextNode(layout_object)) { | 591 HasVisibleTextNode(layout_object)) { |
| 585 if (behavior_.CollapseTrailingSpace()) { | 592 if (behavior_.CollapseTrailingSpace()) { |
| 586 if (run_start > 0 && str[run_start - 1] == ' ') { | 593 if (offset_ > 0 && str[offset_ - 1] == ' ') { |
| 587 SpliceBuffer(kSpaceCharacter, text_node, 0, run_start, run_start); | 594 SpliceBuffer(kSpaceCharacter, text_node, 0, offset_, offset_); |
| 588 return false; | 595 return false; |
| 589 } | 596 } |
| 590 } else { | 597 } else { |
| 591 SpliceBuffer(kSpaceCharacter, text_node, 0, run_start, run_start); | 598 SpliceBuffer(kSpaceCharacter, text_node, 0, offset_, offset_); |
| 592 return false; | 599 return false; |
| 593 } | 600 } |
| 594 } | 601 } |
| 595 if (!handled_first_letter_ && layout_object->IsTextFragment() && !offset_) { | 602 if (ShouldHandleFirstLetter(*layout_object)) { |
| 596 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); | 603 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); |
| 597 if (first_letter_text_) { | 604 if (first_letter_text_) { |
| 598 String first_letter = first_letter_text_->GetText(); | 605 String first_letter = first_letter_text_->GetText(); |
| 599 EmitText(text_node, first_letter_text_, offset_, | 606 EmitText(text_node, first_letter_text_, offset_, |
| 600 offset_ + first_letter.length()); | 607 offset_ + first_letter.length()); |
| 601 first_letter_text_ = nullptr; | 608 first_letter_text_ = nullptr; |
| 602 text_box_ = 0; | 609 text_box_ = 0; |
| 603 return false; | 610 return false; |
| 604 } | 611 } |
| 605 } | 612 } |
| 606 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 613 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
| 607 !IgnoresStyleVisibility()) | 614 !IgnoresStyleVisibility()) |
| 608 return false; | 615 return false; |
| 609 int str_length = str.length(); | 616 const unsigned run_start = offset_; |
| 610 int end = (text_node == end_container_) ? end_offset_ : INT_MAX; | 617 const unsigned str_length = str.length(); |
| 611 int run_end = std::min(str_length, end); | 618 const unsigned end = (text_node == end_container_) ? end_offset_ : INT_MAX; |
| 619 const unsigned run_end = std::min(str_length, end); |
| 612 | 620 |
| 613 if (run_start >= run_end) | 621 if (run_start >= run_end) |
| 614 return true; | 622 return true; |
| 615 | 623 |
| 616 EmitText(text_node, text_node->GetLayoutObject(), run_start, run_end); | 624 EmitText(text_node, text_node->GetLayoutObject(), run_start, run_end); |
| 617 return true; | 625 return true; |
| 618 } | 626 } |
| 619 | 627 |
| 620 if (layout_object->FirstTextBox()) | 628 if (layout_object->FirstTextBox()) |
| 621 text_box_ = layout_object->FirstTextBox(); | 629 text_box_ = layout_object->FirstTextBox(); |
| 622 | 630 |
| 623 bool should_handle_first_letter = | 631 const bool should_handle_first_letter = |
| 624 !handled_first_letter_ && layout_object->IsTextFragment() && !offset_; | 632 ShouldHandleFirstLetter(*layout_object); |
| 625 if (should_handle_first_letter) | 633 if (should_handle_first_letter) |
| 626 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); | 634 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); |
| 627 | 635 |
| 628 if (!layout_object->FirstTextBox() && str.length() > 0 && | 636 if (!layout_object->FirstTextBox() && str.length() > 0 && |
| 629 !should_handle_first_letter) { | 637 !should_handle_first_letter) { |
| 630 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 638 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
| 631 !IgnoresStyleVisibility()) | 639 !IgnoresStyleVisibility()) |
| 632 return false; | 640 return false; |
| 633 last_text_node_ended_with_collapsed_space_ = | 641 last_text_node_ended_with_collapsed_space_ = |
| 634 true; // entire block is collapsed space | 642 true; // entire block is collapsed space |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 void TextIteratorAlgorithm<Strategy>::HandleTextBox() { | 697 void TextIteratorAlgorithm<Strategy>::HandleTextBox() { |
| 690 LayoutText* layout_object = first_letter_text_ | 698 LayoutText* layout_object = first_letter_text_ |
| 691 ? first_letter_text_ | 699 ? first_letter_text_ |
| 692 : ToLayoutText(node_->GetLayoutObject()); | 700 : ToLayoutText(node_->GetLayoutObject()); |
| 693 | 701 |
| 694 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 702 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
| 695 !IgnoresStyleVisibility()) { | 703 !IgnoresStyleVisibility()) { |
| 696 text_box_ = nullptr; | 704 text_box_ = nullptr; |
| 697 } else { | 705 } else { |
| 698 String str = layout_object->GetText(); | 706 String str = layout_object->GetText(); |
| 699 unsigned start = offset_; | 707 const unsigned start = offset_; |
| 700 unsigned end = (node_ == end_container_) | 708 const unsigned end = (node_ == end_container_) |
| 701 ? static_cast<unsigned>(end_offset_) | 709 ? static_cast<unsigned>(end_offset_) |
| 702 : INT_MAX; | 710 : INT_MAX; |
| 703 while (text_box_) { | 711 while (text_box_) { |
| 704 unsigned text_box_start = text_box_->Start(); | 712 const unsigned text_box_start = text_box_->Start(); |
| 705 unsigned run_start = std::max(text_box_start, start); | 713 const unsigned run_start = std::max(text_box_start, start); |
| 706 | 714 |
| 707 // Check for collapsed space at the start of this run. | 715 // Check for collapsed space at the start of this run. |
| 708 InlineTextBox* first_text_box = | 716 InlineTextBox* first_text_box = |
| 709 layout_object->ContainsReversedText() | 717 layout_object->ContainsReversedText() |
| 710 ? (sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]) | 718 ? (sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]) |
| 711 : layout_object->FirstTextBox(); | 719 : layout_object->FirstTextBox(); |
| 712 bool need_space = last_text_node_ended_with_collapsed_space_ || | 720 const bool need_space = last_text_node_ended_with_collapsed_space_ || |
| 713 (text_box_ == first_text_box && | 721 (text_box_ == first_text_box && |
| 714 text_box_start == run_start && run_start > 0); | 722 text_box_start == run_start && run_start > 0); |
| 715 if (need_space && | 723 if (need_space && |
| 716 !layout_object->Style()->IsCollapsibleWhiteSpace( | 724 !layout_object->Style()->IsCollapsibleWhiteSpace( |
| 717 text_state_.LastCharacter()) && | 725 text_state_.LastCharacter()) && |
| 718 text_state_.LastCharacter()) { | 726 text_state_.LastCharacter()) { |
| 719 if (last_text_node_ == node_ && run_start > 0 && | 727 if (last_text_node_ == node_ && run_start > 0 && |
| 720 str[run_start - 1] == ' ') { | 728 str[run_start - 1] == ' ') { |
| 721 unsigned space_run_start = run_start - 1; | 729 unsigned space_run_start = run_start - 1; |
| 722 while (space_run_start > 0 && str[space_run_start - 1] == ' ') | 730 while (space_run_start > 0 && str[space_run_start - 1] == ' ') |
| 723 --space_run_start; | 731 --space_run_start; |
| 724 EmitText(node_, layout_object, space_run_start, space_run_start + 1); | 732 EmitText(node_, layout_object, space_run_start, space_run_start + 1); |
| 725 } else { | 733 } else { |
| 726 SpliceBuffer(kSpaceCharacter, node_, 0, run_start, run_start); | 734 SpliceBuffer(kSpaceCharacter, node_, 0, run_start, run_start); |
| 727 } | 735 } |
| 728 return; | 736 return; |
| 729 } | 737 } |
| 730 unsigned text_box_end = text_box_start + text_box_->Len(); | 738 const unsigned text_box_end = text_box_start + text_box_->Len(); |
| 731 unsigned run_end = std::min(text_box_end, end); | 739 const unsigned run_end = std::min(text_box_end, end); |
| 732 | 740 |
| 733 // Determine what the next text box will be, but don't advance yet | 741 // Determine what the next text box will be, but don't advance yet |
| 734 InlineTextBox* next_text_box = nullptr; | 742 InlineTextBox* next_text_box = nullptr; |
| 735 if (layout_object->ContainsReversedText()) { | 743 if (layout_object->ContainsReversedText()) { |
| 736 if (sorted_text_boxes_position_ + 1 < sorted_text_boxes_.size()) | 744 if (sorted_text_boxes_position_ + 1 < sorted_text_boxes_.size()) |
| 737 next_text_box = sorted_text_boxes_[sorted_text_boxes_position_ + 1]; | 745 next_text_box = sorted_text_boxes_[sorted_text_boxes_position_ + 1]; |
| 738 } else { | 746 } else { |
| 739 next_text_box = text_box_->NextTextBox(); | 747 next_text_box = text_box_->NextTextBox(); |
| 740 } | 748 } |
| 741 | 749 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 788 // If the subrun went to the text box end and this end is also the end | 796 // If the subrun went to the text box end and this end is also the end |
| 789 // of the range, do not advance to the next text box and do not | 797 // of the range, do not advance to the next text box and do not |
| 790 // generate a space, just stop. | 798 // generate a space, just stop. |
| 791 if (text_box_end == end) { | 799 if (text_box_end == end) { |
| 792 text_box_ = nullptr; | 800 text_box_ = nullptr; |
| 793 return; | 801 return; |
| 794 } | 802 } |
| 795 } | 803 } |
| 796 | 804 |
| 797 // Advance and return | 805 // Advance and return |
| 798 unsigned next_run_start = | 806 const unsigned next_run_start = |
| 799 next_text_box ? next_text_box->Start() : str.length(); | 807 next_text_box ? next_text_box->Start() : str.length(); |
| 800 if (next_run_start > run_end) | 808 if (next_run_start > run_end) |
| 801 last_text_node_ended_with_collapsed_space_ = | 809 last_text_node_ended_with_collapsed_space_ = |
| 802 true; // collapsed space between runs or at the end | 810 true; // collapsed space between runs or at the end |
| 803 | 811 |
| 804 text_box_ = next_text_box; | 812 text_box_ = next_text_box; |
| 805 if (layout_object->ContainsReversedText()) | 813 if (layout_object->ContainsReversedText()) |
| 806 ++sorted_text_boxes_position_; | 814 ++sorted_text_boxes_position_; |
| 807 return; | 815 return; |
| 808 } | 816 } |
| 809 // Advance and continue | 817 // Advance and continue |
| 810 text_box_ = next_text_box; | 818 text_box_ = next_text_box; |
| 811 if (layout_object->ContainsReversedText()) | 819 if (layout_object->ContainsReversedText()) |
| 812 ++sorted_text_boxes_position_; | 820 ++sorted_text_boxes_position_; |
| 813 } | 821 } |
| 814 } | 822 } |
| 815 | 823 |
| 816 if (!text_box_ && remaining_text_box_) { | 824 if (ShouldProceedToRemainingText()) { |
| 817 text_box_ = remaining_text_box_; | 825 ProceedToRemainingText(); |
| 818 remaining_text_box_ = 0; | |
| 819 first_letter_text_ = nullptr; | |
| 820 offset_ = 0; | |
| 821 HandleTextBox(); | 826 HandleTextBox(); |
| 822 } | 827 } |
| 823 } | 828 } |
| 824 | 829 |
| 825 template <typename Strategy> | 830 template <typename Strategy> |
| 831 bool TextIteratorAlgorithm<Strategy>::ShouldProceedToRemainingText() const { |
| 832 // TODO(xiaochengh): Handle the case where the iterator should stop in |
| 833 // :first-letter. |
| 834 return !text_box_ && remaining_text_box_; |
| 835 } |
| 836 |
| 837 template <typename Strategy> |
| 838 void TextIteratorAlgorithm<Strategy>::ProceedToRemainingText() { |
| 839 text_box_ = remaining_text_box_; |
| 840 remaining_text_box_ = 0; |
| 841 first_letter_text_ = nullptr; |
| 842 // TODO(xiaochengh): |offset_| should be set to the starting offset of the |
| 843 // remaining text; |
| 844 offset_ = 0; |
| 845 } |
| 846 |
| 847 template <typename Strategy> |
| 826 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter( | 848 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter( |
| 827 LayoutTextFragment* layout_object) { | 849 LayoutTextFragment* layout_object) { |
| 828 handled_first_letter_ = true; | 850 handled_first_letter_ = true; |
| 829 | 851 |
| 830 if (!layout_object->IsRemainingTextLayoutObject()) | 852 if (!layout_object->IsRemainingTextLayoutObject()) |
| 831 return; | 853 return; |
| 832 | 854 |
| 833 FirstLetterPseudoElement* first_letter_element = | 855 FirstLetterPseudoElement* first_letter_element = |
| 834 layout_object->GetFirstLetterPseudoElement(); | 856 layout_object->GetFirstLetterPseudoElement(); |
| 835 if (!first_letter_element) | 857 if (!first_letter_element) |
| (...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1445 String PlainText(const EphemeralRangeInFlatTree& range, | 1467 String PlainText(const EphemeralRangeInFlatTree& range, |
| 1446 const TextIteratorBehavior& behavior) { | 1468 const TextIteratorBehavior& behavior) { |
| 1447 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); | 1469 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); |
| 1448 } | 1470 } |
| 1449 | 1471 |
| 1450 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; | 1472 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; |
| 1451 template class CORE_TEMPLATE_EXPORT | 1473 template class CORE_TEMPLATE_EXPORT |
| 1452 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; | 1474 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; |
| 1453 | 1475 |
| 1454 } // namespace blink | 1476 } // namespace blink |
| OLD | NEW |