Commit 0a2243c0 authored by dmazzoni's avatar dmazzoni Committed by Commit bot

Int and Float properties for Accessibility Object Model phase 1

BUG=680345

Review-Url: https://codereview.chromium.org/2894103002
Cr-Commit-Position: refs/heads/master@{#473999}
parent f494f865
<!DOCTYPE HTML>
<script src="../resources/gc.js"></script>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<!--
Accessibility Object Model
Explainer: https://github.com/WICG/aom/blob/master/explainer.md
Spec: https://wicg.github.io/aom/spec/
-->
<script>
if (window.internals)
internals.runtimeFlags.accessibilityObjectModelEnabled = true;
</script>
<div role="slider" id="slider" aria-valuenow="5"></div>
<script>
test(function(t) {
var node = document.getElementById("slider");
var axNode = accessibilityController.accessibleElementById("slider");
assert_equals(axNode.intValue, 5);
assert_equals(node.accessibleNode.valueNow, null);
node.accessibleNode.valueNow = 9;
assert_equals(axNode.intValue, 9);
node.accessibleNode.valueNow = null;
assert_equals(axNode.intValue, 5);
assert_equals(node.accessibleNode.valueNow, null);
}, "Boolean AOM properties do not reflect ARIA, and can be cleared.");
</script>
<div role="slider" id="slider2"></div>
<script>
test(function(t) {
var node = document.getElementById("slider2");
var axNode = accessibilityController.accessibleElementById("slider2");
assert_equals(axNode.intValue, 0);
assert_equals(axNode.minValue, 0);
assert_equals(axNode.maxValue, 0);
node.accessibleNode.valueNow = 33;
node.accessibleNode.valueMin = -100;
node.accessibleNode.valueMax = 100;;
assert_equals(axNode.intValue, 33);
assert_equals(axNode.minValue, -100);
assert_equals(axNode.maxValue, 100);
}, "Range values in accessible node.");
</script>
<!DOCTYPE HTML>
<script src="../resources/gc.js"></script>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<!--
Accessibility Object Model
Explainer: https://github.com/WICG/aom/blob/master/explainer.md
Spec: https://wicg.github.io/aom/spec/
-->
<script>
if (window.internals)
internals.runtimeFlags.accessibilityObjectModelEnabled = true;
</script>
<div role=heading id=heading>
<script>
test(function(t) {
var node = document.getElementById("heading");
var axNode = accessibilityController.accessibleElementById("heading");
node.accessibleNode.level = 3;
// For historical reasons intValue returns the heading level.
assert_equals(axNode.intValue, 3);
}, "AOM level property");
</script>
<div role=list>
<div role=listitem id="listitem"></div>
</div>
<script>
test(function(t) {
var node = document.getElementById("listitem");
var axNode = accessibilityController.accessibleElementById("listitem");
node.accessibleNode.posInSet = 9;
node.accessibleNode.setSize = 10;
assert_equals(axNode.posInSet, 9);
assert_equals(axNode.setSize, 10);
}, "AOM posInSet and setSize");
</script>
......@@ -20,6 +20,9 @@ interface AccessibleNode
getter autocomplete
getter busy
getter checked
getter colCount
getter colIndex
getter colSpan
getter current
getter disabled
getter expanded
......@@ -27,25 +30,37 @@ interface AccessibleNode
getter invalid
getter keyShortcuts
getter label
getter level
getter live
getter modal
getter multiline
getter multiselectable
getter orientation
getter placeholder
getter posInSet
getter readOnly
getter relevant
getter required
getter role
getter roleDescription
getter rowCount
getter rowIndex
getter rowSpan
getter selected
getter setSize
getter sort
getter valueMax
getter valueMin
getter valueNow
getter valueText
method constructor
setter atomic
setter autocomplete
setter busy
setter checked
setter colCount
setter colIndex
setter colSpan
setter current
setter disabled
setter expanded
......@@ -53,19 +68,28 @@ interface AccessibleNode
setter invalid
setter keyShortcuts
setter label
setter level
setter live
setter modal
setter multiline
setter multiselectable
setter orientation
setter placeholder
setter posInSet
setter readOnly
setter relevant
setter required
setter role
setter roleDescription
setter rowCount
setter rowIndex
setter rowSpan
setter selected
setter setSize
setter sort
setter valueMax
setter valueMin
setter valueNow
setter valueText
interface AmbientLightSensor : Sensor
attribute @@toStringTag
......
......@@ -20,6 +20,9 @@ interface AccessibleNode
getter autocomplete
getter busy
getter checked
getter colCount
getter colIndex
getter colSpan
getter current
getter disabled
getter expanded
......@@ -27,25 +30,37 @@ interface AccessibleNode
getter invalid
getter keyShortcuts
getter label
getter level
getter live
getter modal
getter multiline
getter multiselectable
getter orientation
getter placeholder
getter posInSet
getter readOnly
getter relevant
getter required
getter role
getter roleDescription
getter rowCount
getter rowIndex
getter rowSpan
getter selected
getter setSize
getter sort
getter valueMax
getter valueMin
getter valueNow
getter valueText
method constructor
setter atomic
setter autocomplete
setter busy
setter checked
setter colCount
setter colIndex
setter colSpan
setter current
setter disabled
setter expanded
......@@ -53,19 +68,28 @@ interface AccessibleNode
setter invalid
setter keyShortcuts
setter label
setter level
setter live
setter modal
setter multiline
setter multiselectable
setter orientation
setter placeholder
setter posInSet
setter readOnly
setter relevant
setter required
setter role
setter roleDescription
setter rowCount
setter rowIndex
setter rowSpan
setter selected
setter setSize
setter sort
setter valueMax
setter valueMin
setter valueNow
setter valueText
interface AmbientLightSensor : Sensor
attribute @@toStringTag
......
......@@ -35,24 +35,79 @@ const AtomicString& AccessibleNode::GetProperty(Element* element,
return g_null_atom;
}
template <typename P, typename T>
static T FindPropertyValue(P property,
bool& is_null,
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;
}
// static
bool AccessibleNode::GetProperty(Element* element,
AOMBooleanProperty property,
bool& is_null) {
is_null = true;
if (!element)
return false;
if (AccessibleNode* accessible_node = element->ExistingAccessibleNode()) {
for (const auto& item : accessible_node->boolean_properties_) {
if (item.first == property) {
is_null = false;
return item.second;
}
}
}
bool default_value = false;
if (!element || !element->ExistingAccessibleNode())
return default_value;
return FindPropertyValue(
property, is_null, element->ExistingAccessibleNode()->boolean_properties_,
default_value);
}
// 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 false;
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);
}
// static
......@@ -156,6 +211,105 @@ bool AccessibleNode::GetPropertyOrARIAAttribute(Element* element,
return EqualIgnoringASCIICase(attr_value, "true");
}
// 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.
AtomicString attr_value;
switch (property) {
case AOMFloatProperty::kValueMax:
attr_value = element->FastGetAttribute(aria_valuemaxAttr);
break;
case AOMFloatProperty::kValueMin:
attr_value = element->FastGetAttribute(aria_valueminAttr);
break;
case AOMFloatProperty::kValueNow:
attr_value = element->FastGetAttribute(aria_valuenowAttr);
break;
}
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.
AtomicString attr_value;
switch (property) {
case AOMUIntProperty::kColIndex:
attr_value = element->FastGetAttribute(aria_colindexAttr);
break;
case AOMUIntProperty::kColSpan:
attr_value = element->FastGetAttribute(aria_colspanAttr);
break;
case AOMUIntProperty::kLevel:
attr_value = element->FastGetAttribute(aria_levelAttr);
break;
case AOMUIntProperty::kPosInSet:
attr_value = element->FastGetAttribute(aria_posinsetAttr);
break;
case AOMUIntProperty::kRowIndex:
attr_value = element->FastGetAttribute(aria_rowindexAttr);
break;
case AOMUIntProperty::kRowSpan:
attr_value = element->FastGetAttribute(aria_rowspanAttr);
break;
}
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.
AtomicString attr_value;
switch (property) {
case AOMIntProperty::kColCount:
attr_value = element->FastGetAttribute(aria_colcountAttr);
break;
case AOMIntProperty::kRowCount:
attr_value = element->FastGetAttribute(aria_rowcountAttr);
break;
case AOMIntProperty::kSetSize:
attr_value = element->FastGetAttribute(aria_setsizeAttr);
break;
}
is_null = attr_value.IsNull();
return attr_value.ToInt();
}
bool AccessibleNode::atomic(bool& is_null) const {
return GetProperty(element_, AOMBooleanProperty::kAtomic, is_null);
}
......@@ -192,6 +346,33 @@ void AccessibleNode::setChecked(const AtomicString& 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);
}
AtomicString AccessibleNode::current() const {
return GetProperty(element_, AOMStringProperty::kCurrent);
}
......@@ -257,6 +438,15 @@ void AccessibleNode::setLabel(const AtomicString& label) {
NotifyAttributeChanged(aria_labelAttr);
}
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(element_, AOMStringProperty::kLive);
}
......@@ -312,6 +502,15 @@ void AccessibleNode::setPlaceholder(const AtomicString& 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);
}
bool AccessibleNode::readOnly(bool& is_null) const {
return GetProperty(element_, AOMBooleanProperty::kReadOnly, is_null);
}
......@@ -357,6 +556,33 @@ void AccessibleNode::setRoleDescription(const AtomicString& 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(element_, AOMBooleanProperty::kSelected, is_null);
}
......@@ -366,6 +592,15 @@ void AccessibleNode::setSelected(bool selected, bool 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(element_, AOMStringProperty::kSort);
}
......@@ -375,6 +610,33 @@ void AccessibleNode::setSort(const AtomicString& 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(element_, AOMStringProperty::kValueText);
}
......@@ -396,21 +658,47 @@ void AccessibleNode::SetStringProperty(AOMStringProperty property,
string_properties_.push_back(std::make_pair(property, value));
}
void AccessibleNode::SetBooleanProperty(AOMBooleanProperty property,
bool value,
bool is_null) {
for (size_t i = 0; i < boolean_properties_.size(); i++) {
auto& item = boolean_properties_[i];
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)
boolean_properties_.erase(i);
properties.erase(i);
else
item.second = value;
return;
}
}
boolean_properties_.push_back(std::make_pair(property, value));
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::NotifyAttributeChanged(
......
......@@ -52,6 +52,23 @@ enum class AOMBooleanProperty {
kSelected
};
// All of the properties of AccessibleNode that have an unsigned integer type.
enum class AOMUIntProperty {
kColIndex,
kColSpan,
kLevel,
kPosInSet,
kRowIndex,
kRowSpan,
};
// All of the properties of AccessibleNode that have a signed integer type.
// (These all allow the value -1.)
enum class AOMIntProperty { kColCount, kRowCount, kSetSize };
// All of the properties of AccessibleNode that have a floating-point type.
enum class AOMFloatProperty { kValueMax, kValueMin, kValueNow };
// Accessibility Object Model node
// Explainer: https://github.com/WICG/aom/blob/master/explainer.md
// Spec: https://wicg.github.io/aom/spec/
......@@ -67,10 +84,13 @@ class CORE_EXPORT AccessibleNode
// Returns the given string property if the Element has an AccessibleNode.
static const AtomicString& GetProperty(Element*, AOMStringProperty);
// Returns the value of the given boolean property if the
// Returns the value of the given property if the
// Element has an AccessibleNode. Sets |isNull| if the property and
// attribute are not present.
static bool GetProperty(Element*, AOMBooleanProperty, bool& is_null);
static float GetProperty(Element*, AOMFloatProperty, bool& is_null);
static int32_t GetProperty(Element*, AOMIntProperty, bool& is_null);
static uint32_t GetProperty(Element*, AOMUIntProperty, bool& is_null);
// Returns the value of the given string property if the
// Element has an AccessibleNode, otherwise returns the equivalent
......@@ -78,36 +98,54 @@ class CORE_EXPORT AccessibleNode
static const AtomicString& GetPropertyOrARIAAttribute(Element*,
AOMStringProperty);
// Returns the value of the given boolean property if the
// Returns the value of the given property if the
// Element has an AccessibleNode, otherwise returns the equivalent
// ARIA attribute. Sets |isNull| if the property and attribute are not
// present.
static bool GetPropertyOrARIAAttribute(Element*,
AOMBooleanProperty,
bool& is_null);
bool atomic(bool&) const;
static float GetPropertyOrARIAAttribute(Element*,
AOMFloatProperty,
bool& is_null);
static int32_t GetPropertyOrARIAAttribute(Element*,
AOMIntProperty,
bool& is_null);
static uint32_t GetPropertyOrARIAAttribute(Element*,
AOMUIntProperty,
bool& is_null);
bool atomic(bool& is_null) const;
void setAtomic(bool, bool is_null);
AtomicString autocomplete() const;
void setAutocomplete(const AtomicString&);
bool busy(bool&) const;
bool busy(bool& is_null) const;
void setBusy(bool, bool is_null);
AtomicString checked() const;
void setChecked(const AtomicString&);
int32_t colCount(bool& is_null) const;
void setColCount(int32_t, bool is_null);
uint32_t colIndex(bool& is_null) const;
void setColIndex(uint32_t, bool is_null);
uint32_t colSpan(bool& is_null) const;
void setColSpan(uint32_t, bool is_null);
AtomicString current() const;
void setCurrent(const AtomicString&);
bool disabled(bool&) const;
bool disabled(bool& is_null) const;
void setDisabled(bool, bool is_null);
bool expanded(bool&) const;
bool expanded(bool& is_null) const;
void setExpanded(bool, bool is_null);
bool hidden(bool&) const;
bool hidden(bool& is_null) const;
void setHidden(bool, bool is_null);
AtomicString invalid() const;
......@@ -119,16 +157,19 @@ class CORE_EXPORT AccessibleNode
AtomicString label() const;
void setLabel(const AtomicString&);
uint32_t level(bool& is_null) const;
void setLevel(uint32_t, bool is_null);
AtomicString live() const;
void setLive(const AtomicString&);
bool modal(bool&) const;
bool modal(bool& is_null) const;
void setModal(bool, bool is_null);
bool multiline(bool&) const;
bool multiline(bool& is_null) const;
void setMultiline(bool, bool is_null);
bool multiselectable(bool&) const;
bool multiselectable(bool& is_null) const;
void setMultiselectable(bool, bool is_null);
AtomicString orientation() const;
......@@ -137,13 +178,16 @@ class CORE_EXPORT AccessibleNode
AtomicString placeholder() const;
void setPlaceholder(const AtomicString&);
bool readOnly(bool&) const;
uint32_t posInSet(bool& is_null) const;
void setPosInSet(uint32_t, bool is_null);
bool readOnly(bool& is_null) const;
void setReadOnly(bool, bool is_null);
AtomicString relevant() const;
void setRelevant(const AtomicString&);
bool required(bool&) const;
bool required(bool& is_null) const;
void setRequired(bool, bool is_null);
AtomicString role() const;
......@@ -152,12 +196,33 @@ class CORE_EXPORT AccessibleNode
AtomicString roleDescription() const;
void setRoleDescription(const AtomicString&);
bool selected(bool&) const;
int32_t rowCount(bool& is_null) const;
void setRowCount(int32_t, bool is_null);
uint32_t rowIndex(bool& is_null) const;
void setRowIndex(uint32_t, bool is_null);
uint32_t rowSpan(bool& is_null) const;
void setRowSpan(uint32_t, bool is_null);
bool selected(bool& is_null) const;
void setSelected(bool, bool is_null);
int32_t setSize(bool& is_null) const;
void setSetSize(int32_t, bool is_null);
AtomicString sort() const;
void setSort(const AtomicString&);
float valueMax(bool& is_null) const;
void setValueMax(float, bool is_null);
float valueMin(bool& is_null) const;
void setValueMin(float, bool is_null);
float valueNow(bool& is_null) const;
void setValueNow(float, bool is_null);
AtomicString valueText() const;
void setValueText(const AtomicString&);
......@@ -166,11 +231,17 @@ class CORE_EXPORT AccessibleNode
private:
void SetStringProperty(AOMStringProperty, const AtomicString&);
void SetBooleanProperty(AOMBooleanProperty, bool value, bool is_null);
void SetFloatProperty(AOMFloatProperty, float value, bool is_null);
void SetUIntProperty(AOMUIntProperty, uint32_t value, bool is_null);
void SetIntProperty(AOMIntProperty, int32_t value, bool is_null);
void NotifyAttributeChanged(const blink::QualifiedName&);
AXObjectCache* GetAXObjectCache();
Vector<std::pair<AOMStringProperty, AtomicString>> string_properties_;
Vector<std::pair<AOMBooleanProperty, bool>> boolean_properties_;
Vector<std::pair<AOMFloatProperty, float>> float_properties_;
Vector<std::pair<AOMIntProperty, int32_t>> int_properties_;
Vector<std::pair<AOMUIntProperty, uint32_t>> uint_properties_;
// This object's owner Element.
Member<Element> element_;
......
......@@ -12,6 +12,9 @@
attribute DOMString? autocomplete;
attribute boolean? busy;
attribute DOMString? checked;
attribute long? colCount;
attribute unsigned long? colIndex;
attribute unsigned long? colSpan;
attribute DOMString? current;
attribute boolean? disabled;
attribute boolean? expanded;
......@@ -19,18 +22,27 @@
attribute DOMString? invalid;
attribute DOMString? keyShortcuts;
attribute DOMString? label;
attribute unsigned long? level;
attribute DOMString? live;
attribute boolean? modal;
attribute boolean? multiline;
attribute boolean? multiselectable;
attribute DOMString? orientation;
attribute DOMString? placeholder;
attribute unsigned long? posInSet;
attribute boolean? readOnly;
attribute DOMString? relevant;
attribute boolean? required;
attribute DOMString? role;
attribute DOMString? roleDescription;
attribute long? rowCount;
attribute unsigned long? rowIndex;
attribute unsigned long? rowSpan;
attribute boolean? selected;
attribute long? setSize;
attribute DOMString? sort;
attribute double? valueMax;
attribute double? valueMin;
attribute double? valueNow;
attribute DOMString? valueText;
};
......@@ -1334,9 +1334,8 @@ int AXNodeObject::HeadingLevel() const {
return 0;
if (RoleValue() == kHeadingRole) {
String level_str = GetAttribute(aria_levelAttr);
if (!level_str.IsEmpty()) {
int level = level_str.ToInt();
uint32_t level;
if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kLevel, level)) {
if (level >= 1 && level <= 9)
return level;
return 1;
......@@ -1369,15 +1368,13 @@ int AXNodeObject::HeadingLevel() const {
}
unsigned AXNodeObject::HierarchicalLevel() const {
Node* node = this->GetNode();
if (!node || !node->IsElementNode())
Element* element = GetElement();
if (!element)
return 0;
Element* element = ToElement(node);
String level_str = element->getAttribute(aria_levelAttr);
if (!level_str.IsEmpty()) {
int level = level_str.ToInt();
if (level > 0)
uint32_t level;
if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kLevel, level)) {
if (level >= 1 && level <= 9)
return level;
return 1;
}
......@@ -1388,7 +1385,7 @@ unsigned AXNodeObject::HierarchicalLevel() const {
// Hierarchy leveling starts at 1, to match the aria-level spec.
// We measure tree hierarchy by the number of groups that the item is within.
unsigned level = 1;
level = 1;
for (AXObjectImpl* parent = ParentObject(); parent;
parent = parent->ParentObject()) {
AccessibilityRole parent_role = parent->RoleValue();
......@@ -1659,13 +1656,9 @@ InvalidState AXNodeObject::GetInvalidState() const {
int AXNodeObject::PosInSet() const {
if (SupportsSetSizeAndPosInSet()) {
String pos_in_set_str = GetAttribute(aria_posinsetAttr);
if (!pos_in_set_str.IsEmpty()) {
int pos_in_set = pos_in_set_str.ToInt();
if (pos_in_set > 0)
return pos_in_set;
return 1;
}
uint32_t pos_in_set;
if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kPosInSet, pos_in_set))
return pos_in_set;
return AXObjectImpl::IndexInParent() + 1;
}
......@@ -1675,13 +1668,9 @@ int AXNodeObject::PosInSet() const {
int AXNodeObject::SetSize() const {
if (SupportsSetSizeAndPosInSet()) {
String set_size_str = GetAttribute(aria_setsizeAttr);
if (!set_size_str.IsEmpty()) {
int set_size = set_size_str.ToInt();
if (set_size > 0)
return set_size;
return 1;
}
int32_t set_size;
if (HasAOMPropertyOrARIAAttribute(AOMIntProperty::kSetSize, set_size))
return set_size;
if (ParentObject()) {
const auto& siblings = ParentObject()->Children();
......@@ -1708,8 +1697,9 @@ String AXNodeObject::ValueDescription() const {
}
float AXNodeObject::ValueForRange() const {
if (HasAttribute(aria_valuenowAttr))
return GetAttribute(aria_valuenowAttr).ToFloat();
float value_now;
if (HasAOMPropertyOrARIAAttribute(AOMFloatProperty::kValueNow, value_now))
return value_now;
if (IsNativeSlider())
return toHTMLInputElement(*GetNode()).valueAsNumber();
......@@ -1721,8 +1711,9 @@ float AXNodeObject::ValueForRange() const {
}
float AXNodeObject::MaxValueForRange() const {
if (HasAttribute(aria_valuemaxAttr))
return GetAttribute(aria_valuemaxAttr).ToFloat();
float value_max;
if (HasAOMPropertyOrARIAAttribute(AOMFloatProperty::kValueMax, value_max))
return value_max;
if (IsNativeSlider())
return toHTMLInputElement(*GetNode()).Maximum();
......@@ -1734,8 +1725,9 @@ float AXNodeObject::MaxValueForRange() const {
}
float AXNodeObject::MinValueForRange() const {
if (HasAttribute(aria_valueminAttr))
return GetAttribute(aria_valueminAttr).ToFloat();
float value_min;
if (HasAOMPropertyOrARIAAttribute(AOMFloatProperty::kValueMin, value_min))
return value_min;
if (IsNativeSlider())
return toHTMLInputElement(*GetNode()).Minimum();
......
......@@ -421,6 +421,42 @@ bool AXObjectImpl::AOMPropertyOrARIAAttributeIsFalse(
return false;
}
bool AXObjectImpl::HasAOMPropertyOrARIAAttribute(AOMUIntProperty property,
uint32_t& result) const {
Element* element = this->GetElement();
if (!element)
return false;
bool is_null = true;
result =
AccessibleNode::GetPropertyOrARIAAttribute(element, property, is_null);
return !is_null;
}
bool AXObjectImpl::HasAOMPropertyOrARIAAttribute(AOMIntProperty property,
int32_t& result) const {
Element* element = this->GetElement();
if (!element)
return false;
bool is_null = true;
result =
AccessibleNode::GetPropertyOrARIAAttribute(element, property, is_null);
return !is_null;
}
bool AXObjectImpl::HasAOMPropertyOrARIAAttribute(AOMFloatProperty property,
float& result) const {
Element* element = this->GetElement();
if (!element)
return false;
bool is_null = true;
result =
AccessibleNode::GetPropertyOrARIAAttribute(element, property, is_null);
return !is_null;
}
bool AXObjectImpl::IsARIATextControl() const {
return AriaRoleAttribute() == kTextFieldRole ||
AriaRoleAttribute() == kSearchBoxRole ||
......
......@@ -57,6 +57,9 @@ class ScrollableArea;
enum class AOMBooleanProperty;
enum class AOMStringProperty;
enum class AOMUIntProperty;
enum class AOMIntProperty;
enum class AOMFloatProperty;
typedef unsigned AXID;
......@@ -353,6 +356,9 @@ class MODULES_EXPORT AXObjectImpl
bool HasAOMPropertyOrARIAAttribute(AOMBooleanProperty, bool& result) const;
bool AOMPropertyOrARIAAttributeIsTrue(AOMBooleanProperty) const;
bool AOMPropertyOrARIAAttributeIsFalse(AOMBooleanProperty) const;
bool HasAOMPropertyOrARIAAttribute(AOMUIntProperty, uint32_t& result) const;
bool HasAOMPropertyOrARIAAttribute(AOMIntProperty, int32_t& result) const;
bool HasAOMPropertyOrARIAAttribute(AOMFloatProperty, float& result) const;
virtual void GetSparseAXAttributes(AXSparseAttributeClient&) const {}
......
......@@ -20,6 +20,7 @@
#include "modules/accessibility/AXProgressIndicator.h"
#include "core/dom/AccessibleNode.h"
#include "core/html/HTMLProgressElement.h"
#include "core/layout/LayoutProgress.h"
#include "modules/accessibility/AXObjectCacheImpl.h"
......@@ -51,8 +52,9 @@ bool AXProgressIndicator::ComputeAccessibilityIsIgnored(
}
float AXProgressIndicator::ValueForRange() const {
if (HasAttribute(aria_valuenowAttr))
return GetAttribute(aria_valuenowAttr).ToFloat();
float value_now;
if (HasAOMPropertyOrARIAAttribute(AOMFloatProperty::kValueNow, value_now))
return value_now;
if (GetProgressElement()->position() >= 0)
return clampTo<float>(GetProgressElement()->value());
......@@ -61,15 +63,17 @@ float AXProgressIndicator::ValueForRange() const {
}
float AXProgressIndicator::MaxValueForRange() const {
if (HasAttribute(aria_valuemaxAttr))
return GetAttribute(aria_valuemaxAttr).ToFloat();
float value_max;
if (HasAOMPropertyOrARIAAttribute(AOMFloatProperty::kValueMax, value_max))
return value_max;
return clampTo<float>(GetProgressElement()->max());
}
float AXProgressIndicator::MinValueForRange() const {
if (HasAttribute(aria_valueminAttr))
return GetAttribute(aria_valueminAttr).ToFloat();
float value_min;
if (HasAOMPropertyOrARIAAttribute(AOMFloatProperty::kValueMin, value_min))
return value_min;
return 0.0f;
}
......
......@@ -5,6 +5,7 @@
#include "modules/accessibility/AXRadioInput.h"
#include "core/InputTypeNames.h"
#include "core/dom/AccessibleNode.h"
#include "core/html/HTMLInputElement.h"
#include "core/html/forms/RadioInputType.h"
#include "core/layout/LayoutObject.h"
......@@ -65,14 +66,16 @@ HTMLInputElement* AXRadioInput::FindFirstRadioButtonInGroup(
}
int AXRadioInput::PosInSet() const {
if (HasAttribute(aria_posinsetAttr))
return GetAttribute(aria_posinsetAttr).ToInt();
uint32_t pos_in_set;
if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kPosInSet, pos_in_set))
return pos_in_set;
return pos_in_set_;
}
int AXRadioInput::SetSize() const {
if (HasAttribute(aria_setsizeAttr))
return GetAttribute(aria_setsizeAttr).ToInt();
int32_t set_size;
if (HasAOMPropertyOrARIAAttribute(AOMIntProperty::kSetSize, set_size))
return set_size;
return set_size_;
}
......
......@@ -28,6 +28,7 @@
#include "modules/accessibility/AXTable.h"
#include "core/dom/AccessibleNode.h"
#include "core/dom/ElementTraversal.h"
#include "core/editing/EditingUtilities.h"
#include "core/html/HTMLCollection.h"
......@@ -496,40 +497,36 @@ void AXTable::RowHeaders(AXObjectVector& headers) {
}
int AXTable::AriaColumnCount() {
if (!HasAttribute(aria_colcountAttr))
int32_t col_count;
if (!HasAOMPropertyOrARIAAttribute(AOMIntProperty::kColCount, col_count))
return 0;
const AtomicString& col_count_value = GetAttribute(aria_colcountAttr);
int col_count_int = col_count_value.ToInt();
if (col_count_int > (int)ColumnCount())
return col_count_int;
if (col_count > static_cast<int>(ColumnCount()))
return col_count;
// Spec says that if all of the columns are present in the DOM, it
// is not necessary to set this attribute as the user agent can
// automatically calculate the total number of columns.
// It returns 0 in order not to set this attribute.
if (col_count_int == (int)ColumnCount() || col_count_int != -1)
if (col_count == static_cast<int>(ColumnCount()) || col_count != -1)
return 0;
return -1;
}
int AXTable::AriaRowCount() {
if (!HasAttribute(aria_rowcountAttr))
int32_t row_count;
if (!HasAOMPropertyOrARIAAttribute(AOMIntProperty::kRowCount, row_count))
return 0;
const AtomicString& row_count_value = GetAttribute(aria_rowcountAttr);
int row_count_int = row_count_value.ToInt();
if (row_count_int > (int)RowCount())
return row_count_int;
if (row_count > static_cast<int>(RowCount()))
return row_count;
// Spec says that if all of the rows are present in the DOM, it is
// not necessary to set this attribute as the user agent can
// automatically calculate the total number of rows.
// It returns 0 in order not to set this attribute.
if (row_count_int == (int)RowCount() || row_count_int != -1)
if (row_count == (int)RowCount() || row_count != -1)
return 0;
// In the spec, -1 explicitly means an unknown number of rows.
......
......@@ -104,9 +104,11 @@ bool AXTableCell::IsTableCell() const {
}
unsigned AXTableCell::AriaColumnIndex() const {
const AtomicString& col_index = GetAttribute(aria_colindexAttr);
if (col_index.ToInt() >= 1)
return col_index.ToInt();
uint32_t col_index;
if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kColIndex, col_index) &&
col_index >= 1) {
return col_index;
}
AXObjectImpl* parent = ParentObjectUnignored();
if (!parent || !parent->IsTableRow())
......@@ -116,9 +118,11 @@ unsigned AXTableCell::AriaColumnIndex() const {
}
unsigned AXTableCell::AriaRowIndex() const {
const AtomicString& row_index = GetAttribute(aria_rowindexAttr);
if (row_index.ToInt() >= 1)
return row_index.ToInt();
uint32_t row_index;
if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kRowIndex, row_index) &&
row_index >= 1) {
return row_index;
}
AXObjectImpl* parent = ParentObjectUnignored();
if (!parent || !parent->IsTableRow())
......
......@@ -70,7 +70,7 @@ class MODULES_EXPORT AXTableCell : public AXLayoutObject {
bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const final;
unsigned aria_col_index_from_row_;
unsigned aria_col_index_from_row_ = 0;
};
DEFINE_AX_OBJECT_TYPE_CASTS(AXTableCell, IsTableCell());
......
......@@ -28,6 +28,7 @@
#include "modules/accessibility/AXTableRow.h"
#include "core/dom/AccessibleNode.h"
#include "core/layout/LayoutObject.h"
#include "modules/accessibility/AXObjectCacheImpl.h"
#include "modules/accessibility/AXTableCell.h"
......@@ -114,17 +115,21 @@ AXObjectImpl* AXTableRow::HeaderObject() {
}
unsigned AXTableRow::AriaColumnIndex() const {
const AtomicString& col_index_value = GetAttribute(aria_colindexAttr);
if (col_index_value.ToInt() >= 1)
return col_index_value.ToInt();
uint32_t col_index;
if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kColIndex, col_index) &&
col_index >= 1) {
return col_index;
}
return 0;
}
unsigned AXTableRow::AriaRowIndex() const {
const AtomicString& row_index_value = GetAttribute(aria_rowindexAttr);
if (row_index_value.ToInt() >= 1)
return row_index_value.ToInt();
uint32_t row_index;
if (HasAOMPropertyOrARIAAttribute(AOMUIntProperty::kRowIndex, row_index) &&
row_index >= 1) {
return row_index;
}
return 0;
}
......
......@@ -5,6 +5,9 @@
#include "core/dom/AccessibleNode.h"
#include "core/html/HTMLBodyElement.h"
#include "modules/accessibility/AXObjectCacheImpl.h"
#include "modules/accessibility/AXTable.h"
#include "modules/accessibility/AXTableCell.h"
#include "modules/accessibility/AXTableRow.h"
#include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
#include "web/tests/sim/SimRequest.h"
#include "web/tests/sim/SimTest.h"
......@@ -131,6 +134,104 @@ TEST_F(AccessibilityObjectModelTest, AOMPropertiesCanBeCleared) {
EXPECT_FALSE(axButton->IsEnabled());
}
TEST_F(AccessibilityObjectModelTest, RangeProperties) {
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Complete("<div role=slider id=slider>");
auto* slider = GetDocument().getElementById("slider");
ASSERT_NE(nullptr, slider);
slider->accessibleNode()->setValueMin(-0.5, false);
slider->accessibleNode()->setValueMax(0.5, false);
slider->accessibleNode()->setValueNow(0.1, false);
auto* cache = AXObjectCache();
ASSERT_NE(nullptr, cache);
auto* ax_slider = cache->GetOrCreate(slider);
EXPECT_EQ(-0.5f, ax_slider->MinValueForRange());
EXPECT_EQ(0.5f, ax_slider->MaxValueForRange());
EXPECT_EQ(0.1f, ax_slider->ValueForRange());
}
TEST_F(AccessibilityObjectModelTest, Level) {
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Complete("<div role=heading id=heading>");
auto* heading = GetDocument().getElementById("heading");
ASSERT_NE(nullptr, heading);
heading->accessibleNode()->setLevel(5, false);
auto* cache = AXObjectCache();
ASSERT_NE(nullptr, cache);
auto* ax_heading = cache->GetOrCreate(heading);
EXPECT_EQ(5, ax_heading->HeadingLevel());
}
TEST_F(AccessibilityObjectModelTest, ListItem) {
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Complete(
"<div role=list><div role=listitem id=listitem></div></div>");
auto* listitem = GetDocument().getElementById("listitem");
ASSERT_NE(nullptr, listitem);
listitem->accessibleNode()->setPosInSet(9, false);
listitem->accessibleNode()->setSetSize(10, false);
auto* cache = AXObjectCache();
ASSERT_NE(nullptr, cache);
auto* ax_listitem = cache->GetOrCreate(listitem);
EXPECT_EQ(9, ax_listitem->PosInSet());
EXPECT_EQ(10, ax_listitem->SetSize());
}
TEST_F(AccessibilityObjectModelTest, Grid) {
SimRequest main_resource("https://example.com/", "text/html");
LoadURL("https://example.com/");
main_resource.Complete(
"<div role=grid id=grid>"
" <div role=row id=row>"
" <div role=gridcell id=cell></div>"
" <div role=gridcell id=cell2></div>"
" </div>"
"</div>");
auto* grid = GetDocument().getElementById("grid");
ASSERT_NE(nullptr, grid);
grid->accessibleNode()->setColCount(16, false);
grid->accessibleNode()->setRowCount(9, false);
auto* row = GetDocument().getElementById("row");
ASSERT_NE(nullptr, row);
row->accessibleNode()->setColIndex(8, false);
row->accessibleNode()->setRowIndex(5, false);
auto* cell = GetDocument().getElementById("cell");
auto* cell2 = GetDocument().getElementById("cell2");
ASSERT_NE(nullptr, cell2);
cell2->accessibleNode()->setColIndex(10, false);
cell2->accessibleNode()->setRowIndex(7, false);
auto* cache = AXObjectCache();
ASSERT_NE(nullptr, cache);
auto* ax_grid = static_cast<AXTable*>(cache->GetOrCreate(grid));
EXPECT_EQ(16, ax_grid->AriaColumnCount());
EXPECT_EQ(9, ax_grid->AriaRowCount());
auto* ax_cell = static_cast<AXTableCell*>(cache->GetOrCreate(cell));
EXPECT_TRUE(ax_cell->IsTableCell());
EXPECT_EQ(8U, ax_cell->AriaColumnIndex());
EXPECT_EQ(5U, ax_cell->AriaRowIndex());
auto* ax_cell2 = static_cast<AXTableCell*>(cache->GetOrCreate(cell2));
EXPECT_TRUE(ax_cell2->IsTableCell());
EXPECT_EQ(10U, ax_cell2->AriaColumnIndex());
EXPECT_EQ(7U, ax_cell2->AriaRowIndex());
}
} // namespace
} // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment