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

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

Issue 2888463002: Refactor some first-letter handling code in TextIterator (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/editing/iterators/TextIterator.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All
3 * rights reserved. 3 * rights reserved.
4 * Copyright (C) 2005 Alexey Proskuryakov. 4 * Copyright (C) 2005 Alexey Proskuryakov.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/iterators/TextIterator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698