Chromium Code Reviews| Index: Source/core/editing/TextIterator.cpp |
| diff --git a/Source/core/editing/TextIterator.cpp b/Source/core/editing/TextIterator.cpp |
| index 7220a76da1c57feddbd673e2f47d8b210b3bb4b6..ecbe5b27d942d01417feb4118488be84b8ddebb9 100644 |
| --- a/Source/core/editing/TextIterator.cpp |
| +++ b/Source/core/editing/TextIterator.cpp |
| @@ -30,6 +30,7 @@ |
| #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
| #include "core/HTMLNames.h" |
| #include "core/dom/Document.h" |
| +#include "core/dom/FirstLetterPseudoElement.h" |
| #include "core/dom/NodeTraversal.h" |
| #include "core/dom/shadow/ShadowRoot.h" |
| #include "core/editing/VisiblePosition.h" |
| @@ -678,80 +679,83 @@ bool TextIterator::handleTextNode() |
| void TextIterator::handleTextBox() |
| { |
| RenderText* renderer = m_firstLetterText ? m_firstLetterText.get() : toRenderText(m_node->renderer()); |
| + |
| if (renderer->style()->visibility() != VISIBLE && !m_ignoresStyleVisibility) { |
| m_textBox = 0; |
| - return; |
| - } |
| - String str = renderer->text(); |
| - unsigned start = m_offset; |
| - unsigned end = (m_node == m_endContainer) ? static_cast<unsigned>(m_endOffset) : INT_MAX; |
| - while (m_textBox) { |
| - unsigned textBoxStart = m_textBox->start(); |
| - unsigned runStart = std::max(textBoxStart, start); |
| - |
| - // Check for collapsed space at the start of this run. |
| - InlineTextBox* firstTextBox = renderer->containsReversedText() ? (m_sortedTextBoxes.isEmpty() ? 0 : m_sortedTextBoxes[0]) : renderer->firstTextBox(); |
| - bool needSpace = m_lastTextNodeEndedWithCollapsedSpace |
| - || (m_textBox == firstTextBox && textBoxStart == runStart && runStart > 0); |
| - if (needSpace && !renderer->style()->isCollapsibleWhiteSpace(m_lastCharacter) && m_lastCharacter) { |
| - if (m_lastTextNode == m_node && runStart > 0 && str[runStart - 1] == ' ') { |
| - unsigned spaceRunStart = runStart - 1; |
| - while (spaceRunStart > 0 && str[spaceRunStart - 1] == ' ') |
| - --spaceRunStart; |
| - emitText(m_node, renderer, spaceRunStart, spaceRunStart + 1); |
| - } else { |
| - emitCharacter(space, m_node, 0, runStart, runStart); |
| + } else { |
| + String str = renderer->text(); |
| + unsigned start = m_offset; |
| + unsigned end = (m_node == m_endContainer) ? static_cast<unsigned>(m_endOffset) : INT_MAX; |
| + while (m_textBox) { |
| + unsigned textBoxStart = m_textBox->start(); |
| + unsigned runStart = std::max(textBoxStart, start); |
| + |
| + // Check for collapsed space at the start of this run. |
| + InlineTextBox* firstTextBox = renderer->containsReversedText() ? (m_sortedTextBoxes.isEmpty() ? 0 : m_sortedTextBoxes[0]) : renderer->firstTextBox(); |
| + bool needSpace = m_lastTextNodeEndedWithCollapsedSpace |
| + || (m_textBox == firstTextBox && textBoxStart == runStart && runStart > 0); |
| + if (needSpace && !renderer->style()->isCollapsibleWhiteSpace(m_lastCharacter) && m_lastCharacter) { |
| + if (m_lastTextNode == m_node && runStart > 0 && str[runStart - 1] == ' ') { |
| + unsigned spaceRunStart = runStart - 1; |
| + while (spaceRunStart > 0 && str[spaceRunStart - 1] == ' ') |
| + --spaceRunStart; |
| + emitText(m_node, renderer, spaceRunStart, spaceRunStart + 1); |
| + } else { |
| + emitCharacter(space, m_node, 0, runStart, runStart); |
| + } |
| + return; |
| } |
| - return; |
| - } |
| - unsigned textBoxEnd = textBoxStart + m_textBox->len(); |
| - unsigned runEnd = std::min(textBoxEnd, end); |
| - |
| - // Determine what the next text box will be, but don't advance yet |
| - InlineTextBox* nextTextBox = nullptr; |
| - if (renderer->containsReversedText()) { |
| - if (m_sortedTextBoxesPosition + 1 < m_sortedTextBoxes.size()) |
| - nextTextBox = m_sortedTextBoxes[m_sortedTextBoxesPosition + 1]; |
| - } else { |
| - nextTextBox = m_textBox->nextTextBox(); |
| - } |
| - ASSERT(!nextTextBox || nextTextBox->renderer() == renderer); |
| - |
| - if (runStart < runEnd) { |
| - // Handle either a single newline character (which becomes a space), |
| - // or a run of characters that does not include a newline. |
| - // This effectively translates newlines to spaces without copying the text. |
| - if (str[runStart] == '\n') { |
| - emitCharacter(space, m_node, 0, runStart, runStart + 1); |
| - m_offset = runStart + 1; |
| + unsigned textBoxEnd = textBoxStart + m_textBox->len(); |
| + unsigned runEnd = std::min(textBoxEnd, end); |
| + |
| + // Determine what the next text box will be, but don't advance yet |
| + InlineTextBox* nextTextBox = nullptr; |
| + if (renderer->containsReversedText()) { |
| + if (m_sortedTextBoxesPosition + 1 < m_sortedTextBoxes.size()) |
| + nextTextBox = m_sortedTextBoxes[m_sortedTextBoxesPosition + 1]; |
| } else { |
| - size_t subrunEnd = str.find('\n', runStart); |
| - if (subrunEnd == kNotFound || subrunEnd > runEnd) |
| - subrunEnd = runEnd; |
| - |
| - m_offset = subrunEnd; |
| - emitText(m_node, renderer, runStart, subrunEnd); |
| + nextTextBox = m_textBox->nextTextBox(); |
| } |
| + ASSERT(!nextTextBox || nextTextBox->renderer() == renderer); |
| + |
| + if (runStart < runEnd) { |
| + // Handle either a single newline character (which becomes a space), |
| + // or a run of characters that does not include a newline. |
| + // This effectively translates newlines to spaces without copying the text. |
| + if (str[runStart] == '\n') { |
| + emitCharacter(space, m_node, 0, runStart, runStart + 1); |
| + m_offset = runStart + 1; |
| + } else { |
| + size_t subrunEnd = str.find('\n', runStart); |
| + if (subrunEnd == kNotFound || subrunEnd > runEnd) |
| + subrunEnd = runEnd; |
| - // If we are doing a subrun that doesn't go to the end of the text box, |
| - // come back again to finish handling this text box; don't advance to the next one. |
| - if (static_cast<unsigned>(m_positionEndOffset) < textBoxEnd) |
| - return; |
| + m_offset = subrunEnd; |
| + emitText(m_node, renderer, runStart, subrunEnd); |
| + } |
| - // Advance and return |
| - unsigned nextRunStart = nextTextBox ? nextTextBox->start() : str.length(); |
| - if (nextRunStart > runEnd) |
| - m_lastTextNodeEndedWithCollapsedSpace = true; // collapsed space between runs or at the end |
| + // If we are doing a subrun that doesn't go to the end of the text box, |
| + // come back again to finish handling this text box; don't advance to the next one. |
| + if (static_cast<unsigned>(m_positionEndOffset) < textBoxEnd) |
| + return; |
| + |
| + // Advance and return |
| + unsigned nextRunStart = nextTextBox ? nextTextBox->start() : str.length(); |
| + if (nextRunStart > runEnd) |
| + m_lastTextNodeEndedWithCollapsedSpace = true; // collapsed space between runs or at the end |
| + |
| + m_textBox = nextTextBox; |
| + if (renderer->containsReversedText()) |
| + ++m_sortedTextBoxesPosition; |
| + return; |
| + } |
| + // Advance and continue |
| m_textBox = nextTextBox; |
| if (renderer->containsReversedText()) |
| ++m_sortedTextBoxesPosition; |
| - return; |
| } |
| - // Advance and continue |
| - m_textBox = nextTextBox; |
| - if (renderer->containsReversedText()) |
| - ++m_sortedTextBoxesPosition; |
| } |
| + |
| if (!m_textBox && m_remainingTextBox) { |
| m_textBox = m_remainingTextBox; |
| m_remainingTextBox = 0; |
| @@ -761,34 +765,28 @@ void TextIterator::handleTextBox() |
| } |
| } |
| -static inline RenderText* firstRenderTextInFirstLetter(RenderBoxModelObject* firstLetter) |
| -{ |
| - if (!firstLetter) |
| - return 0; |
| - |
| - // FIXME: Should this check descendent objects? |
| - for (RenderObject* current = firstLetter->slowFirstChild(); current; current = current->nextSibling()) { |
| - if (current->isText()) |
| - return toRenderText(current); |
| - } |
| - return 0; |
| -} |
| - |
| void TextIterator::handleTextNodeFirstLetter(RenderTextFragment* renderer) |
| { |
| - if (renderer->firstLetter()) { |
| - RenderBoxModelObject* r = renderer->firstLetter(); |
| - if (r->style()->visibility() != VISIBLE && !m_ignoresStyleVisibility) |
| - return; |
| - if (RenderText* firstLetter = firstRenderTextInFirstLetter(r)) { |
| - m_handledFirstLetter = true; |
| - m_remainingTextBox = m_textBox; |
| - m_textBox = firstLetter->firstTextBox(); |
| - m_sortedTextBoxes.clear(); |
| - m_firstLetterText = firstLetter; |
| - } |
| - } |
| m_handledFirstLetter = true; |
| + |
| + if (!renderer->isRemainingTextRenderer()) |
| + return; |
| + |
| + FirstLetterPseudoElement* firstLetterElement = renderer->firstLetterPseudoElement(); |
| + if (!firstLetterElement) |
| + return; |
| + |
| + RenderObject* pseudoRenderer = firstLetterElement->renderer(); |
| + if (pseudoRenderer->style()->visibility() != VISIBLE && !m_ignoresStyleVisibility) |
| + return; |
| + |
| + RenderObject* firstLetter = pseudoRenderer->slowFirstChild(); |
| + ASSERT(firstLetter); |
| + |
| + m_remainingTextBox = m_textBox; |
| + m_textBox = toRenderText(firstLetter)->firstTextBox(); |
| + m_sortedTextBoxes.clear(); |
| + m_firstLetterText = toRenderText(firstLetter); |
| } |
| bool TextIterator::handleReplacedElement() |
| @@ -850,11 +848,18 @@ bool TextIterator::hasVisibleTextNode(RenderText* renderer) |
| { |
| if (renderer->style()->visibility() == VISIBLE) |
| return true; |
| - if (renderer->isTextFragment()) { |
| - RenderTextFragment* fragment = toRenderTextFragment(renderer); |
| - if (fragment->firstLetter() && fragment->firstLetter()->style()->visibility() == VISIBLE) |
| - return true; |
| - } |
| + |
| + if (!renderer->isTextFragment()) |
| + return false; |
| + |
| + RenderTextFragment* fragment = toRenderTextFragment(renderer); |
| + if (!fragment->isRemainingTextRenderer()) |
| + return false; |
| + |
| + RenderObject* pseudoElementRenderer = fragment->firstLetterPseudoElement()->renderer(); |
| + 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.
|
| + return true; |
| + |
| return false; |
| } |
| @@ -1528,7 +1533,14 @@ RenderText* SimplifiedBackwardsTextIterator::handleFirstLetter(int& startOffset, |
| m_shouldHandleFirstLetter = false; |
| offsetInNode = 0; |
| - RenderText* firstLetterRenderer = firstRenderTextInFirstLetter(fragment->firstLetter()); |
| + |
| + ASSERT(fragment->isRemainingTextRenderer()); |
| + ASSERT(fragment->firstLetterPseudoElement()); |
| + |
| + RenderObject* pseudoElementRenderer = fragment->firstLetterPseudoElement()->renderer(); |
| + ASSERT(pseudoElementRenderer); |
| + ASSERT(pseudoElementRenderer->slowFirstChild()); |
| + RenderText* firstLetterRenderer = toRenderText(pseudoElementRenderer->slowFirstChild()); |
| m_offset = firstLetterRenderer->caretMaxOffset(); |
| m_offset += collapsedSpaceLength(firstLetterRenderer, m_offset); |