Changeset 83996 in webkit


Ignore:
Timestamp:
Apr 15, 2011 11:31:27 AM (13 years ago)
Author:
xji@chromium.org
Message:

2011-04-13 Xiaomei Ji <xji@chromium.org>

Reviewed by Ryosuke Niwa.

Continue (3rd) experiment with moving caret by word in visual order.
https://bugs.webkit.org/show_bug.cgi?id=58294

  • editing/selection/move-by-word-visually-expected.txt:
  • editing/selection/move-by-word-visually.html:

2011-04-13 Xiaomei Ji <xji@chromium.org>

Reviewed by Ryosuke Niwa.

Continue (3rd) experiment with moving caret by word in visual order.
https://bugs.webkit.org/show_bug.cgi?id=58294

This patch along with r82588 and r83483 implements moving caret by
word in visual order.


The overall algorithm is:

  1. First get the InlineBox and offset of the pass-in VisiblePosition.
  2. Based on the position (left boundary, middle, right boundary) of the offset and the direction of the movement, look for visually adjacent word breaks. 2.1 If the offset is the minimum offset of the box,

return the rightmost word boundary in previous boxes if moving left.
return the leftmost word boundary in box and next boxes if moving right.

2.2 Similar for the case when offset is at the maximum offset of the box.
2.3 When offset is inside the box (not at boundaries), first find the previousWordPosition

or nextWordPosition based on the directionality of the box. If this word break position
is also inside the same box, return it. Otherwise (the nextWordPosition or
previousWordPosition is not in the same box or is at the box boundary), collect all the
word breaks in the box and search for the one closest to the input "offset" based on
box directionality, block directionality, and movement direction. Continue search in
adjacent boxes if needed.

Notes:

  1. Word boundaries are collected one box at a time. Only when a boundary that is closest to the input position (in the moving direction) is not available in current box, word boundaries in adjacent box will be collected. So, there is no need to save InlineBox in word boundaries. Instead, the word boundaries are saved as a pair (VisiblePosition, offset) to avoid recomputing VisiblePosition.


  1. We only collect boundaries of the right kind (i.e. left boundary of a word in LTR block and right boundary of a word in RTL block). And word boundaries are collected using previousWordPosition() and nextWordPosition(). So when box directionality is the same as block directionality, word boundaries are collected from right to left visually in a LTR box, and word boundaries are collected from left to right visually in a RTL box. It is the other way around when box directionality is different from block directionality.
  1. To find the right kinds of word boundaries, we must move back and forth between words in some situations. For example, if we're moving to the right in a LTR box in LTR block, we cannot simply return nextWordPosition() because it would return the right boundary of a word. Instead, we return nextWordPosition()'s nextWordPosition()'s previousWordPosition().
  1. When collecting word breaks inside a box, it first computes a start position, then collect the right kind of word breaks until it reaches the end of (or beyond) the box. In the meanwhile, it might need special handling on the rightmost or leftmost position based on the directionality of the box and block. These computations do not consider the box's bidi level.
  • editing/visible_units.cpp: (WebCore::nextWordBreakInBoxInsideBlockWithDifferentDirectionality): (WebCore::collectWordBreaksInBox): (WebCore::previousWordBoundaryInBox): (WebCore::nextWordBoundaryInBox): (WebCore::visuallyLastWordBoundaryInBox): (WebCore::leftWordBoundary): (WebCore::rightWordBoundary): (WebCore::leftWordPosition): (WebCore::rightWordPosition):
Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r83993 r83996  
     12011-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
    1112011-04-15  Simon Fraser  <simon.fraser@apple.com>
    212
  • trunk/LayoutTests/editing/selection/move-by-word-visually-expected.txt

    r83483 r83996  
    33Test 1, LTR:
    44Move 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]
    66Move 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]
     8Test 2, LTR:
     9Move right by one word
     10"abc def hij opq rst"[0, 4, 8, 12, 16]
    911Move 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]
     13Test 3, RTL:
     14Move left by one word
     15"abc def hij opq rst"[0, 15, 11, 7, 3]
    1116Move 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]
     18Test 4, LTR:
    1419Move right by one word
    15 "ZZZ QQQ BBB CCC XXX"[0, 11, 7, 3, 3, 19]    FAIL expected: [15, 11, 7, 3, 19, 19]
     20"ZZZ QQQ BBB CCC XXX"[0, 15, 11, 7, 3]
    1621Move 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]
     23Test 5, RTL:
    1924Move 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]
    2126Move right by one word
    22 "ZZZ QQQ BBB CCC XXX"[16, 12, 8, 4, 0, 0]
    23 Test 5, LTR:
     27"ZZZ QQQ BBB CCC XXX"[19, 16, 12, 8, 4, 0]
     28Test 6, LTR:
    2429Move 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]
    2631Move 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]
     33Test 7, RTL:
    2934Move 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]
    3136Move 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]
     38Test 8, LTR:
    3439Move 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]
    3641Move 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]
     43Test 9, RTL:
    3944Move 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]
    4146Move 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]
     48Test 10, LTR:
     49Move right by one word
     50"aaa AAA bbb"[0, 4, 8]
     51Move left by one word
     52"aaa AAA bbb"[11, 8, 4, 0]
     53Test 11, RTL:
     54Move left by one word
     55"aaa AAA bbb"[0, 4, 8, 11]
     56Move right by one word
     57"aaa AAA bbb"[11, 8, 4, 0]
     58Test 12, LTR:
     59Move right by one word
     60"AAA BBB WWW aaa bbb ccc DDD SSS UUU"[0, 7, 3, 12, 16, 20, 24, 31, 27]
     61Move left by one word
     62"AAA BBB WWW aaa bbb ccc DDD SSS UUU"[35, 27, 31, 24, 20, 16, 12, 3, 7, 0]
     63Test 13, RTL:
     64Move left by one word
     65"AAA BBB WWW aaa bbb ccc DDD SSS UUU"[0, 4, 8, 12, 19, 15, 24, 28, 32]
     66Move right by one word
     67"AAA BBB WWW aaa bbb ccc DDD SSS UUU"[35, 32, 28, 24, 15, 19, 12, 8, 4, 0]
     68Test 14, LTR:
     69Move right by one word
     70"AAA BBB aaa bbb WWW DDD"[0, 3, 8, 12, 16, 19]
     71Move left by one word
     72"AAA BBB aaa bbb WWW DDD"[23, 19, 16, 12, 8, 3, 0]
     73Test 15, RTL:
     74Move left by one word
     75"AAA BBB aaa bbb WWW DDD"[0, 4, 8, 11, 16, 20]
     76Move right by one word
     77"AAA BBB aaa bbb WWW DDD"[23, 20, 16, 11, 8, 4, 0]
     78Test 16, LTR:
     79Move right by one word
     80"ZQB abc RIG"[0, 4, 8, 11]
     81Move left by one word
     82"ZQB abc RIG"[11, 8, 4, 0]
     83Test 17, RTL:
     84Move left by one word
     85"ZQB abc RIG"[0, 4, 8]
     86Move right by one word
     87"ZQB abc RIG"[11, 8, 4, 0]
     88Test 18, LTR:
     89Move right by one word
     90"abc def    hij opq"[0, 4, 15]    FAIL expected: [0, 4, 11, 15]
     91Move left by one word
     92"abc def    hij opq"[18, 15, 4, 0]    FAIL expected: [18, 15, 11, 4, 0]
     93Test 19, LTR:
     94Move right by one word
     95"AAA "[0, 3]
     96Move left by one word
     97"BB"[2], "AAA "[3, 0]
     98Test 20, RTL:
     99Move left by one word
     100"AAA "[0, 4]
     101Move right by one word
     102"BB"[2], "AAA "[4, 0]
     103Test 21, LTR:
     104Move right by one word
     105"abc def "[0, 4, 8], "hij opq"[4], " rst uvw"[1, 5]
     106Move left by one word
     107" rst uvw"[8, 5, 1], "hij opq"[4], "abc def "[8, 4, 0]
     108Test 22, RTL:
     109Move 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]
     111Move 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]
     113Test 23, RTL:
     114Move 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]
     116Move 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]
     118Test 24, LTR:
     119Move right by one word
     120"abc def "[0, 4, 8], "hij opq"[4], " rst uvw"[1, 5]
     121Move left by one word
     122" rst uvw"[8, 5, 1], "hij opq"[4], "abc def "[8, 4, 0]
     123Test 25, RTL:
     124Move left by one word
     125"ABD DSU "[0, 4, 8], "EJH FUX"[4], "FFZ LIG"[4]
     126Move right by one word
     127"FFZ LIG"[7, 4], "EJH FUX"[4], "ABD DSU "[8, 4, 0]
     128Test 26, LTR:
     129Move right by one word
     130"ABD DSU "[0], "FFZ LIG"[3], "EJH FUX"[3], "ABD DSU "[7, 3]
     131Move left by one word
     132"FFZ LIG"[7], "ABD DSU "[3, 7], "EJH FUX"[3], "FFZ LIG"[3], "ABD DSU "[0]
     133Test 27, RTL:
     134Move left by one word
     135"ABD DSU "[0, 4, 8], "EJH FUX"[4], "FFZ LIG"[4]
     136Move right by one word
     137"FFZ LIG"[7, 4], "EJH FUX"[4], "ABD DSU "[8, 4, 0]
     138Test 28, LTR:
     139Move right by one word
     140"ABD DSU "[0], "FFZ LIG"[3], "EJH FUX"[3], "ABD DSU "[7, 3]
     141Move left by one word
     142"FFZ LIG"[7], "ABD DSU "[3, 7], "EJH FUX"[3], "FFZ LIG"[3], "ABD DSU "[0]
     143Test 29, RTL:
     144Move left by one word
     145"ABD DSU "[0, 4, 8], "abc def"[3], "FFZ LIG"[4]
     146Move right by one word
     147"FFZ LIG"[7, 4], "abc def"[3], "ABD DSU "[8, 4, 0]
     148Test 30, LTR:
     149Move right by one word
     150"ABD DSU "[0], "FFZ LIG"[3], "ABD DSU "[8], "abc def"[4], "ABD DSU "[7, 3]
     151Move 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]
     153Test 31, RTL:
     154Move left by one word
     155"ABD DSU "[0, 4, 8], "abc def"[3], "FFZ LIG"[4]
     156Move right by one word
     157"FFZ LIG"[7, 4], "abc def"[3], "ABD DSU "[8, 4, 0]
     158Test 32, LTR:
     159Move right by one word
     160"ABD DSU "[0, 3, 8], "abc def"[4], "FFZ LIG"[3]
     161Move left by one word
     162"FFZ LIG"[7, 3], "abc def"[4], "ABD DSU "[8, 4, 0]
     163Test 33, RTL:
     164Move 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]
     166Move 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]
     168Test 34, LTR:
     169Move 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]
     171Move 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]
     173Test 35, RTL:
     174Move 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]
     176Move 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]
     178Test 36, LTR:
     179Move right by one word
     180"ABD opq DSU "[0, 4, 8, 12], "abc AAA def"[4, 8], "FFZ rst LIG"[4, 8, 11]
     181Move left by one word
     182"FFZ rst LIG"[11, 8, 4], "abc AAA def"[8, 4], "ABD opq DSU "[12, 8, 4, 0]
     183Test 37, LTR:
     184Move right by one word
     185"aaa "[0, 4], "bbb AAA "[4, 7]
     186Move left by one word
     187"FFZ"[3], "bbb AAA "[7, 4], "aaa "[4, 0]
    43188
    44189======== Move By Word Specific Test ====
  • trunk/LayoutTests/editing/selection/move-by-word-visually.html

    r83483 r83996  
    7373}
    7474
     75function 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
    7587var wordBreaks;
    7688
     89function 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
     111function 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
    77121function validateData(positions)
    78122{
     123    var equal = true;
     124    if (positions.length != wordBreaks.length)
     125        equal = false;
    79126    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;
    81129            break;
    82130        }
    83131    }
    84     if (i != wordBreaks.length - 1 && positions[i] != wordBreaks[i]) {
     132    if (equal == false) {
    85133        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("]");
    90140    }
    91141}
     
    93143function collectWordBreaks(test, searchDirection)
    94144{
    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
     162function 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]);
    105169    }
    106170}
     
    110174    log("Move " + searchDirection + " by one word\n");
    111175    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);
    113189    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);
    124190    validateData(positions);
    125191    log("\n");
     
    134200        direction = "left";   
    135201    moveByWord(sel, test, direction, dir);   
     202
     203    sel.modify("move", "forward", "lineBoundary");
    136204    // Check ctrl-left-arrow works for every position.
    137205    if (dir == "ltr")
     
    216284<body>
    217285<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<!--
     287Title saves the word breaks.
     288The format of title is "xxx|xxxx".
     289
     290The sequence on the left of "|" is word boundaries when moving caret from left to right.
     291The sequence on the right of "|" is word boundaries when moving caret from right to left.
     292
     293If there is a single node in the line, the sequence are offsets.
     294If there are multiple nodes in the line, the sequence is array of [anchor_node_id, offset, child_node_index],
     295where 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
    226325<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]"
     370contenteditable>אבד 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>
    228381
    229382<!-- 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_1 0">בב</span></div>
     383<div id="div_100" contenteditable>אאא <span id="span_100" class="specific_test" title="1 left div_100 0">בב</span></div>
    231384</div>
    232385
  • trunk/Source/WebCore/ChangeLog

    r83992 r83996  
     12011-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
    1632011-04-14  Zhenyao Mo  <zmo@google.com>
    264
  • trunk/Source/WebCore/editing/visible_units.cpp

    r83483 r83996  
    12751275    VisiblePosition wordBreak = hasSeenWordBreakInThisBox ? previousWordBreak : Position(box->renderer()->node(), box->caretMinOffset(), Position::PositionIsOffsetInAnchor);
    12761276    wordBreak = nextWordPosition(wordBreak);
    1277    
    1278     if (wordBreak == previousWordBreak) {
    1279         isLastWordBreakInBox = true;
    1280         return VisiblePosition();
    1281     }
    1282 
    1283 
     1277 
    12841278    // Given RTL box "ABC DEF" either follows a LTR box or is the first visual box in an LTR block as an example,
    12851279    // 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)",
     
    12881282    // But nextWordPosition() of offset 7 is offset 11, which should be ignored,
    12891283    // 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)) {
    12911285        isLastWordBreakInBox = false;
    12921286        return wordBreak;
     
    13471341    }
    13481342}
    1349    
    1350 static VisiblePosition previousWordBreakInBox(const InlineBox* box, int offset, TextDirection blockDirection)
     1343
     1344static 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   
     1352static VisiblePosition previousWordBoundaryInBox(const InlineBox* box, int offset)
    13511353{
    13521354    int offsetOfWordBreak = 0;
    13531355    VisiblePosition wordBreak;
    13541356    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);
    13581358        if (wordBreak.isNull())
    13591359            break;
     
    13641364}
    13651365
     1366static 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   
     1379static 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       
    13661392static int greatestValueUnder(int offset, bool boxAndBlockAreInSameDirection, const WordBoundaryVector& orderedWordBoundaries)
    13671393{
     
    14011427    return invalidOffset;
    14021428}
    1403  
     1429
    14041430static VisiblePosition leftWordBoundary(const InlineBox* box, int offset, TextDirection blockDirection)
    14051431{
    14061432    VisiblePosition wordBreak;
    14071433    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);           
    14111441        if (wordBreak.isNotNull())
    14121442            return wordBreak;
     
    14201450    VisiblePosition wordBreak;
    14211451    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);           
    14251459        if (!wordBreak.isNull())
    14261460            return wordBreak;
     
    14871521   
    14881522    WordBoundaryVector orderedWordBoundaries;
    1489     if (box->direction() == blockDirection)
    1490         collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries);
    1491     else
    1492         collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries);
     1523    collectWordBreaksInBox(box, orderedWordBoundaries, blockDirection);
    14931524
    14941525    int index = box->isLeftToRightDirection() ? greatestValueUnder(offset, blockDirection == LTR, orderedWordBoundaries) :
     
    15281559   
    15291560    WordBoundaryVector orderedWordBoundaries;
    1530     if (box->direction() == blockDirection)
    1531         collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries);
    1532     else
    1533         collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries);
     1561    collectWordBreaksInBox(box, orderedWordBoundaries, blockDirection);
     1562   
    15341563    int index = box->isLeftToRightDirection() ? smallestOffsetAbove(offset, blockDirection == LTR, orderedWordBoundaries) :
    15351564        greatestValueUnder(offset, blockDirection == RTL, orderedWordBoundaries);
Note: See TracChangeset for help on using the changeset viewer.