mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Auto merge of #8723 - dzbarsky:origin_clean, r=dzbarsky
Add origin-clean flag tracking for canvas The resulting failures are because we aren't doing origin-comparison correctly (I bet the image ends up with an empty hostname or something). We could probably hack around that if we care, but it should just go away when we get the origin checking right. r? @jdm <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8723) <!-- Reviewable:end -->
This commit is contained in:
commit
82e73e7a5f
15 changed files with 135 additions and 86 deletions
|
@ -18,12 +18,14 @@ pub struct CanvasPattern {
|
||||||
surface_size: Size2D<i32>,
|
surface_size: Size2D<i32>,
|
||||||
repeat_x: bool,
|
repeat_x: bool,
|
||||||
repeat_y: bool,
|
repeat_y: bool,
|
||||||
|
origin_clean: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CanvasPattern {
|
impl CanvasPattern {
|
||||||
fn new_inherited(surface_data: Vec<u8>,
|
fn new_inherited(surface_data: Vec<u8>,
|
||||||
surface_size: Size2D<i32>,
|
surface_size: Size2D<i32>,
|
||||||
repeat: RepetitionStyle)
|
repeat: RepetitionStyle,
|
||||||
|
origin_clean: bool)
|
||||||
-> CanvasPattern {
|
-> CanvasPattern {
|
||||||
let (x, y) = match repeat {
|
let (x, y) = match repeat {
|
||||||
RepetitionStyle::Repeat => (true, true),
|
RepetitionStyle::Repeat => (true, true),
|
||||||
|
@ -38,17 +40,23 @@ impl CanvasPattern {
|
||||||
surface_size: surface_size,
|
surface_size: surface_size,
|
||||||
repeat_x: x,
|
repeat_x: x,
|
||||||
repeat_y: y,
|
repeat_y: y,
|
||||||
|
origin_clean: origin_clean,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn new(global: GlobalRef,
|
pub fn new(global: GlobalRef,
|
||||||
surface_data: Vec<u8>,
|
surface_data: Vec<u8>,
|
||||||
surface_size: Size2D<i32>,
|
surface_size: Size2D<i32>,
|
||||||
repeat: RepetitionStyle)
|
repeat: RepetitionStyle,
|
||||||
|
origin_clean: bool)
|
||||||
-> Root<CanvasPattern> {
|
-> Root<CanvasPattern> {
|
||||||
reflect_dom_object(box CanvasPattern::new_inherited(surface_data, surface_size, repeat),
|
reflect_dom_object(box CanvasPattern::new_inherited(surface_data, surface_size,
|
||||||
|
repeat, origin_clean),
|
||||||
global,
|
global,
|
||||||
CanvasPatternBinding::Wrap)
|
CanvasPatternBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
pub fn origin_is_clean(&self) -> bool {
|
||||||
|
self.origin_clean
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ToFillOrStrokeStyle for &'a CanvasPattern {
|
impl<'a> ToFillOrStrokeStyle for &'a CanvasPattern {
|
||||||
|
|
|
@ -39,6 +39,7 @@ use net_traits::image::base::PixelFormat;
|
||||||
use net_traits::image_cache_task::ImageResponse;
|
use net_traits::image_cache_task::ImageResponse;
|
||||||
use num::{Float, ToPrimitive};
|
use num::{Float, ToPrimitive};
|
||||||
use script_traits::ScriptMsg as ConstellationMsg;
|
use script_traits::ScriptMsg as ConstellationMsg;
|
||||||
|
use std::cell::Cell;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
use std::{cmp, fmt};
|
use std::{cmp, fmt};
|
||||||
|
@ -66,6 +67,7 @@ pub struct CanvasRenderingContext2D {
|
||||||
canvas: JS<HTMLCanvasElement>,
|
canvas: JS<HTMLCanvasElement>,
|
||||||
state: DOMRefCell<CanvasContextState>,
|
state: DOMRefCell<CanvasContextState>,
|
||||||
saved_states: DOMRefCell<Vec<CanvasContextState>>,
|
saved_states: DOMRefCell<Vec<CanvasContextState>>,
|
||||||
|
origin_clean: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_root]
|
#[must_root]
|
||||||
|
@ -131,6 +133,7 @@ impl CanvasRenderingContext2D {
|
||||||
canvas: JS::from_ref(canvas),
|
canvas: JS::from_ref(canvas),
|
||||||
state: DOMRefCell::new(CanvasContextState::new()),
|
state: DOMRefCell::new(CanvasContextState::new()),
|
||||||
saved_states: DOMRefCell::new(Vec::new()),
|
saved_states: DOMRefCell::new(Vec::new()),
|
||||||
|
origin_clean: Cell::new(true),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,6 +225,29 @@ impl CanvasRenderingContext2D {
|
||||||
(source_rect, dest_rect)
|
(source_rect, dest_rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#the-image-argument-is-not-origin-clean
|
||||||
|
fn is_origin_clean(&self,
|
||||||
|
image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D)
|
||||||
|
-> bool {
|
||||||
|
match image {
|
||||||
|
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(canvas) => {
|
||||||
|
canvas.origin_is_clean()
|
||||||
|
}
|
||||||
|
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(image) =>
|
||||||
|
image.r().origin_is_clean(),
|
||||||
|
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLImageElement(image) =>
|
||||||
|
match image.get_url() {
|
||||||
|
None => true,
|
||||||
|
Some(url) => {
|
||||||
|
// TODO(zbarsky): we should check the origin of the image against
|
||||||
|
// the entry settings object, but for now check it against the canvas' doc.
|
||||||
|
let node: &Node = &*self.canvas.upcast();
|
||||||
|
url.origin() == node.owner_doc().url().origin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// drawImage coordinates explained
|
// drawImage coordinates explained
|
||||||
//
|
//
|
||||||
|
@ -254,19 +280,20 @@ impl CanvasRenderingContext2D {
|
||||||
dw: Option<f64>,
|
dw: Option<f64>,
|
||||||
dh: Option<f64>)
|
dh: Option<f64>)
|
||||||
-> Fallible<()> {
|
-> Fallible<()> {
|
||||||
match image {
|
let result = match image {
|
||||||
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(canvas) =>
|
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(ref canvas) => {
|
||||||
self.draw_html_canvas_element(canvas.r(),
|
self.draw_html_canvas_element(canvas.r(),
|
||||||
sx, sy, sw, sh,
|
sx, sy, sw, sh,
|
||||||
dx, dy, dw, dh),
|
dx, dy, dw, dh)
|
||||||
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(image) => {
|
}
|
||||||
|
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(ref image) => {
|
||||||
let context = image.r();
|
let context = image.r();
|
||||||
let canvas = context.Canvas();
|
let canvas = context.Canvas();
|
||||||
self.draw_html_canvas_element(canvas.r(),
|
self.draw_html_canvas_element(canvas.r(),
|
||||||
sx, sy, sw, sh,
|
sx, sy, sw, sh,
|
||||||
dx, dy, dw, dh)
|
dx, dy, dw, dh)
|
||||||
}
|
}
|
||||||
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLImageElement(image) => {
|
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLImageElement(ref image) => {
|
||||||
let image_element = image.r();
|
let image_element = image.r();
|
||||||
// https://html.spec.whatwg.org/multipage/#img-error
|
// https://html.spec.whatwg.org/multipage/#img-error
|
||||||
// If the image argument is an HTMLImageElement object that is in the broken state,
|
// If the image argument is an HTMLImageElement object that is in the broken state,
|
||||||
|
@ -290,8 +317,15 @@ impl CanvasRenderingContext2D {
|
||||||
sx, sy, sw, sh,
|
sx, sy, sw, sh,
|
||||||
dx, dy, dw, dh)
|
dx, dy, dw, dh)
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if result.is_ok() {
|
||||||
|
if !self.is_origin_clean(image) {
|
||||||
|
self.set_origin_unclean()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_html_canvas_element(&self,
|
fn draw_html_canvas_element(&self,
|
||||||
canvas: &HTMLCanvasElement,
|
canvas: &HTMLCanvasElement,
|
||||||
|
@ -475,6 +509,14 @@ impl CanvasRenderingContext2D {
|
||||||
pub fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg> {
|
pub fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg> {
|
||||||
self.ipc_renderer.clone()
|
self.ipc_renderer.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn origin_is_clean(&self) -> bool {
|
||||||
|
self.origin_clean.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_origin_unclean(&self) {
|
||||||
|
self.origin_clean.set(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait LayoutCanvasRenderingContext2DHelpers {
|
pub trait LayoutCanvasRenderingContext2DHelpers {
|
||||||
|
@ -887,16 +929,13 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) {
|
fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) {
|
||||||
match value {
|
match value {
|
||||||
StringOrCanvasGradientOrCanvasPattern::eString(string) => {
|
StringOrCanvasGradientOrCanvasPattern::eString(string) => {
|
||||||
match self.parse_color(&string) {
|
if let Ok(rgba) = self.parse_color(&string) {
|
||||||
Ok(rgba) => {
|
|
||||||
self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba);
|
self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba);
|
||||||
self.ipc_renderer
|
self.ipc_renderer
|
||||||
.send(CanvasMsg::Canvas2d(Canvas2dMsg::SetStrokeStyle(
|
.send(CanvasMsg::Canvas2d(Canvas2dMsg::SetStrokeStyle(
|
||||||
FillOrStrokeStyle::Color(rgba))))
|
FillOrStrokeStyle::Color(rgba))))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient) => {
|
StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient) => {
|
||||||
self.state.borrow_mut().stroke_style =
|
self.state.borrow_mut().stroke_style =
|
||||||
|
@ -905,7 +944,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
Canvas2dMsg::SetStrokeStyle(gradient.to_fill_or_stroke_style()));
|
Canvas2dMsg::SetStrokeStyle(gradient.to_fill_or_stroke_style()));
|
||||||
self.ipc_renderer.send(msg).unwrap();
|
self.ipc_renderer.send(msg).unwrap();
|
||||||
},
|
},
|
||||||
_ => {}
|
StringOrCanvasGradientOrCanvasPattern::eCanvasPattern(pattern) => {
|
||||||
|
let msg = CanvasMsg::Canvas2d(
|
||||||
|
Canvas2dMsg::SetStrokeStyle(pattern.to_fill_or_stroke_style()));
|
||||||
|
self.ipc_renderer.send(msg).unwrap();
|
||||||
|
if !pattern.origin_is_clean() {
|
||||||
|
self.set_origin_unclean();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -943,8 +989,12 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
self.ipc_renderer.send(msg).unwrap();
|
self.ipc_renderer.send(msg).unwrap();
|
||||||
}
|
}
|
||||||
StringOrCanvasGradientOrCanvasPattern::eCanvasPattern(pattern) => {
|
StringOrCanvasGradientOrCanvasPattern::eCanvasPattern(pattern) => {
|
||||||
self.ipc_renderer.send(CanvasMsg::Canvas2d(Canvas2dMsg::SetFillStyle(
|
let msg = CanvasMsg::Canvas2d(
|
||||||
pattern.to_fill_or_stroke_style()))).unwrap();
|
Canvas2dMsg::SetFillStyle(pattern.to_fill_or_stroke_style()));
|
||||||
|
self.ipc_renderer.send(msg).unwrap();
|
||||||
|
if !pattern.origin_is_clean() {
|
||||||
|
self.set_origin_unclean();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -975,6 +1025,11 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
sw: Finite<f64>,
|
sw: Finite<f64>,
|
||||||
sh: Finite<f64>)
|
sh: Finite<f64>)
|
||||||
-> Fallible<Root<ImageData>> {
|
-> Fallible<Root<ImageData>> {
|
||||||
|
|
||||||
|
if !self.origin_is_clean() {
|
||||||
|
return Err(Error::Security)
|
||||||
|
}
|
||||||
|
|
||||||
let mut sx = *sx;
|
let mut sx = *sx;
|
||||||
let mut sy = *sy;
|
let mut sy = *sy;
|
||||||
let mut sw = *sw;
|
let mut sw = *sw;
|
||||||
|
@ -1095,38 +1150,34 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
repetition: DOMString)
|
repetition: DOMString)
|
||||||
-> Fallible<Root<CanvasPattern>> {
|
-> Fallible<Root<CanvasPattern>> {
|
||||||
let (image_data, image_size) = match image {
|
let (image_data, image_size) = match image {
|
||||||
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLImageElement(image) => {
|
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLImageElement(ref image) => {
|
||||||
// https://html.spec.whatwg.org/multipage/#img-error
|
// https://html.spec.whatwg.org/multipage/#img-error
|
||||||
// If the image argument is an HTMLImageElement object that is in the broken state,
|
// If the image argument is an HTMLImageElement object that is in the broken state,
|
||||||
// then throw an InvalidStateError exception
|
// then throw an InvalidStateError exception
|
||||||
match self.fetch_image_data(&image.r()) {
|
try!(self.fetch_image_data(&image.r()).ok_or(Error::InvalidState))
|
||||||
Some((data, size)) => (data, size),
|
|
||||||
None => return Err(Error::InvalidState),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(canvas) => {
|
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(ref canvas) => {
|
||||||
let _ = canvas.get_or_init_2d_context();
|
let _ = canvas.get_or_init_2d_context();
|
||||||
|
|
||||||
match canvas.fetch_all_data() {
|
try!(canvas.fetch_all_data().ok_or(Error::InvalidState))
|
||||||
Some((data, size)) => (data, size),
|
|
||||||
None => return Err(Error::InvalidState),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(context) => {
|
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(ref context) => {
|
||||||
let canvas = context.Canvas();
|
let canvas = context.Canvas();
|
||||||
let _ = canvas.get_or_init_2d_context();
|
let _ = canvas.get_or_init_2d_context();
|
||||||
|
|
||||||
match canvas.fetch_all_data() {
|
try!(canvas.fetch_all_data().ok_or(Error::InvalidState))
|
||||||
Some((data, size)) => (data, size),
|
|
||||||
None => return Err(Error::InvalidState),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(rep) = RepetitionStyle::from_str(&repetition) {
|
if let Ok(rep) = RepetitionStyle::from_str(&repetition) {
|
||||||
return Ok(CanvasPattern::new(self.global.root().r(), image_data, image_size, rep));
|
Ok(CanvasPattern::new(self.global.root().r(),
|
||||||
|
image_data,
|
||||||
|
image_size,
|
||||||
|
rep,
|
||||||
|
self.is_origin_clean(image)))
|
||||||
|
} else {
|
||||||
|
Err(Error::Syntax)
|
||||||
}
|
}
|
||||||
return Err(Error::Syntax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth
|
||||||
|
|
|
@ -90,6 +90,13 @@ impl HTMLCanvasElement {
|
||||||
pub fn get_size(&self) -> Size2D<i32> {
|
pub fn get_size(&self) -> Size2D<i32> {
|
||||||
Size2D::new(self.Width() as i32, self.Height() as i32)
|
Size2D::new(self.Width() as i32, self.Height() as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn origin_is_clean(&self) -> bool {
|
||||||
|
match *self.context.borrow() {
|
||||||
|
Some(CanvasContext::Context2d(ref context)) => context.origin_is_clean(),
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HTMLCanvasData {
|
pub struct HTMLCanvasData {
|
||||||
|
@ -251,8 +258,12 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
|
||||||
_mime_type: Option<DOMString>,
|
_mime_type: Option<DOMString>,
|
||||||
_arguments: Vec<HandleValue>) -> Fallible<DOMString> {
|
_arguments: Vec<HandleValue>) -> Fallible<DOMString> {
|
||||||
|
|
||||||
// Step 1: Check the origin-clean flag (should be set in fillText/strokeText
|
if let Some(CanvasContext::Context2d(ref context)) = *self.context.borrow() {
|
||||||
// and currently unimplemented)
|
|
||||||
|
// Step 1.
|
||||||
|
if !context.origin_is_clean() {
|
||||||
|
return Err(Error::Security);
|
||||||
|
}
|
||||||
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
if self.Width() == 0 || self.Height() == 0 {
|
if self.Width() == 0 || self.Height() == 0 {
|
||||||
|
@ -260,7 +271,6 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
if let Some(CanvasContext::Context2d(ref context)) = *self.context.borrow() {
|
|
||||||
let window = window_from_node(self);
|
let window = window_from_node(self);
|
||||||
let image_data = try!(context.GetImageData(Finite::wrap(0f64), Finite::wrap(0f64),
|
let image_data = try!(context.GetImageData(Finite::wrap(0f64), Finite::wrap(0f64),
|
||||||
Finite::wrap(self.Width() as f64),
|
Finite::wrap(self.Width() as f64),
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[security.dataURI.html]
|
||||||
|
type: testharness
|
||||||
|
[data: URIs do not count as different-origin, and do not taint the canvas]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[security.drawImage.canvas.sub.html]
|
|
||||||
type: testharness
|
|
||||||
[drawImage of unclean canvas makes the canvas origin-unclean]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[security.drawImage.image.sub.html]
|
|
||||||
type: testharness
|
|
||||||
[drawImage of different-origin image makes the canvas origin-unclean]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[security.pattern.canvas.fillStyle.sub.html]
|
|
||||||
type: testharness
|
|
||||||
[Setting fillStyle to a pattern of an unclean canvas makes the canvas origin-unclean]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[security.pattern.canvas.strokeStyle.sub.html]
|
|
||||||
type: testharness
|
|
||||||
[Setting strokeStyle to a pattern of an unclean canvas makes the canvas origin-unclean]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[security.pattern.cross.sub.html]
|
|
||||||
type: testharness
|
|
||||||
[Using an unclean pattern makes the target canvas origin-unclean, not the pattern canvas]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[security.pattern.image.fillStyle.sub.html]
|
|
||||||
type: testharness
|
|
||||||
[Setting fillStyle to a pattern of a different-origin image makes the canvas origin-unclean]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[security.pattern.image.strokeStyle.sub.html]
|
|
||||||
type: testharness
|
|
||||||
[Setting strokeStyle to a pattern of a different-origin image makes the canvas origin-unclean]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[security.reset.sub.html]
|
|
||||||
type: testharness
|
|
||||||
[Resetting the canvas state does not reset the origin-clean flag]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[toDataURL.jpeg.primarycolours.html]
|
||||||
|
type: testharness
|
||||||
|
[toDataURL with JPEG handles simple colours correctly]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[toDataURL.png.complexcolours.html]
|
||||||
|
type: testharness
|
||||||
|
[toDataURL with PNG handles non-primary and non-solid colours correctly]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[toDataURL.png.primarycolours.html]
|
||||||
|
type: testharness
|
||||||
|
[toDataURL with PNG handles simple colours correctly]
|
||||||
|
expected: FAIL
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue