From 6f8cf4704ff54d59ddc3fdefff1eade38cb4491f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Wed, 20 Oct 2021 13:25:17 +0000 Subject: [PATCH] Map MathML elements to specific roles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL introduces the minimal number of MathML roles so that one can implement role and attribute mapping for ATK and AX API [1]. Exact roles for some tags are still being discussed on the spec side and might change in the future [2] [3] [4] [5] [6]. On Windows and Android platforms, math roles is a bit undefined and so some dummy role mapping is used right now. Node tests are added to cover all elements of MathML Core. These new tests also verify that the MathML element tags are exposed as an AtkObject attribute. [1] https://w3c.github.io/mathml-aam/ [2] https://github.com/w3c/mathml-aam/issues/9 [3] https://github.com/w3c/mathml-aam/issues/11 [4] https://github.com/w3c/mathml-aam/issues/12 [5] https://github.com/w3c/mathml-aam/issues/13 [6] https://github.com/w3c/mathml-aam/issues/14 AX-Relnotes: MathML elements are exposed in the accessible tree with specific roles. Bug: 6606, 1038895, 1051115, 1038897, 1038898, 1038899, 1038900, 1038901, 1038911, 1038913, 1052420 Change-Id: I7e857a0cfc05616a30bf4842e334c1dfde082d49 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3207929 Commit-Queue: FrΓ©dΓ©ric Wang Reviewed-by: Nektarios Paisios Reviewed-by: Tom Sepez Cr-Commit-Position: refs/heads/main@{#933442} NOKEYCHECK=True GitOrigin-RevId: d6d648b6dc54c1c78936dc506e5ccebe23cee7a3 --- .../core/mathml/mathml_tag_names.json5 | 8 +++ .../modules/accessibility/ax_layout_object.cc | 1 + .../modules/accessibility/ax_node_object.cc | 61 ++++++++++++++++++- .../modules/accessibility/ax_object.cc | 21 +++++++ .../element-role-mapping-normal-expected.txt | 30 ++++----- closure_compiler/externs/automation.js | 21 +++++++ 6 files changed, 126 insertions(+), 16 deletions(-) diff --git a/blink/renderer/core/mathml/mathml_tag_names.json5 b/blink/renderer/core/mathml/mathml_tag_names.json5 index 0cda392e4422..5fa80b654bc2 100644 --- a/blink/renderer/core/mathml/mathml_tag_names.json5 +++ b/blink/renderer/core/mathml/mathml_tag_names.json5 @@ -107,6 +107,14 @@ name: "mtable", interfaceName: "MathMLElement", }, + { + name: "mtd", + interfaceName: "MathMLElement", + }, + { + name: "mtr", + interfaceName: "MathMLElement", + }, { name: "mtext", interfaceName: "MathMLElement", diff --git a/blink/renderer/modules/accessibility/ax_layout_object.cc b/blink/renderer/modules/accessibility/ax_layout_object.cc index 0c9e7fa4b5f6..3e981fa7dbd2 100644 --- a/blink/renderer/modules/accessibility/ax_layout_object.cc +++ b/blink/renderer/modules/accessibility/ax_layout_object.cc @@ -81,6 +81,7 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" #include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h" #include "third_party/blink/renderer/core/loader/progress_tracker.h" +#include "third_party/blink/renderer/core/mathml/mathml_element.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" diff --git a/blink/renderer/modules/accessibility/ax_node_object.cc b/blink/renderer/modules/accessibility/ax_node_object.cc index 18008a34c440..647cfd8bf9b2 100644 --- a/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/blink/renderer/modules/accessibility/ax_node_object.cc @@ -577,6 +577,14 @@ AXObjectInclusion AXNodeObject::ShouldIncludeBasedOnSemantics( always_included_computed_roles.end()) return kIncludeObject; + // Don't ignore MathML nodes by default, since MathML relies on child + // positions to determine semantics (e.g. numerator is the first child of a + // fraction). + if (RuntimeEnabledFeatures::MathMLCoreEnabled() && IsA(node) && + RoleValue() != ax::mojom::blink::Role::kNone) { + return kIncludeObject; + } + // Using the title or accessibility description (so we // check if there's some kind of accessible name for the element) // to decide an element's visibility is not as definitive as @@ -1073,9 +1081,60 @@ ax::mojom::blink::Role AXNodeObject::NativeRoleIgnoringAria() const { ? ax::mojom::blink::Role::kMathMLMath : ax::mojom::blink::Role::kMath; } - // TODO(crbug.com/6606): Map more MathML elements. + if (element->HasTagName(mathml_names::kMfracTag)) + return ax::mojom::blink::Role::kMathMLFraction; + if (element->HasTagName(mathml_names::kMiTag)) + return ax::mojom::blink::Role::kMathMLIdentifier; + if (element->HasTagName(mathml_names::kMmultiscriptsTag)) + return ax::mojom::blink::Role::kMathMLMultiscripts; + if (element->HasTagName(mathml_names::kMnTag)) + return ax::mojom::blink::Role::kMathMLNumber; + if (element->HasTagName(mathml_names::kMoTag)) + return ax::mojom::blink::Role::kMathMLOperator; + if (element->HasTagName(mathml_names::kMoverTag)) + return ax::mojom::blink::Role::kMathMLOver; + if (element->HasTagName(mathml_names::kMunderTag)) + return ax::mojom::blink::Role::kMathMLUnder; + if (element->HasTagName(mathml_names::kMunderoverTag)) + return ax::mojom::blink::Role::kMathMLUnderOver; + if (element->HasTagName(mathml_names::kMrootTag)) + return ax::mojom::blink::Role::kMathMLRoot; + if (element->HasTagName(mathml_names::kMrowTag) || + element->HasTagName(mathml_names::kAnnotationXmlTag) || + element->HasTagName(mathml_names::kMactionTag) || + element->HasTagName(mathml_names::kMerrorTag) || + element->HasTagName(mathml_names::kMpaddedTag) || + element->HasTagName(mathml_names::kMphantomTag) || + element->HasTagName(mathml_names::kMstyleTag) || + element->HasTagName(mathml_names::kSemanticsTag)) { + return ax::mojom::blink::Role::kMathMLRow; + } + if (element->HasTagName(mathml_names::kMprescriptsTag)) + return ax::mojom::blink::Role::kMathMLPrescriptDelimiter; + if (element->HasTagName(mathml_names::kNoneTag)) + return ax::mojom::blink::Role::kMathMLNoneScript; + if (element->HasTagName(mathml_names::kMsqrtTag)) + return ax::mojom::blink::Role::kMathMLSquareRoot; + if (element->HasTagName(mathml_names::kMsTag)) + return ax::mojom::blink::Role::kMathMLStringLiteral; if (element->HasTagName(mathml_names::kMspaceTag)) return ax::mojom::blink::Role::kNone; + if (element->HasTagName(mathml_names::kMsubTag)) + return ax::mojom::blink::Role::kMathMLSub; + if (element->HasTagName(mathml_names::kMsubsupTag)) + return ax::mojom::blink::Role::kMathMLSubSup; + if (element->HasTagName(mathml_names::kMsupTag)) + return ax::mojom::blink::Role::kMathMLSup; + if (element->HasTagName(mathml_names::kMtableTag)) + return ax::mojom::blink::Role::kMathMLTable; + if (element->HasTagName(mathml_names::kMtdTag)) + return ax::mojom::blink::Role::kMathMLTableCell; + if (element->HasTagName(mathml_names::kMtrTag)) + return ax::mojom::blink::Role::kMathMLTableRow; + if (element->HasTagName(mathml_names::kMtextTag) || + element->HasTagName(mathml_names::kAnnotationTag)) { + return ax::mojom::blink::Role::kMathMLText; + } } if (GetNode()->HasTagName(html_names::kRpTag) || diff --git a/blink/renderer/modules/accessibility/ax_object.cc b/blink/renderer/modules/accessibility/ax_object.cc index d8b67476d080..10e0bd3ae9b1 100644 --- a/blink/renderer/modules/accessibility/ax_object.cc +++ b/blink/renderer/modules/accessibility/ax_object.cc @@ -5640,7 +5640,28 @@ bool AXObject::SupportsNameFromContents(bool recursive) const { case ax::mojom::blink::Role::kLog: case ax::mojom::blink::Role::kMain: case ax::mojom::blink::Role::kMarquee: + case ax::mojom::blink::Role::kMathMLFraction: + case ax::mojom::blink::Role::kMathMLIdentifier: case ax::mojom::blink::Role::kMathMLMath: + case ax::mojom::blink::Role::kMathMLMultiscripts: + case ax::mojom::blink::Role::kMathMLNoneScript: + case ax::mojom::blink::Role::kMathMLNumber: + case ax::mojom::blink::Role::kMathMLOperator: + case ax::mojom::blink::Role::kMathMLOver: + case ax::mojom::blink::Role::kMathMLPrescriptDelimiter: + case ax::mojom::blink::Role::kMathMLRoot: + case ax::mojom::blink::Role::kMathMLRow: + case ax::mojom::blink::Role::kMathMLSquareRoot: + case ax::mojom::blink::Role::kMathMLStringLiteral: + case ax::mojom::blink::Role::kMathMLSub: + case ax::mojom::blink::Role::kMathMLSubSup: + case ax::mojom::blink::Role::kMathMLSup: + case ax::mojom::blink::Role::kMathMLTable: + case ax::mojom::blink::Role::kMathMLTableCell: + case ax::mojom::blink::Role::kMathMLTableRow: + case ax::mojom::blink::Role::kMathMLText: + case ax::mojom::blink::Role::kMathMLUnder: + case ax::mojom::blink::Role::kMathMLUnderOver: case ax::mojom::blink::Role::kMenuListPopup: case ax::mojom::blink::Role::kMenu: case ax::mojom::blink::Role::kMenuBar: diff --git a/blink/web_tests/accessibility/element-role-mapping-normal-expected.txt b/blink/web_tests/accessibility/element-role-mapping-normal-expected.txt index c7babf96f547..3982ca95040e 100644 --- a/blink/web_tests/accessibility/element-role-mapping-normal-expected.txt +++ b/blink/web_tests/accessibility/element-role-mapping-normal-expected.txt @@ -87,40 +87,40 @@ AXRole: AXGenericContainer AXRole: AXDescriptionListDetail AXRole: AXStaticText "- white cold drink" AXRole: AXInlineTextBox "- white cold drink" - AXRole: AXMath "x + a / b" - AXRole: AXGenericContainer - AXRole: AXGenericContainer + AXRole: AXMath + AXRole: AXMathMLRow + AXRole: AXMathMLIdentifier AXRole: AXStaticText "x" AXRole: AXInlineTextBox "x" - AXRole: AXGenericContainer + AXRole: AXMathMLOperator AXRole: AXStaticText "+" AXRole: AXInlineTextBox "+" - AXRole: AXGenericContainer - AXRole: AXGenericContainer + AXRole: AXMathMLRow + AXRole: AXMathMLIdentifier AXRole: AXStaticText "a" AXRole: AXInlineTextBox "a" - AXRole: AXGenericContainer + AXRole: AXMathMLOperator AXRole: AXStaticText "/" AXRole: AXInlineTextBox "/" - AXRole: AXGenericContainer + AXRole: AXMathMLIdentifier AXRole: AXStaticText "b" AXRole: AXInlineTextBox "b" AXRole: AXMathMLMath - AXRole: AXGenericContainer - AXRole: AXGenericContainer + AXRole: AXMathMLRow + AXRole: AXMathMLIdentifier AXRole: AXStaticText "π‘₯" AXRole: AXInlineTextBox "π‘₯" - AXRole: AXGenericContainer + AXRole: AXMathMLOperator AXRole: AXStaticText "+" AXRole: AXInlineTextBox "+" - AXRole: AXGenericContainer - AXRole: AXGenericContainer + AXRole: AXMathMLRow + AXRole: AXMathMLIdentifier AXRole: AXStaticText "π‘Ž" AXRole: AXInlineTextBox "π‘Ž" - AXRole: AXGenericContainer + AXRole: AXMathMLOperator AXRole: AXStaticText "/" AXRole: AXInlineTextBox "/" - AXRole: AXGenericContainer + AXRole: AXMathMLIdentifier AXRole: AXStaticText "𝑏" AXRole: AXInlineTextBox "𝑏" AXRole: AXMain diff --git a/closure_compiler/externs/automation.js b/closure_compiler/externs/automation.js index 15dbafc5cbbe..552e4333428d 100644 --- a/closure_compiler/externs/automation.js +++ b/closure_compiler/externs/automation.js @@ -266,7 +266,28 @@ chrome.automation.RoleType = { MARK: 'mark', MARQUEE: 'marquee', MATH: 'math', + MATH_MLFRACTION: 'mathMLFraction', + MATH_MLIDENTIFIER: 'mathMLIdentifier', MATH_MLMATH: 'mathMLMath', + MATH_MLMULTISCRIPTS: 'mathMLMultiscripts', + MATH_MLNUMBER: 'mathMLNumber', + MATH_MLOPERATOR: 'mathMLOperator', + MATH_MLOVER: 'mathMLOver', + MATH_MLROOT: 'mathMLRoot', + MATH_MLROW: 'mathMLRow', + MATH_MLSQUARE_ROOT: 'mathMLSquareRoot', + MATH_MLSTRING_LITERAL: 'mathMLStringLiteral', + MATH_MLSUB: 'mathMLSub', + MATH_MLSUB_SUP: 'mathMLSubSup', + MATH_MLSUP: 'mathMLSup', + MATH_MLTABLE: 'mathMLTable', + MATH_MLTABLE_CELL: 'mathMLTableCell', + MATH_MLTABLE_ROW: 'mathMLTableRow', + MATH_MLTEXT: 'mathMLText', + MATH_MLUNDER: 'mathMLUnder', + MATH_MLUNDER_OVER: 'mathMLUnderOver', + MATH_MLPRESCRIPT_DELIMITER: 'mathMLPrescriptDelimiter', + MATH_MLNONE_SCRIPT: 'mathMLNoneScript', MENU: 'menu', MENU_BAR: 'menuBar', MENU_ITEM: 'menuItem',