| Index: Source/core/editing/TextIterator.cpp
|
| diff --git a/Source/core/editing/TextIterator.cpp b/Source/core/editing/TextIterator.cpp
|
| index 7220a76da1c57feddbd673e2f47d8b210b3bb4b6..1d48170e7aa3272f8888b8d105b82f80d9d9a487 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,12 +848,16 @@ 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;
|
| - }
|
| - return false;
|
| +
|
| + if (!renderer->isTextFragment())
|
| + return false;
|
| +
|
| + RenderTextFragment* fragment = toRenderTextFragment(renderer);
|
| + if (!fragment->isRemainingTextRenderer())
|
| + return false;
|
| +
|
| + RenderObject* pseudoElementRenderer = fragment->firstLetterPseudoElement()->renderer();
|
| + return pseudoElementRenderer && pseudoElementRenderer->style()->visibility() == VISIBLE;
|
| }
|
|
|
| static bool shouldEmitTabBeforeNode(Node* node)
|
| @@ -1528,7 +1530,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);
|
|
|