Skip to content

Commit

Permalink
SVG-AAM Implementation: Expose SVGs with no accessible children as image
Browse files Browse the repository at this point in the history
Currently an SVG root element is treated as a document rather than an
image. Given that most SVGs on the web are for icons rather than complex
documents, this exposure might not make sense. There is an open issue in
the SVG-AAM spec's github suggesting that if an SVG has no accessible
children, it should be exposed as an image rather than as a document.
See w3c/svg-aam#12

AX-Relnotes: Expose SVGs with no accessible children as an image rather
than a document.

Bug: 231654
Change-Id: I1b05d713813ecc9546cd26b602b8f6526b41e861
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3195891
Reviewed-by: Aaron Leventhal <[email protected]>
Reviewed-by: Jochen Eisinger <[email protected]>
Reviewed-by: Nektarios Paisios <[email protected]>
Commit-Queue: Aaron Leventhal <[email protected]>
Cr-Commit-Position: refs/heads/main@{#930670}
NOKEYCHECK=True
GitOrigin-RevId: 2b46499fc2ba3e80f2b1f1e3f7fef64fa6be3c03
  • Loading branch information
joanmarie authored and copybara-github committed Oct 12, 2021
1 parent b27d0c5 commit 30cb356
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 11 deletions.
18 changes: 17 additions & 1 deletion blink/renderer/modules/accessibility/ax_object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1056,7 +1056,7 @@ AccessibleNode* AXObject::GetAccessibleNode() const {

void AXObject::Serialize(ui::AXNodeData* node_data,
ui::AXMode accessibility_mode) {
node_data->role = RoleValue();
node_data->role = ComputeFinalRoleForSerialization();
node_data->id = AXObjectID();

DCHECK(!IsDetached()) << "Do not serialize detached nodes: "
Expand Down Expand Up @@ -1727,6 +1727,22 @@ bool AXObject::IsVirtualObject() const {
return false;
}

ax::mojom::blink::Role AXObject::ComputeFinalRoleForSerialization() const {
// An SVG with no accessible children should be exposed as an image rather
// than a document. See https://github.com/w3c/svg-aam/issues/12.
// We do this check here for performance purposes: When
// AXLayoutObject::RoleFromLayoutObjectOrNode is called, that node's
// accessible children have not been calculated. Rather than force calculation
// there, wait until we have the full tree.
if (role_ == ax::mojom::blink::Role::kSvgRoot && !UnignoredChildCount())
return ax::mojom::blink::Role::kImage;

// TODO(accessibility): Consider moving the image vs. image map role logic
// here. Currently it is implemented in AXPlatformNode subclasses and thus
// not available to the InspectorAccessibilityAgent.
return role_;
}

ax::mojom::blink::Role AXObject::RoleValue() const {
return role_;
}
Expand Down
8 changes: 8 additions & 0 deletions blink/renderer/modules/accessibility/ax_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,14 @@ class MODULES_EXPORT AXObject : public GarbageCollected<AXObject> {
// Check object role or purpose.
ax::mojom::blink::Role RoleValue() const;

// This method is useful in cases where the final role exposed to ATs needs
// to change based on contextual information. For instance, an svgRoot should
// be exposed as an image if it lacks accessible children. Whether or not it
// has accessible children is not known at the time the role is assigned and
// may depend on whether or not a given platform includes children that other
// platforms ignore.
ax::mojom::blink::Role ComputeFinalRoleForSerialization() const;

// Returns true if this object is an ARIA text field, i.e. it is neither an
// <input> nor a <textarea>, but it has an ARIA role of textbox, searchbox or
// (on certain platforms) combobox.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ bool RoleAllowsSort(ax::mojom::Role role) {

void FillWidgetProperties(AXObject& ax_object,
protocol::Array<AXProperty>& properties) {
ax::mojom::Role role = ax_object.RoleValue();
ax::mojom::blink::Role role = ax_object.ComputeFinalRoleForSerialization();
String autocomplete = ax_object.AutoComplete();
if (!autocomplete.IsEmpty())
properties.emplace_back(
Expand Down Expand Up @@ -303,7 +303,7 @@ void FillWidgetProperties(AXObject& ax_object,

void FillWidgetStates(AXObject& ax_object,
protocol::Array<AXProperty>& properties) {
ax::mojom::Role role = ax_object.RoleValue();
ax::mojom::blink::Role role = ax_object.ComputeFinalRoleForSerialization();
const char* checked_prop_val = nullptr;
switch (ax_object.CheckedState()) {
case ax::mojom::CheckedState::kTrue:
Expand Down Expand Up @@ -695,7 +695,7 @@ std::unique_ptr<AXNode> InspectorAccessibilityAgent::BuildProtocolAXObject(
bool fetch_relatives,
std::unique_ptr<protocol::Array<AXNode>>& nodes,
AXObjectCacheImpl& cache) const {
ax::mojom::Role role = ax_object.RoleValue();
ax::mojom::blink::Role role = ax_object.ComputeFinalRoleForSerialization();
std::unique_ptr<AXNode> node_object =
AXNode::create()
.setNodeId(String::Number(ax_object.AXObjectID()))
Expand Down Expand Up @@ -957,7 +957,7 @@ void InspectorAccessibilityAgent::AddChildren(
namespace {

void setNameAndRole(const AXObject& ax_object, std::unique_ptr<AXNode>& node) {
ax::mojom::blink::Role role = ax_object.RoleValue();
ax::mojom::blink::Role role = ax_object.ComputeFinalRoleForSerialization();
node->setRole(CreateRoleNameValue(role));
AXObject::NameSources name_sources;
String computed_name = ax_object.GetName(&name_sources);
Expand Down Expand Up @@ -1021,7 +1021,8 @@ Response InspectorAccessibilityAgent::queryAXTree(

// if querying by role: skip if role of current object does not match.
if (role.isJust() &&
role.fromJust() != AXObject::RoleName(ax_object->RoleValue())) {
role.fromJust() !=
AXObject::RoleName(ax_object->ComputeFinalRoleForSerialization())) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ RootWebArea

RootWebArea
img
*SvgRoot
*img
{
childIds : <object>
domNode : svg
Expand Down Expand Up @@ -47,8 +47,8 @@ RootWebArea
properties : [
]
role : {
type : internalRole
value : SvgRoot
type : role
value : img
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -671,8 +671,8 @@ Tests name sources in images and figures.
}
]
role : {
type : internalRole
value : SvgRoot
type : role
value : img
}
}

0 comments on commit 30cb356

Please sign in to comment.