| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2008 Apple Inc. All rights reserved. |
| 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 * | 7 * |
| 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 19 matching lines...) Expand all Loading... |
| 30 | 30 |
| 31 #include "bindings/core/v8/ExceptionState.h" | 31 #include "bindings/core/v8/ExceptionState.h" |
| 32 #include "core/CSSPropertyNames.h" | 32 #include "core/CSSPropertyNames.h" |
| 33 #include "core/InputTypeNames.h" | 33 #include "core/InputTypeNames.h" |
| 34 #include "core/dom/AccessibleNode.h" | 34 #include "core/dom/AccessibleNode.h" |
| 35 #include "core/dom/ElementTraversal.h" | 35 #include "core/dom/ElementTraversal.h" |
| 36 #include "core/dom/Range.h" | 36 #include "core/dom/Range.h" |
| 37 #include "core/dom/shadow/ShadowRoot.h" | 37 #include "core/dom/shadow/ShadowRoot.h" |
| 38 #include "core/editing/EditingUtilities.h" | 38 #include "core/editing/EditingUtilities.h" |
| 39 #include "core/editing/FrameSelection.h" | 39 #include "core/editing/FrameSelection.h" |
| 40 #include "core/editing/RenderedPosition.h" | |
| 41 #include "core/editing/TextAffinity.h" | 40 #include "core/editing/TextAffinity.h" |
| 42 #include "core/editing/VisibleUnits.h" | 41 #include "core/editing/VisibleUnits.h" |
| 43 #include "core/editing/iterators/CharacterIterator.h" | 42 #include "core/editing/iterators/CharacterIterator.h" |
| 44 #include "core/editing/iterators/TextIterator.h" | 43 #include "core/editing/iterators/TextIterator.h" |
| 45 #include "core/frame/FrameOwner.h" | 44 #include "core/frame/FrameOwner.h" |
| 46 #include "core/frame/ImageBitmap.h" | 45 #include "core/frame/ImageBitmap.h" |
| 47 #include "core/frame/LocalFrame.h" | 46 #include "core/frame/LocalFrame.h" |
| 48 #include "core/frame/LocalFrameView.h" | 47 #include "core/frame/LocalFrameView.h" |
| 49 #include "core/frame/Settings.h" | 48 #include "core/frame/Settings.h" |
| 50 #include "core/html/HTMLCanvasElement.h" | 49 #include "core/html/HTMLCanvasElement.h" |
| (...skipping 1665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1716 for (Node& runner : NodeTraversal::InclusiveAncestorsOf(*node)) { | 1715 for (Node& runner : NodeTraversal::InclusiveAncestorsOf(*node)) { |
| 1717 if (isHTMLAnchorElement(runner) || | 1716 if (isHTMLAnchorElement(runner) || |
| 1718 (runner.GetLayoutObject() && | 1717 (runner.GetLayoutObject() && |
| 1719 cache.GetOrCreate(runner.GetLayoutObject())->IsAnchor())) | 1718 cache.GetOrCreate(runner.GetLayoutObject())->IsAnchor())) |
| 1720 return ToElement(&runner); | 1719 return ToElement(&runner); |
| 1721 } | 1720 } |
| 1722 | 1721 |
| 1723 return 0; | 1722 return 0; |
| 1724 } | 1723 } |
| 1725 | 1724 |
| 1726 // | |
| 1727 // Functions that retrieve the current selection. | |
| 1728 // | |
| 1729 | |
| 1730 AXObjectImpl::AXRange AXLayoutObject::Selection() const { | |
| 1731 AXRange text_selection = TextControlSelection(); | |
| 1732 if (text_selection.IsValid()) | |
| 1733 return text_selection; | |
| 1734 | |
| 1735 if (!GetLayoutObject() || !GetLayoutObject()->GetFrame()) | |
| 1736 return AXRange(); | |
| 1737 | |
| 1738 VisibleSelection selection = | |
| 1739 GetLayoutObject() | |
| 1740 ->GetFrame() | |
| 1741 ->Selection() | |
| 1742 .ComputeVisibleSelectionInDOMTreeDeprecated(); | |
| 1743 if (selection.IsNone()) | |
| 1744 return AXRange(); | |
| 1745 | |
| 1746 VisiblePosition visible_start = selection.VisibleStart(); | |
| 1747 Position start = visible_start.ToParentAnchoredPosition(); | |
| 1748 TextAffinity start_affinity = visible_start.Affinity(); | |
| 1749 VisiblePosition visible_end = selection.VisibleEnd(); | |
| 1750 Position end = visible_end.ToParentAnchoredPosition(); | |
| 1751 TextAffinity end_affinity = visible_end.Affinity(); | |
| 1752 | |
| 1753 Node* anchor_node = start.AnchorNode(); | |
| 1754 DCHECK(anchor_node); | |
| 1755 | |
| 1756 AXLayoutObject* anchor_object = nullptr; | |
| 1757 // Find the closest node that has a corresponding AXObjectImpl. | |
| 1758 // This is because some nodes may be aria hidden or might not even have | |
| 1759 // a layout object if they are part of the shadow DOM. | |
| 1760 while (anchor_node) { | |
| 1761 anchor_object = GetUnignoredObjectFromNode(*anchor_node); | |
| 1762 if (anchor_object) | |
| 1763 break; | |
| 1764 | |
| 1765 if (anchor_node->nextSibling()) | |
| 1766 anchor_node = anchor_node->nextSibling(); | |
| 1767 else | |
| 1768 anchor_node = anchor_node->parentNode(); | |
| 1769 } | |
| 1770 | |
| 1771 Node* focus_node = end.AnchorNode(); | |
| 1772 DCHECK(focus_node); | |
| 1773 | |
| 1774 AXLayoutObject* focus_object = nullptr; | |
| 1775 while (focus_node) { | |
| 1776 focus_object = GetUnignoredObjectFromNode(*focus_node); | |
| 1777 if (focus_object) | |
| 1778 break; | |
| 1779 | |
| 1780 if (focus_node->previousSibling()) | |
| 1781 focus_node = focus_node->previousSibling(); | |
| 1782 else | |
| 1783 focus_node = focus_node->parentNode(); | |
| 1784 } | |
| 1785 | |
| 1786 if (!anchor_object || !focus_object) | |
| 1787 return AXRange(); | |
| 1788 | |
| 1789 int anchor_offset = anchor_object->IndexForVisiblePosition(visible_start); | |
| 1790 DCHECK_GE(anchor_offset, 0); | |
| 1791 int focus_offset = focus_object->IndexForVisiblePosition(visible_end); | |
| 1792 DCHECK_GE(focus_offset, 0); | |
| 1793 return AXRange(anchor_object, anchor_offset, start_affinity, focus_object, | |
| 1794 focus_offset, end_affinity); | |
| 1795 } | |
| 1796 | |
| 1797 // Gets only the start and end offsets of the selection computed using the | |
| 1798 // current object as the starting point. Returns a null selection if there is | |
| 1799 // no selection in the subtree rooted at this object. | |
| 1800 AXObjectImpl::AXRange AXLayoutObject::SelectionUnderObject() const { | |
| 1801 AXRange text_selection = TextControlSelection(); | |
| 1802 if (text_selection.IsValid()) | |
| 1803 return text_selection; | |
| 1804 | |
| 1805 if (!GetNode() || !GetLayoutObject()->GetFrame()) | |
| 1806 return AXRange(); | |
| 1807 | |
| 1808 VisibleSelection selection = | |
| 1809 GetLayoutObject() | |
| 1810 ->GetFrame() | |
| 1811 ->Selection() | |
| 1812 .ComputeVisibleSelectionInDOMTreeDeprecated(); | |
| 1813 Range* selection_range = CreateRange(FirstEphemeralRangeOf(selection)); | |
| 1814 ContainerNode* parent_node = GetNode()->parentNode(); | |
| 1815 int node_index = GetNode()->NodeIndex(); | |
| 1816 if (!selection_range | |
| 1817 // Selection is contained in node. | |
| 1818 || !(parent_node && | |
| 1819 selection_range->comparePoint(parent_node, node_index, | |
| 1820 IGNORE_EXCEPTION_FOR_TESTING) < 0 && | |
| 1821 selection_range->comparePoint(parent_node, node_index + 1, | |
| 1822 IGNORE_EXCEPTION_FOR_TESTING) > 0)) { | |
| 1823 return AXRange(); | |
| 1824 } | |
| 1825 | |
| 1826 int start = IndexForVisiblePosition(selection.VisibleStart()); | |
| 1827 DCHECK_GE(start, 0); | |
| 1828 int end = IndexForVisiblePosition(selection.VisibleEnd()); | |
| 1829 DCHECK_GE(end, 0); | |
| 1830 | |
| 1831 return AXRange(start, end); | |
| 1832 } | |
| 1833 | |
| 1834 AXObjectImpl::AXRange AXLayoutObject::TextControlSelection() const { | |
| 1835 if (!GetLayoutObject()) | |
| 1836 return AXRange(); | |
| 1837 | |
| 1838 LayoutObject* layout = nullptr; | |
| 1839 if (GetLayoutObject()->IsTextControl()) { | |
| 1840 layout = GetLayoutObject(); | |
| 1841 } else { | |
| 1842 Element* focused_element = GetDocument()->FocusedElement(); | |
| 1843 if (focused_element && focused_element->GetLayoutObject() && | |
| 1844 focused_element->GetLayoutObject()->IsTextControl()) | |
| 1845 layout = focused_element->GetLayoutObject(); | |
| 1846 } | |
| 1847 | |
| 1848 if (!layout) | |
| 1849 return AXRange(); | |
| 1850 | |
| 1851 AXObjectImpl* ax_object = AxObjectCache().GetOrCreate(layout); | |
| 1852 if (!ax_object || !ax_object->IsAXLayoutObject()) | |
| 1853 return AXRange(); | |
| 1854 | |
| 1855 VisibleSelection selection = | |
| 1856 layout->GetFrame() | |
| 1857 ->Selection() | |
| 1858 .ComputeVisibleSelectionInDOMTreeDeprecated(); | |
| 1859 TextControlElement* text_control = | |
| 1860 ToLayoutTextControl(layout)->GetTextControlElement(); | |
| 1861 DCHECK(text_control); | |
| 1862 int start = text_control->selectionStart(); | |
| 1863 int end = text_control->selectionEnd(); | |
| 1864 | |
| 1865 return AXRange(ax_object, start, selection.VisibleStart().Affinity(), | |
| 1866 ax_object, end, selection.VisibleEnd().Affinity()); | |
| 1867 } | |
| 1868 | |
| 1869 int AXLayoutObject::IndexForVisiblePosition( | |
| 1870 const VisiblePosition& position) const { | |
| 1871 if (GetLayoutObject() && GetLayoutObject()->IsTextControl()) { | |
| 1872 TextControlElement* text_control = | |
| 1873 ToLayoutTextControl(GetLayoutObject())->GetTextControlElement(); | |
| 1874 return text_control->IndexForVisiblePosition(position); | |
| 1875 } | |
| 1876 | |
| 1877 if (!GetNode()) | |
| 1878 return 0; | |
| 1879 | |
| 1880 Position index_position = position.DeepEquivalent(); | |
| 1881 if (index_position.IsNull()) | |
| 1882 return 0; | |
| 1883 | |
| 1884 Range* range = Range::Create(*GetDocument()); | |
| 1885 range->setStart(GetNode(), 0, IGNORE_EXCEPTION_FOR_TESTING); | |
| 1886 range->setEnd(index_position, IGNORE_EXCEPTION_FOR_TESTING); | |
| 1887 | |
| 1888 return TextIterator::RangeLength(range->StartPosition(), | |
| 1889 range->EndPosition()); | |
| 1890 } | |
| 1891 | |
| 1892 AXLayoutObject* AXLayoutObject::GetUnignoredObjectFromNode(Node& node) const { | |
| 1893 if (IsDetached()) | |
| 1894 return nullptr; | |
| 1895 | |
| 1896 AXObjectImpl* ax_object = AxObjectCache().GetOrCreate(&node); | |
| 1897 if (!ax_object) | |
| 1898 return nullptr; | |
| 1899 | |
| 1900 if (ax_object->IsAXLayoutObject() && !ax_object->AccessibilityIsIgnored()) | |
| 1901 return ToAXLayoutObject(ax_object); | |
| 1902 | |
| 1903 return nullptr; | |
| 1904 } | |
| 1905 | |
| 1906 // | |
| 1907 // Modify or take an action on an object. | |
| 1908 // | |
| 1909 | |
| 1910 // Convert from an accessible object and offset to a VisiblePosition. | |
| 1911 static VisiblePosition ToVisiblePosition(AXObjectImpl* obj, int offset) { | |
| 1912 if (!obj->GetNode()) | |
| 1913 return VisiblePosition(); | |
| 1914 | |
| 1915 Node* node = obj->GetNode(); | |
| 1916 if (!node->IsTextNode()) { | |
| 1917 int child_count = obj->Children().size(); | |
| 1918 | |
| 1919 // Place position immediately before the container node, if there was no | |
| 1920 // children. | |
| 1921 if (child_count == 0) { | |
| 1922 if (!obj->ParentObject()) | |
| 1923 return VisiblePosition(); | |
| 1924 return ToVisiblePosition(obj->ParentObject(), obj->IndexInParent()); | |
| 1925 } | |
| 1926 | |
| 1927 // The offsets are child offsets over the AX tree. Note that we allow | |
| 1928 // for the offset to equal the number of children as |Range| does. | |
| 1929 if (offset < 0 || offset > child_count) | |
| 1930 return VisiblePosition(); | |
| 1931 | |
| 1932 // Clamp to between 0 and child count - 1. | |
| 1933 int clamped_offset = | |
| 1934 static_cast<unsigned>(offset) > (obj->Children().size() - 1) | |
| 1935 ? offset - 1 | |
| 1936 : offset; | |
| 1937 AXObjectImpl* child_obj = obj->Children()[clamped_offset]; | |
| 1938 Node* child_node = child_obj->GetNode(); | |
| 1939 if (!child_node || !child_node->parentNode()) | |
| 1940 return VisiblePosition(); | |
| 1941 | |
| 1942 // The index in parent. | |
| 1943 int adjusted_offset = child_node->NodeIndex(); | |
| 1944 | |
| 1945 // If we had to clamp the offset above, the client wants to select the | |
| 1946 // end of the node. | |
| 1947 if (clamped_offset != offset) | |
| 1948 adjusted_offset++; | |
| 1949 | |
| 1950 return CreateVisiblePosition( | |
| 1951 Position::EditingPositionOf(child_node->parentNode(), adjusted_offset)); | |
| 1952 } | |
| 1953 | |
| 1954 // If it is a text node, we need to call some utility functions that use a | |
| 1955 // TextIterator to walk the characters of the node and figure out the position | |
| 1956 // corresponding to the visible character at position |offset|. | |
| 1957 ContainerNode* parent = node->parentNode(); | |
| 1958 if (!parent) | |
| 1959 return VisiblePosition(); | |
| 1960 | |
| 1961 VisiblePosition node_position = blink::VisiblePositionBeforeNode(*node); | |
| 1962 int node_index = blink::IndexForVisiblePosition(node_position, parent); | |
| 1963 return blink::VisiblePositionForIndex(node_index + offset, parent); | |
| 1964 } | |
| 1965 | |
| 1966 void AXLayoutObject::SetSelection(const AXRange& selection) { | |
| 1967 if (!GetLayoutObject() || !selection.IsValid()) | |
| 1968 return; | |
| 1969 | |
| 1970 AXObjectImpl* anchor_object = | |
| 1971 selection.anchor_object ? selection.anchor_object.Get() : this; | |
| 1972 AXObjectImpl* focus_object = | |
| 1973 selection.focus_object ? selection.focus_object.Get() : this; | |
| 1974 | |
| 1975 if (!IsValidSelectionBound(anchor_object) || | |
| 1976 !IsValidSelectionBound(focus_object)) { | |
| 1977 return; | |
| 1978 } | |
| 1979 | |
| 1980 // The selection offsets are offsets into the accessible value. | |
| 1981 if (anchor_object == focus_object && | |
| 1982 anchor_object->GetLayoutObject()->IsTextControl()) { | |
| 1983 TextControlElement* text_control = | |
| 1984 ToLayoutTextControl(anchor_object->GetLayoutObject()) | |
| 1985 ->GetTextControlElement(); | |
| 1986 if (selection.anchor_offset <= selection.focus_offset) { | |
| 1987 text_control->SetSelectionRange(selection.anchor_offset, | |
| 1988 selection.focus_offset, | |
| 1989 kSelectionHasForwardDirection); | |
| 1990 } else { | |
| 1991 text_control->SetSelectionRange(selection.focus_offset, | |
| 1992 selection.anchor_offset, | |
| 1993 kSelectionHasBackwardDirection); | |
| 1994 } | |
| 1995 return; | |
| 1996 } | |
| 1997 | |
| 1998 LocalFrame* frame = GetLayoutObject()->GetFrame(); | |
| 1999 if (!frame) | |
| 2000 return; | |
| 2001 | |
| 2002 // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets | |
| 2003 // needs to be audited. see http://crbug.com/590369 for more details. | |
| 2004 // This callsite should probably move up the stack. | |
| 2005 frame->GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets(); | |
| 2006 | |
| 2007 // Set the selection based on visible positions, because the offsets in | |
| 2008 // accessibility nodes are based on visible indexes, which often skips | |
| 2009 // redundant whitespace, for example. | |
| 2010 VisiblePosition anchor_visible_position = | |
| 2011 ToVisiblePosition(anchor_object, selection.anchor_offset); | |
| 2012 VisiblePosition focus_visible_position = | |
| 2013 ToVisiblePosition(focus_object, selection.focus_offset); | |
| 2014 if (anchor_visible_position.IsNull() || focus_visible_position.IsNull()) | |
| 2015 return; | |
| 2016 | |
| 2017 frame->Selection().SetSelection( | |
| 2018 SelectionInDOMTree::Builder() | |
| 2019 .Collapse(anchor_visible_position.ToPositionWithAffinity()) | |
| 2020 .Extend(focus_visible_position.DeepEquivalent()) | |
| 2021 .Build()); | |
| 2022 } | |
| 2023 | |
| 2024 bool AXLayoutObject::IsValidSelectionBound( | |
| 2025 const AXObjectImpl* bound_object) const { | |
| 2026 return GetLayoutObject() && bound_object && !bound_object->IsDetached() && | |
| 2027 bound_object->IsAXLayoutObject() && bound_object->GetLayoutObject() && | |
| 2028 bound_object->GetLayoutObject()->GetFrame() == | |
| 2029 GetLayoutObject()->GetFrame() && | |
| 2030 &bound_object->AxObjectCache() == &AxObjectCache(); | |
| 2031 } | |
| 2032 | |
| 2033 void AXLayoutObject::SetValue(const String& string) { | 1725 void AXLayoutObject::SetValue(const String& string) { |
| 2034 if (!GetNode() || !GetNode()->IsElementNode()) | 1726 if (!GetNode() || !GetNode()->IsElementNode()) |
| 2035 return; | 1727 return; |
| 2036 if (!layout_object_ || !layout_object_->IsBoxModelObject()) | 1728 if (!layout_object_ || !layout_object_->IsBoxModelObject()) |
| 2037 return; | 1729 return; |
| 2038 | 1730 |
| 2039 LayoutBoxModelObject* layout_object = ToLayoutBoxModelObject(layout_object_); | 1731 LayoutBoxModelObject* layout_object = ToLayoutBoxModelObject(layout_object_); |
| 2040 if (layout_object->IsTextField() && isHTMLInputElement(*GetNode())) | 1732 if (layout_object->IsTextField() && isHTMLInputElement(*GetNode())) |
| 2041 toHTMLInputElement(*GetNode()) | 1733 toHTMLInputElement(*GetNode()) |
| 2042 .setValue(string, kDispatchInputAndChangeEvent); | 1734 .setValue(string, kDispatchInputAndChangeEvent); |
| (...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2520 | 2212 |
| 2521 bool AXLayoutObject::ElementAttributeValue( | 2213 bool AXLayoutObject::ElementAttributeValue( |
| 2522 const QualifiedName& attribute_name) const { | 2214 const QualifiedName& attribute_name) const { |
| 2523 if (!layout_object_) | 2215 if (!layout_object_) |
| 2524 return false; | 2216 return false; |
| 2525 | 2217 |
| 2526 return EqualIgnoringASCIICase(GetAttribute(attribute_name), "true"); | 2218 return EqualIgnoringASCIICase(GetAttribute(attribute_name), "true"); |
| 2527 } | 2219 } |
| 2528 | 2220 |
| 2529 } // namespace blink | 2221 } // namespace blink |
| OLD | NEW |