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

Side by Side Diff: third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp

Issue 1435113003: Make use of new AX name calc in Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix issue with ariaTextAlternative Created 5 years, 1 month 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
OLDNEW
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
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 if (!ariaLabelledby.isEmpty()) 149 if (!ariaLabelledby.isEmpty())
150 return ariaLabelledby; 150 return ariaLabelledby;
151 151
152 const AtomicString& ariaLabel = getAttribute(aria_labelAttr); 152 const AtomicString& ariaLabel = getAttribute(aria_labelAttr);
153 if (!ariaLabel.isEmpty()) 153 if (!ariaLabel.isEmpty())
154 return ariaLabel; 154 return ariaLabel;
155 155
156 return String(); 156 return String();
157 } 157 }
158 158
159
160 void AXNodeObject::ariaLabelledbyElements(WillBeHeapVector<RawPtrWillBeMember<El ement>>& elements) const
161 {
162 // Try both spellings, but prefer aria-labelledby, which is the official spe c.
163 elementsFromAttribute(elements, aria_labelledbyAttr);
164 if (!elements.size())
165 elementsFromAttribute(elements, aria_labeledbyAttr);
166 }
167
168 bool AXNodeObject::computeAccessibilityIsIgnored(IgnoredReasons* ignoredReasons) const 159 bool AXNodeObject::computeAccessibilityIsIgnored(IgnoredReasons* ignoredReasons) const
169 { 160 {
170 #if ENABLE(ASSERT) 161 #if ENABLE(ASSERT)
171 // Double-check that an AXObject is never accessed before 162 // Double-check that an AXObject is never accessed before
172 // it's been initialized. 163 // it's been initialized.
173 ASSERT(m_initialized); 164 ASSERT(m_initialized);
174 #endif 165 #endif
175 166
176 // If this element is within a parent that cannot have children, it should n ot be exposed. 167 // If this element is within a parent that cannot have children, it should n ot be exposed.
177 if (isDescendantOfLeafNode()) { 168 if (isDescendantOfLeafNode()) {
178 if (ignoredReasons) 169 if (ignoredReasons)
179 ignoredReasons->append(IgnoredReason(AXAncestorIsLeafNode, leafNodeA ncestor())); 170 ignoredReasons->append(IgnoredReason(AXAncestorIsLeafNode, leafNodeA ncestor()));
180 return true; 171 return true;
181 } 172 }
182 173
183 // Ignore labels that are already referenced by a control's title UI element . 174 // Ignore labels that are already referenced by a control.
184 AXObject* controlObject = correspondingControlForLabelElement(); 175 AXObject* controlObject = correspondingControlForLabelElement();
185 if (controlObject && !controlObject->deprecatedExposesTitleUIElement() && co ntrolObject->isCheckboxOrRadio()) { 176 if (controlObject && controlObject->isCheckboxOrRadio()) {
186 if (ignoredReasons) { 177 AXNameFrom controlNameFrom;
187 HTMLLabelElement* label = labelElementContainer(); 178 AXObject::AXObjectVector controlNameObjects;
188 if (label && !label->isSameNode(node())) { 179 controlObject->name(controlNameFrom, &controlNameObjects);
189 AXObject* labelAXObject = axObjectCache().getOrCreate(label); 180 if (controlNameFrom == AXNameFromRelatedElement) {
190 ignoredReasons->append(IgnoredReason(AXLabelContainer, labelAXOb ject)); 181 if (ignoredReasons) {
182 HTMLLabelElement* label = labelElementContainer();
183 if (label && !label->isSameNode(node())) {
184 AXObject* labelAXObject = axObjectCache().getOrCreate(label) ;
185 ignoredReasons->append(IgnoredReason(AXLabelContainer, label AXObject));
186 }
187
188 ignoredReasons->append(IgnoredReason(AXLabelFor, controlObject)) ;
191 } 189 }
192 190 return true;
193 ignoredReasons->append(IgnoredReason(AXLabelFor, controlObject));
194 } 191 }
195 return true;
196 } 192 }
197 193
198 Element* element = node()->isElementNode() ? toElement(node()) : node()->par entElement(); 194 Element* element = node()->isElementNode() ? toElement(node()) : node()->par entElement();
199 if (!layoutObject() 195 if (!layoutObject()
200 && (!element || !element->isInCanvasSubtree()) 196 && (!element || !element->isInCanvasSubtree())
201 && !equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) { 197 && !equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) {
202 if (ignoredReasons) 198 if (ignoredReasons)
203 ignoredReasons->append(IgnoredReason(AXNotRendered)); 199 ignoredReasons->append(IgnoredReason(AXNotRendered));
204 return true; 200 return true;
205 } 201 }
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 role = buttonRoleType(); 541 role = buttonRoleType();
546 542
547 role = remapAriaRoleDueToParent(role); 543 role = remapAriaRoleDueToParent(role);
548 544
549 if (role) 545 if (role)
550 return role; 546 return role;
551 547
552 return UnknownRole; 548 return UnknownRole;
553 } 549 }
554 550
555 void AXNodeObject::tokenVectorFromAttribute(Vector<String>& tokens, const Qualif iedName& attribute) const
556 {
557 Node* node = this->node();
558 if (!node || !node->isElementNode())
559 return;
560
561 String attributeValue = getAttribute(attribute).string();
562 if (attributeValue.isEmpty())
563 return;
564
565 attributeValue.simplifyWhiteSpace();
566 attributeValue.split(' ', tokens);
567 }
568
569 void AXNodeObject::elementsFromAttribute(WillBeHeapVector<RawPtrWillBeMember<Ele ment>>& elements, const QualifiedName& attribute) const
570 {
571 Vector<String> ids;
572 tokenVectorFromAttribute(ids, attribute);
573 if (ids.isEmpty())
574 return;
575
576 TreeScope& scope = node()->treeScope();
577 for (const auto& id : ids) {
578 if (Element* idElement = scope.getElementById(AtomicString(id)))
579 elements.append(idElement);
580 }
581 }
582
583 void AXNodeObject::accessibilityChildrenFromAttribute(QualifiedName attr, AXObje ct::AXObjectVector& children) const 551 void AXNodeObject::accessibilityChildrenFromAttribute(QualifiedName attr, AXObje ct::AXObjectVector& children) const
584 { 552 {
585 WillBeHeapVector<RawPtrWillBeMember<Element>> elements; 553 WillBeHeapVector<RawPtrWillBeMember<Element>> elements;
586 elementsFromAttribute(elements, attr); 554 elementsFromAttribute(elements, attr);
587 555
588 AXObjectCacheImpl& cache = axObjectCache(); 556 AXObjectCacheImpl& cache = axObjectCache();
589 for (const auto& element : elements) { 557 for (const auto& element : elements) {
590 if (AXObject* child = cache.getOrCreate(element)) 558 if (AXObject* child = cache.getOrCreate(element))
591 children.append(child); 559 children.append(child);
592 } 560 }
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after
1132 Node* node = this->node(); 1100 Node* node = this->node();
1133 if (!isHTMLCanvasElement(node)) 1101 if (!isHTMLCanvasElement(node))
1134 return false; 1102 return false;
1135 1103
1136 // If it has any children that are elements, we'll assume it might be fallba ck 1104 // If it has any children that are elements, we'll assume it might be fallba ck
1137 // content. If it has no children or its only children are not elements 1105 // content. If it has no children or its only children are not elements
1138 // (e.g. just text nodes), it doesn't have fallback content. 1106 // (e.g. just text nodes), it doesn't have fallback content.
1139 return ElementTraversal::firstChild(*node); 1107 return ElementTraversal::firstChild(*node);
1140 } 1108 }
1141 1109
1142 bool AXNodeObject::deprecatedExposesTitleUIElement() const
1143 {
1144 if (!isControl())
1145 return false;
1146
1147 // If this control is ignored (because it's invisible),
1148 // then the label needs to be exposed so it can be visible to accessibility.
1149 if (accessibilityIsIgnored())
1150 return true;
1151
1152 // ARIA: section 2A, bullet #3 says if aria-labelledby or aria-label appears , it should
1153 // override the "label" element association.
1154 bool hasTextAlternative = (!ariaLabelledbyAttribute().isEmpty() || !getAttri bute(aria_labelAttr).isEmpty());
1155
1156 // Checkboxes and radio buttons use the text of their title ui element as th eir own AXTitle.
1157 // This code controls whether the title ui element should appear in the AX t ree (usually, no).
1158 // It should appear if the control already has a label (which will be used a s the AXTitle instead).
1159 if (isCheckboxOrRadio())
1160 return hasTextAlternative;
1161
1162 // When controls have their own descriptions, the title element should be ig nored.
1163 if (hasTextAlternative)
1164 return false;
1165
1166 return true;
1167 }
1168
1169 int AXNodeObject::headingLevel() const 1110 int AXNodeObject::headingLevel() const
1170 { 1111 {
1171 // headings can be in block flow and non-block flow 1112 // headings can be in block flow and non-block flow
1172 Node* node = this->node(); 1113 Node* node = this->node();
1173 if (!node) 1114 if (!node)
1174 return 0; 1115 return 0;
1175 1116
1176 if (roleValue() == HeadingRole && hasAttribute(aria_levelAttr)) { 1117 if (roleValue() == HeadingRole && hasAttribute(aria_levelAttr)) {
1177 int level = getAttribute(aria_levelAttr).toInt(); 1118 int level = getAttribute(aria_levelAttr).toInt();
1178 if (level >= 1 && level <= 9) 1119 if (level >= 1 && level <= 9)
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1239 1180
1240 const AtomicString& ariaAutoComplete = getAttribute(aria_autocompleteAttr).l ower(); 1181 const AtomicString& ariaAutoComplete = getAttribute(aria_autocompleteAttr).l ower();
1241 1182
1242 if (ariaAutoComplete == "inline" || ariaAutoComplete == "list" 1183 if (ariaAutoComplete == "inline" || ariaAutoComplete == "list"
1243 || ariaAutoComplete == "both") 1184 || ariaAutoComplete == "both")
1244 return ariaAutoComplete; 1185 return ariaAutoComplete;
1245 1186
1246 return String(); 1187 return String();
1247 } 1188 }
1248 1189
1249 String AXNodeObject::deprecatedPlaceholder() const
1250 {
1251 String placeholder;
1252 if (node()) {
1253 if (isHTMLInputElement(*node())) {
1254 HTMLInputElement* inputElement = toHTMLInputElement(node());
1255 placeholder = inputElement->strippedPlaceholder();
1256 } else if (isHTMLTextAreaElement(*node())) {
1257 HTMLTextAreaElement* textAreaElement = toHTMLTextAreaElement(node()) ;
1258 placeholder = textAreaElement->strippedPlaceholder();
1259 }
1260 }
1261 return placeholder;
1262 }
1263
1264 AccessibilityOrientation AXNodeObject::orientation() const 1190 AccessibilityOrientation AXNodeObject::orientation() const
1265 { 1191 {
1266 const AtomicString& ariaOrientation = getAttribute(aria_orientationAttr); 1192 const AtomicString& ariaOrientation = getAttribute(aria_orientationAttr);
1267 AccessibilityOrientation orientation = AccessibilityOrientationUndefined; 1193 AccessibilityOrientation orientation = AccessibilityOrientationUndefined;
1268 if (equalIgnoringCase(ariaOrientation, "horizontal")) 1194 if (equalIgnoringCase(ariaOrientation, "horizontal"))
1269 orientation = AccessibilityOrientationHorizontal; 1195 orientation = AccessibilityOrientationHorizontal;
1270 else if (equalIgnoringCase(ariaOrientation, "vertical")) 1196 else if (equalIgnoringCase(ariaOrientation, "vertical"))
1271 orientation = AccessibilityOrientationVertical; 1197 orientation = AccessibilityOrientationVertical;
1272 1198
1273 switch (roleValue()) { 1199 switch (roleValue()) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1314 1240
1315 if (isNativeTextControl() && (isHTMLTextAreaElement(*node) || isHTMLInputEle ment(*node))) 1241 if (isNativeTextControl() && (isHTMLTextAreaElement(*node) || isHTMLInputEle ment(*node)))
1316 return toHTMLTextFormControlElement(*node).value(); 1242 return toHTMLTextFormControlElement(*node).value();
1317 1243
1318 if (!node->isElementNode()) 1244 if (!node->isElementNode())
1319 return String(); 1245 return String();
1320 1246
1321 return toElement(node)->innerText(); 1247 return toElement(node)->innerText();
1322 } 1248 }
1323 1249
1324 AXObject* AXNodeObject::deprecatedTitleUIElement() const
1325 {
1326 if (!node() || !node()->isElementNode())
1327 return 0;
1328
1329 if (isFieldset())
1330 return axObjectCache().getOrCreate(toHTMLFieldSetElement(node())->legend ());
1331
1332 HTMLLabelElement* label = labelForElement(toElement(node()));
1333 if (label)
1334 return axObjectCache().getOrCreate(label);
1335
1336 return 0;
1337 }
1338
1339 AccessibilityButtonState AXNodeObject::checkboxOrRadioValue() const 1250 AccessibilityButtonState AXNodeObject::checkboxOrRadioValue() const
1340 { 1251 {
1341 if (isNativeCheckboxOrRadio()) 1252 if (isNativeCheckboxOrRadio())
1342 return isChecked() ? ButtonStateOn : ButtonStateOff; 1253 return isChecked() ? ButtonStateOn : ButtonStateOff;
1343 1254
1344 return AXObject::checkboxOrRadioValue(); 1255 return AXObject::checkboxOrRadioValue();
1345 } 1256 }
1346 1257
1347 RGBA32 AXNodeObject::colorValue() const 1258 RGBA32 AXNodeObject::colorValue() const
1348 { 1259 {
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1483 Decimal step = toHTMLInputElement(*node()).createStepRange(RejectAny).step() ; 1394 Decimal step = toHTMLInputElement(*node()).createStepRange(RejectAny).step() ;
1484 return step.toString().toFloat(); 1395 return step.toString().toFloat();
1485 } 1396 }
1486 1397
1487 String AXNodeObject::stringValue() const 1398 String AXNodeObject::stringValue() const
1488 { 1399 {
1489 Node* node = this->node(); 1400 Node* node = this->node();
1490 if (!node) 1401 if (!node)
1491 return String(); 1402 return String();
1492 1403
1493 if (ariaRoleAttribute() == StaticTextRole) {
1494 String staticText = text();
1495 if (!staticText.length())
1496 staticText = deprecatedTextUnderElement(TextUnderElementAll);
1497 return staticText;
1498 }
1499
1500 if (node->isTextNode())
1501 return deprecatedTextUnderElement(TextUnderElementAll);
1502
1503 return stringValueOfControl();
1504 }
1505
1506 String AXNodeObject::stringValueOfControl() const
1507 {
1508 Node* node = this->node();
1509 if (!node)
1510 return String();
1511
1512 if (isHTMLSelectElement(*node)) { 1404 if (isHTMLSelectElement(*node)) {
1513 HTMLSelectElement& selectElement = toHTMLSelectElement(*node); 1405 HTMLSelectElement& selectElement = toHTMLSelectElement(*node);
1514 int selectedIndex = selectElement.selectedIndex(); 1406 int selectedIndex = selectElement.selectedIndex();
1515 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = sel ectElement.listItems(); 1407 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = sel ectElement.listItems();
1516 if (selectedIndex >= 0 && static_cast<size_t>(selectedIndex) < listItems .size()) { 1408 if (selectedIndex >= 0 && static_cast<size_t>(selectedIndex) < listItems .size()) {
1517 const AtomicString& overriddenDescription = listItems[selectedIndex] ->fastGetAttribute(aria_labelAttr); 1409 const AtomicString& overriddenDescription = listItems[selectedIndex] ->fastGetAttribute(aria_labelAttr);
1518 if (!overriddenDescription.isNull()) 1410 if (!overriddenDescription.isNull())
1519 return overriddenDescription; 1411 return overriddenDescription;
1520 } 1412 }
1521 if (!selectElement.multiple()) 1413 if (!selectElement.multiple())
(...skipping 20 matching lines...) Expand all
1542 { 1434 {
1543 WillBeHeapVector<RawPtrWillBeMember<Element>> elements; 1435 WillBeHeapVector<RawPtrWillBeMember<Element>> elements;
1544 elementsFromAttribute(elements, aria_describedbyAttr); 1436 elementsFromAttribute(elements, aria_describedbyAttr);
1545 1437
1546 return accessibilityDescriptionForElements(elements); 1438 return accessibilityDescriptionForElements(elements);
1547 } 1439 }
1548 1440
1549 String AXNodeObject::ariaLabelledbyAttribute() const 1441 String AXNodeObject::ariaLabelledbyAttribute() const
1550 { 1442 {
1551 WillBeHeapVector<RawPtrWillBeMember<Element>> elements; 1443 WillBeHeapVector<RawPtrWillBeMember<Element>> elements;
1552 ariaLabelledbyElements(elements); 1444 ariaLabelledbyElementVector(elements);
1553 1445
1554 return accessibilityDescriptionForElements(elements); 1446 return accessibilityDescriptionForElements(elements);
1555 } 1447 }
1556 1448
1557 AccessibilityRole AXNodeObject::ariaRoleAttribute() const 1449 AccessibilityRole AXNodeObject::ariaRoleAttribute() const
1558 { 1450 {
1559 return m_ariaRole; 1451 return m_ariaRole;
1560 } 1452 }
1561 1453
1562 // When building the textUnderElement for an object, determine whether or not
1563 // we should include the inner text of this given descendant object or skip it.
1564 static bool shouldUseAccessibilityObjectInnerText(AXObject* obj)
1565 {
1566 // Consider this hypothetical example:
1567 // <div tabindex=0>
1568 // <h2>
1569 // Table of contents
1570 // </h2>
1571 // <a href="#start">Jump to start of book</a>
1572 // <ul>
1573 // <li><a href="#1">Chapter 1</a></li>
1574 // <li><a href="#1">Chapter 2</a></li>
1575 // </ul>
1576 // </div>
1577 //
1578 // The goal is to return a reasonable title for the outer container div, bec ause
1579 // it's focusable - but without making its title be the full inner text, whi ch is
1580 // quite long. As a heuristic, skip links, controls, and elements that are u sually
1581 // containers with lots of children.
1582
1583 // Skip hidden children
1584 if (obj->isInertOrAriaHidden())
1585 return false;
1586
1587 // If something doesn't expose any children, then we can always take the inn er text content.
1588 // This is what we want when someone puts an <a> inside a <button> for examp le.
1589 if (obj->isDescendantOfLeafNode())
1590 return true;
1591
1592 // Skip focusable children, so we don't include the text of links and contro ls.
1593 if (obj->canSetFocusAttribute())
1594 return false;
1595
1596 // Skip big container elements like lists, tables, etc.
1597 if (obj->isList() || obj->isAXTable() || obj->isTree() || obj->isCanvas())
1598 return false;
1599
1600 return true;
1601 }
1602
1603 // Returns the nearest LayoutBlockFlow ancestor which does not have an 1454 // Returns the nearest LayoutBlockFlow ancestor which does not have an
1604 // inlineBoxWrapper - i.e. is not itself an inline object. 1455 // inlineBoxWrapper - i.e. is not itself an inline object.
1605 static LayoutBlockFlow* nonInlineBlockFlow(LayoutObject* object) 1456 static LayoutBlockFlow* nonInlineBlockFlow(LayoutObject* object)
1606 { 1457 {
1607 LayoutObject* current = object; 1458 LayoutObject* current = object;
1608 while (current) { 1459 while (current) {
1609 if (current->isLayoutBlockFlow()) { 1460 if (current->isLayoutBlockFlow()) {
1610 LayoutBlockFlow* blockFlow = toLayoutBlockFlow(current); 1461 LayoutBlockFlow* blockFlow = toLayoutBlockFlow(current);
1611 if (!blockFlow->inlineBoxWrapper()) 1462 if (!blockFlow->inlineBoxWrapper())
1612 return blockFlow; 1463 return blockFlow;
(...skipping 11 matching lines...) Expand all
1624 { 1475 {
1625 if (!r1 || !r2) 1476 if (!r1 || !r2)
1626 return false; 1477 return false;
1627 if (!r1->isInline() || !r2->isInline()) 1478 if (!r1->isInline() || !r2->isInline())
1628 return false; 1479 return false;
1629 LayoutBlockFlow* b1 = nonInlineBlockFlow(r1); 1480 LayoutBlockFlow* b1 = nonInlineBlockFlow(r1);
1630 LayoutBlockFlow* b2 = nonInlineBlockFlow(r2); 1481 LayoutBlockFlow* b2 = nonInlineBlockFlow(r2);
1631 return b1 && b2 && b1 == b2; 1482 return b1 && b2 && b1 == b2;
1632 } 1483 }
1633 1484
1634 String AXNodeObject::deprecatedTextUnderElement(TextUnderElementMode mode) const
1635 {
1636 Node* node = this->node();
1637 if (node && node->isTextNode())
1638 return toText(node)->wholeText();
1639
1640 StringBuilder builder;
1641 AXObject* previous = nullptr;
1642 for (AXObject* child = firstChild(); child; child = child->nextSibling()) {
1643 if (!shouldUseAccessibilityObjectInnerText(child))
1644 continue;
1645
1646 if (child->isAXNodeObject()) {
1647 HeapVector<Member<AccessibilityText>> textOrder;
1648 toAXNodeObject(child)->deprecatedAlternativeText(textOrder);
1649 if (textOrder.size() > 0) {
1650 builder.append(textOrder[0]->text());
1651 if (mode == TextUnderElementAny)
1652 break;
1653 continue;
1654 }
1655 }
1656
1657 // If we're going between two layoutObjects that are in separate LayoutB oxes, add
1658 // whitespace if it wasn't there already. Intuitively if you have
1659 // <span>Hello</span><span>World</span>, those are part of the same Layo utBox
1660 // so we should return "HelloWorld", but given <div>Hello</div><div>Worl d</div> the
1661 // strings are in separate boxes so we should return "Hello World".
1662 if (previous && builder.length() && !isHTMLSpace(builder[builder.length( ) - 1])) {
1663 if (!isInSameNonInlineBlockFlow(child->layoutObject(), previous->lay outObject()))
1664 builder.append(' ');
1665 }
1666
1667 builder.append(child->deprecatedTextUnderElement(mode));
1668 previous = child;
1669
1670 if (mode == TextUnderElementAny && !builder.isEmpty())
1671 break;
1672 }
1673
1674 return builder.toString();
1675 }
1676
1677 AXObject* AXNodeObject::findChildWithTagName(const HTMLQualifiedName& tagName) c onst 1485 AXObject* AXNodeObject::findChildWithTagName(const HTMLQualifiedName& tagName) c onst
1678 { 1486 {
1679 for (AXObject* child = firstChild(); child; child = child->nextSibling()) { 1487 for (AXObject* child = firstChild(); child; child = child->nextSibling()) {
1680 Node* childNode = child->node(); 1488 Node* childNode = child->node();
1681 if (childNode && childNode->hasTagName(tagName)) 1489 if (childNode && childNode->hasTagName(tagName))
1682 return child; 1490 return child;
1683 } 1491 }
1684 return 0; 1492 return 0;
1685 } 1493 }
1686 1494
1687 String AXNodeObject::deprecatedAccessibilityDescription() const
1688 {
1689 // Static text should not have a description, it should only have a stringVa lue.
1690 if (roleValue() == StaticTextRole)
1691 return String();
1692
1693 String ariaDescription = ariaAccessibilityDescription();
1694 if (!ariaDescription.isEmpty())
1695 return ariaDescription;
1696
1697 if (isImage() || isInputImage() || isNativeImage() || isCanvas()) {
1698 // Images should use alt as long as the attribute is present, even if em pty.
1699 // Otherwise, it should fallback to other methods, like the title attrib ute.
1700 const AtomicString& alt = getAttribute(altAttr);
1701 if (!alt.isNull())
1702 return alt;
1703 }
1704
1705 // An element's descriptive text is comprised of deprecatedTitle() (what's v isible on the screen) and deprecatedAccessibilityDescription() (other descriptiv e text).
1706 // Both are used to generate what a screen reader speaks.
1707 // If this point is reached (i.e. there's no accessibilityDescription) and t here's no deprecatedTitle(), we should fallback to using the title attribute.
1708 // The title attribute is normally used as help text (because it is a toolti p), but if there is nothing else available, this should be used (according to AR IA).
1709 if (deprecatedTitle(TextUnderElementAny).isEmpty())
1710 return getAttribute(titleAttr);
1711
1712 if (roleValue() == FigureRole) {
1713 AXObject* figcaption = findChildWithTagName(figcaptionTag);
1714 if (figcaption)
1715 return figcaption->deprecatedAccessibilityDescription();
1716 }
1717
1718 return String();
1719 }
1720
1721 String AXNodeObject::deprecatedTitle(TextUnderElementMode mode) const
1722 {
1723 Node* node = this->node();
1724 if (!node)
1725 return String();
1726
1727 bool isInputElement = isHTMLInputElement(*node);
1728 if (isInputElement) {
1729 HTMLInputElement& input = toHTMLInputElement(*node);
1730 if (input.isTextButton())
1731 return input.valueWithDefault();
1732 }
1733
1734 if (isInputElement || AXObject::isARIAInput(ariaRoleAttribute()) || isContro l()) {
1735 HTMLLabelElement* label = labelForElement(toElement(node));
1736 if (label && !deprecatedExposesTitleUIElement())
1737 return label->innerText();
1738 }
1739
1740 // If this node isn't laid out, there's no inner text we can extract from a select element.
1741 if (!isAXLayoutObject() && isHTMLSelectElement(*node))
1742 return String();
1743
1744 switch (roleValue()) {
1745 case PopUpButtonRole:
1746 // Native popup buttons should not use their button children's text as a title. That value is retrieved through stringValue().
1747 if (isHTMLSelectElement(*node))
1748 return String();
1749 case ButtonRole:
1750 case ToggleButtonRole:
1751 case CheckBoxRole:
1752 case LineBreakRole:
1753 case ListBoxOptionRole:
1754 case ListItemRole:
1755 case MenuButtonRole:
1756 case MenuItemRole:
1757 case MenuItemCheckBoxRole:
1758 case MenuItemRadioRole:
1759 case RadioButtonRole:
1760 case SwitchRole:
1761 case TabRole:
1762 return deprecatedTextUnderElement(mode);
1763 // SVGRoots should not use the text under itself as a title. That could incl ude the text of objects like <text>.
1764 case SVGRootRole:
1765 return String();
1766 case FigureRole: {
1767 AXObject* figcaption = findChildWithTagName(figcaptionTag);
1768 if (figcaption)
1769 return figcaption->deprecatedTextUnderElement();
1770 }
1771 default:
1772 break;
1773 }
1774
1775 if (isHeading() || isLink())
1776 return deprecatedTextUnderElement(mode);
1777
1778 // If it's focusable but it's not content editable or a known control type, then it will appear to
1779 // the user as a single atomic object, so we should use its text as the defa ult title.
1780 if (isGenericFocusableElement())
1781 return deprecatedTextUnderElement(mode);
1782
1783 return String();
1784 }
1785
1786 String AXNodeObject::deprecatedHelpText() const
1787 {
1788 Node* node = this->node();
1789 if (!node)
1790 return String();
1791
1792 const AtomicString& ariaHelp = getAttribute(aria_helpAttr);
1793 if (!ariaHelp.isEmpty())
1794 return ariaHelp;
1795
1796 String describedBy = ariaDescribedByAttribute();
1797 if (!describedBy.isEmpty())
1798 return describedBy;
1799
1800 String description = deprecatedAccessibilityDescription();
1801 for (Node* curr = node; curr; curr = curr->parentNode()) {
1802 if (curr->isHTMLElement()) {
1803 const AtomicString& summary = toElement(curr)->getAttribute(summaryA ttr);
1804 if (!summary.isEmpty())
1805 return summary;
1806
1807 // The title attribute should be used as help text unless it is alre ady being used as descriptive text.
1808 const AtomicString& title = toElement(curr)->getAttribute(titleAttr) ;
1809 if (!title.isEmpty() && description != title)
1810 return title;
1811 }
1812
1813 // Only take help text from an ancestor element if its a group or an unk nown role. If help was
1814 // added to those kinds of elements, it is likely it was meant for a chi ld element.
1815 AXObject* axObj = axObjectCache().getOrCreate(curr);
1816 if (axObj) {
1817 AccessibilityRole role = axObj->roleValue();
1818 if (role != GroupRole && role != UnknownRole)
1819 break;
1820 }
1821 }
1822
1823 return String();
1824 }
1825
1826 String AXNodeObject::computedName() const
1827 {
1828 String title = this->deprecatedTitle(TextUnderElementAll);
1829
1830 String titleUIText;
1831 if (title.isEmpty()) {
1832 AXObject* titleUIElement = this->deprecatedTitleUIElement();
1833 if (titleUIElement) {
1834 titleUIText = titleUIElement->deprecatedTextUnderElement();
1835 if (!titleUIText.isEmpty())
1836 return titleUIText;
1837 }
1838 }
1839
1840 String description = deprecatedAccessibilityDescription();
1841 if (!description.isEmpty())
1842 return description;
1843
1844 if (!title.isEmpty())
1845 return title;
1846
1847 String placeholder;
1848 if (isHTMLInputElement(node())) {
1849 HTMLInputElement* element = toHTMLInputElement(node());
1850 placeholder = element->strippedPlaceholder();
1851 if (!placeholder.isEmpty())
1852 return placeholder;
1853 }
1854
1855 return String();
1856 }
1857
1858 // 1495 //
1859 // New AX name calculation. 1496 // New AX name calculation.
1860 // 1497 //
1861 1498
1862 String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver sal, AXObjectSet& visited, AXNameFrom& nameFrom, AXRelatedObjectVector* relatedO bjects, NameSources* nameSources) const 1499 String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver sal, AXObjectSet& visited, AXNameFrom& nameFrom, AXRelatedObjectVector* relatedO bjects, NameSources* nameSources) const
1863 { 1500 {
1864 // If nameSources is non-null, relatedObjects is used in filling it in, so i t must be non-null as well. 1501 // If nameSources is non-null, relatedObjects is used in filling it in, so i t must be non-null as well.
1865 if (nameSources) 1502 if (nameSources)
1866 ASSERT(relatedObjects); 1503 ASSERT(relatedObjects);
1867 1504
1868 bool alreadyVisited = visited.contains(this);
1869 bool foundTextAlternative = false; 1505 bool foundTextAlternative = false;
1870 visited.add(this);
1871 String textAlternative;
1872 1506
1873 if (!node() && !layoutObject()) 1507 if (!node() && !layoutObject())
1874 return String(); 1508 return String();
1875 1509
1876 // Step 2A from: http://www.w3.org/TR/accname-aam-1.1 1510 String textAlternative = ariaTextAlternative(recursive, inAriaLabelledByTrav ersal, visited, nameFrom, relatedObjects, nameSources, &foundTextAlternative);
1877 if (!recursive && layoutObject() 1511 if (foundTextAlternative && !nameSources)
1878 && layoutObject()->style()->visibility() != VISIBLE 1512 return textAlternative;
1879 && !equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) {
1880 return String();
1881 }
1882
1883 // Step 2B from: http://www.w3.org/TR/accname-aam-1.1
1884 if (!inAriaLabelledByTraversal && !alreadyVisited) {
1885 const QualifiedName& attr = hasAttribute(aria_labeledbyAttr) && !hasAttr ibute(aria_labelledbyAttr) ? aria_labeledbyAttr : aria_labelledbyAttr;
1886 nameFrom = AXNameFromRelatedElement;
1887 if (nameSources) {
1888 nameSources->append(NameSource(foundTextAlternative, attr));
1889 nameSources->last().type = nameFrom;
1890 }
1891
1892 const AtomicString& ariaLabelledby = getAttribute(attr);
1893 if (!ariaLabelledby.isNull()) {
1894 if (nameSources)
1895 nameSources->last().attributeValue = ariaLabelledby;
1896
1897 textAlternative = textFromAriaLabelledby(visited, relatedObjects);
1898
1899 if (!textAlternative.isNull()) {
1900 if (nameSources) {
1901 NameSource& source = nameSources->last();
1902 source.type = nameFrom;
1903 source.relatedObjects = *relatedObjects;
1904 source.text = textAlternative;
1905 foundTextAlternative = true;
1906 } else {
1907 return textAlternative;
1908 }
1909 } else if (nameSources) {
1910 nameSources->last().invalid = true;
1911 }
1912 }
1913 }
1914
1915 // Step 2C from: http://www.w3.org/TR/accname-aam-1.1
1916 nameFrom = AXNameFromAttribute;
1917 if (nameSources) {
1918 nameSources->append(NameSource(foundTextAlternative, aria_labelAttr));
1919 nameSources->last().type = nameFrom;
1920 }
1921 const AtomicString& ariaLabel = getAttribute(aria_labelAttr);
1922 if (!ariaLabel.isEmpty()) {
1923 textAlternative = ariaLabel;
1924
1925 if (nameSources) {
1926 NameSource& source = nameSources->last();
1927 source.text = textAlternative;
1928 source.attributeValue = ariaLabel;
1929 foundTextAlternative = true;
1930 } else {
1931 return textAlternative;
1932 }
1933 }
1934 1513
1935 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1 1514 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1
1936 textAlternative = nativeTextAlternative(visited, nameFrom, relatedObjects, n ameSources, &foundTextAlternative); 1515 textAlternative = nativeTextAlternative(visited, nameFrom, relatedObjects, n ameSources, &foundTextAlternative);
1937 if (!textAlternative.isNull() && !nameSources) 1516 if (!textAlternative.isEmpty() && !nameSources)
1938 return textAlternative; 1517 return textAlternative;
1939 1518
1940 // Step 2E from: http://www.w3.org/TR/accname-aam-1.1 1519 // Step 2E from: http://www.w3.org/TR/accname-aam-1.1
1941 if (recursive && !inAriaLabelledByTraversal && isControl()) { 1520 if (recursive && !inAriaLabelledByTraversal && isControl()) {
1942 // No need to set any name source info in a recursive call. 1521 // No need to set any name source info in a recursive call.
1943 if (isRange()) { 1522 if (isRange()) {
1944 const AtomicString& ariaValuetext = getAttribute(aria_valuetextAttr) ; 1523 const AtomicString& ariaValuetext = getAttribute(aria_valuetextAttr) ;
1945 if (!ariaValuetext.isNull()) 1524 if (!ariaValuetext.isNull())
1946 return ariaValuetext.string(); 1525 return ariaValuetext.string();
1947 return String::number(valueForRange()); 1526 return String::number(valueForRange());
1948 } 1527 }
1949 1528
1950 return stringValueOfControl(); 1529 return stringValue();
1951 } 1530 }
1952 1531
1953 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 1532 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1
1954 if (recursive || nameFromContents()) { 1533 if (recursive || nameFromContents()) {
1955 nameFrom = AXNameFromContents; 1534 nameFrom = AXNameFromContents;
1956 if (nameSources) { 1535 if (nameSources) {
1957 nameSources->append(NameSource(foundTextAlternative)); 1536 nameSources->append(NameSource(foundTextAlternative));
1958 nameSources->last().type = nameFrom; 1537 nameSources->last().type = nameFrom;
1959 } 1538 }
1960 1539
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
2030 } 1609 }
2031 1610
2032 String result = recursiveTextAlternative(*child, false, visited); 1611 String result = recursiveTextAlternative(*child, false, visited);
2033 accumulatedText.append(result); 1612 accumulatedText.append(result);
2034 previous = child; 1613 previous = child;
2035 } 1614 }
2036 1615
2037 return accumulatedText.toString(); 1616 return accumulatedText.toString();
2038 } 1617 }
2039 1618
2040 String AXNodeObject::textFromElements(bool inAriaLabelledbyTraversal, AXObjectSe t& visited, WillBeHeapVector<RawPtrWillBeMember<Element>>& elements, AXRelatedOb jectVector* relatedObjects) const
2041 {
2042 StringBuilder accumulatedText;
2043 bool foundValidElement = false;
2044 AXRelatedObjectVector localRelatedObjects;
2045
2046 for (const auto& element : elements) {
2047 AXObject* axElement = axObjectCache().getOrCreate(element);
2048 if (axElement) {
2049 foundValidElement = true;
2050
2051 String result = recursiveTextAlternative(*axElement, inAriaLabelledb yTraversal, visited);
2052 localRelatedObjects.append(new NameSourceRelatedObject(axElement, re sult));
2053 if (!result.isEmpty()) {
2054 if (!accumulatedText.isEmpty())
2055 accumulatedText.append(" ");
2056 accumulatedText.append(result);
2057 }
2058 }
2059 }
2060 if (!foundValidElement)
2061 return String();
2062 if (relatedObjects)
2063 *relatedObjects = localRelatedObjects;
2064 return accumulatedText.toString();
2065 }
2066
2067 String AXNodeObject::textFromAriaLabelledby(AXObjectSet& visited, AXRelatedObjec tVector* relatedObjects) const
2068 {
2069 WillBeHeapVector<RawPtrWillBeMember<Element>> elements;
2070 ariaLabelledbyElements(elements);
2071 return textFromElements(true, visited, elements, relatedObjects);
2072 }
2073
2074 String AXNodeObject::textFromAriaDescribedby(AXRelatedObjectVector* relatedObjec ts) const
2075 {
2076 AXObjectSet visited;
2077 WillBeHeapVector<RawPtrWillBeMember<Element>> elements;
2078 elementsFromAttribute(elements, aria_describedbyAttr);
2079 return textFromElements(true, visited, elements, relatedObjects);
2080 }
2081
2082 LayoutRect AXNodeObject::elementRect() const 1619 LayoutRect AXNodeObject::elementRect() const
2083 { 1620 {
2084 // First check if it has a custom rect, for example if this element is tied to a canvas path. 1621 // First check if it has a custom rect, for example if this element is tied to a canvas path.
2085 if (!m_explicitElementRect.isEmpty()) 1622 if (!m_explicitElementRect.isEmpty())
2086 return m_explicitElementRect; 1623 return m_explicitElementRect;
2087 1624
2088 // FIXME: If there are a lot of elements in the canvas, it will be inefficie nt. 1625 // FIXME: If there are a lot of elements in the canvas, it will be inefficie nt.
2089 // We can avoid the inefficient calculations by using AXComputedObjectAttrib uteCache. 1626 // We can avoid the inefficient calculations by using AXComputedObjectAttrib uteCache.
2090 if (node()->parentElement()->isInCanvasSubtree()) { 1627 if (node()->parentElement()->isInCanvasSubtree()) {
2091 LayoutRect rect; 1628 LayoutRect rect;
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after
2503 { 2040 {
2504 if (!hasAttribute(aria_ownsAttr)) 2041 if (!hasAttribute(aria_ownsAttr))
2505 return; 2042 return;
2506 2043
2507 Vector<String> idVector; 2044 Vector<String> idVector;
2508 tokenVectorFromAttribute(idVector, aria_ownsAttr); 2045 tokenVectorFromAttribute(idVector, aria_ownsAttr);
2509 2046
2510 axObjectCache().updateAriaOwns(this, idVector, ownedChildren); 2047 axObjectCache().updateAriaOwns(this, idVector, ownedChildren);
2511 } 2048 }
2512 2049
2513 String AXNodeObject::deprecatedAlternativeTextForWebArea() const
2514 {
2515 // The WebArea description should follow this order:
2516 // aria-label on the <html>
2517 // title on the <html>
2518 // <title> inside the <head> (of it was set through JS)
2519 // name on the <html>
2520 // For iframes:
2521 // aria-label on the <iframe>
2522 // title on the <iframe>
2523 // name on the <iframe>
2524
2525 Document* document = this->document();
2526 if (!document)
2527 return String();
2528
2529 // Check if the HTML element has an aria-label for the webpage.
2530 if (Element* documentElement = document->documentElement()) {
2531 const AtomicString& ariaLabel = documentElement->getAttribute(aria_label Attr);
2532 if (!ariaLabel.isEmpty())
2533 return ariaLabel;
2534 }
2535
2536 if (HTMLFrameOwnerElement* owner = document->ownerElement()) {
2537 if (isHTMLFrameElementBase(*owner)) {
2538 const AtomicString& title = owner->getAttribute(titleAttr);
2539 if (!title.isEmpty())
2540 return title;
2541 }
2542 return owner->getNameAttribute();
2543 }
2544
2545 String documentTitle = document->title();
2546 if (!documentTitle.isEmpty())
2547 return documentTitle;
2548
2549 if (HTMLElement* body = document->body())
2550 return body->getNameAttribute();
2551
2552 return String();
2553 }
2554
2555 void AXNodeObject::deprecatedAlternativeText(HeapVector<Member<AccessibilityText >>& textOrder) const
2556 {
2557 if (isWebArea()) {
2558 String webAreaText = deprecatedAlternativeTextForWebArea();
2559 if (!webAreaText.isEmpty())
2560 textOrder.append(AccessibilityText::create(webAreaText, AlternativeT ext));
2561 return;
2562 }
2563
2564 deprecatedAriaLabelledbyText(textOrder);
2565
2566 const AtomicString& ariaLabel = getAttribute(aria_labelAttr);
2567 if (!ariaLabel.isEmpty())
2568 textOrder.append(AccessibilityText::create(ariaLabel, AlternativeText));
2569
2570 if (isImage() || isInputImage() || isNativeImage() || isCanvas()) {
2571 // Images should use alt as long as the attribute is present, even if em pty.
2572 // Otherwise, it should fallback to other methods, like the title attrib ute.
2573 const AtomicString& alt = getAttribute(altAttr);
2574 if (!alt.isNull())
2575 textOrder.append(AccessibilityText::create(alt, AlternativeText));
2576 }
2577 }
2578
2579 void AXNodeObject::deprecatedAriaLabelledbyText(HeapVector<Member<AccessibilityT ext>>& textOrder) const
2580 {
2581 String ariaLabelledby = ariaLabelledbyAttribute();
2582 if (!ariaLabelledby.isEmpty()) {
2583 WillBeHeapVector<RawPtrWillBeMember<Element>> elements;
2584 ariaLabelledbyElements(elements);
2585
2586 for (const auto& element : elements) {
2587 AXObject* axElement = axObjectCache().getOrCreate(element);
2588 textOrder.append(AccessibilityText::create(ariaLabelledby, Alternati veText, axElement));
2589 }
2590 }
2591 }
2592
2593 // Based on http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible- name-and-description-calculation 2050 // Based on http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible- name-and-description-calculation
2594 String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam eFrom, AXRelatedObjectVector* relatedObjects, NameSources* nameSources, bool* fo undTextAlternative) const 2051 String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam eFrom, AXRelatedObjectVector* relatedObjects, NameSources* nameSources, bool* fo undTextAlternative) const
2595 { 2052 {
2596 if (!node()) 2053 if (!node())
2597 return String(); 2054 return String();
2598 2055
2599 // If nameSources is non-null, relatedObjects is used in filling it in, so i t must be non-null as well. 2056 // If nameSources is non-null, relatedObjects is used in filling it in, so i t must be non-null as well.
2600 if (nameSources) 2057 if (nameSources)
2601 ASSERT(relatedObjects); 2058 ASSERT(relatedObjects);
2602 2059
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
2703 if (nameSources) { 2160 if (nameSources) {
2704 NameSource& source = nameSources->last(); 2161 NameSource& source = nameSources->last();
2705 source.text = textAlternative; 2162 source.text = textAlternative;
2706 *foundTextAlternative = true; 2163 *foundTextAlternative = true;
2707 } else { 2164 } else {
2708 return textAlternative; 2165 return textAlternative;
2709 } 2166 }
2710 } 2167 }
2711 2168
2712 // localised default value ("Submit") 2169 // localised default value ("Submit")
2713 nameFrom = AXNameFromAttribute; 2170 nameFrom = AXNameFromValue;
2714 textAlternative = inputElement->locale().queryString(WebLocalizedString: :SubmitButtonDefaultLabel); 2171 textAlternative = inputElement->locale().queryString(WebLocalizedString: :SubmitButtonDefaultLabel);
2715 if (nameSources) { 2172 if (nameSources) {
2716 nameSources->append(NameSource(*foundTextAlternative, typeAttr)); 2173 nameSources->append(NameSource(*foundTextAlternative, typeAttr));
2717 NameSource& source = nameSources->last(); 2174 NameSource& source = nameSources->last();
2718 source.attributeValue = inputElement->getAttribute(typeAttr); 2175 source.attributeValue = inputElement->getAttribute(typeAttr);
2719 source.type = nameFrom; 2176 source.type = nameFrom;
2720 source.text = textAlternative; 2177 source.text = textAlternative;
2721 *foundTextAlternative = true; 2178 *foundTextAlternative = true;
2722 } else { 2179 } else {
2723 return textAlternative; 2180 return textAlternative;
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
2892 source.relatedObjects = *relatedObjects; 2349 source.relatedObjects = *relatedObjects;
2893 source.text = textAlternative; 2350 source.text = textAlternative;
2894 *foundTextAlternative = true; 2351 *foundTextAlternative = true;
2895 } else { 2352 } else {
2896 return textAlternative; 2353 return textAlternative;
2897 } 2354 }
2898 } 2355 }
2899 } 2356 }
2900 } 2357 }
2901 2358
2359 // Document.
2360 if (isWebArea()) {
2361 Document* document = this->document();
2362 if (document) {
2363 nameFrom = AXNameFromAttribute;
2364 if (nameSources) {
2365 nameSources->append(NameSource(foundTextAlternative, aria_labelA ttr));
2366 nameSources->last().type = nameFrom;
2367 }
2368 if (Element* documentElement = document->documentElement()) {
2369 const AtomicString& ariaLabel = documentElement->getAttribute(ar ia_labelAttr);
2370 if (!ariaLabel.isEmpty()) {
2371 textAlternative = ariaLabel;
2372
2373 if (nameSources) {
2374 NameSource& source = nameSources->last();
2375 source.text = textAlternative;
2376 source.attributeValue = ariaLabel;
2377 *foundTextAlternative = true;
2378 } else {
2379 return textAlternative;
2380 }
2381 }
2382 }
2383
2384 nameFrom = AXNameFromRelatedElement;
2385 if (nameSources) {
2386 nameSources->append(NameSource(*foundTextAlternative));
2387 nameSources->last().type = nameFrom;
2388 nameSources->last().nativeSource = AXTextFromNativeHTMLTitleElem ent;
2389 }
2390
2391 textAlternative = document->title();
2392
2393 Element* titleElement = document->titleElement();
2394 AXObject* titleAXObject = axObjectCache().getOrCreate(titleElement);
2395 if (titleAXObject) {
2396 if (relatedObjects) {
2397 localRelatedObjects.append(new NameSourceRelatedObject(title AXObject, textAlternative));
2398 *relatedObjects = localRelatedObjects;
2399 localRelatedObjects.clear();
2400 }
2401
2402 if (nameSources) {
2403 NameSource& source = nameSources->last();
2404 source.relatedObjects = *relatedObjects;
2405 source.text = textAlternative;
2406 *foundTextAlternative = true;
2407 } else {
2408 return textAlternative;
2409 }
2410 }
2411 }
2412 }
2413
2902 return textAlternative; 2414 return textAlternative;
2903 } 2415 }
2904 2416
2905 String AXNodeObject::description(AXNameFrom nameFrom, AXDescriptionFrom& descrip tionFrom, AXObjectVector* descriptionObjects) const 2417 String AXNodeObject::description(AXNameFrom nameFrom, AXDescriptionFrom& descrip tionFrom, AXObjectVector* descriptionObjects) const
2906 { 2418 {
2907 AXRelatedObjectVector relatedObjects; 2419 AXRelatedObjectVector relatedObjects;
2908 String result = description(nameFrom, descriptionFrom, nullptr, &relatedObje cts); 2420 String result = description(nameFrom, descriptionFrom, nullptr, &relatedObje cts);
2909 if (descriptionObjects) { 2421 if (descriptionObjects) {
2910 descriptionObjects->clear(); 2422 descriptionObjects->clear();
2911 for (size_t i = 0; i < relatedObjects.size(); i++) 2423 for (size_t i = 0; i < relatedObjects.size(); i++)
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
3106 if (!descriptionSource.relatedObjects.isEmpty()) 2618 if (!descriptionSource.relatedObjects.isEmpty())
3107 *relatedObjects = descriptionSource.relatedObjects; 2619 *relatedObjects = descriptionSource.relatedObjects;
3108 return descriptionSource.text; 2620 return descriptionSource.text;
3109 } 2621 }
3110 } 2622 }
3111 } 2623 }
3112 2624
3113 return String(); 2625 return String();
3114 } 2626 }
3115 2627
2628 String AXNodeObject::placeholder(AXNameFrom nameFrom, AXDescriptionFrom descript ionFrom) const
2629 {
2630 if (nameFrom == AXNameFromPlaceholder)
2631 return String();
2632
2633 if (descriptionFrom == AXDescriptionFromPlaceholder)
2634 return String();
2635
2636 if (!node())
2637 return String();
2638
2639 String placeholder;
2640 if (isHTMLInputElement(*node())) {
2641 HTMLInputElement* inputElement = toHTMLInputElement(node());
2642 placeholder = inputElement->strippedPlaceholder();
2643 } else if (isHTMLTextAreaElement(*node())) {
2644 HTMLTextAreaElement* textAreaElement = toHTMLTextAreaElement(node());
2645 placeholder = textAreaElement->strippedPlaceholder();
2646 }
2647 return placeholder;
2648 }
2649
3116 DEFINE_TRACE(AXNodeObject) 2650 DEFINE_TRACE(AXNodeObject)
3117 { 2651 {
3118 visitor->trace(m_node); 2652 visitor->trace(m_node);
3119 AXObject::trace(visitor); 2653 AXObject::trace(visitor);
3120 } 2654 }
3121 2655
3122 } // namespace blin 2656 } // namespace blin
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698