Changeset 83996 in webkit
- Timestamp:
- Apr 15, 2011 11:31:27 AM (13 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r83993 r83996 1 2011-04-13 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-15 Simon Fraser <simon.fraser@apple.com> 2 12 -
trunk/LayoutTests/editing/selection/move-by-word-visually-expected.txt
r83483 r83996 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
r83483 r83996 73 73 } 74 74 75 function nodeOfWordBreak(nodeAndOffset) 76 { 77 var node = document.getElementById(nodeAndOffset[0]).firstChild; 78 if (nodeAndOffset.length == 3) { 79 var childIndex = nodeAndOffset[2]; 80 for (var i = 0; i < childIndex - 1; ++i) { 81 node = node.nextSibling; 82 } 83 } 84 return node; 85 } 86 75 87 var wordBreaks; 76 88 89 function logWordBreak(index) 90 { 91 var wordBreak = wordBreaks[index]; 92 if (wordBreak.search(',') == -1) 93 log(wordBreak); 94 else { 95 var nodeAndOffset = wordBreak.split(','); 96 var node = nodeOfWordBreak(nodeAndOffset); 97 98 var differentNode = false; 99 if (index != 0) { 100 differentNode = nodeOfWordBreak(nodeAndOffset) != nodeOfWordBreak(wordBreaks[index - 1].split(',')); 101 102 } 103 if (differentNode == true) 104 log("]"); 105 if (index == 0 || differentNode == true) 106 log((node instanceof Text ? '"' + fold(node.data) + '"' : "<" + node.tagName + ">") + "["); 107 log(nodeAndOffset[1]); 108 } 109 } 110 111 function positionEqualToWordBreak(position, wordBreak) 112 { 113 if (wordBreak.search(',') == -1) 114 return position.offset == wordBreak; 115 else { 116 var nodeAndOffset = wordBreak.split(','); 117 return position.node == nodeOfWordBreak(nodeAndOffset) && position.offset == nodeAndOffset[1]; 118 } 119 } 120 77 121 function validateData(positions) 78 122 { 123 var equal = true; 124 if (positions.length != wordBreaks.length) 125 equal = false; 79 126 for (var i = 0; i < wordBreaks.length - 1; ++i) { 80 if (positions[i].offset != wordBreaks[i + 1]) { 127 if (!positionEqualToWordBreak(positions[i], wordBreaks[i])) { 128 equal = false; 81 129 break; 82 130 } 83 131 } 84 if ( i != wordBreaks.length - 1 && positions[i] != wordBreaks[i]) {132 if (equal == false) { 85 133 log(" FAIL expected: ["); 86 for (var i = 1; i < wordBreaks.length; ++i) { 87 log(wordBreaks[i] + ", "); 88 } 89 log(wordBreaks[wordBreaks.length - 1] + "]"); 134 for (var i = 0; i < wordBreaks.length; ++i) { 135 logWordBreak(i); 136 if (i != wordBreaks.length - 1) 137 log(", "); 138 } 139 log("]"); 90 140 } 91 141 } … … 93 143 function collectWordBreaks(test, searchDirection) 94 144 { 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(" "); 145 var title; 146 if (searchDirection == "right") 147 title = test.title.split("|")[0]; 148 else 149 title = test.title.split("|")[1]; 150 151 var pattern = /\[(.+?)\]/g; 152 var result; 153 wordBreaks = []; 154 while ((result = pattern.exec(title)) != null) { 155 wordBreaks.push(result[1]); 156 } 157 if (wordBreaks.length == 0) { 158 wordBreaks = title.split(" "); 159 } 160 } 161 162 function setPosition(sel, node, wordBreak) 163 { 164 if (wordBreak.search(',') == -1) 165 sel.setPosition(node, wordBreak); 166 else { 167 var nodeAndOffset = wordBreak.split(','); 168 sel.setPosition(nodeOfWordBreak(nodeAndOffset), nodeAndOffset[1]); 105 169 } 106 170 } … … 110 174 log("Move " + searchDirection + " by one word\n"); 111 175 var prevOffset = sel.anchorOffset; 112 var node = sel.anchorNode; 176 var prevNode = sel.anchorNode; 177 var positions = []; 178 positions.push({ node: sel.anchorNode, offset: sel.anchorOffset, point: caretCoordinates() }); 179 180 while (1) { 181 sel.modify("move", searchDirection, "-webkit-visual-word"); 182 if (prevNode == sel.anchorNode && prevOffset == sel.anchorOffset) 183 break; 184 positions.push({ node: sel.anchorNode, offset: sel.anchorOffset, point: caretCoordinates() }); 185 prevNode = sel.anchorNode; 186 prevOffset = sel.anchorOffset; 187 }; 188 logPositions(positions); 113 189 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 190 validateData(positions); 125 191 log("\n"); … … 134 200 direction = "left"; 135 201 moveByWord(sel, test, direction, dir); 202 203 sel.modify("move", "forward", "lineBoundary"); 136 204 // Check ctrl-left-arrow works for every position. 137 205 if (dir == "ltr") … … 216 284 <body> 217 285 <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> 286 <!-- 287 Title saves the word breaks. 288 The format of title is "xxx|xxxx". 289 290 The sequence on the left of "|" is word boundaries when moving caret from left to right. 291 The sequence on the right of "|" is word boundaries when moving caret from right to left. 292 293 If there is a single node in the line, the sequence are offsets. 294 If there are multiple nodes in the line, the sequence is array of [anchor_node_id, offset, child_node_index], 295 where child_node_index is optional, default is the first child of the anchor node. 296 --> 297 <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> 298 299 <!-- pure English --> 300 <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> 301 <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> 302 303 <!-- pure Hebrew --> 304 <div dir=ltr class="test_move_by_word" title="0 15 11 7 3|19 3 7 11 15 0" contenteditable>ששש נננ בבב גגג קקק</div> 305 <div dir=rtl class="test_move_by_word" title="19 16 12 8 4 0|0 4 8 12 16" contenteditable>ששש נננ בבב גגג קקק</div> 306 307 <!-- bidi text --> 308 <!-- English Hebrew English --> 309 <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> 310 <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> 311 312 <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> 313 <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> 314 315 <div dir=ltr class="test_move_by_word" title="0 4 8|11 8 4 0" contenteditable>aaa אאא bbb</div> 316 <div dir=rtl class="test_move_by_word" title="11 8 4 0|0 4 8 11" contenteditable>aaa אאא bbb</div> 317 318 <!-- Hebrew English Hebrew --> 319 <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> 320 <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> 321 322 <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> 323 <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> 324 226 325 <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> 326 <div dir=rtl class="test_move_by_word" title="11 8 4 0|0 4 8" contenteditable>שנב abc סטז</div> 327 328 <!-- multiple spaces between word. 329 FAILED: word break between "def" and "hij" is unreachable. 330 --> 331 <div dir=ltr class="test_move_by_word" title="0 4 11 15|18 15 11 4 0" contenteditable>abc def hij opq</div> 332 333 <!-- Inline element --> 334 <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> 335 <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> 336 337 <!-- pure English in inline element with same or different directionality from its parent --> 338 <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> 339 340 <!-- FAILED --> 341 <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> 342 343 <!-- FAILED --> 344 <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> 345 346 <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> 347 348 <!-- pure Hebrew in inline element with same or different directionality from its parent --> 349 350 <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> 351 352 <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> 353 354 <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> 355 356 <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> 357 358 <!-- bidi in inline element with same or different directionality from its parent --> 359 <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> 360 361 <!-- FAIL --> 362 <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> 363 364 <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> 365 366 <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> 367 368 <!-- FAILED --> 369 <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]" 370 contenteditable>אבד opq דעפ <span dir=ltr id="span_15">abc אאא def</span>ווש rst כטז</div> 371 372 <!-- FAILED, and wrong printing result --> 373 <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> 374 375 <!-- FAILED --> 376 <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> 377 378 <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> 379 380 <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 381 229 382 <!-- 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>383 <div id="div_100" contenteditable>אאא <span id="span_100" class="specific_test" title="1 left div_100 0">בב</span></div> 231 384 </div> 232 385 -
trunk/Source/WebCore/ChangeLog
r83992 r83996 1 2011-04-13 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-14 Zhenyao Mo <zmo@google.com> 2 64 -
trunk/Source/WebCore/editing/visible_units.cpp
r83483 r83996 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.