2011-04-22 Xiaomei Ji <xji@chromium.org>
[WebKit-https.git] / LayoutTests / editing / selection / move-by-word-visually.html
index eaa551691e632baa615f9f68ab9def511dfc07a3..2c8e2ca3723432fbabe9e972d6feb409ad11a8d9 100644 (file)
@@ -32,15 +32,6 @@ function flushLog()
     document.getElementById("console").appendChild(document.createTextNode(messages.join("")));
 }
 
     document.getElementById("console").appendChild(document.createTextNode(messages.join("")));
 }
 
-function caretCoordinates()
-{
-    if (!window.textInputController)
-        return { x: 0, y :0 };
-    var caretRect = textInputController.firstRectForCharacterRange(textInputController.selectedRange()[0], 0);
-    return { x: caretRect[0], y: caretRect[1] };
-}
-
-
 function fold(string)
 {
     var result = "";
 function fold(string)
 {
     var result = "";
@@ -72,36 +63,106 @@ function logPositions(positions)
     log("]");
 }
 
     log("]");
 }
 
+function nodeOfWordBreak(nodeAndOffset)
+{
+    var node = document.getElementById(nodeAndOffset[0]).firstChild;
+    if (nodeAndOffset.length == 3) {
+        var childIndex = nodeAndOffset[2];
+        for (var i = 0; i < childIndex - 1; ++i) {
+            node = node.nextSibling;
+        }
+    }
+    return node;
+}
+
 var wordBreaks;
 
 var wordBreaks;
 
+function logWordBreak(index, first)
+{
+    var withNodeData = false;
+    var wordBreak = wordBreaks[index];
+    if (wordBreak.search(',') == -1)
+        log(wordBreak);
+    else {
+        var nodeAndOffset = wordBreak.split(',');
+        var node = nodeOfWordBreak(nodeAndOffset);
+
+        var differentNode = false;
+        if (first == false) {
+            differentNode = nodeOfWordBreak(nodeAndOffset) != nodeOfWordBreak(wordBreaks[index - 1].split(','));
+        
+        }
+
+        if (differentNode == true)
+            log("]");
+
+        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)
+{
+    if (wordBreak.search(',') == -1)
+        return position.offset == wordBreak;
+    else {
+        var nodeAndOffset = wordBreak.split(',');
+        return position.node == nodeOfWordBreak(nodeAndOffset) && position.offset == nodeAndOffset[1];
+    }
+}
+
 function validateData(positions)
 {
 function validateData(positions)
 {
+    var equal = true;
+    if (positions.length != wordBreaks.length)
+        equal = false;
     for (var i = 0; i < wordBreaks.length - 1; ++i) {
     for (var i = 0; i < wordBreaks.length - 1; ++i) {
-        if (positions[i].offset != wordBreaks[i + 1]) {
+        if (!positionEqualToWordBreak(positions[i], wordBreaks[i])) {
+            equal = false;
             break;
         }
     }
             break;
         }
     }
-    if (i != wordBreaks.length - 1 && positions[i] != wordBreaks[i]) {
+    if (equal == false) {
         log("    FAIL expected: [");
         log("    FAIL expected: [");
-        for (var i = 1; i < wordBreaks.length; ++i) {
-            log(wordBreaks[i] + ", ");
+        for (var i = 0; i < wordBreaks.length; ++i) {
+            logWordBreak(i, i == 0);
+            if (i != wordBreaks.length - 1)
+                log(", ");
         }
         }
-        log(wordBreaks[wordBreaks.length - 1] + "]");
+        log("]");
     }
 }
 
 function collectWordBreaks(test, searchDirection)
 {
     }
 }
 
 function collectWordBreaks(test, searchDirection)
 {
-    if (searchDirection == "right") {
-        if (test.getAttribute("dir") == 'ltr') 
-            wordBreaks = test.title.split("|")[0].split(" ");
-        else 
-            wordBreaks = test.title.split("|")[1].split(" ");
-    } else {
-        if (test.getAttribute("dir") == 'ltr') 
-            wordBreaks = test.title.split("|")[1].split(" ");
-        else 
-            wordBreaks = test.title.split("|")[0].split(" ");
+    var title;
+    if (searchDirection == "right") 
+        title = test.title.split("|")[0];
+    else
+        title = test.title.split("|")[1];
+
+    var pattern = /\[(.+?)\]/g;
+    var result;
+    wordBreaks = [];
+    while ((result = pattern.exec(title)) != null) {
+        wordBreaks.push(result[1]);
+    }
+    if (wordBreaks.length == 0) {
+        wordBreaks = title.split(" ");
+    }
+}
+
+function setPosition(sel, node, wordBreak)
+{
+    if (wordBreak.search(',') == -1)
+        sel.setPosition(node, wordBreak);
+    else {
+        var nodeAndOffset = wordBreak.split(',');
+        sel.setPosition(nodeOfWordBreak(nodeAndOffset), nodeAndOffset[1]);
     }
 }
 
     }
 }
 
@@ -109,22 +170,84 @@ function moveByWord(sel, test, searchDirection, dir)
 {
     log("Move " + searchDirection + " by one word\n");
     var prevOffset = sel.anchorOffset;
 {
     log("Move " + searchDirection + " by one word\n");
     var prevOffset = sel.anchorOffset;
-    var node = sel.anchorNode;
-    collectWordBreaks(test, searchDirection);
-    sel.setPosition(node, wordBreaks[0]);
+    var prevNode = sel.anchorNode;
     var positions = [];
     var positions = [];
-    for (var index = 1; index < wordBreaks.length; ++index) {
+    positions.push({ node: sel.anchorNode, offset: sel.anchorOffset });
+
+    while (1) {
         sel.modify("move", searchDirection, "-webkit-visual-word");
         sel.modify("move", searchDirection, "-webkit-visual-word");
-        positions.push({ node: sel.anchorNode, offset: sel.anchorOffset, point: caretCoordinates() });
-        sel.setPosition(node, wordBreaks[index]);
-    }
-    sel.modify("move", searchDirection, "-webkit-visual-word");
-    positions.push({ node: sel.anchorNode, offset: sel.anchorOffset, point: caretCoordinates() });
+        if (prevNode == sel.anchorNode && prevOffset == sel.anchorOffset)
+            break;
+        positions.push({ node: sel.anchorNode, offset: sel.anchorOffset });
+        prevNode = sel.anchorNode;
+        prevOffset = sel.anchorOffset;
+    };
     logPositions(positions);
     logPositions(positions);
+    collectWordBreaks(test, searchDirection);
     validateData(positions);
     log("\n");
 }
 
     validateData(positions);
     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.
 function moveByWordForEveryPosition(sel, test, dir)
 {
     // Check ctrl-right-arrow works for every position.
@@ -133,12 +256,18 @@ function moveByWordForEveryPosition(sel, test, dir)
     if (dir == "rtl")
         direction = "left";    
     moveByWord(sel, test, direction, 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.
     if (dir == "ltr")
         direction = "left";
     else
         direction = "right";    
     moveByWord(sel, test, direction, dir);    
     // Check ctrl-left-arrow works for every position.
     if (dir == "ltr")
         direction = "left";
     else
         direction = "right";    
     moveByWord(sel, test, direction, dir);    
+    sel.modify("move", "forward", "lineBoundary");
+    moveByWordOnEveryChar(sel, test, direction, dir);
 }
 
 function runMoveLeftRight(tests, unit)
 }
 
 function runMoveLeftRight(tests, unit)
@@ -156,39 +285,8 @@ function runMoveLeftRight(tests, unit)
             log("Test " + (i + 1) + ", RTL:\n");
             moveByWordForEveryPosition(sel, tests[i], "rtl");
         }
             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, point: caretCoordinates() });
-
-        sel.modify("move", movingDirection, "-webkit-visual-word");
-        positions.push({ node: sel.anchorNode, offset: sel.anchorOffset, point: caretCoordinates() });
-
-        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";
 }
 
     document.getElementById("testMoveByWord").style.display = "none";
 }
 
@@ -196,9 +294,6 @@ function runTest() {
     log("\n======== Move By Word ====\n");
     var tests = document.getElementsByClassName("test_move_by_word");
     runMoveLeftRight(tests, "word");
     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() {
 }
 
 onload = function() {
@@ -215,19 +310,101 @@ if (window.layoutTestController)
 </head>
 <body>
 <div id="testMoveByWord">
 </head>
 <body>
 <div id="testMoveByWord">
-<!-- The numbers put in title are starting word boundaries.
-The numbers printed out in the output are ending word boundaries. -->
-<div dir=ltr class="test_move_by_word" title="0 4 8 12 16 19|19 16 12 8 4 0" contenteditable>abc def hij opq rst</div>
-<div dir=rtl class="test_move_by_word" title="0 15 11 7 3 19|19 3 7 11 15 0" contenteditable>abc def hij opq rst</div>
-<div dir=ltr class="test_move_by_word" title="0 15 11 7 3 19|19 3 7 11 15 0" contenteditable>ששש נננ בבב גגג קקק</div>
-<div dir=rtl class="test_move_by_word" title="0 4 8 12 16 19|19 16 12 8 4 0" contenteditable>ששש נננ בבב גגג קקק</div>
-<div dir=ltr class="test_move_by_word" title="0 4 8 11 16 20 23|23 20 16 11 8 4 0" contenteditable>abc def שנב סטז uvw xyz</div>
-<div dir=rtl class="test_move_by_word" title="0 3 8 12 16 19 23|23 19 16 12 8 3 0" contenteditable>abc def שנב סטז uvw xyz</div>
+<!-- 
+Title saves the word breaks.
+The format of title is "xxx|xxxx".
+
+The sequence on the left of "|" is word boundaries when moving caret from left to right.
+The sequence on the right of "|" is word boundaries when moving caret from right to left.
+
+If there is a single node in the line, the sequence are offsets.
+If there are multiple nodes in the line, the sequence is array of [anchor_node_id, offset, child_node_index], 
+where child_node_index is optional, default is the first child of the anchor node.
+-->
+<div dir=ltr class="test_move_by_word" title="0 4 8 12 16|19 16 12 8 4 0" contenteditable>abc def hij opq rst</div>
+
+<!-- pure English -->
+<div dir=ltr class="test_move_by_word" title="0 4 8 12 16|19 16 12 8 4 0" contenteditable>abc def hij opq rst</div>
+<div dir=rtl class="test_move_by_word" title="19 3 7 11 15 0|0 15 11 7 3" contenteditable>abc def hij opq rst</div>
+
+<!-- pure Hebrew -->
+<div dir=ltr class="test_move_by_word" title="0 15 11 7 3|19 3 7 11 15 0" contenteditable>ששש נננ בבב גגג קקק</div>
+<div dir=rtl class="test_move_by_word" title="19 16 12 8 4 0|0 4 8 12 16" contenteditable>ששש נננ בבב גגג קקק</div>
+
+<!-- bidi text -->
+<!-- English Hebrew English -->
+<div dir=ltr class="test_move_by_word" title="0 4 8 12 19 15 24 28 32|35 32 28 24 15 19 12 8 4 0" contenteditable>abc def hij אאא בבב צצצ opr uvw xyz</div>
+<div dir=rtl class="test_move_by_word" title="35 27 31 24 20 16 12 3 7 0|0 7 3 12 16 20 24 31 27" contenteditable>abc def hij אאא בבב צצצ opr uvw xyz</div>
+
+<div dir=ltr class="test_move_by_word" title="0 4 8 11 16 20|23 20 16 11 8 4 0" contenteditable>abc def שנב סטז uvw xyz</div>
+<div dir=rtl class="test_move_by_word" title="23 19 16 12 8 3 0|0 3 8 12 16 19" contenteditable>abc def שנב סטז uvw xyz</div>
+
+<div dir=ltr class="test_move_by_word" title="0 4 8|11 8 4 0" contenteditable>aaa אאא bbb</div>
+<div dir=rtl class="test_move_by_word" title="11 8 4 0|0 4 8 11" contenteditable>aaa אאא bbb</div>
+
+<!-- Hebrew English Hebrew -->
+<div dir=ltr class="test_move_by_word" title="0 7 3 12 16 20 24 31 27|35 27 31 24 20 16 12 3 7 0" contenteditable>אאא בבב צצצ aaa bbb ccc דדד עעע פפפ</div>
+<div dir=rtl class="test_move_by_word" title="35 32 28 24 15 19 12 8 4 0|0 4 8 12 19 15 24 28 32" contenteditable>אאא בבב צצצ aaa bbb ccc דדד עעע פפפ</div>
+
+<div dir=ltr class="test_move_by_word" title="0 3 8 12 16 19|23 19 16 12 8 3 0" contenteditable>אאא בבב aaa bbb צצצ דדד</div>
+<div dir=rtl class="test_move_by_word" title="23 20 16 11 8 4 0|0 4 8 11 16 20" contenteditable>אאא בבב aaa bbb צצצ דדד</div>
+
 <div dir=ltr class="test_move_by_word" title="0 4 8 11|11 8 4 0" contenteditable>שנב abc סטז</div>
 <div dir=ltr class="test_move_by_word" title="0 4 8 11|11 8 4 0" contenteditable>שנב abc סטז</div>
-<div dir=rtl class="test_move_by_word" title="0 4 8 11|11 8 4 0" contenteditable>שנב abc סטז</div>
+<div dir=rtl class="test_move_by_word" title="11 8 4 0|0 4 8" contenteditable>שנב abc סטז</div>
+
+<!-- multiple spaces between word. 
+     FAILED: word break between "def" and "hij" is unreachable.
+-->
+<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>
+<div dir=rtl id="div_2" class="test_move_by_word" title="[span_2, 2][div_2, 4][div_2, 0]|[div_2, 0][div_2, 4]" contenteditable>אאא <span id="span_2">בב</span></div>
+
+<!-- pure English in inline element with same or different directionality from its parent -->
+<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][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. 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>
+
+<!-- pure Hebrew in inline element with same or different directionality from its parent -->
+
+<div id="div_7" dir=rtl class="test_move_by_word" title="[div_7, 7, 3][div_7, 4, 3][span_7, 4, 1][div_7, 8, 1][div_7, 4, 1][div_7, 0, 1]|[div_7, 0, 1][div_7, 4, 1][div_7, 8, 1][span_7, 4, 1][div_7, 4, 3]" contenteditable>אבד דעפ <span dir=ltr id="span_7">היח ופק</span>ווש כטז</div>
+
+<div id="div_8" dir=ltr class="test_move_by_word" title="[div_8, 0, 1][div_8, 3, 3][span_8, 3, 1][div_8, 7, 1][div_8, 3, 1]|[div_8, 7, 3][div_8, 3, 1][div_8, 7, 1][span_8, 3, 1][div_8, 3, 3][div_8, 0, 1]" contenteditable>אבד דעפ <span dir=rtl id="span_8">היח ופק</span>ווש כטז</div>
+
+<div id="div_9" dir=rtl class="test_move_by_word" title="[div_9, 7, 3][div_9, 4, 3][span_9, 4, 1][div_9, 8, 1][div_9, 4, 1][div_9, 0, 1]|[div_9, 0, 1][div_9, 4, 1][div_9, 8, 1][span_9, 4, 1][div_9, 4, 3]" contenteditable>אבד דעפ <span id="span_9">היח ופק</span>ווש כטז</div>
+
+<div id="div_10" dir=ltr class="test_move_by_word" title="[div_10, 0, 1][div_10, 3, 3][span_10, 3, 1][div_10, 7, 1][div_10, 3, 1]|[div_10, 7, 3][div_10, 3, 1][div_10, 7, 1][span_10, 3, 1][div_10, 3, 3][div_10, 0, 1]" contenteditable>אבד דעפ <span id="span_10">היח ופק</span>ווש כטז</div>
+
+<!-- bidi in inline element with same or different directionality from its parent -->
+<div id="div_11" dir=rtl class="test_move_by_word" title="[div_11, 7, 3][div_11, 4, 3][span_11, 3, 1][div_11, 8, 1][div_11, 4, 1][div_11, 0, 1]|[div_11, 0, 1][div_11, 4, 1][div_11, 8, 1][span_11, 3, 1][div_11, 4, 3]" contenteditable>אבד דעפ <span dir=ltr id="span_11">abc def</span>ווש כטז</div>
+
+<!-- FAIL -->
+<div id="div_12" dir=ltr class="test_move_by_word" title="[div_12, 0, 1][div_12, 3, 3][div_12, 8, 1][span_12, 4, 1][div_12, 7, 1][div_12, 3, 1]|[div_12, 7, 3][div_12, 3, 1][div_12, 7, 1][span_12, 4, 1][div_12, 8, 1][div_12, 3, 3][div_12, 0]" contenteditable>אבד דעפ <span dir=rtl id="span_12">abc def</span>ווש כטז</div>
+
+<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, 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>
+
+<!-- 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>
+
+<!-- FAILED -->
+<div id="div_17" dir=rtl class="test_move_by_word" title="[div_17, 11, 3][div_17, 8, 3][div_17, 4, 3][span_17, 8, 1][span_17, 4, 1][div_17, 12, 1][div_17, 8, 1][div_17, 4, 1][div_17, 0, 1]|[div_17, 0, 1][div_17, 4, 1][div_17, 8, 1][div_17, 12, 1][span_17, 4, 1][span_17, 8, 1][div_17, 4, 3][div_17, 8, 3]" contenteditable>אבד opq דעפ <span id="span_17">abc אאא def</span>ווש rst כטז</div>
+
+<div id="div_18" dir=ltr class="test_move_by_word" title="[div_18, 0, 1][div_18, 4, 1][div_18, 8, 1][div_18, 12, 1][span_18, 4, 1][span_18, 8, 1][div_18, 4, 3][div_18, 8, 3][div_18, 11, 3]|[div_18, 11, 3][div_18, 8, 3][div_18, 4, 3][span_18, 8, 1][span_18, 4, 1][div_18, 12, 1][div_18, 8, 1][div_18, 4, 1][div_18, 0, 1]" contenteditable>אבד opq דעפ <span id="span_18">abc אאא def</span>ווש rst כטז</div>
+
+<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_1" contenteditable>אאא <span id="span_1" class="specific_test" title="1 left div_1 0">בב</span></div>
 </div>
 
 <pre id="console"></pre>
 </div>
 
 <pre id="console"></pre>