blob: f4bb1644ead762eeda2ae2dc22710f59f3d542ef [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#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"
#include "platform/runtime_enabled_features.h"
namespace blink {
using namespace HTMLNames;
namespace {
QualifiedName GetCorrespondingARIAAttribute(AOMStringProperty property) {
switch (property) {
case AOMStringProperty::kAutocomplete:
return aria_autocompleteAttr;
case AOMStringProperty::kChecked:
return aria_checkedAttr;
case AOMStringProperty::kCurrent:
return aria_currentAttr;
case AOMStringProperty::kHasPopUp:
return aria_haspopupAttr;
case AOMStringProperty::kInvalid:
return aria_invalidAttr;
case AOMStringProperty::kKeyShortcuts:
return aria_keyshortcutsAttr;
case AOMStringProperty::kLabel:
return aria_labelAttr;
case AOMStringProperty::kLive:
return aria_liveAttr;
case AOMStringProperty::kOrientation:
return aria_orientationAttr;
case AOMStringProperty::kPlaceholder:
return aria_placeholderAttr;
case AOMStringProperty::kPressed:
return aria_pressedAttr;
case AOMStringProperty::kRelevant:
return aria_relevantAttr;
case AOMStringProperty::kRole:
return roleAttr;
case AOMStringProperty::kRoleDescription:
return aria_roledescriptionAttr;
case AOMStringProperty::kSort:
return aria_sortAttr;
case AOMStringProperty::kValueText:
return aria_valuetextAttr;
}
NOTREACHED();
return g_null_name;
}
QualifiedName GetCorrespondingARIAAttribute(AOMRelationProperty property) {
switch (property) {
case AOMRelationProperty::kActiveDescendant:
return aria_activedescendantAttr;
break;
case AOMRelationProperty::kDetails:
return aria_detailsAttr;
break;
case AOMRelationProperty::kErrorMessage:
return aria_errormessageAttr;
break;
}
NOTREACHED();
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:
return aria_atomicAttr;
break;
case AOMBooleanProperty::kBusy:
return aria_busyAttr;
break;
case AOMBooleanProperty::kDisabled:
return aria_disabledAttr;
break;
case AOMBooleanProperty::kExpanded:
return aria_expandedAttr;
break;
case AOMBooleanProperty::kHidden:
return aria_hiddenAttr;
break;
case AOMBooleanProperty::kModal:
return aria_modalAttr;
break;
case AOMBooleanProperty::kMultiline:
return aria_multilineAttr;
break;
case AOMBooleanProperty::kMultiselectable:
return aria_multiselectableAttr;
break;
case AOMBooleanProperty::kReadOnly:
return aria_readonlyAttr;
break;
case AOMBooleanProperty::kRequired:
return aria_requiredAttr;
break;
case AOMBooleanProperty::kSelected:
return aria_selectedAttr;
break;
}
NOTREACHED();
return g_null_name;
}
QualifiedName GetCorrespondingARIAAttribute(AOMFloatProperty property) {
AtomicString attr_value;
switch (property) {
case AOMFloatProperty::kValueMax:
return aria_valuemaxAttr;
break;
case AOMFloatProperty::kValueMin:
return aria_valueminAttr;
break;
case AOMFloatProperty::kValueNow:
return aria_valuenowAttr;
break;
}
NOTREACHED();
return g_null_name;
}
QualifiedName GetCorrespondingARIAAttribute(AOMUIntProperty property) {
switch (property) {
case AOMUIntProperty::kColIndex:
return aria_colindexAttr;
break;
case AOMUIntProperty::kColSpan:
return aria_colspanAttr;
break;
case AOMUIntProperty::kLevel:
return aria_levelAttr;
break;
case AOMUIntProperty::kPosInSet:
return aria_posinsetAttr;
break;
case AOMUIntProperty::kRowIndex:
return aria_rowindexAttr;
break;
case AOMUIntProperty::kRowSpan:
return aria_rowspanAttr;
break;
}
NOTREACHED();
return g_null_name;
}
QualifiedName GetCorrespondingARIAAttribute(AOMIntProperty property) {
switch (property) {
case AOMIntProperty::kColCount:
return aria_colcountAttr;
break;
case AOMIntProperty::kRowCount:
return aria_rowcountAttr;
break;
case AOMIntProperty::kSetSize:
return aria_setsizeAttr;
break;
}
NOTREACHED();
return g_null_name;
}
} // namespace
AccessibleNode::AccessibleNode(Element* element)
: element_(element), document_(nullptr) {
DCHECK(RuntimeEnabledFeatures::AccessibilityObjectModelEnabled());
}
AccessibleNode::AccessibleNode(Document& document)
: element_(nullptr), document_(document) {
DCHECK(RuntimeEnabledFeatures::AccessibilityObjectModelEnabled());
}
AccessibleNode::~AccessibleNode() = default;
// static
AccessibleNode* AccessibleNode::Create(Document& document) {
return new AccessibleNode(document);
}
Document* AccessibleNode::GetDocument() const {
if (document_)
return document_;
if (element_)
return &element_->GetDocument();
NOTREACHED();
return nullptr;
}
const AtomicString& AccessibleNode::GetProperty(
AOMStringProperty property) const {
for (const auto& item : string_properties_) {
if (item.first == property && !item.second.IsNull())
return item.second;
}
return g_null_atom;
}
// static
AccessibleNode* AccessibleNode::GetProperty(Element* element,
AOMRelationProperty property) {
if (!element)
return nullptr;
if (AccessibleNode* accessible_node = element->ExistingAccessibleNode()) {
for (const auto& item : accessible_node->relation_properties_) {
if (item.first == property && item.second)
return item.second;
}
}
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,
const Vector<std::pair<P, T>>& properties,
T default_value) {
for (const auto& item : properties) {
if (item.first == property) {
is_null = false;
return item.second;
}
}
return default_value;
}
bool AccessibleNode::GetProperty(AOMBooleanProperty property,
bool& is_null) const {
is_null = true;
return FindPropertyValue(property, is_null, boolean_properties_, false);
}
// static
float AccessibleNode::GetProperty(Element* element,
AOMFloatProperty property,
bool& is_null) {
is_null = true;
float default_value = 0.0;
if (!element || !element->ExistingAccessibleNode())
return default_value;
return FindPropertyValue(property, is_null,
element->ExistingAccessibleNode()->float_properties_,
default_value);
}
// static
int32_t AccessibleNode::GetProperty(Element* element,
AOMIntProperty property,
bool& is_null) {
is_null = true;
int32_t default_value = 0;
if (!element || !element->ExistingAccessibleNode())
return default_value;
return FindPropertyValue(property, is_null,
element->ExistingAccessibleNode()->int_properties_,
default_value);
}
// static
uint32_t AccessibleNode::GetProperty(Element* element,
AOMUIntProperty property,
bool& is_null) {
is_null = true;
uint32_t default_value = 0;
if (!element || !element->ExistingAccessibleNode())
return default_value;
return FindPropertyValue(property, is_null,
element->ExistingAccessibleNode()->uint_properties_,
default_value);
}
bool AccessibleNode::IsUndefinedAttrValue(const AtomicString& value) {
return value.IsEmpty() || EqualIgnoringASCIICase(value, "undefined");
}
// static
const AtomicString& AccessibleNode::GetPropertyOrARIAAttribute(
Element* element,
AOMStringProperty property) {
if (!element)
return g_null_atom;
const bool is_token_attr = IsStringTokenProperty(property);
AccessibleNode* accessible_node = element->ExistingAccessibleNode();
if (accessible_node) {
const AtomicString& result = accessible_node->GetProperty(property);
if (!result.IsNull()) {
if (is_token_attr && IsUndefinedAttrValue(result))
return g_null_atom; // Property specifically set to undefined value.
return result;
}
}
// Fall back on the equivalent ARIA attribute.
QualifiedName attribute = GetCorrespondingARIAAttribute(property);
const AtomicString& attr_value = element->FastGetAttribute(attribute);
if (is_token_attr && IsUndefinedAttrValue(attr_value))
return g_null_atom; // Attribute not set or explicitly undefined.
return attr_value;
}
// static
Element* AccessibleNode::GetPropertyOrARIAAttribute(
Element* element,
AOMRelationProperty property) {
if (!element)
return nullptr;
if (AccessibleNode* result = GetProperty(element, property))
return result->element();
// Fall back on the equivalent ARIA attribute.
QualifiedName attribute = GetCorrespondingARIAAttribute(property);
AtomicString value = element->FastGetAttribute(attribute);
return element->GetTreeScope().getElementById(value);
}
// 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) {
is_null = true;
if (!element)
return false;
AccessibleNode* accessible_node = element->ExistingAccessibleNode();
if (accessible_node) {
bool result = accessible_node->GetProperty(property, is_null);
if (!is_null)
return result;
}
// Fall back on the equivalent ARIA attribute.
QualifiedName attribute = GetCorrespondingARIAAttribute(property);
AtomicString attr_value = element->FastGetAttribute(attribute);
is_null = IsUndefinedAttrValue(attr_value);
return !is_null && !EqualIgnoringASCIICase(attr_value, "false");
}
// static
float AccessibleNode::GetPropertyOrARIAAttribute(Element* element,
AOMFloatProperty property,
bool& is_null) {
is_null = true;
if (!element)
return 0.0;
float result = GetProperty(element, property, is_null);
if (!is_null)
return result;
// Fall back on the equivalent ARIA attribute.
QualifiedName attribute = GetCorrespondingARIAAttribute(property);
AtomicString attr_value = element->FastGetAttribute(attribute);
is_null = attr_value.IsNull();
return attr_value.ToFloat();
}
// static
uint32_t AccessibleNode::GetPropertyOrARIAAttribute(Element* element,
AOMUIntProperty property,
bool& is_null) {
is_null = true;
if (!element)
return 0;
int32_t result = GetProperty(element, property, is_null);
if (!is_null)
return result;
// Fall back on the equivalent ARIA attribute.
QualifiedName attribute = GetCorrespondingARIAAttribute(property);
AtomicString attr_value = element->FastGetAttribute(attribute);
is_null = attr_value.IsNull();
return attr_value.GetString().ToUInt();
}
// static
int32_t AccessibleNode::GetPropertyOrARIAAttribute(Element* element,
AOMIntProperty property,
bool& is_null) {
is_null = true;
if (!element)
return 0;
int32_t result = GetProperty(element, property, is_null);
if (!is_null)
return result;
// Fall back on the equivalent ARIA attribute.
QualifiedName attribute = GetCorrespondingARIAAttribute(property);
AtomicString attr_value = element->FastGetAttribute(attribute);
is_null = attr_value.IsNull();
return attr_value.ToInt();
}
void AccessibleNode::GetAllAOMProperties(
AOMPropertyClient* client,
HashSet<QualifiedName>& shadowed_aria_attributes) {
for (auto& item : string_properties_) {
client->AddStringProperty(item.first, item.second);
shadowed_aria_attributes.insert(GetCorrespondingARIAAttribute(item.first));
}
for (auto& item : boolean_properties_) {
client->AddBooleanProperty(item.first, item.second);
shadowed_aria_attributes.insert(GetCorrespondingARIAAttribute(item.first));
}
for (auto& item : float_properties_) {
client->AddFloatProperty(item.first, item.second);
shadowed_aria_attributes.insert(GetCorrespondingARIAAttribute(item.first));
}
for (auto& item : int_properties_) {
client->AddIntProperty(item.first, item.second);
shadowed_aria_attributes.insert(GetCorrespondingARIAAttribute(item.first));
}
for (auto& item : uint_properties_) {
client->AddUIntProperty(item.first, item.second);
shadowed_aria_attributes.insert(GetCorrespondingARIAAttribute(item.first));
}
for (auto& item : relation_properties_) {
if (!item.second)
continue;
client->AddRelationProperty(item.first, *item.second);
shadowed_aria_attributes.insert(GetCorrespondingARIAAttribute(item.first));
}
for (auto& item : relation_list_properties_) {
if (!item.second)
continue;
client->AddRelationListProperty(item.first, *item.second);
shadowed_aria_attributes.insert(GetCorrespondingARIAAttribute(item.first));
}
}
AccessibleNode* AccessibleNode::activeDescendant() const {
return GetProperty(element_, AOMRelationProperty::kActiveDescendant);
}
void AccessibleNode::setActiveDescendant(AccessibleNode* active_descendant) {
SetRelationProperty(AOMRelationProperty::kActiveDescendant,
active_descendant);
NotifyAttributeChanged(aria_activedescendantAttr);
}
bool AccessibleNode::atomic(bool& is_null) const {
return GetProperty(AOMBooleanProperty::kAtomic, is_null);
}
void AccessibleNode::setAtomic(bool atomic, bool is_null) {
SetBooleanProperty(AOMBooleanProperty::kAtomic, atomic, is_null);
NotifyAttributeChanged(aria_atomicAttr);
}
AtomicString AccessibleNode::autocomplete() const {
return GetProperty(AOMStringProperty::kAutocomplete);
}
void AccessibleNode::setAutocomplete(const AtomicString& autocomplete) {
SetStringProperty(AOMStringProperty::kAutocomplete, autocomplete);
NotifyAttributeChanged(aria_autocompleteAttr);
}
bool AccessibleNode::busy(bool& is_null) const {
return GetProperty(AOMBooleanProperty::kBusy, is_null);
}
void AccessibleNode::setBusy(bool busy, bool is_null) {
SetBooleanProperty(AOMBooleanProperty::kBusy, busy, is_null);
NotifyAttributeChanged(aria_busyAttr);
}
AtomicString AccessibleNode::checked() const {
return GetProperty(AOMStringProperty::kChecked);
}
void AccessibleNode::setChecked(const AtomicString& checked) {
SetStringProperty(AOMStringProperty::kChecked, checked);
NotifyAttributeChanged(aria_checkedAttr);
}
int32_t AccessibleNode::colCount(bool& is_null) const {
return GetProperty(element_, AOMIntProperty::kColCount, is_null);
}
void AccessibleNode::setColCount(int32_t col_count, bool is_null) {
SetIntProperty(AOMIntProperty::kColCount, col_count, is_null);
NotifyAttributeChanged(aria_colcountAttr);
}
uint32_t AccessibleNode::colIndex(bool& is_null) const {
return GetProperty(element_, AOMUIntProperty::kColIndex, is_null);
}
void AccessibleNode::setColIndex(uint32_t col_index, bool is_null) {
SetUIntProperty(AOMUIntProperty::kColIndex, col_index, is_null);
NotifyAttributeChanged(aria_colindexAttr);
}
uint32_t AccessibleNode::colSpan(bool& is_null) const {
return GetProperty(element_, AOMUIntProperty::kColSpan, is_null);
}
void AccessibleNode::setColSpan(uint32_t col_span, bool is_null) {
SetUIntProperty(AOMUIntProperty::kColSpan, col_span, 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(AOMStringProperty::kCurrent);
}
void AccessibleNode::setCurrent(const AtomicString& current) {
SetStringProperty(AOMStringProperty::kCurrent, current);
if (AXObjectCache* cache = GetAXObjectCache())
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);
}
void AccessibleNode::setDetails(AccessibleNode* details) {
SetRelationProperty(AOMRelationProperty::kDetails, details);
NotifyAttributeChanged(aria_detailsAttr);
}
bool AccessibleNode::disabled(bool& is_null) const {
return GetProperty(AOMBooleanProperty::kDisabled, is_null);
}
void AccessibleNode::setDisabled(bool disabled, bool is_null) {
SetBooleanProperty(AOMBooleanProperty::kDisabled, disabled, is_null);
NotifyAttributeChanged(aria_disabledAttr);
}
AccessibleNode* AccessibleNode::errorMessage() const {
return GetProperty(element_, AOMRelationProperty::kErrorMessage);
}
void AccessibleNode::setErrorMessage(AccessibleNode* error_message) {
SetRelationProperty(AOMRelationProperty::kErrorMessage, error_message);
NotifyAttributeChanged(aria_errormessageAttr);
}
bool AccessibleNode::expanded(bool& is_null) const {
return GetProperty(AOMBooleanProperty::kExpanded, is_null);
}
void AccessibleNode::setExpanded(bool expanded, bool is_null) {
SetBooleanProperty(AOMBooleanProperty::kExpanded, expanded, 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);
}
AtomicString AccessibleNode::hasPopUp() const {
return GetProperty(AOMStringProperty::kHasPopUp);
}
void AccessibleNode::setHasPopUp(const AtomicString& has_popup) {
SetStringProperty(AOMStringProperty::kHasPopUp, has_popup);
NotifyAttributeChanged(aria_haspopupAttr);
}
bool AccessibleNode::hidden(bool& is_null) const {
return GetProperty(AOMBooleanProperty::kHidden, is_null);
}
void AccessibleNode::setHidden(bool hidden, bool is_null) {
SetBooleanProperty(AOMBooleanProperty::kHidden, hidden, is_null);
NotifyAttributeChanged(aria_hiddenAttr);
}
AtomicString AccessibleNode::invalid() const {
return GetProperty(AOMStringProperty::kInvalid);
}
void AccessibleNode::setInvalid(const AtomicString& invalid) {
SetStringProperty(AOMStringProperty::kInvalid, invalid);
NotifyAttributeChanged(aria_invalidAttr);
}
AtomicString AccessibleNode::keyShortcuts() const {
return GetProperty(AOMStringProperty::kKeyShortcuts);
}
void AccessibleNode::setKeyShortcuts(const AtomicString& key_shortcuts) {
SetStringProperty(AOMStringProperty::kKeyShortcuts, key_shortcuts);
NotifyAttributeChanged(aria_keyshortcutsAttr);
}
AtomicString AccessibleNode::label() const {
return GetProperty(AOMStringProperty::kLabel);
}
void AccessibleNode::setLabel(const AtomicString& label) {
SetStringProperty(AOMStringProperty::kLabel, 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);
}
void AccessibleNode::setLevel(uint32_t level, bool is_null) {
SetUIntProperty(AOMUIntProperty::kLevel, level, is_null);
NotifyAttributeChanged(aria_levelAttr);
}
AtomicString AccessibleNode::live() const {
return GetProperty(AOMStringProperty::kLive);
}
void AccessibleNode::setLive(const AtomicString& live) {
SetStringProperty(AOMStringProperty::kLive, live);
NotifyAttributeChanged(aria_liveAttr);
}
bool AccessibleNode::modal(bool& is_null) const {
return GetProperty(AOMBooleanProperty::kModal, is_null);
}
void AccessibleNode::setModal(bool modal, bool is_null) {
SetBooleanProperty(AOMBooleanProperty::kModal, modal, is_null);
NotifyAttributeChanged(aria_modalAttr);
}
bool AccessibleNode::multiline(bool& is_null) const {
return GetProperty(AOMBooleanProperty::kMultiline, is_null);
}
void AccessibleNode::setMultiline(bool multiline, bool is_null) {
SetBooleanProperty(AOMBooleanProperty::kMultiline, multiline, is_null);
NotifyAttributeChanged(aria_multilineAttr);
}
bool AccessibleNode::multiselectable(bool& is_null) const {
return GetProperty(AOMBooleanProperty::kMultiselectable, is_null);
}
void AccessibleNode::setMultiselectable(bool multiselectable, bool is_null) {
SetBooleanProperty(AOMBooleanProperty::kMultiselectable, multiselectable,
is_null);
NotifyAttributeChanged(aria_multiselectableAttr);
}
AtomicString AccessibleNode::orientation() const {
return GetProperty(AOMStringProperty::kOrientation);
}
void AccessibleNode::setOrientation(const AtomicString& orientation) {
SetStringProperty(AOMStringProperty::kOrientation, 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(AOMStringProperty::kPlaceholder);
}
void AccessibleNode::setPlaceholder(const AtomicString& placeholder) {
SetStringProperty(AOMStringProperty::kPlaceholder, placeholder);
NotifyAttributeChanged(aria_placeholderAttr);
}
uint32_t AccessibleNode::posInSet(bool& is_null) const {
return GetProperty(element_, AOMUIntProperty::kPosInSet, is_null);
}
void AccessibleNode::setPosInSet(uint32_t pos_in_set, bool is_null) {
SetUIntProperty(AOMUIntProperty::kPosInSet, pos_in_set, is_null);
NotifyAttributeChanged(aria_posinsetAttr);
}
AtomicString AccessibleNode::pressed() const {
return GetProperty(AOMStringProperty::kPressed);
}
void AccessibleNode::setPressed(const AtomicString& pressed) {
SetStringProperty(AOMStringProperty::kPressed, pressed);
NotifyAttributeChanged(aria_pressedAttr);
}
bool AccessibleNode::readOnly(bool& is_null) const {
return GetProperty(AOMBooleanProperty::kReadOnly, is_null);
}
void AccessibleNode::setReadOnly(bool read_only, bool is_null) {
SetBooleanProperty(AOMBooleanProperty::kReadOnly, read_only, is_null);
NotifyAttributeChanged(aria_readonlyAttr);
}
AtomicString AccessibleNode::relevant() const {
return GetProperty(AOMStringProperty::kRelevant);
}
void AccessibleNode::setRelevant(const AtomicString& relevant) {
SetStringProperty(AOMStringProperty::kRelevant, relevant);
NotifyAttributeChanged(aria_relevantAttr);
}
bool AccessibleNode::required(bool& is_null) const {
return GetProperty(AOMBooleanProperty::kRequired, is_null);
}
void AccessibleNode::setRequired(bool required, bool is_null) {
SetBooleanProperty(AOMBooleanProperty::kRequired, required, is_null);
NotifyAttributeChanged(aria_requiredAttr);
}
AtomicString AccessibleNode::role() const {
return GetProperty(AOMStringProperty::kRole);
}
void AccessibleNode::setRole(const AtomicString& role) {
SetStringProperty(AOMStringProperty::kRole, role);
NotifyAttributeChanged(roleAttr);
}
AtomicString AccessibleNode::roleDescription() const {
return GetProperty(AOMStringProperty::kRoleDescription);
}
void AccessibleNode::setRoleDescription(const AtomicString& role_description) {
SetStringProperty(AOMStringProperty::kRoleDescription, role_description);
NotifyAttributeChanged(aria_roledescriptionAttr);
}
int32_t AccessibleNode::rowCount(bool& is_null) const {
return GetProperty(element_, AOMIntProperty::kRowCount, is_null);
}
void AccessibleNode::setRowCount(int32_t row_count, bool is_null) {
SetIntProperty(AOMIntProperty::kRowCount, row_count, is_null);
NotifyAttributeChanged(aria_rowcountAttr);
}
uint32_t AccessibleNode::rowIndex(bool& is_null) const {
return GetProperty(element_, AOMUIntProperty::kRowIndex, is_null);
}
void AccessibleNode::setRowIndex(uint32_t row_index, bool is_null) {
SetUIntProperty(AOMUIntProperty::kRowIndex, row_index, is_null);
NotifyAttributeChanged(aria_rowindexAttr);
}
uint32_t AccessibleNode::rowSpan(bool& is_null) const {
return GetProperty(element_, AOMUIntProperty::kRowSpan, is_null);
}
void AccessibleNode::setRowSpan(uint32_t row_span, bool is_null) {
SetUIntProperty(AOMUIntProperty::kRowSpan, row_span, is_null);
NotifyAttributeChanged(aria_rowspanAttr);
}
bool AccessibleNode::selected(bool& is_null) const {
return GetProperty(AOMBooleanProperty::kSelected, is_null);
}
void AccessibleNode::setSelected(bool selected, bool is_null) {
SetBooleanProperty(AOMBooleanProperty::kSelected, selected, is_null);
NotifyAttributeChanged(aria_selectedAttr);
}
int32_t AccessibleNode::setSize(bool& is_null) const {
return GetProperty(element_, AOMIntProperty::kSetSize, is_null);
}
void AccessibleNode::setSetSize(int32_t set_size, bool is_null) {
SetIntProperty(AOMIntProperty::kSetSize, set_size, is_null);
NotifyAttributeChanged(aria_setsizeAttr);
}
AtomicString AccessibleNode::sort() const {
return GetProperty(AOMStringProperty::kSort);
}
void AccessibleNode::setSort(const AtomicString& sort) {
SetStringProperty(AOMStringProperty::kSort, sort);
NotifyAttributeChanged(aria_sortAttr);
}
float AccessibleNode::valueMax(bool& is_null) const {
return GetProperty(element_, AOMFloatProperty::kValueMax, is_null);
}
void AccessibleNode::setValueMax(float value_max, bool is_null) {
SetFloatProperty(AOMFloatProperty::kValueMax, value_max, is_null);
NotifyAttributeChanged(aria_valuemaxAttr);
}
float AccessibleNode::valueMin(bool& is_null) const {
return GetProperty(element_, AOMFloatProperty::kValueMin, is_null);
}
void AccessibleNode::setValueMin(float value_min, bool is_null) {
SetFloatProperty(AOMFloatProperty::kValueMin, value_min, is_null);
NotifyAttributeChanged(aria_valueminAttr);
}
float AccessibleNode::valueNow(bool& is_null) const {
return GetProperty(element_, AOMFloatProperty::kValueNow, is_null);
}
void AccessibleNode::setValueNow(float value_now, bool is_null) {
SetFloatProperty(AOMFloatProperty::kValueNow, value_now, is_null);
NotifyAttributeChanged(aria_valuenowAttr);
}
AtomicString AccessibleNode::valueText() const {
return GetProperty(AOMStringProperty::kValueText);
}
void AccessibleNode::setValueText(const AtomicString& value_text) {
SetStringProperty(AOMStringProperty::kValueText, value_text);
NotifyAttributeChanged(aria_valuetextAttr);
}
void AccessibleNode::appendChild(AccessibleNode* child,
ExceptionState& exception_state) {
if (child->element()) {
exception_state.ThrowDOMException(
kInvalidAccessError,
"An AccessibleNode associated with an Element cannot be a child.");
return;
}
if (!GetDocument()->GetSecurityOrigin()->CanAccess(
child->GetDocument()->GetSecurityOrigin())) {
exception_state.ThrowDOMException(
kInvalidAccessError,
"Trying to access an AccessibleNode from a different origin.");
return;
}
children_.push_back(child);
if (AXObjectCache* cache = GetAXObjectCache())
cache->ChildrenChanged(this);
}
// These properties support a list of tokens, and "undefined"/"" is
// equivalent to not setting the attribute.
bool AccessibleNode::IsStringTokenProperty(AOMStringProperty property) {
switch (property) {
case AOMStringProperty::kAutocomplete:
case AOMStringProperty::kChecked:
case AOMStringProperty::kCurrent:
case AOMStringProperty::kHasPopUp:
case AOMStringProperty::kInvalid:
case AOMStringProperty::kLive:
case AOMStringProperty::kOrientation:
case AOMStringProperty::kPressed:
case AOMStringProperty::kRelevant:
case AOMStringProperty::kSort:
return true;
case AOMStringProperty::kKeyShortcuts:
case AOMStringProperty::kLabel:
case AOMStringProperty::kPlaceholder:
case AOMStringProperty::kRole: // Is token, but ""/"undefined" not
// supported.
case AOMStringProperty::kRoleDescription:
case AOMStringProperty::kValueText:
break;
}
return false;
}
const AtomicString& AccessibleNode::InterfaceName() const {
return EventTargetNames::AccessibleNode;
}
ExecutionContext* AccessibleNode::GetExecutionContext() const {
return element_->GetExecutionContext();
}
void AccessibleNode::SetStringProperty(AOMStringProperty property,
const AtomicString& value) {
for (auto& item : string_properties_) {
if (item.first == property) {
item.second = value;
return;
}
}
string_properties_.push_back(std::make_pair(property, value));
}
void AccessibleNode::SetRelationProperty(AOMRelationProperty property,
AccessibleNode* value) {
for (auto& item : relation_properties_) {
if (item.first == property) {
item.second = value;
return;
}
}
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,
bool is_null,
Vector<std::pair<P, T>>& properties) {
for (size_t i = 0; i < properties.size(); i++) {
auto& item = properties[i];
if (item.first == property) {
if (is_null)
properties.EraseAt(i);
else
item.second = value;
return;
}
}
properties.push_back(std::make_pair(property, value));
}
void AccessibleNode::SetBooleanProperty(AOMBooleanProperty property,
bool value,
bool is_null) {
SetProperty(property, value, is_null, boolean_properties_);
}
void AccessibleNode::SetIntProperty(AOMIntProperty property,
int32_t value,
bool is_null) {
SetProperty(property, value, is_null, int_properties_);
}
void AccessibleNode::SetUIntProperty(AOMUIntProperty property,
uint32_t value,
bool is_null) {
SetProperty(property, value, is_null, uint_properties_);
}
void AccessibleNode::SetFloatProperty(AOMFloatProperty property,
float value,
bool is_null) {
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
// the DOM attribute changed.
if (AXObjectCache* cache = GetAXObjectCache())
cache->HandleAttributeChanged(attribute, element_);
}
AXObjectCache* AccessibleNode::GetAXObjectCache() {
return GetDocument()->ExistingAXObjectCache();
}
void AccessibleNode::Trace(blink::Visitor* visitor) {
visitor->Trace(element_);
visitor->Trace(document_);
visitor->Trace(relation_properties_);
visitor->Trace(relation_list_properties_);
visitor->Trace(children_);
EventTargetWithInlineData::Trace(visitor);
}
} // namespace blink