зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1151648: Construct accessible objects for SVG elements which have title or desc. r=MarcoZ,yzen
According to SVG Accessibility API Mappings, an SVG element which has title or desc element must be exposed. https://w3c.github.io/svg-aam/#include_elements Previously, we didn't expose <g> elements at all even if they had a title/desc, and we unconditionally exposed some other SVG elements even when they didn't. This removes the Dev Tools A11y Panel code which explicitly allowed unlabelled descendants of role="img" <svg> elements, since we don't create descendants if they don't have a label now anyway. The associated tests had to be tweaked as well, since now we don't create unlabelled descendants. Original patch by Takeshi Kurosawa. Differential Revision: https://phabricator.services.mozilla.com/D77763
This commit is contained in:
Родитель
7c97f420c8
Коммит
c45ca37cf4
|
@ -147,6 +147,20 @@ static bool MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the SVG element should be accessible
|
||||
*/
|
||||
static bool MustSVGElementBeAccessible(nsIContent* aContent) {
|
||||
// https://w3c.github.io/svg-aam/#include_elements
|
||||
for (nsIContent* childElm = aContent->GetFirstChild(); childElm;
|
||||
childElm = childElm->GetNextSibling()) {
|
||||
if (childElm->IsAnyOfSVGElements(nsGkAtoms::title, nsGkAtoms::desc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by XULMap.h to map both menupopup and popup elements
|
||||
*/
|
||||
|
@ -1140,7 +1154,7 @@ Accessible* nsAccessibilityService::CreateAccessible(nsINode* aNode,
|
|||
if (!newAcc) {
|
||||
if (content->IsSVGElement()) {
|
||||
SVGGeometryFrame* geometryFrame = do_QueryFrame(frame);
|
||||
if (geometryFrame) {
|
||||
if (geometryFrame && MustSVGElementBeAccessible(content)) {
|
||||
// A graphic elements: rect, circle, ellipse, line, path, polygon,
|
||||
// polyline and image. A 'use' and 'text' graphic elements require
|
||||
// special support.
|
||||
|
@ -1149,6 +1163,9 @@ Accessible* nsAccessibilityService::CreateAccessible(nsINode* aNode,
|
|||
newAcc = new HyperTextAccessibleWrap(content->AsElement(), document);
|
||||
} else if (content->IsSVGElement(nsGkAtoms::svg)) {
|
||||
newAcc = new EnumRoleAccessible<roles::DIAGRAM>(content, document);
|
||||
} else if (content->IsSVGElement(nsGkAtoms::g) &&
|
||||
MustSVGElementBeAccessible(content)) {
|
||||
newAcc = new EnumRoleAccessible<roles::GROUPING>(content, document);
|
||||
}
|
||||
|
||||
} else if (content->IsMathMLElement()) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<script type="application/javascript">
|
||||
function doTests() {
|
||||
testRole("svg", ROLE_DIAGRAM);
|
||||
testRole("g", ROLE_GROUPING);
|
||||
testRole("rect", ROLE_GRAPHIC);
|
||||
testRole("circle", ROLE_GRAPHIC);
|
||||
testRole("ellipse", ROLE_GRAPHIC);
|
||||
|
@ -47,21 +48,40 @@
|
|||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="g">
|
||||
<title>g</title>
|
||||
</g>
|
||||
<rect width="300" height="100" id="rect"
|
||||
style="fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,0)"/>
|
||||
style="fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,0)">
|
||||
<title>rect</title>
|
||||
</rect>
|
||||
<circle cx="100" cy="50" r="40" stroke="black" id="circle"
|
||||
stroke-width="2" fill="red"/>
|
||||
stroke-width="2" fill="red">
|
||||
<title>circle</title>
|
||||
</circle>
|
||||
<ellipse cx="300" cy="80" rx="100" ry="50" id="ellipse"
|
||||
style="fill:yellow;stroke:purple;stroke-width:2"/>
|
||||
style="fill:yellow;stroke:purple;stroke-width:2">
|
||||
<title>ellipse</title>
|
||||
</ellipse>
|
||||
<line x1="0" y1="0" x2="200" y2="200" id="line"
|
||||
style="stroke:rgb(255,0,0);stroke-width:2"/>
|
||||
style="stroke:rgb(255,0,0);stroke-width:2">
|
||||
<title>line</title>
|
||||
</line>
|
||||
<polygon points="200,10 250,190 160,210" id="polygon"
|
||||
style="fill:lime;stroke:purple;stroke-width:1"/>
|
||||
style="fill:lime;stroke:purple;stroke-width:1">
|
||||
<title>polygon</title>
|
||||
</polygon>
|
||||
<polyline points="20,20 40,25 60,40 80,120 120,140 200,180" id="polyline"
|
||||
style="fill:none;stroke:black;stroke-width:3" />
|
||||
<path d="M150 0 L75 200 L225 200 Z" id="path"/>
|
||||
style="fill:none;stroke:black;stroke-width:3" >
|
||||
<title>polyline</title>
|
||||
</polyline>
|
||||
<path d="M150 0 L75 200 L225 200 Z" id="path">
|
||||
<title>path</title>
|
||||
</path>
|
||||
<image x1="25" y1="80" width="50" height="20" id="image"
|
||||
xlink:href="../moz.png"/>
|
||||
xlink:href="../moz.png">
|
||||
<title>image</title>
|
||||
</image>
|
||||
</svg>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
<script type="application/javascript">
|
||||
function doTest() {
|
||||
// svgText
|
||||
var accTree = {
|
||||
role: ROLE_DIAGRAM,
|
||||
children: [
|
||||
|
@ -26,7 +27,55 @@
|
|||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree("svgItem", accTree);
|
||||
testAccessibleTree("svgText", accTree);
|
||||
|
||||
// svg1
|
||||
accTree = {
|
||||
role: ROLE_DIAGRAM,
|
||||
children: []
|
||||
};
|
||||
testAccessibleTree("svg1", accTree);
|
||||
|
||||
// svg2
|
||||
accTree = {
|
||||
role: ROLE_DIAGRAM,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_GROUPING,
|
||||
children: []
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree("svg2", accTree);
|
||||
|
||||
// svg3
|
||||
accTree = {
|
||||
role: ROLE_DIAGRAM,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_GRAPHIC,
|
||||
children: []
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree("svg3", accTree);
|
||||
|
||||
// svg4
|
||||
accTree = {
|
||||
role: ROLE_DIAGRAM,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_GROUPING,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_GRAPHIC,
|
||||
children: []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree("svg4", accTree);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
@ -40,8 +89,39 @@
|
|||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
<svg id="svgItem">
|
||||
<svg id="svgText">
|
||||
<text>This is some text</text>
|
||||
</svg>
|
||||
|
||||
<!-- no accessible objects -->
|
||||
<svg id="svg1">
|
||||
<g id="g1">
|
||||
<rect width="300" height="100" id="rect1" style="fill:#00f" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<svg id="svg2">
|
||||
<g id="g2">
|
||||
<title>g</title>
|
||||
<rect width="300" height="100" id="rect2" style="fill:#00f" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<svg id="svg3">
|
||||
<g id="g3">
|
||||
<rect width="300" height="100" id="rect3" style="fill:#00f">
|
||||
<title>rect</title>
|
||||
</rect>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<svg id="svg4">
|
||||
<g id="g4">
|
||||
<title>g</title>
|
||||
<rect width="300" height="100" id="rect4" style="fill:#00f">
|
||||
<title>rect</title>
|
||||
</rect>
|
||||
</g>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -6,13 +6,6 @@
|
|||
|
||||
const { Ci } = require("chrome");
|
||||
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"getAriaRoles",
|
||||
"devtools/server/actors/utils/accessibility",
|
||||
true
|
||||
);
|
||||
|
||||
const {
|
||||
accessibility: {
|
||||
AUDIT_TYPE: { TEXT_LABEL },
|
||||
|
@ -145,23 +138,6 @@ const dialogRule = shouldHaveNonEmptyNameRule.bind(null, DIALOG_NO_NAME);
|
|||
*/
|
||||
const imageRule = function(accessible) {
|
||||
const name = getAccessibleName(accessible);
|
||||
const { DOMNode } = accessible;
|
||||
if (
|
||||
DOMNode instanceof DOMNode.ownerGlobal.SVGElement &&
|
||||
DOMNode.ownerSVGElement
|
||||
) {
|
||||
let ownerSVGAccessible = accessible.parent;
|
||||
while (ownerSVGAccessible.DOMNode.ownerSVGElement) {
|
||||
ownerSVGAccessible = ownerSVGAccessible.parent;
|
||||
}
|
||||
|
||||
const ariaRoles = getAriaRoles(ownerSVGAccessible);
|
||||
if (ariaRoles && ariaRoles.includes("img")) {
|
||||
// Do not require a defined name if a wrapping SVG has a role="img".
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return name != null ? null : { score: FAIL, issue: IMAGE_NO_NAME };
|
||||
};
|
||||
|
||||
|
|
|
@ -1065,63 +1065,43 @@ add_task(async function() {
|
|||
],
|
||||
["Non-unique aria toolbar with aria-labelledby", "#toolbar-4", null],
|
||||
["SVGElement with role=img that has a title", "#svg-1", null],
|
||||
[
|
||||
"SVGElement with no name and with ownerSVGElement with role=img that has a title",
|
||||
"#svg-2",
|
||||
null,
|
||||
],
|
||||
["SVGElement without role=img that has a title", "#svg-3", null],
|
||||
[
|
||||
"SVGElement with no name and with ownerSVGElement without role=img",
|
||||
"#svg-4",
|
||||
{ score: FAIL, issue: IMAGE_NO_NAME },
|
||||
],
|
||||
["SVGElement without role=img that has a title", "#svg-2", null],
|
||||
[
|
||||
"SVGElement with role=img and no name",
|
||||
"#svg-5",
|
||||
"#svg-3",
|
||||
{ score: FAIL, issue: IMAGE_NO_NAME },
|
||||
],
|
||||
[
|
||||
"SVGElement with no name and with ownerSVGElement with role=img",
|
||||
"#svg-6",
|
||||
null,
|
||||
],
|
||||
[
|
||||
"SVGElement with no name",
|
||||
"#svg-7",
|
||||
"#svg-4",
|
||||
{ score: FAIL, issue: IMAGE_NO_NAME },
|
||||
],
|
||||
[
|
||||
"SVGElement with no name and with ownerSVGElement with no name",
|
||||
"#svg-8",
|
||||
{ score: FAIL, issue: IMAGE_NO_NAME },
|
||||
],
|
||||
["SVGElement with a name", "#svg-9", null],
|
||||
["SVGElement with a name", "#svg-5", null],
|
||||
[
|
||||
"SVGElement with a name and with ownerSVGElement with a name",
|
||||
"#svg-10",
|
||||
"#svg-6",
|
||||
null,
|
||||
],
|
||||
["SVGElement with a title", "#svg-11", null],
|
||||
["SVGElement with a title", "#svg-7", null],
|
||||
[
|
||||
"SVGElement with a name and with ownerSVGElement with a title",
|
||||
"#svg-12",
|
||||
"#svg-8",
|
||||
null,
|
||||
],
|
||||
["SVGElement with role=img that has a title", "#svg-13", null],
|
||||
["SVGElement with role=img that has a title", "#svg-9", null],
|
||||
[
|
||||
"SVGElement with a name and with ownerSVGElement with role=img that has a title",
|
||||
"#svg-14",
|
||||
"#svg-10",
|
||||
null,
|
||||
],
|
||||
[
|
||||
"SVGElement with role=img and no title",
|
||||
"#svg-15",
|
||||
"#svg-11",
|
||||
{ score: FAIL, issue: IMAGE_NO_NAME },
|
||||
],
|
||||
[
|
||||
"SVGElement with a name and with ownerSVGElement with role=img and no title",
|
||||
"#svg-16",
|
||||
"#svg-12",
|
||||
null,
|
||||
],
|
||||
];
|
||||
|
|
|
@ -435,31 +435,31 @@
|
|||
<span id="toolbar-4" role="toolbar" aria-labelledby="toolbar-4-label"></span>
|
||||
<svg id="svg-1" role="img" viewbox="0 0 100 10" height="10px">
|
||||
<title id="siteLogoTitle">Site Logo</title>
|
||||
<rect id="svg-2" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
<rect x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
</svg>
|
||||
<svg id="svg-3" viewbox="0 0 100 10" height="10px">
|
||||
<svg id="svg-2" viewbox="0 0 100 10" height="10px">
|
||||
<title id="siteLogoTitle">Site Logo</title>
|
||||
<rect id="svg-4" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
<rect x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
</svg>
|
||||
<svg id="svg-5" role="img" viewbox="0 0 100 10" height="10px">
|
||||
<rect id="svg-6" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
<svg id="svg-3" role="img" viewbox="0 0 100 10" height="10px">
|
||||
<rect x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
</svg>
|
||||
<svg id="svg-4" viewbox="0 0 100 10" height="10px">
|
||||
<rect x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
</svg>
|
||||
<svg id="svg-5" aria-label="foo" viewbox="0 0 100 10" height="10px">
|
||||
<rect id="svg-6" aria-label="bar" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
</svg>
|
||||
<svg id="svg-7" viewbox="0 0 100 10" height="10px">
|
||||
<rect id="svg-8" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
</svg>
|
||||
<svg id="svg-9" aria-label="foo" viewbox="0 0 100 10" height="10px">
|
||||
<rect id="svg-10" aria-label="bar" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
</svg>
|
||||
<svg id="svg-11" viewbox="0 0 100 10" height="10px">
|
||||
<title id="siteLogoTitle">Site Logo</title>
|
||||
<rect id="svg-12" aria-label="foo" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
<rect id="svg-8" aria-label="foo" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
</svg>
|
||||
<svg id="svg-13" role="img" viewbox="0 0 100 10" height="10px">
|
||||
<svg id="svg-9" role="img" viewbox="0 0 100 10" height="10px">
|
||||
<title id="siteLogoTitle">Site Logo</title>
|
||||
<rect aria-label="foo" id="svg-14" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
<rect aria-label="foo" id="svg-10" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
</svg>
|
||||
<svg id="svg-15" role="img" viewbox="0 0 100 10" height="10px">
|
||||
<rect aria-label="foo" id="svg-16" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
<svg id="svg-11" role="img" viewbox="0 0 100 10" height="10px">
|
||||
<rect aria-label="foo" id="svg-12" x="0" y="00" width="100" height="10" fill="red"></rect>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Загрузка…
Ссылка в новой задаче