Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All r ights reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All r ights reserved. |
| 3 * Copyright (C) 2005 Alexey Proskuryakov. | 3 * Copyright (C) 2005 Alexey Proskuryakov. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 */ | 25 */ |
| 26 | 26 |
| 27 #include "config.h" | 27 #include "config.h" |
| 28 #include "core/editing/TextIterator.h" | 28 #include "core/editing/TextIterator.h" |
| 29 | 29 |
| 30 #include "bindings/core/v8/ExceptionStatePlaceholder.h" | 30 #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
| 31 #include "core/HTMLNames.h" | 31 #include "core/HTMLNames.h" |
| 32 #include "core/dom/Document.h" | 32 #include "core/dom/Document.h" |
| 33 #include "core/dom/FirstLetterPseudoElement.h" | |
| 33 #include "core/dom/NodeTraversal.h" | 34 #include "core/dom/NodeTraversal.h" |
| 34 #include "core/dom/shadow/ShadowRoot.h" | 35 #include "core/dom/shadow/ShadowRoot.h" |
| 35 #include "core/editing/VisiblePosition.h" | 36 #include "core/editing/VisiblePosition.h" |
| 36 #include "core/editing/VisibleUnits.h" | 37 #include "core/editing/VisibleUnits.h" |
| 37 #include "core/editing/htmlediting.h" | 38 #include "core/editing/htmlediting.h" |
| 38 #include "core/frame/FrameView.h" | 39 #include "core/frame/FrameView.h" |
| 39 #include "core/html/HTMLElement.h" | 40 #include "core/html/HTMLElement.h" |
| 40 #include "core/html/HTMLTextFormControlElement.h" | 41 #include "core/html/HTMLTextFormControlElement.h" |
| 41 #include "core/rendering/InlineTextBox.h" | 42 #include "core/rendering/InlineTextBox.h" |
| 42 #include "core/rendering/RenderImage.h" | 43 #include "core/rendering/RenderImage.h" |
| (...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 671 m_textBox = m_sortedTextBoxes.isEmpty() ? 0 : m_sortedTextBoxes[0]; | 672 m_textBox = m_sortedTextBoxes.isEmpty() ? 0 : m_sortedTextBoxes[0]; |
| 672 } | 673 } |
| 673 | 674 |
| 674 handleTextBox(); | 675 handleTextBox(); |
| 675 return true; | 676 return true; |
| 676 } | 677 } |
| 677 | 678 |
| 678 void TextIterator::handleTextBox() | 679 void TextIterator::handleTextBox() |
| 679 { | 680 { |
| 680 RenderText* renderer = m_firstLetterText ? m_firstLetterText.get() : toRende rText(m_node->renderer()); | 681 RenderText* renderer = m_firstLetterText ? m_firstLetterText.get() : toRende rText(m_node->renderer()); |
| 682 | |
| 681 if (renderer->style()->visibility() != VISIBLE && !m_ignoresStyleVisibility) { | 683 if (renderer->style()->visibility() != VISIBLE && !m_ignoresStyleVisibility) { |
| 682 m_textBox = 0; | 684 m_textBox = 0; |
| 683 return; | 685 } else { |
| 684 } | 686 String str = renderer->text(); |
| 685 String str = renderer->text(); | 687 unsigned start = m_offset; |
| 686 unsigned start = m_offset; | 688 unsigned end = (m_node == m_endContainer) ? static_cast<unsigned>(m_endO ffset) : INT_MAX; |
| 687 unsigned end = (m_node == m_endContainer) ? static_cast<unsigned>(m_endOffse t) : INT_MAX; | 689 while (m_textBox) { |
| 688 while (m_textBox) { | 690 unsigned textBoxStart = m_textBox->start(); |
| 689 unsigned textBoxStart = m_textBox->start(); | 691 unsigned runStart = std::max(textBoxStart, start); |
| 690 unsigned runStart = std::max(textBoxStart, start); | |
| 691 | 692 |
| 692 // Check for collapsed space at the start of this run. | 693 // Check for collapsed space at the start of this run. |
| 693 InlineTextBox* firstTextBox = renderer->containsReversedText() ? (m_sort edTextBoxes.isEmpty() ? 0 : m_sortedTextBoxes[0]) : renderer->firstTextBox(); | 694 InlineTextBox* firstTextBox = renderer->containsReversedText() ? (m_ sortedTextBoxes.isEmpty() ? 0 : m_sortedTextBoxes[0]) : renderer->firstTextBox() ; |
| 694 bool needSpace = m_lastTextNodeEndedWithCollapsedSpace | 695 bool needSpace = m_lastTextNodeEndedWithCollapsedSpace |
| 695 || (m_textBox == firstTextBox && textBoxStart == runStart && runStar t > 0); | 696 || (m_textBox == firstTextBox && textBoxStart == runStart && run Start > 0); |
| 696 if (needSpace && !renderer->style()->isCollapsibleWhiteSpace(m_lastChara cter) && m_lastCharacter) { | 697 if (needSpace && !renderer->style()->isCollapsibleWhiteSpace(m_lastC haracter) && m_lastCharacter) { |
| 697 if (m_lastTextNode == m_node && runStart > 0 && str[runStart - 1] == ' ') { | 698 if (m_lastTextNode == m_node && runStart > 0 && str[runStart - 1 ] == ' ') { |
| 698 unsigned spaceRunStart = runStart - 1; | 699 unsigned spaceRunStart = runStart - 1; |
| 699 while (spaceRunStart > 0 && str[spaceRunStart - 1] == ' ') | 700 while (spaceRunStart > 0 && str[spaceRunStart - 1] == ' ') |
| 700 --spaceRunStart; | 701 --spaceRunStart; |
| 701 emitText(m_node, renderer, spaceRunStart, spaceRunStart + 1); | 702 emitText(m_node, renderer, spaceRunStart, spaceRunStart + 1) ; |
| 703 } else { | |
| 704 emitCharacter(space, m_node, 0, runStart, runStart); | |
| 705 } | |
| 706 return; | |
| 707 } | |
| 708 unsigned textBoxEnd = textBoxStart + m_textBox->len(); | |
| 709 unsigned runEnd = std::min(textBoxEnd, end); | |
| 710 | |
| 711 // Determine what the next text box will be, but don't advance yet | |
| 712 InlineTextBox* nextTextBox = nullptr; | |
| 713 if (renderer->containsReversedText()) { | |
| 714 if (m_sortedTextBoxesPosition + 1 < m_sortedTextBoxes.size()) | |
| 715 nextTextBox = m_sortedTextBoxes[m_sortedTextBoxesPosition + 1]; | |
| 702 } else { | 716 } else { |
| 703 emitCharacter(space, m_node, 0, runStart, runStart); | 717 nextTextBox = m_textBox->nextTextBox(); |
| 704 } | 718 } |
| 705 return; | 719 ASSERT(!nextTextBox || nextTextBox->renderer() == renderer); |
| 706 } | |
| 707 unsigned textBoxEnd = textBoxStart + m_textBox->len(); | |
| 708 unsigned runEnd = std::min(textBoxEnd, end); | |
| 709 | 720 |
| 710 // Determine what the next text box will be, but don't advance yet | 721 if (runStart < runEnd) { |
| 711 InlineTextBox* nextTextBox = nullptr; | 722 // Handle either a single newline character (which becomes a spa ce), |
| 712 if (renderer->containsReversedText()) { | 723 // or a run of characters that does not include a newline. |
| 713 if (m_sortedTextBoxesPosition + 1 < m_sortedTextBoxes.size()) | 724 // This effectively translates newlines to spaces without copyin g the text. |
| 714 nextTextBox = m_sortedTextBoxes[m_sortedTextBoxesPosition + 1]; | 725 if (str[runStart] == '\n') { |
| 715 } else { | 726 emitCharacter(space, m_node, 0, runStart, runStart + 1); |
| 716 nextTextBox = m_textBox->nextTextBox(); | 727 m_offset = runStart + 1; |
| 717 } | 728 } else { |
| 718 ASSERT(!nextTextBox || nextTextBox->renderer() == renderer); | 729 size_t subrunEnd = str.find('\n', runStart); |
| 730 if (subrunEnd == kNotFound || subrunEnd > runEnd) | |
| 731 subrunEnd = runEnd; | |
| 719 | 732 |
| 720 if (runStart < runEnd) { | 733 m_offset = subrunEnd; |
| 721 // Handle either a single newline character (which becomes a space), | 734 emitText(m_node, renderer, runStart, subrunEnd); |
| 722 // or a run of characters that does not include a newline. | 735 } |
| 723 // This effectively translates newlines to spaces without copying th e text. | |
| 724 if (str[runStart] == '\n') { | |
| 725 emitCharacter(space, m_node, 0, runStart, runStart + 1); | |
| 726 m_offset = runStart + 1; | |
| 727 } else { | |
| 728 size_t subrunEnd = str.find('\n', runStart); | |
| 729 if (subrunEnd == kNotFound || subrunEnd > runEnd) | |
| 730 subrunEnd = runEnd; | |
| 731 | 736 |
| 732 m_offset = subrunEnd; | 737 // If we are doing a subrun that doesn't go to the end of the te xt box, |
| 733 emitText(m_node, renderer, runStart, subrunEnd); | 738 // come back again to finish handling this text box; don't advan ce to the next one. |
| 739 if (static_cast<unsigned>(m_positionEndOffset) < textBoxEnd) | |
| 740 return; | |
| 741 | |
| 742 // Advance and return | |
| 743 unsigned nextRunStart = nextTextBox ? nextTextBox->start() : str .length(); | |
| 744 if (nextRunStart > runEnd) | |
| 745 m_lastTextNodeEndedWithCollapsedSpace = true; // collapsed s pace between runs or at the end | |
| 746 | |
| 747 m_textBox = nextTextBox; | |
| 748 if (renderer->containsReversedText()) | |
| 749 ++m_sortedTextBoxesPosition; | |
| 750 return; | |
| 734 } | 751 } |
| 735 | 752 // Advance and continue |
| 736 // If we are doing a subrun that doesn't go to the end of the text b ox, | |
| 737 // come back again to finish handling this text box; don't advance t o the next one. | |
| 738 if (static_cast<unsigned>(m_positionEndOffset) < textBoxEnd) | |
| 739 return; | |
| 740 | |
| 741 // Advance and return | |
| 742 unsigned nextRunStart = nextTextBox ? nextTextBox->start() : str.len gth(); | |
| 743 if (nextRunStart > runEnd) | |
| 744 m_lastTextNodeEndedWithCollapsedSpace = true; // collapsed space between runs or at the end | |
| 745 m_textBox = nextTextBox; | 753 m_textBox = nextTextBox; |
| 746 if (renderer->containsReversedText()) | 754 if (renderer->containsReversedText()) |
| 747 ++m_sortedTextBoxesPosition; | 755 ++m_sortedTextBoxesPosition; |
| 748 return; | |
| 749 } | 756 } |
| 750 // Advance and continue | |
| 751 m_textBox = nextTextBox; | |
| 752 if (renderer->containsReversedText()) | |
| 753 ++m_sortedTextBoxesPosition; | |
| 754 } | 757 } |
| 758 | |
| 755 if (!m_textBox && m_remainingTextBox) { | 759 if (!m_textBox && m_remainingTextBox) { |
| 756 m_textBox = m_remainingTextBox; | 760 m_textBox = m_remainingTextBox; |
| 757 m_remainingTextBox = 0; | 761 m_remainingTextBox = 0; |
| 758 m_firstLetterText = nullptr; | 762 m_firstLetterText = nullptr; |
| 759 m_offset = 0; | 763 m_offset = 0; |
| 760 handleTextBox(); | 764 handleTextBox(); |
| 761 } | 765 } |
| 762 } | 766 } |
| 763 | 767 |
| 764 static inline RenderText* firstRenderTextInFirstLetter(RenderBoxModelObject* fir stLetter) | |
| 765 { | |
| 766 if (!firstLetter) | |
| 767 return 0; | |
| 768 | |
| 769 // FIXME: Should this check descendent objects? | |
| 770 for (RenderObject* current = firstLetter->slowFirstChild(); current; current = current->nextSibling()) { | |
| 771 if (current->isText()) | |
| 772 return toRenderText(current); | |
| 773 } | |
| 774 return 0; | |
| 775 } | |
| 776 | |
| 777 void TextIterator::handleTextNodeFirstLetter(RenderTextFragment* renderer) | 768 void TextIterator::handleTextNodeFirstLetter(RenderTextFragment* renderer) |
| 778 { | 769 { |
| 779 if (renderer->firstLetter()) { | |
| 780 RenderBoxModelObject* r = renderer->firstLetter(); | |
| 781 if (r->style()->visibility() != VISIBLE && !m_ignoresStyleVisibility) | |
| 782 return; | |
| 783 if (RenderText* firstLetter = firstRenderTextInFirstLetter(r)) { | |
| 784 m_handledFirstLetter = true; | |
| 785 m_remainingTextBox = m_textBox; | |
| 786 m_textBox = firstLetter->firstTextBox(); | |
| 787 m_sortedTextBoxes.clear(); | |
| 788 m_firstLetterText = firstLetter; | |
| 789 } | |
| 790 } | |
| 791 m_handledFirstLetter = true; | 770 m_handledFirstLetter = true; |
| 771 | |
| 772 if (!renderer->isRemainingTextRenderer()) | |
| 773 return; | |
| 774 | |
| 775 FirstLetterPseudoElement* firstLetterElement = renderer->firstLetterPseudoEl ement(); | |
| 776 if (!firstLetterElement) | |
| 777 return; | |
| 778 | |
| 779 RenderObject* pseudoRenderer = firstLetterElement->renderer(); | |
| 780 if (pseudoRenderer->style()->visibility() != VISIBLE && !m_ignoresStyleVisib ility) | |
| 781 return; | |
| 782 | |
| 783 RenderObject* firstLetter = pseudoRenderer->slowFirstChild(); | |
| 784 ASSERT(firstLetter); | |
| 785 | |
| 786 m_remainingTextBox = m_textBox; | |
| 787 m_textBox = toRenderText(firstLetter)->firstTextBox(); | |
| 788 m_sortedTextBoxes.clear(); | |
| 789 m_firstLetterText = toRenderText(firstLetter); | |
| 792 } | 790 } |
| 793 | 791 |
| 794 bool TextIterator::handleReplacedElement() | 792 bool TextIterator::handleReplacedElement() |
| 795 { | 793 { |
| 796 if (m_fullyClippedStack.top()) | 794 if (m_fullyClippedStack.top()) |
| 797 return false; | 795 return false; |
| 798 | 796 |
| 799 RenderObject* renderer = m_node->renderer(); | 797 RenderObject* renderer = m_node->renderer(); |
| 800 if (renderer->style()->visibility() != VISIBLE && !m_ignoresStyleVisibility) | 798 if (renderer->style()->visibility() != VISIBLE && !m_ignoresStyleVisibility) |
| 801 return false; | 799 return false; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 843 m_textLength = 0; | 841 m_textLength = 0; |
| 844 m_lastCharacter = 0; | 842 m_lastCharacter = 0; |
| 845 | 843 |
| 846 return true; | 844 return true; |
| 847 } | 845 } |
| 848 | 846 |
| 849 bool TextIterator::hasVisibleTextNode(RenderText* renderer) | 847 bool TextIterator::hasVisibleTextNode(RenderText* renderer) |
| 850 { | 848 { |
| 851 if (renderer->style()->visibility() == VISIBLE) | 849 if (renderer->style()->visibility() == VISIBLE) |
| 852 return true; | 850 return true; |
| 853 if (renderer->isTextFragment()) { | 851 |
| 854 RenderTextFragment* fragment = toRenderTextFragment(renderer); | 852 if (!renderer->isTextFragment()) |
| 855 if (fragment->firstLetter() && fragment->firstLetter()->style()->visibil ity() == VISIBLE) | 853 return false; |
| 856 return true; | 854 |
| 857 } | 855 RenderTextFragment* fragment = toRenderTextFragment(renderer); |
| 856 if (!fragment->isRemainingTextRenderer()) | |
| 857 return false; | |
| 858 | |
| 859 RenderObject* pseudoElementRenderer = fragment->firstLetterPseudoElement()-> renderer(); | |
| 860 if (pseudoElementRenderer && pseudoElementRenderer->style()->visibility() == VISIBLE) | |
|
Julien - ping for review
2014/11/12 21:58:51
Way, way better written:
return pseudoElementRend
dsinclair
2014/11/13 17:55:36
Good catch, thanks.
| |
| 861 return true; | |
| 862 | |
| 858 return false; | 863 return false; |
| 859 } | 864 } |
| 860 | 865 |
| 861 static bool shouldEmitTabBeforeNode(Node* node) | 866 static bool shouldEmitTabBeforeNode(Node* node) |
| 862 { | 867 { |
| 863 RenderObject* r = node->renderer(); | 868 RenderObject* r = node->renderer(); |
| 864 | 869 |
| 865 // Table cells are delimited by tabs. | 870 // Table cells are delimited by tabs. |
| 866 if (!r || !isTableCell(node)) | 871 if (!r || !isTableCell(node)) |
| 867 return false; | 872 return false; |
| (...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1521 } | 1526 } |
| 1522 | 1527 |
| 1523 if (!m_shouldHandleFirstLetter && offsetAfterFirstLetter < m_offset) { | 1528 if (!m_shouldHandleFirstLetter && offsetAfterFirstLetter < m_offset) { |
| 1524 m_shouldHandleFirstLetter = true; | 1529 m_shouldHandleFirstLetter = true; |
| 1525 offsetInNode = offsetAfterFirstLetter; | 1530 offsetInNode = offsetAfterFirstLetter; |
| 1526 return renderer; | 1531 return renderer; |
| 1527 } | 1532 } |
| 1528 | 1533 |
| 1529 m_shouldHandleFirstLetter = false; | 1534 m_shouldHandleFirstLetter = false; |
| 1530 offsetInNode = 0; | 1535 offsetInNode = 0; |
| 1531 RenderText* firstLetterRenderer = firstRenderTextInFirstLetter(fragment->fir stLetter()); | 1536 |
| 1537 ASSERT(fragment->isRemainingTextRenderer()); | |
| 1538 ASSERT(fragment->firstLetterPseudoElement()); | |
| 1539 | |
| 1540 RenderObject* pseudoElementRenderer = fragment->firstLetterPseudoElement()-> renderer(); | |
| 1541 ASSERT(pseudoElementRenderer); | |
| 1542 ASSERT(pseudoElementRenderer->slowFirstChild()); | |
| 1543 RenderText* firstLetterRenderer = toRenderText(pseudoElementRenderer->slowFi rstChild()); | |
| 1532 | 1544 |
| 1533 m_offset = firstLetterRenderer->caretMaxOffset(); | 1545 m_offset = firstLetterRenderer->caretMaxOffset(); |
| 1534 m_offset += collapsedSpaceLength(firstLetterRenderer, m_offset); | 1546 m_offset += collapsedSpaceLength(firstLetterRenderer, m_offset); |
| 1535 | 1547 |
| 1536 return firstLetterRenderer; | 1548 return firstLetterRenderer; |
| 1537 } | 1549 } |
| 1538 | 1550 |
| 1539 bool SimplifiedBackwardsTextIterator::handleReplacedElement() | 1551 bool SimplifiedBackwardsTextIterator::handleReplacedElement() |
| 1540 { | 1552 { |
| 1541 unsigned index = m_node->nodeIndex(); | 1553 unsigned index = m_node->nodeIndex(); |
| (...skipping 879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2421 resultEnd = collapseTo; | 2433 resultEnd = collapseTo; |
| 2422 return; | 2434 return; |
| 2423 } | 2435 } |
| 2424 } | 2436 } |
| 2425 | 2437 |
| 2426 CharacterIterator computeRangeIterator(inputStart, inputEnd, iteratorFlagsFo rFindPlainText); | 2438 CharacterIterator computeRangeIterator(inputStart, inputEnd, iteratorFlagsFo rFindPlainText); |
| 2427 calculateCharacterSubrange(computeRangeIterator, matchStart, matchLength, re sultStart, resultEnd); | 2439 calculateCharacterSubrange(computeRangeIterator, matchStart, matchLength, re sultStart, resultEnd); |
| 2428 } | 2440 } |
| 2429 | 2441 |
| 2430 } | 2442 } |
| OLD | NEW |