Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2012, Google Inc. All rights reserved. | 2 * Copyright (C) 2012, Google 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 |
| 11 * notice, this list of conditions and the following disclaimer in the | 11 * notice, this list of conditions and the following disclaimer in the |
| 12 * documentation and/or other materials provided with the distribution. | 12 * documentation and/or other materials provided with the distribution. |
| 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
| 14 * its contributors may be used to endorse or promote products derived | 14 * its contributors may be used to endorse or promote products derived |
| 15 * from this software without specific prior written permission. | 15 * from this software without specific prior written permission. |
| 16 * | 16 * |
| 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 */ | 27 */ |
| 28 | 28 |
| 29 #include "config.h" | 29 #include "config.h" |
| 30 #include "modules/accessibility/AXNodeObject.h" | 30 #include "modules/accessibility/AXNodeObject.h" |
| 31 | 31 |
| 32 #include "core/InputTypeNames.h" | 32 #include "core/InputTypeNames.h" |
| 33 #include "core/dom/NodeTraversal.h" | 33 #include "core/dom/NodeTraversal.h" |
| 34 #include "core/dom/Text.h" | 34 #include "core/dom/Text.h" |
| 35 #include "core/dom/shadow/ComposedTreeTraversal.h" | |
| 35 #include "core/html/HTMLDListElement.h" | 36 #include "core/html/HTMLDListElement.h" |
| 36 #include "core/html/HTMLFieldSetElement.h" | 37 #include "core/html/HTMLFieldSetElement.h" |
| 37 #include "core/html/HTMLFrameElementBase.h" | 38 #include "core/html/HTMLFrameElementBase.h" |
| 38 #include "core/html/HTMLImageElement.h" | 39 #include "core/html/HTMLImageElement.h" |
| 39 #include "core/html/HTMLInputElement.h" | 40 #include "core/html/HTMLInputElement.h" |
| 40 #include "core/html/HTMLLabelElement.h" | 41 #include "core/html/HTMLLabelElement.h" |
| 41 #include "core/html/HTMLLegendElement.h" | 42 #include "core/html/HTMLLegendElement.h" |
| 42 #include "core/html/HTMLMediaElement.h" | 43 #include "core/html/HTMLMediaElement.h" |
| 43 #include "core/html/HTMLMeterElement.h" | 44 #include "core/html/HTMLMeterElement.h" |
| 44 #include "core/html/HTMLPlugInElement.h" | 45 #include "core/html/HTMLPlugInElement.h" |
| 45 #include "core/html/HTMLSelectElement.h" | 46 #include "core/html/HTMLSelectElement.h" |
| 46 #include "core/html/HTMLTableCaptionElement.h" | 47 #include "core/html/HTMLTableCaptionElement.h" |
| 47 #include "core/html/HTMLTableCellElement.h" | 48 #include "core/html/HTMLTableCellElement.h" |
| 48 #include "core/html/HTMLTableElement.h" | 49 #include "core/html/HTMLTableElement.h" |
| 49 #include "core/html/HTMLTableRowElement.h" | 50 #include "core/html/HTMLTableRowElement.h" |
| 50 #include "core/html/HTMLTableSectionElement.h" | 51 #include "core/html/HTMLTableSectionElement.h" |
| 51 #include "core/html/HTMLTextAreaElement.h" | 52 #include "core/html/HTMLTextAreaElement.h" |
| 52 #include "core/html/parser/HTMLParserIdioms.h" | 53 #include "core/html/parser/HTMLParserIdioms.h" |
| 53 #include "core/html/shadow/MediaControlElements.h" | 54 #include "core/html/shadow/MediaControlElements.h" |
| 54 #include "core/layout/LayoutObject.h" | 55 #include "core/layout/LayoutObject.h" |
| 55 #include "modules/accessibility/AXObjectCacheImpl.h" | 56 #include "modules/accessibility/AXObjectCacheImpl.h" |
| 56 #include "platform/UserGestureIndicator.h" | 57 #include "platform/UserGestureIndicator.h" |
| 58 #include "platform/text/PlatformLocale.h" | |
| 57 #include "wtf/text/StringBuilder.h" | 59 #include "wtf/text/StringBuilder.h" |
| 58 | 60 |
| 59 | 61 |
| 60 namespace blink { | 62 namespace blink { |
| 61 | 63 |
| 62 using namespace HTMLNames; | 64 using namespace HTMLNames; |
| 63 | 65 |
| 64 AXNodeObject::AXNodeObject(Node* node, AXObjectCacheImpl& axObjectCache) | 66 AXNodeObject::AXNodeObject(Node* node, AXObjectCacheImpl& axObjectCache) |
| 65 : AXObject(axObjectCache) | 67 : AXObject(axObjectCache) |
| 66 , m_ariaRole(UnknownRole) | 68 , m_ariaRole(UnknownRole) |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 243 static bool isRequiredOwnedElement(AXObject* parent, AccessibilityRole currentRo le, HTMLElement* currentElement) | 245 static bool isRequiredOwnedElement(AXObject* parent, AccessibilityRole currentRo le, HTMLElement* currentElement) |
| 244 { | 246 { |
| 245 Node* parentNode = parent->node(); | 247 Node* parentNode = parent->node(); |
| 246 if (!parentNode || !parentNode->isHTMLElement()) | 248 if (!parentNode || !parentNode->isHTMLElement()) |
| 247 return false; | 249 return false; |
| 248 | 250 |
| 249 if (currentRole == ListItemRole) | 251 if (currentRole == ListItemRole) |
| 250 return isListElement(parentNode); | 252 return isListElement(parentNode); |
| 251 if (currentRole == ListMarkerRole) | 253 if (currentRole == ListMarkerRole) |
| 252 return isHTMLLIElement(*parentNode); | 254 return isHTMLLIElement(*parentNode); |
| 253 if (currentRole == MenuItemCheckBoxRole || currentRole == MenuItemRole || c urrentRole == MenuItemRadioRole) | 255 if (currentRole == MenuItemCheckBoxRole || currentRole == MenuItemRole || cu rrentRole == MenuItemRadioRole) |
| 254 return isHTMLMenuElement(*parentNode); | 256 return isHTMLMenuElement(*parentNode); |
| 255 | 257 |
| 256 if (!currentElement) | 258 if (!currentElement) |
| 257 return false; | 259 return false; |
| 258 if (isHTMLTableCellElement(*currentElement)) | 260 if (isHTMLTableCellElement(*currentElement)) |
| 259 return isHTMLTableRowElement(*parentNode); | 261 return isHTMLTableRowElement(*parentNode); |
| 260 if (isHTMLTableRowElement(*currentElement)) | 262 if (isHTMLTableRowElement(*currentElement)) |
| 261 return isHTMLTableSectionElement(toHTMLElement(*parentNode)); | 263 return isHTMLTableSectionElement(toHTMLElement(*parentNode)); |
| 262 | 264 |
| 263 // In case of ListboxRole and it's child, ListBoxOptionRole, | 265 // In case of ListboxRole and it's child, ListBoxOptionRole, |
| 264 // Inheritance of presentation role is handled in AXListBoxOption | 266 // Inheritance of presentation role is handled in AXListBoxOption |
| 265 // Because ListBoxOption Role doesn't have any child. | 267 // Because ListBoxOption Role doesn't have any child. |
| 266 // If it's just ignored because of presentation, we can't see any AX tree re lated to ListBoxOption. | 268 // If it's just ignored because of presentation, we can't see any AX tree re lated to ListBoxOption. |
| 267 return false; | 269 return false; |
| 268 } | 270 } |
| 269 | 271 |
| 270 | |
| 271 const AXObject* AXNodeObject::inheritsPresentationalRoleFrom() const | 272 const AXObject* AXNodeObject::inheritsPresentationalRoleFrom() const |
| 272 { | 273 { |
| 273 // ARIA states if an item can get focus, it should not be presentational. | 274 // ARIA states if an item can get focus, it should not be presentational. |
| 274 if (canSetFocusAttribute()) | 275 if (canSetFocusAttribute()) |
| 275 return 0; | 276 return 0; |
| 276 | 277 |
| 277 if (isPresentational()) | 278 if (isPresentational()) |
| 278 return this; | 279 return this; |
| 279 | 280 |
| 280 // http://www.w3.org/TR/wai-aria/complete#presentation | 281 // http://www.w3.org/TR/wai-aria/complete#presentation |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 329 if (node()->isLink() || (isHTMLAnchorElement(*node()) && isClickable())) | 330 if (node()->isLink() || (isHTMLAnchorElement(*node()) && isClickable())) |
| 330 return LinkRole; | 331 return LinkRole; |
| 331 | 332 |
| 332 if (isHTMLButtonElement(*node())) | 333 if (isHTMLButtonElement(*node())) |
| 333 return buttonRoleType(); | 334 return buttonRoleType(); |
| 334 | 335 |
| 335 if (isHTMLDetailsElement(*node())) | 336 if (isHTMLDetailsElement(*node())) |
| 336 return DetailsRole; | 337 return DetailsRole; |
| 337 | 338 |
| 338 if (isHTMLSummaryElement(*node())) { | 339 if (isHTMLSummaryElement(*node())) { |
| 339 if (node()->parentNode() && isHTMLDetailsElement(node()->parentNode())) | 340 if (ComposedTreeTraversal::parent(*node()) && isHTMLDetailsElement(Compo sedTreeTraversal::parent(*node()))) |
| 340 return DisclosureTriangleRole; | 341 return DisclosureTriangleRole; |
| 341 return UnknownRole; | 342 return UnknownRole; |
| 342 } | 343 } |
| 343 | 344 |
| 344 if (isHTMLInputElement(*node())) { | 345 if (isHTMLInputElement(*node())) { |
| 345 HTMLInputElement& input = toHTMLInputElement(*node()); | 346 HTMLInputElement& input = toHTMLInputElement(*node()); |
| 346 const AtomicString& type = input.type(); | 347 const AtomicString& type = input.type(); |
| 347 if (input.dataList()) | 348 if (input.dataList()) |
| 348 return ComboBoxRole; | 349 return ComboBoxRole; |
| 349 if (type == InputTypeNames::button) { | 350 if (type == InputTypeNames::button) { |
| (...skipping 1421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1771 return placeholder; | 1772 return placeholder; |
| 1772 } | 1773 } |
| 1773 | 1774 |
| 1774 return String(); | 1775 return String(); |
| 1775 } | 1776 } |
| 1776 | 1777 |
| 1777 // | 1778 // |
| 1778 // New AX name calculation. | 1779 // New AX name calculation. |
| 1779 // | 1780 // |
| 1780 | 1781 |
| 1781 String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver sal, AXObjectSet& visited, AXNameFrom& nameFrom, AXObjectVector& nameObjects, Na meSources* nameSources) const | 1782 String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver sal, AXObjectSet& visited, AXNameFrom& nameFrom, AXObjectVector* nameObjects, Na meSources* nameSources) const |
| 1782 { | 1783 { |
| 1784 // If nameSources is non-null, nameObjects is used in filling it in, so it m ust be non-null as well. | |
| 1785 if (nameSources) | |
| 1786 assert(nameObjects); | |
| 1787 | |
| 1783 bool alreadyVisited = visited.contains(this); | 1788 bool alreadyVisited = visited.contains(this); |
| 1784 bool foundTextAlternative = false; | 1789 bool foundTextAlternative = false; |
| 1785 visited.add(this); | 1790 visited.add(this); |
| 1786 String textAlternative; | 1791 String textAlternative; |
| 1787 | 1792 |
| 1788 if (!node() && !layoutObject()) | 1793 if (!node() && !layoutObject()) |
| 1789 return String(); | 1794 return String(); |
| 1790 | 1795 |
| 1791 // Step 2A from: http://www.w3.org/TR/accname-aam-1.1 | 1796 // Step 2A from: http://www.w3.org/TR/accname-aam-1.1 |
| 1792 if (!recursive && layoutObject() | 1797 if (!recursive && layoutObject() |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1807 if (hasAttribute(attr)) { | 1812 if (hasAttribute(attr)) { |
| 1808 if (nameSources) | 1813 if (nameSources) |
| 1809 nameSources->last().attributeValue = getAttribute(attr); | 1814 nameSources->last().attributeValue = getAttribute(attr); |
| 1810 | 1815 |
| 1811 textAlternative = textFromAriaLabelledby(visited, nameObjects); | 1816 textAlternative = textFromAriaLabelledby(visited, nameObjects); |
| 1812 | 1817 |
| 1813 if (!textAlternative.isNull()) { | 1818 if (!textAlternative.isNull()) { |
| 1814 if (nameSources) { | 1819 if (nameSources) { |
| 1815 NameSource& source = nameSources->last(); | 1820 NameSource& source = nameSources->last(); |
| 1816 source.type = nameFrom; | 1821 source.type = nameFrom; |
| 1817 source.nameObjects = nameObjects; | 1822 source.nameObjects = *nameObjects; |
| 1818 source.text = textAlternative; | 1823 source.text = textAlternative; |
| 1819 foundTextAlternative = true; | 1824 foundTextAlternative = true; |
| 1820 } else { | 1825 } else { |
| 1821 return textAlternative; | 1826 return textAlternative; |
| 1822 } | 1827 } |
| 1823 } else if (nameSources) { | 1828 } else if (nameSources) { |
| 1824 nameSources->last().invalid = true; | 1829 nameSources->last().invalid = true; |
| 1825 } | 1830 } |
| 1826 } | 1831 } |
| 1827 } | 1832 } |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 1847 } | 1852 } |
| 1848 } | 1853 } |
| 1849 } | 1854 } |
| 1850 | 1855 |
| 1851 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1 | 1856 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1 |
| 1852 textAlternative = nativeTextAlternative(visited, nameFrom, nameObjects, name Sources, &foundTextAlternative); | 1857 textAlternative = nativeTextAlternative(visited, nameFrom, nameObjects, name Sources, &foundTextAlternative); |
| 1853 if (!textAlternative.isNull() && !nameSources) | 1858 if (!textAlternative.isNull() && !nameSources) |
| 1854 return textAlternative; | 1859 return textAlternative; |
| 1855 | 1860 |
| 1856 // Step 2E from: http://www.w3.org/TR/accname-aam-1.1 | 1861 // Step 2E from: http://www.w3.org/TR/accname-aam-1.1 |
| 1857 | 1862 if (recursive && !inAriaLabelledByTraversal && isControl()) { |
| 1863 // No need to set any name source info in a recursive call. | |
| 1864 if (roleValue() == TextFieldRole || roleValue() == ComboBoxRole) | |
| 1865 return text(); | |
| 1866 if (isRange()) { | |
| 1867 if (hasAttribute(aria_valuetextAttr)) | |
| 1868 return getAttribute(aria_valuetextAttr).string(); | |
| 1869 return String::number(valueForRange()); | |
| 1870 } | |
| 1871 } | |
| 1858 | 1872 |
| 1859 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 | 1873 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 |
| 1860 if (recursive || nameFromContents()) { | 1874 if (recursive || nameFromContents()) { |
| 1861 nameFrom = AXNameFromContents; | 1875 nameFrom = AXNameFromContents; |
| 1862 if (nameSources) { | 1876 if (nameSources) { |
| 1863 nameSources->append(NameSource(foundTextAlternative)); | 1877 nameSources->append(NameSource(foundTextAlternative)); |
| 1864 nameSources->last().type = nameFrom; | 1878 nameSources->last().type = nameFrom; |
| 1865 } | 1879 } |
| 1866 | 1880 |
| 1867 Node* node = this->node(); | 1881 Node* node = this->node(); |
| 1868 if (node && node->isTextNode()) | 1882 if (node && node->isTextNode()) |
| 1869 textAlternative = toText(node)->wholeText(); | 1883 textAlternative = toText(node)->wholeText(); |
| 1870 else | 1884 else |
| 1871 textAlternative = textFromDescendants(visited); | 1885 textAlternative = textFromDescendants(visited); |
| 1872 | 1886 |
| 1873 if (nameSources) { | 1887 if (!textAlternative.isEmpty()) { |
| 1874 foundTextAlternative = true; | 1888 if (nameSources) { |
| 1875 nameSources->last().text = textAlternative; | 1889 foundTextAlternative = true; |
| 1876 } else { | 1890 nameSources->last().text = textAlternative; |
| 1877 return textAlternative; | 1891 } else { |
| 1892 return textAlternative; | |
| 1893 } | |
| 1894 } | |
| 1895 } | |
| 1896 | |
| 1897 // Step 2H from: http://www.w3.org/TR/accname-aam-1.1 | |
| 1898 nameFrom = AXNameFromAttribute; | |
| 1899 if (nameSources) { | |
| 1900 nameSources->append(NameSource(foundTextAlternative, titleAttr)); | |
| 1901 nameSources->last().type = nameFrom; | |
| 1902 } | |
| 1903 if (hasAttribute(titleAttr)) { | |
| 1904 const AtomicString& title = getAttribute(titleAttr); | |
| 1905 if (!title.isEmpty()) { | |
| 1906 textAlternative = title; | |
| 1907 if (nameSources) { | |
| 1908 foundTextAlternative = true; | |
| 1909 nameSources->last().text = textAlternative; | |
| 1910 } else { | |
| 1911 return textAlternative; | |
| 1912 } | |
| 1878 } | 1913 } |
| 1879 } | 1914 } |
| 1880 | 1915 |
| 1881 nameFrom = AXNameFromUninitialized; | 1916 nameFrom = AXNameFromUninitialized; |
| 1882 | 1917 |
| 1883 if (nameSources && !nameSources->isEmpty()) { | 1918 if (foundTextAlternative) { |
| 1884 for (size_t i = 0; i < nameSources->size(); ++i) { | 1919 for (size_t i = 0; i < nameSources->size(); ++i) { |
| 1885 if (!(*nameSources)[i].text.isNull() && !(*nameSources)[i].supersede d) { | 1920 if (!(*nameSources)[i].text.isNull() && !(*nameSources)[i].supersede d) { |
| 1886 nameFrom = (*nameSources)[i].type; | 1921 NameSource& nameSource = (*nameSources)[i]; |
| 1887 nameObjects = (*nameSources)[i].nameObjects; | 1922 nameFrom = nameSource.type; |
| 1888 return (*nameSources)[i].text; | 1923 if (!nameSource.nameObjects.isEmpty()) |
| 1924 *nameObjects = nameSource.nameObjects; | |
| 1925 return nameSource.text; | |
| 1889 } | 1926 } |
| 1890 } | 1927 } |
| 1891 } | 1928 } |
| 1892 | 1929 |
| 1893 return String(); | 1930 return String(); |
| 1894 } | 1931 } |
| 1895 | 1932 |
| 1896 String AXNodeObject::textFromDescendants(AXObjectSet& visited) const | 1933 String AXNodeObject::textFromDescendants(AXObjectSet& visited) const |
| 1897 { | 1934 { |
| 1898 StringBuilder accumulatedText; | 1935 StringBuilder accumulatedText; |
| 1899 AXObject* previous = nullptr; | 1936 AXObject* previous = nullptr; |
| 1900 for (AXObject* child = firstChild(); child; child = child->nextSibling()) { | 1937 for (AXObject* child = firstChild(); child; child = child->nextSibling()) { |
| 1901 // If we're going between two layoutObjects that are in separate LayoutB oxes, add | 1938 // If we're going between two layoutObjects that are in separate LayoutB oxes, add |
| 1902 // whitespace if it wasn't there already. Intuitively if you have | 1939 // whitespace if it wasn't there already. Intuitively if you have |
| 1903 // <span>Hello</span><span>World</span>, those are part of the same Layo utBox | 1940 // <span>Hello</span><span>World</span>, those are part of the same Layo utBox |
| 1904 // so we should return "HelloWorld", but given <div>Hello</div><div>Worl d</div> the | 1941 // so we should return "HelloWorld", but given <div>Hello</div><div>Worl d</div> the |
| 1905 // strings are in separate boxes so we should return "Hello World". | 1942 // strings are in separate boxes so we should return "Hello World". |
| 1906 if (previous && accumulatedText.length() && !isHTMLSpace(accumulatedText [accumulatedText.length() - 1])) { | 1943 if (previous && accumulatedText.length() && !isHTMLSpace(accumulatedText [accumulatedText.length() - 1])) { |
| 1907 if (!isSameLayoutBox(child->layoutObject(), previous->layoutObject() )) | 1944 if (!isSameLayoutBox(child->layoutObject(), previous->layoutObject() )) |
| 1908 accumulatedText.append(' '); | 1945 accumulatedText.append(' '); |
| 1909 } | 1946 } |
| 1910 | 1947 |
| 1911 AXNameFrom nameFrom; | 1948 String result = recursiveTextAlternative(*child, false, visited); |
| 1912 AXObjectVector nameObjects; | |
| 1913 String result = child->textAlternative(true, false, visited, nameFrom, n ameObjects, nullptr); | |
| 1914 accumulatedText.append(result); | 1949 accumulatedText.append(result); |
| 1915 previous = child; | 1950 previous = child; |
| 1916 } | 1951 } |
| 1917 | 1952 |
| 1918 return accumulatedText.toString(); | 1953 return accumulatedText.toString(); |
| 1919 } | 1954 } |
| 1920 | 1955 |
| 1921 String AXNodeObject::textFromElements(bool inAriaLabelledbyTraversal, AXObjectSe t& visited, WillBeHeapVector<RawPtrWillBeMember<Element>>& elements, AXObjectVec tor& nameObjects) const | 1956 String AXNodeObject::textFromElements(bool inAriaLabelledbyTraversal, AXObjectSe t& visited, WillBeHeapVector<RawPtrWillBeMember<Element>>& elements, AXObjectVec tor* nameObjects) const |
| 1922 { | 1957 { |
| 1923 StringBuilder accumulatedText; | 1958 StringBuilder accumulatedText; |
| 1924 bool foundValidElement = false; | 1959 bool foundValidElement = false; |
| 1925 AXObjectVector localNameObjects; | 1960 AXObjectVector localNameObjects; |
| 1926 | 1961 |
| 1927 for (const auto& element : elements) { | 1962 for (const auto& element : elements) { |
| 1928 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate(ele ment); | 1963 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate(ele ment); |
| 1929 if (axElement) { | 1964 if (axElement) { |
| 1930 foundValidElement = true; | 1965 foundValidElement = true; |
| 1931 localNameObjects.append(axElement.get()); | 1966 localNameObjects.append(axElement.get()); |
| 1932 | 1967 |
| 1933 String result = recursiveTextAlternative(*axElement, inAriaLabelledb yTraversal, visited); | 1968 String result = recursiveTextAlternative(*axElement, inAriaLabelledb yTraversal, visited); |
| 1934 if (!result.isEmpty()) { | 1969 if (!result.isEmpty()) { |
| 1935 if (!accumulatedText.isEmpty()) | 1970 if (!accumulatedText.isEmpty()) |
| 1936 accumulatedText.append(" "); | 1971 accumulatedText.append(" "); |
| 1937 accumulatedText.append(result); | 1972 accumulatedText.append(result); |
| 1938 } | 1973 } |
| 1939 } | 1974 } |
| 1940 } | 1975 } |
| 1941 if (!foundValidElement) | 1976 if (!foundValidElement) |
| 1942 return String(); | 1977 return String(); |
| 1943 nameObjects = localNameObjects; | 1978 if (nameObjects) |
| 1979 *nameObjects = localNameObjects; | |
| 1944 return accumulatedText.toString(); | 1980 return accumulatedText.toString(); |
| 1945 } | 1981 } |
| 1946 | 1982 |
| 1947 String AXNodeObject::textFromAriaLabelledby(AXObjectSet& visited, AXObjectVector & nameObjects) const | 1983 String AXNodeObject::textFromAriaLabelledby(AXObjectSet& visited, AXObjectVector * nameObjects) const |
| 1948 { | 1984 { |
| 1949 WillBeHeapVector<RawPtrWillBeMember<Element>> elements; | 1985 WillBeHeapVector<RawPtrWillBeMember<Element>> elements; |
| 1950 ariaLabelledbyElements(elements); | 1986 ariaLabelledbyElements(elements); |
| 1951 return textFromElements(true, visited, elements, nameObjects); | 1987 return textFromElements(true, visited, elements, nameObjects); |
| 1952 } | 1988 } |
| 1953 | 1989 |
| 1954 LayoutRect AXNodeObject::elementRect() const | 1990 LayoutRect AXNodeObject::elementRect() const |
| 1955 { | 1991 { |
| 1956 // First check if it has a custom rect, for example if this element is tied to a canvas path. | 1992 // First check if it has a custom rect, for example if this element is tied to a canvas path. |
| 1957 if (!m_explicitElementRect.isEmpty()) | 1993 if (!m_explicitElementRect.isEmpty()) |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2140 } | 2176 } |
| 2141 | 2177 |
| 2142 Element* AXNodeObject::actionElement() const | 2178 Element* AXNodeObject::actionElement() const |
| 2143 { | 2179 { |
| 2144 Node* node = this->node(); | 2180 Node* node = this->node(); |
| 2145 if (!node) | 2181 if (!node) |
| 2146 return 0; | 2182 return 0; |
| 2147 | 2183 |
| 2148 if (isHTMLInputElement(*node)) { | 2184 if (isHTMLInputElement(*node)) { |
| 2149 HTMLInputElement& input = toHTMLInputElement(*node); | 2185 HTMLInputElement& input = toHTMLInputElement(*node); |
| 2150 if (!input.isDisabledFormControl() && (isCheckboxOrRadio() || input.isTe xtButton() | 2186 if (!input.isDisabledFormControl() && (isCheckboxOrRadio() || input.isTe xtButton() || input.type() == InputTypeNames::file)) |
| 2151 || input.type() == InputTypeNames::file)) | |
| 2152 return &input; | 2187 return &input; |
| 2153 } else if (isHTMLButtonElement(*node)) { | 2188 } else if (isHTMLButtonElement(*node)) { |
| 2154 return toElement(node); | 2189 return toElement(node); |
| 2155 } | 2190 } |
| 2156 | 2191 |
| 2157 if (AXObject::isARIAInput(ariaRoleAttribute())) | 2192 if (AXObject::isARIAInput(ariaRoleAttribute())) |
| 2158 return toElement(node); | 2193 return toElement(node); |
| 2159 | 2194 |
| 2160 if (isImageButton()) | 2195 if (isImageButton()) |
| 2161 return toElement(node); | 2196 return toElement(node); |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2447 ariaLabelledbyElements(elements); | 2482 ariaLabelledbyElements(elements); |
| 2448 | 2483 |
| 2449 for (const auto& element : elements) { | 2484 for (const auto& element : elements) { |
| 2450 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate (element); | 2485 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate (element); |
| 2451 textOrder.append(AccessibilityText::create(ariaLabelledby, Alternati veText, axElement)); | 2486 textOrder.append(AccessibilityText::create(ariaLabelledby, Alternati veText, axElement)); |
| 2452 } | 2487 } |
| 2453 } | 2488 } |
| 2454 } | 2489 } |
| 2455 | 2490 |
| 2456 // Based on http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible- name-and-description-calculation | 2491 // Based on http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible- name-and-description-calculation |
| 2457 String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam eFrom, AXObjectVector& nameObjects, NameSources* nameSources, bool* foundTextAlt ernative) const | 2492 String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam eFrom, AXObjectVector* nameObjects, NameSources* nameSources, bool* foundTextAlt ernative) const |
| 2458 { | 2493 { |
| 2459 if (!node()) | 2494 if (!node()) |
| 2460 return String(); | 2495 return String(); |
| 2461 | 2496 |
| 2497 // If nameSources is non-null, nameObjects is used in filling it in, so it m ust be non-null as well. | |
| 2498 if (nameSources) | |
| 2499 assert(nameObjects); | |
| 2500 | |
| 2462 String textAlternative; | 2501 String textAlternative; |
| 2463 AXObjectVector localNameObjects; | 2502 AXObjectVector localNameObjects; |
| 2464 | 2503 |
| 2465 const HTMLInputElement* inputElement = nullptr; | 2504 const HTMLInputElement* inputElement = nullptr; |
| 2466 if (isHTMLInputElement(node())) | 2505 if (isHTMLInputElement(node())) |
| 2467 inputElement = toHTMLInputElement(node()); | 2506 inputElement = toHTMLInputElement(node()); |
| 2468 | 2507 |
| 2508 // 5.1/5.5 Text inputs, Other labelable Elements | |
| 2509 HTMLElement* htmlElement = nullptr; | |
| 2510 if (node()->isHTMLElement()) | |
| 2511 htmlElement = toHTMLElement(node()); | |
| 2512 if (htmlElement && htmlElement->isLabelable()) { | |
| 2513 // label | |
| 2514 nameFrom = AXNameFromRelatedElement; | |
| 2515 if (nameSources) { | |
| 2516 nameSources->append(NameSource(*foundTextAlternative)); | |
| 2517 nameSources->last().type = nameFrom; | |
| 2518 nameSources->last().nativeSource = AXTextFromNativeHTMLLabel; | |
| 2519 } | |
| 2520 HTMLLabelElement* label = labelForElement(htmlElement); | |
| 2521 if (label) { | |
| 2522 RefPtrWillBeRawPtr<AXObject> labelAXObject = axObjectCache().getOrCr eate(label); | |
| 2523 if (labelAXObject) { | |
| 2524 if (nameObjects) { | |
| 2525 localNameObjects.append(labelAXObject.get()); | |
| 2526 *nameObjects = localNameObjects; | |
| 2527 localNameObjects.clear(); | |
| 2528 } | |
| 2529 textAlternative = recursiveTextAlternative(*labelAXObject, false , visited); | |
| 2530 | |
| 2531 if (nameSources) { | |
| 2532 NameSource& source = nameSources->last(); | |
| 2533 source.nameObjects = *nameObjects; | |
| 2534 source.text = textAlternative; | |
| 2535 if (label->getAttribute(forAttr).isNull()) | |
| 2536 source.nativeSource = AXTextFromNativeHTMLLabelWrapped; | |
| 2537 else | |
| 2538 source.nativeSource = AXTextFromNativeHTMLLabelFor; | |
| 2539 *foundTextAlternative = true; | |
| 2540 } else { | |
| 2541 return textAlternative; | |
| 2542 } | |
| 2543 } | |
| 2544 } | |
| 2545 } | |
| 2546 | |
| 2469 // 5.2 input type="button", input type="submit" and input type="reset" | 2547 // 5.2 input type="button", input type="submit" and input type="reset" |
| 2470 if (inputElement && inputElement->isTextButton()) { | 2548 if (inputElement && inputElement->isTextButton()) { |
| 2471 // value attribue | 2549 // value attribue |
| 2472 nameFrom = AXNameFromAttribute; | 2550 nameFrom = AXNameFromAttribute; |
| 2473 if (nameSources) { | 2551 if (nameSources) { |
| 2474 nameSources->append(NameSource(*foundTextAlternative, valueAttr)); | 2552 nameSources->append(NameSource(*foundTextAlternative, valueAttr)); |
| 2475 nameSources->last().type = nameFrom; | 2553 nameSources->last().type = nameFrom; |
| 2476 } | 2554 } |
| 2477 String value = inputElement->value(); | 2555 String value = inputElement->value(); |
| 2478 if (!value.isNull()) { | 2556 if (!value.isNull()) { |
| 2479 textAlternative = value; | 2557 textAlternative = value; |
| 2480 if (nameSources) { | 2558 if (nameSources) { |
| 2481 NameSource& source = nameSources->last(); | 2559 NameSource& source = nameSources->last(); |
| 2482 source.text = textAlternative; | 2560 source.text = textAlternative; |
| 2483 *foundTextAlternative = true; | 2561 *foundTextAlternative = true; |
| 2484 } else { | 2562 } else { |
| 2485 return textAlternative; | 2563 return textAlternative; |
| 2486 } | 2564 } |
| 2487 } | 2565 } |
| 2488 | |
| 2489 // localised default value ("Submit" or "Reset") | |
| 2490 String defaultValue = inputElement->defaultValue(); | |
| 2491 if (!defaultValue.isNull()) { | |
| 2492 // defaultValue is always set for submit and reset buttons, and neve r set for anything else. | |
| 2493 nameFrom = AXNameFromAttribute; | |
| 2494 textAlternative = defaultValue; | |
| 2495 if (nameSources) { | |
| 2496 nameSources->append(NameSource(*foundTextAlternative, typeAttr)) ; | |
| 2497 NameSource& source = nameSources->last(); | |
| 2498 source.attributeValue = inputElement->getAttribute(typeAttr); | |
| 2499 source.text = textAlternative; | |
| 2500 *foundTextAlternative = true; | |
| 2501 } else { | |
| 2502 return textAlternative; | |
| 2503 } | |
| 2504 } | |
| 2505 return textAlternative; | 2566 return textAlternative; |
| 2506 } | 2567 } |
| 2507 | 2568 |
| 2508 // 5.3 input type="image" | 2569 // 5.3 input type="image" |
| 2509 if (inputElement && inputElement->getAttribute(typeAttr) == InputTypeNames:: image) { | 2570 if (inputElement && inputElement->getAttribute(typeAttr) == InputTypeNames:: image) { |
| 2510 // alt attr | 2571 // alt attr |
| 2511 nameFrom = AXNameFromAttribute; | 2572 nameFrom = AXNameFromAttribute; |
| 2512 if (nameSources) { | 2573 if (nameSources) { |
| 2513 nameSources->append(NameSource(*foundTextAlternative, altAttr)); | 2574 nameSources->append(NameSource(*foundTextAlternative, altAttr)); |
| 2514 nameSources->last().type = nameFrom; | 2575 nameSources->last().type = nameFrom; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 2537 textAlternative = value; | 2598 textAlternative = value; |
| 2538 if (nameSources) { | 2599 if (nameSources) { |
| 2539 NameSource& source = nameSources->last(); | 2600 NameSource& source = nameSources->last(); |
| 2540 source.text = textAlternative; | 2601 source.text = textAlternative; |
| 2541 *foundTextAlternative = true; | 2602 *foundTextAlternative = true; |
| 2542 } else { | 2603 } else { |
| 2543 return textAlternative; | 2604 return textAlternative; |
| 2544 } | 2605 } |
| 2545 } | 2606 } |
| 2546 | 2607 |
| 2608 // localised default value ("Submit") | |
|
dmazzoni
2015/08/24 18:02:03
Oh, got it - <input type=image> implies a Submit b
| |
| 2609 nameFrom = AXNameFromAttribute; | |
| 2610 textAlternative = inputElement->locale().queryString(WebLocalizedString: :SubmitButtonDefaultLabel); | |
| 2611 if (nameSources) { | |
| 2612 nameSources->append(NameSource(*foundTextAlternative, typeAttr)); | |
| 2613 NameSource& source = nameSources->last(); | |
| 2614 source.attributeValue = inputElement->getAttribute(typeAttr); | |
| 2615 source.type = nameFrom; | |
| 2616 source.text = textAlternative; | |
| 2617 *foundTextAlternative = true; | |
| 2618 } else { | |
| 2619 return textAlternative; | |
| 2620 } | |
| 2547 return textAlternative; | 2621 return textAlternative; |
| 2548 } | 2622 } |
| 2549 | 2623 |
| 2550 // 5.5 Other labelable Elements | 2624 // 5.1 Text inputs - step 3 (placeholder attribute) |
| 2551 if (node()->isHTMLElement() && toHTMLElement(node())->isLabelable()) { | 2625 if (htmlElement && htmlElement->isTextFormControl()) { |
| 2552 // label | 2626 nameFrom = AXNameFromPlaceholder; |
| 2553 nameFrom = AXNameFromRelatedElement; | |
| 2554 if (nameSources) { | 2627 if (nameSources) { |
| 2555 nameSources->append(NameSource(*foundTextAlternative)); | 2628 nameSources->append(NameSource(*foundTextAlternative, placeholderAtt r)); |
| 2556 nameSources->last().type = nameFrom; | 2629 NameSource& source = nameSources->last(); |
| 2557 nameSources->last().nativeSource = AXTextFromNativeHTMLLabel; | 2630 source.type = nameFrom; |
| 2558 } | 2631 } |
| 2559 HTMLLabelElement* label = labelForElement(toHTMLElement(node())); | 2632 HTMLElement* element = toHTMLElement(node()); |
| 2560 if (label) { | 2633 if (element->fastHasAttribute(placeholderAttr)) { |
| 2561 RefPtrWillBeRawPtr<AXObject> labelAXObject = axObjectCache().getOrCr eate(label); | 2634 const AtomicString& placeholder = element->fastGetAttribute(placehol derAttr); |
| 2562 if (labelAXObject) { | 2635 if (!placeholder.isEmpty()) { |
| 2563 localNameObjects.append(labelAXObject.get()); | 2636 textAlternative = placeholder; |
| 2564 nameObjects = localNameObjects; | |
| 2565 localNameObjects.clear(); | |
| 2566 | |
| 2567 textAlternative = recursiveTextAlternative(*labelAXObject, false , visited); | |
| 2568 | |
| 2569 if (nameSources) { | 2637 if (nameSources) { |
| 2570 NameSource& source = nameSources->last(); | 2638 NameSource& source = nameSources->last(); |
| 2571 source.nameObjects = nameObjects; | |
| 2572 source.text = textAlternative; | 2639 source.text = textAlternative; |
| 2573 if (label->getAttribute(forAttr).isNull()) | 2640 source.attributeValue = placeholder; |
| 2574 source.nativeSource = AXTextFromNativeHTMLLabelWrapped; | |
| 2575 else | |
| 2576 source.nativeSource = AXTextFromNativeHTMLLabelFor; | |
| 2577 *foundTextAlternative = true; | |
| 2578 } else { | 2641 } else { |
| 2579 return textAlternative; | 2642 return textAlternative; |
| 2580 } | 2643 } |
| 2581 } | 2644 } |
| 2582 } | 2645 } |
| 2583 return textAlternative; | 2646 return textAlternative; |
| 2584 } | 2647 } |
| 2585 | 2648 |
| 2586 // 5.7 figure and figcaption Elements | 2649 // 5.7 figure and figcaption Elements |
| 2587 if (node()->hasTagName(figureTag)) { | 2650 if (node()->hasTagName(figureTag)) { |
| 2588 // figcaption | 2651 // figcaption |
| 2589 nameFrom = AXNameFromRelatedElement; | 2652 nameFrom = AXNameFromRelatedElement; |
| 2590 if (nameSources) { | 2653 if (nameSources) { |
| 2591 nameSources->append(NameSource(*foundTextAlternative)); | 2654 nameSources->append(NameSource(*foundTextAlternative)); |
| 2592 nameSources->last().type = nameFrom; | 2655 nameSources->last().type = nameFrom; |
| 2593 nameSources->last().nativeSource = AXTextFromNativeHTMLFigcaption; | 2656 nameSources->last().nativeSource = AXTextFromNativeHTMLFigcaption; |
| 2594 } | 2657 } |
| 2595 Element* figcaption = nullptr; | 2658 Element* figcaption = nullptr; |
| 2596 for (Element& element : ElementTraversal::descendantsOf(*(node()))) { | 2659 for (Element& element : ElementTraversal::descendantsOf(*(node()))) { |
| 2597 if (element.hasTagName(figcaptionTag)) { | 2660 if (element.hasTagName(figcaptionTag)) { |
| 2598 figcaption = &element; | 2661 figcaption = &element; |
| 2599 break; | 2662 break; |
| 2600 } | 2663 } |
| 2601 } | 2664 } |
| 2602 if (figcaption) { | 2665 if (figcaption) { |
| 2603 RefPtrWillBeRawPtr<AXObject> figcaptionAXObject = axObjectCache().ge tOrCreate(figcaption); | 2666 RefPtrWillBeRawPtr<AXObject> figcaptionAXObject = axObjectCache().ge tOrCreate(figcaption); |
| 2604 if (figcaptionAXObject) { | 2667 if (figcaptionAXObject) { |
| 2605 localNameObjects.append(figcaptionAXObject.get()); | 2668 if (nameObjects) { |
| 2606 nameObjects = localNameObjects; | 2669 localNameObjects.append(figcaptionAXObject.get()); |
| 2607 localNameObjects.clear(); | 2670 *nameObjects = localNameObjects; |
| 2671 localNameObjects.clear(); | |
| 2672 } | |
| 2608 | 2673 |
| 2609 textAlternative = recursiveTextAlternative(*figcaptionAXObject, false, visited); | 2674 textAlternative = recursiveTextAlternative(*figcaptionAXObject, false, visited); |
| 2610 | 2675 |
| 2611 if (nameSources) { | 2676 if (nameSources) { |
| 2612 NameSource& source = nameSources->last(); | 2677 NameSource& source = nameSources->last(); |
| 2613 source.nameObjects = nameObjects; | 2678 source.nameObjects = *nameObjects; |
| 2614 source.text = textAlternative; | 2679 source.text = textAlternative; |
| 2615 } else { | 2680 } else { |
| 2616 return textAlternative; | 2681 return textAlternative; |
| 2617 } | 2682 } |
| 2618 } | 2683 } |
| 2619 } | 2684 } |
| 2620 return textAlternative; | 2685 return textAlternative; |
| 2621 } | 2686 } |
| 2622 | 2687 |
| 2623 // 5.8 img Element | 2688 // 5.8 img Element |
| 2624 if (isHTMLImageElement(node())) { | 2689 if (isHTMLImageElement(node())) { |
| 2625 HTMLImageElement* imgElement = toHTMLImageElement(node()); | |
| 2626 | |
| 2627 // alt | 2690 // alt |
| 2628 nameFrom = AXNameFromAttribute; | 2691 nameFrom = AXNameFromAttribute; |
| 2629 if (nameSources) { | 2692 if (nameSources) { |
| 2630 nameSources->append(NameSource(*foundTextAlternative, altAttr)); | 2693 nameSources->append(NameSource(*foundTextAlternative, altAttr)); |
| 2631 nameSources->last().type = nameFrom; | 2694 nameSources->last().type = nameFrom; |
| 2632 } | 2695 } |
| 2633 if (imgElement->hasAttribute(altAttr)) { | 2696 if (hasAttribute(altAttr)) { |
| 2634 AtomicString alt = imgElement->getAttribute(altAttr); | 2697 AtomicString alt = getAttribute(altAttr); |
| 2635 textAlternative = alt; | 2698 textAlternative = alt; |
| 2636 if (nameSources) { | 2699 if (nameSources) { |
| 2637 NameSource& source = nameSources->last(); | 2700 NameSource& source = nameSources->last(); |
| 2638 source.attributeValue = alt; | 2701 source.attributeValue = alt; |
| 2639 source.text = textAlternative; | 2702 source.text = textAlternative; |
| 2640 *foundTextAlternative = true; | 2703 *foundTextAlternative = true; |
| 2641 } else { | 2704 } else { |
| 2642 return textAlternative; | 2705 return textAlternative; |
| 2643 } | 2706 } |
| 2644 } | 2707 } |
| 2645 return textAlternative; | 2708 return textAlternative; |
| 2646 } | 2709 } |
| 2647 | 2710 |
| 2648 // 5.9 table Element | 2711 // 5.9 table Element |
| 2649 if (isHTMLTableElement(node())) { | 2712 if (isHTMLTableElement(node())) { |
| 2650 HTMLTableElement* tableElement = toHTMLTableElement(node()); | 2713 HTMLTableElement* tableElement = toHTMLTableElement(node()); |
| 2651 | 2714 |
| 2652 // caption | 2715 // caption |
| 2653 nameFrom = AXNameFromRelatedElement; | 2716 nameFrom = AXNameFromRelatedElement; |
| 2654 if (nameSources) { | 2717 if (nameSources) { |
| 2655 nameSources->append(NameSource(*foundTextAlternative)); | 2718 nameSources->append(NameSource(*foundTextAlternative)); |
| 2656 nameSources->last().type = nameFrom; | 2719 nameSources->last().type = nameFrom; |
| 2657 nameSources->last().nativeSource = AXTextFromNativeHTMLTableCaption; | 2720 nameSources->last().nativeSource = AXTextFromNativeHTMLTableCaption; |
| 2658 } | 2721 } |
| 2659 HTMLTableCaptionElement* caption = tableElement->caption(); | 2722 HTMLTableCaptionElement* caption = tableElement->caption(); |
| 2660 if (caption) { | 2723 if (caption) { |
| 2661 RefPtrWillBeRawPtr<AXObject> captionAXObject = axObjectCache().getOr Create(caption); | 2724 RefPtrWillBeRawPtr<AXObject> captionAXObject = axObjectCache().getOr Create(caption); |
| 2662 if (captionAXObject) { | 2725 if (captionAXObject) { |
| 2663 localNameObjects.append(captionAXObject.get()); | 2726 if (nameObjects) { |
| 2664 nameObjects = localNameObjects; | 2727 localNameObjects.append(captionAXObject.get()); |
| 2665 localNameObjects.clear(); | 2728 *nameObjects = localNameObjects; |
| 2729 localNameObjects.clear(); | |
| 2730 } | |
| 2666 | 2731 |
| 2667 textAlternative = recursiveTextAlternative(*captionAXObject, fal se, visited); | 2732 textAlternative = recursiveTextAlternative(*captionAXObject, fal se, visited); |
| 2668 if (nameSources) { | 2733 if (nameSources) { |
| 2669 NameSource& source = nameSources->last(); | 2734 NameSource& source = nameSources->last(); |
| 2670 source.nameObjects = nameObjects; | 2735 source.nameObjects = *nameObjects; |
| 2671 source.text = textAlternative; | 2736 source.text = textAlternative; |
| 2672 } else { | 2737 } else { |
| 2673 return textAlternative; | 2738 return textAlternative; |
| 2674 } | 2739 } |
| 2675 } | 2740 } |
| 2676 } | 2741 } |
| 2742 | |
| 2743 // summary | |
| 2744 nameFrom = AXNameFromAttribute; | |
| 2745 if (nameSources) { | |
| 2746 nameSources->append(NameSource(*foundTextAlternative)); | |
| 2747 nameSources->last().type = nameFrom; | |
| 2748 } | |
| 2749 if (hasAttribute(summaryAttr)) { | |
| 2750 AtomicString summary = getAttribute(summaryAttr); | |
| 2751 textAlternative = summary; | |
| 2752 if (nameSources) { | |
| 2753 NameSource& source = nameSources->last(); | |
| 2754 source.attributeValue = summary; | |
| 2755 source.text = textAlternative; | |
| 2756 *foundTextAlternative = true; | |
| 2757 } else { | |
| 2758 return textAlternative; | |
| 2759 } | |
| 2760 } | |
| 2761 | |
| 2677 return textAlternative; | 2762 return textAlternative; |
| 2678 } | 2763 } |
| 2679 | 2764 |
| 2680 return textAlternative; | 2765 return textAlternative; |
| 2681 } | 2766 } |
| 2682 | 2767 |
| 2683 DEFINE_TRACE(AXNodeObject) | 2768 DEFINE_TRACE(AXNodeObject) |
| 2684 { | 2769 { |
| 2685 visitor->trace(m_node); | 2770 visitor->trace(m_node); |
| 2686 AXObject::trace(visitor); | 2771 AXObject::trace(visitor); |
| 2687 } | 2772 } |
| 2688 | 2773 |
| 2689 } // namespace blink | 2774 } // namespace blink |
| OLD | NEW |