Bug 495912 - Expose content in HTML canvas elements. r=bz,roc r=surkov(tests)

layout-mentor: bz (mucho thanks!)

We make html canvas frame a container and render frames for its content which makes a lot of what we need for accessibility "just work".
This commit is contained in:
David Bolter 2012-02-17 23:26:37 -05:00
parent 6023e952c8
commit 6392ae8ed0
10 changed files with 192 additions and 14 deletions

View File

@ -65,6 +65,7 @@ _TEST_FILES =\
test_focus_aria_activedescendant.html \
test_focus_autocomplete.xul \
test_focus_browserui.xul \
test_focus_canvas.html \
test_focus_contextmenu.xul \
test_focus_controls.html \
test_focus_dialog.html \

View File

@ -0,0 +1,59 @@
<html>
<head>
<title>Accessible focus testing in canvas subdom</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript"
src="../states.js"></script>
<script type="application/javascript">
//gA11yEventDumpToConsole = true;
var gQueue = null;
function doTests()
{
gQueue = new eventQueue();
gQueue.push(new synthFocus("button"));
gQueue.push(new synthTab("button", new focusChecker("textbox")));
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<a target="_blank"
title="Expose content in Canvas element"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=495912">
Mozilla Bug 495912
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<canvas>
<input id="button" type="button">
<input id="textbox">
</canvas>
<div id="eventdump"></div>
</body>
</html>

View File

@ -17,14 +17,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=495912
<script type="application/javascript">
function doTest()
{
var accTree = {
role: ROLE_CANVAS,
children: [
]
};
testAccessibleTree("canvas", accTree);
{
var tree =
{ ROLE_CANVAS: [
{ CHECKBUTTON: [] },
{ ENTRY: [] }
] };
testAccessibleTree("canvas", accTree);
SimpleTest.finish();
}
@ -42,9 +42,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=495912
<pre id="test">
</pre>
<canvas id="canvas" tabindex="0">
fallback content.
</canvas>
<canvas id="canvas" tabindex="0"><input type="checkbox"><input></canvas>
<script type="text/javascript">
var c=document.getElementById("canvas");

View File

@ -47,6 +47,7 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
test_ariadialog.html \
test_canvas.html \
test_colorpicker.xul \
test_cssoverflow.html \
test_contextmenu.xul \

View File

@ -0,0 +1,92 @@
<!DOCTYPE html>
<html>
<head>
<title>Canvas subdom mutation</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
////////////////////////////////////////////////////////////////////////////
// Invokers
function addSubtree(aID)
{
this.node = getNode(aID);
this.eventSeq = [
new invokerChecker(EVENT_SHOW, this.node)
];
this.invoke = function addSubtree_invoke()
{
// ensure we start with no subtree
testAccessibleTree("canvas", { CANVAS: [] });
getNode("dialog").style.display = "block";
}
this.finalCheck = function addSubtree_finalCheck() {
testAccessibleTree({ DIALOG: [] }, tree);
}
this.getID = function addSubtree_getID()
{
return "show canvas subdom";
}
}
////////////////////////////////////////////////////////////////////////////
// Test
//gA11yEventDumpID = "eventdump"; // debug stuff
//gA11yEventDumpToConsole = true;
var gQueue = null;
function doTest()
{
gQueue = new eventQueue();
// make the subdom come alive!
gQueue.push(new addSubtree("dialog"));
gQueue.invoke(); // SimpleTest.finish() will be called in the end
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Expose content in Canvas element"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=495912">
Mozilla Bug 495912
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<canvas id="canvas">
<div id="dialog" role="dialog" style="display: none;">
</div>
</canvas>
<div id="eventdump"></div>
</body>
</html>

View File

@ -3540,7 +3540,8 @@ nsCSSFrameConstructor::FindCanvasData(Element* aElement,
}
static const FrameConstructionData sCanvasData =
SIMPLE_FCDATA(NS_NewHTMLCanvasFrame);
FCDATA_WITH_WRAPPING_BLOCK(0, NS_NewHTMLCanvasFrame,
nsCSSAnonBoxes::htmlCanvasContent);
return &sCanvasData;
}

View File

@ -249,10 +249,24 @@ nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext,
Invalidate(nsRect(0, 0, mRect.width, mRect.height));
}
// Reflow the single anon block child.
nsReflowStatus childStatus;
nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE);
nsIFrame* childFrame = mFrames.FirstChild();
NS_ASSERTION(!childFrame->GetNextSibling(), "HTML canvas should have 1 kid");
nsHTMLReflowMetrics childDesiredSize(aMetrics.mFlags);
nsHTMLReflowState childReflowState(aPresContext, aReflowState, childFrame,
availSize);
ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowState,
0, 0, 0, childStatus, nsnull);
FinishReflowChild(childFrame, aPresContext, &childReflowState,
childDesiredSize, 0, 0, 0);
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
("exit nsHTMLCanvasFrame::Reflow: size=%d,%d",
aMetrics.width, aMetrics.height));
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
return NS_OK;
}

View File

@ -40,7 +40,7 @@
#ifndef nsHTMLCanvasFrame_h___
#define nsHTMLCanvasFrame_h___
#include "nsSplittableFrame.h"
#include "nsContainerFrame.h"
#include "nsString.h"
#include "nsAString.h"
#include "nsIIOService.h"
@ -52,7 +52,7 @@ class nsDisplayItem;
nsIFrame* NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
class nsHTMLCanvasFrame : public nsSplittableFrame
class nsHTMLCanvasFrame : public nsContainerFrame
{
public:
typedef mozilla::layers::Layer Layer;
@ -60,7 +60,7 @@ public:
NS_DECL_FRAMEARENA_HELPERS
nsHTMLCanvasFrame(nsStyleContext* aContext) : nsSplittableFrame(aContext) {}
nsHTMLCanvasFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
NS_IMETHOD Init(nsIContent* aContent,
nsIFrame* aParent,
@ -108,6 +108,11 @@ public:
NS_IMETHOD GetFrameName(nsAString& aResult) const;
#endif
// Inserted child content gets its frames parented by our child block
virtual nsIFrame* GetContentInsertionFrame() {
return GetFirstPrincipalChild()->GetContentInsertionFrame();
}
protected:
virtual ~nsHTMLCanvasFrame();

View File

@ -750,6 +750,12 @@ audio:not([controls]) {
display: none;
}
*|*::-moz-html-canvas-content {
display: block !important;
/* we want to be an absolute and fixed container */
-moz-transform: translate(0) !important;
}
/* emulation of non-standard HTML <marquee> tag */
marquee {
width: -moz-available;

View File

@ -72,6 +72,7 @@ CSS_ANON_BOX(dropDownList, ":-moz-dropdown-list")
CSS_ANON_BOX(fieldsetContent, ":-moz-fieldset-content")
CSS_ANON_BOX(framesetBlank, ":-moz-frameset-blank")
CSS_ANON_BOX(mozDisplayComboboxControlFrame, ":-moz-display-comboboxcontrol-frame")
CSS_ANON_BOX(htmlCanvasContent, ":-moz-html-canvas-content")
CSS_ANON_BOX(inlineTable, ":-moz-inline-table")
CSS_ANON_BOX(table, ":-moz-table")