Changeset 84425 in webkit
- Timestamp:
- Apr 20, 2011 3:20:39 PM (13 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r84422 r84425 1 2011-04-20 Xiaomei Ji <xji@chromium.org> 2 3 Reviewed by Ryosuke Niwa. 4 5 Continue (3rd) experiment with moving caret by word in visual order. 6 https://bugs.webkit.org/show_bug.cgi?id=58294 7 8 * editing/selection/move-by-word-visually-expected.txt: 9 * editing/selection/move-by-word-visually.html: 10 1 11 2011-04-20 Cris Neckar <cdn@chromium.org> 2 12 -
trunk/LayoutTests/editing/selection/move-by-word-visually-expected.txt
r84147 r84425 3 3 Test 1, LTR: 4 4 Move right by one word 5 "abc def hij opq rst"[0, 8, 12, 16, 16, 19] FAIL expected: [4, 8, 12, 16, 19, 19]5 "abc def hij opq rst"[0, 4, 8, 12, 16] 6 6 Move left by one word 7 "abc def hij opq rst"[16, 12, 8, 4, 0, 0] 8 Test 2, RTL: 7 "abc def hij opq rst"[19, 16, 12, 8, 4, 0] 8 Test 2, LTR: 9 Move right by one word 10 "abc def hij opq rst"[0, 4, 8, 12, 16] 9 11 Move left by one word 10 "abc def hij opq rst"[0, 11, 7, 3, 3, 19] FAIL expected: [15, 11, 7, 3, 19, 19] 12 "abc def hij opq rst"[19, 16, 12, 8, 4, 0] 13 Test 3, RTL: 14 Move left by one word 15 "abc def hij opq rst"[0, 15, 11, 7, 3] 11 16 Move right by one word 12 "abc def hij opq rst"[19, 7, 11, 15, 0, 0] FAIL expected: [3, 7, 11, 15, 0, 0]13 Test 3, LTR:17 "abc def hij opq rst"[19, 3, 7, 11, 15, 0] 18 Test 4, LTR: 14 19 Move right by one word 15 "ZZZ QQQ BBB CCC XXX"[0, 1 1, 7, 3, 3, 19] FAIL expected: [15, 11, 7, 3, 19, 19]20 "ZZZ QQQ BBB CCC XXX"[0, 15, 11, 7, 3] 16 21 Move left by one word 17 "ZZZ QQQ BBB CCC XXX"[19, 7, 11, 15, 0, 0] FAIL expected: [3, 7, 11, 15, 0, 0]18 Test 4, RTL:22 "ZZZ QQQ BBB CCC XXX"[19, 3, 7, 11, 15, 0] 23 Test 5, RTL: 19 24 Move left by one word 20 "ZZZ QQQ BBB CCC XXX"[0, 8, 12, 16, 16, 19] FAIL expected: [4, 8, 12, 16, 19, 19]25 "ZZZ QQQ BBB CCC XXX"[0, 4, 8, 12, 16] 21 26 Move right by one word 22 "ZZZ QQQ BBB CCC XXX"[1 6, 12, 8, 4, 0, 0]23 Test 5, LTR:27 "ZZZ QQQ BBB CCC XXX"[19, 16, 12, 8, 4, 0] 28 Test 6, LTR: 24 29 Move right by one word 25 "abc def ZQB RIG uvw xyz"[0, 4, 8, 11, 20, 20, 23] FAIL expected: [4, 8, 11, 16, 20, 23, 23]30 "abc def hij AAA BBB WWW opr uvw xyz"[0, 4, 8, 12, 19, 15, 24, 28, 32] 26 31 Move left by one word 27 "abc def ZQB RIG uvw xyz"[20, 16, 4, 8, 4, 0, 0] FAIL expected: [20, 16, 11, 8, 4, 0, 0]28 Test 6, RTL:32 "abc def hij AAA BBB WWW opr uvw xyz"[35, 32, 28, 24, 15, 19, 12, 8, 4, 0] 33 Test 7, RTL: 29 34 Move left by one word 30 "abc def ZQB RIG uvw xyz"[0, 3, 12, 12, 16, 19, 23] FAIL expected: [3, 8, 12, 16, 19, 23, 23]35 "abc def hij AAA BBB WWW opr uvw xyz"[0, 7, 3, 12, 16, 20, 24, 31, 27] 31 36 Move right by one word 32 "abc def ZQB RIG uvw xyz"[12, 16, 12, 8, 8, 0, 0] FAIL expected: [19, 16, 12, 8, 3, 0, 0]33 Test 7, LTR:37 "abc def hij AAA BBB WWW opr uvw xyz"[35, 27, 31, 24, 20, 16, 12, 3, 7, 0] 38 Test 8, LTR: 34 39 Move right by one word 35 " ZQB abc RIG"[0, 4, 8, 11] FAIL expected: [4, 8, 11, 11]40 "abc def ZQB RIG uvw xyz"[0, 4, 8, 11, 16, 20] 36 41 Move left by one word 37 " ZQB abc RIG"[4, 4, 4, 0] FAIL expected: [8, 4, 0, 0]38 Test 8, RTL:42 "abc def ZQB RIG uvw xyz"[23, 20, 16, 11, 8, 4, 0] 43 Test 9, RTL: 39 44 Move left by one word 40 " ZQB abc RIG"[0, 4, 8, 11] FAIL expected: [4, 8, 11, 11]45 "abc def ZQB RIG uvw xyz"[0, 3, 8, 12, 16, 19] 41 46 Move right by one word 42 "ZQB abc RIG"[8, 0, 0, 0] FAIL expected: [8, 4, 0, 0] 47 "abc def ZQB RIG uvw xyz"[23, 19, 16, 12, 8, 3, 0] 48 Test 10, LTR: 49 Move right by one word 50 "aaa AAA bbb"[0, 4, 8] 51 Move left by one word 52 "aaa AAA bbb"[11, 8, 4, 0] 53 Test 11, RTL: 54 Move left by one word 55 "aaa AAA bbb"[0, 4, 8, 11] 56 Move right by one word 57 "aaa AAA bbb"[11, 8, 4, 0] 58 Test 12, LTR: 59 Move right by one word 60 "AAA BBB WWW aaa bbb ccc DDD SSS UUU"[0, 7, 3, 12, 16, 20, 24, 31, 27] 61 Move left by one word 62 "AAA BBB WWW aaa bbb ccc DDD SSS UUU"[35, 27, 31, 24, 20, 16, 12, 3, 7, 0] 63 Test 13, RTL: 64 Move left by one word 65 "AAA BBB WWW aaa bbb ccc DDD SSS UUU"[0, 4, 8, 12, 19, 15, 24, 28, 32] 66 Move right by one word 67 "AAA BBB WWW aaa bbb ccc DDD SSS UUU"[35, 32, 28, 24, 15, 19, 12, 8, 4, 0] 68 Test 14, LTR: 69 Move right by one word 70 "AAA BBB aaa bbb WWW DDD"[0, 3, 8, 12, 16, 19] 71 Move left by one word 72 "AAA BBB aaa bbb WWW DDD"[23, 19, 16, 12, 8, 3, 0] 73 Test 15, RTL: 74 Move left by one word 75 "AAA BBB aaa bbb WWW DDD"[0, 4, 8, 11, 16, 20] 76 Move right by one word 77 "AAA BBB aaa bbb WWW DDD"[23, 20, 16, 11, 8, 4, 0] 78 Test 16, LTR: 79 Move right by one word 80 "ZQB abc RIG"[0, 4, 8, 11] 81 Move left by one word 82 "ZQB abc RIG"[11, 8, 4, 0] 83 Test 17, RTL: 84 Move left by one word 85 "ZQB abc RIG"[0, 4, 8] 86 Move right by one word 87 "ZQB abc RIG"[11, 8, 4, 0] 88 Test 18, LTR: 89 Move right by one word 90 "abc def hij opq"[0, 4, 15] FAIL expected: [0, 4, 11, 15] 91 Move left by one word 92 "abc def hij opq"[18, 15, 4, 0] FAIL expected: [18, 15, 11, 4, 0] 93 Test 19, LTR: 94 Move right by one word 95 "AAA "[0, 3] 96 Move left by one word 97 "BB"[2], "AAA "[3, 0] 98 Test 20, RTL: 99 Move left by one word 100 "AAA "[0, 4] 101 Move right by one word 102 "BB"[2], "AAA "[4, 0] 103 Test 21, LTR: 104 Move right by one word 105 "abc def "[0, 4, 8], "hij opq"[4], " rst uvw"[1, 5] 106 Move left by one word 107 " rst uvw"[8, 5, 1], "hij opq"[4], "abc def "[8, 4, 0] 108 Test 22, RTL: 109 Move left by one word 110 "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] 111 Move right by one word 112 " 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] 113 Test 23, RTL: 114 Move left by one word 115 "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] 116 Move right by one word 117 " 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] 118 Test 24, LTR: 119 Move right by one word 120 "abc def "[0, 4, 8], "hij opq"[4], " rst uvw"[1, 5] 121 Move left by one word 122 " rst uvw"[8, 5, 1], "hij opq"[4], "abc def "[8, 4, 0] 123 Test 25, RTL: 124 Move left by one word 125 "ABD DSU "[0, 4, 8], "EJH FUX"[4], "FFZ LIG"[4] 126 Move right by one word 127 "FFZ LIG"[7, 4], "EJH FUX"[4], "ABD DSU "[8, 4, 0] 128 Test 26, LTR: 129 Move right by one word 130 "ABD DSU "[0], "FFZ LIG"[3], "EJH FUX"[3], "ABD DSU "[7, 3] 131 Move left by one word 132 "FFZ LIG"[7], "ABD DSU "[3, 7], "EJH FUX"[3], "FFZ LIG"[3], "ABD DSU "[0] 133 Test 27, RTL: 134 Move left by one word 135 "ABD DSU "[0, 4, 8], "EJH FUX"[4], "FFZ LIG"[4] 136 Move right by one word 137 "FFZ LIG"[7, 4], "EJH FUX"[4], "ABD DSU "[8, 4, 0] 138 Test 28, LTR: 139 Move right by one word 140 "ABD DSU "[0], "FFZ LIG"[3], "EJH FUX"[3], "ABD DSU "[7, 3] 141 Move left by one word 142 "FFZ LIG"[7], "ABD DSU "[3, 7], "EJH FUX"[3], "FFZ LIG"[3], "ABD DSU "[0] 143 Test 29, RTL: 144 Move left by one word 145 "ABD DSU "[0, 4, 8], "abc def"[3], "FFZ LIG"[4] 146 Move right by one word 147 "FFZ LIG"[7, 4], "abc def"[3], "ABD DSU "[8, 4, 0] 148 Test 30, LTR: 149 Move right by one word 150 "ABD DSU "[0], "FFZ LIG"[3], "ABD DSU "[8], "abc def"[4], "ABD DSU "[7, 3] 151 Move left by one word 152 "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] 153 Test 31, RTL: 154 Move left by one word 155 "ABD DSU "[0, 4, 8], "abc def"[3], "FFZ LIG"[4] 156 Move right by one word 157 "FFZ LIG"[7, 4], "abc def"[3], "ABD DSU "[8, 4, 0] 158 Test 32, LTR: 159 Move right by one word 160 "ABD DSU "[0, 3, 8], "abc def"[4], "FFZ LIG"[3] 161 Move left by one word 162 "FFZ LIG"[7, 3], "abc def"[4], "ABD DSU "[8, 4, 0] 163 Test 33, RTL: 164 Move left by one word 165 "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] 166 Move right by one word 167 "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] 168 Test 34, LTR: 169 Move right by one word 170 "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] 171 Move left by one word 172 "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] 173 Test 35, RTL: 174 Move left by one word 175 "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] 176 Move right by one word 177 "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] 178 Test 36, LTR: 179 Move right by one word 180 "ABD opq DSU "[0, 4, 8, 12], "abc AAA def"[4, 8], "FFZ rst LIG"[4, 8, 11] 181 Move left by one word 182 "FFZ rst LIG"[11, 8, 4], "abc AAA def"[8, 4], "ABD opq DSU "[12, 8, 4, 0] 183 Test 37, LTR: 184 Move right by one word 185 "aaa "[0, 4], "bbb AAA "[4, 7] 186 Move left by one word 187 "FFZ"[3], "bbb AAA "[7, 4], "aaa "[4, 0] 43 188 44 189 ======== Move By Word Specific Test ==== -
trunk/LayoutTests/editing/selection/move-by-word-visually.html
r84147 r84425 33 33 } 34 34 35 function caretCoordinates()36 {37 if (!window.textInputController)38 return { x: 0, y :0 };39 var caretRect = textInputController.firstRectForCharacterRange(textInputController.selectedRange()[0], 0);40 return { x: caretRect[0], y: caretRect[1] };41 }42 43 44 35 function fold(string) 45 36 { … … 73 64 } 74 65 66 function nodeOfWordBreak(nodeAndOffset) 67 { 68 var node = document.getElementById(nodeAndOffset[0]).firstChild; 69 if (nodeAndOffset.length == 3) { 70 var childIndex = nodeAndOffset[2]; 71 for (var i = 0; i < childIndex - 1; ++i) { 72 node = node.nextSibling; 73 } 74 } 75 return node; 76 } 77 75 78 var wordBreaks; 76 79 80 function logWordBreak(index) 81 { 82 var wordBreak = wordBreaks[index]; 83 if (wordBreak.search(',') == -1) 84 log(wordBreak); 85 else { 86 var nodeAndOffset = wordBreak.split(','); 87 var node = nodeOfWordBreak(nodeAndOffset); 88 89 var differentNode = false; 90 if (index != 0) { 91 differentNode = nodeOfWordBreak(nodeAndOffset) != nodeOfWordBreak(wordBreaks[index - 1].split(',')); 92 93 } 94 if (differentNode == true) 95 log("]"); 96 if (index == 0 || differentNode == true) 97 log((node instanceof Text ? '"' + fold(node.data) + '"' : "<" + node.tagName + ">") + "["); 98 log(nodeAndOffset[1]); 99 } 100 } 101 102 function positionEqualToWordBreak(position, wordBreak) 103 { 104 if (wordBreak.search(',') == -1) 105 return position.offset == wordBreak; 106 else { 107 var nodeAndOffset = wordBreak.split(','); 108 return position.node == nodeOfWordBreak(nodeAndOffset) && position.offset == nodeAndOffset[1]; 109 } 110 } 111 77 112 function validateData(positions) 78 113 { 114 var equal = true; 115 if (positions.length != wordBreaks.length) 116 equal = false; 79 117 for (var i = 0; i < wordBreaks.length - 1; ++i) { 80 if (positions[i].offset != wordBreaks[i + 1]) { 118 if (!positionEqualToWordBreak(positions[i], wordBreaks[i])) { 119 equal = false; 81 120 break; 82 121 } 83 122 } 84 if ( i != wordBreaks.length - 1 && positions[i] != wordBreaks[i]) {123 if (equal == false) { 85 124 log(" FAIL expected: ["); 86 for (var i = 1; i < wordBreaks.length; ++i) { 87 log(wordBreaks[i] + ", "); 88 } 89 log(wordBreaks[wordBreaks.length - 1] + "]"); 125 for (var i = 0; i < wordBreaks.length; ++i) { 126 logWordBreak(i); 127 if (i != wordBreaks.length - 1) 128 log(", "); 129 } 130 log("]"); 90 131 } 91 132 } … … 93 134 function collectWordBreaks(test, searchDirection) 94 135 { 95 if (searchDirection == "right") { 96 if (test.getAttribute("dir") == 'ltr') 97 wordBreaks = test.title.split("|")[0].split(" "); 98 else 99 wordBreaks = test.title.split("|")[1].split(" "); 100 } else { 101 if (test.getAttribute("dir") == 'ltr') 102 wordBreaks = test.title.split("|")[1].split(" "); 103 else 104 wordBreaks = test.title.split("|")[0].split(" "); 136 var title; 137 if (searchDirection == "right") 138 title = test.title.split("|")[0]; 139 else 140 title = test.title.split("|")[1]; 141 142 var pattern = /\[(.+?)\]/g; 143 var result; 144 wordBreaks = []; 145 while ((result = pattern.exec(title)) != null) { 146 wordBreaks.push(result[1]); 147 } 148 if (wordBreaks.length == 0) { 149 wordBreaks = title.split(" "); 150 } 151 } 152 153 function setPosition(sel, node, wordBreak) 154 { 155 if (wordBreak.search(',') == -1) 156 sel.setPosition(node, wordBreak); 157 else { 158 var nodeAndOffset = wordBreak.split(','); 159 sel.setPosition(nodeOfWordBreak(nodeAndOffset), nodeAndOffset[1]); 105 160 } 106 161 } … … 110 165 log("Move " + searchDirection + " by one word\n"); 111 166 var prevOffset = sel.anchorOffset; 112 var node = sel.anchorNode; 167 var prevNode = sel.anchorNode; 168 var positions = []; 169 positions.push({ node: sel.anchorNode, offset: sel.anchorOffset }); 170 171 while (1) { 172 sel.modify("move", searchDirection, "-webkit-visual-word"); 173 if (prevNode == sel.anchorNode && prevOffset == sel.anchorOffset) 174 break; 175 positions.push({ node: sel.anchorNode, offset: sel.anchorOffset }); 176 prevNode = sel.anchorNode; 177 prevOffset = sel.anchorOffset; 178 }; 179 logPositions(positions); 113 180 collectWordBreaks(test, searchDirection); 114 sel.setPosition(node, wordBreaks[0]);115 var positions = [];116 for (var index = 1; index < wordBreaks.length; ++index) {117 sel.modify("move", searchDirection, "-webkit-visual-word");118 positions.push({ node: sel.anchorNode, offset: sel.anchorOffset, point: caretCoordinates() });119 sel.setPosition(node, wordBreaks[index]);120 }121 sel.modify("move", searchDirection, "-webkit-visual-word");122 positions.push({ node: sel.anchorNode, offset: sel.anchorOffset, point: caretCoordinates() });123 logPositions(positions);124 181 validateData(positions); 125 182 log("\n"); … … 134 191 direction = "left"; 135 192 moveByWord(sel, test, direction, dir); 193 194 sel.modify("move", "forward", "lineBoundary"); 136 195 // Check ctrl-left-arrow works for every position. 137 196 if (dir == "ltr") … … 177 236 var positions = []; 178 237 sel.setPosition(tests[i].firstChild, startOffset); 179 positions.push({ node: sel.anchorNode, offset: sel.anchorOffset , point: caretCoordinates()});238 positions.push({ node: sel.anchorNode, offset: sel.anchorOffset }); 180 239 181 240 sel.modify("move", movingDirection, "-webkit-visual-word"); 182 positions.push({ node: sel.anchorNode, offset: sel.anchorOffset , point: caretCoordinates()});241 positions.push({ node: sel.anchorNode, offset: sel.anchorOffset }); 183 242 184 243 logPositions(positions); … … 216 275 <body> 217 276 <div id="testMoveByWord"> 218 <!-- The numbers put in title are starting word boundaries. 219 The numbers printed out in the output are ending word boundaries. --> 220 <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> 221 <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> 222 <div dir=ltr class="test_move_by_word" title="0 15 11 7 3 19|19 3 7 11 15 0" contenteditable>ששש נננ בבב גגג קקק</div> 223 <div dir=rtl class="test_move_by_word" title="0 4 8 12 16 19|19 16 12 8 4 0" contenteditable>ששש נננ בבב גגג קקק</div> 224 <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> 225 <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> 277 <!-- 278 Title saves the word breaks. 279 The format of title is "xxx|xxxx". 280 281 The sequence on the left of "|" is word boundaries when moving caret from left to right. 282 The sequence on the right of "|" is word boundaries when moving caret from right to left. 283 284 If there is a single node in the line, the sequence are offsets. 285 If there are multiple nodes in the line, the sequence is array of [anchor_node_id, offset, child_node_index], 286 where child_node_index is optional, default is the first child of the anchor node. 287 --> 288 <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> 289 290 <!-- pure English --> 291 <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> 292 <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> 293 294 <!-- pure Hebrew --> 295 <div dir=ltr class="test_move_by_word" title="0 15 11 7 3|19 3 7 11 15 0" contenteditable>ששש נננ בבב גגג קקק</div> 296 <div dir=rtl class="test_move_by_word" title="19 16 12 8 4 0|0 4 8 12 16" contenteditable>ששש נננ בבב גגג קקק</div> 297 298 <!-- bidi text --> 299 <!-- English Hebrew English --> 300 <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> 301 <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> 302 303 <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> 304 <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> 305 306 <div dir=ltr class="test_move_by_word" title="0 4 8|11 8 4 0" contenteditable>aaa אאא bbb</div> 307 <div dir=rtl class="test_move_by_word" title="11 8 4 0|0 4 8 11" contenteditable>aaa אאא bbb</div> 308 309 <!-- Hebrew English Hebrew --> 310 <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> 311 <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> 312 313 <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> 314 <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> 315 226 316 <div dir=ltr class="test_move_by_word" title="0 4 8 11|11 8 4 0" contenteditable>שנב abc סטז</div> 227 <div dir=rtl class="test_move_by_word" title="0 4 8 11|11 8 4 0" contenteditable>שנב abc סטז</div> 317 <div dir=rtl class="test_move_by_word" title="11 8 4 0|0 4 8" contenteditable>שנב abc סטז</div> 318 319 <!-- multiple spaces between word. 320 FAILED: word break between "def" and "hij" is unreachable. 321 --> 322 <div dir=ltr class="test_move_by_word" title="0 4 11 15|18 15 11 4 0" contenteditable>abc def hij opq</div> 323 324 <!-- Inline element --> 325 <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> 326 <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> 327 328 <!-- pure English in inline element with same or different directionality from its parent --> 329 <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> 330 331 <!-- FAILED --> 332 <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> 333 334 <!-- FAILED --> 335 <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> 336 337 <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> 338 339 <!-- pure Hebrew in inline element with same or different directionality from its parent --> 340 341 <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> 342 343 <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> 344 345 <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> 346 347 <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> 348 349 <!-- bidi in inline element with same or different directionality from its parent --> 350 <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> 351 352 <!-- FAIL --> 353 <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> 354 355 <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> 356 357 <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> 358 359 <!-- FAILED --> 360 <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]" 361 contenteditable>אבד opq דעפ <span dir=ltr id="span_15">abc אאא def</span>ווש rst כטז</div> 362 363 <!-- FAILED, and wrong printing result --> 364 <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> 365 366 <!-- FAILED --> 367 <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> 368 369 <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> 370 371 <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> 228 372 229 373 <!-- The content in title means "startOffsetInCurrentNode movingDirectionByWord endingNode endingOffsetInEndingNode" --> 230 <div id="div_1 " contenteditable>אאא <span id="span_1" class="specific_test" title="1 left div_10">בב</span></div>374 <div id="div_100" contenteditable>אאא <span id="span_100" class="specific_test" title="1 left div_100 0">בב</span></div> 231 375 </div> 232 376 -
trunk/Source/WebCore/ChangeLog
r84422 r84425 1 2011-04-20 Xiaomei Ji <xji@chromium.org> 2 3 Reviewed by Ryosuke Niwa. 4 5 Continue (3rd) experiment with moving caret by word in visual order. 6 https://bugs.webkit.org/show_bug.cgi?id=58294 7 8 This patch along with r82588 and r83483 implements moving caret by 9 word in visual order. 10 11 The overall algorithm is: 12 1. First get the InlineBox and offset of the pass-in VisiblePosition. 13 2. Based on the position (left boundary, middle, right boundary) of the offset and the 14 direction of the movement, look for visually adjacent word breaks. 15 2.1 If the offset is the minimum offset of the box, 16 return the rightmost word boundary in previous boxes if moving left. 17 return the leftmost word boundary in box and next boxes if moving right. 18 2.2 Similar for the case when offset is at the maximum offset of the box. 19 2.3 When offset is inside the box (not at boundaries), first find the previousWordPosition 20 or nextWordPosition based on the directionality of the box. If this word break position 21 is also inside the same box, return it. Otherwise (the nextWordPosition or 22 previousWordPosition is not in the same box or is at the box boundary), collect all the 23 word breaks in the box and search for the one closest to the input "offset" based on 24 box directionality, block directionality, and movement direction. Continue search in 25 adjacent boxes if needed. 26 27 Notes: 28 1. Word boundaries are collected one box at a time. Only when a boundary that is closest to 29 the input position (in the moving direction) is not available in current box, word 30 boundaries in adjacent box will be collected. So, there is no need to save InlineBox in 31 word boundaries. Instead, the word boundaries are saved as a pair 32 (VisiblePosition, offset) to avoid recomputing VisiblePosition. 33 34 2. We only collect boundaries of the right kind (i.e. left boundary of a word in LTR block 35 and right boundary of a word in RTL block). And word boundaries are collected using 36 previousWordPosition() and nextWordPosition(). So when box directionality is the same as 37 block directionality, word boundaries are collected from right to left visually in a LTR 38 box, and word boundaries are collected from left to right visually in a RTL box. It is 39 the other way around when box directionality is different from block directionality. 40 41 3. To find the right kinds of word boundaries, we must move back and forth between words 42 in some situations. For example, if we're moving to the right in a LTR box in LTR block, 43 we cannot simply return nextWordPosition() because it would return the right boundary 44 of a word. Instead, we return nextWordPosition()'s nextWordPosition()'s previousWordPosition(). 45 46 4. When collecting word breaks inside a box, it first computes a start position, then 47 collect the right kind of word breaks until it reaches the end of (or beyond) the box. 48 In the meanwhile, it might need special handling on the rightmost or leftmost position 49 based on the directionality of the box and block. These computations do not consider the 50 box's bidi level. 51 52 * editing/visible_units.cpp: 53 (WebCore::nextWordBreakInBoxInsideBlockWithDifferentDirectionality): 54 (WebCore::collectWordBreaksInBox): 55 (WebCore::previousWordBoundaryInBox): 56 (WebCore::nextWordBoundaryInBox): 57 (WebCore::visuallyLastWordBoundaryInBox): 58 (WebCore::leftWordBoundary): 59 (WebCore::rightWordBoundary): 60 (WebCore::leftWordPosition): 61 (WebCore::rightWordPosition): 62 1 63 2011-04-20 Cris Neckar <cdn@chromium.org> 2 64 -
trunk/Source/WebCore/editing/visible_units.cpp
r84147 r84425 1275 1275 VisiblePosition wordBreak = hasSeenWordBreakInThisBox ? previousWordBreak : Position(box->renderer()->node(), box->caretMinOffset(), Position::PositionIsOffsetInAnchor); 1276 1276 wordBreak = nextWordPosition(wordBreak); 1277 1278 if (wordBreak == previousWordBreak) { 1279 isLastWordBreakInBox = true; 1280 return VisiblePosition(); 1281 } 1282 1283 1277 1284 1278 // Given RTL box "ABC DEF" either follows a LTR box or is the first visual box in an LTR block as an example, 1285 1279 // the visual display of the RTL box is: "(0)J(10)I(9)H(8) (7)F(6)E(5)D(4) (3)C(2)B(1)A(11)", … … 1288 1282 // But nextWordPosition() of offset 7 is offset 11, which should be ignored, 1289 1283 // and the position at offset 0 should be manually added as the last word break within the box. 1290 if ( positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality(wordBreak, box, offsetOfWordBreak)) {1284 if (wordBreak != previousWordBreak && positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality(wordBreak, box, offsetOfWordBreak)) { 1291 1285 isLastWordBreakInBox = false; 1292 1286 return wordBreak; … … 1347 1341 } 1348 1342 } 1349 1350 static VisiblePosition previousWordBreakInBox(const InlineBox* box, int offset, TextDirection blockDirection) 1343 1344 static void collectWordBreaksInBox(const InlineBox* box, WordBoundaryVector& orderedWordBoundaries, TextDirection blockDirection) 1345 { 1346 if (box->direction() == blockDirection) 1347 collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries); 1348 else 1349 collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries); 1350 } 1351 1352 static VisiblePosition previousWordBoundaryInBox(const InlineBox* box, int offset) 1351 1353 { 1352 1354 int offsetOfWordBreak = 0; 1353 1355 VisiblePosition wordBreak; 1354 1356 while (true) { 1355 if (box->direction() == blockDirection) 1356 wordBreak = previousWordBreakInBoxInsideBlockWithSameDirectionality(box, wordBreak, offsetOfWordBreak); 1357 // FIXME: Implement the 'else' case when the box direction is not equal to the block direction. 1357 wordBreak = previousWordBreakInBoxInsideBlockWithSameDirectionality(box, wordBreak, offsetOfWordBreak); 1358 1358 if (wordBreak.isNull()) 1359 1359 break; … … 1364 1364 } 1365 1365 1366 static VisiblePosition nextWordBoundaryInBox(const InlineBox* box, int offset) 1367 { 1368 int offsetOfWordBreak = 0; 1369 VisiblePosition wordBreak; 1370 bool isLastWordBreakInBox = false; 1371 do { 1372 wordBreak = nextWordBreakInBoxInsideBlockWithDifferentDirectionality(box, wordBreak, offsetOfWordBreak, isLastWordBreakInBox); 1373 if (wordBreak.isNotNull() && (offset == invalidOffset || offsetOfWordBreak != offset)) 1374 return wordBreak; 1375 } while (!isLastWordBreakInBox); 1376 return VisiblePosition(); 1377 } 1378 1379 static VisiblePosition visuallyLastWordBoundaryInBox(const InlineBox* box, int offset, TextDirection blockDirection) 1380 { 1381 WordBoundaryVector orderedWordBoundaries; 1382 collectWordBreaksInBox(box, orderedWordBoundaries, blockDirection); 1383 if (!orderedWordBoundaries.size()) 1384 return VisiblePosition(); 1385 if (offset == invalidOffset || orderedWordBoundaries[orderedWordBoundaries.size() - 1].offsetInInlineBox != offset) 1386 return orderedWordBoundaries[orderedWordBoundaries.size() - 1].visiblePosition; 1387 if (orderedWordBoundaries.size() > 1) 1388 return orderedWordBoundaries[orderedWordBoundaries.size() - 2].visiblePosition; 1389 return VisiblePosition(); 1390 } 1391 1366 1392 static int greatestValueUnder(int offset, bool boxAndBlockAreInSameDirection, const WordBoundaryVector& orderedWordBoundaries) 1367 1393 { … … 1401 1427 return invalidOffset; 1402 1428 } 1403 1429 1404 1430 static VisiblePosition leftWordBoundary(const InlineBox* box, int offset, TextDirection blockDirection) 1405 1431 { 1406 1432 VisiblePosition wordBreak; 1407 1433 for (const InlineBox* adjacentBox = box; adjacentBox; adjacentBox = adjacentBox->prevLeafChild()) { 1408 if (blockDirection == LTR) 1409 wordBreak = previousWordBreakInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection); 1410 // FIXME: Implement the "else" case. 1434 if (blockDirection == LTR) { 1435 if (box->isLeftToRightDirection()) 1436 wordBreak = previousWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset); 1437 else 1438 wordBreak = nextWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset); 1439 } else 1440 wordBreak = visuallyLastWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection); 1411 1441 if (wordBreak.isNotNull()) 1412 1442 return wordBreak; … … 1420 1450 VisiblePosition wordBreak; 1421 1451 for (const InlineBox* adjacentBox = box; adjacentBox; adjacentBox = adjacentBox->nextLeafChild()) { 1422 if (blockDirection == RTL) 1423 wordBreak = previousWordBreakInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection); 1424 // FIXME: Implement the "else" case. 1452 if (blockDirection == RTL) { 1453 if (box->isLeftToRightDirection()) 1454 wordBreak = nextWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset); 1455 else 1456 wordBreak = previousWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset); 1457 } else 1458 wordBreak = visuallyLastWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection); 1425 1459 if (!wordBreak.isNull()) 1426 1460 return wordBreak; … … 1487 1521 1488 1522 WordBoundaryVector orderedWordBoundaries; 1489 if (box->direction() == blockDirection) 1490 collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries); 1491 else 1492 collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries); 1523 collectWordBreaksInBox(box, orderedWordBoundaries, blockDirection); 1493 1524 1494 1525 int index = box->isLeftToRightDirection() ? greatestValueUnder(offset, blockDirection == LTR, orderedWordBoundaries) : … … 1528 1559 1529 1560 WordBoundaryVector orderedWordBoundaries; 1530 if (box->direction() == blockDirection) 1531 collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries); 1532 else 1533 collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries); 1561 collectWordBreaksInBox(box, orderedWordBoundaries, blockDirection); 1562 1534 1563 int index = box->isLeftToRightDirection() ? smallestOffsetAbove(offset, blockDirection == LTR, orderedWordBoundaries) : 1535 1564 greatestValueUnder(offset, blockDirection == RTL, orderedWordBoundaries);
Note: See TracChangeset
for help on using the changeset viewer.