Chromium Code Reviews| 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..266c42553ae842109b0fc461343deed29da2ffe3 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 valid spellings of this attribute. |
|
aboxhall
2017/07/06 05:37:14
Perhaps "allowed" instead of "valid"?
dmazzoni
2017/07/06 06:34:25
Done.
|
| + // Callers should check both. |
| + return aria_labeledbyAttr; |
|
aboxhall
2017/07/06 05:37:14
I think we should prefer the English spelling here
dmazzoni
2017/07/06 06:34:25
Done, I flipped a couple other places in this file
|
| + 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_labelledbyAttr).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_labeledbyAttr); |
| +} |
| + |
| 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 |