Chromium Code Reviews| Index: third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp |
| diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp |
| index 58b6cd37e5ce8175a7e970004de4385f78d8dd0f..26df107f9da7473179f3a5256d74d4169c889323 100644 |
| --- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp |
| +++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp |
| @@ -32,6 +32,7 @@ |
| #include "core/dom/DocumentUserGestureToken.h" |
| #include "core/dom/Element.h" |
| #include "core/dom/NodeTraversal.h" |
| +#include "core/dom/QualifiedName.h" |
| #include "core/dom/Text.h" |
| #include "core/dom/shadow/FlatTreeTraversal.h" |
| #include "core/editing/EditingUtilities.h" |
| @@ -70,6 +71,130 @@ namespace blink { |
| using namespace HTMLNames; |
| +class SparseAttributeSetter { |
|
haraken
2017/01/18 23:40:00
Add USING_FAST_MALLOC().
dmazzoni
2017/01/21 00:16:35
Done.
|
| + public: |
| + virtual void Run(const AXObject*, |
| + AXSparseAttributeClient&, |
| + const AtomicString& value) = 0; |
| +}; |
| + |
| +class BoolAttributeSetter : public SparseAttributeSetter { |
| + public: |
| + BoolAttributeSetter(AXBoolAttribute attribute) : m_attribute(attribute) {} |
| + |
| + private: |
| + AXBoolAttribute m_attribute; |
| + |
| + void Run(const AXObject* obj, |
| + AXSparseAttributeClient& attributeMap, |
| + const AtomicString& value) override { |
| + attributeMap.addBoolAttribute(m_attribute, |
| + equalIgnoringCase(value, "true")); |
| + } |
| +}; |
| + |
| +class StringAttributeSetter : public SparseAttributeSetter { |
| + public: |
| + StringAttributeSetter(AXStringAttribute attribute) : m_attribute(attribute) {} |
| + |
| + private: |
| + AXStringAttribute m_attribute; |
| + |
| + void Run(const AXObject* obj, |
| + AXSparseAttributeClient& attributeMap, |
| + const AtomicString& value) override { |
| + attributeMap.addStringAttribute(m_attribute, value); |
| + } |
| +}; |
| + |
| +class ObjectAttributeSetter : public SparseAttributeSetter { |
| + public: |
| + ObjectAttributeSetter(AXObjectAttribute attribute) : m_attribute(attribute) {} |
| + |
| + private: |
| + AXObjectAttribute m_attribute; |
| + |
| + void Run(const AXObject* obj, |
| + AXSparseAttributeClient& attributeMap, |
| + const AtomicString& value) override { |
| + if (value.isNull() || value.isEmpty()) |
| + return; |
| + |
| + Node* node = obj->getNode(); |
| + if (!node || !node->isElementNode()) |
| + return; |
| + Element* target = toElement(node)->treeScope().getElementById(value); |
| + if (!target) |
| + return; |
| + AXObject* axTarget = obj->axObjectCache().getOrCreate(target); |
| + if (axTarget) |
| + attributeMap.addObjectAttribute(m_attribute, axTarget); |
| + } |
| +}; |
| + |
| +class ObjectVectorAttributeSetter : public SparseAttributeSetter { |
| + public: |
| + ObjectVectorAttributeSetter(AXObjectVectorAttribute attribute) |
| + : m_attribute(attribute) {} |
| + |
| + private: |
| + AXObjectVectorAttribute m_attribute; |
| + |
| + void Run(const AXObject* obj, |
| + AXSparseAttributeClient& attributeMap, |
| + const AtomicString& value) override { |
| + Node* node = obj->getNode(); |
| + if (!node || !node->isElementNode()) |
| + return; |
| + |
| + String attributeValue = value.getString(); |
| + if (attributeValue.isEmpty()) |
| + return; |
| + |
| + attributeValue.simplifyWhiteSpace(); |
| + Vector<String> ids; |
| + attributeValue.split(' ', ids); |
| + if (ids.isEmpty()) |
| + return; |
| + |
| + HeapVector<Member<AXObject>> objects; |
| + TreeScope& scope = node->treeScope(); |
| + for (const auto& id : ids) { |
| + if (Element* idElement = scope.getElementById(AtomicString(id))) { |
| + AXObject* axIdElement = obj->axObjectCache().getOrCreate(idElement); |
| + if (axIdElement && !axIdElement->accessibilityIsIgnored()) |
| + objects.append(axIdElement); |
| + } |
| + } |
| + |
| + attributeMap.addObjectVectorAttribute(m_attribute, objects); |
| + } |
| +}; |
| + |
| +typedef HashMap<QualifiedName, SparseAttributeSetter*> |
| + AXSparseAttributeSetterMap; |
|
dcheng
2017/01/19 23:02:44
Nit: prefer using AXSpareAttributeSetterMap = Hash
dmazzoni
2017/01/21 00:16:35
Done.
|
| + |
| +static AXSparseAttributeSetterMap& GetSparseAttributeSetterMap() { |
| + // Use a map from attribute name to properties of that attribute. |
| + // That way we only need to iterate over the list of attributes once, |
| + // rather than calling getAttribute() once for each possible obscure |
| + // accessibility attribute. |
| + DEFINE_STATIC_LOCAL(AXSparseAttributeSetterMap, axSparseAttributeSetterMap, |
| + ()); |
| + if (axSparseAttributeSetterMap.isEmpty()) { |
| + axSparseAttributeSetterMap.set( |
| + aria_activedescendantAttr, |
| + new ObjectAttributeSetter(AXObjectAttribute::AriaActiveDescendant)); |
| + axSparseAttributeSetterMap.set( |
| + aria_controlsAttr, |
| + new ObjectVectorAttributeSetter(AXObjectVectorAttribute::AriaControls)); |
| + axSparseAttributeSetterMap.set( |
| + aria_flowtoAttr, |
| + new ObjectVectorAttributeSetter(AXObjectVectorAttribute::AriaFlowTo)); |
| + } |
| + return axSparseAttributeSetterMap; |
| +} |
| + |
| AXNodeObject::AXNodeObject(Node* node, AXObjectCacheImpl& axObjectCache) |
| : AXObject(axObjectCache), |
| m_ariaRole(UnknownRole), |
| @@ -753,6 +878,22 @@ void AXNodeObject::detach() { |
| m_node = nullptr; |
| } |
| +void AXNodeObject::getSparseAXAttributes( |
| + AXSparseAttributeClient& sparseAttributeClient) const { |
| + Node* node = this->getNode(); |
| + if (!node || !node->isElementNode()) |
| + return; |
| + |
| + AXSparseAttributeSetterMap& axSparseAttributeSetterMap = |
| + GetSparseAttributeSetterMap(); |
| + AttributeCollection attributes = toElement(node)->attributesWithoutUpdate(); |
| + for (const Attribute& attr : attributes) { |
| + SparseAttributeSetter* setter = axSparseAttributeSetterMap.get(attr.name()); |
| + if (setter) |
| + setter->Run(this, sparseAttributeClient, attr.value()); |
| + } |
| +} |
| + |
| bool AXNodeObject::isAnchor() const { |
| return !isNativeImage() && isLink(); |
| } |