| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights |
| 3 * reserved. | 3 * reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 1569 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1580 position.AnchorNode(), Strategy::CaretMaxOffset(*position.AnchorNode())); | 1580 position.AnchorNode(), Strategy::CaretMaxOffset(*position.AnchorNode())); |
| 1581 } | 1581 } |
| 1582 | 1582 |
| 1583 template <typename Strategy> | 1583 template <typename Strategy> |
| 1584 static PositionTemplate<Strategy> MostBackwardCaretPosition( | 1584 static PositionTemplate<Strategy> MostBackwardCaretPosition( |
| 1585 const PositionTemplate<Strategy>& position, | 1585 const PositionTemplate<Strategy>& position, |
| 1586 EditingBoundaryCrossingRule rule) { | 1586 EditingBoundaryCrossingRule rule) { |
| 1587 DCHECK(!NeedsLayoutTreeUpdate(position)) << position; | 1587 DCHECK(!NeedsLayoutTreeUpdate(position)) << position; |
| 1588 TRACE_EVENT0("input", "VisibleUnits::mostBackwardCaretPosition"); | 1588 TRACE_EVENT0("input", "VisibleUnits::mostBackwardCaretPosition"); |
| 1589 | 1589 |
| 1590 Node* start_node = position.AnchorNode(); | 1590 Node* const start_node = position.AnchorNode(); |
| 1591 if (!start_node) | 1591 if (!start_node) |
| 1592 return PositionTemplate<Strategy>(); | 1592 return PositionTemplate<Strategy>(); |
| 1593 | 1593 |
| 1594 // iterate backward from there, looking for a qualified position | 1594 // iterate backward from there, looking for a qualified position |
| 1595 Node* boundary = EnclosingVisualBoundary<Strategy>(start_node); | 1595 Node* const boundary = EnclosingVisualBoundary<Strategy>(start_node); |
| 1596 // FIXME: PositionIterator should respect Before and After positions. | 1596 // FIXME: PositionIterator should respect Before and After positions. |
| 1597 PositionIteratorAlgorithm<Strategy> last_visible( | 1597 PositionIteratorAlgorithm<Strategy> last_visible( |
| 1598 AdjustPositionForBackwardIteration<Strategy>(position)); | 1598 AdjustPositionForBackwardIteration<Strategy>(position)); |
| 1599 PositionIteratorAlgorithm<Strategy> current_pos = last_visible; | 1599 const bool start_editable = HasEditableStyle(*start_node); |
| 1600 bool start_editable = HasEditableStyle(*start_node); | |
| 1601 Node* last_node = start_node; | 1600 Node* last_node = start_node; |
| 1602 bool boundary_crossed = false; | 1601 bool boundary_crossed = false; |
| 1603 for (; !current_pos.AtStart(); current_pos.Decrement()) { | 1602 for (PositionIteratorAlgorithm<Strategy> current_pos = last_visible; |
| 1603 !current_pos.AtStart(); current_pos.Decrement()) { |
| 1604 Node* current_node = current_pos.GetNode(); | 1604 Node* current_node = current_pos.GetNode(); |
| 1605 // Don't check for an editability change if we haven't moved to a different | 1605 // Don't check for an editability change if we haven't moved to a different |
| 1606 // node, to avoid the expense of computing hasEditableStyle(). | 1606 // node, to avoid the expense of computing hasEditableStyle(). |
| 1607 if (current_node != last_node) { | 1607 if (current_node != last_node) { |
| 1608 // Don't change editability. | 1608 // Don't change editability. |
| 1609 bool current_editable = HasEditableStyle(*current_node); | 1609 const bool current_editable = HasEditableStyle(*current_node); |
| 1610 if (start_editable != current_editable) { | 1610 if (start_editable != current_editable) { |
| 1611 if (rule == kCannotCrossEditingBoundary) | 1611 if (rule == kCannotCrossEditingBoundary) |
| 1612 break; | 1612 break; |
| 1613 boundary_crossed = true; | 1613 boundary_crossed = true; |
| 1614 } | 1614 } |
| 1615 last_node = current_node; | 1615 last_node = current_node; |
| 1616 } | 1616 } |
| 1617 | 1617 |
| 1618 // If we've moved to a position that is visually distinct, return the last | 1618 // If we've moved to a position that is visually distinct, return the last |
| 1619 // saved position. There is code below that terminates early if we're | 1619 // saved position. There is code below that terminates early if we're |
| 1620 // *about* to move to a visually distinct position. | 1620 // *about* to move to a visually distinct position. |
| 1621 if (EndsOfNodeAreVisuallyDistinctPositions(current_node) && | 1621 if (EndsOfNodeAreVisuallyDistinctPositions(current_node) && |
| 1622 current_node != boundary) | 1622 current_node != boundary) |
| 1623 return last_visible.DeprecatedComputePosition(); | 1623 return last_visible.DeprecatedComputePosition(); |
| 1624 | 1624 |
| 1625 // skip position in non-laid out or invisible node | 1625 // skip position in non-laid out or invisible node |
| 1626 LayoutObject* layout_object = | 1626 LayoutObject* const layout_object = |
| 1627 AssociatedLayoutObjectOf(*current_node, current_pos.OffsetInLeafNode()); | 1627 AssociatedLayoutObjectOf(*current_node, current_pos.OffsetInLeafNode()); |
| 1628 if (!layout_object || | 1628 if (!layout_object || |
| 1629 layout_object->Style()->Visibility() != EVisibility::kVisible) | 1629 layout_object->Style()->Visibility() != EVisibility::kVisible) |
| 1630 continue; | 1630 continue; |
| 1631 | 1631 |
| 1632 if (rule == kCanCrossEditingBoundary && boundary_crossed) { | 1632 if (rule == kCanCrossEditingBoundary && boundary_crossed) { |
| 1633 last_visible = current_pos; | 1633 last_visible = current_pos; |
| 1634 break; | 1634 break; |
| 1635 } | 1635 } |
| 1636 | 1636 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1648 // Return position after tables and nodes which have content that can be | 1648 // Return position after tables and nodes which have content that can be |
| 1649 // ignored. | 1649 // ignored. |
| 1650 if (EditingIgnoresContent(*current_node) || | 1650 if (EditingIgnoresContent(*current_node) || |
| 1651 IsDisplayInsideTable(current_node)) { | 1651 IsDisplayInsideTable(current_node)) { |
| 1652 if (current_pos.AtEndOfNode()) | 1652 if (current_pos.AtEndOfNode()) |
| 1653 return PositionTemplate<Strategy>::AfterNode(current_node); | 1653 return PositionTemplate<Strategy>::AfterNode(current_node); |
| 1654 continue; | 1654 continue; |
| 1655 } | 1655 } |
| 1656 | 1656 |
| 1657 // return current position if it is in laid out text | 1657 // return current position if it is in laid out text |
| 1658 if (layout_object->IsText() && | 1658 if (!layout_object->IsText()) |
| 1659 ToLayoutText(layout_object)->FirstTextBox()) { | 1659 continue; |
| 1660 LayoutText* const text_layout_object = ToLayoutText(layout_object); | 1660 LayoutText* const text_layout_object = ToLayoutText(layout_object); |
| 1661 const unsigned text_start_offset = text_layout_object->TextStartOffset(); | 1661 if (!text_layout_object->FirstTextBox()) |
| 1662 if (current_node != start_node) { | 1662 continue; |
| 1663 // This assertion fires in layout tests in the case-transform.html test | 1663 const unsigned text_start_offset = text_layout_object->TextStartOffset(); |
| 1664 // because of a mix-up between offsets in the text in the DOM tree with | 1664 if (current_node != start_node) { |
| 1665 // text in the layout tree which can have a different length due to case | 1665 // This assertion fires in layout tests in the case-transform.html test |
| 1666 // transformation. | 1666 // because of a mix-up between offsets in the text in the DOM tree with |
| 1667 // Until we resolve that, disable this so we can run the layout tests! | 1667 // text in the layout tree which can have a different length due to case |
| 1668 // DCHECK_GE(currentOffset, layoutObject->caretMaxOffset()); | 1668 // transformation. |
| 1669 return PositionTemplate<Strategy>( | 1669 // Until we resolve that, disable this so we can run the layout tests! |
| 1670 current_node, layout_object->CaretMaxOffset() + text_start_offset); | 1670 // DCHECK_GE(currentOffset, layoutObject->caretMaxOffset()); |
| 1671 } | 1671 return PositionTemplate<Strategy>( |
| 1672 current_node, layout_object->CaretMaxOffset() + text_start_offset); |
| 1673 } |
| 1672 | 1674 |
| 1673 if (CanBeBackwardCaretPosition(text_layout_object, | 1675 if (CanBeBackwardCaretPosition(text_layout_object, |
| 1674 current_pos.OffsetInLeafNode())) { | 1676 current_pos.OffsetInLeafNode())) { |
| 1675 return current_pos.ComputePosition(); | 1677 return current_pos.ComputePosition(); |
| 1676 } | |
| 1677 } | 1678 } |
| 1678 } | 1679 } |
| 1679 return last_visible.DeprecatedComputePosition(); | 1680 return last_visible.DeprecatedComputePosition(); |
| 1680 } | 1681 } |
| 1681 | 1682 |
| 1682 // The text continues on the next line only if the last text box is not on this | 1683 // The text continues on the next line only if the last text box is not on this |
| 1683 // line and none of the boxes on this line have a larger start offset. | 1684 // line and none of the boxes on this line have a larger start offset. |
| 1684 static bool DoesContinueOnNextLine(const LayoutText& text_layout_object, | 1685 static bool DoesContinueOnNextLine(const LayoutText& text_layout_object, |
| 1685 InlineBox* box, | 1686 InlineBox* box, |
| 1686 unsigned text_offset) { | 1687 unsigned text_offset) { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1764 return MostBackwardCaretPosition<EditingInFlatTreeStrategy>(position, rule); | 1765 return MostBackwardCaretPosition<EditingInFlatTreeStrategy>(position, rule); |
| 1765 } | 1766 } |
| 1766 | 1767 |
| 1767 template <typename Strategy> | 1768 template <typename Strategy> |
| 1768 PositionTemplate<Strategy> MostForwardCaretPosition( | 1769 PositionTemplate<Strategy> MostForwardCaretPosition( |
| 1769 const PositionTemplate<Strategy>& position, | 1770 const PositionTemplate<Strategy>& position, |
| 1770 EditingBoundaryCrossingRule rule) { | 1771 EditingBoundaryCrossingRule rule) { |
| 1771 DCHECK(!NeedsLayoutTreeUpdate(position)) << position; | 1772 DCHECK(!NeedsLayoutTreeUpdate(position)) << position; |
| 1772 TRACE_EVENT0("input", "VisibleUnits::mostForwardCaretPosition"); | 1773 TRACE_EVENT0("input", "VisibleUnits::mostForwardCaretPosition"); |
| 1773 | 1774 |
| 1774 Node* start_node = position.AnchorNode(); | 1775 Node* const start_node = position.AnchorNode(); |
| 1775 if (!start_node) | 1776 if (!start_node) |
| 1776 return PositionTemplate<Strategy>(); | 1777 return PositionTemplate<Strategy>(); |
| 1777 | 1778 |
| 1778 // iterate forward from there, looking for a qualified position | 1779 // iterate forward from there, looking for a qualified position |
| 1779 Node* boundary = EnclosingVisualBoundary<Strategy>(start_node); | 1780 Node* const boundary = EnclosingVisualBoundary<Strategy>(start_node); |
| 1780 // FIXME: PositionIterator should respect Before and After positions. | 1781 // FIXME: PositionIterator should respect Before and After positions. |
| 1781 PositionIteratorAlgorithm<Strategy> last_visible( | 1782 PositionIteratorAlgorithm<Strategy> last_visible( |
| 1782 position.IsAfterAnchor() | 1783 position.IsAfterAnchor() |
| 1783 ? PositionTemplate<Strategy>::EditingPositionOf( | 1784 ? PositionTemplate<Strategy>::EditingPositionOf( |
| 1784 position.AnchorNode(), | 1785 position.AnchorNode(), |
| 1785 Strategy::CaretMaxOffset(*position.AnchorNode())) | 1786 Strategy::CaretMaxOffset(*position.AnchorNode())) |
| 1786 : position); | 1787 : position); |
| 1787 PositionIteratorAlgorithm<Strategy> current_pos = last_visible; | 1788 const bool start_editable = HasEditableStyle(*start_node); |
| 1788 bool start_editable = HasEditableStyle(*start_node); | |
| 1789 Node* last_node = start_node; | 1789 Node* last_node = start_node; |
| 1790 bool boundary_crossed = false; | 1790 bool boundary_crossed = false; |
| 1791 for (; !current_pos.AtEnd(); current_pos.Increment()) { | 1791 for (PositionIteratorAlgorithm<Strategy> current_pos = last_visible; |
| 1792 !current_pos.AtEnd(); current_pos.Increment()) { |
| 1792 Node* current_node = current_pos.GetNode(); | 1793 Node* current_node = current_pos.GetNode(); |
| 1793 // Don't check for an editability change if we haven't moved to a different | 1794 // Don't check for an editability change if we haven't moved to a different |
| 1794 // node, to avoid the expense of computing hasEditableStyle(). | 1795 // node, to avoid the expense of computing hasEditableStyle(). |
| 1795 if (current_node != last_node) { | 1796 if (current_node != last_node) { |
| 1796 // Don't change editability. | 1797 // Don't change editability. |
| 1797 bool current_editable = HasEditableStyle(*current_node); | 1798 const bool current_editable = HasEditableStyle(*current_node); |
| 1798 if (start_editable != current_editable) { | 1799 if (start_editable != current_editable) { |
| 1799 if (rule == kCannotCrossEditingBoundary) | 1800 if (rule == kCannotCrossEditingBoundary) |
| 1800 break; | 1801 break; |
| 1801 boundary_crossed = true; | 1802 boundary_crossed = true; |
| 1802 } | 1803 } |
| 1803 | 1804 |
| 1804 last_node = current_node; | 1805 last_node = current_node; |
| 1805 } | 1806 } |
| 1806 | 1807 |
| 1807 // stop before going above the body, up into the head | 1808 // stop before going above the body, up into the head |
| 1808 // return the last visible streamer position | 1809 // return the last visible streamer position |
| 1809 if (isHTMLBodyElement(*current_node) && current_pos.AtEndOfNode()) | 1810 if (isHTMLBodyElement(*current_node) && current_pos.AtEndOfNode()) |
| 1810 break; | 1811 break; |
| 1811 | 1812 |
| 1812 // Do not move to a visually distinct position. | 1813 // Do not move to a visually distinct position. |
| 1813 if (EndsOfNodeAreVisuallyDistinctPositions(current_node) && | 1814 if (EndsOfNodeAreVisuallyDistinctPositions(current_node) && |
| 1814 current_node != boundary) | 1815 current_node != boundary) |
| 1815 return last_visible.DeprecatedComputePosition(); | 1816 return last_visible.DeprecatedComputePosition(); |
| 1816 // Do not move past a visually disinct position. | 1817 // Do not move past a visually disinct position. |
| 1817 // Note: The first position after the last in a node whose ends are visually | 1818 // Note: The first position after the last in a node whose ends are visually |
| 1818 // distinct positions will be [boundary->parentNode(), | 1819 // distinct positions will be [boundary->parentNode(), |
| 1819 // originalBlock->nodeIndex() + 1]. | 1820 // originalBlock->nodeIndex() + 1]. |
| 1820 if (boundary && Strategy::Parent(*boundary) == current_node) | 1821 if (boundary && Strategy::Parent(*boundary) == current_node) |
| 1821 return last_visible.DeprecatedComputePosition(); | 1822 return last_visible.DeprecatedComputePosition(); |
| 1822 | 1823 |
| 1823 // skip position in non-laid out or invisible node | 1824 // skip position in non-laid out or invisible node |
| 1824 LayoutObject* layout_object = | 1825 LayoutObject* const layout_object = |
| 1825 AssociatedLayoutObjectOf(*current_node, current_pos.OffsetInLeafNode()); | 1826 AssociatedLayoutObjectOf(*current_node, current_pos.OffsetInLeafNode()); |
| 1826 if (!layout_object || | 1827 if (!layout_object || |
| 1827 layout_object->Style()->Visibility() != EVisibility::kVisible) | 1828 layout_object->Style()->Visibility() != EVisibility::kVisible) |
| 1828 continue; | 1829 continue; |
| 1829 | 1830 |
| 1830 if (rule == kCanCrossEditingBoundary && boundary_crossed) { | 1831 if (rule == kCanCrossEditingBoundary && boundary_crossed) |
| 1831 last_visible = current_pos; | 1832 return current_pos.DeprecatedComputePosition(); |
| 1832 break; | |
| 1833 } | |
| 1834 | 1833 |
| 1835 // track last visible streamer position | 1834 // track last visible streamer position |
| 1836 if (IsStreamer<Strategy>(current_pos)) | 1835 if (IsStreamer<Strategy>(current_pos)) |
| 1837 last_visible = current_pos; | 1836 last_visible = current_pos; |
| 1838 | 1837 |
| 1839 // Return position before tables and nodes which have content that can be | 1838 // Return position before tables and nodes which have content that can be |
| 1840 // ignored. | 1839 // ignored. |
| 1841 if (EditingIgnoresContent(*current_node) || | 1840 if (EditingIgnoresContent(*current_node) || |
| 1842 IsDisplayInsideTable(current_node)) { | 1841 IsDisplayInsideTable(current_node)) { |
| 1843 if (current_pos.OffsetInLeafNode() <= layout_object->CaretMinOffset()) | 1842 if (current_pos.OffsetInLeafNode() <= layout_object->CaretMinOffset()) |
| 1844 return PositionTemplate<Strategy>::EditingPositionOf( | 1843 return PositionTemplate<Strategy>::EditingPositionOf( |
| 1845 current_node, layout_object->CaretMinOffset()); | 1844 current_node, layout_object->CaretMinOffset()); |
| 1846 continue; | 1845 continue; |
| 1847 } | 1846 } |
| 1848 | 1847 |
| 1849 // return current position if it is in laid out text | 1848 // return current position if it is in laid out text |
| 1850 if (layout_object->IsText() && | 1849 if (!layout_object->IsText()) |
| 1851 ToLayoutText(layout_object)->FirstTextBox()) { | 1850 continue; |
| 1852 LayoutText* const text_layout_object = ToLayoutText(layout_object); | 1851 LayoutText* const text_layout_object = ToLayoutText(layout_object); |
| 1853 const unsigned text_start_offset = text_layout_object->TextStartOffset(); | 1852 if (!text_layout_object->FirstTextBox()) |
| 1854 if (current_node != start_node) { | 1853 continue; |
| 1855 DCHECK(current_pos.AtStartOfNode()); | 1854 const unsigned text_start_offset = text_layout_object->TextStartOffset(); |
| 1856 return PositionTemplate<Strategy>( | 1855 if (current_node != start_node) { |
| 1857 current_node, layout_object->CaretMinOffset() + text_start_offset); | 1856 DCHECK(current_pos.AtStartOfNode()); |
| 1858 } | 1857 return PositionTemplate<Strategy>( |
| 1858 current_node, layout_object->CaretMinOffset() + text_start_offset); |
| 1859 } |
| 1859 | 1860 |
| 1860 if (CanBeForwardCaretPosition(text_layout_object, | 1861 if (CanBeForwardCaretPosition(text_layout_object, |
| 1861 current_pos.OffsetInLeafNode())) { | 1862 current_pos.OffsetInLeafNode())) { |
| 1862 return current_pos.ComputePosition(); | 1863 return current_pos.ComputePosition(); |
| 1863 } | |
| 1864 } | 1864 } |
| 1865 } | 1865 } |
| 1866 return last_visible.DeprecatedComputePosition(); | 1866 return last_visible.DeprecatedComputePosition(); |
| 1867 } | 1867 } |
| 1868 | 1868 |
| 1869 // TODO(editing-dev): This function is just moved out from | 1869 // TODO(editing-dev): This function is just moved out from |
| 1870 // |MostForwardCaretPosition()|. We should study this function more and | 1870 // |MostForwardCaretPosition()|. We should study this function more and |
| 1871 // name it appropriately. See https://trac.webkit.org/changeset/32438/ | 1871 // name it appropriately. See https://trac.webkit.org/changeset/32438/ |
| 1872 // which introduce this. | 1872 // which introduce this. |
| 1873 static bool CanBeForwardCaretPosition(const LayoutText* text_layout_object, | 1873 static bool CanBeForwardCaretPosition(const LayoutText* text_layout_object, |
| (...skipping 898 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2772 | 2772 |
| 2773 IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) { | 2773 IntRect ComputeTextRect(const EphemeralRangeInFlatTree& range) { |
| 2774 return EnclosingIntRect(ComputeTextRectTemplate(range)); | 2774 return EnclosingIntRect(ComputeTextRectTemplate(range)); |
| 2775 } | 2775 } |
| 2776 | 2776 |
| 2777 FloatRect ComputeTextFloatRect(const EphemeralRange& range) { | 2777 FloatRect ComputeTextFloatRect(const EphemeralRange& range) { |
| 2778 return ComputeTextRectTemplate(range); | 2778 return ComputeTextRectTemplate(range); |
| 2779 } | 2779 } |
| 2780 | 2780 |
| 2781 } // namespace blink | 2781 } // namespace blink |
| OLD | NEW |