1102 static const int invalidOffset = -1;
1103 static const int offsetNotFound = -1;
1104
1105 static bool positionIsInBox(const VisiblePosition& wordBreak, const InlineBox* box, int& offsetOfWordBreak)
1106 {
1107 if (wordBreak.isNull())
1108 return false;
1109
1110 InlineBox* boxOfWordBreak;
1111 wordBreak.getInlineBoxAndOffset(boxOfWordBreak, offsetOfWordBreak);
1112 return box == boxOfWordBreak;
1113 }
1114
1115 static VisiblePosition previousWordBreakInBoxInsideBlockWithSameDirectionality(const InlineBox* box, const VisiblePosition& previousWordBreak, int& offsetOfWordBreak)
1116 {
1117 // In a LTR block, the word break should be on the left boundary of a word.
1118 // In a RTL block, the word break should be on the right boundary of a word.
1119 // Because nextWordPosition() returns the word break on the right boundary of the word for LTR text,
1120 // we need to use previousWordPosition() to traverse words within the inline boxes from right to left
1121 // to find the previous word break (i.e. the first word break on the left). The same applies to RTL text.
1122
1123 bool hasSeenWordBreakInThisBox = previousWordBreak.isNotNull();
1124
1125 VisiblePosition wordBreak;
1126
1127 if (hasSeenWordBreakInThisBox)
1128 wordBreak = previousWordBreak;
1129 else {
1130 wordBreak = createLegacyEditingPosition(box->renderer()->node(), box->caretMaxOffset());
1131
1132 // Return the rightmost word boundary of LTR box or leftmost word boundary of RTL box if
1133 // it is not in the previously visited boxes. For example, given a logical text
1134 // "abc def hij opq", there are 2 boxes: the "abc def " (starts at 0 and length is 8)
1135 // and the "hij opq" (starts at 12 and length is 7). The word breaks are
1136 // "abc |def | hij |opq". We normally catch the word break between "def" and "hij" when
1137 // we visit the box that contains "hij opq", but this word break doesn't exist in the box
1138 // that contains "hij opq" when there are multiple spaces. So we detect it when we're
1139 // traversing the box that contains "abc def " instead.
1140
1141 if ((box->isLeftToRightDirection() && box->nextLeafChild())
1142 || (!box->isLeftToRightDirection() && box->prevLeafChild())) {
1143
1144 VisiblePosition positionAfterWord = nextBoundary(wordBreak, nextWordPositionBoundary);
1145 if (positionAfterWord.isNotNull()) {
1146 VisiblePosition positionBeforeWord = previousBoundary(positionAfterWord, previousWordPositionBoundary);
1147
1148 if (positionIsInBox(positionBeforeWord, box, offsetOfWordBreak))
1149 return positionBeforeWord;
1150 }
1151 }
1152 }
1153
1154 wordBreak = previousBoundary(wordBreak, previousWordPositionBoundary);
1155 if (previousWordBreak == wordBreak)
1156 return VisiblePosition();
1157
1158 return positionIsInBox(wordBreak, box, offsetOfWordBreak) ? wordBreak : VisiblePosition();
1159 }
1160
1161 static VisiblePosition leftmostPositionInRTLBoxInLTRBlock(const InlineBox* box)
1162 {
1163 // FIXME: Probably need to take care of bidi level too.
1164 Node* node = box->renderer()->node();
1165 InlineBox* previousLeaf = box->prevLeafChild();
1166 InlineBox* nextLeaf = box->nextLeafChild();
1167
1168 if (previousLeaf && !previousLeaf->isLeftToRightDirection())
1169 return createLegacyEditingPosition(node, box->caretMaxOffset());
1170
1171 if (nextLeaf && !nextLeaf->isLeftToRightDirection()) {
1172 if (previousLeaf)
1173 return createLegacyEditingPosition(previousLeaf->renderer()->node(), previousLeaf->caretMaxOffset());
1174
1175 InlineBox* lastRTLLeaf;
1176 do {
1177 lastRTLLeaf = nextLeaf;
1178 nextLeaf = nextLeaf->nextLeafChild();
1179 } while (nextLeaf && !nextLeaf->isLeftToRightDirection());
1180 return createLegacyEditingPosition(lastRTLLeaf->renderer()->node(), lastRTLLeaf->caretMinOffset());
1181 }
1182
1183 return createLegacyEditingPosition(node, box->caretMinOffset());
1184 }
1185
1186 static VisiblePosition rightmostPositionInLTRBoxInRTLBlock(const InlineBox* box)
1187 {
1188 // FIXME: Probably need to take care of bidi level too.
1189 Node* node = box->renderer()->node();
1190 InlineBox* previousLeaf = box->prevLeafChild();
1191 InlineBox* nextLeaf = box->nextLeafChild();
1192
1193 if (nextLeaf && nextLeaf->isLeftToRightDirection())
1194 return createLegacyEditingPosition(node, box->caretMaxOffset());
1195
1196 if (previousLeaf && previousLeaf->isLeftToRightDirection()) {
1197 if (nextLeaf)
1198 return createLegacyEditingPosition(nextLeaf->renderer()->node(), nextLeaf->caretMaxOffset());
1199
1200 InlineBox* firstLTRLeaf;
1201 do {
1202 firstLTRLeaf = previousLeaf;
1203 previousLeaf = previousLeaf->prevLeafChild();
1204 } while (previousLeaf && previousLeaf->isLeftToRightDirection());
1205 return createLegacyEditingPosition(firstLTRLeaf->renderer()->node(), firstLTRLeaf->caretMinOffset());
1206 }
1207
1208 return createLegacyEditingPosition(node, box->caretMinOffset());
1209 }
1210
1211 static VisiblePosition lastWordBreakInBox(const InlineBox* box, int& offsetOfWordBreak)
1212 {
1213 // Add the leftmost word break for RTL box or rightmost word break for LTR box.
1214 InlineBox* previousLeaf = box->prevLeafChild();
1215 InlineBox* nextLeaf = box->nextLeafChild();
1216 VisiblePosition boundaryPosition;
1217 if (box->direction() == RTL && (!previousLeaf || previousLeaf->isLeftToRightDirection()))
1218 boundaryPosition = leftmostPositionInRTLBoxInLTRBlock(box);
1219 else if (box->direction() == LTR && (!nextLeaf || !nextLeaf->isLeftToRightDirection()))
1220 boundaryPosition = rightmostPositionInLTRBoxInRTLBlock(box);
1221
1222 if (boundaryPosition.isNull())
1223 return VisiblePosition();
1224
1225 VisiblePosition wordBreak = nextBoundary(boundaryPosition, nextWordPositionBoundary);
1226 if (wordBreak.isNull())
1227 wordBreak = boundaryPosition;
1228 else if (wordBreak != boundaryPosition)
1229 wordBreak = previousBoundary(wordBreak, previousWordPositionBoundary);
1230
1231 return positionIsInBox(wordBreak, box, offsetOfWordBreak) ? wordBreak : VisiblePosition();
1232 }
1233
1234 static bool positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality(const VisiblePosition& wordBreak, const InlineBox* box, int& offsetOfWordBreak)
1235 {
1236 int previousOffset = offsetOfWordBreak;
1237 return positionIsInBox(wordBreak, box, offsetOfWordBreak)
1238 && (previousOffset == invalidOffset || previousOffset < offsetOfWordBreak);
1239 }
1240
1241 static VisiblePosition nextWordBreakInBoxInsideBlockWithDifferentDirectionality(
1242 const InlineBox* box, const VisiblePosition& previousWordBreak, int& offsetOfWordBreak, bool& isLastWordBreakInBox)
1243 {
1244 // FIXME: Probably need to take care of bidi level too.
1245
1246 // In a LTR block, the word break should be on the left boundary of a word.
1247 // In a RTL block, the word break should be on the right boundary of a word.
1248 // Because previousWordPosition() returns the word break on the right boundary of the word for RTL text,
1249 // we need to use nextWordPosition() to traverse words within the inline boxes from right to left to find the next word break.
1250 // The same applies to LTR text, in which words are traversed within the inline boxes from left to right.
1251
1252 bool hasSeenWordBreakInThisBox = previousWordBreak.isNotNull();
1253 VisiblePosition wordBreak = hasSeenWordBreakInThisBox ? previousWordBreak :
1254 createLegacyEditingPosition(box->renderer()->node(), box->caretMinOffset());
1255
1256 wordBreak = nextBoundary(wordBreak, nextWordPositionBoundary);
1257
1258 // Given RTL box "ABC DEF" either follows a LTR box or is the first visual box in an LTR block as an example,
1259 // 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)",
1260 // where the number in parenthesis represents offset in visiblePosition.
1261 // 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.
1262 // But nextWordPosition() of offset 7 is offset 11, which should be ignored,
1263 // and the position at offset 0 should be manually added as the last word break within the box.
1264 if (wordBreak != previousWordBreak && positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality(wordBreak, box, offsetOfWordBreak)) {
1265 isLastWordBreakInBox = false;
1266 return wordBreak;
1267 }
1268
1269 isLastWordBreakInBox = true;
1270 return lastWordBreakInBox(box, offsetOfWordBreak);
1271 }
1272
1273 struct WordBoundaryEntry {
1274 WordBoundaryEntry()
1275 : offsetInInlineBox(invalidOffset)
1276 {
1277 }
1278
1279 WordBoundaryEntry(const VisiblePosition& position, int offset)
1280 : visiblePosition(position)
1281 , offsetInInlineBox(offset)
1282 {
1283 }
1284
1285 VisiblePosition visiblePosition;
1286 int offsetInInlineBox;
1287 };
1288
1289 typedef Vector<WordBoundaryEntry, 50> WordBoundaryVector;
1290
1291 static void collectWordBreaksInBoxInsideBlockWithSameDirectionality(const InlineBox* box, WordBoundaryVector& orderedWordBoundaries)
1292 {
1293 orderedWordBoundaries.clear();
1294
1295 VisiblePosition wordBreak;
1296 int offsetOfWordBreak = invalidOffset;
1297 while (1) {
1298 wordBreak = previousWordBreakInBoxInsideBlockWithSameDirectionality(box, wordBreak, offsetOfWordBreak);
1299 if (wordBreak.isNull())
1300 break;
1301 WordBoundaryEntry wordBoundaryEntry(wordBreak, offsetOfWordBreak);
1302 orderedWordBoundaries.append(wordBoundaryEntry);
1303 }
1304 }
1305
1306 static void collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(const InlineBox* box, WordBoundaryVector& orderedWordBoundaries)
1307 {
1308 orderedWordBoundaries.clear();
1309
1310 VisiblePosition wordBreak;
1311 int offsetOfWordBreak = invalidOffset;
1312 bool isLastWordBreakInBox = false;
1313 while (1) {
1314 wordBreak = nextWordBreakInBoxInsideBlockWithDifferentDirectionality(box, wordBreak, offsetOfWordBreak, isLastWordBreakInBox);
1315 if (wordBreak.isNotNull()) {
1316 WordBoundaryEntry wordBoundaryEntry(wordBreak, offsetOfWordBreak);
1317 orderedWordBoundaries.append(wordBoundaryEntry);
1318 }
1319 if (isLastWordBreakInBox)
1320 break;
1321 }
1322 }
1323
1324 static void collectWordBreaksInBox(const InlineBox* box, WordBoundaryVector& orderedWordBoundaries, TextDirection blockDirection)
1325 {
1326 if (box->direction() == blockDirection)
1327 collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries);
1328 else
1329 collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries);
1330 }
1331
1332 static VisiblePosition previousWordBoundaryInBox(const InlineBox* box, int offset)
1333 {
1334 int offsetOfWordBreak = 0;
1335 VisiblePosition wordBreak;
1336 while (true) {
1337 wordBreak = previousWordBreakInBoxInsideBlockWithSameDirectionality(box, wordBreak, offsetOfWordBreak);
1338 if (wordBreak.isNull())
1339 break;
1340 if (offset == invalidOffset || offsetOfWordBreak != offset)
1341 return wordBreak;
1342 }
1343 return VisiblePosition();
1344 }
1345
1346 static VisiblePosition nextWordBoundaryInBox(const InlineBox* box, int offset)
1347 {
1348 int offsetOfWordBreak = 0;
1349 VisiblePosition wordBreak;
1350 bool isLastWordBreakInBox = false;
1351 do {
1352 wordBreak = nextWordBreakInBoxInsideBlockWithDifferentDirectionality(box, wordBreak, offsetOfWordBreak, isLastWordBreakInBox);
1353 if (wordBreak.isNotNull() && (offset == invalidOffset || offsetOfWordBreak != offset))
1354 return wordBreak;
1355 } while (!isLastWordBreakInBox);
1356 return VisiblePosition();
1357 }
1358
1359 static VisiblePosition visuallyLastWordBoundaryInBox(const InlineBox* box, int offset, TextDirection blockDirection)
1360 {
1361 WordBoundaryVector orderedWordBoundaries;
1362 collectWordBreaksInBox(box, orderedWordBoundaries, blockDirection);
1363 if (!orderedWordBoundaries.size())
1364 return VisiblePosition();
1365 if (offset == invalidOffset || orderedWordBoundaries[orderedWordBoundaries.size() - 1].offsetInInlineBox != offset)
1366 return orderedWordBoundaries[orderedWordBoundaries.size() - 1].visiblePosition;
1367 if (orderedWordBoundaries.size() > 1)
1368 return orderedWordBoundaries[orderedWordBoundaries.size() - 2].visiblePosition;
1369 return VisiblePosition();
1370 }
1371
1372 static int greatestOffsetUnder(int offset, bool boxAndBlockAreInSameDirection, const WordBoundaryVector& orderedWordBoundaries)
1373 {
1374 if (!orderedWordBoundaries.size())
1375 return offsetNotFound;
1376 // FIXME: binary search.
1377 if (boxAndBlockAreInSameDirection) {
1378 for (unsigned i = 0; i < orderedWordBoundaries.size(); ++i) {
1379 if (orderedWordBoundaries[i].offsetInInlineBox < offset)
1380 return i;
1381 }
1382 return offsetNotFound;
1383 }
1384 for (int i = orderedWordBoundaries.size() - 1; i >= 0; --i) {
1385 if (orderedWordBoundaries[i].offsetInInlineBox < offset)
1386 return i;
1387 }
1388 return offsetNotFound;
1389 }
1390
1391 static int smallestOffsetAbove(int offset, bool boxAndBlockAreInSameDirection, const WordBoundaryVector& orderedWordBoundaries)
1392 {
1393 if (!orderedWordBoundaries.size())
1394 return offsetNotFound;
1395 // FIXME: binary search.
1396 if (boxAndBlockAreInSameDirection) {
1397 for (int i = orderedWordBoundaries.size() - 1; i >= 0; --i) {
1398 if (orderedWordBoundaries[i].offsetInInlineBox > offset)
1399 return i;
1400 }
1401 return offsetNotFound;
1402 }
1403 for (unsigned i = 0; i < orderedWordBoundaries.size(); ++i) {
1404 if (orderedWordBoundaries[i].offsetInInlineBox > offset)
1405 return i;
1406 }
1407 return offsetNotFound;
1408 }
1409
1410 static const RootInlineBox* previousRootInlineBox(const InlineBox* box)
1411 {
1412 Node* node = box->renderer()->node();
1413 Node* enclosingBlockNode = enclosingNodeWithNonInlineRenderer(node);
1414 Node* previousNode = node->previousLeafNode();
1415 while (previousNode && enclosingBlockNode == enclosingNodeWithNonInlineRenderer(previousNode))
1416 previousNode = previousNode->previousLeafNode();
1417
1418 while (previousNode && !previousNode->isShadowRoot()) {
1419 Position pos = createLegacyEditingPosition(previousNode, caretMaxOffset(previousNode));
1420
1421 if (pos.isCandidate()) {
1422 RenderedPosition renderedPos(pos, DOWNSTREAM);
1423 RootInlineBox* root = renderedPos.rootBox();
1424 if (root)
1425 return root;
1426 }
1427
1428 previousNode = previousNode->previousLeafNode();
1429 }
1430 return 0;
1431 }
1432
1433 static const RootInlineBox* nextRootInlineBox(const InlineBox* box)
1434 {
1435 Node* node = box->renderer()->node();
1436 Node* enclosingBlockNode = enclosingNodeWithNonInlineRenderer(node);
1437 Node* nextNode = node->nextLeafNode();
1438 while (nextNode && enclosingBlockNode == enclosingNodeWithNonInlineRenderer(nextNode))
1439 nextNode = nextNode->nextLeafNode();
1440
1441 while (nextNode && !nextNode->isShadowRoot()) {
1442 Position pos;
1443 pos = createLegacyEditingPosition(nextNode, caretMinOffset(nextNode));
1444
1445 if (pos.isCandidate()) {
1446 RenderedPosition renderedPos(pos, DOWNSTREAM);
1447 RootInlineBox* root = renderedPos.rootBox();
1448 if (root)
1449 return root;
1450 }
1451
1452 nextNode = nextNode->nextLeafNode();
1453 }
1454 return 0;
1455 }
1456
1457 static const InlineBox* leftInlineBox(const InlineBox* box, TextDirection blockDirection)
1458 {
1459 if (box->prevLeafChild())
1460 return box->prevLeafChild();
1461
1462 const RootInlineBox* rootBox = box->root();
1463 const bool isBlockLTR = blockDirection == LTR;
1464 const InlineFlowBox* leftLineBox = isBlockLTR ? rootBox->prevLineBox() : rootBox->nextLineBox();
1465 if (leftLineBox)
1466 return leftLineBox->lastLeafChild();
1467
1468 const RootInlineBox* leftRootInlineBox = isBlockLTR ? previousRootInlineBox(box) :
1469 nextRootInlineBox(box);
1470 return leftRootInlineBox ? leftRootInlineBox->lastLeafChild() : 0;
1471 }
1472
1473 static const InlineBox* rightInlineBox(const InlineBox* box, TextDirection blockDirection)
1474 {
1475 if (box->nextLeafChild())
1476 return box->nextLeafChild();
1477
1478 const RootInlineBox* rootBox = box->root();
1479 const bool isBlockLTR = blockDirection == LTR;
1480 const InlineFlowBox* rightLineBox = isBlockLTR ? rootBox->nextLineBox() : rootBox->prevLineBox();
1481 if (rightLineBox)
1482 return rightLineBox->firstLeafChild();
1483
1484 const RootInlineBox* rightRootInlineBox = isBlockLTR ? nextRootInlineBox(box) :
1485 previousRootInlineBox(box);
1486 return rightRootInlineBox ? rightRootInlineBox->firstLeafChild() : 0;
1487 }
1488
1489 static VisiblePosition leftWordBoundary(const InlineBox* box, int offset, TextDirection blockDirection)
1490 {
1491 VisiblePosition wordBreak;
1492 for (const InlineBox* adjacentBox = box; adjacentBox; adjacentBox = leftInlineBox(adjacentBox, blockDirection)) {
1493 if (blockDirection == LTR) {
1494 if (adjacentBox->isLeftToRightDirection())
1495 wordBreak = previousWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset);
1496 else
1497 wordBreak = nextWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset);
1498 } else
1499 wordBreak = visuallyLastWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection);
1500 if (wordBreak.isNotNull())
1501 return wordBreak;
1502 }
1503 return VisiblePosition();
1504 }
1505
1506 static VisiblePosition rightWordBoundary(const InlineBox* box, int offset, TextDirection blockDirection)
1507 {
1508
1509 VisiblePosition wordBreak;
1510 for (const InlineBox* adjacentBox = box; adjacentBox; adjacentBox = rightInlineBox(adjacentBox, blockDirection)) {
1511 if (blockDirection == RTL) {
1512 if (adjacentBox->isLeftToRightDirection())
1513 wordBreak = nextWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset);
1514 else
1515 wordBreak = previousWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset);
1516 } else
1517 wordBreak = visuallyLastWordBoundaryInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection);
1518 if (!wordBreak.isNull())
1519 return wordBreak;
1520 }
1521 return VisiblePosition();
1522 }
1523
1524 static bool positionIsInBoxButNotOnBoundary(const VisiblePosition& wordBreak, const InlineBox* box)
1525 {
1526 int offsetOfWordBreak;
1527 return positionIsInBox(wordBreak, box, offsetOfWordBreak)
1528 && offsetOfWordBreak != box->caretMaxOffset() && offsetOfWordBreak != box->caretMinOffset();
1529 }
1530
1531 static VisiblePosition leftWordPositionIgnoringEditingBoundary(const VisiblePosition& visiblePosition)
1532 {
1533 InlineBox* box;
1534 int offset;
1535 visiblePosition.getInlineBoxAndOffset(box, offset);
1536
1537 if (!box)
1538 return VisiblePosition();
1539
1540 TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent());
1541
1542 // FIXME: If the box's directionality is the same as that of the enclosing block, when the offset is at the box boundary
1543 // and the direction is towards inside the box, do I still need to make it a special case? For example, a LTR box inside a LTR block,
1544 // when offset is at box's caretMinOffset and the direction is DirectionRight, should it be taken care as a general case?
1545 if (offset == box->caretLeftmostOffset())
1546 return leftWordBoundary(leftInlineBox(box, blockDirection), invalidOffset, blockDirection);
1547 if (offset == box->caretRightmostOffset())
1548 return leftWordBoundary(box, offset, blockDirection);
1549
1550
1551 VisiblePosition wordBreak;
1552 if (blockDirection == LTR) {
1553 if (box->direction() == blockDirection)
1554 wordBreak = previousBoundary(visiblePosition, previousWordPositionBoundary);
1555 else
1556 wordBreak = nextBoundary(visiblePosition, nextWordPositionBoundary);
1557 }
1558 if (wordBreak.isNotNull() && positionIsInBoxButNotOnBoundary(wordBreak, box))
1559 return wordBreak;
1560
1561 WordBoundaryVector orderedWordBoundaries;
1562 collectWordBreaksInBox(box, orderedWordBoundaries, blockDirection);
1563
1564 int index = box->isLeftToRightDirection() ? greatestOffsetUnder(offset, blockDirection == LTR, orderedWordBoundaries)
1565 : smallestOffsetAbove(offset, blockDirection == RTL, orderedWordBoundaries);
1566 if (index >= 0)
1567 return orderedWordBoundaries[index].visiblePosition;
1568
1569 return leftWordBoundary(leftInlineBox(box, blockDirection), invalidOffset, blockDirection);
1570 }
1571
1572 static VisiblePosition rightWordPositionIgnoringEditingBoundary(const VisiblePosition& visiblePosition)
1573 {
1574 InlineBox* box;
1575 int offset;
1576 visiblePosition.getInlineBoxAndOffset(box, offset);
1577
1578 if (!box)
1579 return VisiblePosition();
1580
1581 TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent());
1582
1583 if (offset == box->caretLeftmostOffset())
1584 return rightWordBoundary(box, offset, blockDirection);
1585 if (offset == box->caretRightmostOffset())
1586 return rightWordBoundary(rightInlineBox(box, blockDirection), invalidOffset, blockDirection);
1587
1588 VisiblePosition wordBreak;
1589 if (blockDirection == RTL) {
1590 if (box->direction() == blockDirection)
1591 wordBreak = previousBoundary(visiblePosition, previousWordPositionBoundary);
1592 else
1593 wordBreak = nextBoundary(visiblePosition, nextWordPositionBoundary);
1594 }
1595 if (wordBreak.isNotNull() && positionIsInBoxButNotOnBoundary(wordBreak, box))
1596 return wordBreak;
1597
1598 WordBoundaryVector orderedWordBoundaries;
1599 collectWordBreaksInBox(box, orderedWordBoundaries, blockDirection);
1600
1601 int index = box->isLeftToRightDirection() ? smallestOffsetAbove(offset, blockDirection == LTR, orderedWordBoundaries)
1602 : greatestOffsetUnder(offset, blockDirection == RTL, orderedWordBoundaries);
1603 if (index >= 0)
1604 return orderedWordBoundaries[index].visiblePosition;
1605
1606 return rightWordBoundary(rightInlineBox(box, blockDirection), invalidOffset, blockDirection);
1607 }
1608
1609 VisiblePosition leftWordPosition(const VisiblePosition& visiblePosition)
1610 {
1611 if (visiblePosition.isNull())
1612 return VisiblePosition();
1613
1614 VisiblePosition leftWordBreak = leftWordPositionIgnoringEditingBoundary(visiblePosition);
1615 leftWordBreak = visiblePosition.honorEditingBoundaryAtOrBefore(leftWordBreak);
1616
1617 // FIXME: How should we handle a non-editable position?
1618 if (leftWordBreak.isNull() && isEditablePosition(visiblePosition.deepEquivalent())) {
1619 TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent());
1620 leftWordBreak = blockDirection == LTR ? startOfEditableContent(visiblePosition) : endOfEditableContent(visiblePosition);
1621 }
1622 return leftWordBreak;
1623 }
1624
1625 VisiblePosition rightWordPosition(const VisiblePosition& visiblePosition)
1626 {
1627 if (visiblePosition.isNull())
1628 return VisiblePosition();
1629
1630 VisiblePosition rightWordBreak = rightWordPositionIgnoringEditingBoundary(visiblePosition);
1631 rightWordBreak = visiblePosition.honorEditingBoundaryAtOrBefore(rightWordBreak);
1632
1633 // FIXME: How should we handle a non-editable position?
1634 if (rightWordBreak.isNull() && isEditablePosition(visiblePosition.deepEquivalent())) {
1635 TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent());
1636 rightWordBreak = blockDirection == LTR ? endOfEditableContent(visiblePosition) : startOfEditableContent(visiblePosition);
1637 }
1638 return rightWordBreak;
1639 }
1640