| Index: third_party/WebKit/Source/core/dom/AccessibleNode.cpp
|
| diff --git a/third_party/WebKit/Source/core/dom/AccessibleNode.cpp b/third_party/WebKit/Source/core/dom/AccessibleNode.cpp
|
| index 05f23c087646240ff2a02390cb6a7bcd4eb1ce85..18a467368d886561072f64aab44652f6c855dd18 100644
|
| --- a/third_party/WebKit/Source/core/dom/AccessibleNode.cpp
|
| +++ b/third_party/WebKit/Source/core/dom/AccessibleNode.cpp
|
| @@ -5,6 +5,7 @@
|
| #include "core/dom/AccessibleNode.h"
|
|
|
| #include "core/dom/AXObjectCache.h"
|
| +#include "core/dom/AccessibleNodeList.h"
|
| #include "core/dom/Element.h"
|
| #include "core/dom/QualifiedName.h"
|
| #include "core/frame/Settings.h"
|
| @@ -70,6 +71,31 @@ QualifiedName GetCorrespondingARIAAttribute(AOMRelationProperty property) {
|
| return g_null_name;
|
| }
|
|
|
| +QualifiedName GetCorrespondingARIAAttribute(AOMRelationListProperty property) {
|
| + switch (property) {
|
| + case AOMRelationListProperty::kDescribedBy:
|
| + return aria_describedbyAttr;
|
| + break;
|
| + case AOMRelationListProperty::kControls:
|
| + return aria_controlsAttr;
|
| + break;
|
| + case AOMRelationListProperty::kFlowTo:
|
| + return aria_flowtoAttr;
|
| + break;
|
| + case AOMRelationListProperty::kLabeledBy:
|
| + // Note that there are two allowed spellings of this attribute.
|
| + // Callers should check both.
|
| + return aria_labelledbyAttr;
|
| + break;
|
| + case AOMRelationListProperty::kOwns:
|
| + return aria_ownsAttr;
|
| + break;
|
| + }
|
| +
|
| + NOTREACHED();
|
| + return g_null_name;
|
| +}
|
| +
|
| QualifiedName GetCorrespondingARIAAttribute(AOMBooleanProperty property) {
|
| switch (property) {
|
| case AOMBooleanProperty::kAtomic:
|
| @@ -212,6 +238,43 @@ AccessibleNode* AccessibleNode::GetProperty(Element* element,
|
| return nullptr;
|
| }
|
|
|
| +// static
|
| +AccessibleNodeList* AccessibleNode::GetProperty(
|
| + Element* element,
|
| + AOMRelationListProperty property) {
|
| + if (!element)
|
| + return nullptr;
|
| +
|
| + if (AccessibleNode* accessible_node = element->ExistingAccessibleNode()) {
|
| + for (const auto& item : accessible_node->relation_list_properties_) {
|
| + if (item.first == property && item.second)
|
| + return item.second;
|
| + }
|
| + }
|
| +
|
| + return nullptr;
|
| +}
|
| +
|
| +// static
|
| +bool AccessibleNode::GetProperty(Element* element,
|
| + AOMRelationListProperty property,
|
| + HeapVector<Member<Element>>& targets) {
|
| + AccessibleNodeList* node_list = GetProperty(element, property);
|
| + if (!node_list)
|
| + return false;
|
| +
|
| + for (size_t i = 0; i < node_list->length(); ++i) {
|
| + AccessibleNode* accessible_node = node_list->item(i);
|
| + if (accessible_node) {
|
| + Element* element = accessible_node->element();
|
| + if (element)
|
| + targets.push_back(element);
|
| + }
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| template <typename P, typename T>
|
| static T FindPropertyValue(P property,
|
| bool& is_null,
|
| @@ -324,6 +387,39 @@ AccessibleNode* AccessibleNode::GetPropertyOrARIAAttribute(
|
| }
|
|
|
| // static
|
| +bool AccessibleNode::GetPropertyOrARIAAttribute(
|
| + Element* element,
|
| + AOMRelationListProperty property,
|
| + HeapVector<Member<Element>>& targets) {
|
| + if (!element)
|
| + return false;
|
| +
|
| + if (GetProperty(element, property, targets))
|
| + return true;
|
| +
|
| + // Fall back on the equivalent ARIA attribute.
|
| + QualifiedName attribute = GetCorrespondingARIAAttribute(property);
|
| + String value = element->FastGetAttribute(attribute).GetString();
|
| + if (value.IsEmpty() && property == AOMRelationListProperty::kLabeledBy)
|
| + value = element->FastGetAttribute(aria_labeledbyAttr).GetString();
|
| + if (value.IsEmpty())
|
| + return false;
|
| +
|
| + value.SimplifyWhiteSpace();
|
| + Vector<String> ids;
|
| + value.Split(' ', ids);
|
| + if (ids.IsEmpty())
|
| + return false;
|
| +
|
| + TreeScope& scope = element->GetTreeScope();
|
| + for (const auto& id : ids) {
|
| + if (Element* id_element = scope.getElementById(AtomicString(id)))
|
| + targets.push_back(id_element);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +// static
|
| bool AccessibleNode::GetPropertyOrARIAAttribute(Element* element,
|
| AOMBooleanProperty property,
|
| bool& is_null) {
|
| @@ -429,9 +525,17 @@ void AccessibleNode::GetAllAOMProperties(
|
| shadowed_aria_attributes.insert(GetCorrespondingARIAAttribute(item.first));
|
| }
|
| for (auto& item : accessible_node->relation_properties_) {
|
| + if (!item.second)
|
| + continue;
|
| client->AddRelationProperty(item.first, *item.second);
|
| shadowed_aria_attributes.insert(GetCorrespondingARIAAttribute(item.first));
|
| }
|
| + for (auto& item : accessible_node->relation_list_properties_) {
|
| + if (!item.second)
|
| + continue;
|
| + client->AddRelationListProperty(item.first, *item.second);
|
| + shadowed_aria_attributes.insert(GetCorrespondingARIAAttribute(item.first));
|
| + }
|
| }
|
|
|
| AccessibleNode* AccessibleNode::activeDescendant() const {
|
| @@ -507,6 +611,15 @@ void AccessibleNode::setColSpan(uint32_t col_span, bool is_null) {
|
| NotifyAttributeChanged(aria_colspanAttr);
|
| }
|
|
|
| +AccessibleNodeList* AccessibleNode::controls() const {
|
| + return GetProperty(element_, AOMRelationListProperty::kControls);
|
| +}
|
| +
|
| +void AccessibleNode::setControls(AccessibleNodeList* controls) {
|
| + SetRelationListProperty(AOMRelationListProperty::kControls, controls);
|
| + NotifyAttributeChanged(aria_controlsAttr);
|
| +}
|
| +
|
| AtomicString AccessibleNode::current() const {
|
| return GetProperty(element_, AOMStringProperty::kCurrent);
|
| }
|
| @@ -518,6 +631,15 @@ void AccessibleNode::setCurrent(const AtomicString& current) {
|
| cache->HandleAttributeChanged(aria_currentAttr, element_);
|
| }
|
|
|
| +AccessibleNodeList* AccessibleNode::describedBy() {
|
| + return GetProperty(element_, AOMRelationListProperty::kDescribedBy);
|
| +}
|
| +
|
| +void AccessibleNode::setDescribedBy(AccessibleNodeList* described_by) {
|
| + SetRelationListProperty(AOMRelationListProperty::kDescribedBy, described_by);
|
| + NotifyAttributeChanged(aria_describedbyAttr);
|
| +}
|
| +
|
| AccessibleNode* AccessibleNode::details() const {
|
| return GetProperty(element_, AOMRelationProperty::kDetails);
|
| }
|
| @@ -554,6 +676,15 @@ void AccessibleNode::setExpanded(bool expanded, bool is_null) {
|
| NotifyAttributeChanged(aria_expandedAttr);
|
| }
|
|
|
| +AccessibleNodeList* AccessibleNode::flowTo() const {
|
| + return GetProperty(element_, AOMRelationListProperty::kFlowTo);
|
| +}
|
| +
|
| +void AccessibleNode::setFlowTo(AccessibleNodeList* flow_to) {
|
| + SetRelationListProperty(AOMRelationListProperty::kFlowTo, flow_to);
|
| + NotifyAttributeChanged(aria_flowtoAttr);
|
| +}
|
| +
|
| bool AccessibleNode::hidden(bool& is_null) const {
|
| return GetProperty(element_, AOMBooleanProperty::kHidden, is_null);
|
| }
|
| @@ -590,6 +721,15 @@ void AccessibleNode::setLabel(const AtomicString& label) {
|
| NotifyAttributeChanged(aria_labelAttr);
|
| }
|
|
|
| +AccessibleNodeList* AccessibleNode::labeledBy() {
|
| + return GetProperty(element_, AOMRelationListProperty::kLabeledBy);
|
| +}
|
| +
|
| +void AccessibleNode::setLabeledBy(AccessibleNodeList* labeled_by) {
|
| + SetRelationListProperty(AOMRelationListProperty::kLabeledBy, labeled_by);
|
| + NotifyAttributeChanged(aria_labelledbyAttr);
|
| +}
|
| +
|
| uint32_t AccessibleNode::level(bool& is_null) const {
|
| return GetProperty(element_, AOMUIntProperty::kLevel, is_null);
|
| }
|
| @@ -645,6 +785,15 @@ void AccessibleNode::setOrientation(const AtomicString& orientation) {
|
| NotifyAttributeChanged(aria_orientationAttr);
|
| }
|
|
|
| +AccessibleNodeList* AccessibleNode::owns() const {
|
| + return GetProperty(element_, AOMRelationListProperty::kOwns);
|
| +}
|
| +
|
| +void AccessibleNode::setOwns(AccessibleNodeList* owns) {
|
| + SetRelationListProperty(AOMRelationListProperty::kOwns, owns);
|
| + NotifyAttributeChanged(aria_ownsAttr);
|
| +}
|
| +
|
| AtomicString AccessibleNode::placeholder() const {
|
| return GetProperty(element_, AOMStringProperty::kPlaceholder);
|
| }
|
| @@ -831,6 +980,22 @@ void AccessibleNode::SetRelationProperty(AOMRelationProperty property,
|
| relation_properties_.push_back(std::make_pair(property, value));
|
| }
|
|
|
| +void AccessibleNode::SetRelationListProperty(AOMRelationListProperty property,
|
| + AccessibleNodeList* value) {
|
| + for (auto& item : relation_list_properties_) {
|
| + if (item.first == property) {
|
| + if (item.second)
|
| + item.second->RemoveOwner(property, this);
|
| + if (value)
|
| + value->AddOwner(property, this);
|
| + item.second = value;
|
| + return;
|
| + }
|
| + }
|
| +
|
| + relation_list_properties_.push_back(std::make_pair(property, value));
|
| +}
|
| +
|
| template <typename P, typename T>
|
| static void SetProperty(P property,
|
| T value,
|
| @@ -874,6 +1039,10 @@ void AccessibleNode::SetFloatProperty(AOMFloatProperty property,
|
| SetProperty(property, value, is_null, float_properties_);
|
| }
|
|
|
| +void AccessibleNode::OnRelationListChanged(AOMRelationListProperty property) {
|
| + NotifyAttributeChanged(GetCorrespondingARIAAttribute(property));
|
| +}
|
| +
|
| void AccessibleNode::NotifyAttributeChanged(
|
| const blink::QualifiedName& attribute) {
|
| // TODO(dmazzoni): Make a cleaner API for this rather than pretending
|
| @@ -889,6 +1058,7 @@ AXObjectCache* AccessibleNode::GetAXObjectCache() {
|
| DEFINE_TRACE(AccessibleNode) {
|
| visitor->Trace(element_);
|
| visitor->Trace(relation_properties_);
|
| + visitor->Trace(relation_list_properties_);
|
| }
|
|
|
| } // namespace blink
|
|
|