| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/modules/accessibility/inspector_type_builder_helper.h" |
| |
| #include "third_party/blink/renderer/core/dom/dom_node_ids.h" |
| #include "third_party/blink/renderer/core/inspector/identifiers_factory.h" |
| #include "third_party/blink/renderer/modules/accessibility/ax_object.h" |
| #include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h" |
| |
| namespace blink { |
| |
| using protocol::Accessibility::AXRelatedNode; |
| |
| std::unique_ptr<AXProperty> CreateProperty(const String& name, |
| std::unique_ptr<AXValue> value) { |
| return AXProperty::create().setName(name).setValue(std::move(value)).build(); |
| } |
| |
| String IgnoredReasonName(AXIgnoredReason reason) { |
| switch (reason) { |
| case kAXActiveFullscreenElement: |
| return "activeFullscreenElement"; |
| case kAXActiveModalDialog: |
| return "activeModalDialog"; |
| case kAXAriaModalDialog: |
| return "activeAriaModalDialog"; |
| case kAXAriaHiddenElement: |
| return "ariaHiddenElement"; |
| case kAXAriaHiddenSubtree: |
| return "ariaHiddenSubtree"; |
| case kAXEmptyAlt: |
| return "emptyAlt"; |
| case kAXEmptyText: |
| return "emptyText"; |
| case kAXHiddenByChildTree: |
| return "hiddenByChildTree"; |
| case kAXInertElement: |
| return "inertElement"; |
| case kAXInertSubtree: |
| return "inertSubtree"; |
| case kAXLabelContainer: |
| return "labelContainer"; |
| case kAXLabelFor: |
| return "labelFor"; |
| case kAXNotRendered: |
| return "notRendered"; |
| case kAXNotVisible: |
| return "notVisible"; |
| case kAXPresentational: |
| return "presentationalRole"; |
| case kAXProbablyPresentational: |
| return "probablyPresentational"; |
| case kAXUninteresting: |
| return "uninteresting"; |
| } |
| NOTREACHED(); |
| return ""; |
| } |
| |
| std::unique_ptr<AXProperty> CreateProperty(IgnoredReason reason) { |
| if (reason.related_object) |
| return CreateProperty( |
| IgnoredReasonName(reason.reason), |
| CreateRelatedNodeListValue(*(reason.related_object), nullptr, |
| AXValueTypeEnum::Idref)); |
| return CreateProperty(IgnoredReasonName(reason.reason), |
| CreateBooleanValue(true)); |
| } |
| |
| std::unique_ptr<AXValue> CreateValue(const String& value, const String& type) { |
| return AXValue::create() |
| .setType(type) |
| .setValue(protocol::ValueConversions<String>::toValue(value)) |
| .build(); |
| } |
| |
| std::unique_ptr<AXValue> CreateValue(int value, const String& type) { |
| return AXValue::create() |
| .setType(type) |
| .setValue(protocol::ValueConversions<int>::toValue(value)) |
| .build(); |
| } |
| |
| std::unique_ptr<AXValue> CreateValue(float value, const String& type) { |
| return AXValue::create() |
| .setType(type) |
| .setValue(protocol::ValueConversions<double>::toValue(value)) |
| .build(); |
| } |
| |
| std::unique_ptr<AXValue> CreateBooleanValue(bool value, const String& type) { |
| return AXValue::create() |
| .setType(type) |
| .setValue(protocol::ValueConversions<bool>::toValue(value)) |
| .build(); |
| } |
| |
| std::unique_ptr<AXRelatedNode> RelatedNodeForAXObject(const AXObject& ax_object, |
| String* name = nullptr) { |
| Node* node = ax_object.GetNode(); |
| if (!node) |
| return nullptr; |
| int backend_node_id = IdentifiersFactory::IntIdForNode(node); |
| if (!backend_node_id) |
| return nullptr; |
| std::unique_ptr<AXRelatedNode> related_node = |
| AXRelatedNode::create().setBackendDOMNodeId(backend_node_id).build(); |
| auto* element = DynamicTo<Element>(node); |
| if (!element) |
| return related_node; |
| |
| String idref = element->GetIdAttribute(); |
| if (!idref.empty()) |
| related_node->setIdref(idref); |
| |
| if (name) |
| related_node->setText(*name); |
| return related_node; |
| } |
| |
| std::unique_ptr<AXValue> CreateRelatedNodeListValue(const AXObject& ax_object, |
| String* name, |
| const String& value_type) { |
| auto related_nodes = std::make_unique<protocol::Array<AXRelatedNode>>(); |
| std::unique_ptr<AXRelatedNode> related_node = |
| RelatedNodeForAXObject(ax_object, name); |
| if (related_node) |
| related_nodes->emplace_back(std::move(related_node)); |
| return AXValue::create() |
| .setType(value_type) |
| .setRelatedNodes(std::move(related_nodes)) |
| .build(); |
| } |
| |
| std::unique_ptr<AXValue> CreateRelatedNodeListValue( |
| AXRelatedObjectVector& related_objects, |
| const String& value_type) { |
| auto frontend_related_nodes = |
| std::make_unique<protocol::Array<AXRelatedNode>>(); |
| for (unsigned i = 0; i < related_objects.size(); i++) { |
| std::unique_ptr<AXRelatedNode> frontend_related_node = |
| RelatedNodeForAXObject(*(related_objects[i]->object), |
| &(related_objects[i]->text)); |
| if (frontend_related_node) |
| frontend_related_nodes->emplace_back(std::move(frontend_related_node)); |
| } |
| return AXValue::create() |
| .setType(value_type) |
| .setRelatedNodes(std::move(frontend_related_nodes)) |
| .build(); |
| } |
| |
| std::unique_ptr<AXValue> CreateRelatedNodeListValue( |
| AXObject::AXObjectVector& ax_objects, |
| const String& value_type) { |
| auto related_nodes = std::make_unique<protocol::Array<AXRelatedNode>>(); |
| for (unsigned i = 0; i < ax_objects.size(); i++) { |
| std::unique_ptr<AXRelatedNode> related_node = |
| RelatedNodeForAXObject(*(ax_objects[i].Get())); |
| if (related_node) |
| related_nodes->emplace_back(std::move(related_node)); |
| } |
| return AXValue::create() |
| .setType(value_type) |
| .setRelatedNodes(std::move(related_nodes)) |
| .build(); |
| } |
| |
| String ValueSourceType(ax::mojom::NameFrom name_from) { |
| namespace SourceType = protocol::Accessibility::AXValueSourceTypeEnum; |
| |
| switch (name_from) { |
| case ax::mojom::NameFrom::kAttribute: |
| case ax::mojom::NameFrom::kAttributeExplicitlyEmpty: |
| case ax::mojom::NameFrom::kTitle: |
| case ax::mojom::NameFrom::kValue: |
| return SourceType::Attribute; |
| case ax::mojom::NameFrom::kContents: |
| return SourceType::Contents; |
| case ax::mojom::NameFrom::kPlaceholder: |
| return SourceType::Placeholder; |
| case ax::mojom::NameFrom::kCaption: |
| case ax::mojom::NameFrom::kRelatedElement: |
| return SourceType::RelatedElement; |
| default: |
| return SourceType::Implicit; // TODO(aboxhall): what to do here? |
| } |
| } |
| |
| String NativeSourceType(AXTextSource native_source) { |
| namespace SourceType = protocol::Accessibility::AXValueNativeSourceTypeEnum; |
| |
| switch (native_source) { |
| case kAXTextFromNativeSVGDescElement: |
| return SourceType::Description; |
| case kAXTextFromNativeHTMLLabel: |
| return SourceType::Label; |
| case kAXTextFromNativeHTMLLabelFor: |
| return SourceType::Labelfor; |
| case kAXTextFromNativeHTMLLabelWrapped: |
| return SourceType::Labelwrapped; |
| case kAXTextFromNativeHTMLRubyAnnotation: |
| return SourceType::Rubyannotation; |
| case kAXTextFromNativeHTMLTableCaption: |
| return SourceType::Tablecaption; |
| case kAXTextFromNativeHTMLLegend: |
| return SourceType::Legend; |
| case kAXTextFromNativeTitleElement: |
| return SourceType::Title; |
| default: |
| return SourceType::Other; |
| } |
| } |
| |
| std::unique_ptr<AXValueSource> CreateValueSource(NameSource& name_source) { |
| String type = ValueSourceType(name_source.type); |
| std::unique_ptr<AXValueSource> value_source = |
| AXValueSource::create().setType(type).build(); |
| if (!name_source.related_objects.empty()) { |
| if ((*name_source.attribute) == html_names::kAriaLabelledbyAttr || |
| (*name_source.attribute) == html_names::kAriaLabeledbyAttr) { |
| std::unique_ptr<AXValue> attribute_value = CreateRelatedNodeListValue( |
| name_source.related_objects, AXValueTypeEnum::IdrefList); |
| if (!name_source.attribute_value.IsNull()) |
| attribute_value->setValue(protocol::StringValue::create( |
| name_source.attribute_value.GetString())); |
| value_source->setAttributeValue(std::move(attribute_value)); |
| } else if ((*name_source.attribute) == QualifiedName::Null()) { |
| value_source->setNativeSourceValue(CreateRelatedNodeListValue( |
| name_source.related_objects, AXValueTypeEnum::NodeList)); |
| } |
| } else if (!name_source.attribute_value.IsNull()) { |
| value_source->setAttributeValue(CreateValue(name_source.attribute_value)); |
| } |
| if (!name_source.text.IsNull()) |
| value_source->setValue( |
| CreateValue(name_source.text, AXValueTypeEnum::ComputedString)); |
| if ((*name_source.attribute) != QualifiedName::Null()) { |
| value_source->setAttribute(name_source.attribute->LocalName().GetString()); |
| } |
| if (name_source.superseded) |
| value_source->setSuperseded(true); |
| if (name_source.invalid) |
| value_source->setInvalid(true); |
| if (name_source.native_source != kAXTextFromNativeSourceUninitialized) |
| value_source->setNativeSource(NativeSourceType(name_source.native_source)); |
| return value_source; |
| } |
| |
| } // namespace blink |