Changeset 207314 in webkit
- Timestamp:
- Oct 13, 2016 3:52:17 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r207313 r207314 1 2016-10-13 Nan Wang <n_wang@apple.com> 2 3 AX: [Mac] better accessibility support for Summary elements 4 https://bugs.webkit.org/show_bug.cgi?id=163367 5 <rdar://problem/28745010> 6 7 Reviewed by Chris Fleizach. 8 9 * accessibility/mac/details-summary-expected.txt: 10 * accessibility/mac/details-summary-role-description-expected.txt: 11 * accessibility/mac/details-summary-role-description.html: 12 * accessibility/mac/details-summary.html: 13 1 14 2016-10-13 Ryan Haddad <ryanhaddad@apple.com> 2 15 -
trunk/LayoutTests/accessibility/mac/details-summary-expected.txt
r187799 r207314 11 11 PASS details1.subrole is 'AXSubrole: AXDetails' 12 12 PASS details1.isExpanded is true 13 PASS details1.childAtIndex(0).role is 'AXRole: AXGroup' 14 PASS details1.childAtIndex(0).subrole is 'AXSubrole: AXSummary' 13 PASS summary1.role is 'AXRole: AXButton' 14 PASS summary1.subrole is 'AXSubrole: AXSummary' 15 PASS summary1.title is 'AXTitle: Some open info' 15 16 PASS details1.isAttributeSettable('AXExpanded') is true 16 17 PASS details1.isExpanded is false 18 PASS summary1.isExpanded is false 17 19 PASS details1.isExpanded is false 20 PASS summary1.isExpanded is false 18 21 PASS details1.isExpanded is true 22 PASS summary1.isExpanded is true 19 23 PASS details1.isExpanded is true 24 PASS summary1.isExpanded is true 20 25 PASS details2.subrole is 'AXSubrole: AXDetails' 21 26 PASS details2.isExpanded is false -
trunk/LayoutTests/accessibility/mac/details-summary-role-description-expected.txt
r206921 r207314 7 7 8 8 9 PASS summary.role is 'AXRole: AX Group'9 PASS summary.role is 'AXRole: AXButton' 10 10 PASS details.role is 'AXRole: AXGroup' 11 11 PASS summary.subrole is 'AXSubrole: AXSummary' -
trunk/LayoutTests/accessibility/mac/details-summary-role-description.html
r206921 r207314 20 20 var details = accessibilityController.accessibleElementById("details"); 21 21 22 shouldBe("summary.role", "'AXRole: AX Group'");22 shouldBe("summary.role", "'AXRole: AXButton'"); 23 23 shouldBe("details.role", "'AXRole: AXGroup'"); 24 24 shouldBe("summary.subrole", "'AXSubrole: AXSummary'"); -
trunk/LayoutTests/accessibility/mac/details-summary.html
r187799 r207314 7 7 8 8 <details open id="details1"> 9 <summary >Some open info</summary>9 <summary id="summary1">Some open info</summary> 10 10 <p>Details about the open topic.</p> 11 11 </details> … … 40 40 41 41 var details1 = accessibilityController.accessibleElementById("details1"); 42 var summary1 = accessibilityController.accessibleElementById("summary1"); 42 43 shouldBe("details1.role", "'AXRole: AXGroup'"); 43 44 shouldBe("details1.subrole", "'AXSubrole: AXDetails'"); 44 45 shouldBeTrue("details1.isExpanded"); 45 shouldBe("details1.childAtIndex(0).role", "'AXRole: AXGroup'"); 46 shouldBe("details1.childAtIndex(0).subrole", "'AXSubrole: AXSummary'"); 46 shouldBe("summary1.role", "'AXRole: AXButton'"); 47 shouldBe("summary1.subrole", "'AXSubrole: AXSummary'"); 48 shouldBe("summary1.title", "'AXTitle: Some open info'"); 47 49 shouldBeTrue("details1.isAttributeSettable('AXExpanded')"); 48 50 … … 50 52 details1.setBoolAttributeValue("AXExpanded", false); 51 53 details1 = accessibilityController.accessibleElementById("details1"); 54 summary1 = accessibilityController.accessibleElementById("summary1"); 52 55 shouldBeFalse("details1.isExpanded"); 56 shouldBeFalse("summary1.isExpanded"); 53 57 54 58 // Give it the same value to make sure we don't expand. 55 59 details1.setBoolAttributeValue("AXExpanded", false); 56 60 details1 = accessibilityController.accessibleElementById("details1"); 61 summary1 = accessibilityController.accessibleElementById("summary1"); 57 62 shouldBeFalse("details1.isExpanded"); 63 shouldBeFalse("summary1.isExpanded"); 58 64 59 65 // Set to expand again. 60 66 details1.setBoolAttributeValue("AXExpanded", true); 61 67 details1 = accessibilityController.accessibleElementById("details1"); 68 summary1 = accessibilityController.accessibleElementById("summary1"); 62 69 shouldBeTrue("details1.isExpanded"); 70 shouldBeTrue("summary1.isExpanded"); 63 71 64 72 // And duplicate the true state to make sure it doesn't toggle off. 65 73 details1.setBoolAttributeValue("AXExpanded", true); 66 74 details1 = accessibilityController.accessibleElementById("details1"); 75 summary1 = accessibilityController.accessibleElementById("summary1"); 67 76 shouldBeTrue("details1.isExpanded"); 77 shouldBeTrue("summary1.isExpanded"); 68 78 69 79 var details2 = accessibilityController.accessibleElementById("details2"); -
trunk/Source/WebCore/ChangeLog
r207310 r207314 1 2016-10-13 Nan Wang <n_wang@apple.com> 2 3 AX: [Mac] better accessibility support for Summary elements 4 https://bugs.webkit.org/show_bug.cgi?id=163367 5 <rdar://problem/28745010> 6 7 Reviewed by Chris Fleizach. 8 9 Exposed summary elements as AXButton and used the text node's content 10 as AXTitle. Also exposed the details parent's expanded status on the summary 11 element, so that users would see it as a collapsed/expanded button. 12 13 Changes are covered in the modified tests. 14 15 * accessibility/AccessibilityObject.cpp: 16 (WebCore::AccessibilityObject::parentObjectUnignored): 17 (WebCore::AccessibilityObject::scrollViewAncestor): 18 (WebCore::AccessibilityObject::headingElementForNode): 19 (WebCore::AccessibilityObject::matchedParent): 20 (WebCore::AccessibilityObject::isDescendantOfObject): 21 (WebCore::AccessibilityObject::isInsideARIALiveRegion): 22 (WebCore::AccessibilityObject::elementAccessibilityHitTest): 23 (WebCore::AccessibilityObject::isExpanded): 24 (WebCore::AccessibilityObject::isARIAHidden): 25 (WebCore::AccessibilityObject::focusableAncestor): 26 (WebCore::AccessibilityObject::editableAncestor): 27 * accessibility/AccessibilityObject.h: 28 (WebCore::AccessibilityObject::isSummary): 29 * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm: 30 (-[WebAccessibilityObjectWrapper _accessibilityListAncestor]): 31 (-[WebAccessibilityObjectWrapper _accessibilityLandmarkAncestor]): 32 (-[WebAccessibilityObjectWrapper _accessibilityTableAncestor]): 33 (-[WebAccessibilityObjectWrapper _accessibilityFieldsetAncestor]): 34 (-[WebAccessibilityObjectWrapper tableCellParent]): 35 (-[WebAccessibilityObjectWrapper tableParent]): 36 (-[WebAccessibilityObjectWrapper convertPointToScreenSpace:]): 37 (-[WebAccessibilityObjectWrapper convertRectToScreenSpace:]): 38 (-[WebAccessibilityObjectWrapper detailParentForSummaryObject:]): 39 (-[WebAccessibilityObjectWrapper detailParentForObject:]): 40 (matchedParent): Deleted. 41 * accessibility/mac/WebAccessibilityObjectWrapperMac.mm: 42 (-[WebAccessibilityObjectWrapper additionalAccessibilityAttributeNames]): 43 (createAccessibilityRoleMap): 44 (-[WebAccessibilityObjectWrapper roleDescription]): 45 (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]): 46 1 47 2016-10-13 Zalan Bujtas <zalan@apple.com> 2 48 -
trunk/Source/WebCore/accessibility/AccessibilityObject.cpp
r207035 r207314 458 458 AccessibilityObject* AccessibilityObject::parentObjectUnignored() const 459 459 { 460 AccessibilityObject* parent; 461 for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) { 462 } 463 464 return parent; 460 return const_cast<AccessibilityObject*>(AccessibilityObject::matchedParent(*this, false, [] (const AccessibilityObject& object) { 461 return !object.accessibilityIsIgnored(); 462 })); 465 463 } 466 464 … … 1697 1695 ScrollView* AccessibilityObject::scrollViewAncestor() const 1698 1696 { 1699 for (const AccessibilityObject* scrollParent = this; scrollParent; scrollParent = scrollParent->parentObject()) {1700 if (is<AccessibilityScrollView>(*scrollParent))1701 return downcast<AccessibilityScrollView>(*scrollParent).scrollView();1702 }1697 if (const AccessibilityObject* scrollParent = AccessibilityObject::matchedParent(*this, true, [] (const AccessibilityObject& object) { 1698 return is<AccessibilityScrollView>(object); 1699 })) 1700 return downcast<AccessibilityScrollView>(*scrollParent).scrollView(); 1703 1701 1704 1702 return nullptr; … … 1791 1789 1792 1790 AccessibilityObject* axObject = renderObject->document().axObjectCache()->getOrCreate(renderObject); 1793 for (; axObject && axObject->roleValue() != HeadingRole; axObject = axObject->parentObject()) { } 1794 1795 return axObject; 1791 1792 return const_cast<AccessibilityObject*>(AccessibilityObject::matchedParent(*axObject, true, [] (const AccessibilityObject& object) { 1793 return object.roleValue() == HeadingRole; 1794 })); 1795 } 1796 1797 const AccessibilityObject* AccessibilityObject::matchedParent(const AccessibilityObject& object, bool includeSelf, const std::function<bool(const AccessibilityObject&)>& matches) 1798 { 1799 const AccessibilityObject* parent = includeSelf ? &object : object.parentObject(); 1800 for (; parent; parent = parent->parentObject()) { 1801 if (matches(*parent)) 1802 return parent; 1803 } 1804 return nullptr; 1796 1805 } 1797 1806 … … 2035 2044 if (!axObject || !axObject->hasChildren()) 2036 2045 return false; 2037 2038 for (const AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) { 2039 if (parent == axObject) 2040 return true; 2041 } 2042 return false; 2046 2047 return AccessibilityObject::matchedParent(*this, false, [axObject] (const AccessibilityObject& object) { 2048 return &object == axObject; 2049 }) != nullptr; 2043 2050 } 2044 2051 … … 2308 2315 return true; 2309 2316 2310 for (AccessibilityObject* axParent = parentObject(); axParent; axParent = axParent->parentObject()) { 2311 if (axParent->supportsARIALiveRegion()) 2312 return true; 2313 } 2314 2315 return false; 2317 return AccessibilityObject::matchedParent(*this, false, [] (const AccessibilityObject& object) { 2318 return object.supportsARIALiveRegion(); 2319 }) != nullptr; 2316 2320 } 2317 2321 … … 2365 2369 } 2366 2370 2367 return const_cast<AccessibilityObject*>(this); 2371 return const_cast<AccessibilityObject*>(this); 2368 2372 } 2369 2373 … … 2478 2482 if (is<HTMLDetailsElement>(node())) 2479 2483 return downcast<HTMLDetailsElement>(node())->isOpen(); 2484 2485 // Summary element should use its details parent's expanded status. 2486 if (isSummary()) { 2487 if (const AccessibilityObject* parent = AccessibilityObject::matchedParent(*this, false, [] (const AccessibilityObject& object) { 2488 return object.roleValue() == DetailsRole; 2489 })) 2490 return parent->isExpanded(); 2491 } 2480 2492 2481 2493 return false; … … 2935 2947 bool AccessibilityObject::isARIAHidden() const 2936 2948 { 2937 for (const AccessibilityObject* object = this; object; object = object->parentObject()) { 2938 if (equalLettersIgnoringASCIICase(object->getAttribute(aria_hiddenAttr), "true")) 2939 return true; 2940 } 2941 return false; 2949 return AccessibilityObject::matchedParent(*this, true, [] (const AccessibilityObject& object) { 2950 return equalLettersIgnoringASCIICase(object.getAttribute(aria_hiddenAttr), "true"); 2951 }) != nullptr; 2942 2952 } 2943 2953 … … 3036 3046 AccessibilityObject* AccessibilityObject::focusableAncestor() 3037 3047 { 3038 AccessibilityObject* potentialFocusableAncestor = this; 3039 while (potentialFocusableAncestor) { 3040 if (potentialFocusableAncestor->canSetFocusAttribute()) 3041 return potentialFocusableAncestor; 3042 potentialFocusableAncestor = potentialFocusableAncestor->parentObject(); 3043 } 3044 3045 return nullptr; 3048 return const_cast<AccessibilityObject*>(AccessibilityObject::matchedParent(*this, true, [] (const AccessibilityObject& object) { 3049 return object.canSetFocusAttribute(); 3050 })); 3046 3051 } 3047 3052 3048 3053 AccessibilityObject* AccessibilityObject::editableAncestor() 3049 3054 { 3050 AccessibilityObject* potentialEditableAncestor = this; 3051 while (potentialEditableAncestor) { 3052 if (potentialEditableAncestor->isTextControl()) 3053 return potentialEditableAncestor; 3054 potentialEditableAncestor = potentialEditableAncestor->parentObject(); 3055 } 3056 3057 return nullptr; 3055 return const_cast<AccessibilityObject*>(AccessibilityObject::matchedParent(*this, true, [] (const AccessibilityObject& object) { 3056 return object.isTextControl(); 3057 })); 3058 3058 } 3059 3059 -
trunk/Source/WebCore/accessibility/AccessibilityObject.h
r206943 r207314 562 562 bool isSuperscriptStyleGroup() const; 563 563 bool isFigure() const; 564 bool isSummary() const { return roleValue() == SummaryRole; } 564 565 565 566 virtual bool isChecked() const { return false; } … … 1063 1064 AccessibilityObject* highestEditableAncestor(); 1064 1065 1066 static const AccessibilityObject* matchedParent(const AccessibilityObject&, bool includeSelf, const std::function<bool(const AccessibilityObject&)>&); 1067 1065 1068 protected: 1066 1069 AXID m_id; -
trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm
r206190 r207314 132 132 } 133 133 134 template<typename MatchFunction>135 static AccessibilityObject* matchedParent(AccessibilityObject* object, bool includeSelf, const MatchFunction& matches)136 {137 if (!object)138 return nullptr;139 140 AccessibilityObject* parent = includeSelf ? object : object->parentObject();141 for (; parent; parent = parent->parentObject()) {142 if (matches(parent))143 return parent;144 }145 146 return nullptr;147 }148 149 150 134 #pragma mark Accessibility Text Marker 151 135 … … 550 534 - (AccessibilityObjectWrapper*)_accessibilityListAncestor 551 535 { 552 auto matchFunc = [] ( AccessibilityObject*object) {553 AccessibilityRole role = object ->roleValue();536 auto matchFunc = [] (const AccessibilityObject& object) { 537 AccessibilityRole role = object.roleValue(); 554 538 return role == ListRole || role == ListBoxRole; 555 539 }; 556 540 557 if ( AccessibilityObject* parent = matchedParent(m_object, false, matchFunc))541 if (const AccessibilityObject* parent = AccessibilityObject::matchedParent(*m_object, false, matchFunc)) 558 542 return parent->wrapper(); 559 543 return nil; … … 562 546 - (AccessibilityObjectWrapper*)_accessibilityLandmarkAncestor 563 547 { 564 auto matchFunc = [self] (AccessibilityObject* object) { 565 return [self _accessibilityIsLandmarkRole:object->roleValue()]; 566 }; 567 568 if (AccessibilityObject* parent = matchedParent(m_object, false, matchFunc)) 548 if (const AccessibilityObject* parent = AccessibilityObject::matchedParent(*m_object, false, [self] (const AccessibilityObject& object) { 549 return [self _accessibilityIsLandmarkRole:object.roleValue()]; 550 })) 569 551 return parent->wrapper(); 570 552 return nil; … … 573 555 - (AccessibilityObjectWrapper*)_accessibilityTableAncestor 574 556 { 575 auto matchFunc = [] (AccessibilityObject* object) { 576 return object->roleValue() == TableRole || object->roleValue() == GridRole; 577 }; 578 579 if (AccessibilityObject* parent = matchedParent(m_object, false, matchFunc)) 557 558 if (const AccessibilityObject* parent = AccessibilityObject::matchedParent(*m_object, false, [] (const AccessibilityObject& object) { 559 return object.roleValue() == TableRole || object.roleValue() == GridRole; 560 })) 580 561 return parent->wrapper(); 581 562 return nil; … … 584 565 - (AccessibilityObjectWrapper*)_accessibilityFieldsetAncestor 585 566 { 586 auto matchFunc = [] (AccessibilityObject* object) { 587 return object->isFieldset(); 588 }; 589 590 if (AccessibilityObject* parent = matchedParent(m_object, false, matchFunc)) 567 if (const AccessibilityObject* parent = AccessibilityObject::matchedParent(*m_object, false, [] (const AccessibilityObject& object) { 568 return object.isFieldset(); 569 })) 591 570 return parent->wrapper(); 592 571 return nil; … … 1042 1021 { 1043 1022 // Find if this element is in a table cell. 1044 auto matchFunc = [] (AccessibilityObject* object) { 1045 return object->isTableCell(); 1046 }; 1047 1048 if (AccessibilityObject* parent = matchedParent(m_object, true, matchFunc)) 1023 if (AccessibilityObject* parent = const_cast<AccessibilityObject*>(AccessibilityObject::matchedParent(*m_object, true, [] (const AccessibilityObject& object) { 1024 return object.isTableCell(); 1025 }))) 1049 1026 return static_cast<AccessibilityTableCell*>(parent); 1050 1027 return nil; … … 1054 1031 { 1055 1032 // Find if the parent table for the table cell. 1056 auto matchFunc = [] (AccessibilityObject* object) { 1057 return is<AccessibilityTable>(*object) && downcast<AccessibilityTable>(*object).isExposableThroughAccessibility(); 1058 }; 1059 1060 if (AccessibilityObject* parent = matchedParent(m_object, true, matchFunc)) 1033 if (AccessibilityObject* parent = const_cast<AccessibilityObject*>(AccessibilityObject::matchedParent(*m_object, true, [] (const AccessibilityObject& object) { 1034 return is<AccessibilityTable>(object) && downcast<AccessibilityTable>(object).isExposableThroughAccessibility(); 1035 }))) 1061 1036 return static_cast<AccessibilityTable*>(parent); 1062 1037 return nil; … … 1427 1402 else { 1428 1403 // Find the appropriate scroll view to use to convert the contents to the window. 1429 auto matchFunc = [] (AccessibilityObject* object) {1430 return is<AccessibilityScrollView>(*object);1431 };1432 1433 1404 ScrollView* scrollView = nullptr; 1434 AccessibilityObject* parent = matchedParent(m_object, false, matchFunc); 1405 const AccessibilityObject* parent = AccessibilityObject::matchedParent(*m_object, false, [] (const AccessibilityObject& object) { 1406 return is<AccessibilityScrollView>(object); 1407 }); 1435 1408 if (parent) 1436 1409 scrollView = downcast<AccessibilityScrollView>(*parent).scrollView(); … … 1481 1454 } else { 1482 1455 // Find the appropriate scroll view to use to convert the contents to the window. 1483 auto matchFunc = [] (AccessibilityObject* object) {1484 return is<AccessibilityScrollView>(*object);1485 };1486 1487 1456 ScrollView* scrollView = nullptr; 1488 AccessibilityObject* parent = matchedParent(m_object, false, matchFunc); 1457 const AccessibilityObject* parent = AccessibilityObject::matchedParent(*m_object, false, [] (const AccessibilityObject& object) { 1458 return is<AccessibilityScrollView>(object); 1459 }); 1489 1460 if (parent) 1490 1461 scrollView = downcast<AccessibilityScrollView>(*parent).scrollView(); … … 1856 1827 // Use this to check if an object is the child of a summary object. 1857 1828 // And return the summary's parent, which is the expandable details object. 1858 auto matchFunc = [] (AccessibilityObject* object) { 1859 return object->hasTagName(summaryTag); 1860 }; 1861 1862 if (AccessibilityObject* summary = matchedParent(object, true, matchFunc)) 1829 if (const AccessibilityObject* summary = AccessibilityObject::matchedParent(*object, true, [] (const AccessibilityObject& object) { 1830 return object.hasTagName(summaryTag); 1831 })) 1863 1832 return summary->parentObject(); 1864 1833 return nil; … … 1868 1837 { 1869 1838 // Use this to check if an object is inside a details object. 1870 auto matchFunc = [] (AccessibilityObject* object) { 1871 return object->hasTagName(detailsTag); 1872 }; 1873 1874 if (AccessibilityObject* details = matchedParent(object, true, matchFunc)) 1875 return details; 1839 if (const AccessibilityObject* details = AccessibilityObject::matchedParent(*object, true, [] (const AccessibilityObject& object) { 1840 return object.hasTagName(detailsTag); 1841 })) 1842 return const_cast<AccessibilityObject*>(details); 1876 1843 return nil; 1877 1844 } -
trunk/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
r206943 r207314 1411 1411 [additional addObject:NSAccessibilityValueAttribute]; 1412 1412 1413 if (m_object->supportsExpanded() )1413 if (m_object->supportsExpanded() || m_object->isSummary()) 1414 1414 [additional addObject:NSAccessibilityExpandedAttribute]; 1415 1415 … … 2208 2208 { RubyTextRole, NSAccessibilityGroupRole }, 2209 2209 { DetailsRole, NSAccessibilityGroupRole }, 2210 { SummaryRole, NSAccessibility GroupRole },2210 { SummaryRole, NSAccessibilityButtonRole }, 2211 2211 { SVGTextPathRole, NSAccessibilityGroupRole }, 2212 2212 { SVGTextRole, NSAccessibilityGroupRole }, … … 2495 2495 case FooterRole: 2496 2496 return AXFooterRoleDescriptionText(); 2497 case SummaryRole:2498 return AXSummaryText();2499 2497 case VideoRole: 2500 2498 return localizedMediaControlElementString("VideoElement"); … … 2535 2533 if (m_object->isTabItem()) 2536 2534 return NSAccessibilityRoleDescription(@"AXTab", nil); 2535 2536 if (m_object->isSummary()) 2537 return AXSummaryText(); 2537 2538 2538 2539 // We should try the system default role description for all other roles. … … 2757 2758 if (m_object->isMeter()) 2758 2759 return [NSString string]; 2760 2761 // Summary element should use its text node as AXTitle. 2762 if (m_object->isSummary()) 2763 return m_object->textUnderElement(); 2759 2764 2760 2765 return [self baseAccessibilityTitle];
Note: See TracChangeset
for help on using the changeset viewer.