Changeset 83483 in webkit


Ignore:
Timestamp:
Apr 11, 2011 1:02:19 PM (13 years ago)
Author:
xji@chromium.org
Message:

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

Reviewed by Ryosuke Niwa.

Continue experiment with moving caret by word in visual order.
https://bugs.webkit.org/show_bug.cgi?id=57806

This is the 2nd patch, which adds implementation when caret is inside box
(not at boundaries). If the word break is inside the same box and not at the boundaries
either, the word break will be returned. If need to search the adjacent boxes for word
breaks, then, only the cases implemented in bug 57336 work.

  • editing/visible_units.cpp: (WebCore::leftmostPositionInRTLBoxInLTRBlock): (WebCore::rightmostPositionInLTRBoxInRTLBlock): (WebCore::lastWordBreakInBox): (WebCore::positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality): (WebCore::nextWordBreakInBoxInsideBlockWithDifferentDirectionality): (WebCore::WordBoundaryEntry::WordBoundaryEntry): (WebCore::collectWordBreaksInBoxInsideBlockWithSameDirectionality): (WebCore::collectWordBreaksInBoxInsideBlockWithDifferntDirectionality): (WebCore::greatestValueUnder): (WebCore::smallestOffsetAbove): (WebCore::positionIsInsideBox): (WebCore::positionBeforeNextWord): (WebCore::positionAfterPreviousWord): (WebCore::leftWordPosition): (WebCore::rightWordPosition):

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

Reviewed by Ryosuke Niwa.

Continue experiment with moving caret by word in visual order.
https://bugs.webkit.org/show_bug.cgi?id=57806

Return correct result when caret and the word break are inside a box (not at boundaries).
Added test case to test word break at a random start point
(not start from a word break).

  • editing/selection/move-by-word-visually-expected.txt:
Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r83482 r83483  
     12011-04-06  Xiaomei Ji  <xji@chromium.org>
     2
     3        Reviewed by Ryosuke Niwa.
     4
     5        Continue experiment with moving caret by word in visual order.
     6        https://bugs.webkit.org/show_bug.cgi?id=57806
     7
     8        Return correct result when caret and the word break are inside a box (not at boundaries).
     9        Added test case to test word break at a random start point
     10        (not start from a word break).
     11
     12        * editing/selection/move-by-word-visually-expected.txt:
     13
    1142011-04-11  Jian Li  <jianli@chromium.org>
    215
  • trunk/LayoutTests/editing/selection/move-by-word-visually-expected.txt

    r82588 r83483  
    33Test 1, LTR:
    44Move right by one word
    5 "abc def hij opq rst"[0, 4, 8, 12, 16, 19]    FAIL expected: [4, 8, 12, 16, 19, 19]
     5"abc def hij opq rst"[0, 8, 12, 16, 16, 19]    FAIL expected: [4, 8, 12, 16, 19, 19]
    66Move left by one word
    7 "abc def hij opq rst"[16, 16, 12, 8, 4, 0]    FAIL expected: [16, 12, 8, 4, 0, 0]
     7"abc def hij opq rst"[16, 12, 8, 4, 0, 0]
    88Test 2, RTL:
    99Move left by one word
    10 "abc def hij opq rst"[0, 15, 11, 7, 3, 19]    FAIL expected: [15, 11, 7, 3, 19, 19]
     10"abc def hij opq rst"[0, 11, 7, 3, 3, 19]    FAIL expected: [15, 11, 7, 3, 19, 19]
    1111Move right by one word
    12 "abc def hij opq rst"[19, 3, 7, 11, 15, 0]    FAIL expected: [3, 7, 11, 15, 0, 0]
     12"abc def hij opq rst"[19, 7, 11, 15, 0, 0]    FAIL expected: [3, 7, 11, 15, 0, 0]
    1313Test 3, LTR:
    1414Move right by one word
    15 "ZZZ QQQ BBB CCC XXX"[0, 15, 11, 7, 3, 19]    FAIL expected: [15, 11, 7, 3, 19, 19]
     15"ZZZ QQQ BBB CCC XXX"[0, 11, 7, 3, 3, 19]    FAIL expected: [15, 11, 7, 3, 19, 19]
    1616Move left by one word
    17 "ZZZ QQQ BBB CCC XXX"[19, 3, 7, 11, 15, 0]    FAIL expected: [3, 7, 11, 15, 0, 0]
     17"ZZZ QQQ BBB CCC XXX"[19, 7, 11, 15, 0, 0]    FAIL expected: [3, 7, 11, 15, 0, 0]
    1818Test 4, RTL:
    1919Move left by one word
    20 "ZZZ QQQ BBB CCC XXX"[0, 4, 8, 12, 16, 19]    FAIL expected: [4, 8, 12, 16, 19, 19]
     20"ZZZ QQQ BBB CCC XXX"[0, 8, 12, 16, 16, 19]    FAIL expected: [4, 8, 12, 16, 19, 19]
    2121Move right by one word
    22 "ZZZ QQQ BBB CCC XXX"[16, 16, 12, 8, 4, 0]    FAIL expected: [16, 12, 8, 4, 0, 0]
     22"ZZZ QQQ BBB CCC XXX"[16, 12, 8, 4, 0, 0]
    2323Test 5, LTR:
    2424Move right by one word
    25 "abc def ZQB RIG uvw xyz"[0, 4, 8, 11, 16, 20, 23]    FAIL expected: [4, 8, 11, 16, 20, 23, 23]
     25"abc def ZQB RIG uvw xyz"[0, 4, 8, 11, 20, 20, 23]    FAIL expected: [4, 8, 11, 16, 20, 23, 23]
    2626Move left by one word
    27 "abc def ZQB RIG uvw xyz"[20, 20, 16, 11, 4, 4, 0]    FAIL expected: [20, 16, 11, 8, 4, 0, 0]
     27"abc def ZQB RIG uvw xyz"[20, 16, 4, 8, 4, 0, 0]    FAIL expected: [20, 16, 11, 8, 4, 0, 0]
    2828Test 6, RTL:
    2929Move left by one word
    30 "abc def ZQB RIG uvw xyz"[0, 3, 8, 12, 16, 19, 23]    FAIL expected: [3, 8, 12, 16, 19, 23, 23]
     30"abc def ZQB RIG uvw xyz"[0, 3, 12, 12, 16, 19, 23]    FAIL expected: [3, 8, 12, 16, 19, 23, 23]
    3131Move right by one word
    32 "abc def ZQB RIG uvw xyz"[12, 19, 12, 12, 8, 3, 0]    FAIL expected: [19, 16, 12, 8, 3, 0, 0]
     32"abc def ZQB RIG uvw xyz"[12, 16, 12, 8, 8, 0, 0]    FAIL expected: [19, 16, 12, 8, 3, 0, 0]
    3333Test 7, LTR:
    3434Move right by one word
     
    4040"ZQB abc RIG"[0, 4, 8, 11]    FAIL expected: [4, 8, 11, 11]
    4141Move right by one word
    42 "ZQB abc RIG"[8, 8, 0, 0]    FAIL expected: [8, 4, 0, 0]
     42"ZQB abc RIG"[8, 0, 0, 0]    FAIL expected: [8, 4, 0, 0]
    4343
     44======== Move By Word Specific Test ====
     45Test 1
     46Move left by one word
     47"BB"[1], "AAA "[0]
  • trunk/LayoutTests/editing/selection/move-by-word-visually.html

    r82588 r83483  
    159159
    160160    }
     161}
     162
     163function runSpecificTest(tests)
     164{
     165    var sel = getSelection();
     166    log("\n======== Move By Word Specific Test ====\n");
     167    for (var i = 0; i < tests.length; ++i) {
     168        log("Test " + (i + 1) + "\n");
     169        var components = tests[i].title.split(" ");
     170        var startOffset = components[0];
     171        var movingDirection = components[1];
     172        var endingNode = components[2];
     173        var endingOffset = components[3];
     174 
     175        log("Move " + movingDirection + " by one word\n");
     176
     177        var positions = [];
     178        sel.setPosition(tests[i].firstChild, startOffset);
     179        positions.push({ node: sel.anchorNode, offset: sel.anchorOffset, point: caretCoordinates() });
     180
     181        sel.modify("move", movingDirection, "-webkit-visual-word");
     182        positions.push({ node: sel.anchorNode, offset: sel.anchorOffset, point: caretCoordinates() });
     183
     184        logPositions(positions);
     185
     186        if (sel.anchorNode.parentNode != document.getElementById(endingNode) || sel.anchorOffset != endingOffset) {
     187            log("    FAIL: expected ");
     188            var endingChildNode = document.getElementById(endingNode).firstChild;
     189            log((endingChildNode instanceof Text ? '"' + fold(endingChildNode.data) + '"' : "<" + endingChildNode.tagName + ">") + "[" + endingOffset + "]");
     190        }
     191    }
    161192    document.getElementById("testMoveByWord").style.display = "none";
    162193}
     
    166197    var tests = document.getElementsByClassName("test_move_by_word");
    167198    runMoveLeftRight(tests, "word");
     199   
     200    tests = document.getElementsByClassName("specific_test");
     201    runSpecificTest(tests);
    168202}
    169203
     
    192226<div dir=ltr class="test_move_by_word" title="0 4 8 11|11 8 4 0" contenteditable>שנב abc סטז</div>
    193227<div dir=rtl class="test_move_by_word" title="0 4 8 11|11 8 4 0" contenteditable>שנב abc סטז</div>
     228
     229<!-- 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>
    194231</div>
    195232
  • trunk/Source/WebCore/ChangeLog

    r83479 r83483  
     12011-04-06  Xiaomei Ji  <xji@chromium.org>
     2
     3        Reviewed by Ryosuke Niwa.
     4
     5        Continue experiment with moving caret by word in visual order.
     6        https://bugs.webkit.org/show_bug.cgi?id=57806
     7
     8        This is the 2nd patch, which adds implementation when caret is inside box
     9        (not at boundaries). If the word break is inside the same box and not at the boundaries
     10        either, the word break will be returned. If need to search the adjacent boxes for word
     11        breaks, then, only the cases implemented in bug 57336 work.
     12
     13        * editing/visible_units.cpp:
     14        (WebCore::leftmostPositionInRTLBoxInLTRBlock):
     15        (WebCore::rightmostPositionInLTRBoxInRTLBlock):
     16        (WebCore::lastWordBreakInBox):
     17        (WebCore::positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality):
     18        (WebCore::nextWordBreakInBoxInsideBlockWithDifferentDirectionality):
     19        (WebCore::WordBoundaryEntry::WordBoundaryEntry):
     20        (WebCore::collectWordBreaksInBoxInsideBlockWithSameDirectionality):
     21        (WebCore::collectWordBreaksInBoxInsideBlockWithDifferntDirectionality):
     22        (WebCore::greatestValueUnder):
     23        (WebCore::smallestOffsetAbove):
     24        (WebCore::positionIsInsideBox):
     25        (WebCore::positionBeforeNextWord):
     26        (WebCore::positionAfterPreviousWord):
     27        (WebCore::leftWordPosition):
     28        (WebCore::rightWordPosition):
     29
    1302011-04-11  Mario Sanchez Prada  <msanchez@igalia.com>
    231
  • trunk/Source/WebCore/editing/visible_units.cpp

    r82588 r83483  
    11741174}
    11751175
     1176static VisiblePosition leftmostPositionInRTLBoxInLTRBlock(const InlineBox* box)
     1177{
     1178    // FIXME: Probably need to take care of bidi level too.
     1179    Node* node = box->renderer()->node();
     1180    InlineBox* previousLeaf = box->prevLeafChild();
     1181    InlineBox* nextLeaf = box->nextLeafChild();   
     1182   
     1183    if (previousLeaf && !previousLeaf->isLeftToRightDirection())
     1184        return Position(node, box->caretMaxOffset(), Position::PositionIsOffsetInAnchor);
     1185
     1186    if (nextLeaf && !nextLeaf->isLeftToRightDirection()) {
     1187        if (previousLeaf)
     1188            return Position(previousLeaf->renderer()->node(), previousLeaf->caretMaxOffset(), Position::PositionIsOffsetInAnchor);
     1189
     1190        InlineBox* lastRTLLeaf;
     1191        do {
     1192            lastRTLLeaf = nextLeaf;
     1193            nextLeaf = nextLeaf->nextLeafChild();
     1194        } while (nextLeaf && !nextLeaf->isLeftToRightDirection());
     1195        return Position(lastRTLLeaf->renderer()->node(), lastRTLLeaf->caretMinOffset(), Position::PositionIsOffsetInAnchor);
     1196    }
     1197
     1198    return Position(node, box->caretMinOffset(), Position::PositionIsOffsetInAnchor);
     1199}
     1200
     1201static VisiblePosition rightmostPositionInLTRBoxInRTLBlock(const InlineBox* box)
     1202{
     1203    // FIXME: Probably need to take care of bidi level too.
     1204    Node* node = box->renderer()->node();
     1205    InlineBox* previousLeaf = box->prevLeafChild();
     1206    InlineBox* nextLeaf = box->nextLeafChild();   
     1207   
     1208    if (nextLeaf && nextLeaf->isLeftToRightDirection())   
     1209        return Position(node, box->caretMaxOffset(), Position::PositionIsOffsetInAnchor);
     1210
     1211    if (previousLeaf && previousLeaf->isLeftToRightDirection()) {
     1212        if (nextLeaf)
     1213            return Position(nextLeaf->renderer()->node(), nextLeaf->caretMaxOffset(), Position::PositionIsOffsetInAnchor);
     1214
     1215        InlineBox* firstLTRLeaf;
     1216        do {
     1217            firstLTRLeaf = previousLeaf;
     1218            previousLeaf = previousLeaf->prevLeafChild();
     1219        } while (previousLeaf && previousLeaf->isLeftToRightDirection());
     1220        return Position(firstLTRLeaf->renderer()->node(), firstLTRLeaf->caretMinOffset(), Position::PositionIsOffsetInAnchor);
     1221    }
     1222
     1223    return Position(node, box->caretMinOffset(), Position::PositionIsOffsetInAnchor);
     1224}
     1225   
     1226static VisiblePosition lastWordBreakInBox(const InlineBox* box, int& offsetOfWordBreak)
     1227{
     1228    // Add the leftmost word break for RTL box or rightmost word break for LTR box.
     1229    InlineBox* previousLeaf = box->prevLeafChild();
     1230    InlineBox* nextLeaf = box->nextLeafChild();
     1231    VisiblePosition boundaryPosition;
     1232    if (box->direction() == RTL && (!previousLeaf || previousLeaf->isLeftToRightDirection()))
     1233        boundaryPosition = leftmostPositionInRTLBoxInLTRBlock(box);
     1234    else if (box->direction() == LTR && (!nextLeaf || !nextLeaf->isLeftToRightDirection()))
     1235        boundaryPosition = rightmostPositionInLTRBoxInRTLBlock(box);
     1236
     1237    if (boundaryPosition.isNull())
     1238        return VisiblePosition();           
     1239
     1240    VisiblePosition wordBreak = nextWordPosition(boundaryPosition);
     1241    if (wordBreak != boundaryPosition)
     1242        wordBreak = previousWordPosition(wordBreak);
     1243
     1244    InlineBox* boxOfWordBreak;
     1245    wordBreak.getInlineBoxAndOffset(boxOfWordBreak, offsetOfWordBreak);
     1246    if (boxOfWordBreak == box)
     1247        return wordBreak;
     1248    return VisiblePosition();   
     1249}
     1250
     1251static bool positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality(const VisiblePosition& wordBreak, const InlineBox* box, int& offsetOfWordBreak)
     1252{
     1253    int previousOffset = offsetOfWordBreak;
     1254    InlineBox* boxOfWordBreak;
     1255    wordBreak.getInlineBoxAndOffset(boxOfWordBreak, offsetOfWordBreak);
     1256    if (boxOfWordBreak == box && (previousOffset == invalidOffset || previousOffset < offsetOfWordBreak))
     1257        return true;
     1258    return false;
     1259}
     1260   
     1261static VisiblePosition nextWordBreakInBoxInsideBlockWithDifferentDirectionality(
     1262    const InlineBox* box, const VisiblePosition& previousWordBreak, int& offsetOfWordBreak, bool& isLastWordBreakInBox)
     1263{
     1264    // FIXME: Probably need to take care of bidi level too.
     1265   
     1266    // In a LTR block, the word break should be on the left boundary of a word.
     1267    // In a RTL block, the word break should be on the right boundary of a word.
     1268    // Because previousWordPosition() returns the word break on the right boundary of the word for RTL text,
     1269    // we need to use nextWordPosition() to traverse words within the inline boxes from right to left to find the next word break.
     1270    // The same applies to LTR text, in which words are traversed within the inline boxes from left to right.
     1271   
     1272    // FIXME: handle multi-spaces (http://webkit.org/b/57543).
     1273   
     1274    bool hasSeenWordBreakInThisBox = previousWordBreak.isNotNull();
     1275    VisiblePosition wordBreak = hasSeenWordBreakInThisBox ? previousWordBreak : Position(box->renderer()->node(), box->caretMinOffset(), Position::PositionIsOffsetInAnchor);
     1276    wordBreak = nextWordPosition(wordBreak);
     1277   
     1278    if (wordBreak == previousWordBreak) {
     1279        isLastWordBreakInBox = true;
     1280        return VisiblePosition();
     1281    }
     1282
     1283
     1284    // Given RTL box "ABC DEF" either follows a LTR box or is the first visual box in an LTR block as an example,
     1285    // 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)",
     1286    // where the number in parenthesis represents offset in visiblePosition.
     1287    // Start at offset 0, the first word break is at offset 3, the 2nd word break is at offset 7, and the 3rd word break should be at offset 0.
     1288    // But nextWordPosition() of offset 7 is offset 11, which should be ignored,
     1289    // and the position at offset 0 should be manually added as the last word break within the box.
     1290    if (positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality(wordBreak, box, offsetOfWordBreak)) {
     1291        isLastWordBreakInBox = false;
     1292        return wordBreak;
     1293    }
     1294   
     1295    isLastWordBreakInBox = true;
     1296    return lastWordBreakInBox(box, offsetOfWordBreak);
     1297}
     1298
     1299struct WordBoundaryEntry {
     1300    WordBoundaryEntry()
     1301        : offsetInInlineBox(invalidOffset)
     1302    {
     1303    }
     1304
     1305    WordBoundaryEntry(const VisiblePosition& position, int offset)
     1306        : visiblePosition(position)
     1307        , offsetInInlineBox(offset)
     1308    {
     1309    }
     1310
     1311    VisiblePosition visiblePosition;
     1312    int offsetInInlineBox;
     1313};
     1314   
     1315typedef Vector<WordBoundaryEntry, 50> WordBoundaryVector;
     1316   
     1317static void collectWordBreaksInBoxInsideBlockWithSameDirectionality(const InlineBox* box, WordBoundaryVector& orderedWordBoundaries)
     1318{
     1319    orderedWordBoundaries.clear();
     1320   
     1321    VisiblePosition wordBreak;
     1322    int offsetOfWordBreak = invalidOffset;
     1323    while (1) {
     1324        wordBreak = previousWordBreakInBoxInsideBlockWithSameDirectionality(box, wordBreak, offsetOfWordBreak);
     1325        if (wordBreak.isNull())
     1326            break;
     1327        WordBoundaryEntry wordBoundaryEntry(wordBreak, offsetOfWordBreak);
     1328        orderedWordBoundaries.append(wordBoundaryEntry);
     1329    }
     1330}
     1331
     1332static void collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(const InlineBox* box, WordBoundaryVector& orderedWordBoundaries)
     1333{
     1334    orderedWordBoundaries.clear();
     1335   
     1336    VisiblePosition wordBreak;
     1337    int offsetOfWordBreak = invalidOffset;
     1338    while (1) {
     1339        bool isLastWordBreakInBox = false;
     1340        wordBreak = nextWordBreakInBoxInsideBlockWithDifferentDirectionality(box, wordBreak, offsetOfWordBreak, isLastWordBreakInBox);
     1341        if (wordBreak.isNotNull()) {
     1342            WordBoundaryEntry wordBoundaryEntry(wordBreak, offsetOfWordBreak);
     1343            orderedWordBoundaries.append(wordBoundaryEntry);
     1344        }
     1345        if (isLastWordBreakInBox)
     1346            break;
     1347    }
     1348}
     1349   
    11761350static VisiblePosition previousWordBreakInBox(const InlineBox* box, int offset, TextDirection blockDirection)
    11771351{
     
    11901364}
    11911365
     1366static int greatestValueUnder(int offset, bool boxAndBlockAreInSameDirection, const WordBoundaryVector& orderedWordBoundaries)
     1367{
     1368    if (!orderedWordBoundaries.size())
     1369        return invalidOffset;
     1370    // FIXME: binary search.
     1371    if (boxAndBlockAreInSameDirection) {
     1372        for (unsigned i = 0; i < orderedWordBoundaries.size(); ++i) {
     1373            if (orderedWordBoundaries[i].offsetInInlineBox < offset)
     1374                return i;
     1375        }
     1376        return invalidOffset;
     1377    }
     1378    for (int i = orderedWordBoundaries.size() - 1; i >= 0; --i) {
     1379        if (orderedWordBoundaries[i].offsetInInlineBox < offset)
     1380            return i;
     1381    }
     1382    return invalidOffset;
     1383}
     1384
     1385static int smallestOffsetAbove(int offset, bool boxAndBlockAreInSameDirection, const WordBoundaryVector& orderedWordBoundaries)
     1386{
     1387    if (!orderedWordBoundaries.size())
     1388        return invalidOffset;
     1389    // FIXME: binary search.
     1390    if (boxAndBlockAreInSameDirection) {
     1391        for (int i = orderedWordBoundaries.size() - 1; i >= 0; --i) {
     1392            if (orderedWordBoundaries[i].offsetInInlineBox > offset)
     1393                return i;
     1394        }
     1395        return invalidOffset;
     1396    }
     1397    for (unsigned i = 0; i < orderedWordBoundaries.size(); ++i) {
     1398        if (orderedWordBoundaries[i].offsetInInlineBox > offset)
     1399            return i;
     1400    }
     1401    return invalidOffset;
     1402}
     1403 
    11921404static VisiblePosition leftWordBoundary(const InlineBox* box, int offset, TextDirection blockDirection)
    11931405{
     
    12161428    return VisiblePosition();
    12171429}
    1218 
     1430   
     1431static bool positionIsInsideBox(const VisiblePosition& wordBreak, const InlineBox* box)
     1432{
     1433    InlineBox* boxOfWordBreak;
     1434    int offsetOfWordBreak;
     1435    wordBreak.getInlineBoxAndOffset(boxOfWordBreak, offsetOfWordBreak);
     1436    return box == boxOfWordBreak && offsetOfWordBreak != box->caretMaxOffset() && offsetOfWordBreak != box->caretMinOffset();
     1437}
     1438
     1439static VisiblePosition positionBeforeNextWord(const VisiblePosition& position)
     1440{
     1441    VisiblePosition positionAfterCurrentWord = nextWordPosition(position);
     1442    VisiblePosition positionAfterNextWord = nextWordPosition(positionAfterCurrentWord);
     1443    if (positionAfterCurrentWord == positionAfterNextWord)
     1444        return positionAfterCurrentWord;
     1445    return previousWordPosition(positionAfterNextWord);
     1446}
     1447
     1448static VisiblePosition positionAfterPreviousWord(const VisiblePosition& position)
     1449{
     1450    VisiblePosition positionBeforeCurrentWord = previousWordPosition(position);
     1451    VisiblePosition positionBeforePreviousWord = previousWordPosition(positionBeforeCurrentWord);
     1452    if (positionBeforeCurrentWord == positionBeforePreviousWord)
     1453        return positionBeforeCurrentWord;
     1454    return nextWordPosition(positionBeforePreviousWord);
     1455}
     1456   
    12191457VisiblePosition leftWordPosition(const VisiblePosition& visiblePosition)
    12201458{
     
    12321470        return leftWordBoundary(box, offset, blockDirection);
    12331471   
    1234     // FIXME: Not implemented.
    1235     return VisiblePosition();
     1472   
     1473    VisiblePosition wordBreak;
     1474    if (box->direction() == blockDirection) {
     1475        if (blockDirection == RTL)
     1476            wordBreak = positionBeforeNextWord(visiblePosition);
     1477        else
     1478            wordBreak = previousWordPosition(visiblePosition);
     1479    } else {
     1480        if (blockDirection == RTL)
     1481            wordBreak = positionAfterPreviousWord(visiblePosition);
     1482        else
     1483            wordBreak = nextWordPosition(visiblePosition);
     1484    }
     1485    if (positionIsInsideBox(wordBreak, box))
     1486        return wordBreak;
     1487   
     1488    WordBoundaryVector orderedWordBoundaries;
     1489    if (box->direction() == blockDirection)
     1490        collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries);
     1491    else
     1492        collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries);
     1493
     1494    int index = box->isLeftToRightDirection() ? greatestValueUnder(offset, blockDirection == LTR, orderedWordBoundaries) :
     1495        smallestOffsetAbove(offset, blockDirection == RTL, orderedWordBoundaries);
     1496    if (index != invalidOffset)
     1497        return orderedWordBoundaries[index].visiblePosition;
     1498   
     1499    return leftWordBoundary(box->prevLeafChild(), invalidOffset, blockDirection);
    12361500}
    12371501
     
    12461510        return rightWordBoundary(box, offset, blockDirection);
    12471511    if (offset == box->caretRightmostOffset())
    1248         return rightWordBoundary(box->nextLeafChild(), -1, blockDirection);
    1249    
    1250     // FIXME: Not implemented.
    1251     return VisiblePosition();
    1252 }
    1253 
    1254 }
     1512        return rightWordBoundary(box->nextLeafChild(), invalidOffset, blockDirection);
     1513 
     1514    VisiblePosition wordBreak;
     1515    if (box->direction() == blockDirection) {
     1516        if (blockDirection == LTR)
     1517            wordBreak = positionBeforeNextWord(visiblePosition);
     1518        else
     1519            wordBreak = previousWordPosition(visiblePosition);
     1520    } else {
     1521        if (blockDirection == LTR)
     1522            wordBreak = positionAfterPreviousWord(visiblePosition);
     1523        else
     1524            wordBreak = nextWordPosition(visiblePosition);
     1525    }
     1526    if (positionIsInsideBox(wordBreak, box))
     1527        return wordBreak;
     1528   
     1529    WordBoundaryVector orderedWordBoundaries;
     1530    if (box->direction() == blockDirection)
     1531        collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries);
     1532    else
     1533        collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries);
     1534    int index = box->isLeftToRightDirection() ? smallestOffsetAbove(offset, blockDirection == LTR, orderedWordBoundaries) :
     1535        greatestValueUnder(offset, blockDirection == RTL, orderedWordBoundaries);
     1536    if (index != invalidOffset)
     1537        return orderedWordBoundaries[index].visiblePosition;
     1538   
     1539    return rightWordBoundary(box->nextLeafChild(), invalidOffset, blockDirection);
     1540}
     1541
     1542}
Note: See TracChangeset for help on using the changeset viewer.