| Index: third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
|
| diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
|
| index e41d636c3b389a8310cc416f33e2f6fc4a06417d..7112f3f6e58ce50cd9a5044346bc433b8ca7ad62 100644
|
| --- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
|
| +++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
|
| @@ -64,6 +64,8 @@ using namespace HTMLNames;
|
|
|
| namespace {
|
|
|
| +const int kInvalidOffset = -1;
|
| +
|
| template <typename Strategy>
|
| TextIteratorBehaviorFlags adjustBehaviorFlags(TextIteratorBehaviorFlags);
|
|
|
| @@ -164,6 +166,8 @@ TextIteratorAlgorithm<Strategy>::TextIteratorAlgorithm(
|
| m_handledFirstLetter(false),
|
| m_shouldStop(false),
|
| m_handleShadowRoot(false),
|
| + m_firstLetterStartOffset(kInvalidOffset),
|
| + m_remainingTextStartOffset(kInvalidOffset),
|
| // The call to emitsOriginalText() must occur after m_behavior is
|
| // initialized.
|
| m_textState(emitsOriginalText()) {
|
| @@ -187,6 +191,43 @@ TextIteratorAlgorithm<Strategy>::TextIteratorAlgorithm(
|
| }
|
|
|
| template <typename Strategy>
|
| +bool TextIteratorAlgorithm<Strategy>::prepareForFirstLetterInitialization() {
|
| + if (m_node != m_startContainer)
|
| + return false;
|
| +
|
| + if (m_node->getNodeType() != Node::kTextNode)
|
| + return false;
|
| +
|
| + Text* textNode = toText(m_node);
|
| + LayoutText* layoutObject = textNode->layoutObject();
|
| + if (!layoutObject || !layoutObject->isTextFragment())
|
| + return false;
|
| +
|
| + LayoutTextFragment* textFragment = toLayoutTextFragment(layoutObject);
|
| + if (!textFragment->isRemainingTextLayoutObject())
|
| + return false;
|
| +
|
| + if (static_cast<unsigned>(m_startOffset) >= textFragment->textStartOffset()) {
|
| + m_remainingTextStartOffset =
|
| + m_startOffset - textFragment->textStartOffset();
|
| + } else {
|
| + m_firstLetterStartOffset = m_startOffset;
|
| + }
|
| + m_offset = 0;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +template <typename Strategy>
|
| +bool TextIteratorAlgorithm<Strategy>::hasNotAdvancedToStartPosition() {
|
| + if (atEnd())
|
| + return false;
|
| + if (m_remainingTextStartOffset == kInvalidOffset)
|
| + return false;
|
| + return m_node == m_startContainer;
|
| +}
|
| +
|
| +template <typename Strategy>
|
| void TextIteratorAlgorithm<Strategy>::initialize(Node* startContainer,
|
| int startOffset,
|
| Node* endContainer,
|
| @@ -220,7 +261,8 @@ void TextIteratorAlgorithm<Strategy>::initialize(Node* startContainer,
|
| return;
|
|
|
| m_fullyClippedStack.setUpFullyClippedStack(m_node);
|
| - m_offset = m_node == m_startContainer ? m_startOffset : 0;
|
| + if (!prepareForFirstLetterInitialization())
|
| + m_offset = m_node == m_startContainer ? m_startOffset : 0;
|
| m_iterationProgress = HandledNone;
|
|
|
| // Calculate first out of bounds node.
|
| @@ -229,6 +271,16 @@ void TextIteratorAlgorithm<Strategy>::initialize(Node* startContainer,
|
|
|
| // Identify the first run.
|
| advance();
|
| +
|
| + // The current design cannot start in a text node with arbitrary offset, if
|
| + // the node has :first-letter. Instead, we start with offset 0, and have extra
|
| + // advance() calls until we have moved to/past the starting position.
|
| + while (hasNotAdvancedToStartPosition())
|
| + advance();
|
| +
|
| + // Clear temporary data for initialization with :first-letter.
|
| + m_firstLetterStartOffset = kInvalidOffset;
|
| + m_remainingTextStartOffset = kInvalidOffset;
|
| }
|
|
|
| template <typename Strategy>
|
| @@ -1152,10 +1204,56 @@ void TextIteratorAlgorithm<Strategy>::spliceBuffer(UChar c,
|
| }
|
|
|
| template <typename Strategy>
|
| +int TextIteratorAlgorithm<Strategy>::adjustedStartForFirstLetter(
|
| + const Node& textNode,
|
| + const LayoutText& layoutObject,
|
| + int textStartOffset,
|
| + int textEndOffset) {
|
| + if (m_firstLetterStartOffset == kInvalidOffset)
|
| + return textStartOffset;
|
| + if (textNode != m_startContainer)
|
| + return textStartOffset;
|
| + if (!layoutObject.isTextFragment())
|
| + return textStartOffset;
|
| + if (toLayoutTextFragment(layoutObject).isRemainingTextLayoutObject())
|
| + return textStartOffset;
|
| + if (textEndOffset <= m_firstLetterStartOffset)
|
| + return textStartOffset;
|
| + int adjustedOffset = std::max(textStartOffset, m_firstLetterStartOffset);
|
| + m_firstLetterStartOffset = kInvalidOffset;
|
| + return adjustedOffset;
|
| +}
|
| +
|
| +template <typename Strategy>
|
| +int TextIteratorAlgorithm<Strategy>::adjustedStartForRemainingText(
|
| + const Node& textNode,
|
| + const LayoutText& layoutObject,
|
| + int textStartOffset,
|
| + int textEndOffset) {
|
| + if (m_remainingTextStartOffset == kInvalidOffset)
|
| + return textStartOffset;
|
| + if (textNode != m_startContainer)
|
| + return textStartOffset;
|
| + if (!layoutObject.isTextFragment())
|
| + return textStartOffset;
|
| + if (!toLayoutTextFragment(layoutObject).isRemainingTextLayoutObject())
|
| + return textStartOffset;
|
| + if (textEndOffset <= m_remainingTextStartOffset)
|
| + return textStartOffset;
|
| + int adjustedOffset = std::max(textStartOffset, m_remainingTextStartOffset);
|
| + m_remainingTextStartOffset = kInvalidOffset;
|
| + return adjustedOffset;
|
| +}
|
| +
|
| +template <typename Strategy>
|
| void TextIteratorAlgorithm<Strategy>::emitText(Node* textNode,
|
| LayoutText* layoutObject,
|
| int textStartOffset,
|
| int textEndOffset) {
|
| + textStartOffset = adjustedStartForFirstLetter(*textNode, *layoutObject,
|
| + textStartOffset, textEndOffset);
|
| + textStartOffset = adjustedStartForRemainingText(
|
| + *textNode, *layoutObject, textStartOffset, textEndOffset);
|
| // Since m_lastTextNodeEndedWithCollapsedSpace seems better placed in
|
| // TextIterator, but is always reset when we call spliceBuffer, we
|
| // wrap TextIteratorTextState::spliceBuffer() with this function.
|
| @@ -1168,12 +1266,8 @@ EphemeralRangeTemplate<Strategy> TextIteratorAlgorithm<Strategy>::range()
|
| const {
|
| // use the current run information, if we have it
|
| if (m_textState.positionNode()) {
|
| - m_textState.flushPositionOffsets();
|
| - return EphemeralRangeTemplate<Strategy>(
|
| - PositionTemplate<Strategy>(m_textState.positionNode(),
|
| - m_textState.positionStartOffset()),
|
| - PositionTemplate<Strategy>(m_textState.positionNode(),
|
| - m_textState.positionEndOffset()));
|
| + return EphemeralRangeTemplate<Strategy>(startPositionInCurrentContainer(),
|
| + endPositionInCurrentContainer());
|
| }
|
|
|
| // otherwise, return the end of the overall range we were given
|
| @@ -1208,7 +1302,7 @@ template <typename Strategy>
|
| int TextIteratorAlgorithm<Strategy>::startOffsetInCurrentContainer() const {
|
| if (m_textState.positionNode()) {
|
| m_textState.flushPositionOffsets();
|
| - return m_textState.positionStartOffset();
|
| + return m_textState.positionStartOffset() + m_textState.textStartOffset();
|
| }
|
| DCHECK(m_endContainer);
|
| return m_endOffset;
|
| @@ -1218,7 +1312,7 @@ template <typename Strategy>
|
| int TextIteratorAlgorithm<Strategy>::endOffsetInCurrentContainer() const {
|
| if (m_textState.positionNode()) {
|
| m_textState.flushPositionOffsets();
|
| - return m_textState.positionEndOffset();
|
| + return m_textState.positionEndOffset() + m_textState.textStartOffset();
|
| }
|
| DCHECK(m_endContainer);
|
| return m_endOffset;
|
|
|