mirror of
https://github.com/servo/servo.git
synced 2025-06-11 01:50:10 +00:00
Allow currentColor in canvas context's shadowColor (#30754)
This allows unifying the parse_color function and method, aligns Servo with other browsers, and obeys the HTML spec: - https://html.spec.whatwg.org/multipage/canvas.html#shadows - https://html.spec.whatwg.org/multipage/infrastructure.html#parsed-as-a-css-color-value
This commit is contained in:
parent
334c67a3cc
commit
3543a87592
8 changed files with 186 additions and 56 deletions
|
@ -296,43 +296,6 @@ impl CanvasState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_color(&self, canvas: Option<&HTMLCanvasElement>, string: &str) -> Result<RGBA, ()> {
|
|
||||||
let mut input = ParserInput::new(string);
|
|
||||||
let mut parser = Parser::new(&mut input);
|
|
||||||
let color = CSSColor::parse(&mut parser);
|
|
||||||
if parser.is_exhausted() {
|
|
||||||
match color {
|
|
||||||
Ok(CSSColor::Rgba(rgba)) => Ok(rgba),
|
|
||||||
Ok(CSSColor::CurrentColor) => {
|
|
||||||
// TODO: https://github.com/whatwg/html/issues/1099
|
|
||||||
// Reconsider how to calculate currentColor in a display:none canvas
|
|
||||||
|
|
||||||
// TODO: will need to check that the context bitmap mode is fixed
|
|
||||||
// once we implement CanvasProxy
|
|
||||||
let canvas = match canvas {
|
|
||||||
// https://drafts.css-houdini.org/css-paint-api/#2d-rendering-context
|
|
||||||
// Whenever "currentColor" is used as a color in the PaintRenderingContext2D API,
|
|
||||||
// it is treated as opaque black.
|
|
||||||
None => return Ok(RGBA::new(0, 0, 0, 1.0)),
|
|
||||||
Some(ref canvas) => &**canvas,
|
|
||||||
};
|
|
||||||
|
|
||||||
let canvas_element = canvas.upcast::<Element>();
|
|
||||||
|
|
||||||
match canvas_element.style() {
|
|
||||||
Some(ref s) if canvas_element.has_css_layout_box() => {
|
|
||||||
Ok(s.get_inherited_text().color)
|
|
||||||
},
|
|
||||||
_ => Ok(RGBA::new(0, 0, 0, 1.0)),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_rect(&self, canvas_size: Size2D<u64>, rect: Rect<u64>) -> Vec<u8> {
|
pub fn get_rect(&self, canvas_size: Size2D<u64>, rect: Rect<u64>) -> Vec<u8> {
|
||||||
assert!(self.origin_is_clean());
|
assert!(self.origin_is_clean());
|
||||||
|
|
||||||
|
@ -753,10 +716,10 @@ impl CanvasState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor
|
||||||
pub fn set_shadow_color(&self, value: DOMString) {
|
pub fn set_shadow_color(&self, canvas: Option<&HTMLCanvasElement>, value: DOMString) {
|
||||||
if let Ok(color) = parse_color(&value) {
|
if let Ok(rgba) = parse_color(canvas, &value) {
|
||||||
self.state.borrow_mut().shadow_color = color;
|
self.state.borrow_mut().shadow_color = rgba;
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::SetShadowColor(color))
|
self.send_canvas_2d_msg(Canvas2dMsg::SetShadowColor(rgba))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,7 +748,7 @@ impl CanvasState {
|
||||||
) {
|
) {
|
||||||
match value {
|
match value {
|
||||||
StringOrCanvasGradientOrCanvasPattern::String(string) => {
|
StringOrCanvasGradientOrCanvasPattern::String(string) => {
|
||||||
if let Ok(rgba) = self.parse_color(canvas, &string) {
|
if let Ok(rgba) = parse_color(canvas, &string) {
|
||||||
self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba);
|
self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -828,7 +791,7 @@ impl CanvasState {
|
||||||
) {
|
) {
|
||||||
match value {
|
match value {
|
||||||
StringOrCanvasGradientOrCanvasPattern::String(string) => {
|
StringOrCanvasGradientOrCanvasPattern::String(string) => {
|
||||||
if let Ok(rgba) = self.parse_color(canvas, &string) {
|
if let Ok(rgba) = parse_color(canvas, &string) {
|
||||||
self.state.borrow_mut().fill_style = CanvasFillOrStrokeStyle::Color(rgba);
|
self.state.borrow_mut().fill_style = CanvasFillOrStrokeStyle::Color(rgba);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1702,18 +1665,40 @@ impl CanvasState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_color(string: &str) -> Result<RGBA, ()> {
|
fn parse_color(canvas: Option<&HTMLCanvasElement>, string: &str) -> Result<RGBA, ()> {
|
||||||
let mut input = ParserInput::new(string);
|
let mut input = ParserInput::new(string);
|
||||||
let mut parser = Parser::new(&mut input);
|
let mut parser = Parser::new(&mut input);
|
||||||
match CSSColor::parse(&mut parser) {
|
let color = CSSColor::parse(&mut parser);
|
||||||
Ok(CSSColor::Rgba(rgba)) => {
|
if parser.is_exhausted() {
|
||||||
if parser.is_exhausted() {
|
match color {
|
||||||
Ok(rgba)
|
Ok(CSSColor::Rgba(rgba)) => Ok(rgba),
|
||||||
} else {
|
Ok(CSSColor::CurrentColor) => {
|
||||||
Err(())
|
// TODO: https://github.com/whatwg/html/issues/1099
|
||||||
}
|
// Reconsider how to calculate currentColor in a display:none canvas
|
||||||
},
|
|
||||||
_ => Err(()),
|
// TODO: will need to check that the context bitmap mode is fixed
|
||||||
|
// once we implement CanvasProxy
|
||||||
|
let canvas = match canvas {
|
||||||
|
// https://drafts.css-houdini.org/css-paint-api/#2d-rendering-context
|
||||||
|
// Whenever "currentColor" is used as a color in the PaintRenderingContext2D API,
|
||||||
|
// it is treated as opaque black.
|
||||||
|
None => return Ok(RGBA::new(0, 0, 0, 1.0)),
|
||||||
|
Some(ref canvas) => &**canvas,
|
||||||
|
};
|
||||||
|
|
||||||
|
let canvas_element = canvas.upcast::<Element>();
|
||||||
|
|
||||||
|
match canvas_element.style() {
|
||||||
|
Some(ref s) if canvas_element.has_css_layout_box() => {
|
||||||
|
Ok(s.get_inherited_text().color)
|
||||||
|
},
|
||||||
|
_ => Ok(RGBA::new(0, 0, 0, 1.0)),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -647,7 +647,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor
|
||||||
fn SetShadowColor(&self, value: DOMString) {
|
fn SetShadowColor(&self, value: DOMString) {
|
||||||
self.canvas_state.set_shadow_color(value)
|
self.canvas_state
|
||||||
|
.set_shadow_color(self.canvas.as_ref().map(|c| &**c), value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,8 @@ impl OffscreenCanvasRenderingContext2DMethods for OffscreenCanvasRenderingContex
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowcolor
|
||||||
fn SetShadowColor(&self, value: DOMString) {
|
fn SetShadowColor(&self, value: DOMString) {
|
||||||
self.canvas_state.set_shadow_color(value)
|
self.canvas_state
|
||||||
|
.set_shadow_color(self.htmlcanvas.as_ref().map(|c| &**c), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle
|
||||||
|
|
|
@ -439502,7 +439502,7 @@
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"shadows.yaml": [
|
"shadows.yaml": [
|
||||||
"366ac0b6072dfaa9de58abbda84525d9fe1806d1",
|
"953ab2c555d5ad9d46d52b6c74f09d344850982c",
|
||||||
[]
|
[]
|
||||||
],
|
],
|
||||||
"text.yaml": [
|
"text.yaml": [
|
||||||
|
@ -621476,6 +621476,27 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"2d.shadow.attributes.shadowColor.current.basic.html": [
|
||||||
|
"bfdc54d31b71e663bb2eef282c2fb4c9655af98f",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"2d.shadow.attributes.shadowColor.current.changed.html": [
|
||||||
|
"9eee2122d5efb1c56f0ad695b90e1d2df54f2c5c",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"2d.shadow.attributes.shadowColor.current.removed.html": [
|
||||||
|
"e1989cbdc80622ff1598adf0485377c7d28777b6",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"2d.shadow.attributes.shadowColor.initial.html": [
|
"2d.shadow.attributes.shadowColor.initial.html": [
|
||||||
"f4d0d33d6d9af347af413fdfc1436034a4a3c919",
|
"f4d0d33d6d9af347af413fdfc1436034a4a3c919",
|
||||||
[
|
[
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
|
||||||
|
<title>Canvas test: 2d.shadow.attributes.shadowColor.current.basic</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/html/canvas/resources/canvas-tests.js"></script>
|
||||||
|
<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css">
|
||||||
|
<body class="show_output">
|
||||||
|
|
||||||
|
<h1>2d.shadow.attributes.shadowColor.current.basic</h1>
|
||||||
|
<p class="desc">currentColor is computed from the canvas element</p>
|
||||||
|
|
||||||
|
|
||||||
|
<p class="output">Actual output:</p>
|
||||||
|
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
|
||||||
|
|
||||||
|
<ul id="d"></ul>
|
||||||
|
<script>
|
||||||
|
var t = async_test("currentColor is computed from the canvas element");
|
||||||
|
_addTest(function(canvas, ctx) {
|
||||||
|
|
||||||
|
canvas.style.color = '#0f0';
|
||||||
|
ctx.shadowColor = 'currentColor';
|
||||||
|
_assertSame(ctx.shadowColor, '#00ff00', "ctx.shadowColor", "'#00ff00'");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
|
||||||
|
<title>Canvas test: 2d.shadow.attributes.shadowColor.current.changed</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/html/canvas/resources/canvas-tests.js"></script>
|
||||||
|
<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css">
|
||||||
|
<body class="show_output">
|
||||||
|
|
||||||
|
<h1>2d.shadow.attributes.shadowColor.current.changed</h1>
|
||||||
|
<p class="desc">currentColor is computed when the attribute is set, not when it is painted</p>
|
||||||
|
|
||||||
|
|
||||||
|
<p class="output">Actual output:</p>
|
||||||
|
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
|
||||||
|
|
||||||
|
<ul id="d"></ul>
|
||||||
|
<script>
|
||||||
|
var t = async_test("currentColor is computed when the attribute is set, not when it is painted");
|
||||||
|
_addTest(function(canvas, ctx) {
|
||||||
|
|
||||||
|
canvas.style.color = '#0f0';
|
||||||
|
ctx.shadowColor = 'currentColor';
|
||||||
|
canvas.style.color = '#f00';
|
||||||
|
_assertSame(ctx.shadowColor, '#00ff00', "ctx.shadowColor", "'#00ff00'");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
|
||||||
|
<title>Canvas test: 2d.shadow.attributes.shadowColor.current.removed</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/html/canvas/resources/canvas-tests.js"></script>
|
||||||
|
<link rel="stylesheet" href="/html/canvas/resources/canvas-tests.css">
|
||||||
|
<body class="show_output">
|
||||||
|
|
||||||
|
<h1>2d.shadow.attributes.shadowColor.current.removed</h1>
|
||||||
|
<p class="desc">currentColor is solid black when the canvas element is not in a document</p>
|
||||||
|
|
||||||
|
|
||||||
|
<p class="output">Actual output:</p>
|
||||||
|
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
|
||||||
|
|
||||||
|
<ul id="d"></ul>
|
||||||
|
<script>
|
||||||
|
var t = async_test("currentColor is solid black when the canvas element is not in a document");
|
||||||
|
_addTest(function(canvas, ctx) {
|
||||||
|
|
||||||
|
// Try not to let it undetectably incorrectly pick up opaque-black
|
||||||
|
// from other parts of the document:
|
||||||
|
document.documentElement.style.color = '#f00';
|
||||||
|
document.body.style.color = '#f00';
|
||||||
|
canvas.style.color = '#f00';
|
||||||
|
|
||||||
|
canvas.remove();
|
||||||
|
ctx.shadowColor = 'currentColor';
|
||||||
|
_assertSame(ctx.shadowColor, '#000000', "ctx.shadowColor", "'#000000'");
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
@ -134,6 +134,37 @@
|
||||||
ctx.shadowColor = 'RGBA(0,255, 0,0)';
|
ctx.shadowColor = 'RGBA(0,255, 0,0)';
|
||||||
@assert ctx.shadowColor === 'rgba(0, 255, 0, 0)';
|
@assert ctx.shadowColor === 'rgba(0, 255, 0, 0)';
|
||||||
|
|
||||||
|
- name: 2d.shadow.attributes.shadowColor.current.basic
|
||||||
|
desc: currentColor is computed from the canvas element
|
||||||
|
canvasType: ['HtmlCanvas']
|
||||||
|
code: |
|
||||||
|
canvas.style.color = '#0f0';
|
||||||
|
ctx.shadowColor = 'currentColor';
|
||||||
|
@assert ctx.shadowColor === '#00ff00';
|
||||||
|
|
||||||
|
- name: 2d.shadow.attributes.shadowColor.current.changed
|
||||||
|
desc: currentColor is computed when the attribute is set, not when it is painted
|
||||||
|
canvasType: ['HtmlCanvas']
|
||||||
|
code: |
|
||||||
|
canvas.style.color = '#0f0';
|
||||||
|
ctx.shadowColor = 'currentColor';
|
||||||
|
canvas.style.color = '#f00';
|
||||||
|
@assert ctx.shadowColor === '#00ff00';
|
||||||
|
|
||||||
|
- name: 2d.shadow.attributes.shadowColor.current.removed
|
||||||
|
desc: currentColor is solid black when the canvas element is not in a document
|
||||||
|
canvasType: ['HtmlCanvas']
|
||||||
|
code: |
|
||||||
|
// Try not to let it undetectably incorrectly pick up opaque-black
|
||||||
|
// from other parts of the document:
|
||||||
|
document.documentElement.style.color = '#f00';
|
||||||
|
document.body.style.color = '#f00';
|
||||||
|
canvas.style.color = '#f00';
|
||||||
|
|
||||||
|
canvas.remove();
|
||||||
|
ctx.shadowColor = 'currentColor';
|
||||||
|
@assert ctx.shadowColor === '#000000';
|
||||||
|
|
||||||
- name: 2d.shadow.attributes.shadowColor.invalid
|
- name: 2d.shadow.attributes.shadowColor.invalid
|
||||||
code: |
|
code: |
|
||||||
ctx.shadowColor = '#00ff00';
|
ctx.shadowColor = '#00ff00';
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue