OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 1438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1449 VisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direc
tion) | 1449 VisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direc
tion) |
1450 { | 1450 { |
1451 return direction == LTR ? logicalStartOfLine(c) : logicalEndOfLine(c); | 1451 return direction == LTR ? logicalStartOfLine(c) : logicalEndOfLine(c); |
1452 } | 1452 } |
1453 | 1453 |
1454 VisiblePosition rightBoundaryOfLine(const VisiblePosition& c, TextDirection dire
ction) | 1454 VisiblePosition rightBoundaryOfLine(const VisiblePosition& c, TextDirection dire
ction) |
1455 { | 1455 { |
1456 return direction == LTR ? logicalEndOfLine(c) : logicalStartOfLine(c); | 1456 return direction == LTR ? logicalEndOfLine(c) : logicalStartOfLine(c); |
1457 } | 1457 } |
1458 | 1458 |
| 1459 static bool isNonTextLeafChild(LayoutObject* object) |
| 1460 { |
| 1461 if (object->slowFirstChild()) |
| 1462 return false; |
| 1463 if (object->isText()) |
| 1464 return false; |
| 1465 return true; |
| 1466 } |
| 1467 |
| 1468 static InlineTextBox* searchAheadForBetterMatch(LayoutObject* layoutObject) |
| 1469 { |
| 1470 LayoutBlock* container = layoutObject->containingBlock(); |
| 1471 for (LayoutObject* next = layoutObject->nextInPreOrder(container); next; nex
t = next->nextInPreOrder(container)) { |
| 1472 if (next->isLayoutBlock()) |
| 1473 return 0; |
| 1474 if (next->isBR()) |
| 1475 return 0; |
| 1476 if (isNonTextLeafChild(next)) |
| 1477 return 0; |
| 1478 if (next->isText()) { |
| 1479 InlineTextBox* match = 0; |
| 1480 int minOffset = INT_MAX; |
| 1481 for (InlineTextBox* box = toLayoutText(next)->firstTextBox(); box; b
ox = box->nextTextBox()) { |
| 1482 int caretMinOffset = box->caretMinOffset(); |
| 1483 if (caretMinOffset < minOffset) { |
| 1484 match = box; |
| 1485 minOffset = caretMinOffset; |
| 1486 } |
| 1487 } |
| 1488 if (match) |
| 1489 return match; |
| 1490 } |
| 1491 } |
| 1492 return 0; |
| 1493 } |
| 1494 |
| 1495 template <typename Strategy> |
| 1496 PositionAlgorithm<Strategy> downstreamIgnoringEditingBoundaries(PositionAlgorith
m<Strategy> position) |
| 1497 { |
| 1498 PositionAlgorithm<Strategy> lastPosition; |
| 1499 while (position != lastPosition) { |
| 1500 lastPosition = position; |
| 1501 position = position.downstream(CanCrossEditingBoundary); |
| 1502 } |
| 1503 return position; |
| 1504 } |
| 1505 |
| 1506 template <typename Strategy> |
| 1507 PositionAlgorithm<Strategy> upstreamIgnoringEditingBoundaries(PositionAlgorithm<
Strategy> position) |
| 1508 { |
| 1509 PositionAlgorithm<Strategy> lastPosition; |
| 1510 while (position != lastPosition) { |
| 1511 lastPosition = position; |
| 1512 position = position.upstream(CanCrossEditingBoundary); |
| 1513 } |
| 1514 return position; |
| 1515 } |
| 1516 |
| 1517 template <typename Strategy> |
| 1518 static InlineBoxPosition computeInlineBoxPositionAlgorithm(const PositionAlgorit
hm<Strategy>& position, TextAffinity affinity, TextDirection primaryDirection) |
| 1519 { |
| 1520 InlineBox* inlineBox = nullptr; |
| 1521 int caretOffset = position.computeEditingOffset(); |
| 1522 Node* const anchorNode = position.anchorNode(); |
| 1523 LayoutObject* layoutObject = anchorNode->isShadowRoot() ? toShadowRoot(ancho
rNode)->host()->layoutObject() : anchorNode->layoutObject(); |
| 1524 |
| 1525 if (!layoutObject->isText()) { |
| 1526 inlineBox = 0; |
| 1527 if (canHaveChildrenForEditing(anchorNode) && layoutObject->isLayoutBlock
Flow() && hasRenderedNonAnonymousDescendantsWithHeight(layoutObject)) { |
| 1528 // Try a visually equivalent position with possibly opposite |
| 1529 // editability. This helps in case |this| is in an editable block |
| 1530 // but surrounded by non-editable positions. It acts to negate the |
| 1531 // logic at the beginning of LayoutObject::createVisiblePosition(). |
| 1532 PositionAlgorithm<Strategy> equivalent = downstreamIgnoringEditingBo
undaries(position); |
| 1533 if (equivalent == position) { |
| 1534 equivalent = upstreamIgnoringEditingBoundaries(position); |
| 1535 if (equivalent == position || downstreamIgnoringEditingBoundarie
s(equivalent) == position) |
| 1536 return InlineBoxPosition(inlineBox, caretOffset); |
| 1537 } |
| 1538 |
| 1539 return computeInlineBoxPosition(equivalent, TextAffinity::Upstream,
primaryDirection); |
| 1540 } |
| 1541 if (layoutObject->isBox()) { |
| 1542 inlineBox = toLayoutBox(layoutObject)->inlineBoxWrapper(); |
| 1543 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && care
tOffset < inlineBox->caretMaxOffset())) |
| 1544 return InlineBoxPosition(inlineBox, caretOffset); |
| 1545 } |
| 1546 } else { |
| 1547 LayoutText* textLayoutObject = toLayoutText(layoutObject); |
| 1548 |
| 1549 InlineTextBox* box; |
| 1550 InlineTextBox* candidate = 0; |
| 1551 |
| 1552 for (box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox
()) { |
| 1553 int caretMinOffset = box->caretMinOffset(); |
| 1554 int caretMaxOffset = box->caretMaxOffset(); |
| 1555 |
| 1556 if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset ||
(caretOffset == caretMaxOffset && box->isLineBreak())) |
| 1557 continue; |
| 1558 |
| 1559 if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) |
| 1560 return InlineBoxPosition(box, caretOffset); |
| 1561 |
| 1562 if (((caretOffset == caretMaxOffset) ^ (affinity == TextAffinity::Do
wnstream)) |
| 1563 || ((caretOffset == caretMinOffset) ^ (affinity == TextAffinity:
:Upstream)) |
| 1564 || (caretOffset == caretMaxOffset && box->nextLeafChild() && box
->nextLeafChild()->isLineBreak())) |
| 1565 break; |
| 1566 |
| 1567 candidate = box; |
| 1568 } |
| 1569 if (candidate && candidate == textLayoutObject->lastTextBox() && affinit
y == TextAffinity::Downstream) { |
| 1570 box = searchAheadForBetterMatch(textLayoutObject); |
| 1571 if (box) |
| 1572 caretOffset = box->caretMinOffset(); |
| 1573 } |
| 1574 inlineBox = box ? box : candidate; |
| 1575 } |
| 1576 |
| 1577 if (!inlineBox) |
| 1578 return InlineBoxPosition(inlineBox, caretOffset); |
| 1579 |
| 1580 unsigned char level = inlineBox->bidiLevel(); |
| 1581 |
| 1582 if (inlineBox->direction() == primaryDirection) { |
| 1583 if (caretOffset == inlineBox->caretRightmostOffset()) { |
| 1584 InlineBox* nextBox = inlineBox->nextLeafChild(); |
| 1585 if (!nextBox || nextBox->bidiLevel() >= level) |
| 1586 return InlineBoxPosition(inlineBox, caretOffset); |
| 1587 |
| 1588 level = nextBox->bidiLevel(); |
| 1589 InlineBox* prevBox = inlineBox; |
| 1590 do { |
| 1591 prevBox = prevBox->prevLeafChild(); |
| 1592 } while (prevBox && prevBox->bidiLevel() > level); |
| 1593 |
| 1594 // For example, abc FED 123 ^ CBA |
| 1595 if (prevBox && prevBox->bidiLevel() == level) |
| 1596 return InlineBoxPosition(inlineBox, caretOffset); |
| 1597 |
| 1598 // For example, abc 123 ^ CBA |
| 1599 while (InlineBox* nextBox = inlineBox->nextLeafChild()) { |
| 1600 if (nextBox->bidiLevel() < level) |
| 1601 break; |
| 1602 inlineBox = nextBox; |
| 1603 } |
| 1604 return InlineBoxPosition(inlineBox, inlineBox->caretRightmostOffset(
)); |
| 1605 } |
| 1606 |
| 1607 InlineBox* prevBox = inlineBox->prevLeafChild(); |
| 1608 if (!prevBox || prevBox->bidiLevel() >= level) |
| 1609 return InlineBoxPosition(inlineBox, caretOffset); |
| 1610 |
| 1611 level = prevBox->bidiLevel(); |
| 1612 InlineBox* nextBox = inlineBox; |
| 1613 do { |
| 1614 nextBox = nextBox->nextLeafChild(); |
| 1615 } while (nextBox && nextBox->bidiLevel() > level); |
| 1616 |
| 1617 if (nextBox && nextBox->bidiLevel() == level) |
| 1618 return InlineBoxPosition(inlineBox, caretOffset); |
| 1619 |
| 1620 while (InlineBox* prevBox = inlineBox->prevLeafChild()) { |
| 1621 if (prevBox->bidiLevel() < level) |
| 1622 break; |
| 1623 inlineBox = prevBox; |
| 1624 } |
| 1625 return InlineBoxPosition(inlineBox, inlineBox->caretLeftmostOffset()); |
| 1626 } |
| 1627 |
| 1628 if (caretOffset == inlineBox->caretLeftmostOffset()) { |
| 1629 InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak(); |
| 1630 if (!prevBox || prevBox->bidiLevel() < level) { |
| 1631 // Left edge of a secondary run. Set to the right edge of the entire |
| 1632 // run. |
| 1633 while (InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBrea
k()) { |
| 1634 if (nextBox->bidiLevel() < level) |
| 1635 break; |
| 1636 inlineBox = nextBox; |
| 1637 } |
| 1638 return InlineBoxPosition(inlineBox, inlineBox->caretRightmostOffset(
)); |
| 1639 } |
| 1640 |
| 1641 if (prevBox->bidiLevel() > level) { |
| 1642 // Right edge of a "tertiary" run. Set to the left edge of that run. |
| 1643 while (InlineBox* tertiaryBox = inlineBox->prevLeafChildIgnoringLine
Break()) { |
| 1644 if (tertiaryBox->bidiLevel() <= level) |
| 1645 break; |
| 1646 inlineBox = tertiaryBox; |
| 1647 } |
| 1648 return InlineBoxPosition(inlineBox, inlineBox->caretLeftmostOffset()
); |
| 1649 } |
| 1650 return InlineBoxPosition(inlineBox, caretOffset); |
| 1651 } |
| 1652 |
| 1653 if (layoutObject && layoutObject->style()->unicodeBidi() == Plaintext) { |
| 1654 if (inlineBox->bidiLevel() < level) |
| 1655 return InlineBoxPosition(inlineBox, inlineBox->caretLeftmostOffset()
); |
| 1656 return InlineBoxPosition(inlineBox, inlineBox->caretRightmostOffset()); |
| 1657 } |
| 1658 |
| 1659 InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak(); |
| 1660 if (!nextBox || nextBox->bidiLevel() < level) { |
| 1661 // Right edge of a secondary run. Set to the left edge of the entire |
| 1662 // run. |
| 1663 while (InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak())
{ |
| 1664 if (prevBox->bidiLevel() < level) |
| 1665 break; |
| 1666 inlineBox = prevBox; |
| 1667 } |
| 1668 return InlineBoxPosition(inlineBox, inlineBox->caretLeftmostOffset()); |
| 1669 } |
| 1670 |
| 1671 if (nextBox->bidiLevel() <= level) |
| 1672 return InlineBoxPosition(inlineBox, caretOffset); |
| 1673 |
| 1674 // Left edge of a "tertiary" run. Set to the right edge of that run. |
| 1675 while (InlineBox* tertiaryBox = inlineBox->nextLeafChildIgnoringLineBreak())
{ |
| 1676 if (tertiaryBox->bidiLevel() <= level) |
| 1677 break; |
| 1678 inlineBox = tertiaryBox; |
| 1679 } |
| 1680 return InlineBoxPosition(inlineBox, inlineBox->caretRightmostOffset()); |
| 1681 } |
| 1682 |
| 1683 template <typename Strategy> |
| 1684 static InlineBoxPosition computeInlineBoxPositionAlgorithm(const PositionAlgorit
hm<Strategy>& position, TextAffinity affinity) |
| 1685 { |
| 1686 return computeInlineBoxPositionAlgorithm<Strategy>(position, affinity, prima
ryDirectionOf(*position.anchorNode())); |
| 1687 } |
| 1688 |
| 1689 InlineBoxPosition computeInlineBoxPosition(const Position& position, TextAffinit
y affinity) |
| 1690 { |
| 1691 return computeInlineBoxPositionAlgorithm<EditingStrategy>(position, affinity
); |
| 1692 } |
| 1693 |
| 1694 InlineBoxPosition computeInlineBoxPosition(const PositionInComposedTree& positio
n, TextAffinity affinity) |
| 1695 { |
| 1696 return computeInlineBoxPositionAlgorithm<EditingInComposedTreeStrategy>(posi
tion, affinity); |
| 1697 } |
| 1698 |
| 1699 InlineBoxPosition computeInlineBoxPosition(const VisiblePosition& position) |
| 1700 { |
| 1701 return computeInlineBoxPosition(position.deepEquivalent(), position.affinity
()); |
| 1702 } |
| 1703 |
| 1704 InlineBoxPosition computeInlineBoxPosition(const Position& position, TextAffinit
y affinity, TextDirection primaryDirection) |
| 1705 { |
| 1706 return computeInlineBoxPositionAlgorithm<EditingStrategy>(position, affinity
, primaryDirection); |
| 1707 } |
| 1708 |
| 1709 InlineBoxPosition computeInlineBoxPosition(const PositionInComposedTree& positio
n, TextAffinity affinity, TextDirection primaryDirection) |
| 1710 { |
| 1711 return computeInlineBoxPositionAlgorithm<EditingInComposedTreeStrategy>(posi
tion, affinity, primaryDirection); |
| 1712 } |
| 1713 |
1459 LayoutRect localCaretRectOfPosition(const PositionWithAffinity& position, Layout
Object*& layoutObject) | 1714 LayoutRect localCaretRectOfPosition(const PositionWithAffinity& position, Layout
Object*& layoutObject) |
1460 { | 1715 { |
1461 if (position.position().isNull()) { | 1716 if (position.position().isNull()) { |
1462 layoutObject = nullptr; | 1717 layoutObject = nullptr; |
1463 return LayoutRect(); | 1718 return LayoutRect(); |
1464 } | 1719 } |
1465 Node* node = position.position().anchorNode(); | 1720 Node* node = position.position().anchorNode(); |
1466 | 1721 |
1467 layoutObject = node->layoutObject(); | 1722 layoutObject = node->layoutObject(); |
1468 if (!layoutObject) | 1723 if (!layoutObject) |
(...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1946 { | 2201 { |
1947 return mostBackwardCaretPosition<EditingStrategy>(position, rule); | 2202 return mostBackwardCaretPosition<EditingStrategy>(position, rule); |
1948 } | 2203 } |
1949 | 2204 |
1950 PositionInComposedTree mostBackwardCaretPosition(const PositionInComposedTree& p
osition, EditingBoundaryCrossingRule rule) | 2205 PositionInComposedTree mostBackwardCaretPosition(const PositionInComposedTree& p
osition, EditingBoundaryCrossingRule rule) |
1951 { | 2206 { |
1952 return mostBackwardCaretPosition<EditingInComposedTreeStrategy>(position, ru
le); | 2207 return mostBackwardCaretPosition<EditingInComposedTreeStrategy>(position, ru
le); |
1953 } | 2208 } |
1954 | 2209 |
1955 } | 2210 } |
OLD | NEW |