Bug 540456 - Support HTML5 canvas draw{Custom,System}FocusRing(). r=smaug

This commit is contained in:
Rik Cabanier 2013-11-04 14:52:24 -05:00
parent 11eb90c533
commit 7f0313f389
12 changed files with 294 additions and 4 deletions

View File

@ -38,6 +38,7 @@
#include "nsIDOMWindow.h"
#include "nsPIDOMWindow.h"
#include "nsDisplayList.h"
#include "nsFocusManager.h"
#include "nsTArray.h"
@ -1712,6 +1713,90 @@ CanvasRenderingContext2D::Stroke()
Redraw();
}
void CanvasRenderingContext2D::DrawSystemFocusRing(mozilla::dom::Element& aElement)
{
EnsureUserSpacePath();
if (!mPath) {
return;
}
if(DrawCustomFocusRing(aElement)) {
Save();
// set state to conforming focus state
ContextState& state = CurrentState();
state.globalAlpha = 1.0;
state.shadowBlur = 0;
state.shadowOffset.x = 0;
state.shadowOffset.y = 0;
state.op = mozilla::gfx::OP_OVER;
state.lineCap = CAP_BUTT;
state.lineJoin = mozilla::gfx::JOIN_MITER_OR_BEVEL;
state.lineWidth = 1;
CurrentState().dash.Clear();
// color and style of the rings is the same as for image maps
// set the background focus color
CurrentState().SetColorStyle(STYLE_STROKE, NS_RGBA(255, 255, 255, 255));
// draw the focus ring
Stroke();
// set dashing for foreground
FallibleTArray<mozilla::gfx::Float>& dash = CurrentState().dash;
dash.AppendElement(1);
dash.AppendElement(1);
// set the foreground focus color
CurrentState().SetColorStyle(STYLE_STROKE, NS_RGBA(0,0,0, 255));
// draw the focus ring
Stroke();
Restore();
}
}
bool CanvasRenderingContext2D::DrawCustomFocusRing(mozilla::dom::Element& aElement)
{
EnsureUserSpacePath();
HTMLCanvasElement* canvas = GetCanvas();
if (!canvas|| !nsContentUtils::ContentIsDescendantOf(&aElement, canvas)) {
return false;
}
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
// check that the element i focused
nsCOMPtr<nsIDOMElement> focusedElement;
fm->GetFocusedElement(getter_AddRefs(focusedElement));
if (SameCOMIdentity(aElement.AsDOMNode(), focusedElement)) {
// get the bounds of the current path
mgfx::Rect bounds;
bounds = mPath->GetBounds(mTarget->GetTransform());
// and set them as the accessible area
nsRect rect(canvas->ClientLeft() + bounds.x, canvas->ClientTop() + bounds.y,
bounds.width, bounds.height);
rect.x *= AppUnitsPerCSSPixel();
rect.y *= AppUnitsPerCSSPixel();
rect.width *= AppUnitsPerCSSPixel();
rect.height *= AppUnitsPerCSSPixel();
nsIFrame* frame = aElement.GetPrimaryFrame();
if(frame) {
frame->SetRect(rect);
}
return true;
}
}
return false;
}
void
CanvasRenderingContext2D::Clip(const CanvasWindingRule& winding)
{

View File

@ -171,6 +171,8 @@ public:
void BeginPath();
void Fill(const CanvasWindingRule& winding);
void Stroke();
void DrawSystemFocusRing(mozilla::dom::Element& element);
bool DrawCustomFocusRing(mozilla::dom::Element& element);
void Clip(const CanvasWindingRule& winding);
bool IsPointInPath(double x, double y, const CanvasWindingRule& winding);
bool IsPointInStroke(double x, double y);

View File

@ -91,6 +91,7 @@ support-files =
[test_bug866575.html]
[test_bug902651.html]
[test_canvas.html]
[test_canvas_focusring.html]
[test_canvas_font_setter.html]
[test_canvas_strokeStyle_getter.html]
[test_drawImageIncomplete.html]

View File

@ -0,0 +1,18 @@
<!--docytpe html-->
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<script>
window.onload=function(){
var c=document.getElementById("myCanvas").getContext("2d");
c.beginPath();
c.strokeRect(10, 10, 200, 200);
}
</script>
</head>
<body>
<canvas id="myCanvas" height="500" width="500" style="border:1px solid black">
</canvas>
</body></html>

View File

@ -0,0 +1,32 @@
<!--docytpe html-->
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<script>
window.onload=function(){
var c=document.getElementById("myCanvas").getContext("2d");
var in1=document.getElementById("in1");
var in2=document.getElementById("in2");
in1.onfocus=function(){
c.beginPath();
c.rect(10, 10, 200, 200);
if(c.drawCustomFocusRing(in1)) {
c.stroke();
}
c.beginPath();
c.rect(10, 220, 200, 200);
if(c.drawCustomFocusRing(in2)) {
c.stroke();
}
}
in1.focus();
}
</script>
</head>
<body>
<canvas id="myCanvas" height="500" width="500" style="border:1px solid black">
<input id="in1" type="range" min="1" max="12">
<input id="in2" type="range" min="1" max="12">
</canvas>
</body></html>

View File

@ -0,0 +1,18 @@
<!--docytpe html-->
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<script>
window.onload=function(){
var c=document.getElementById("myCanvas").getContext("2d");
c.beginPath();
c.mozDash = [1,1];
c.strokeRect(10, 10, 200, 200);
}
</script>
</head>
<body>
<canvas id="myCanvas" height="500" width="500" style="border:1px solid black">
</canvas>
</body></html>

View File

@ -0,0 +1,28 @@
<!--docytpe html-->
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<script>
window.onload=function(){
var c=document.getElementById("myCanvas").getContext("2d");
var in1=document.getElementById("in1");
var in2=document.getElementById("in2");
in1.onfocus=function(){
c.beginPath();
c.rect(10, 10, 200, 200);
c.drawSystemFocusRing(in1);
c.beginPath();
c.rect(10, 220, 200, 200);
c.drawSystemFocusRing(in2);
}
in1.focus();
}
</script>
</head>
<body>
<canvas id="myCanvas" height="500" width="500" style="border:1px solid black">
<input id="in1" type="range" min="1" max="12">
<input id="in2" type="range" min="1" max="12">
</canvas>
</body></html>

View File

@ -188,3 +188,7 @@ skip-if(!winWidget) pref(webgl.prefer-native-gl,true) pref(webgl.prefer-16bpp,tr
# Bug 815648
== stroketext-shadow.html stroketext-shadow-ref.html
# focus rings
pref(canvas.focusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion<15,8,500) skip-if(winWidget) needs-focus == drawSystemFocusRing.html drawSystemFocusRing-ref.html
pref(canvas.focusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion<15,8,500) skip-if(winWidget) needs-focus == drawCustomFocusRing.html drawCustomFocusRing-ref.html

View File

@ -0,0 +1,98 @@
<!DOCTYPE HTML>
<title>Canvas Tests</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<body>
<script>
SimpleTest.waitForExplicitFinish();
const Cc = SpecialPowers.Cc;
const Cr = SpecialPowers.Cr;
SpecialPowers.setBoolPref("canvas.focusring.enabled", true);
</script>
<p>Canvas test: drawCustomFocusRing</p>
<canvas id="c688" class="output" width="100" height="50">+
<input id="button1" type="range" min="1" max="12"></input>
<input id="button2" type="range" min="1" max="12"></input>
</canvas>
<script type="text/javascript">
function test_drawCustomFocusRing_canvas() {
var c = document.getElementById("c688");
var ctx = c.getContext("2d");
ctx.beginPath();
var b1 = document.getElementById('button1');
var b2 = document.getElementById('button2');
ok(!ctx.drawCustomFocusRing(b1), "button 1 is focused");
ok(!ctx.drawCustomFocusRing(b2), "button 2 is focused");
b1.focus();
ok(ctx.drawCustomFocusRing(b1), "button 1 should not be focused");
}
</script>
<p>Canvas test: drawSystemFocusRing</p>
<canvas id="c689" class="output" width="50" height="25">
<input id="button3" type="range" min="1" max="12"></input>
<input id="button4" type="range" min="1" max="12"></input>
</canvas>
<script type="text/javascript">
function isEmptyCanvas(ctx, w, h) {
var imgdata = ctx.getImageData(0, 0, w, h);
for(var x = 0; x < w*h*4; x++)
if(imgdata.data[x] != 0)
return false;
return true;
}
function test_drawSystemFocusRing_canvas() {
var c = document.getElementById("c689");
var ctx = c.getContext("2d");
var b1 = document.getElementById('button3');
var b2 = document.getElementById('button4');
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.beginPath();
ctx.rect(10, 10, 30, 30);
ctx.drawSystemFocusRing(b1);
ok(isEmptyCanvas(ctx, ctx.canvas.width, ctx.canvas.height), "focus of button 1 is drawn");
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.beginPath();
ctx.rect(50, 10, 30, 30);
ctx.drawSystemFocusRing(b2);
ctx.rect(50, 10, 30, 30);
ctx.drawSystemFocusRing(b2);
ok(isEmptyCanvas(ctx, ctx.canvas.width, ctx.canvas.height), "focus of button 2 is drawn");
b1.focus();
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.beginPath();
ctx.rect(10, 10, 30, 30);
ctx.drawSystemFocusRing(b1);
ok(!isEmptyCanvas(ctx, ctx.canvas.width, ctx.canvas.height) , "focus of button 1 is not drawn");
}
</script>
<script>
function runTests() {
try {
test_drawCustomFocusRing_canvas();
} catch(e) {
throw e;
ok(false, "unexpected exception thrown in: test_drawCustomFocusRing_canvas");
}
try {
test_drawSystemFocusRing_canvas();
} catch(e) {
throw e;
ok(false, "unexpected exception thrown in: test_drawSystemFocusRing_canvas");
}
SpecialPowers.setBoolPref("canvas.focusring.enabled", false);
SimpleTest.finish();
}
addLoadEvent(runTests);
</script>

View File

@ -77,10 +77,10 @@ interface CanvasRenderingContext2D {
// NOT IMPLEMENTED void fill(Path path);
void stroke();
// NOT IMPLEMENTED void stroke(Path path);
// NOT IMPLEMENTED void drawSystemFocusRing(Element element);
// NOT IMPLEMENTED void drawSystemFocusRing(Path path, Element element);
// NOT IMPLEMENTED boolean drawCustomFocusRing(Element element);
// NOT IMPLEMENTED boolean drawCustomFocusRing(Path path, Element element);
[Pref="canvas.focusring.enabled"] void drawSystemFocusRing(Element element);
// NOT IMPLEMENTED void drawSystemFocusRing(Path path, HTMLElement element);
[Pref="canvas.focusring.enabled"] boolean drawCustomFocusRing(Element element);
// NOT IMPLEMENTED boolean drawCustomFocusRing(Path path, HTMLElement element);
// NOT IMPLEMENTED void scrollPathIntoView();
// NOT IMPLEMENTED void scrollPathIntoView(Path path);
void clip(optional CanvasWindingRule winding = "nonzero");

View File

@ -421,6 +421,9 @@ pref("ui.scrollToClick", 0);
pref("accessibility.tabfocus_applies_to_xul", true);
#endif
// provide ability to turn on support for canvas focus rings
pref("canvas.focusring.enabled", false);
// We want the ability to forcibly disable platform a11y, because
// some non-a11y-related components attempt to bring it up. See bug
// 538530 for details about Windows; we have a pref here that allows it

View File

@ -100,6 +100,7 @@
"content/base/test/test_child_process_shutdown_message.html":"specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE",
"content/base/test/test_messagemanager_assertpermission.html":"specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE",
"content/canvas/test/test_canvas_focusring.html":"specialpowers.wrap",
"content/html/content/test/test_formSubmission.html":"NS_ERROR_FILE_TARGET_DOES_NOT_EXIST",