Modified: trunk/LayoutTests/editing/selection/move-by-word-visually-single-space-one-element-expected.txt (111623 => 111624)
--- trunk/LayoutTests/editing/selection/move-by-word-visually-single-space-one-element-expected.txt 2012-03-22 00:20:38 UTC (rev 111623)
+++ trunk/LayoutTests/editing/selection/move-by-word-visually-single-space-one-element-expected.txt 2012-03-22 00:20:43 UTC (rev 111624)
@@ -97,6 +97,11 @@
" opq rst "[8, 5, 1], "abc def hij "[8, 4, 0]
Test 19, LTR:
Move right by one word
+"abc def this"[0, 4, 8], "end opq rst "[4, 8, 11]
+Move left by one word
+"end opq rst "[11, 8, 4], "abc def this"[8, 4, 0]
+Test 20, LTR:
+Move right by one word
<DIV>[0]
Move left by one word
<DIV>[0]
Modified: trunk/LayoutTests/editing/selection/move-by-word-visually-single-space-one-element.html (111623 => 111624)
--- trunk/LayoutTests/editing/selection/move-by-word-visually-single-space-one-element.html 2012-03-22 00:20:38 UTC (rev 111623)
+++ trunk/LayoutTests/editing/selection/move-by-word-visually-single-space-one-element.html 2012-03-22 00:20:43 UTC (rev 111624)
@@ -71,6 +71,8 @@
<!-- Test with image -- non-inline-text-box -->
<div id="d_1" dir=ltr class="test_move_by_word" contenteditable title="[d_1, 0, 1][d_1, 4, 1][d_1, 8, 1][d_1, 1, 3][d_1, 5, 3][d_1, 8, 3]|[d_1, 8, 3][d_1, 5, 3][d_1, 1, 3][d_1, 8, 1][d_1, 4, 1][d_1, 0, 1]">abc def hij <img src="" opq rst </div>
+<div id="d_2" dir=ltr class="test_move_by_word" contenteditable title="[d_2, 0, 1][d_2, 4, 1][d_2, 8, 1][d_2, 4, 5][d_2, 8, 5][d_2, 11, 5]|[d_2, 11, 5][d_2, 8, 5][d_2, 4, 5][d_2, 8, 1][d_2, 4, 1][d_2, 0, 1]">abc def this<span>is</span><span>one</span><span>word</span>end opq rst </div>
+
<!-- empty div -->
<div dir=ltr class="test_move_by_word" title="0|0" contenteditable></div>
Modified: trunk/Source/WebCore/editing/visible_units.cpp (111623 => 111624)
--- trunk/Source/WebCore/editing/visible_units.cpp 2012-03-22 00:20:38 UTC (rev 111623)
+++ trunk/Source/WebCore/editing/visible_units.cpp 2012-03-22 00:20:43 UTC (rev 111624)
@@ -165,46 +165,96 @@
return 0;
}
-static int boxIndexInVector(const InlineTextBox* box, const Vector<InlineBox*>& leafBoxesInLogicalOrder)
+class CachedLogicallyOrderedLeafBoxes {
+public:
+ CachedLogicallyOrderedLeafBoxes();
+
+ const InlineTextBox* previousTextBox(const RootInlineBox*, const InlineTextBox*);
+ const InlineTextBox* nextTextBox(const RootInlineBox*, const InlineTextBox*);
+
+ size_t size() const { return m_leafBoxes.size(); }
+ const InlineBox* firstBox() const { return m_leafBoxes[0]; }
+
+private:
+ const Vector<InlineBox*>& collectBoxes(const RootInlineBox*);
+ int boxIndexInLeaves(const InlineTextBox*);
+
+ const RootInlineBox* m_rootInlineBox;
+ Vector<InlineBox*> m_leafBoxes;
+};
+
+CachedLogicallyOrderedLeafBoxes::CachedLogicallyOrderedLeafBoxes() : m_rootInlineBox(0) { };
+
+const InlineTextBox* CachedLogicallyOrderedLeafBoxes::previousTextBox(const RootInlineBox* root, const InlineTextBox* box)
{
- for (size_t i = 0; i < leafBoxesInLogicalOrder.size(); ++i) {
- if (box == leafBoxesInLogicalOrder[i])
- return i;
+ if (!root)
+ return 0;
+
+ collectBoxes(root);
+
+ // If box is null, root is box's previous RootInlineBox, and previousBox is the last logical box in root.
+ int boxIndex = m_leafBoxes.size() - 1;
+ if (box)
+ boxIndex = boxIndexInLeaves(box) - 1;
+
+ for (int i = boxIndex; i >= 0; --i) {
+ if (m_leafBoxes[i]->isInlineTextBox())
+ return toInlineTextBox(m_leafBoxes[i]);
}
+
return 0;
}
-static const InlineTextBox* previousBoxInLine(const RootInlineBox* root, const InlineTextBox* box, Vector<InlineBox*>& leafBoxesInLogicalOrder)
+const InlineTextBox* CachedLogicallyOrderedLeafBoxes::nextTextBox(const RootInlineBox* root, const InlineTextBox* box)
{
if (!root)
return 0;
- leafBoxesInLogicalOrder.clear();
- root->collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder);
+ collectBoxes(root);
- // If box is null, root is box's previous RootInlineBox, and previousBox is the last logical box in root.
- int boxIndex = leafBoxesInLogicalOrder.size() - 1;
+ // If box is null, root is box's next RootInlineBox, and nextBox is the first logical box in root.
+ // Otherwise, root is box's RootInlineBox, and nextBox is the next logical box in the same line.
+ size_t nextBoxIndex = 0;
if (box)
- boxIndex = boxIndexInVector(box, leafBoxesInLogicalOrder) - 1;
+ nextBoxIndex = boxIndexInLeaves(box) + 1;
- for (int i = boxIndex; i >= 0; --i) {
- if (leafBoxesInLogicalOrder[i]->isInlineTextBox())
- return toInlineTextBox(leafBoxesInLogicalOrder[i]);
+ for (size_t i = nextBoxIndex; i < m_leafBoxes.size(); ++i) {
+ if (m_leafBoxes[i]->isInlineTextBox())
+ return toInlineTextBox(m_leafBoxes[i]);
}
return 0;
}
-static const InlineTextBox* logicallyPreviousBox(const VisiblePosition& visiblePosition, const InlineTextBox* textBox, bool& previousBoxInDifferentBlock)
+const Vector<InlineBox*>& CachedLogicallyOrderedLeafBoxes::collectBoxes(const RootInlineBox* root)
{
+ if (m_rootInlineBox != root) {
+ m_rootInlineBox = root;
+ m_leafBoxes.clear();
+ root->collectLeafBoxesInLogicalOrder(m_leafBoxes);
+ }
+ return m_leafBoxes;
+}
+
+int CachedLogicallyOrderedLeafBoxes::boxIndexInLeaves(const InlineTextBox* box)
+{
+ for (size_t i = 0; i < m_leafBoxes.size(); ++i) {
+ if (box == m_leafBoxes[i])
+ return i;
+ }
+ return 0;
+}
+
+static const InlineTextBox* logicallyPreviousBox(const VisiblePosition& visiblePosition, const InlineTextBox* textBox,
+ bool& previousBoxInDifferentBlock, CachedLogicallyOrderedLeafBoxes& leafBoxes)
+{
const InlineBox* startBox = textBox;
- Vector<InlineBox*> leafBoxesInLogicalOrder;
- const InlineTextBox* previousBox = previousBoxInLine(startBox->root(), textBox, leafBoxesInLogicalOrder);
+ const InlineTextBox* previousBox = leafBoxes.previousTextBox(startBox->root(), textBox);
if (previousBox)
return previousBox;
- previousBox = previousBoxInLine(startBox->root()->prevRootBox(), 0, leafBoxesInLogicalOrder);
+ previousBox = leafBoxes.previousTextBox(startBox->root()->prevRootBox(), 0);
if (previousBox)
return previousBox;
@@ -213,51 +263,30 @@
if (!previousRoot)
break;
- previousBox = previousBoxInLine(previousRoot, 0, leafBoxesInLogicalOrder);
+ previousBox = leafBoxes.previousTextBox(previousRoot, 0);
if (previousBox) {
previousBoxInDifferentBlock = true;
return previousBox;
}
- if (!leafBoxesInLogicalOrder.size())
+ if (!leafBoxes.size())
break;
- startBox = leafBoxesInLogicalOrder[0];
+ startBox = leafBoxes.firstBox();
}
return 0;
}
-static const InlineTextBox* nextBoxInLine(const RootInlineBox* root, const InlineTextBox* box, Vector<InlineBox*>& leafBoxesInLogicalOrder)
-{
- if (!root)
- return 0;
- leafBoxesInLogicalOrder.clear();
- root->collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder);
-
- // If box is null, root is box's next RootInlineBox, and nextBox is the first logical box in root.
- // Otherwise, root is box's RootInlineBox, and nextBox is the next logical box in the same line.
- size_t nextBoxIndex = 0;
- if (box)
- nextBoxIndex = boxIndexInVector(box, leafBoxesInLogicalOrder) + 1;
-
- for (size_t i = nextBoxIndex; i < leafBoxesInLogicalOrder.size(); ++i) {
- if (leafBoxesInLogicalOrder[i]->isInlineTextBox())
- return toInlineTextBox(leafBoxesInLogicalOrder[i]);
- }
-
- return 0;
-}
-
-static const InlineTextBox* logicallyNextBox(const VisiblePosition& visiblePosition, const InlineTextBox* textBox, bool& nextBoxInDifferentBlock)
+static const InlineTextBox* logicallyNextBox(const VisiblePosition& visiblePosition, const InlineTextBox* textBox,
+ bool& nextBoxInDifferentBlock, CachedLogicallyOrderedLeafBoxes& leafBoxes)
{
const InlineBox* startBox = textBox;
- Vector<InlineBox*> leafBoxesInLogicalOrder;
- const InlineTextBox* nextBox = nextBoxInLine(startBox->root(), textBox, leafBoxesInLogicalOrder);
+ const InlineTextBox* nextBox = leafBoxes.nextTextBox(startBox->root(), textBox);
if (nextBox)
return nextBox;
- nextBox = nextBoxInLine(startBox->root()->nextRootBox(), 0, leafBoxesInLogicalOrder);
+ nextBox = leafBoxes.nextTextBox(startBox->root()->nextRootBox(), 0);
if (nextBox)
return nextBox;
@@ -266,26 +295,26 @@
if (!nextRoot)
break;
- nextBox = nextBoxInLine(nextRoot, 0, leafBoxesInLogicalOrder);
+ nextBox = leafBoxes.nextTextBox(nextRoot, 0);
if (nextBox) {
nextBoxInDifferentBlock = true;
return nextBox;
}
- if (!leafBoxesInLogicalOrder.size())
+ if (!leafBoxes.size())
break;
- startBox = leafBoxesInLogicalOrder[0];
+ startBox = leafBoxes.firstBox();
}
return 0;
}
static TextBreakIterator* wordBreakIteratorForMinOffsetBoundary(const VisiblePosition& visiblePosition, const InlineTextBox* textBox,
- int& previousBoxLength, bool& previousBoxInDifferentBlock, Vector<UChar, 1024>& string)
+ int& previousBoxLength, bool& previousBoxInDifferentBlock, Vector<UChar, 1024>& string, CachedLogicallyOrderedLeafBoxes& leafBoxes)
{
previousBoxInDifferentBlock = false;
// FIXME: Handle the case when we don't have an inline text box.
- const InlineTextBox* previousBox = logicallyPreviousBox(visiblePosition, textBox, previousBoxInDifferentBlock);
+ const InlineTextBox* previousBox = logicallyPreviousBox(visiblePosition, textBox, previousBoxInDifferentBlock, leafBoxes);
int len = 0;
string.clear();
@@ -301,12 +330,12 @@
}
static TextBreakIterator* wordBreakIteratorForMaxOffsetBoundary(const VisiblePosition& visiblePosition, const InlineTextBox* textBox,
- bool& nextBoxInDifferentBlock, Vector<UChar, 1024>& string)
+ bool& nextBoxInDifferentBlock, Vector<UChar, 1024>& string, CachedLogicallyOrderedLeafBoxes& leafBoxes)
{
nextBoxInDifferentBlock = false;
// FIXME: Handle the case when we don't have an inline text box.
- const InlineTextBox* nextBox = logicallyNextBox(visiblePosition, textBox, nextBoxInDifferentBlock);
+ const InlineTextBox* nextBox = logicallyNextBox(visiblePosition, textBox, nextBoxInDifferentBlock, leafBoxes);
int len = 0;
string.clear();
@@ -349,6 +378,9 @@
VisiblePosition current = visiblePosition;
TextBreakIterator* iter = 0;
+ CachedLogicallyOrderedLeafBoxes leafBoxes;
+ Vector<UChar, 1024> string;
+
while (1) {
VisiblePosition adjacentCharacterPosition = direction == MoveRight ? current.right(true) : current.left(true);
if (adjacentCharacterPosition == current || adjacentCharacterPosition.isNull())
@@ -371,11 +403,10 @@
bool nextBoxInDifferentBlock = false;
bool movingIntoNewBox = previouslyVisitedBox != box;
- Vector<UChar, 1024> string;
if (offsetInBox == box->caretMinOffset())
- iter = wordBreakIteratorForMinOffsetBoundary(visiblePosition, textBox, previousBoxLength, previousBoxInDifferentBlock, string);
+ iter = wordBreakIteratorForMinOffsetBoundary(visiblePosition, textBox, previousBoxLength, previousBoxInDifferentBlock, string, leafBoxes);
else if (offsetInBox == box->caretMaxOffset())
- iter = wordBreakIteratorForMaxOffsetBoundary(visiblePosition, textBox, nextBoxInDifferentBlock, string);
+ iter = wordBreakIteratorForMaxOffsetBoundary(visiblePosition, textBox, nextBoxInDifferentBlock, string, leafBoxes);
else if (movingIntoNewBox) {
iter = wordBreakIterator(textBox->textRenderer()->text()->characters() + textBox->start(), textBox->len());
previouslyVisitedBox = box;