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); |