https://bugs.webkit.org/show_bug.cgi?id=179500
Reviewed by Ryosuke Niwa.
Source/WebCore:
Accessibility Object Model
Explainer: https://wicg.github.io/aom/explainer.html
Spec: https://wicg.github.io/aom/spec/
Implemented the AOM support for activeDescendant, details and errorMessage.
The corresponding ARIA attributes all take IDREFs, and the AOM properties
take references to AccessibleNodes instead.
Test: accessibility/mac/AOM-relation-property.html
* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::getAttribute const):
(WebCore::AccessibilityObject::hasProperty const):
(WebCore::AccessibilityObject::stringValueForProperty const):
(WebCore::AccessibilityObject::boolValueForProperty const):
(WebCore::AccessibilityObject::intValueForProperty const):
(WebCore::AccessibilityObject::unsignedValueForProperty const):
(WebCore::AccessibilityObject::doubleValueForProperty const):
(WebCore::AccessibilityObject::elementValueForProperty const):
(WebCore::AccessibilityObject::supportsARIAAttributes const):
(WebCore::AccessibilityObject::elementsFromProperty const):
(WebCore::AccessibilityObject::elementsReferencedByProperty const):
(WebCore::AccessibilityObject::ariaActiveDescendantReferencingElements const):
(WebCore::AccessibilityObject::ariaDetailsElements const):
(WebCore::AccessibilityObject::ariaDetailsReferencingElements const):
(WebCore::AccessibilityObject::ariaErrorMessageElements const):
(WebCore::AccessibilityObject::ariaErrorMessageReferencingElements const):
* accessibility/AccessibilityObject.h:
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::activeDescendant const):
* accessibility/AccessibleNode.cpp:
(WebCore::ariaAttributeMap):
(WebCore::isPropertyValueRelation):
(WebCore::AccessibleNode::attributeFromAXPropertyName):
(WebCore::AccessibleNode::setRelationProperty):
(WebCore::AccessibleNode::singleRelationValueForProperty):
(WebCore::AccessibleNode::activeDescendant const):
(WebCore::AccessibleNode::setActiveDescendant):
(WebCore::AccessibleNode::details const):
(WebCore::AccessibleNode::setDetails):
(WebCore::AccessibleNode::errorMessage const):
(WebCore::AccessibleNode::setErrorMessage):
* accessibility/AccessibleNode.h:
* accessibility/AccessibleNode.idl:
* accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
Tools:
* WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
(WTR::AccessibilityUIElement::ariaDetailsElementAtIndex):
(WTR::AccessibilityUIElement::ariaErrorMessageElementAtIndex):
(WTR::AccessibilityUIElement::ariaDescribedByReferencingElementAtIndex):
(WTR::AccessibilityUIElement::ariaDetailsReferencingElementAtIndex):
* WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:
(WTR::AccessibilityUIElement::ariaDetailsElementAtIndex):
(WTR::AccessibilityUIElement::ariaErrorMessageElementAtIndex):
LayoutTests:
Only enable this test on WK2.
* accessibility/mac/AOM-relation-property-expected.txt: Added.
* accessibility/mac/AOM-relation-property.html: Added.
* platform/mac-wk1/TestExpectations:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225511
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-12-04 Nan Wang <n_wang@apple.com>
+
+ AX: AOM: Implement relation type properties
+ https://bugs.webkit.org/show_bug.cgi?id=179500
+
+ Reviewed by Ryosuke Niwa.
+
+ Only enable this test on WK2.
+
+ * accessibility/mac/AOM-relation-property-expected.txt: Added.
+ * accessibility/mac/AOM-relation-property.html: Added.
+ * platform/mac-wk1/TestExpectations:
+
2017-12-04 Zalan Bujtas <zalan@apple.com>
REGRESSION (r211531): Text flow changes and overlaps other text after double-click selecting paragraph
--- /dev/null
+Menu item 1
+Menu item 2
+
+Information about the error.
+This tests relation type Accessibility Object Model properties.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+
+ActiveDescendant support
+PASS axRelation.isSelected is false
+PASS axRelation.isSelected is true
+PASS axRelation.boolAttributeValue('AXIsActiveDescendantOfFocusedContainer') is false
+PASS axRelation.boolAttributeValue('AXIsActiveDescendantOfFocusedContainer') is true
+PASS axRelation.boolAttributeValue('AXIsActiveDescendantOfFocusedContainer') is false
+PASS axRelation.boolAttributeValue('AXIsActiveDescendantOfFocusedContainer') is true
+
+Details support
+PASS axNode.ariaDetailsElementAtIndex(0) is null
+PASS axNode.ariaDetailsElementAtIndex(0).childAtIndex(0).stringValue is "AXValue: Detailed descriptive information."
+PASS axNode.ariaDetailsElementAtIndex(0) is null
+
+ErrorMessage support
+PASS axNode.ariaErrorMessageElementAtIndex(0) is null
+PASS axNode.ariaErrorMessageElementAtIndex(0).childAtIndex(0).stringValue is "AXValue: Information about the error."
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+<script src="../../resources/accessibility-helper.js"></script>
+</head>
+<body>
+
+<div id="menu" role="menu" aria-label="First menu" tabindex="-1">
+<div role="menuitem" id="item1" aria-label="item 1" tabindex="-1">Menu item 1</div>
+<div role="menuitem" id="item2" aria-label="item 2" tabindex="0">Menu item 2</div>
+</div>
+
+<input id="input">
+<div id="details">Detailed descriptive information.</div>
+<div id="error">Information about the error.</div>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+ description("This tests relation type Accessibility Object Model properties.");
+ if (window.accessibilityController) {
+ var node;
+ var axNode;
+ var relation;
+ var axRelation;
+
+ testActiveDescendant();
+ testDetails();
+ testErrorMessage();
+ }
+
+ function testActiveDescendant() {
+ debug("\nActiveDescendant support");
+ node = document.getElementById("menu");
+ axNode = accessibilityController.accessibleElementById("menu");
+ relation = document.getElementById("item1");
+ axRelation = accessibilityController.accessibleElementById("item1");
+
+ // Active Descendant makes the Menu item selected.
+ shouldBeFalse("axRelation.isSelected");
+ node.accessibleNode.activeDescendant = relation.accessibleNode;
+ shouldBeTrue("axRelation.isSelected");
+
+ // Test that we are able to get the right container.
+ shouldBeFalse("axRelation.boolAttributeValue('AXIsActiveDescendantOfFocusedContainer')");
+ node.focus();
+ shouldBeTrue("axRelation.boolAttributeValue('AXIsActiveDescendantOfFocusedContainer')");
+
+ // Make sure it falls back to ARIA attribute if AOM property is not set.
+ node.accessibleNode.activeDescendant = null;
+ shouldBeFalse("axRelation.boolAttributeValue('AXIsActiveDescendantOfFocusedContainer')");
+ node.setAttribute("aria-activedescendant", "item1");
+ shouldBeTrue("axRelation.boolAttributeValue('AXIsActiveDescendantOfFocusedContainer')");
+ }
+
+ function testDetails() {
+ debug("\nDetails support");
+ node = document.getElementById("input");
+ axNode = accessibilityController.accessibleElementById("input");
+ relation = document.getElementById("details");
+
+ shouldBeNull("axNode.ariaDetailsElementAtIndex(0)");
+ node.accessibleNode.details = relation.accessibleNode;
+ shouldBeEqualToString("axNode.ariaDetailsElementAtIndex(0).childAtIndex(0).stringValue", "AXValue: Detailed descriptive information.");
+
+ // Test removing the details element.
+ relation.parentElement.removeChild(relation);
+ shouldBeNull("axNode.ariaDetailsElementAtIndex(0)");
+ }
+
+ function testErrorMessage() {
+ debug("\nErrorMessage support");
+ node = document.getElementById("input");
+ axNode = accessibilityController.accessibleElementById("input");
+ relation = document.getElementById("error");
+
+ shouldBeNull("axNode.ariaErrorMessageElementAtIndex(0)");
+ node.accessibleNode.errorMessage = relation.accessibleNode;
+ shouldBeEqualToString("axNode.ariaErrorMessageElementAtIndex(0).childAtIndex(0).stringValue", "AXValue: Information about the error.");
+ }
+
+</script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
webkit.org/b/172044 [ Debug ] imported/w3c/web-platform-tests/IndexedDB/open-request-queue.html [ Pass Timeout ]
+webkit.org/b/179500 accessibility/mac/AOM-relation-property.html [ Skip ]
+2017-12-04 Nan Wang <n_wang@apple.com>
+
+ AX: AOM: Implement relation type properties
+ https://bugs.webkit.org/show_bug.cgi?id=179500
+
+ Reviewed by Ryosuke Niwa.
+
+ Accessibility Object Model
+ Explainer: https://wicg.github.io/aom/explainer.html
+ Spec: https://wicg.github.io/aom/spec/
+
+ Implemented the AOM support for activeDescendant, details and errorMessage.
+ The corresponding ARIA attributes all take IDREFs, and the AOM properties
+ take references to AccessibleNodes instead.
+
+ Test: accessibility/mac/AOM-relation-property.html
+
+ * accessibility/AccessibilityObject.cpp:
+ (WebCore::AccessibilityObject::getAttribute const):
+ (WebCore::AccessibilityObject::hasProperty const):
+ (WebCore::AccessibilityObject::stringValueForProperty const):
+ (WebCore::AccessibilityObject::boolValueForProperty const):
+ (WebCore::AccessibilityObject::intValueForProperty const):
+ (WebCore::AccessibilityObject::unsignedValueForProperty const):
+ (WebCore::AccessibilityObject::doubleValueForProperty const):
+ (WebCore::AccessibilityObject::elementValueForProperty const):
+ (WebCore::AccessibilityObject::supportsARIAAttributes const):
+ (WebCore::AccessibilityObject::elementsFromProperty const):
+ (WebCore::AccessibilityObject::elementsReferencedByProperty const):
+ (WebCore::AccessibilityObject::ariaActiveDescendantReferencingElements const):
+ (WebCore::AccessibilityObject::ariaDetailsElements const):
+ (WebCore::AccessibilityObject::ariaDetailsReferencingElements const):
+ (WebCore::AccessibilityObject::ariaErrorMessageElements const):
+ (WebCore::AccessibilityObject::ariaErrorMessageReferencingElements const):
+ * accessibility/AccessibilityObject.h:
+ * accessibility/AccessibilityRenderObject.cpp:
+ (WebCore::AccessibilityRenderObject::activeDescendant const):
+ * accessibility/AccessibleNode.cpp:
+ (WebCore::ariaAttributeMap):
+ (WebCore::isPropertyValueRelation):
+ (WebCore::AccessibleNode::attributeFromAXPropertyName):
+ (WebCore::AccessibleNode::setRelationProperty):
+ (WebCore::AccessibleNode::singleRelationValueForProperty):
+ (WebCore::AccessibleNode::activeDescendant const):
+ (WebCore::AccessibleNode::setActiveDescendant):
+ (WebCore::AccessibleNode::details const):
+ (WebCore::AccessibleNode::setDetails):
+ (WebCore::AccessibleNode::errorMessage const):
+ (WebCore::AccessibleNode::setErrorMessage):
+ * accessibility/AccessibleNode.h:
+ * accessibility/AccessibleNode.idl:
+ * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+ (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
+
2017-12-04 Simon Fraser <simon.fraser@apple.com>
Minor DisplayRefreshMonitor-related cleanup
const AtomicString& AccessibilityObject::getAttribute(const QualifiedName& attribute) const
{
- if (Element* element = this->element())
+ if (auto* element = this->element())
return element->attributeWithoutSynchronization(attribute);
return nullAtom();
}
bool AccessibilityObject::hasProperty(AXPropertyName propertyKey) const
{
- if (Element* element = this->element())
+ if (auto* element = this->element())
return AccessibleNode::hasProperty(*element, propertyKey);
return false;
}
const String AccessibilityObject::stringValueForProperty(AXPropertyName propertyKey) const
{
- if (Element* element = this->element())
+ if (auto* element = this->element())
return AccessibleNode::effectiveStringValueForElement(*element, propertyKey);
return nullAtom();
}
std::optional<bool> AccessibilityObject::boolValueForProperty(AXPropertyName propertyKey) const
{
- if (Element* element = this->element())
+ if (auto* element = this->element())
return AccessibleNode::effectiveBoolValueForElement(*element, propertyKey);
return std::nullopt;
}
int AccessibilityObject::intValueForProperty(AXPropertyName propertyKey) const
{
- if (Element* element = this->element())
+ if (auto* element = this->element())
return AccessibleNode::effectiveIntValueForElement(*element, propertyKey);
return 0;
}
unsigned AccessibilityObject::unsignedValueForProperty(AXPropertyName propertyKey) const
{
- if (Element* element = this->element())
+ if (auto* element = this->element())
return AccessibleNode::effectiveUnsignedValueForElement(*element, propertyKey);
return 0;
}
double AccessibilityObject::doubleValueForProperty(AXPropertyName propertyKey) const
{
- if (Element* element = this->element())
+ if (auto* element = this->element())
return AccessibleNode::effectiveDoubleValueForElement(*element, propertyKey);
return 0.0;
}
+Element* AccessibilityObject::elementValueForProperty(AXPropertyName propertyKey) const
+{
+ if (auto* element = this->element()) {
+ auto elements = AccessibleNode::effectiveElementsValueForElement(*element, propertyKey);
+ size_t size = elements.size();
+ ASSERT(!size || size == 1);
+ if (size)
+ return elements.first().get();
+ }
+ return nullptr;
+}
+
// Lacking concrete evidence of orientation, horizontal means width > height. vertical is height > width;
AccessibilityOrientation AccessibilityObject::orientation() const
{
|| hasAttribute(aria_controlsAttr)
|| hasProperty(AXPropertyName::Current)
|| hasAttribute(aria_describedbyAttr)
- || hasAttribute(aria_detailsAttr)
+ || hasProperty(AXPropertyName::Details)
|| hasProperty(AXPropertyName::Disabled)
- || hasAttribute(aria_errormessageAttr)
+ || hasProperty(AXPropertyName::ErrorMessage)
|| hasAttribute(aria_flowtoAttr)
|| hasProperty(AXPropertyName::HasPopUp)
|| hasProperty(AXPropertyName::Invalid)
}
}
+void AccessibilityObject::elementsFromProperty(AccessibilityChildrenVector& children, AXPropertyName property) const
+{
+ auto* element = this->element();
+ if (!element)
+ return;
+
+ auto* cache = axObjectCache();
+ if (!cache)
+ return;
+
+ auto elements = AccessibleNode::effectiveElementsValueForElement(*element, property);
+ for (const auto& element : elements) {
+ if (AccessibilityObject* axObject = cache->getOrCreate(element.get()))
+ children.append(axObject);
+ }
+}
+
+void AccessibilityObject::elementsReferencedByProperty(AccessibilityChildrenVector& elements, AXPropertyName property) const
+{
+ auto* thisElement = this->element();
+ if (!thisElement)
+ return;
+
+ auto id = identifierAttribute();
+ bool idIsEmpty = id.isEmpty();
+ auto* accessibleNode = thisElement->existingAccessibleNode();
+ if (idIsEmpty && !accessibleNode)
+ return;
+
+ auto* cache = axObjectCache();
+ if (!cache)
+ return;
+
+ for (auto& element : descendantsOfType<Element>(node()->treeScope().rootNode())) {
+ bool shouldStore = false;
+ auto referencedAccessibleNodes = AccessibleNode::relationsValueForProperty(element, property);
+ if (referencedAccessibleNodes.size())
+ shouldStore = referencedAccessibleNodes.contains(accessibleNode);
+ if (!shouldStore && !idIsEmpty) {
+ const AtomicString& idList = element.attributeWithoutSynchronization(AccessibleNode::attributeFromAXPropertyName(property));
+ if (SpaceSplitString(idList, false).contains(id))
+ shouldStore = true;
+ }
+
+ if (!shouldStore)
+ continue;
+ if (AccessibilityObject* axObject = cache->getOrCreate(&element))
+ elements.append(axObject);
+ }
+}
+
bool AccessibilityObject::isActiveDescendantOfFocusedContainer() const
{
AccessibilityChildrenVector containers;
void AccessibilityObject::ariaActiveDescendantReferencingElements(AccessibilityChildrenVector& containers) const
{
- ariaElementsReferencedByAttribute(containers, aria_activedescendantAttr);
+ elementsReferencedByProperty(containers, AXPropertyName::ActiveDescendant);
}
void AccessibilityObject::ariaControlsElements(AccessibilityChildrenVector& ariaControls) const
void AccessibilityObject::ariaDetailsElements(AccessibilityChildrenVector& ariaDetails) const
{
- ariaElementsFromAttribute(ariaDetails, aria_detailsAttr);
+ elementsFromProperty(ariaDetails, AXPropertyName::Details);
}
void AccessibilityObject::ariaDetailsReferencingElements(AccessibilityChildrenVector& detailsFor) const
{
- ariaElementsReferencedByAttribute(detailsFor, aria_detailsAttr);
+ elementsReferencedByProperty(detailsFor, AXPropertyName::Details);
}
void AccessibilityObject::ariaErrorMessageElements(AccessibilityChildrenVector& ariaErrorMessage) const
{
- ariaElementsFromAttribute(ariaErrorMessage, aria_errormessageAttr);
+ elementsFromProperty(ariaErrorMessage, AXPropertyName::ErrorMessage);
}
void AccessibilityObject::ariaErrorMessageReferencingElements(AccessibilityChildrenVector& errorMessageFor) const
{
- ariaElementsReferencedByAttribute(errorMessageFor, aria_errormessageAttr);
+ elementsReferencedByProperty(errorMessageFor, AXPropertyName::ErrorMessage);
}
void AccessibilityObject::ariaFlowToElements(AccessibilityChildrenVector& flowTo) const
int intValueForProperty(AXPropertyName) const;
unsigned unsignedValueForProperty(AXPropertyName) const;
double doubleValueForProperty(AXPropertyName) const;
+ Element* elementValueForProperty(AXPropertyName) const;
virtual VisiblePositionRange visiblePositionRange() const { return VisiblePositionRange(); }
virtual VisiblePositionRange visiblePositionRangeForLine(unsigned) const { return VisiblePositionRange(); }
void ariaElementsFromAttribute(AccessibilityChildrenVector&, const QualifiedName&) const;
void ariaElementsReferencedByAttribute(AccessibilityChildrenVector&, const QualifiedName&) const;
+ void elementsFromProperty(AccessibilityChildrenVector&, AXPropertyName) const;
+ void elementsReferencedByProperty(AccessibilityChildrenVector&, AXPropertyName) const;
AccessibilityObject* radioGroupAncestor() const;
if (!m_renderer)
return nullptr;
- const AtomicString& activeDescendantAttrStr = getAttribute(aria_activedescendantAttr);
- if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty())
- return nullptr;
-
- Element* element = this->element();
- if (!element)
- return nullptr;
- Element* target = element->treeScope().getElementById(activeDescendantAttrStr);
+ Element* target = elementValueForProperty(AXPropertyName::ActiveDescendant);
if (!target)
return nullptr;
AXPropertyName name;
QualifiedName ariaAttribute;
} attributes[] = {
+ { AXPropertyName::ActiveDescendant, aria_activedescendantAttr },
{ AXPropertyName::Atomic, aria_atomicAttr },
{ AXPropertyName::Autocomplete, aria_autocompleteAttr },
{ AXPropertyName::Busy, aria_busyAttr },
{ AXPropertyName::ColIndex, aria_colindexAttr },
{ AXPropertyName::ColSpan, aria_colspanAttr },
{ AXPropertyName::Current, aria_currentAttr },
+ { AXPropertyName::Details, aria_detailsAttr },
{ AXPropertyName::Disabled, aria_disabledAttr },
+ { AXPropertyName::ErrorMessage, aria_errormessageAttr },
{ AXPropertyName::Expanded, aria_expandedAttr },
{ AXPropertyName::HasPopUp, aria_haspopupAttr },
{ AXPropertyName::Hidden, aria_hiddenAttr },
}
}
+static bool isPropertyValueRelation(AXPropertyName propertyName)
+{
+ switch (propertyName) {
+ case AXPropertyName::ActiveDescendant:
+ case AXPropertyName::Details:
+ case AXPropertyName::ErrorMessage:
+ return true;
+ default:
+ return false;
+ }
+}
+
+QualifiedName AccessibleNode::attributeFromAXPropertyName(AXPropertyName propertyName)
+{
+ return ariaAttributeMap().get(propertyName);
+}
+
bool AccessibleNode::hasProperty(Element& element, AXPropertyName propertyName)
{
if (auto* accessibleNode = element.existingAccessibleNode()) {
setProperty(propertyName, value, value.isEmpty());
}
+void AccessibleNode::setRelationProperty(AXPropertyName propertyName, AccessibleNode* value)
+{
+ Vector<RefPtr<AccessibleNode>> accessibleNodes;
+ if (value)
+ accessibleNodes.append(value);
+ setProperty(propertyName, accessibleNodes, !value);
+}
+
const String AccessibleNode::effectiveStringValueForElement(Element& element, AXPropertyName propertyName)
{
const String& value = stringValueForProperty(element, propertyName);
return 0.0;
}
+RefPtr<AccessibleNode> AccessibleNode::singleRelationValueForProperty(Element& element, AXPropertyName propertyName)
+{
+ Vector<RefPtr<AccessibleNode>> accessibleNodes = relationsValueForProperty(element, propertyName);
+ size_t size = accessibleNodes.size();
+ ASSERT(!size || size == 1);
+ if (size)
+ return accessibleNodes.first();
+ return nullptr;
+}
+
+Vector<RefPtr<AccessibleNode>> AccessibleNode::relationsValueForProperty(Element& element, AXPropertyName propertyName)
+{
+ const PropertyValueVariant&& variant = AccessibleNode::valueForProperty(element, propertyName);
+ if (WTF::holds_alternative<Vector<RefPtr<AccessibleNode>>>(variant))
+ return WTF::get<Vector<RefPtr<AccessibleNode>>>(variant);
+ return Vector<RefPtr<AccessibleNode>> { };
+}
+
+Vector<RefPtr<Element>> AccessibleNode::effectiveElementsValueForElement(Element& element, AXPropertyName propertyName)
+{
+ Vector<RefPtr<Element>> elements;
+ auto value = relationsValueForProperty(element, propertyName);
+ if (value.size()) {
+ for (auto accessibleNode : value)
+ elements.append(&accessibleNode->m_ownerElement);
+ return elements;
+ }
+
+ if (ariaAttributeMap().contains(propertyName) && isPropertyValueRelation(propertyName)) {
+ const AtomicString& attrStr = element.attributeWithoutSynchronization(ariaAttributeMap().get(propertyName));
+ if (attrStr.isNull() || attrStr.isEmpty())
+ return elements;
+ auto spaceSplitString = SpaceSplitString(attrStr, false);
+ size_t length = spaceSplitString.size();
+ for (size_t i = 0; i < length; ++i) {
+ if (auto* idElement = element.treeScope().getElementById(spaceSplitString[i]))
+ elements.append(idElement);
+ }
+ }
+ return elements;
+}
+
void AccessibleNode::notifyAttributeChanged(const WebCore::QualifiedName& name)
{
if (AXObjectCache* cache = m_ownerElement.document().axObjectCache())
cache->handleAttributeChanged(name, &m_ownerElement);
}
+RefPtr<AccessibleNode> AccessibleNode::activeDescendant() const
+{
+ return singleRelationValueForProperty(m_ownerElement, AXPropertyName::ActiveDescendant);
+}
+
+void AccessibleNode::setActiveDescendant(AccessibleNode* value)
+{
+ setRelationProperty(AXPropertyName::ActiveDescendant, value);
+ notifyAttributeChanged(aria_activedescendantAttr);
+}
+
std::optional<bool> AccessibleNode::atomic() const
{
return optionalValueForProperty<bool>(m_ownerElement, AXPropertyName::Atomic);
notifyAttributeChanged(aria_currentAttr);
}
+RefPtr<AccessibleNode> AccessibleNode::details() const
+{
+ return singleRelationValueForProperty(m_ownerElement, AXPropertyName::Details);
+}
+
+void AccessibleNode::setDetails(AccessibleNode* value)
+{
+ setRelationProperty(AXPropertyName::Details, value);
+ notifyAttributeChanged(aria_detailsAttr);
+}
+
std::optional<bool> AccessibleNode::disabled() const
{
return optionalValueForProperty<bool>(m_ownerElement, AXPropertyName::Disabled);
}
+RefPtr<AccessibleNode> AccessibleNode::errorMessage() const
+{
+ return singleRelationValueForProperty(m_ownerElement, AXPropertyName::ErrorMessage);
+}
+
+void AccessibleNode::setErrorMessage(AccessibleNode* value)
+{
+ setRelationProperty(AXPropertyName::ErrorMessage, value);
+ notifyAttributeChanged(aria_errormessageAttr);
+}
+
+
void AccessibleNode::setDisabled(std::optional<bool> value)
{
setOptionalProperty<bool>(AXPropertyName::Disabled, value);
namespace WebCore {
-typedef Variant<std::nullptr_t, String, bool, int, unsigned, double> PropertyValueVariant;
+typedef Variant<std::nullptr_t, String, bool, int, unsigned, double, Vector<RefPtr<AccessibleNode>>> PropertyValueVariant;
enum class AXPropertyName {
None,
+ ActiveDescendant,
Atomic,
Autocomplete,
Busy,
ColIndex,
ColSpan,
Current,
+ Details,
Disabled,
+ ErrorMessage,
Expanded,
HasPopUp,
Hidden,
void ref() { m_ownerElement.ref(); }
void deref() { m_ownerElement.deref(); }
+ static QualifiedName attributeFromAXPropertyName(AXPropertyName);
+
static const String effectiveStringValueForElement(Element&, AXPropertyName);
static std::optional<bool> effectiveBoolValueForElement(Element&, AXPropertyName);
static int effectiveIntValueForElement(Element&, AXPropertyName);
static unsigned effectiveUnsignedValueForElement(Element&, AXPropertyName);
static double effectiveDoubleValueForElement(Element&, AXPropertyName);
+ static Vector<RefPtr<Element>> effectiveElementsValueForElement(Element&, AXPropertyName);
+ static Vector<RefPtr<AccessibleNode>> relationsValueForProperty(Element&, AXPropertyName);
static bool hasProperty(Element&, AXPropertyName);
+ RefPtr<AccessibleNode> activeDescendant() const;
+ void setActiveDescendant(AccessibleNode*);
+
std::optional<bool> atomic() const;
void setAtomic(std::optional<bool>);
String current() const;
void setCurrent(const String&);
+ RefPtr<AccessibleNode> details() const;
+ void setDetails(AccessibleNode*);
+
std::optional<bool> disabled() const;
void setDisabled(std::optional<bool>);
+ RefPtr<AccessibleNode> errorMessage() const;
+ void setErrorMessage(AccessibleNode*);
+
std::optional<bool> expanded() const;
void setExpanded(std::optional<bool>);
static const PropertyValueVariant valueForProperty(Element&, AXPropertyName);
static const String stringValueForProperty(Element&, AXPropertyName);
template<typename T> static std::optional<T> optionalValueForProperty(Element&, AXPropertyName);
+ static RefPtr<AccessibleNode> singleRelationValueForProperty(Element&, AXPropertyName);
void setProperty(AXPropertyName, PropertyValueVariant&&, bool);
template<typename T> void setOptionalProperty(AXPropertyName, std::optional<T>);
void setStringProperty(AXPropertyName, const String&);
+ void setRelationProperty(AXPropertyName, AccessibleNode*);
void notifyAttributeChanged(const WebCore::QualifiedName&);
SkipVTableValidation,
EnabledAtRuntime=AccessibilityObjectModel,
] interface AccessibleNode {
+ attribute AccessibleNode? activeDescendant;
attribute boolean? atomic;
attribute DOMString? autocomplete;
attribute boolean? busy;
attribute unsigned long? colIndex;
attribute unsigned long? colSpan;
attribute DOMString? current;
+ attribute AccessibleNode? details;
attribute boolean? disabled;
+ attribute AccessibleNode? errorMessage;
attribute boolean? expanded;
attribute DOMString? hasPopUp;
attribute boolean? hidden;
if ([attributeName isEqualToString:@"AXReadOnlyValue"])
return m_object->readOnlyValue();
+ if ([attributeName isEqualToString:@"AXIsActiveDescendantOfFocusedContainer"])
+ return [NSNumber numberWithBool:m_object->isActiveDescendantOfFocusedContainer()];
+
+ if ([attributeName isEqualToString:@"AXDetailsElements"]) {
+ AccessibilityObject::AccessibilityChildrenVector details;
+ m_object->ariaDetailsElements(details);
+ return convertToNSArray(details);
+ }
+
+ if ([attributeName isEqualToString:@"AXErrorMessageElements"]) {
+ AccessibilityObject::AccessibilityChildrenVector errorMessages;
+ m_object->ariaErrorMessageElements(errorMessages);
+ return convertToNSArray(errorMessages);
+ }
+
if (m_object->isWebArea() && [attributeName isEqualToString:NSAccessibilityPreventKeyboardDOMEventDispatchAttribute])
return [NSNumber numberWithBool:m_object->preventKeyboardDOMEventDispatch()];
+2017-12-04 Nan Wang <n_wang@apple.com>
+
+ AX: AOM: Implement relation type properties
+ https://bugs.webkit.org/show_bug.cgi?id=179500
+
+ Reviewed by Ryosuke Niwa.
+
+ * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
+ (WTR::AccessibilityUIElement::ariaDetailsElementAtIndex):
+ (WTR::AccessibilityUIElement::ariaErrorMessageElementAtIndex):
+ (WTR::AccessibilityUIElement::ariaDescribedByReferencingElementAtIndex):
+ (WTR::AccessibilityUIElement::ariaDetailsReferencingElementAtIndex):
+ * WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:
+ (WTR::AccessibilityUIElement::ariaDetailsElementAtIndex):
+ (WTR::AccessibilityUIElement::ariaErrorMessageElementAtIndex):
+
2017-12-04 Simon Fraser <simon.fraser@apple.com>
Minor DisplayRefreshMonitor-related cleanup
RefPtr<AccessibilityUIElement> ariaOwnsElementAtIndex(unsigned);
RefPtr<AccessibilityUIElement> ariaFlowToElementAtIndex(unsigned);
RefPtr<AccessibilityUIElement> ariaControlsElementAtIndex(unsigned);
+#if PLATFORM(MAC) || PLATFORM(GTK)
+ RefPtr<AccessibilityUIElement> ariaDetailsElementAtIndex(unsigned);
+ RefPtr<AccessibilityUIElement> ariaErrorMessageElementAtIndex(unsigned);
+#else
+ RefPtr<AccessibilityUIElement> ariaDetailsElementAtIndex(unsigned) { return nullptr; }
+ RefPtr<AccessibilityUIElement> ariaErrorMessageElementAtIndex(unsigned) { return nullptr; }
+#endif
+
#if PLATFORM(GTK)
RefPtr<AccessibilityUIElement> ariaLabelledByElementAtIndex(unsigned);
RefPtr<AccessibilityUIElement> ariaDescribedByElementAtIndex(unsigned);
RefPtr<AccessibilityUIElement> ariaControlsReferencingElementAtIndex(unsigned);
RefPtr<AccessibilityUIElement> ariaLabelledByReferencingElementAtIndex(unsigned);
RefPtr<AccessibilityUIElement> ariaDescribedByReferencingElementAtIndex(unsigned);
- RefPtr<AccessibilityUIElement> ariaDetailsElementAtIndex(unsigned);
RefPtr<AccessibilityUIElement> ariaDetailsReferencingElementAtIndex(unsigned);
- RefPtr<AccessibilityUIElement> ariaErrorMessageElementAtIndex(unsigned);
RefPtr<AccessibilityUIElement> ariaErrorMessageReferencingElementAtIndex(unsigned);
#else
RefPtr<AccessibilityUIElement> ariaLabelledByElementAtIndex(unsigned) { return nullptr; }
RefPtr<AccessibilityUIElement> ariaControlsReferencingElementAtIndex(unsigned) { return nullptr; }
RefPtr<AccessibilityUIElement> ariaLabelledByReferencingElementAtIndex(unsigned) { return nullptr; }
RefPtr<AccessibilityUIElement> ariaDescribedByReferencingElementAtIndex(unsigned) { return nullptr; }
- RefPtr<AccessibilityUIElement> ariaDetailsElementAtIndex(unsigned) { return nullptr; }
RefPtr<AccessibilityUIElement> ariaDetailsReferencingElementAtIndex(unsigned) { return nullptr; }
- RefPtr<AccessibilityUIElement> ariaErrorMessageElementAtIndex(unsigned) { return nullptr; }
RefPtr<AccessibilityUIElement> ariaErrorMessageReferencingElementAtIndex(unsigned) { return nullptr; }
#endif
return nullptr;
}
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaDetailsElementAtIndex(unsigned index)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* details = [m_element accessibilityAttributeValue:@"AXDetailsElements"];
+ if (index < [details count])
+ return AccessibilityUIElement::create([details objectAtIndex:index]);
+ END_AX_OBJC_EXCEPTIONS
+ return nullptr;
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaErrorMessageElementAtIndex(unsigned index)
+{
+ BEGIN_AX_OBJC_EXCEPTIONS
+ NSArray* errorMessages = [m_element accessibilityAttributeValue:@"AXErrorMessageElements"];
+ if (index < [errorMessages count])
+ return AccessibilityUIElement::create([errorMessages objectAtIndex:index]);
+ END_AX_OBJC_EXCEPTIONS
+ return nullptr;
+}
+
RefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
{
BEGIN_AX_OBJC_EXCEPTIONS