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 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 TextNodeContentExtractor::TextNodeContentExtractor( | |
| 156 const TextIteratorBehavior& behavior, | |
| 157 TextIteratorTextState& text_state) | |
| 158 : start_offset_(0), | |
|
yosin_UTC9
2017/05/25 06:44:09
Initialization of member variables should be done
| |
| 159 end_offset_(0), | |
| 160 offset_(0), | |
| 161 text_box_(nullptr), | |
| 162 needs_handle_pre_formatted_text_node_(false), | |
| 163 handled_first_letter_(false), | |
| 164 remaining_text_box_(nullptr), | |
| 165 first_letter_text_(nullptr), | |
| 166 last_text_node_ended_with_collapsed_space_(false), | |
| 167 sorted_text_boxes_position_(0), | |
| 168 behavior_(behavior), | |
| 169 text_state_(text_state) {} | |
| 170 | |
| 155 template <typename Strategy> | 171 template <typename Strategy> |
| 156 TextIteratorAlgorithm<Strategy>::TextIteratorAlgorithm( | 172 TextIteratorAlgorithm<Strategy>::TextIteratorAlgorithm( |
| 157 const PositionTemplate<Strategy>& start, | 173 const PositionTemplate<Strategy>& start, |
| 158 const PositionTemplate<Strategy>& end, | 174 const PositionTemplate<Strategy>& end, |
| 159 const TextIteratorBehavior& behavior) | 175 const TextIteratorBehavior& behavior) |
| 160 : offset_(0), | 176 : start_container_(nullptr), |
| 161 start_container_(nullptr), | |
| 162 start_offset_(0), | 177 start_offset_(0), |
| 163 end_container_(nullptr), | 178 end_container_(nullptr), |
| 164 end_offset_(0), | 179 end_offset_(0), |
| 165 needs_another_newline_(false), | 180 needs_another_newline_(false), |
| 166 text_box_(nullptr), | |
| 167 remaining_text_box_(nullptr), | |
| 168 first_letter_text_(nullptr), | |
| 169 last_text_node_(nullptr), | 181 last_text_node_(nullptr), |
| 170 last_text_node_ended_with_collapsed_space_(false), | |
| 171 sorted_text_boxes_position_(0), | |
| 172 behavior_(AdjustBehaviorFlags<Strategy>(behavior)), | 182 behavior_(AdjustBehaviorFlags<Strategy>(behavior)), |
| 173 needs_handle_pre_formatted_text_node_(false), | |
| 174 handled_first_letter_(false), | |
| 175 should_stop_(false), | 183 should_stop_(false), |
| 176 handle_shadow_root_(false), | 184 handle_shadow_root_(false), |
| 177 text_state_(behavior_) { | 185 text_state_(behavior_), |
| 186 text_extractor_(behavior_, text_state_) { | |
| 178 DCHECK(start.IsNotNull()); | 187 DCHECK(start.IsNotNull()); |
| 179 DCHECK(end.IsNotNull()); | 188 DCHECK(end.IsNotNull()); |
| 180 | 189 |
| 181 // TODO(dglazkov): TextIterator should not be created for documents that don't | 190 // 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 | 191 // have a frame, but it currently still happens in some cases. See |
| 183 // http://crbug.com/591877 for details. | 192 // http://crbug.com/591877 for details. |
| 184 DCHECK(!start.GetDocument()->View() || | 193 DCHECK(!start.GetDocument()->View() || |
| 185 !start.GetDocument()->View()->NeedsLayout()); | 194 !start.GetDocument()->View()->NeedsLayout()); |
| 186 DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate()); | 195 DCHECK(!start.GetDocument()->NeedsLayoutTreeUpdate()); |
| 187 | 196 |
| 188 if (start.CompareTo(end) > 0) { | 197 if (start.CompareTo(end) > 0) { |
| 189 Initialize(end.ComputeContainerNode(), end.ComputeOffsetInContainerNode(), | 198 Initialize(end.ComputeContainerNode(), end.ComputeOffsetInContainerNode(), |
| 190 start.ComputeContainerNode(), | 199 start.ComputeContainerNode(), |
| 191 start.ComputeOffsetInContainerNode()); | 200 start.ComputeOffsetInContainerNode()); |
| 192 return; | 201 return; |
| 193 } | 202 } |
| 194 Initialize(start.ComputeContainerNode(), start.ComputeOffsetInContainerNode(), | 203 Initialize(start.ComputeContainerNode(), start.ComputeOffsetInContainerNode(), |
| 195 end.ComputeContainerNode(), end.ComputeOffsetInContainerNode()); | 204 end.ComputeContainerNode(), end.ComputeOffsetInContainerNode()); |
| 196 } | 205 } |
| 197 | 206 |
| 207 void TextNodeContentExtractor::SetBoundaries(Node* start_container, | |
| 208 int start_offset, | |
| 209 Node* end_container, | |
| 210 int end_offset) { | |
| 211 start_container_ = start_container; | |
| 212 start_offset_ = start_offset; | |
| 213 end_container_ = end_container; | |
| 214 end_offset_ = end_offset; | |
| 215 } | |
| 216 | |
| 198 template <typename Strategy> | 217 template <typename Strategy> |
| 199 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container, | 218 void TextIteratorAlgorithm<Strategy>::Initialize(Node* start_container, |
| 200 int start_offset, | 219 int start_offset, |
| 201 Node* end_container, | 220 Node* end_container, |
| 202 int end_offset) { | 221 int end_offset) { |
| 203 DCHECK(start_container); | 222 DCHECK(start_container); |
| 204 DCHECK(end_container); | 223 DCHECK(end_container); |
| 205 | 224 |
| 225 text_extractor_.SetBoundaries(start_container, start_offset, end_container, | |
| 226 end_offset); | |
| 227 | |
| 206 // Remember the range - this does not change. | 228 // Remember the range - this does not change. |
| 207 start_container_ = start_container; | 229 start_container_ = start_container; |
| 208 start_offset_ = start_offset; | 230 start_offset_ = start_offset; |
| 209 end_container_ = end_container; | 231 end_container_ = end_container; |
| 210 end_offset_ = end_offset; | 232 end_offset_ = end_offset; |
| 211 end_node_ = | 233 end_node_ = |
| 212 end_container && !end_container->IsCharacterDataNode() && end_offset > 0 | 234 end_container && !end_container->IsCharacterDataNode() && end_offset > 0 |
| 213 ? Strategy::ChildAt(*end_container, end_offset - 1) | 235 ? Strategy::ChildAt(*end_container, end_offset - 1) |
| 214 : nullptr; | 236 : nullptr; |
| 215 | 237 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 257 | 279 |
| 258 template <typename Strategy> | 280 template <typename Strategy> |
| 259 bool TextIteratorAlgorithm<Strategy>::IsInsideAtomicInlineElement() const { | 281 bool TextIteratorAlgorithm<Strategy>::IsInsideAtomicInlineElement() const { |
| 260 if (AtEnd() || length() != 1 || !node_) | 282 if (AtEnd() || length() != 1 || !node_) |
| 261 return false; | 283 return false; |
| 262 | 284 |
| 263 LayoutObject* layout_object = node_->GetLayoutObject(); | 285 LayoutObject* layout_object = node_->GetLayoutObject(); |
| 264 return layout_object && layout_object->IsAtomicInlineLevel(); | 286 return layout_object && layout_object->IsAtomicInlineLevel(); |
| 265 } | 287 } |
| 266 | 288 |
| 267 template <typename Strategy> | 289 bool TextNodeContentExtractor::HandleRemainingTextRuns() { |
| 268 bool TextIteratorAlgorithm<Strategy>::HandleRemainingTextRuns() { | |
| 269 if (ShouldProceedToRemainingText()) | 290 if (ShouldProceedToRemainingText()) |
| 270 ProceedToRemainingText(); | 291 ProceedToRemainingText(); |
| 271 // handle remembered text box | 292 // handle remembered text box |
| 272 if (text_box_) { | 293 if (text_box_) { |
| 273 HandleTextBox(); | 294 HandleTextBox(); |
| 274 return text_state_.PositionNode(); | 295 return text_state_.PositionNode(); |
| 275 } | 296 } |
| 276 if (needs_handle_pre_formatted_text_node_) { | 297 if (needs_handle_pre_formatted_text_node_) { |
| 277 HandlePreFormattedTextNode(); | 298 HandlePreFormattedTextNode(); |
| 278 return text_state_.PositionNode(); | 299 return text_state_.PositionNode(); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 300 // line break begins. | 321 // line break begins. |
| 301 // FIXME: It would be cleaner if we emitted two newlines during the last | 322 // FIXME: It would be cleaner if we emitted two newlines during the last |
| 302 // iteration, instead of using m_needsAnotherNewline. | 323 // iteration, instead of using m_needsAnotherNewline. |
| 303 Node* last_child = Strategy::LastChild(*node_); | 324 Node* last_child = Strategy::LastChild(*node_); |
| 304 Node* base_node = last_child ? last_child : node_.Get(); | 325 Node* base_node = last_child ? last_child : node_.Get(); |
| 305 SpliceBuffer('\n', Strategy::Parent(*base_node), base_node, 1, 1); | 326 SpliceBuffer('\n', Strategy::Parent(*base_node), base_node, 1, 1); |
| 306 needs_another_newline_ = false; | 327 needs_another_newline_ = false; |
| 307 return; | 328 return; |
| 308 } | 329 } |
| 309 | 330 |
| 310 if (HandleRemainingTextRuns()) | 331 if (text_extractor_.HandleRemainingTextRuns()) |
| 311 return; | 332 return; |
| 312 | 333 |
| 313 while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) { | 334 while (node_ && (node_ != past_end_node_ || shadow_depth_ > 0)) { |
| 314 if (!should_stop_ && StopsOnFormControls() && | 335 if (!should_stop_ && StopsOnFormControls() && |
| 315 HTMLFormControlElement::EnclosingFormControlElement(node_)) | 336 HTMLFormControlElement::EnclosingFormControlElement(node_)) |
| 316 should_stop_ = true; | 337 should_stop_ = true; |
| 317 | 338 |
| 318 // if the range ends at offset 0 of an element, represent the | 339 // 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 | 340 // position, but not the content, of that element e.g. if the |
| 320 // node is a blockflow element, emit a newline that | 341 // 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; | 525 return false; |
| 505 | 526 |
| 506 DCHECK(fragment->GetFirstLetterPseudoElement()); | 527 DCHECK(fragment->GetFirstLetterPseudoElement()); |
| 507 LayoutObject* pseudo_element_layout_object = | 528 LayoutObject* pseudo_element_layout_object = |
| 508 fragment->GetFirstLetterPseudoElement()->GetLayoutObject(); | 529 fragment->GetFirstLetterPseudoElement()->GetLayoutObject(); |
| 509 return pseudo_element_layout_object && | 530 return pseudo_element_layout_object && |
| 510 pseudo_element_layout_object->Style()->Visibility() == | 531 pseudo_element_layout_object->Style()->Visibility() == |
| 511 EVisibility::kVisible; | 532 EVisibility::kVisible; |
| 512 } | 533 } |
| 513 | 534 |
| 514 template <typename Strategy> | 535 bool TextNodeContentExtractor::ShouldHandleFirstLetter( |
| 515 bool TextIteratorAlgorithm<Strategy>::ShouldHandleFirstLetter( | |
| 516 const LayoutText& layout_text) const { | 536 const LayoutText& layout_text) const { |
| 517 if (handled_first_letter_) | 537 if (handled_first_letter_) |
| 518 return false; | 538 return false; |
| 519 if (!layout_text.IsTextFragment()) | 539 if (!layout_text.IsTextFragment()) |
| 520 return false; | 540 return false; |
| 521 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text); | 541 const LayoutTextFragment& text_fragment = ToLayoutTextFragment(layout_text); |
| 522 return offset_ < static_cast<int>(text_fragment.TextStartOffset()); | 542 return offset_ < static_cast<int>(text_fragment.TextStartOffset()); |
| 523 } | 543 } |
| 524 | 544 |
| 525 template <typename Strategy> | 545 void TextNodeContentExtractor::HandlePreFormattedTextNode() { |
| 526 void TextIteratorAlgorithm<Strategy>::HandlePreFormattedTextNode() { | |
| 527 // TODO(xiaochengh): Get rid of repeated computation of these fields. | 546 // TODO(xiaochengh): Get rid of repeated computation of these fields. |
| 528 LayoutText* const layout_object = text_node_->GetLayoutObject(); | 547 LayoutText* const layout_object = text_node_->GetLayoutObject(); |
| 529 const String str = layout_object->GetText(); | 548 const String str = layout_object->GetText(); |
| 530 | 549 |
| 531 needs_handle_pre_formatted_text_node_ = false; | 550 needs_handle_pre_formatted_text_node_ = false; |
| 532 | 551 |
| 533 if (last_text_node_ended_with_collapsed_space_) { | 552 if (last_text_node_ended_with_collapsed_space_) { |
| 534 last_text_node_ended_with_collapsed_space_ = false; | 553 last_text_node_ended_with_collapsed_space_ = false; |
| 535 if (HasVisibleTextNode(layout_object)) { | 554 if (HasVisibleTextNode(layout_object)) { |
| 536 if (!behavior_.CollapseTrailingSpace() || | 555 if (!behavior_.CollapseTrailingSpace() || |
| 537 (offset_ > 0 && str[offset_ - 1] == ' ')) { | 556 (offset_ > 0 && str[offset_ - 1] == ' ')) { |
| 538 SpliceBuffer(kSpaceCharacter, text_node_, 0, offset_, offset_); | 557 text_state_.SpliceBuffer(kSpaceCharacter, text_node_, 0, offset_, |
| 558 offset_); | |
| 539 needs_handle_pre_formatted_text_node_ = true; | 559 needs_handle_pre_formatted_text_node_ = true; |
| 540 return; | 560 return; |
| 541 } | 561 } |
| 542 } | 562 } |
| 543 } | 563 } |
| 544 if (ShouldHandleFirstLetter(*layout_object)) { | 564 if (ShouldHandleFirstLetter(*layout_object)) { |
| 545 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); | 565 HandleTextNodeFirstLetter(ToLayoutTextFragment(layout_object)); |
| 546 if (first_letter_text_) { | 566 if (first_letter_text_) { |
| 547 const String first_letter = first_letter_text_->GetText(); | 567 const String first_letter = first_letter_text_->GetText(); |
| 548 const unsigned run_start = offset_; | 568 const unsigned run_start = offset_; |
| 549 const bool stops_in_first_letter = | 569 const bool stops_in_first_letter = |
| 550 text_node_ == end_container_ && | 570 text_node_ == end_container_ && |
| 551 end_offset_ <= static_cast<int>(first_letter.length()); | 571 end_offset_ <= static_cast<int>(first_letter.length()); |
| 552 const unsigned run_end = | 572 const unsigned run_end = |
| 553 stops_in_first_letter ? end_offset_ : first_letter.length(); | 573 stops_in_first_letter ? end_offset_ : first_letter.length(); |
| 554 EmitText(text_node_, first_letter_text_, run_start, run_end); | 574 text_state_.EmitText(text_node_, first_letter_text_, run_start, run_end); |
| 555 first_letter_text_ = nullptr; | 575 first_letter_text_ = nullptr; |
| 556 text_box_ = 0; | 576 text_box_ = 0; |
| 557 offset_ = run_end; | 577 offset_ = run_end; |
| 558 if (!stops_in_first_letter) | 578 if (!stops_in_first_letter) |
| 559 needs_handle_pre_formatted_text_node_ = true; | 579 needs_handle_pre_formatted_text_node_ = true; |
| 560 return; | 580 return; |
| 561 } | 581 } |
| 562 // We are here only if the DOM and/or layout trees are broken. | 582 // We are here only if the DOM and/or layout trees are broken. |
| 563 // For robustness, we should stop processing this node. | 583 // For robustness, we should stop processing this node. |
| 564 NOTREACHED(); | 584 NOTREACHED(); |
| 565 return; | 585 return; |
| 566 } | 586 } |
| 567 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 587 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
| 568 !IgnoresStyleVisibility()) | 588 !IgnoresStyleVisibility()) |
| 569 return; | 589 return; |
| 570 DCHECK_GE(static_cast<unsigned>(offset_), layout_object->TextStartOffset()); | 590 DCHECK_GE(static_cast<unsigned>(offset_), layout_object->TextStartOffset()); |
| 571 const unsigned run_start = offset_ - layout_object->TextStartOffset(); | 591 const unsigned run_start = offset_ - layout_object->TextStartOffset(); |
| 572 const unsigned str_length = str.length(); | 592 const unsigned str_length = str.length(); |
| 573 const unsigned end = (text_node_ == end_container_) | 593 const unsigned end = (text_node_ == end_container_) |
| 574 ? end_offset_ - layout_object->TextStartOffset() | 594 ? end_offset_ - layout_object->TextStartOffset() |
| 575 : str_length; | 595 : str_length; |
| 576 const unsigned run_end = std::min(str_length, end); | 596 const unsigned run_end = std::min(str_length, end); |
| 577 | 597 |
| 578 if (run_start >= run_end) | 598 if (run_start >= run_end) |
| 579 return; | 599 return; |
| 580 | 600 |
| 581 EmitText(text_node_, text_node_->GetLayoutObject(), run_start, run_end); | 601 text_state_.EmitText(text_node_, text_node_->GetLayoutObject(), run_start, |
| 602 run_end); | |
| 582 } | 603 } |
| 583 | 604 |
| 584 template <typename Strategy> | 605 template <typename Strategy> |
| 585 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() { | 606 bool TextIteratorAlgorithm<Strategy>::HandleTextNode() { |
| 586 if (ExcludesAutofilledValue()) { | 607 if (ExcludesAutofilledValue()) { |
| 587 TextControlElement* control = EnclosingTextControl(node_); | 608 TextControlElement* control = EnclosingTextControl(node_); |
| 588 // For security reason, we don't expose suggested value if it is | 609 // For security reason, we don't expose suggested value if it is |
| 589 // auto-filled. | 610 // auto-filled. |
| 590 if (control && control->IsAutofilled()) | 611 if (control && control->IsAutofilled()) |
| 591 return true; | 612 return true; |
| 592 } | 613 } |
| 593 | 614 |
| 594 DCHECK_NE(last_text_node_, node_) | 615 DCHECK_NE(last_text_node_, node_) |
| 595 << "We should never call HandleTextNode on the same node twice"; | 616 << "We should never call HandleTextNode on the same node twice"; |
| 596 last_text_node_ = ToText(node_); | 617 last_text_node_ = ToText(node_); |
| 618 return text_extractor_.HandleTextNode(ToText(node_)); | |
| 619 } | |
| 597 | 620 |
| 598 text_node_ = ToText(node_); | 621 bool TextNodeContentExtractor::HandleTextNode(Text* node) { |
| 622 text_node_ = node; | |
| 599 offset_ = text_node_ == start_container_ ? start_offset_ : 0; | 623 offset_ = text_node_ == start_container_ ? start_offset_ : 0; |
| 600 handled_first_letter_ = false; | 624 handled_first_letter_ = false; |
| 601 first_letter_text_ = nullptr; | 625 first_letter_text_ = nullptr; |
| 602 | 626 |
| 603 LayoutText* layout_object = text_node_->GetLayoutObject(); | 627 LayoutText* layout_object = text_node_->GetLayoutObject(); |
| 604 String str = layout_object->GetText(); | 628 String str = layout_object->GetText(); |
| 605 | 629 |
| 606 // handle pre-formatted text | 630 // handle pre-formatted text |
| 607 if (!layout_object->Style()->CollapseWhiteSpace()) { | 631 if (!layout_object->Style()->CollapseWhiteSpace()) { |
| 608 HandlePreFormattedTextNode(); | 632 HandlePreFormattedTextNode(); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 641 InlineTextBox::CompareByStart); | 665 InlineTextBox::CompareByStart); |
| 642 sorted_text_boxes_position_ = 0; | 666 sorted_text_boxes_position_ = 0; |
| 643 text_box_ = sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]; | 667 text_box_ = sorted_text_boxes_.IsEmpty() ? 0 : sorted_text_boxes_[0]; |
| 644 } | 668 } |
| 645 | 669 |
| 646 HandleTextBox(); | 670 HandleTextBox(); |
| 647 return true; | 671 return true; |
| 648 } | 672 } |
| 649 | 673 |
| 650 // Restore the collapsed space for copy & paste. See http://crbug.com/318925 | 674 // Restore the collapsed space for copy & paste. See http://crbug.com/318925 |
| 651 template <typename Strategy> | 675 size_t TextNodeContentExtractor::RestoreCollapsedTrailingSpace( |
| 652 size_t TextIteratorAlgorithm<Strategy>::RestoreCollapsedTrailingSpace( | |
| 653 InlineTextBox* next_text_box, | 676 InlineTextBox* next_text_box, |
| 654 size_t subrun_end) { | 677 size_t subrun_end) { |
| 655 if (next_text_box || !text_box_->Root().NextRootBox() || | 678 if (next_text_box || !text_box_->Root().NextRootBox() || |
| 656 text_box_->Root().LastChild() != text_box_) | 679 text_box_->Root().LastChild() != text_box_) |
| 657 return subrun_end; | 680 return subrun_end; |
| 658 | 681 |
| 659 const String& text = text_node_->GetLayoutObject()->GetText(); | 682 const String& text = text_node_->GetLayoutObject()->GetText(); |
| 660 if (text.EndsWith(' ') == 0 || subrun_end != text.length() - 1 || | 683 if (text.EndsWith(' ') == 0 || subrun_end != text.length() - 1 || |
| 661 text[subrun_end - 1] == ' ') | 684 text[subrun_end - 1] == ' ') |
| 662 return subrun_end; | 685 return subrun_end; |
| 663 | 686 |
| 664 // If there is the leading space in the next line, we don't need to restore | 687 // If there is the leading space in the next line, we don't need to restore |
| 665 // the trailing space. | 688 // the trailing space. |
| 666 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div> | 689 // Example: <div style="width: 2em;"><b><i>foo </i></b> bar</div> |
| 667 InlineBox* first_box_of_next_line = | 690 InlineBox* first_box_of_next_line = |
| 668 text_box_->Root().NextRootBox()->FirstChild(); | 691 text_box_->Root().NextRootBox()->FirstChild(); |
| 669 if (!first_box_of_next_line) | 692 if (!first_box_of_next_line) |
| 670 return subrun_end + 1; | 693 return subrun_end + 1; |
| 671 Node* first_node_of_next_line = | 694 Node* first_node_of_next_line = |
| 672 first_box_of_next_line->GetLineLayoutItem().GetNode(); | 695 first_box_of_next_line->GetLineLayoutItem().GetNode(); |
| 673 if (!first_node_of_next_line || | 696 if (!first_node_of_next_line || |
| 674 first_node_of_next_line->nodeValue()[0] != ' ') | 697 first_node_of_next_line->nodeValue()[0] != ' ') |
| 675 return subrun_end + 1; | 698 return subrun_end + 1; |
| 676 | 699 |
| 677 return subrun_end; | 700 return subrun_end; |
| 678 } | 701 } |
| 679 | 702 |
| 680 template <typename Strategy> | 703 void TextNodeContentExtractor::HandleTextBox() { |
| 681 void TextIteratorAlgorithm<Strategy>::HandleTextBox() { | |
| 682 LayoutText* layout_object = | 704 LayoutText* layout_object = |
| 683 first_letter_text_ ? first_letter_text_ : text_node_->GetLayoutObject(); | 705 first_letter_text_ ? first_letter_text_ : text_node_->GetLayoutObject(); |
| 684 const unsigned text_start_offset = layout_object->TextStartOffset(); | 706 const unsigned text_start_offset = layout_object->TextStartOffset(); |
| 685 | 707 |
| 686 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 708 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
| 687 !IgnoresStyleVisibility()) { | 709 !IgnoresStyleVisibility()) { |
| 688 text_box_ = nullptr; | 710 text_box_ = nullptr; |
| 689 } else { | 711 } else { |
| 690 String str = layout_object->GetText(); | 712 String str = layout_object->GetText(); |
| 691 // Start and end offsets in |str|, i.e., str[start..end - 1] should be | 713 // Start and end offsets in |str|, i.e., str[start..end - 1] should be |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 709 text_box_start == run_start && run_start > 0); | 731 text_box_start == run_start && run_start > 0); |
| 710 last_text_node_ended_with_collapsed_space_ = false; | 732 last_text_node_ended_with_collapsed_space_ = false; |
| 711 if (need_space && | 733 if (need_space && |
| 712 !layout_object->Style()->IsCollapsibleWhiteSpace( | 734 !layout_object->Style()->IsCollapsibleWhiteSpace( |
| 713 text_state_.LastCharacter()) && | 735 text_state_.LastCharacter()) && |
| 714 text_state_.LastCharacter()) { | 736 text_state_.LastCharacter()) { |
| 715 if (run_start > 0 && str[run_start - 1] == ' ') { | 737 if (run_start > 0 && str[run_start - 1] == ' ') { |
| 716 unsigned space_run_start = run_start - 1; | 738 unsigned space_run_start = run_start - 1; |
| 717 while (space_run_start > 0 && str[space_run_start - 1] == ' ') | 739 while (space_run_start > 0 && str[space_run_start - 1] == ' ') |
| 718 --space_run_start; | 740 --space_run_start; |
| 719 EmitText(text_node_, layout_object, space_run_start, | 741 text_state_.EmitText(text_node_, layout_object, space_run_start, |
|
yosin_UTC9
2017/05/25 06:44:09
Let's introduce TextNodeContentExtract::EmitText()
Xiaocheng
2017/05/25 23:47:58
Done.
| |
| 720 space_run_start + 1); | 742 space_run_start + 1); |
| 721 } else { | 743 } else { |
| 722 SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start, run_start); | 744 text_state_.SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start, |
|
yosin_UTC9
2017/05/25 06:44:09
Let's introduce TextNodeContentExtract::SpliceBuff
Xiaocheng
2017/05/25 23:47:58
Done.
| |
| 745 run_start); | |
| 723 } | 746 } |
| 724 return; | 747 return; |
| 725 } | 748 } |
| 726 const unsigned text_box_end = text_box_start + text_box_->Len(); | 749 const unsigned text_box_end = text_box_start + text_box_->Len(); |
| 727 const unsigned run_end = std::min(text_box_end, end); | 750 const unsigned run_end = std::min(text_box_end, end); |
| 728 | 751 |
| 729 // Determine what the next text box will be, but don't advance yet | 752 // Determine what the next text box will be, but don't advance yet |
| 730 InlineTextBox* next_text_box = nullptr; | 753 InlineTextBox* next_text_box = nullptr; |
| 731 if (layout_object->ContainsReversedText()) { | 754 if (layout_object->ContainsReversedText()) { |
| 732 if (sorted_text_boxes_position_ + 1 < sorted_text_boxes_.size()) | 755 if (sorted_text_boxes_position_ + 1 < sorted_text_boxes_.size()) |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 750 | 773 |
| 751 if (run_start < run_end) { | 774 if (run_start < run_end) { |
| 752 // Handle either a single newline character (which becomes a space), | 775 // Handle either a single newline character (which becomes a space), |
| 753 // or a run of characters that does not include a newline. | 776 // or a run of characters that does not include a newline. |
| 754 // This effectively translates newlines to spaces without copying the | 777 // This effectively translates newlines to spaces without copying the |
| 755 // text. | 778 // text. |
| 756 if (str[run_start] == '\n') { | 779 if (str[run_start] == '\n') { |
| 757 // We need to preserve new lines in case of PreLine. | 780 // We need to preserve new lines in case of PreLine. |
| 758 // See bug crbug.com/317365. | 781 // See bug crbug.com/317365. |
| 759 if (layout_object->Style()->WhiteSpace() == EWhiteSpace::kPreLine) { | 782 if (layout_object->Style()->WhiteSpace() == EWhiteSpace::kPreLine) { |
| 760 SpliceBuffer('\n', text_node_, 0, run_start, run_start); | 783 text_state_.SpliceBuffer('\n', text_node_, 0, run_start, run_start); |
| 761 } else { | 784 } else { |
| 762 SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start, | 785 text_state_.SpliceBuffer(kSpaceCharacter, text_node_, 0, run_start, |
| 763 run_start + 1); | 786 run_start + 1); |
| 764 } | 787 } |
| 765 offset_ = text_start_offset + run_start + 1; | 788 offset_ = text_start_offset + run_start + 1; |
| 766 } else { | 789 } else { |
| 767 size_t subrun_end = str.find('\n', run_start); | 790 size_t subrun_end = str.find('\n', run_start); |
| 768 if (subrun_end == kNotFound || subrun_end > run_end) { | 791 if (subrun_end == kNotFound || subrun_end > run_end) { |
| 769 subrun_end = run_end; | 792 subrun_end = run_end; |
| 770 subrun_end = | 793 subrun_end = |
| 771 RestoreCollapsedTrailingSpace(next_text_box, subrun_end); | 794 RestoreCollapsedTrailingSpace(next_text_box, subrun_end); |
| 772 } | 795 } |
| 773 | 796 |
| 774 offset_ = text_start_offset + subrun_end; | 797 offset_ = text_start_offset + subrun_end; |
| 775 EmitText(text_node_, layout_object, run_start, subrun_end); | 798 text_state_.EmitText(text_node_, layout_object, run_start, |
| 799 subrun_end); | |
| 776 } | 800 } |
| 777 | 801 |
| 778 // If we are doing a subrun that doesn't go to the end of the text box, | 802 // If we are doing a subrun that doesn't go to the end of the text box, |
| 779 // come back again to finish handling this text box; don't advance to | 803 // come back again to finish handling this text box; don't advance to |
| 780 // the next one. | 804 // the next one. |
| 781 if (static_cast<unsigned>(text_state_.PositionEndOffset()) < | 805 if (static_cast<unsigned>(text_state_.PositionEndOffset()) < |
| 782 text_box_end) | 806 text_box_end) |
| 783 return; | 807 return; |
| 784 | 808 |
| 785 if (behavior_.DoesNotEmitSpaceBeyondRangeEnd()) { | 809 if (behavior_.DoesNotEmitSpaceBeyondRangeEnd()) { |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 810 ++sorted_text_boxes_position_; | 834 ++sorted_text_boxes_position_; |
| 811 } | 835 } |
| 812 } | 836 } |
| 813 | 837 |
| 814 if (ShouldProceedToRemainingText()) { | 838 if (ShouldProceedToRemainingText()) { |
| 815 ProceedToRemainingText(); | 839 ProceedToRemainingText(); |
| 816 HandleTextBox(); | 840 HandleTextBox(); |
| 817 } | 841 } |
| 818 } | 842 } |
| 819 | 843 |
| 820 template <typename Strategy> | 844 bool TextNodeContentExtractor::ShouldProceedToRemainingText() const { |
| 821 bool TextIteratorAlgorithm<Strategy>::ShouldProceedToRemainingText() const { | |
| 822 if (text_box_ || !remaining_text_box_) | 845 if (text_box_ || !remaining_text_box_) |
| 823 return false; | 846 return false; |
| 824 if (text_node_ != end_container_) | 847 if (text_node_ != end_container_) |
| 825 return true; | 848 return true; |
| 826 return offset_ < end_offset_; | 849 return offset_ < end_offset_; |
| 827 } | 850 } |
| 828 | 851 |
| 829 template <typename Strategy> | 852 void TextNodeContentExtractor::ProceedToRemainingText() { |
| 830 void TextIteratorAlgorithm<Strategy>::ProceedToRemainingText() { | |
| 831 text_box_ = remaining_text_box_; | 853 text_box_ = remaining_text_box_; |
| 832 remaining_text_box_ = 0; | 854 remaining_text_box_ = 0; |
| 833 first_letter_text_ = nullptr; | 855 first_letter_text_ = nullptr; |
| 834 offset_ = text_node_->GetLayoutObject()->TextStartOffset(); | 856 offset_ = text_node_->GetLayoutObject()->TextStartOffset(); |
| 835 } | 857 } |
| 836 | 858 |
| 837 template <typename Strategy> | 859 void TextNodeContentExtractor::HandleTextNodeFirstLetter( |
| 838 void TextIteratorAlgorithm<Strategy>::HandleTextNodeFirstLetter( | |
| 839 LayoutTextFragment* layout_object) { | 860 LayoutTextFragment* layout_object) { |
| 840 handled_first_letter_ = true; | 861 handled_first_letter_ = true; |
| 841 | 862 |
| 842 if (!layout_object->IsRemainingTextLayoutObject()) | 863 if (!layout_object->IsRemainingTextLayoutObject()) |
| 843 return; | 864 return; |
| 844 | 865 |
| 845 FirstLetterPseudoElement* first_letter_element = | 866 FirstLetterPseudoElement* first_letter_element = |
| 846 layout_object->GetFirstLetterPseudoElement(); | 867 layout_object->GetFirstLetterPseudoElement(); |
| 847 if (!first_letter_element) | 868 if (!first_letter_element) |
| 848 return; | 869 return; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 869 | 890 |
| 870 // FIXME: Add isSVGImageElement. | 891 // FIXME: Add isSVGImageElement. |
| 871 if (isHTMLImageElement(element)) | 892 if (isHTMLImageElement(element)) |
| 872 return true; | 893 return true; |
| 873 if (isHTMLInputElement(ToHTMLElement(*node)) && | 894 if (isHTMLInputElement(ToHTMLElement(*node)) && |
| 874 toHTMLInputElement(*node).type() == InputTypeNames::image) | 895 toHTMLInputElement(*node).type() == InputTypeNames::image) |
| 875 return true; | 896 return true; |
| 876 return false; | 897 return false; |
| 877 } | 898 } |
| 878 | 899 |
| 879 template <typename Strategy> | 900 bool TextNodeContentExtractor::FixLeadingWhiteSpaceForReplacedElement( |
| 880 bool TextIteratorAlgorithm<Strategy>::FixLeadingWhiteSpaceForReplacedElement( | |
| 881 Node* parent) { | 901 Node* parent) { |
| 882 if (!last_text_node_ended_with_collapsed_space_) | 902 if (!last_text_node_ended_with_collapsed_space_) |
| 883 return false; | 903 return false; |
| 884 last_text_node_ended_with_collapsed_space_ = false; | 904 last_text_node_ended_with_collapsed_space_ = false; |
| 885 | 905 |
| 886 if (!behavior_.CollapseTrailingSpace()) { | 906 if (!behavior_.CollapseTrailingSpace()) { |
| 887 SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1); | 907 text_state_.SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1); |
| 888 return true; | 908 return true; |
| 889 } | 909 } |
| 890 if (text_node_) { | 910 if (text_node_) { |
| 891 const String str = text_node_->GetLayoutObject()->GetText(); | 911 const String str = text_node_->GetLayoutObject()->GetText(); |
| 892 if (offset_ > 0 && str[offset_ - 1] == ' ') { | 912 if (offset_ > 0 && str[offset_ - 1] == ' ') { |
| 893 SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1); | 913 text_state_.SpliceBuffer(kSpaceCharacter, parent, text_node_, 1, 1); |
| 894 return true; | 914 return true; |
| 895 } | 915 } |
| 896 } | 916 } |
| 897 | 917 |
| 898 return false; | 918 return false; |
| 899 } | 919 } |
| 900 | 920 |
| 901 template <typename Strategy> | 921 template <typename Strategy> |
| 902 bool TextIteratorAlgorithm<Strategy>::HandleReplacedElement() { | 922 bool TextIteratorAlgorithm<Strategy>::HandleReplacedElement() { |
| 903 if (fully_clipped_stack_.Top()) | 923 if (fully_clipped_stack_.Top()) |
| 904 return false; | 924 return false; |
| 905 | 925 |
| 906 LayoutObject* layout_object = node_->GetLayoutObject(); | 926 LayoutObject* layout_object = node_->GetLayoutObject(); |
| 907 if (layout_object->Style()->Visibility() != EVisibility::kVisible && | 927 if (layout_object->Style()->Visibility() != EVisibility::kVisible && |
| 908 !IgnoresStyleVisibility()) | 928 !IgnoresStyleVisibility()) |
| 909 return false; | 929 return false; |
| 910 | 930 |
| 911 if (EmitsObjectReplacementCharacter()) { | 931 if (EmitsObjectReplacementCharacter()) { |
| 912 SpliceBuffer(kObjectReplacementCharacter, Strategy::Parent(*node_), node_, | 932 SpliceBuffer(kObjectReplacementCharacter, Strategy::Parent(*node_), node_, |
| 913 0, 1); | 933 0, 1); |
| 914 return true; | 934 return true; |
| 915 } | 935 } |
| 916 | 936 |
| 917 if (last_text_node_) { | 937 if (last_text_node_) { |
| 918 if (FixLeadingWhiteSpaceForReplacedElement( | 938 if (text_extractor_.FixLeadingWhiteSpaceForReplacedElement( |
| 919 Strategy::Parent(*last_text_node_))) | 939 Strategy::Parent(*last_text_node_))) |
| 920 return false; | 940 return false; |
| 921 } | 941 } |
| 922 | 942 |
| 923 if (EntersTextControls() && layout_object->IsTextControl()) { | 943 if (EntersTextControls() && layout_object->IsTextControl()) { |
| 924 // The shadow tree should be already visited. | 944 // The shadow tree should be already visited. |
| 925 return true; | 945 return true; |
| 926 } | 946 } |
| 927 | 947 |
| 928 if (EmitsCharactersBetweenAllVisiblePositions()) { | 948 if (EmitsCharactersBetweenAllVisiblePositions()) { |
| (...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1420 String PlainText(const EphemeralRangeInFlatTree& range, | 1440 String PlainText(const EphemeralRangeInFlatTree& range, |
| 1421 const TextIteratorBehavior& behavior) { | 1441 const TextIteratorBehavior& behavior) { |
| 1422 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); | 1442 return CreatePlainText<EditingInFlatTreeStrategy>(range, behavior); |
| 1423 } | 1443 } |
| 1424 | 1444 |
| 1425 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; | 1445 template class CORE_TEMPLATE_EXPORT TextIteratorAlgorithm<EditingStrategy>; |
| 1426 template class CORE_TEMPLATE_EXPORT | 1446 template class CORE_TEMPLATE_EXPORT |
| 1427 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; | 1447 TextIteratorAlgorithm<EditingInFlatTreeStrategy>; |
| 1428 | 1448 |
| 1429 } // namespace blink | 1449 } // namespace blink |
| OLD | NEW |