Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: Source/core/editing/VisibleUnits.cpp

Issue 1299323006: [Editing][CodeHealth] Move Position::up/downstream implementation to VisibleUnit.cpp (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/core/editing/VisibleUnits.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 18 matching lines...) Expand all
29 #include "bindings/core/v8/ExceptionState.h" 29 #include "bindings/core/v8/ExceptionState.h"
30 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 30 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
31 #include "core/HTMLNames.h" 31 #include "core/HTMLNames.h"
32 #include "core/dom/Document.h" 32 #include "core/dom/Document.h"
33 #include "core/dom/Element.h" 33 #include "core/dom/Element.h"
34 #include "core/dom/NodeTraversal.h" 34 #include "core/dom/NodeTraversal.h"
35 #include "core/dom/Text.h" 35 #include "core/dom/Text.h"
36 #include "core/editing/EditingUtilities.h" 36 #include "core/editing/EditingUtilities.h"
37 #include "core/editing/FrameSelection.h" 37 #include "core/editing/FrameSelection.h"
38 #include "core/editing/Position.h" 38 #include "core/editing/Position.h"
39 #include "core/editing/PositionIterator.h"
39 #include "core/editing/RenderedPosition.h" 40 #include "core/editing/RenderedPosition.h"
40 #include "core/editing/TextAffinity.h" 41 #include "core/editing/TextAffinity.h"
41 #include "core/editing/VisiblePosition.h" 42 #include "core/editing/VisiblePosition.h"
42 #include "core/editing/iterators/BackwardsCharacterIterator.h" 43 #include "core/editing/iterators/BackwardsCharacterIterator.h"
43 #include "core/editing/iterators/CharacterIterator.h" 44 #include "core/editing/iterators/CharacterIterator.h"
44 #include "core/editing/iterators/SimplifiedBackwardsTextIterator.h" 45 #include "core/editing/iterators/SimplifiedBackwardsTextIterator.h"
45 #include "core/editing/iterators/TextIterator.h" 46 #include "core/editing/iterators/TextIterator.h"
46 #include "core/html/HTMLBRElement.h" 47 #include "core/html/HTMLBRElement.h"
47 #include "core/layout/HitTestRequest.h" 48 #include "core/layout/HitTestRequest.h"
48 #include "core/layout/HitTestResult.h" 49 #include "core/layout/HitTestResult.h"
(...skipping 1546 matching lines...) Expand 10 before | Expand all | Expand 10 after
1595 } 1596 }
1596 1597
1597 if (previousRenderedEditable(position1.anchorNode()) == position2.anchorNode () 1598 if (previousRenderedEditable(position1.anchorNode()) == position2.anchorNode ()
1598 && !renderedOffset1 && renderedOffset2 == caretMaxOffset(position2.ancho rNode())) { 1599 && !renderedOffset1 && renderedOffset2 == caretMaxOffset(position2.ancho rNode())) {
1599 return false; 1600 return false;
1600 } 1601 }
1601 1602
1602 return true; 1603 return true;
1603 } 1604 }
1604 1605
1605 } 1606 // Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions.
1607 // If true, adjacent candidates are visually distinct.
1608 // FIXME: Disregard nodes with layoutObjects that have no height, as we do in is Candidate.
1609 // FIXME: Share code with isCandidate, if possible.
1610 static bool endsOfNodeAreVisuallyDistinctPositions(Node* node)
1611 {
1612 if (!node || !node->layoutObject())
1613 return false;
1614
1615 if (!node->layoutObject()->isInline())
1616 return true;
1617
1618 // Don't include inline tables.
1619 if (isHTMLTableElement(*node))
1620 return false;
1621
1622 // A Marquee elements are moving so we should assume their ends are always
1623 // visibily distinct.
1624 if (isHTMLMarqueeElement(*node))
1625 return true;
1626
1627 // There is a VisiblePosition inside an empty inline-block container.
1628 return node->layoutObject()->isReplaced() && canHaveChildrenForEditing(node) && toLayoutBox(node->layoutObject())->size().height() != 0 && !node->hasChildre n();
1629 }
1630
1631 template <typename Strategy>
1632 static Node* enclosingVisualBoundary(Node* node)
1633 {
1634 while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
1635 node = Strategy::parent(*node);
1636
1637 return node;
1638 }
1639
1640 // upstream() and downstream() want to return positions that are either in a
1641 // text node or at just before a non-text node. This method checks for that.
1642 template <typename Strategy>
1643 static bool isStreamer(const PositionIteratorAlgorithm<Strategy>& pos)
1644 {
1645 if (!pos.node())
1646 return true;
1647
1648 if (isAtomicNode(pos.node()))
1649 return true;
1650
1651 return pos.atStartOfNode();
1652 }
1653
1654 template <typename Strategy>
1655 static PositionAlgorithm<Strategy> mostForwardCaretPosition(const PositionAlgori thm<Strategy>& position, EditingBoundaryCrossingRule rule)
1656 {
1657 TRACE_EVENT0("blink", "Position::upstream");
1658
1659 Node* startNode = position.anchorNode();
1660 if (!startNode)
1661 return PositionAlgorithm<Strategy>();
1662
1663 // iterate backward from there, looking for a qualified position
1664 Node* boundary = enclosingVisualBoundary<Strategy>(startNode);
1665 // FIXME: PositionIterator should respect Before and After positions.
1666 PositionIteratorAlgorithm<Strategy> lastVisible(position.isAfterAnchor() ? P ositionAlgorithm<Strategy>::editingPositionOf(position.anchorNode(), Strategy::c aretMaxOffset(*position.anchorNode())) : position);
1667 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible;
1668 bool startEditable = startNode->hasEditableStyle();
1669 Node* lastNode = startNode;
1670 bool boundaryCrossed = false;
1671 for (; !currentPos.atStart(); currentPos.decrement()) {
1672 Node* currentNode = currentPos.node();
1673 // Don't check for an editability change if we haven't moved to a differ ent node,
1674 // to avoid the expense of computing hasEditableStyle().
1675 if (currentNode != lastNode) {
1676 // Don't change editability.
1677 bool currentEditable = currentNode->hasEditableStyle();
1678 if (startEditable != currentEditable) {
1679 if (rule == CannotCrossEditingBoundary)
1680 break;
1681 boundaryCrossed = true;
1682 }
1683 lastNode = currentNode;
1684 }
1685
1686 // If we've moved to a position that is visually distinct, return the la st saved position. There
1687 // is code below that terminates early if we're *about* to move to a vis ually distinct position.
1688 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode ! = boundary)
1689 return lastVisible.deprecatedComputePosition();
1690
1691 // skip position in non-laid out or invisible node
1692 LayoutObject* layoutObject = currentNode->layoutObject();
1693 if (!layoutObject || layoutObject->style()->visibility() != VISIBLE)
1694 continue;
1695
1696 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
1697 lastVisible = currentPos;
1698 break;
1699 }
1700
1701 // track last visible streamer position
1702 if (isStreamer<Strategy>(currentPos))
1703 lastVisible = currentPos;
1704
1705 // Don't move past a position that is visually distinct. We could rely on code above to terminate and
1706 // return lastVisible on the next iteration, but we terminate early to a void doing a nodeIndex() call.
1707 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.at StartOfNode())
1708 return lastVisible.deprecatedComputePosition();
1709
1710 // Return position after tables and nodes which have content that can be ignored.
1711 if (Strategy::editingIgnoresContent(currentNode) || isRenderedHTMLTableE lement(currentNode)) {
1712 if (currentPos.atEndOfNode())
1713 return PositionAlgorithm<Strategy>::afterNode(currentNode);
1714 continue;
1715 }
1716
1717 // return current position if it is in laid out text
1718 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox() ) {
1719 if (currentNode != startNode) {
1720 // This assertion fires in layout tests in the case-transform.ht ml test because
1721 // of a mix-up between offsets in the text in the DOM tree with text in the
1722 // layout tree which can have a different length due to case tra nsformation.
1723 // Until we resolve that, disable this so we can run the layout tests!
1724 // ASSERT(currentOffset >= layoutObject->caretMaxOffset());
1725 return PositionAlgorithm<Strategy>(currentNode, layoutObject->ca retMaxOffset());
1726 }
1727
1728 unsigned textOffset = currentPos.offsetInLeafNode();
1729 LayoutText* textLayoutObject = toLayoutText(layoutObject);
1730 InlineTextBox* lastTextBox = textLayoutObject->lastTextBox();
1731 for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) {
1732 if (textOffset <= box->start() + box->len()) {
1733 if (textOffset > box->start())
1734 return currentPos.computePosition();
1735 continue;
1736 }
1737
1738 if (box == lastTextBox || textOffset != box->start() + box->len( ) + 1)
1739 continue;
1740
1741 // The text continues on the next line only if the last text box is not on this line and
1742 // none of the boxes on this line have a larger start offset.
1743
1744 bool continuesOnNextLine = true;
1745 InlineBox* otherBox = box;
1746 while (continuesOnNextLine) {
1747 otherBox = otherBox->nextLeafChild();
1748 if (!otherBox)
1749 break;
1750 if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() > textOffset))
1751 continuesOnNextLine = false;
1752 }
1753
1754 otherBox = box;
1755 while (continuesOnNextLine) {
1756 otherBox = otherBox->prevLeafChild();
1757 if (!otherBox)
1758 break;
1759 if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() > textOffset))
1760 continuesOnNextLine = false;
1761 }
1762
1763 if (continuesOnNextLine)
1764 return currentPos.computePosition();
1765 }
1766 }
1767 }
1768 return lastVisible.deprecatedComputePosition();
1769 }
1770
1771 Position mostForwardCaretPosition(const Position& position, EditingBoundaryCross ingRule rule)
1772 {
1773 return mostForwardCaretPosition<EditingStrategy>(position, rule);
1774 }
1775
1776 PositionInComposedTree mostForwardCaretPosition(const PositionInComposedTree& po sition, EditingBoundaryCrossingRule rule)
1777 {
1778 return mostForwardCaretPosition<EditingInComposedTreeStrategy>(position, rul e);
1779 }
1780
1781 template <typename Strategy>
1782 PositionAlgorithm<Strategy> mostBackwardCaretPosition(const PositionAlgorithm<St rategy>& position, EditingBoundaryCrossingRule rule)
1783 {
1784 TRACE_EVENT0("blink", "Position::downstream");
1785
1786 Node* startNode = position.anchorNode();
1787 if (!startNode)
1788 return PositionAlgorithm<Strategy>();
1789
1790 // iterate forward from there, looking for a qualified position
1791 Node* boundary = enclosingVisualBoundary<Strategy>(startNode);
1792 // FIXME: PositionIterator should respect Before and After positions.
1793 PositionIteratorAlgorithm<Strategy> lastVisible(position.isAfterAnchor() ? P ositionAlgorithm<Strategy>::editingPositionOf(position.anchorNode(), Strategy::c aretMaxOffset(*position.anchorNode())) : position);
1794 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible;
1795 bool startEditable = startNode->hasEditableStyle();
1796 Node* lastNode = startNode;
1797 bool boundaryCrossed = false;
1798 for (; !currentPos.atEnd(); currentPos.increment()) {
1799 Node* currentNode = currentPos.node();
1800 // Don't check for an editability change if we haven't moved to a differ ent node,
1801 // to avoid the expense of computing hasEditableStyle().
1802 if (currentNode != lastNode) {
1803 // Don't change editability.
1804 bool currentEditable = currentNode->hasEditableStyle();
1805 if (startEditable != currentEditable) {
1806 if (rule == CannotCrossEditingBoundary)
1807 break;
1808 boundaryCrossed = true;
1809 }
1810
1811 lastNode = currentNode;
1812 }
1813
1814 // stop before going above the body, up into the head
1815 // return the last visible streamer position
1816 if (isHTMLBodyElement(*currentNode) && currentPos.atEndOfNode())
1817 break;
1818
1819 // Do not move to a visually distinct position.
1820 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode ! = boundary)
1821 return lastVisible.deprecatedComputePosition();
1822 // Do not move past a visually disinct position.
1823 // Note: The first position after the last in a node whose ends are visu ally distinct
1824 // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1].
1825 if (boundary && Strategy::parent(*boundary) == currentNode)
1826 return lastVisible.deprecatedComputePosition();
1827
1828 // skip position in non-laid out or invisible node
1829 LayoutObject* layoutObject = currentNode->layoutObject();
1830 if (!layoutObject || layoutObject->style()->visibility() != VISIBLE)
1831 continue;
1832
1833 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
1834 lastVisible = currentPos;
1835 break;
1836 }
1837
1838 // track last visible streamer position
1839 if (isStreamer<Strategy>(currentPos))
1840 lastVisible = currentPos;
1841
1842 // Return position before tables and nodes which have content that can b e ignored.
1843 if (Strategy::editingIgnoresContent(currentNode) || isRenderedHTMLTableE lement(currentNode)) {
1844 if (currentPos.offsetInLeafNode() <= layoutObject->caretMinOffset())
1845 return PositionAlgorithm<Strategy>::editingPositionOf(currentNod e, layoutObject->caretMinOffset());
1846 continue;
1847 }
1848
1849 // return current position if it is in laid out text
1850 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox() ) {
1851 if (currentNode != startNode) {
1852 ASSERT(currentPos.atStartOfNode());
1853 return PositionAlgorithm<Strategy>(currentNode, layoutObject->ca retMinOffset());
1854 }
1855
1856 unsigned textOffset = currentPos.offsetInLeafNode();
1857 LayoutText* textLayoutObject = toLayoutText(layoutObject);
1858 InlineTextBox* lastTextBox = textLayoutObject->lastTextBox();
1859 for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) {
1860 if (textOffset <= box->end()) {
1861 if (textOffset >= box->start())
1862 return currentPos.computePosition();
1863 continue;
1864 }
1865
1866 if (box == lastTextBox || textOffset != box->start() + box->len( ))
1867 continue;
1868
1869 // The text continues on the next line only if the last text box is not on this line and
1870 // none of the boxes on this line have a larger start offset.
1871
1872 bool continuesOnNextLine = true;
1873 InlineBox* otherBox = box;
1874 while (continuesOnNextLine) {
1875 otherBox = otherBox->nextLeafChild();
1876 if (!otherBox)
1877 break;
1878 if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() >= textOffset))
1879 continuesOnNextLine = false;
1880 }
1881
1882 otherBox = box;
1883 while (continuesOnNextLine) {
1884 otherBox = otherBox->prevLeafChild();
1885 if (!otherBox)
1886 break;
1887 if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() >= textOffset))
1888 continuesOnNextLine = false;
1889 }
1890
1891 if (continuesOnNextLine)
1892 return currentPos.computePosition();
1893 }
1894 }
1895 }
1896
1897 return lastVisible.deprecatedComputePosition();
1898 }
1899
1900 Position mostBackwardCaretPosition(const Position& position, EditingBoundaryCros singRule rule)
1901 {
1902 return mostBackwardCaretPosition<EditingStrategy>(position, rule);
1903 }
1904
1905 PositionInComposedTree mostBackwardCaretPosition(const PositionInComposedTree& p osition, EditingBoundaryCrossingRule rule)
1906 {
1907 return mostBackwardCaretPosition<EditingInComposedTreeStrategy>(position, ru le);
1908 }
1909
1910 }
OLDNEW
« no previous file with comments | « Source/core/editing/VisibleUnits.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698