2011-04-22 Xiaomei Ji <xji@chromium.org>
authorxji@chromium.org <xji@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Apr 2011 00:12:23 +0000 (00:12 +0000)
committerxji@chromium.org <xji@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Apr 2011 00:12:23 +0000 (00:12 +0000)
        Reviewed by Ryosuke Niwa.

        move caret by word in visual order returns wrong result when caret itself is at word boundary.
        https://bugs.webkit.org/show_bug.cgi?id=58504.

        Add test case to test moving left/right by word visually on every character position.
        Remove a specific test added before for testing a specific code path since the test case
        is covered now.

        * editing/selection/move-by-word-visually-expected.txt:
        * editing/selection/move-by-word-visually.html:
2011-04-22  Xiaomei Ji  <xji@chromium.org>

        Reviewed by Ryosuke Niwa.

        move caret by word in visual order returns wrong result when caret itself is at word boundary.
        https://bugs.webkit.org/show_bug.cgi?id=58504.

        positionBeforeNextWord should take care that the current position is after current word.
        positionAfterPreviousWord should take care that the current positin is before current word.

        * editing/visible_units.cpp:
        (WebCore::positionBeforeNextWord):
        (WebCore::positionAfterPreviousWord):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@84710 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/editing/selection/move-by-word-visually-expected.txt
LayoutTests/editing/selection/move-by-word-visually.html
Source/WebCore/ChangeLog
Source/WebCore/editing/visible_units.cpp

index 7d326147d0f0b3e39552a043b43c3de9ee0e49e9..61c486294c06a58046e69403bb89391d01b647b2 100644 (file)
@@ -1,3 +1,17 @@
+2011-04-22  Xiaomei Ji  <xji@chromium.org>
+
+        Reviewed by Ryosuke Niwa.
+
+        move caret by word in visual order returns wrong result when caret itself is at word boundary.
+        https://bugs.webkit.org/show_bug.cgi?id=58504.
+
+        Add test case to test moving left/right by word visually on every character position.
+        Remove a specific test added before for testing a specific code path since the test case
+        is covered now.
+
+        * editing/selection/move-by-word-visually-expected.txt:
+        * editing/selection/move-by-word-visually.html:
+
 2011-04-22  Xiaomei Ji  <xji@chromium.org>
 
         Rebaseline after r84655.
index f94f22e9b8954f5d619a244a02c42d120049ffb5..0a17318c9dc932588679614c85b3fb8619870042 100644 (file)
@@ -88,8 +88,17 @@ Move right by one word
 Test 18, LTR:
 Move right by one word
 "abc def    hij opq"[0, 4, 15]    FAIL expected: [0, 4, 11, 15]
+"abc def    hij opq"[4, 15]   FAIL expected 11
+"abc def    hij opq"[5, 15]   FAIL expected 11
+"abc def    hij opq"[6, 15]   FAIL expected 11
+"abc def    hij opq"[7, 15]   FAIL expected 11
+"abc def    hij opq"[8, 15]   FAIL expected 11
 Move left by one word
 "abc def    hij opq"[18, 15, 4, 0]    FAIL expected: [18, 15, 11, 4, 0]
+"abc def    hij opq"[15, 4]   FAIL expected 11
+"abc def    hij opq"[14, 4]   FAIL expected 11
+"abc def    hij opq"[13, 4]   FAIL expected 11
+"abc def    hij opq"[12, 4]   FAIL expected 11
 Test 19, LTR:
 Move right by one word
 "AAA "[0, 3]
@@ -107,14 +116,30 @@ Move left by one word
 " rst uvw"[8, 5, 1], "hij opq"[4], "abc def "[8, 4, 0]
 Test 22, RTL:
 Move left by one word
-"abc def "[0], " rst uvw"[4], "hij opq"[3], "abc def "[7, 3]    FAIL expected: ["abc def "[ 0, ]" rst uvw"[ 4,  0, ]"hij opq"[ 3, ]"abc def "[ 7,  3]
-Move right by one word
-" rst uvw"[8], "abc def "[3, 7], "hij opq"[3], " rst uvw"[4], "abc def "[0]    FAIL expected: [" rst uvw"[ 8, ]"abc def "[ 3,  7, ]"hij opq"[ 3, ]" rst uvw"[ 0,  4, ]"abc def "[ 0]
+"abc def "[0], " rst uvw"[4], "hij opq"[3], "abc def "[7, 3]    FAIL expected: ["abc def "[ 0, ]" rst uvw"[ 4, ]"hij opq"[ 7,  3, ]"abc def "[ 7,  3]
+" rst uvw"[4], "hij opq"[3]   FAIL expected "hij opq"[ 7]
+" rst uvw"[3], "hij opq"[3]   FAIL expected "hij opq"[ 7]
+" rst uvw"[2], "hij opq"[3]   FAIL expected "hij opq"[ 7]
+" rst uvw"[1], "hij opq"[3]   FAIL expected "hij opq"[ 7]
+Move right by one word
+" rst uvw"[8], "abc def "[3, 7], "hij opq"[3], " rst uvw"[4], "abc def "[0]    FAIL expected: [" rst uvw"[ 8, ]"abc def "[ 3,  7, ]"hij opq"[ 3,  7, ]" rst uvw"[ 4, ]"abc def "[ 0]
+"hij opq"[3], " rst uvw"[4]   FAIL expected "hij opq"[ 7]
+"hij opq"[4], " rst uvw"[4]   FAIL expected "hij opq"[ 7]
+"hij opq"[5], " rst uvw"[4]   FAIL expected "hij opq"[ 7]
+"hij opq"[6], " rst uvw"[4]   FAIL expected "hij opq"[ 7]
 Test 23, RTL:
 Move left by one word
-"abc def "[0], " rst uvw"[4], "hij opq"[3], "abc def "[7, 3]    FAIL expected: ["abc def "[ 0, ]" rst uvw"[ 4,  0, ]"hij opq"[ 3, ]"abc def "[ 7,  3]
-Move right by one word
-" rst uvw"[8], "abc def "[3, 7], "hij opq"[3], " rst uvw"[4], "abc def "[0]    FAIL expected: [" rst uvw"[ 8, ]"abc def "[ 3,  7, ]"hij opq"[ 3, ]" rst uvw"[ 0,  4, ]"abc def "[ 0]
+"abc def "[0], " rst uvw"[4], "hij opq"[3], "abc def "[7, 3]    FAIL expected: ["abc def "[ 0, ]" rst uvw"[ 4, ]"hij opq"[ 7,  3, ]"abc def "[ 7,  3]
+" rst uvw"[4], "hij opq"[3]   FAIL expected "hij opq"[ 7]
+" rst uvw"[3], "hij opq"[3]   FAIL expected "hij opq"[ 7]
+" rst uvw"[2], "hij opq"[3]   FAIL expected "hij opq"[ 7]
+" rst uvw"[1], "hij opq"[3]   FAIL expected "hij opq"[ 7]
+Move right by one word
+" rst uvw"[8], "abc def "[3, 7], "hij opq"[3], " rst uvw"[4], "abc def "[0]    FAIL expected: [" rst uvw"[ 8, ]"abc def "[ 3,  7, ]"hij opq"[ 3,  7, ]" rst uvw"[ 4, ]"abc def "[ 0]
+"hij opq"[3], " rst uvw"[4]   FAIL expected "hij opq"[ 7]
+"hij opq"[4], " rst uvw"[4]   FAIL expected "hij opq"[ 7]
+"hij opq"[5], " rst uvw"[4]   FAIL expected "hij opq"[ 7]
+"hij opq"[6], " rst uvw"[4]   FAIL expected "hij opq"[ 7]
 Test 24, LTR:
 Move right by one word
 "abc def "[0, 4, 8], "hij opq"[4], " rst uvw"[1, 5]
@@ -150,6 +175,10 @@ Move right by one word
 "ABD DSU "[0], "FFZ LIG"[3], "ABD DSU "[8], "abc def"[4], "ABD DSU "[7, 3]
 Move left by one word
 "FFZ LIG"[7], "ABD DSU "[3, 7], "abc def"[4], "ABD DSU "[8], "FFZ LIG"[3]    FAIL expected: ["FFZ LIG"[ 7, ]"ABD DSU "[ 3,  7, ]"abc def"[ 4, ]"ABD DSU "[ 8, ]"FFZ LIG"[ 3, ]"ABD DSU "[ 0]
+"FFZ LIG"[3, 3]   FAIL expected "ABD DSU "[ 0]
+"FFZ LIG"[4, 4]   FAIL expected "ABD DSU "[ 0]
+"FFZ LIG"[5, 5]   FAIL expected "ABD DSU "[ 0]
+"FFZ LIG"[6, 6]   FAIL expected "ABD DSU "[ 0]
 Test 31, RTL:
 Move left by one word
 "ABD DSU "[0, 4, 8], "abc def"[3], "FFZ LIG"[4]
@@ -159,22 +188,57 @@ Test 32, LTR:
 Move right by one word
 "ABD DSU "[0, 3, 8], "abc def"[4], "FFZ LIG"[3]
 Move left by one word
-"FFZ LIG"[7, 3], "abc def"[4], "ABD DSU "[8, 4, 0]
+"FFZ LIG"[7, 3], "abc def"[4], "ABD DSU "[8, 4, 0]    FAIL expected: ["FFZ LIG"[ 7,  3, ]"abc def"[ 4, ]"ABD DSU "[ 8,  3,  0]
+"ABD DSU "[8, 4]   FAIL expected "ABD DSU "[ 3]
 Test 33, RTL:
 Move left by one word
 "ABD opq DSU "[0, 4, 8], "abc AAA def"[8, 4, 3], "FFZ rst LIG"[4, 8]    FAIL expected: ["ABD opq DSU "[ 0,  4,  8,  12, ]"abc AAA def"[ 4,  3, ]"FFZ rst LIG"[ 4,  8]
+"ABD opq DSU "[8], "abc AAA def"[8]   FAIL expected "ABD opq DSU "[ 12]
+"ABD opq DSU "[9], "abc AAA def"[8]   FAIL expected "ABD opq DSU "[ 12]
+"ABD opq DSU "[10], "abc AAA def"[8]   FAIL expected "ABD opq DSU "[ 12]
+"ABD opq DSU "[11], "abc AAA def"[8]   FAIL expected "ABD opq DSU "[ 12]
+"ABD opq DSU "[12], "abc AAA def"[8]   FAIL expected "abc AAA def"[ 4]
+"abc AAA def"[10, 8]   FAIL expected "abc AAA def"[ 4]
+"abc AAA def"[9, 8]   FAIL expected "abc AAA def"[ 4]
 Move right by one word
 "FFZ rst LIG"[11, 8, 4], "abc AAA def"[4, 8], "ABD opq DSU "[8, 4, 0]    FAIL expected: ["FFZ rst LIG"[ 11,  8,  4, ]"abc AAA def"[ 3,  4, ]"ABD opq DSU "[ 12,  8,  4,  0]
+"FFZ rst LIG"[4], "abc AAA def"[4]   FAIL expected "abc AAA def"[ 3]
+"abc AAA def"[4, 8]   FAIL expected "ABD opq DSU "[ 12]
+"abc AAA def"[8], "ABD opq DSU "[8]   FAIL expected "ABD opq DSU "[ 12]
+"abc AAA def"[9], "ABD opq DSU "[8]   FAIL expected "ABD opq DSU "[ 12]
+"abc AAA def"[10], "ABD opq DSU "[8]   FAIL expected "ABD opq DSU "[ 12]
 Test 34, LTR:
 Move right by one word
 "ABD opq DSU "[0, 4], "abc AAA def"[8, 4], "ABD opq DSU "[12, 11], "FFZ rst LIG"[4, 8, 11]    FAIL expected: ["ABD opq DSU "[ 0,  4,  8, ]"abc AAA def"[ 8,  7, ]"ABD opq DSU "[ 12,  11, ]"FFZ rst LIG"[ 4,  8,  11]
+"ABD opq DSU "[4], "abc AAA def"[8]   FAIL expected "ABD opq DSU "[ 8]
+"ABD opq DSU "[5], "abc AAA def"[8]   FAIL expected "ABD opq DSU "[ 8]
+"ABD opq DSU "[6], "abc AAA def"[8]   FAIL expected "ABD opq DSU "[ 8]
+"ABD opq DSU "[7], "abc AAA def"[8]   FAIL expected "ABD opq DSU "[ 8]
+"abc AAA def"[8, 4]   FAIL expected "abc AAA def"[ 7]
+"abc AAA def"[9, 4]   FAIL expected "abc AAA def"[ 7]
+"abc AAA def"[10, 4]   FAIL expected "abc AAA def"[ 7]
+"abc AAA def"[11, 4]   FAIL expected "abc AAA def"[ 7]
+"abc AAA def"[7, 4]   FAIL expected "ABD opq DSU "[ 12]
+"abc AAA def"[6, 4]   FAIL expected "ABD opq DSU "[ 12]
+"abc AAA def"[5, 4]   FAIL expected "ABD opq DSU "[ 12]
 Move left by one word
 "FFZ rst LIG"[11, 8, 4], "ABD opq DSU "[11, 12], "abc AAA def"[7, 8], "ABD opq DSU "[7, 4, 0]    FAIL expected: ["FFZ rst LIG"[ 11,  8,  4, ]"ABD opq DSU "[ 11,  12, ]"abc AAA def"[ 7,  8, ]"ABD opq DSU "[ 8,  4,  0]
+"abc AAA def"[8], "ABD opq DSU "[7]   FAIL expected "ABD opq DSU "[ 8]
+"FFZ rst LIG"[1], "ABD opq DSU "[4]   FAIL expected "ABD opq DSU "[ 8]
+"FFZ rst LIG"[2], "ABD opq DSU "[4]   FAIL expected "ABD opq DSU "[ 8]
 Test 35, RTL:
 Move left by one word
 "ABD opq DSU "[0, 4, 8], "abc AAA def"[4, 8], "FFZ rst LIG"[4, 8]    FAIL expected: ["ABD opq DSU "[ 0,  4,  8,  12, ]"abc AAA def"[ 4,  8, ]"FFZ rst LIG"[ 4,  8]
+"ABD opq DSU "[8], "abc AAA def"[4]   FAIL expected "ABD opq DSU "[ 12]
+"ABD opq DSU "[9], "abc AAA def"[4]   FAIL expected "ABD opq DSU "[ 12]
+"ABD opq DSU "[10], "abc AAA def"[4]   FAIL expected "ABD opq DSU "[ 12]
+"ABD opq DSU "[11], "abc AAA def"[4]   FAIL expected "ABD opq DSU "[ 12]
 Move right by one word
 "FFZ rst LIG"[11, 8, 4], "abc AAA def"[8, 4], "ABD opq DSU "[11, 8, 4, 0]    FAIL expected: ["FFZ rst LIG"[ 11,  8,  4, ]"abc AAA def"[ 8,  4, ]"ABD opq DSU "[ 12,  8,  4,  0]
+"abc AAA def"[4], "ABD opq DSU "[11]   FAIL expected "ABD opq DSU "[ 12]
+"abc AAA def"[3], "ABD opq DSU "[11]   FAIL expected "ABD opq DSU "[ 12]
+"abc AAA def"[1], "ABD opq DSU "[8]   FAIL expected "ABD opq DSU "[ 12]
+"abc AAA def"[2], "ABD opq DSU "[8]   FAIL expected "ABD opq DSU "[ 12]
 Test 36, LTR:
 Move right by one word
 "ABD opq DSU "[0, 4, 8, 12], "abc AAA def"[4, 8], "FFZ rst LIG"[4, 8, 11]
@@ -186,7 +250,3 @@ Move right by one word
 Move left by one word
 "FFZ"[3], "bbb AAA "[7, 4], "aaa "[4, 0]
 
-======== Move By Word Specific Test ====
-Test 1
-Move left by one word
-"BB"[1], "AAA "[0]
index 66f8acfe889f9f0556f3b665b479db65dfcdf049..2c8e2ca3723432fbabe9e972d6feb409ad11a8d9 100644 (file)
@@ -77,8 +77,9 @@ function nodeOfWordBreak(nodeAndOffset)
 
 var wordBreaks;
 
-function logWordBreak(index)
+function logWordBreak(index, first)
 {
+    var withNodeData = false;
     var wordBreak = wordBreaks[index];
     if (wordBreak.search(',') == -1)
         log(wordBreak);
@@ -87,16 +88,21 @@ function logWordBreak(index)
         var node = nodeOfWordBreak(nodeAndOffset);
 
         var differentNode = false;
-        if (index != 0) {
+        if (first == false) {
             differentNode = nodeOfWordBreak(nodeAndOffset) != nodeOfWordBreak(wordBreaks[index - 1].split(','));
         
         }
+
         if (differentNode == true)
             log("]");
-        if (index == 0 || differentNode == true)
+
+        if (first == true || differentNode == true) {
+            withNodeData = (node instanceof Text);
             log((node instanceof Text ? '"' + fold(node.data) + '"' : "<" + node.tagName + ">") + "[");
+        }
         log(nodeAndOffset[1]);
     }
+    return withNodeData;
 }
 
 function positionEqualToWordBreak(position, wordBreak)
@@ -123,7 +129,7 @@ function validateData(positions)
     if (equal == false) {
         log("    FAIL expected: [");
         for (var i = 0; i < wordBreaks.length; ++i) {
-            logWordBreak(i);
+            logWordBreak(i, i == 0);
             if (i != wordBreaks.length - 1)
                 log(", ");
         }
@@ -182,6 +188,66 @@ function moveByWord(sel, test, searchDirection, dir)
     log("\n");
 }
 
+function positionPassWordBreak(position, wordBreak, searchDirection)
+{
+    // Hack for space collapse.
+    // sel.modify("move", dir, "character") not reach multi-space.
+    var node = position.node;
+    if (node.parentNode.id == "multispace") {
+        if (searchDirection == "right" && position.offset >= wordBreak
+            || searchDirection == "left" && position.offset <= wordBreak) 
+            return true;
+    }
+    return false;
+}
+
+function moveByWordOnEveryChar(sel, test, searchDirection, dir)
+{
+    collectWordBreaks(test, searchDirection);
+    var wordBreakIndex = 1;
+    var prevOffset = sel.anchorOffset;
+    var prevNode = sel.anchorNode;
+
+    while (1) {
+        var positions = [];
+        positions.push({ node: sel.anchorNode, offset: sel.anchorOffset });
+        sel.modify("move", searchDirection, "-webkit-visual-word");
+
+        var position = { node: sel.anchorNode, offset: sel.anchorOffset };
+
+        if (wordBreakIndex >= wordBreaks.length) {
+            if (sel.anchorNode != prevNode || sel.anchorOffset != prevOffset) {
+                positions.push(position);
+                logPositions(positions);
+                log("   FAIL expected to stay in the same position\n");
+            }
+        } else if (!positionEqualToWordBreak(position, wordBreaks[wordBreakIndex])) {
+            positions.push(position);
+            logPositions(positions);
+            log("   FAIL expected ");
+            var withNodeData = logWordBreak(wordBreakIndex, true);
+            if (withNodeData)
+                log("]");
+            log("\n");
+        }
+
+        // Restore position and move by 1 character.
+        sel.setPosition(prevNode, prevOffset);
+        sel.modify("move", searchDirection, "character");
+        if (prevNode == sel.anchorNode && prevOffset == sel.anchorOffset)
+            break;
+
+        position = { node: sel.anchorNode, offset: sel.anchorOffset };
+        if (wordBreakIndex < wordBreaks.length 
+            && (positionEqualToWordBreak(position, wordBreaks[wordBreakIndex]) 
+            || positionPassWordBreak(position, wordBreaks[wordBreakIndex], searchDirection)))
+            ++wordBreakIndex;
+
+        prevNode = sel.anchorNode;
+        prevOffset = sel.anchorOffset;
+    };
+}
+
 function moveByWordForEveryPosition(sel, test, dir)
 {
     // Check ctrl-right-arrow works for every position.
@@ -190,6 +256,8 @@ function moveByWordForEveryPosition(sel, test, dir)
     if (dir == "rtl")
         direction = "left";    
     moveByWord(sel, test, direction, dir);    
+    sel.setPosition(test, 0);
+    moveByWordOnEveryChar(sel, test, direction, dir);
 
     sel.modify("move", "forward", "lineBoundary");
     // Check ctrl-left-arrow works for every position.
@@ -198,6 +266,8 @@ function moveByWordForEveryPosition(sel, test, dir)
     else
         direction = "right";    
     moveByWord(sel, test, direction, dir);    
+    sel.modify("move", "forward", "lineBoundary");
+    moveByWordOnEveryChar(sel, test, direction, dir);
 }
 
 function runMoveLeftRight(tests, unit)
@@ -215,39 +285,8 @@ function runMoveLeftRight(tests, unit)
             log("Test " + (i + 1) + ", RTL:\n");
             moveByWordForEveryPosition(sel, tests[i], "rtl");
         }
-
     }
-}
 
-function runSpecificTest(tests)
-{
-    var sel = getSelection();
-    log("\n======== Move By Word Specific Test ====\n");
-    for (var i = 0; i < tests.length; ++i) {
-        log("Test " + (i + 1) + "\n");
-        var components = tests[i].title.split(" ");
-        var startOffset = components[0];
-        var movingDirection = components[1];
-        var endingNode = components[2];
-        var endingOffset = components[3];
-        log("Move " + movingDirection + " by one word\n");
-
-        var positions = [];
-        sel.setPosition(tests[i].firstChild, startOffset);
-        positions.push({ node: sel.anchorNode, offset: sel.anchorOffset });
-
-        sel.modify("move", movingDirection, "-webkit-visual-word");
-        positions.push({ node: sel.anchorNode, offset: sel.anchorOffset });
-
-        logPositions(positions);
-
-        if (sel.anchorNode.parentNode != document.getElementById(endingNode) || sel.anchorOffset != endingOffset) {
-            log("    FAIL: expected ");
-            var endingChildNode = document.getElementById(endingNode).firstChild;
-            log((endingChildNode instanceof Text ? '"' + fold(endingChildNode.data) + '"' : "<" + endingChildNode.tagName + ">") + "[" + endingOffset + "]");
-        }
-    }
     document.getElementById("testMoveByWord").style.display = "none";
 }
 
@@ -255,9 +294,6 @@ function runTest() {
     log("\n======== Move By Word ====\n");
     var tests = document.getElementsByClassName("test_move_by_word");
     runMoveLeftRight(tests, "word");
-    
-    tests = document.getElementsByClassName("specific_test");
-    runSpecificTest(tests);
 }
 
 onload = function() {
@@ -319,7 +355,7 @@ where child_node_index is optional, default is the first child of the anchor nod
 <!-- multiple spaces between word. 
      FAILED: word break between "def" and "hij" is unreachable.
 -->
-<div dir=ltr class="test_move_by_word" title="0 4 11 15|18 15 11 4 0" contenteditable>abc def    hij opq</div>
+<div id="multispace" dir=ltr class="test_move_by_word" title="0 4 11 15|18 15 11 4 0" contenteditable>abc def    hij opq</div>
 
 <!-- Inline element -->
 <div dir=ltr id="div_1" class="test_move_by_word" title="[div_1, 0][div_1, 3]|[span_1, 2][div_1, 3][div_1,0]" contenteditable>אאא <span id="span_1">בב</span></div>
@@ -329,10 +365,10 @@ where child_node_index is optional, default is the first child of the anchor nod
 <div dir=ltr id="div_3" class="test_move_by_word" title="[div_3, 0][div_3, 4][div_3, 8][span_3, 4][div_3, 1, 3][div_3, 5, 3]|[div_3, 8, 3][div_3, 5, 3][div_3, 1, 3][span_3, 4][div_3, 8][div_3, 4][div_3, 0]" contenteditable>abc def <span id="span_3">hij opq</span> rst uvw</div>
 
 <!-- FAILED -->
-<div dir=rtl id="div_4" class="test_move_by_word" title="[div_4, 8, 3][div_4, 3, 1][div_4, 7, 1][span_4, 3, 1][div_4, 0, 3][div_4, 4, 3][div_4, 0, 1]|[div_4, 0, 1][div_4, 4, 3][div_4, 0, 3][span_4, 3, 1][div_4, 7, 1][div_4, 3, 1]" contenteditable>abc def <span id="span_4">hij opq</span> rst uvw</div>
+<div dir=rtl id="div_4" class="test_move_by_word" title="[div_4, 8, 3][div_4, 3, 1][div_4, 7, 1][span_4, 3, 1][span_4, 7, 1][div_4, 4, 3][div_4, 0, 1]|[div_4, 0, 1][div_4, 4, 3][span_4, 7, 1][span_4, 3, 1][div_4, 7, 1][div_4, 3, 1]" contenteditable>abc def <span id="span_4">hij opq</span> rst uvw</div>
 
-<!-- FAILED -->
-<div id="div_5" dir=rtl class="test_move_by_word" title="[div_5, 8, 3][div_5, 3, 1][div_5, 7, 1][span_5, 3, 1][div_5, 0, 3][div_5, 4, 3][div_5, 0, 1]|[div_5, 0, 1][div_5, 4, 3][div_5, 0, 3][span_5, 3, 1][div_5, 7, 1][div_5, 3, 1]"contenteditable>abc def <span dir=ltr id="span_5">hij opq</span> rst uvw</div>
+<!-- FAILED. The render result is the same as div_4. -->
+<div id="div_5" dir=rtl class="test_move_by_word" title="[div_5, 8, 3][div_5, 3, 1][div_5, 7, 1][span_5, 3, 1][span_5, 7, 1][div_5, 4, 3][div_5, 0, 1]|[div_5, 0, 1][div_5, 4, 3][span_5, 7, 1][span_5, 3, 1][div_5, 7, 1][div_5, 3, 1]"contenteditable>abc def <span dir=ltr id="span_5">hij opq</span> rst uvw</div>
 
 <div id="div_6" dir=ltr class="test_move_by_word" title="[div_6, 0, 1][div_6, 4, 1][div_6, 8, 1][span_6, 4, 1][div_6, 1, 3][div_6, 5, 3]|[div_6, 8, 3][div_6, 5, 3][div_6, 1, 3][span_6, 4, 1][div_6, 8, 1][div_6, 4, 1][div_6, 0, 1]" contenteditable>abc def <span dir=rtl id="span_6">hij opq</span> rst uvw</div>
 
@@ -354,11 +390,10 @@ where child_node_index is optional, default is the first child of the anchor nod
 
 <div id="div_13" dir=rtl class="test_move_by_word" title="[div_13, 7, 3][div_13, 4, 3][span_13, 3, 1][div_13, 8, 1][div_13, 4, 1][div_13, 0, 1]|[div_13, 0, 1][div_13, 4, 1][div_13, 8, 1][span_13, 3, 1][div_13, 4, 3]" contenteditable>אבד דעפ <span id="span_13">abc def</span>ווש כטז</div>
 
-<div id="div_14" dir=ltr class="test_move_by_word" title="[div_14, 0, 1][div_14, 3, 1][div_14, 8, 1][span_14, 4, 1][div_14, 3, 3]|[div_14, 7, 3][div_14, 3, 3][span_14, 4, 1][div_14, 8, 1][div_14, 4, 1][div_14, 0, 1]" contenteditable>אבד דעפ <span id="span_14">abc def</span>ווש כטז</div>
+<div id="div_14" dir=ltr class="test_move_by_word" title="[div_14, 0, 1][div_14, 3, 1][div_14, 8, 1][span_14, 4, 1][div_14, 3, 3]|[div_14, 7, 3][div_14, 3, 3][span_14, 4, 1][div_14, 8, 1][div_14, 3, 1][div_14, 0, 1]" contenteditable>אבד דעפ <span id="span_14">abc def</span>ווש כטז</div>
 
 <!-- FAILED -->
-<div id="div_15" dir=rtl class="test_move_by_word" title="[div_15, 11, 3][div_15, 8, 3][div_15, 4, 3][span_15, 3, 1][span_15, 4, 1][div_15, 12, 1][div_15, 8, 1][div_15, 4, 1][div_15, 0, 1]|[div_15, 0, 1][div_15, 4, 1][div_15, 8, 1][div_15, 12, 1][span_15, 4, 1][span_15, 3, 1][div_15, 4, 3][div_15, 8, 3]"
-contenteditable>אבד opq דעפ <span dir=ltr id="span_15">abc אאא def</span>ווש rst כטז</div>
+<div id="div_15" dir=rtl class="test_move_by_word" title="[div_15, 11, 3][div_15, 8, 3][div_15, 4, 3][span_15, 3, 1][span_15, 4, 1][div_15, 12, 1][div_15, 8, 1][div_15, 4, 1][div_15, 0, 1]|[div_15, 0, 1][div_15, 4, 1][div_15, 8, 1][div_15, 12, 1][span_15, 4, 1][span_15, 3, 1][div_15, 4, 3][div_15, 8, 3]" contenteditable>אבד opq דעפ <span dir=ltr id="span_15">abc אאא def</span>ווש rst כטז</div>
 
 <!-- FAILED, and wrong printing result -->
 <div id="div_16" dir=ltr class="test_move_by_word" title="[div_16, 0, 1][div_16, 4, 1][div_16, 8, 1][span_16, 8, 1][span_16, 7, 1][div_16, 12, 1][div_16, 11, 1][div_16, 4, 3][div_16, 8, 3][div_16, 11, 3]|[div_16, 11, 3][div_16, 8, 3][div_16, 4, 3][div_16, 11, 1][div_16, 12, 1][span_16, 7, 1][span_16, 8, 1][div_16, 8, 1][div_16, 4, 1][div_16, 0, 1]" contenteditable>אבד opq דעפ <span dir=rtl id="span_16">abc אאא def</span>ווש rst כטז</div>
@@ -370,8 +405,6 @@ contenteditable>אבד opq דעפ <span dir=ltr id="span_15">abc אאא def</spa
 
 <div id="div_19" dir=ltr class="test_move_by_word" title="[div_19, 0, 1][div_19, 4, 1][span_19, 4, 1][span_19, 7, 1]|[div_19, 3, 3][span_19, 7, 1][span_19, 4, 1][div_19, 4, 1][div_19, 0, 1]" contenteditable>aaa <span id="span_19">bbb אאא </span>ווש</div>
 
-<!-- The content in title means "startOffsetInCurrentNode movingDirectionByWord endingNode endingOffsetInEndingNode" -->
-<div id="div_100" contenteditable>אאא <span id="span_100" class="specific_test" title="1 left div_100 0">בב</span></div>
 </div>
 
 <pre id="console"></pre>
index 635315a2521d767f2c125dc796d61aa44d3b4986..e752690fd016054e70fcfb933643678497dee89a 100644 (file)
@@ -1,3 +1,17 @@
+2011-04-22  Xiaomei Ji  <xji@chromium.org>
+
+        Reviewed by Ryosuke Niwa.
+
+        move caret by word in visual order returns wrong result when caret itself is at word boundary.
+        https://bugs.webkit.org/show_bug.cgi?id=58504.
+
+        positionBeforeNextWord should take care that the current position is after current word.
+        positionAfterPreviousWord should take care that the current positin is before current word.
+
+        * editing/visible_units.cpp:
+        (WebCore::positionBeforeNextWord):
+        (WebCore::positionAfterPreviousWord):
+
 2011-04-19  Jer Noble  <jer.noble@apple.com>
 
         Reviewed by Daniel Bates.
index 934bd85e16c7648136a064e407b63a76e127eed4..ff683a5aaf46c18ab7a5d278db929c4388441e27 100644 (file)
@@ -1480,7 +1480,11 @@ static bool positionIsInsideBox(const VisiblePosition& wordBreak, const InlineBo
 
 static VisiblePosition positionBeforeNextWord(const VisiblePosition& position)
 {
-    VisiblePosition positionAfterCurrentWord = nextWordPosition(position);
+    VisiblePosition positionAfterCurrentWord;
+    if (nextWordPosition(previousWordPosition(position)) == position)
+        positionAfterCurrentWord = position;
+    else
+        positionAfterCurrentWord = nextWordPosition(position);
     VisiblePosition positionAfterNextWord = nextWordPosition(positionAfterCurrentWord);
     if (positionAfterCurrentWord == positionAfterNextWord)
         return positionAfterCurrentWord;
@@ -1489,7 +1493,11 @@ static VisiblePosition positionBeforeNextWord(const VisiblePosition& position)
 
 static VisiblePosition positionAfterPreviousWord(const VisiblePosition& position)
 {
-    VisiblePosition positionBeforeCurrentWord = previousWordPosition(position);
+    VisiblePosition positionBeforeCurrentWord;
+    if (previousWordPosition(nextWordPosition(position)) == position)
+        positionBeforeCurrentWord = position;
+    else
+        positionBeforeCurrentWord = previousWordPosition(position);
     VisiblePosition positionBeforePreviousWord = previousWordPosition(positionBeforeCurrentWord);
     if (positionBeforeCurrentWord == positionBeforePreviousWord)
         return positionBeforeCurrentWord;