Chromium Code Reviews| 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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 #include "platform/fonts/Font.h" | 55 #include "platform/fonts/Font.h" |
| 56 #include "platform/wtf/text/CString.h" | 56 #include "platform/wtf/text/CString.h" |
| 57 #include "platform/wtf/text/StringBuilder.h" | 57 #include "platform/wtf/text/StringBuilder.h" |
| 58 | 58 |
| 59 namespace blink { | 59 namespace blink { |
| 60 | 60 |
| 61 using namespace HTMLNames; | 61 using namespace HTMLNames; |
| 62 | 62 |
| 63 namespace { | 63 namespace { |
| 64 | 64 |
| 65 const int kInvalidTextOffset = -1; | |
| 66 | |
| 67 template <typename Strategy> | 65 template <typename Strategy> |
| 68 TextIteratorBehavior AdjustBehaviorFlags(const TextIteratorBehavior&); | 66 TextIteratorBehavior AdjustBehaviorFlags(const TextIteratorBehavior&); |
| 69 | 67 |
| 70 template <> | 68 template <> |
| 71 TextIteratorBehavior AdjustBehaviorFlags<EditingStrategy>( | 69 TextIteratorBehavior AdjustBehaviorFlags<EditingStrategy>( |
| 72 const TextIteratorBehavior& behavior) { | 70 const TextIteratorBehavior& behavior) { |
| 73 if (!behavior.ForSelectionToString()) | 71 if (!behavior.ForSelectionToString()) |
| 74 return behavior; | 72 return behavior; |
| 75 return TextIteratorBehavior::Builder(behavior) | 73 return TextIteratorBehavior::Builder(behavior) |
| 76 .SetExcludeAutofilledValue(true) | 74 .SetExcludeAutofilledValue(true) |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 text_box_(nullptr), | 166 text_box_(nullptr), |
| 169 remaining_text_box_(nullptr), | 167 remaining_text_box_(nullptr), |
| 170 first_letter_text_(nullptr), | 168 first_letter_text_(nullptr), |
| 171 last_text_node_(nullptr), | 169 last_text_node_(nullptr), |
| 172 last_text_node_ended_with_collapsed_space_(false), | 170 last_text_node_ended_with_collapsed_space_(false), |
| 173 sorted_text_boxes_position_(0), | 171 sorted_text_boxes_position_(0), |
| 174 behavior_(AdjustBehaviorFlags<Strategy>(behavior)), | 172 behavior_(AdjustBehaviorFlags<Strategy>(behavior)), |
| 175 handled_first_letter_(false), | 173 handled_first_letter_(false), |
| 176 should_stop_(false), | 174 should_stop_(false), |
| 177 handle_shadow_root_(false), | 175 handle_shadow_root_(false), |
| 178 first_letter_start_offset_(kInvalidTextOffset), | |
| 179 remaining_text_start_offset_(kInvalidTextOffset), | |
| 180 text_state_(behavior_) { | 176 text_state_(behavior_) { |
| 181 DCHECK(start.IsNotNull()); | 177 DCHECK(start.IsNotNull()); |
| 182 DCHECK(end.IsNotNull()); | 178 DCHECK(end.IsNotNull()); |
| 183 | 179 |
| 184 // TODO(dglazkov): TextIterator should not be created for documents that don't | 180 // TODO(dglazkov): TextIterator should not be created for documents that don't |
| 185 // have a frame, but it currently still happens in some cases. See | 181 // have a frame, but it currently still happens in some cases. See |
| 186 // http://crbug.com/591877 for details. | 182 // http://crbug.com/591877 for details. |
| 187 DCHECK(!start.GetDocument()->View() || | 183 DCHECK(!start.GetDocument()->View() || |
| 188 !start.GetDocument()->View()->NeedsLayout()); | 184 !start.GetDocument()->View()->NeedsLayout()); |
| 189 DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate()); | 185 DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate()); |
| 190 | 186 |
| 191 if (start.CompareTo(end) > 0) { | 187 if (start.CompareTo(end) > 0) { |
| 192 Initialize(end.ComputeContainerNode(), end.ComputeOffsetInContainerNode(), | 188 Initialize(end.ComputeContainerNode(), end.ComputeOffsetInContainerNode(), |
| 193 start.ComputeContainerNode(), | 189 start.ComputeContainerNode(), |
| 194 start.ComputeOffsetInContainerNode()); | 190 start.ComputeOffsetInContainerNode()); |
| 195 return; | 191 return; |
| 196 } | 192 } |
| 197 Initialize(start.ComputeContainerNode(), start.ComputeOffsetInContainerNode(), | 193 Initialize(start.ComputeContainerNode(), start.ComputeOffsetInContainerNode(), |
| 198 end.ComputeContainerNode(), end.ComputeOffsetInContainerNode()); | 194 end.ComputeContainerNode(), end.ComputeOffsetInContainerNode()); |
| 199 } | 195 } |
| 200 | 196 |
| 201 template <typename Strategy> | 197 template <typename Strategy> |
| 202 bool TextIteratorAlgorithm<Strategy>::PrepareForFirstLetterInitialization() { | |
| 203 if (node_ != start_container_) | |
| 204 return false; | |
| 205 | |
| 206 if (node_->getNodeType() != Node::kTextNode) | |
| 207 return false; | |
| 208 | |
| 209 Text* text_node = ToText(node_); | |
| 210 LayoutText* layout_object = text_node->GetLayoutObject(); | |
| 211 if (!layout_object || !layout_object->IsTextFragment()) | |
| 212 return false; | |
| 213 | |
| 214 LayoutTextFragment* text_fragment = ToLayoutTextFragment(layout_object); | |
| 215 if (!text_fragment->IsRemainingTextLayoutObject()) | |
| 216 return false; | |
| 217 | |
| 218 if (static_cast<unsigned>(start_offset_) >= | |
| 219 text_fragment->TextStartOffset()) { | |
| 220 remaining_text_start_offset_ = | |
| 221 start_offset_ - text_fragment->TextStartOffset(); | |
| 222 } else { | |
| 223 first_letter_start_offset_ = start_offset_; | |
| 224 } | |
| 225 offset_ = 0; | |
| 226 | |
| 227 return true; | |
| 228 } | |
| 229 | |
| 230 template <typename Strategy> | |
| 231 bool TextIteratorAlgorithm<Strategy>::HasNotAdvancedToStartPosition() { | |
| 232 if (AtEnd()) | |
| 233 return false; | |
| 234 if (remaining_text_start_offset_ == kInvalidTextOffset) | |
| 235 return false; | |
| 236 return node_ == start_container_; | |
| 237 } | |
| 238 | |
| 239 template <typename Strategy> | |
| 240 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container, | 198 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container, |
| 241 int start_offset, | 199 int start_offset, |
| 242 Node* end_container, | 200 Node* end_container, |
| 243 int end_offset) { | 201 int end_offset) { |
| 244 DCHECK(start_container); | 202 DCHECK(start_container); |
| 245 DCHECK(end_container); | 203 DCHECK(end_container); |
| 246 | 204 |
| 247 // Remember the range - this does not change. | 205 // Remember the range - this does not change. |
| 248 start_container_ = start_container; | 206 start_container_ = start_container; |
| 249 start_offset_ = start_offset; | 207 start_offset_ = start_offset; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 263 node_ = child; | 221 node_ = child; |
| 264 else if (!start_offset) | 222 else if (!start_offset) |
| 265 node_ = start_container; | 223 node_ = start_container; |
| 266 else | 224 else |
| 267 node_ = Strategy::NextSkippingChildren(*start_container); | 225 node_ = Strategy::NextSkippingChildren(*start_container); |
| 268 | 226 |
| 269 if (!node_) | 227 if (!node_) |
| 270 return; | 228 return; |
| 271 | 229 |
| 272 fully_clipped_stack_.SetUpFullyClippedStack(node_); | 230 fully_clipped_stack_.SetUpFullyClippedStack(node_); |
| 273 if (!PrepareForFirstLetterInitialization()) | 231 offset_ = node_ == start_container_ ? start_offset_ : 0; |
| 274 offset_ = node_ == start_container_ ? start_offset_ : 0; | |
| 275 iteration_progress_ = kHandledNone; | 232 iteration_progress_ = kHandledNone; |
| 276 | 233 |
| 277 // Calculate first out of bounds node. | 234 // Calculate first out of bounds node. |
| 278 past_end_node_ = end_container | 235 past_end_node_ = end_container |
| 279 ? PastLastNode<Strategy>(*end_container, end_offset) | 236 ? PastLastNode<Strategy>(*end_container, end_offset) |
| 280 : nullptr; | 237 : nullptr; |
| 281 | 238 |
| 282 // Identify the first run. | 239 // Identify the first run. |
| 283 Advance(); | 240 Advance(); |
| 284 | |
| 285 // The current design cannot start in a text node with arbitrary offset, if | |
| 286 // the node has :first-letter. Instead, we start with offset 0, and have extra | |
| 287 // advance() calls until we have moved to/past the starting position. | |
| 288 while (HasNotAdvancedToStartPosition()) | |
| 289 Advance(); | |
| 290 | |
| 291 // Clear temporary data for initialization with :first-letter. | |
| 292 first_letter_start_offset_ = kInvalidTextOffset; | |
| 293 remaining_text_start_offset_ = kInvalidTextOffset; | |
| 294 } | 241 } |
| 295 | 242 |
| 296 template <typename Strategy> | 243 template <typename Strategy> |
| 297 TextIteratorAlgorithm<Strategy>::~TextIteratorAlgorithm() { | 244 TextIteratorAlgorithm<Strategy>::~TextIteratorAlgorithm() { |
| 298 if (!handle_shadow_root_) | 245 if (!handle_shadow_root_) |
| 299 return; | 246 return; |
| 300 Document* document = OwnerDocument(); | 247 Document* document = OwnerDocument(); |
| 301 if (!document) | 248 if (!document) |
| 302 return; | 249 return; |
| 303 if (behavior_.ForInnerText()) | 250 if (behavior_.ForInnerText()) |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 557 EVisibility::kVisible; | 504 EVisibility::kVisible; |
| 558 } | 505 } |
| 559 | 506 |
| 560 template <typename Strategy> | 507 template <typename Strategy> |
| 561 bool TextIteratorAlgorithm<Strategy>::ShouldHandleFirstLetter( | 508 bool TextIteratorAlgorithm<Strategy>::ShouldHandleFirstLetter( |
| 562 const LayoutText& layout_text) const { | 509 const LayoutText& layout_text) const { |
| 563 if (handled_first_letter_) | 510 if (handled_first_letter_) |
| 564 return false; | 511 return false; |
| 565 if (!layout_text.IsTextFragment()) | 512 if (!layout_text.IsTextFragment()) |
| 566 return false; | 513 return false; |
| 567 // TODO(xiaochengh): Handle the case where :first-letter has multiple chars, | 514 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text); |
| 568 // and eliminate the hack with first_letter/remaining_text_start_offset_. | 515 return offset_ < static_cast<int>(text_fragment.TextStartOffset()); |
| 569 return !offset_; | |
| 570 } | 516 } |
| 571 | 517 |
| 572 template <typename Strategy> | 518 template <typename Strategy> |
| 573 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() { | 519 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() { |
| 574 if (ExcludesAutofilledValue()) { | 520 if (ExcludesAutofilledValue()) { |
| 575 TextControlElement* control = EnclosingTextControl(node_); | 521 TextControlElement* control = EnclosingTextControl(node_); |
| 576 // For security reason, we don't expose suggested value if it is | 522 // For security reason, we don't expose suggested value if it is |
| 577 // auto-filled. | 523 // auto-filled. |
| 578 if (control && control->IsAutofilled()) | 524 if (control && control->IsAutofilled()) |
| 579 return true; | 525 return true; |
| 580 } | 526 } |
| 581 | 527 |
| 582 Text* text_node = ToText(node_); | 528 Text* text_node = ToText(node_); |
| 583 LayoutText* layout_object = text_node->GetLayoutObject(); | 529 LayoutText* layout_object = text_node->GetLayoutObject(); |
| 584 | 530 |
| 585 last_text_node_ = text_node; | 531 last_text_node_ = text_node; |
| 586 String str = layout_object->GetText(); | 532 String str = layout_object->GetText(); |
| 587 | 533 |
| 588 // handle pre-formatted text | 534 // handle pre-formatted text |
| 589 if (!layout_object->Style()->CollapseWhiteSpace()) { | 535 if (!layout_object->Style()->CollapseWhiteSpace()) { |
| 590 if (last_text_node_ended_with_collapsed_space_ && | 536 if (last_text_node_ended_with_collapsed_space_ && |
| 591 HasVisibleTextNode(layout_object)) { | 537 HasVisibleTextNode(layout_object)) { |
| 592 if (behavior_.CollapseTrailingSpace()) { | 538 if (behavior_.CollapseTrailingSpace()) { |
| 593 if (offset_ > 0 && str[offset_ - 1] == ' ') { | 539 if (offset_ > 0 && str[offset_ - 1] == ' ') { |
| 594 SpliceBuffer(kSpaceCharacter, text_node, 0, offset_, offset_); | 540 SpliceBuffer(kSpaceCharacter, text_node, 0, offset_, offset_); |
|
Xiaocheng
2017/05/16 23:33:31
I don't think this line is reachable. I'll remove
| |
| 595 return false; | 541 return false; |
| 596 } | 542 } |
| 597 } else { | 543 } else { |
| 598 SpliceBuffer(kSpaceCharacter, text_node, 0, offset_, offset_); | 544 SpliceBuffer(kSpaceCharacter, text_node, 0, offset_, offset_); |
| 599 return false; | 545 return false; |
| 600 } | 546 } |
| 601 } | 547 } |
| 602 if (ShouldHandleFirstLetter(*layout_object)) { | 548 if (ShouldHandleFirstLetter(*layout_object)) { |
| 603 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); | 549 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); |
| 604 if (first_letter_text_) { | 550 if (first_letter_text_) { |
| 605 String first_letter = first_letter_text_->GetText(); | 551 String first_letter = first_letter_text_->GetText(); |
| 606 EmitText(text_node, first_letter_text_, offset_, | 552 const unsigned run_start = offset_; |
| 607 offset_ + first_letter.length()); | 553 const bool stops_in_first_letter = |
| 554 text_node == end_container_ && | |
| 555 end_offset_ <= static_cast<int>(first_letter.length()); | |
| 556 const unsigned run_end = | |
| 557 stops_in_first_letter ? end_offset_ : first_letter.length(); | |
| 558 EmitText(text_node, first_letter_text_, run_start, run_end); | |
| 608 first_letter_text_ = nullptr; | 559 first_letter_text_ = nullptr; |
| 609 text_box_ = 0; | 560 text_box_ = 0; |
| 610 return false; | 561 offset_ = run_end; |
| 562 return stops_in_first_letter; | |
| 611 } | 563 } |
| 564 // We are here only if the DOM and/or layout trees are broken. | |
| 565 NOTREACHED(); | |
| 612 } | 566 } |
| 613 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 567 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
| 614 !IgnoresStyleVisibility()) | 568 !IgnoresStyleVisibility()) |
| 615 return false; | 569 return false; |
| 616 const unsigned run_start = offset_; | 570 const unsigned run_start = offset_ - layout_object->TextStartOffset(); |
| 617 const unsigned str_length = str.length(); | 571 const unsigned str_length = str.length(); |
| 618 const unsigned end = (text_node == end_container_) ? end_offset_ : INT_MAX; | 572 const unsigned end = (text_node == end_container_) |
| 573 ? end_offset_ - layout_object->TextStartOffset() | |
| 574 : INT_MAX; | |
| 619 const unsigned run_end = std::min(str_length, end); | 575 const unsigned run_end = std::min(str_length, end); |
| 620 | 576 |
| 621 if (run_start >= run_end) | 577 if (run_start >= run_end) |
| 622 return true; | 578 return true; |
| 623 | 579 |
| 624 EmitText(text_node, text_node->GetLayoutObject(), run_start, run_end); | 580 EmitText(text_node, text_node->GetLayoutObject(), run_start, run_end); |
| 625 return true; | 581 return true; |
| 626 } | 582 } |
| 627 | 583 |
| 628 if (layout_object->FirstTextBox()) | 584 if (layout_object->FirstTextBox()) |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 691 return subrun_end + 1; | 647 return subrun_end + 1; |
| 692 | 648 |
| 693 return subrun_end; | 649 return subrun_end; |
| 694 } | 650 } |
| 695 | 651 |
| 696 template <typename Strategy> | 652 template <typename Strategy> |
| 697 void TextIteratorAlgorithm<Strategy>::HandleTextBox() { | 653 void TextIteratorAlgorithm<Strategy>::HandleTextBox() { |
| 698 LayoutText* layout_object = first_letter_text_ | 654 LayoutText* layout_object = first_letter_text_ |
| 699 ? first_letter_text_ | 655 ? first_letter_text_ |
| 700 : ToLayoutText(node_->GetLayoutObject()); | 656 : ToLayoutText(node_->GetLayoutObject()); |
| 657 const unsigned text_start_offset = layout_object->TextStartOffset(); | |
| 701 | 658 |
| 702 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 659 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
| 703 !IgnoresStyleVisibility()) { | 660 !IgnoresStyleVisibility()) { |
| 704 text_box_ = nullptr; | 661 text_box_ = nullptr; |
| 705 } else { | 662 } else { |
| 706 String str = layout_object->GetText(); | 663 String str = layout_object->GetText(); |
| 707 const unsigned start = offset_; | 664 // Start and end offsets in |str|, i.e., str[start..end - 1] should be |
| 708 const unsigned end = (node_ == end_container_) | 665 // emitted (after handling whitespace collapsing). |
| 709 ? static_cast<unsigned>(end_offset_) | 666 const unsigned start = offset_ - layout_object->TextStartOffset(); |
| 710 : INT_MAX; | 667 const unsigned end = |
| 668 (node_ == end_container_) | |
| 669 ? static_cast<unsigned>(end_offset_) - text_start_offset | |
| 670 : INT_MAX; | |
| 711 while (text_box_) { | 671 while (text_box_) { |
| 712 const unsigned text_box_start = text_box_->Start(); | 672 const unsigned text_box_start = text_box_->Start(); |
| 713 const unsigned run_start = std::max(text_box_start, start); | 673 const unsigned run_start = std::max(text_box_start, start); |
| 714 | 674 |
| 715 // Check for collapsed space at the start of this run. | 675 // Check for collapsed space at the start of this run. |
| 716 InlineTextBox* first_text_box = | 676 InlineTextBox* first_text_box = |
| 717 layout_object->ContainsReversedText() | 677 layout_object->ContainsReversedText() |
| 718 ? (sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]) | 678 ? (sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]) |
| 719 : layout_object->FirstTextBox(); | 679 : layout_object->FirstTextBox(); |
| 720 const bool need_space = last_text_node_ended_with_collapsed_space_ || | 680 const bool need_space = last_text_node_ended_with_collapsed_space_ || |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 765 // or a run of characters that does not include a newline. | 725 // or a run of characters that does not include a newline. |
| 766 // This effectively translates newlines to spaces without copying the | 726 // This effectively translates newlines to spaces without copying the |
| 767 // text. | 727 // text. |
| 768 if (str[run_start] == '\n') { | 728 if (str[run_start] == '\n') { |
| 769 // We need to preserve new lines in case of PreLine. | 729 // We need to preserve new lines in case of PreLine. |
| 770 // See bug crbug.com/317365. | 730 // See bug crbug.com/317365. |
| 771 if (layout_object->Style()->WhiteSpace() == EWhiteSpace::kPreLine) | 731 if (layout_object->Style()->WhiteSpace() == EWhiteSpace::kPreLine) |
| 772 SpliceBuffer('\n', node_, 0, run_start, run_start); | 732 SpliceBuffer('\n', node_, 0, run_start, run_start); |
| 773 else | 733 else |
| 774 SpliceBuffer(kSpaceCharacter, node_, 0, run_start, run_start + 1); | 734 SpliceBuffer(kSpaceCharacter, node_, 0, run_start, run_start + 1); |
| 775 offset_ = run_start + 1; | 735 offset_ = text_start_offset + run_start + 1; |
| 776 } else { | 736 } else { |
| 777 size_t subrun_end = str.find('\n', run_start); | 737 size_t subrun_end = str.find('\n', run_start); |
| 778 if (subrun_end == kNotFound || subrun_end > run_end) { | 738 if (subrun_end == kNotFound || subrun_end > run_end) { |
| 779 subrun_end = run_end; | 739 subrun_end = run_end; |
| 780 subrun_end = | 740 subrun_end = |
| 781 RestoreCollapsedTrailingSpace(next_text_box, subrun_end); | 741 RestoreCollapsedTrailingSpace(next_text_box, subrun_end); |
| 782 } | 742 } |
| 783 | 743 |
| 784 offset_ = subrun_end; | 744 offset_ = text_start_offset + subrun_end; |
| 785 EmitText(node_, layout_object, run_start, subrun_end); | 745 EmitText(node_, layout_object, run_start, subrun_end); |
| 786 } | 746 } |
| 787 | 747 |
| 788 // If we are doing a subrun that doesn't go to the end of the text box, | 748 // If we are doing a subrun that doesn't go to the end of the text box, |
| 789 // come back again to finish handling this text box; don't advance to | 749 // come back again to finish handling this text box; don't advance to |
| 790 // the next one. | 750 // the next one. |
| 791 if (static_cast<unsigned>(text_state_.PositionEndOffset()) < | 751 if (static_cast<unsigned>(text_state_.PositionEndOffset()) < |
| 792 text_box_end) | 752 text_box_end) |
| 793 return; | 753 return; |
| 794 | 754 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 822 } | 782 } |
| 823 | 783 |
| 824 if (ShouldProceedToRemainingText()) { | 784 if (ShouldProceedToRemainingText()) { |
| 825 ProceedToRemainingText(); | 785 ProceedToRemainingText(); |
| 826 HandleTextBox(); | 786 HandleTextBox(); |
| 827 } | 787 } |
| 828 } | 788 } |
| 829 | 789 |
| 830 template <typename Strategy> | 790 template <typename Strategy> |
| 831 bool TextIteratorAlgorithm<Strategy>::ShouldProceedToRemainingText() const { | 791 bool TextIteratorAlgorithm<Strategy>::ShouldProceedToRemainingText() const { |
| 832 // TODO(xiaochengh): Handle the case where the iterator should stop in | 792 if (text_box_ || !remaining_text_box_) |
| 833 // :first-letter. | 793 return false; |
| 834 return !text_box_ && remaining_text_box_; | 794 if (node_ != end_container_) |
| 795 return true; | |
| 796 return offset_ < end_offset_; | |
| 835 } | 797 } |
| 836 | 798 |
| 837 template <typename Strategy> | 799 template <typename Strategy> |
| 838 void TextIteratorAlgorithm<Strategy>::ProceedToRemainingText() { | 800 void TextIteratorAlgorithm<Strategy>::ProceedToRemainingText() { |
| 839 text_box_ = remaining_text_box_; | 801 text_box_ = remaining_text_box_; |
| 840 remaining_text_box_ = 0; | 802 remaining_text_box_ = 0; |
| 841 first_letter_text_ = nullptr; | 803 first_letter_text_ = nullptr; |
| 842 // TODO(xiaochengh): |offset_| should be set to the starting offset of the | 804 offset_ = ToLayoutText(node_->GetLayoutObject())->TextStartOffset(); |
| 843 // remaining text; | |
| 844 offset_ = 0; | |
| 845 } | 805 } |
| 846 | 806 |
| 847 template <typename Strategy> | 807 template <typename Strategy> |
| 848 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter( | 808 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter( |
| 849 LayoutTextFragment* layout_object) { | 809 LayoutTextFragment* layout_object) { |
| 850 handled_first_letter_ = true; | 810 handled_first_letter_ = true; |
| 851 | 811 |
| 852 if (!layout_object->IsRemainingTextLayoutObject()) | 812 if (!layout_object->IsRemainingTextLayoutObject()) |
| 853 return; | 813 return; |
| 854 | 814 |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1223 int text_end_offset) { | 1183 int text_end_offset) { |
| 1224 // Since m_lastTextNodeEndedWithCollapsedSpace seems better placed in | 1184 // Since m_lastTextNodeEndedWithCollapsedSpace seems better placed in |
| 1225 // TextIterator, but is always reset when we call spliceBuffer, we | 1185 // TextIterator, but is always reset when we call spliceBuffer, we |
| 1226 // wrap TextIteratorTextState::spliceBuffer() with this function. | 1186 // wrap TextIteratorTextState::spliceBuffer() with this function. |
| 1227 text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset, | 1187 text_state_.SpliceBuffer(c, text_node, offset_base_node, text_start_offset, |
| 1228 text_end_offset); | 1188 text_end_offset); |
| 1229 last_text_node_ended_with_collapsed_space_ = false; | 1189 last_text_node_ended_with_collapsed_space_ = false; |
| 1230 } | 1190 } |
| 1231 | 1191 |
| 1232 template <typename Strategy> | 1192 template <typename Strategy> |
| 1233 int TextIteratorAlgorithm<Strategy>::AdjustedStartForFirstLetter( | |
| 1234 const Node& text_node, | |
| 1235 const LayoutText& layout_object, | |
| 1236 int text_start_offset, | |
| 1237 int text_end_offset) { | |
| 1238 if (first_letter_start_offset_ == kInvalidTextOffset) | |
| 1239 return text_start_offset; | |
| 1240 if (text_node != start_container_) | |
| 1241 return text_start_offset; | |
| 1242 if (!layout_object.IsTextFragment()) | |
| 1243 return text_start_offset; | |
| 1244 if (ToLayoutTextFragment(layout_object).IsRemainingTextLayoutObject()) | |
| 1245 return text_start_offset; | |
| 1246 if (text_end_offset <= first_letter_start_offset_) | |
| 1247 return text_start_offset; | |
| 1248 int adjusted_offset = std::max(text_start_offset, first_letter_start_offset_); | |
| 1249 first_letter_start_offset_ = kInvalidTextOffset; | |
| 1250 return adjusted_offset; | |
| 1251 } | |
| 1252 | |
| 1253 template <typename Strategy> | |
| 1254 int TextIteratorAlgorithm<Strategy>::AdjustedStartForRemainingText( | |
| 1255 const Node& text_node, | |
| 1256 const LayoutText& layout_object, | |
| 1257 int text_start_offset, | |
| 1258 int text_end_offset) { | |
| 1259 if (remaining_text_start_offset_ == kInvalidTextOffset) | |
| 1260 return text_start_offset; | |
| 1261 if (text_node != start_container_) | |
| 1262 return text_start_offset; | |
| 1263 if (!layout_object.IsTextFragment()) | |
| 1264 return text_start_offset; | |
| 1265 if (!ToLayoutTextFragment(layout_object).IsRemainingTextLayoutObject()) | |
| 1266 return text_start_offset; | |
| 1267 if (text_end_offset <= remaining_text_start_offset_) | |
| 1268 return text_start_offset; | |
| 1269 int adjusted_offset = | |
| 1270 std::max(text_start_offset, remaining_text_start_offset_); | |
| 1271 remaining_text_start_offset_ = kInvalidTextOffset; | |
| 1272 return adjusted_offset; | |
| 1273 } | |
| 1274 | |
| 1275 template <typename Strategy> | |
| 1276 void TextIteratorAlgorithm<Strategy>::EmitText(Node* text_node, | 1193 void TextIteratorAlgorithm<Strategy>::EmitText(Node* text_node, |
| 1277 LayoutText* layout_object, | 1194 LayoutText* layout_object, |
| 1278 int text_start_offset, | 1195 int text_start_offset, |
| 1279 int text_end_offset) { | 1196 int text_end_offset) { |
| 1280 text_start_offset = AdjustedStartForFirstLetter( | |
| 1281 *text_node, *layout_object, text_start_offset, text_end_offset); | |
| 1282 text_start_offset = AdjustedStartForRemainingText( | |
| 1283 *text_node, *layout_object, text_start_offset, text_end_offset); | |
| 1284 // Since m_lastTextNodeEndedWithCollapsedSpace seems better placed in | 1197 // Since m_lastTextNodeEndedWithCollapsedSpace seems better placed in |
| 1285 // TextIterator, but is always reset when we call spliceBuffer, we | 1198 // TextIterator, but is always reset when we call spliceBuffer, we |
| 1286 // wrap TextIteratorTextState::spliceBuffer() with this function. | 1199 // wrap TextIteratorTextState::spliceBuffer() with this function. |
| 1287 text_state_.EmitText(text_node, layout_object, text_start_offset, | 1200 text_state_.EmitText(text_node, layout_object, text_start_offset, |
| 1288 text_end_offset); | 1201 text_end_offset); |
| 1289 last_text_node_ended_with_collapsed_space_ = false; | 1202 last_text_node_ended_with_collapsed_space_ = false; |
| 1290 } | 1203 } |
| 1291 | 1204 |
| 1292 template <typename Strategy> | 1205 template <typename Strategy> |
| 1293 EphemeralRangeTemplate<Strategy> TextIteratorAlgorithm<Strategy>::Range() | 1206 EphemeralRangeTemplate<Strategy> TextIteratorAlgorithm<Strategy>::Range() |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1467 String PlainText(const EphemeralRangeInFlatTree& range, | 1380 String PlainText(const EphemeralRangeInFlatTree& range, |
| 1468 const TextIteratorBehavior& behavior) { | 1381 const TextIteratorBehavior& behavior) { |
| 1469 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); | 1382 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); |
| 1470 } | 1383 } |
| 1471 | 1384 |
| 1472 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; | 1385 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; |
| 1473 template class CORE_TEMPLATE_EXPORT | 1386 template class CORE_TEMPLATE_EXPORT |
| 1474 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; | 1387 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; |
| 1475 | 1388 |
| 1476 } // namespace blink | 1389 } // namespace blink |
| OLD | NEW |