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 503 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
514 return false; | 514 return false; |
515 if (!layout_text.IsTextFragment()) | 515 if (!layout_text.IsTextFragment()) |
516 return false; | 516 return false; |
517 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text); | 517 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text); |
518 return offset_ < static_cast<int>(text_fragment.TextStartOffset()); | 518 return offset_ < static_cast<int>(text_fragment.TextStartOffset()); |
519 } | 519 } |
520 | 520 |
521 template <typename Strategy> | 521 template <typename Strategy> |
522 void TextIteratorAlgorithm<Strategy>::HandlePreFormattedTextNode() { | 522 void TextIteratorAlgorithm<Strategy>::HandlePreFormattedTextNode() { |
523 // TODO(xiaochengh): Get rid of repeated computation of these fields. | 523 // TODO(xiaochengh): Get rid of repeated computation of these fields. |
524 Text* const text_node = ToText(node_); | 524 LayoutText* const layout_object = text_node_->GetLayoutObject(); |
525 LayoutText* const layout_object = text_node->GetLayoutObject(); | |
526 const String str = layout_object->GetText(); | 525 const String str = layout_object->GetText(); |
527 | 526 |
528 needs_handle_pre_formatted_text_node_ = false; | 527 needs_handle_pre_formatted_text_node_ = false; |
529 | 528 |
530 if (last_text_node_ended_with_collapsed_space_ && | 529 if (last_text_node_ended_with_collapsed_space_ && |
531 HasVisibleTextNode(layout_object)) { | 530 HasVisibleTextNode(layout_object)) { |
532 if (!behavior_.CollapseTrailingSpace() || | 531 if (!behavior_.CollapseTrailingSpace() || |
533 (offset_ > 0 && str[offset_ - 1] == ' ')) { | 532 (offset_ > 0 && str[offset_ - 1] == ' ')) { |
534 SpliceBuffer(kSpaceCharacter, text_node, 0, offset_, offset_); | 533 SpliceBuffer(kSpaceCharacter, text_node_, 0, offset_, offset_); |
535 needs_handle_pre_formatted_text_node_ = true; | 534 needs_handle_pre_formatted_text_node_ = true; |
536 return; | 535 return; |
537 } | 536 } |
538 } | 537 } |
539 if (ShouldHandleFirstLetter(*layout_object)) { | 538 if (ShouldHandleFirstLetter(*layout_object)) { |
540 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); | 539 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); |
541 if (first_letter_text_) { | 540 if (first_letter_text_) { |
542 const String first_letter = first_letter_text_->GetText(); | 541 const String first_letter = first_letter_text_->GetText(); |
543 const unsigned run_start = offset_; | 542 const unsigned run_start = offset_; |
544 const bool stops_in_first_letter = | 543 const bool stops_in_first_letter = |
545 text_node == end_container_ && | 544 text_node_ == end_container_ && |
546 end_offset_ <= static_cast<int>(first_letter.length()); | 545 end_offset_ <= static_cast<int>(first_letter.length()); |
547 const unsigned run_end = | 546 const unsigned run_end = |
548 stops_in_first_letter ? end_offset_ : first_letter.length(); | 547 stops_in_first_letter ? end_offset_ : first_letter.length(); |
549 EmitText(text_node, first_letter_text_, run_start, run_end); | 548 EmitText(text_node_, first_letter_text_, run_start, run_end); |
550 first_letter_text_ = nullptr; | 549 first_letter_text_ = nullptr; |
551 text_box_ = 0; | 550 text_box_ = 0; |
552 offset_ = run_end; | 551 offset_ = run_end; |
553 if (!stops_in_first_letter) | 552 if (!stops_in_first_letter) |
554 needs_handle_pre_formatted_text_node_ = true; | 553 needs_handle_pre_formatted_text_node_ = true; |
555 return; | 554 return; |
556 } | 555 } |
557 // We are here only if the DOM and/or layout trees are broken. | 556 // We are here only if the DOM and/or layout trees are broken. |
558 // For robustness, we should stop processing this node. | 557 // For robustness, we should stop processing this node. |
559 NOTREACHED(); | 558 NOTREACHED(); |
560 return; | 559 return; |
561 } | 560 } |
562 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 561 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
563 !IgnoresStyleVisibility()) | 562 !IgnoresStyleVisibility()) |
564 return; | 563 return; |
565 DCHECK_GE(static_cast<unsigned>(offset_), layout_object->TextStartOffset()); | 564 DCHECK_GE(static_cast<unsigned>(offset_), layout_object->TextStartOffset()); |
566 const unsigned run_start = offset_ - layout_object->TextStartOffset(); | 565 const unsigned run_start = offset_ - layout_object->TextStartOffset(); |
567 const unsigned str_length = str.length(); | 566 const unsigned str_length = str.length(); |
568 const unsigned end = (text_node == end_container_) | 567 const unsigned end = (text_node_ == end_container_) |
569 ? end_offset_ - layout_object->TextStartOffset() | 568 ? end_offset_ - layout_object->TextStartOffset() |
570 : str_length; | 569 : str_length; |
571 const unsigned run_end = std::min(str_length, end); | 570 const unsigned run_end = std::min(str_length, end); |
572 | 571 |
573 if (run_start >= run_end) | 572 if (run_start >= run_end) |
574 return; | 573 return; |
575 | 574 |
576 EmitText(text_node, text_node->GetLayoutObject(), run_start, run_end); | 575 EmitText(text_node_, text_node_->GetLayoutObject(), run_start, run_end); |
577 } | 576 } |
578 | 577 |
579 template <typename Strategy> | 578 template <typename Strategy> |
580 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() { | 579 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() { |
581 if (ExcludesAutofilledValue()) { | 580 if (ExcludesAutofilledValue()) { |
582 TextControlElement* control = EnclosingTextControl(node_); | 581 TextControlElement* control = EnclosingTextControl(node_); |
583 // For security reason, we don't expose suggested value if it is | 582 // For security reason, we don't expose suggested value if it is |
584 // auto-filled. | 583 // auto-filled. |
585 if (control && control->IsAutofilled()) | 584 if (control && control->IsAutofilled()) |
586 return true; | 585 return true; |
587 } | 586 } |
588 | 587 |
589 DCHECK_NE(last_text_node_, node_) | 588 DCHECK_NE(last_text_node_, node_) |
590 << "We should never call HandleTextNode on the same node twice"; | 589 << "We should never call HandleTextNode on the same node twice"; |
591 | 590 |
592 offset_ = node_ == start_container_ ? start_offset_ : 0; | 591 text_node_ = ToText(node_); |
| 592 offset_ = text_node_ == start_container_ ? start_offset_ : 0; |
593 handled_first_letter_ = false; | 593 handled_first_letter_ = false; |
594 first_letter_text_ = nullptr; | 594 first_letter_text_ = nullptr; |
595 | 595 |
596 Text* text_node = ToText(node_); | 596 LayoutText* layout_object = text_node_->GetLayoutObject(); |
597 LayoutText* layout_object = text_node->GetLayoutObject(); | |
598 | 597 |
599 last_text_node_ = text_node; | 598 last_text_node_ = text_node_; |
600 String str = layout_object->GetText(); | 599 String str = layout_object->GetText(); |
601 | 600 |
602 // handle pre-formatted text | 601 // handle pre-formatted text |
603 if (!layout_object->Style()->CollapseWhiteSpace()) { | 602 if (!layout_object->Style()->CollapseWhiteSpace()) { |
604 HandlePreFormattedTextNode(); | 603 HandlePreFormattedTextNode(); |
605 return true; | 604 return true; |
606 } | 605 } |
607 | 606 |
608 if (layout_object->FirstTextBox()) | 607 if (layout_object->FirstTextBox()) |
609 text_box_ = layout_object->FirstTextBox(); | 608 text_box_ = layout_object->FirstTextBox(); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 | 644 |
646 // Restore the collapsed space for copy & paste. See http://crbug.com/318925 | 645 // Restore the collapsed space for copy & paste. See http://crbug.com/318925 |
647 template <typename Strategy> | 646 template <typename Strategy> |
648 size_t TextIteratorAlgorithm<Strategy>::RestoreCollapsedTrailingSpace( | 647 size_t TextIteratorAlgorithm<Strategy>::RestoreCollapsedTrailingSpace( |
649 InlineTextBox* next_text_box, | 648 InlineTextBox* next_text_box, |
650 size_t subrun_end) { | 649 size_t subrun_end) { |
651 if (next_text_box || !text_box_->Root().NextRootBox() || | 650 if (next_text_box || !text_box_->Root().NextRootBox() || |
652 text_box_->Root().LastChild() != text_box_) | 651 text_box_->Root().LastChild() != text_box_) |
653 return subrun_end; | 652 return subrun_end; |
654 | 653 |
655 const String& text = ToLayoutText(node_->GetLayoutObject())->GetText(); | 654 const String& text = text_node_->GetLayoutObject()->GetText(); |
656 if (text.EndsWith(' ') == 0 || subrun_end != text.length() - 1 || | 655 if (text.EndsWith(' ') == 0 || subrun_end != text.length() - 1 || |
657 text[subrun_end - 1] == ' ') | 656 text[subrun_end - 1] == ' ') |
658 return subrun_end; | 657 return subrun_end; |
659 | 658 |
660 // If there is the leading space in the next line, we don't need to restore | 659 // If there is the leading space in the next line, we don't need to restore |
661 // the trailing space. | 660 // the trailing space. |
662 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div> | 661 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div> |
663 InlineBox* first_box_of_next_line = | 662 InlineBox* first_box_of_next_line = |
664 text_box_->Root().NextRootBox()->FirstChild(); | 663 text_box_->Root().NextRootBox()->FirstChild(); |
665 if (!first_box_of_next_line) | 664 if (!first_box_of_next_line) |
666 return subrun_end + 1; | 665 return subrun_end + 1; |
667 Node* first_node_of_next_line = | 666 Node* first_node_of_next_line = |
668 first_box_of_next_line->GetLineLayoutItem().GetNode(); | 667 first_box_of_next_line->GetLineLayoutItem().GetNode(); |
669 if (!first_node_of_next_line || | 668 if (!first_node_of_next_line || |
670 first_node_of_next_line->nodeValue()[0] != ' ') | 669 first_node_of_next_line->nodeValue()[0] != ' ') |
671 return subrun_end + 1; | 670 return subrun_end + 1; |
672 | 671 |
673 return subrun_end; | 672 return subrun_end; |
674 } | 673 } |
675 | 674 |
676 template <typename Strategy> | 675 template <typename Strategy> |
677 void TextIteratorAlgorithm<Strategy>::HandleTextBox() { | 676 void TextIteratorAlgorithm<Strategy>::HandleTextBox() { |
678 LayoutText* layout_object = first_letter_text_ | 677 LayoutText* layout_object = |
679 ? first_letter_text_ | 678 first_letter_text_ ? first_letter_text_ : text_node_->GetLayoutObject(); |
680 : ToLayoutText(node_->GetLayoutObject()); | |
681 const unsigned text_start_offset = layout_object->TextStartOffset(); | 679 const unsigned text_start_offset = layout_object->TextStartOffset(); |
682 | 680 |
683 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 681 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
684 !IgnoresStyleVisibility()) { | 682 !IgnoresStyleVisibility()) { |
685 text_box_ = nullptr; | 683 text_box_ = nullptr; |
686 } else { | 684 } else { |
687 String str = layout_object->GetText(); | 685 String str = layout_object->GetText(); |
688 // Start and end offsets in |str|, i.e., str[start..end - 1] should be | 686 // Start and end offsets in |str|, i.e., str[start..end - 1] should be |
689 // emitted (after handling whitespace collapsing). | 687 // emitted (after handling whitespace collapsing). |
690 const unsigned start = offset_ - layout_object->TextStartOffset(); | 688 const unsigned start = offset_ - layout_object->TextStartOffset(); |
691 const unsigned end = | 689 const unsigned end = |
692 (node_ == end_container_) | 690 (text_node_ == end_container_) |
693 ? static_cast<unsigned>(end_offset_) - text_start_offset | 691 ? static_cast<unsigned>(end_offset_) - text_start_offset |
694 : INT_MAX; | 692 : INT_MAX; |
695 while (text_box_) { | 693 while (text_box_) { |
696 const unsigned text_box_start = text_box_->Start(); | 694 const unsigned text_box_start = text_box_->Start(); |
697 const unsigned run_start = std::max(text_box_start, start); | 695 const unsigned run_start = std::max(text_box_start, start); |
698 | 696 |
699 // Check for collapsed space at the start of this run. | 697 // Check for collapsed space at the start of this run. |
700 InlineTextBox* first_text_box = | 698 InlineTextBox* first_text_box = |
701 layout_object->ContainsReversedText() | 699 layout_object->ContainsReversedText() |
702 ? (sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]) | 700 ? (sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]) |
703 : layout_object->FirstTextBox(); | 701 : layout_object->FirstTextBox(); |
704 const bool need_space = last_text_node_ended_with_collapsed_space_ || | 702 const bool need_space = last_text_node_ended_with_collapsed_space_ || |
705 (text_box_ == first_text_box && | 703 (text_box_ == first_text_box && |
706 text_box_start == run_start && run_start > 0); | 704 text_box_start == run_start && run_start > 0); |
707 if (need_space && | 705 if (need_space && |
708 !layout_object->Style()->IsCollapsibleWhiteSpace( | 706 !layout_object->Style()->IsCollapsibleWhiteSpace( |
709 text_state_.LastCharacter()) && | 707 text_state_.LastCharacter()) && |
710 text_state_.LastCharacter()) { | 708 text_state_.LastCharacter()) { |
711 if (last_text_node_ == node_ && run_start > 0 && | 709 if (last_text_node_ == text_node_ && run_start > 0 && |
712 str[run_start - 1] == ' ') { | 710 str[run_start - 1] == ' ') { |
713 unsigned space_run_start = run_start - 1; | 711 unsigned space_run_start = run_start - 1; |
714 while (space_run_start > 0 && str[space_run_start - 1] == ' ') | 712 while (space_run_start > 0 && str[space_run_start - 1] == ' ') |
715 --space_run_start; | 713 --space_run_start; |
716 EmitText(node_, layout_object, space_run_start, space_run_start + 1); | 714 EmitText(text_node_, layout_object, space_run_start, |
| 715 space_run_start + 1); |
717 } else { | 716 } else { |
718 SpliceBuffer(kSpaceCharacter, node_, 0, run_start, run_start); | 717 SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start, run_start); |
719 } | 718 } |
720 return; | 719 return; |
721 } | 720 } |
722 const unsigned text_box_end = text_box_start + text_box_->Len(); | 721 const unsigned text_box_end = text_box_start + text_box_->Len(); |
723 const unsigned run_end = std::min(text_box_end, end); | 722 const unsigned run_end = std::min(text_box_end, end); |
724 | 723 |
725 // Determine what the next text box will be, but don't advance yet | 724 // Determine what the next text box will be, but don't advance yet |
726 InlineTextBox* next_text_box = nullptr; | 725 InlineTextBox* next_text_box = nullptr; |
727 if (layout_object->ContainsReversedText()) { | 726 if (layout_object->ContainsReversedText()) { |
728 if (sorted_text_boxes_position_ + 1 < sorted_text_boxes_.size()) | 727 if (sorted_text_boxes_position_ + 1 < sorted_text_boxes_.size()) |
(...skipping 16 matching lines...) Expand all Loading... |
745 next_text_box->GetLineLayoutItem().IsEqual(layout_object)); | 744 next_text_box->GetLineLayoutItem().IsEqual(layout_object)); |
746 | 745 |
747 if (run_start < run_end) { | 746 if (run_start < run_end) { |
748 // Handle either a single newline character (which becomes a space), | 747 // Handle either a single newline character (which becomes a space), |
749 // or a run of characters that does not include a newline. | 748 // or a run of characters that does not include a newline. |
750 // This effectively translates newlines to spaces without copying the | 749 // This effectively translates newlines to spaces without copying the |
751 // text. | 750 // text. |
752 if (str[run_start] == '\n') { | 751 if (str[run_start] == '\n') { |
753 // We need to preserve new lines in case of PreLine. | 752 // We need to preserve new lines in case of PreLine. |
754 // See bug crbug.com/317365. | 753 // See bug crbug.com/317365. |
755 if (layout_object->Style()->WhiteSpace() == EWhiteSpace::kPreLine) | 754 if (layout_object->Style()->WhiteSpace() == EWhiteSpace::kPreLine) { |
756 SpliceBuffer('\n', node_, 0, run_start, run_start); | 755 SpliceBuffer('\n', text_node_, 0, run_start, run_start); |
757 else | 756 } else { |
758 SpliceBuffer(kSpaceCharacter, node_, 0, run_start, run_start + 1); | 757 SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start, |
| 758 run_start + 1); |
| 759 } |
759 offset_ = text_start_offset + run_start + 1; | 760 offset_ = text_start_offset + run_start + 1; |
760 } else { | 761 } else { |
761 size_t subrun_end = str.find('\n', run_start); | 762 size_t subrun_end = str.find('\n', run_start); |
762 if (subrun_end == kNotFound || subrun_end > run_end) { | 763 if (subrun_end == kNotFound || subrun_end > run_end) { |
763 subrun_end = run_end; | 764 subrun_end = run_end; |
764 subrun_end = | 765 subrun_end = |
765 RestoreCollapsedTrailingSpace(next_text_box, subrun_end); | 766 RestoreCollapsedTrailingSpace(next_text_box, subrun_end); |
766 } | 767 } |
767 | 768 |
768 offset_ = text_start_offset + subrun_end; | 769 offset_ = text_start_offset + subrun_end; |
769 EmitText(node_, layout_object, run_start, subrun_end); | 770 EmitText(text_node_, layout_object, run_start, subrun_end); |
770 } | 771 } |
771 | 772 |
772 // If we are doing a subrun that doesn't go to the end of the text box, | 773 // If we are doing a subrun that doesn't go to the end of the text box, |
773 // come back again to finish handling this text box; don't advance to | 774 // come back again to finish handling this text box; don't advance to |
774 // the next one. | 775 // the next one. |
775 if (static_cast<unsigned>(text_state_.PositionEndOffset()) < | 776 if (static_cast<unsigned>(text_state_.PositionEndOffset()) < |
776 text_box_end) | 777 text_box_end) |
777 return; | 778 return; |
778 | 779 |
779 if (behavior_.DoesNotEmitSpaceBeyondRangeEnd()) { | 780 if (behavior_.DoesNotEmitSpaceBeyondRangeEnd()) { |
(...skipping 28 matching lines...) Expand all Loading... |
808 if (ShouldProceedToRemainingText()) { | 809 if (ShouldProceedToRemainingText()) { |
809 ProceedToRemainingText(); | 810 ProceedToRemainingText(); |
810 HandleTextBox(); | 811 HandleTextBox(); |
811 } | 812 } |
812 } | 813 } |
813 | 814 |
814 template <typename Strategy> | 815 template <typename Strategy> |
815 bool TextIteratorAlgorithm<Strategy>::ShouldProceedToRemainingText() const { | 816 bool TextIteratorAlgorithm<Strategy>::ShouldProceedToRemainingText() const { |
816 if (text_box_ || !remaining_text_box_) | 817 if (text_box_ || !remaining_text_box_) |
817 return false; | 818 return false; |
818 if (node_ != end_container_) | 819 if (text_node_ != end_container_) |
819 return true; | 820 return true; |
820 return offset_ < end_offset_; | 821 return offset_ < end_offset_; |
821 } | 822 } |
822 | 823 |
823 template <typename Strategy> | 824 template <typename Strategy> |
824 void TextIteratorAlgorithm<Strategy>::ProceedToRemainingText() { | 825 void TextIteratorAlgorithm<Strategy>::ProceedToRemainingText() { |
825 text_box_ = remaining_text_box_; | 826 text_box_ = remaining_text_box_; |
826 remaining_text_box_ = 0; | 827 remaining_text_box_ = 0; |
827 first_letter_text_ = nullptr; | 828 first_letter_text_ = nullptr; |
828 offset_ = ToLayoutText(node_->GetLayoutObject())->TextStartOffset(); | 829 offset_ = text_node_->GetLayoutObject()->TextStartOffset(); |
829 } | 830 } |
830 | 831 |
831 template <typename Strategy> | 832 template <typename Strategy> |
832 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter( | 833 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter( |
833 LayoutTextFragment* layout_object) { | 834 LayoutTextFragment* layout_object) { |
834 handled_first_letter_ = true; | 835 handled_first_letter_ = true; |
835 | 836 |
836 if (!layout_object->IsRemainingTextLayoutObject()) | 837 if (!layout_object->IsRemainingTextLayoutObject()) |
837 return; | 838 return; |
838 | 839 |
(...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1404 String PlainText(const EphemeralRangeInFlatTree& range, | 1405 String PlainText(const EphemeralRangeInFlatTree& range, |
1405 const TextIteratorBehavior& behavior) { | 1406 const TextIteratorBehavior& behavior) { |
1406 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); | 1407 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); |
1407 } | 1408 } |
1408 | 1409 |
1409 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; | 1410 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; |
1410 template class CORE_TEMPLATE_EXPORT | 1411 template class CORE_TEMPLATE_EXPORT |
1411 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; | 1412 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; |
1412 | 1413 |
1413 } // namespace blink | 1414 } // namespace blink |
OLD | NEW |