diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/canvaspattern.rs | 14 | ||||
-rw-r--r-- | components/script/dom/canvasrenderingcontext2d.rs | 119 | ||||
-rw-r--r-- | components/script/dom/htmlcanvaselement.rs | 26 |
3 files changed, 114 insertions, 45 deletions
diff --git a/components/script/dom/canvaspattern.rs b/components/script/dom/canvaspattern.rs index 3eec8beb3bc..059710a296b 100644 --- a/components/script/dom/canvaspattern.rs +++ b/components/script/dom/canvaspattern.rs @@ -18,12 +18,14 @@ pub struct CanvasPattern { surface_size: Size2D<i32>, repeat_x: bool, repeat_y: bool, + origin_clean: bool, } impl CanvasPattern { fn new_inherited(surface_data: Vec<u8>, surface_size: Size2D<i32>, - repeat: RepetitionStyle) + repeat: RepetitionStyle, + origin_clean: bool) -> CanvasPattern { let (x, y) = match repeat { RepetitionStyle::Repeat => (true, true), @@ -38,17 +40,23 @@ impl CanvasPattern { surface_size: surface_size, repeat_x: x, repeat_y: y, + origin_clean: origin_clean, } } pub fn new(global: GlobalRef, surface_data: Vec<u8>, surface_size: Size2D<i32>, - repeat: RepetitionStyle) + repeat: RepetitionStyle, + origin_clean: bool) -> 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, CanvasPatternBinding::Wrap) } + pub fn origin_is_clean(&self) -> bool { + self.origin_clean + } } impl<'a> ToFillOrStrokeStyle for &'a CanvasPattern { diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 22e1c388f59..05a4b875852 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -39,6 +39,7 @@ use net_traits::image::base::PixelFormat; use net_traits::image_cache_task::ImageResponse; use num::{Float, ToPrimitive}; use script_traits::ScriptMsg as ConstellationMsg; +use std::cell::Cell; use std::str::FromStr; use std::sync::mpsc::channel; use std::{cmp, fmt}; @@ -66,6 +67,7 @@ pub struct CanvasRenderingContext2D { canvas: JS<HTMLCanvasElement>, state: DOMRefCell<CanvasContextState>, saved_states: DOMRefCell<Vec<CanvasContextState>>, + origin_clean: Cell<bool>, } #[must_root] @@ -131,6 +133,7 @@ impl CanvasRenderingContext2D { canvas: JS::from_ref(canvas), state: DOMRefCell::new(CanvasContextState::new()), saved_states: DOMRefCell::new(Vec::new()), + origin_clean: Cell::new(true), } } @@ -222,6 +225,29 @@ impl CanvasRenderingContext2D { (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 // @@ -254,19 +280,20 @@ impl CanvasRenderingContext2D { dw: Option<f64>, dh: Option<f64>) -> Fallible<()> { - match image { - HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(canvas) => + let result = match image { + HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(ref canvas) => { self.draw_html_canvas_element(canvas.r(), sx, sy, sw, sh, - dx, dy, dw, dh), - HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(image) => { + dx, dy, dw, dh) + } + HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(ref image) => { let context = image.r(); let canvas = context.Canvas(); self.draw_html_canvas_element(canvas.r(), sx, sy, sw, sh, dx, dy, dw, dh) } - HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLImageElement(image) => { + HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLImageElement(ref image) => { let image_element = image.r(); // https://html.spec.whatwg.org/multipage/#img-error // If the image argument is an HTMLImageElement object that is in the broken state, @@ -290,7 +317,14 @@ impl CanvasRenderingContext2D { sx, sy, sw, sh, 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, @@ -475,6 +509,14 @@ impl CanvasRenderingContext2D { pub fn get_ipc_renderer(&self) -> IpcSender<CanvasMsg> { 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 { @@ -887,15 +929,12 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { fn SetStrokeStyle(&self, value: StringOrCanvasGradientOrCanvasPattern) { match value { StringOrCanvasGradientOrCanvasPattern::eString(string) => { - match self.parse_color(&string) { - Ok(rgba) => { - self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba); - self.ipc_renderer - .send(CanvasMsg::Canvas2d(Canvas2dMsg::SetStrokeStyle( - FillOrStrokeStyle::Color(rgba)))) - .unwrap(); - } - _ => {} + if let Ok(rgba) = self.parse_color(&string) { + self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Color(rgba); + self.ipc_renderer + .send(CanvasMsg::Canvas2d(Canvas2dMsg::SetStrokeStyle( + FillOrStrokeStyle::Color(rgba)))) + .unwrap(); } }, StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient) => { @@ -905,7 +944,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { Canvas2dMsg::SetStrokeStyle(gradient.to_fill_or_stroke_style())); 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(); } StringOrCanvasGradientOrCanvasPattern::eCanvasPattern(pattern) => { - self.ipc_renderer.send(CanvasMsg::Canvas2d(Canvas2dMsg::SetFillStyle( - pattern.to_fill_or_stroke_style()))).unwrap(); + let msg = CanvasMsg::Canvas2d( + 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>, sh: Finite<f64>) -> Fallible<Root<ImageData>> { + + if !self.origin_is_clean() { + return Err(Error::Security) + } + let mut sx = *sx; let mut sy = *sy; let mut sw = *sw; @@ -1095,38 +1150,34 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { repetition: DOMString) -> Fallible<Root<CanvasPattern>> { let (image_data, image_size) = match image { - HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLImageElement(image) => { + HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLImageElement(ref image) => { // https://html.spec.whatwg.org/multipage/#img-error // If the image argument is an HTMLImageElement object that is in the broken state, // then throw an InvalidStateError exception - match self.fetch_image_data(&image.r()) { - Some((data, size)) => (data, size), - None => return Err(Error::InvalidState), - } + try!(self.fetch_image_data(&image.r()).ok_or(Error::InvalidState)) }, - HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(canvas) => { + HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(ref canvas) => { let _ = canvas.get_or_init_2d_context(); - match canvas.fetch_all_data() { - Some((data, size)) => (data, size), - None => return Err(Error::InvalidState), - } + try!(canvas.fetch_all_data().ok_or(Error::InvalidState)) }, - HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(context) => { + HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(ref context) => { let canvas = context.Canvas(); let _ = canvas.get_or_init_2d_context(); - match canvas.fetch_all_data() { - Some((data, size)) => (data, size), - None => return Err(Error::InvalidState), - } + try!(canvas.fetch_all_data().ok_or(Error::InvalidState)) } }; 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 diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index cd3cb0942da..2fa7a233c75 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -90,6 +90,13 @@ impl HTMLCanvasElement { pub fn get_size(&self) -> Size2D<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 { @@ -251,16 +258,19 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { _mime_type: Option<DOMString>, _arguments: Vec<HandleValue>) -> Fallible<DOMString> { - // Step 1: Check the origin-clean flag (should be set in fillText/strokeText - // and currently unimplemented) + if let Some(CanvasContext::Context2d(ref context)) = *self.context.borrow() { - // Step 2. - if self.Width() == 0 || self.Height() == 0 { - return Ok(DOMString::from("data:,")); - } + // Step 1. + if !context.origin_is_clean() { + return Err(Error::Security); + } - // Step 3. - if let Some(CanvasContext::Context2d(ref context)) = *self.context.borrow() { + // Step 2. + if self.Width() == 0 || self.Height() == 0 { + return Ok(DOMString::from("data:,")); + } + + // Step 3. let window = window_from_node(self); let image_data = try!(context.GetImageData(Finite::wrap(0f64), Finite::wrap(0f64), Finite::wrap(self.Width() as f64), |