Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1007)

Unified Diff: third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp

Issue 2541163003: Fix TextIterator's behavior with first-letter (Closed)
Patch Set: Mon Dec 5 18:00:48 JST 2016 Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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;

Powered by Google App Engine
This is Rietveld 408576698