diff options
Diffstat (limited to 'components/script/dom/canvasrenderingcontext2d.rs')
-rw-r--r-- | components/script/dom/canvasrenderingcontext2d.rs | 325 |
1 files changed, 220 insertions, 105 deletions
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 757f7e19cad..527ac5f85fa 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -113,7 +113,9 @@ impl CanvasContextState { } impl CanvasRenderingContext2D { - fn new_inherited(global: GlobalRef, canvas: &HTMLCanvasElement, size: Size2D<i32>) + fn new_inherited(global: GlobalRef, + canvas: &HTMLCanvasElement, + size: Size2D<i32>) -> CanvasRenderingContext2D { let (sender, receiver) = ipc::channel().unwrap(); let constellation_chan = global.constellation_chan(); @@ -130,10 +132,13 @@ impl CanvasRenderingContext2D { } } - pub fn new(global: GlobalRef, canvas: &HTMLCanvasElement, size: Size2D<i32>) + pub fn new(global: GlobalRef, + canvas: &HTMLCanvasElement, + size: Size2D<i32>) -> Root<CanvasRenderingContext2D> { reflect_dom_object(box CanvasRenderingContext2D::new_inherited(global, canvas, size), - global, CanvasRenderingContext2DBinding::Wrap) + global, + CanvasRenderingContext2DBinding::Wrap) } pub fn recreate(&self, size: Size2D<i32>) { @@ -161,9 +166,16 @@ impl CanvasRenderingContext2D { // source rectangle = area of the original image to be copied // destination rectangle = area of the destination canvas where the source image is going to be drawn fn adjust_source_dest_rects(&self, - image_size: Size2D<f64>, - sx: f64, sy: f64, sw: f64, sh: f64, - dx: f64, dy: f64, dw: f64, dh: f64) -> (Rect<f64>, Rect<f64>) { + image_size: Size2D<f64>, + sx: f64, + sy: f64, + sw: f64, + sh: f64, + dx: f64, + dy: f64, + dw: f64, + dh: f64) + -> (Rect<f64>, Rect<f64>) { let image_rect = Rect::new(Point2D::new(0f64, 0f64), Size2D::new(image_size.width as f64, image_size.height as f64)); @@ -221,9 +233,17 @@ impl CanvasRenderingContext2D { // is copied on the rectangle (dx, dy, dh, dw) of the destination canvas // // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage - fn draw_image(&self, image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D, - sx: f64, sy: f64, sw: Option<f64>, sh: Option<f64>, - dx: f64, dy: f64, dw: Option<f64>, dh: Option<f64>) -> Fallible<()> { + fn draw_image(&self, + image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D, + sx: f64, + sy: f64, + sw: Option<f64>, + sh: Option<f64>, + dx: f64, + dy: f64, + dw: Option<f64>, + dh: Option<f64>) + -> Fallible<()> { match image { HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(canvas) => self.draw_html_canvas_element(canvas.r(), @@ -264,12 +284,19 @@ impl CanvasRenderingContext2D { } fn draw_html_canvas_element(&self, - canvas: &HTMLCanvasElement, - sx: f64, sy: f64, sw: Option<f64>, sh: Option<f64>, - dx: f64, dy: f64, dw: Option<f64>, dh: Option<f64>) -> Fallible<()> { + canvas: &HTMLCanvasElement, + sx: f64, + sy: f64, + sw: Option<f64>, + sh: Option<f64>, + dx: f64, + dy: f64, + dw: Option<f64>, + dh: Option<f64>) + -> Fallible<()> { // 1. Check the usability of the image argument if !canvas.is_valid() { - return Err(Error::InvalidState) + return Err(Error::InvalidState); } let canvas_size = canvas.get_size(); @@ -280,18 +307,30 @@ impl CanvasRenderingContext2D { let image_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64); // 2. Establish the source and destination rectangles - let (source_rect, dest_rect) = self.adjust_source_dest_rects(image_size, sx, sy, sw, sh, dx, dy, dw, dh); + let (source_rect, dest_rect) = self.adjust_source_dest_rects(image_size, + sx, + sy, + sw, + sh, + dx, + dy, + dw, + dh); if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) { - return Err(Error::IndexSize) + return Err(Error::IndexSize); } let smoothing_enabled = self.state.borrow().image_smoothing_enabled; // If the source and target canvas are the same let msg = if &*self.canvas == canvas { - CanvasMsg::Canvas2d(Canvas2dMsg::DrawImageSelf(image_size, dest_rect, source_rect, smoothing_enabled)) - } else { // Source and target canvases are different + CanvasMsg::Canvas2d(Canvas2dMsg::DrawImageSelf(image_size, + dest_rect, + source_rect, + smoothing_enabled)) + } else { + // Source and target canvases are different let context = match canvas.get_or_init_2d_context() { Some(context) => context, None => return Err(Error::InvalidState), @@ -302,11 +341,15 @@ impl CanvasRenderingContext2D { // Reads pixels from source image renderer.send(CanvasMsg::Canvas2d(Canvas2dMsg::GetImageData(source_rect.to_i32(), image_size, - sender))).unwrap(); + sender))) + .unwrap(); let imagedata = receiver.recv().unwrap(); // Writes pixels to destination canvas - CanvasMsg::Canvas2d( - Canvas2dMsg::DrawImage(imagedata, source_rect.size, dest_rect, source_rect, smoothing_enabled)) + CanvasMsg::Canvas2d(Canvas2dMsg::DrawImage(imagedata, + source_rect.size, + dest_rect, + source_rect, + smoothing_enabled)) }; self.ipc_renderer.send(msg).unwrap(); @@ -317,13 +360,28 @@ impl CanvasRenderingContext2D { fn draw_image_data(&self, image_data: Vec<u8>, image_size: Size2D<f64>, - sx: f64, sy: f64, sw: f64, sh: f64, - dx: f64, dy: f64, dw: f64, dh: f64) -> Fallible<()> { + sx: f64, + sy: f64, + sw: f64, + sh: f64, + dx: f64, + dy: f64, + dw: f64, + dh: f64) + -> Fallible<()> { // Establish the source and destination rectangles - let (source_rect, dest_rect) = self.adjust_source_dest_rects(image_size, sx, sy, sw, sh, dx, dy, dw, dh); + let (source_rect, dest_rect) = self.adjust_source_dest_rects(image_size, + sx, + sy, + sw, + sh, + dx, + dy, + dw, + dh); if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) { - return Err(Error::IndexSize) + return Err(Error::IndexSize); } let smoothing_enabled = self.state.borrow().image_smoothing_enabled; @@ -338,9 +396,7 @@ impl CanvasRenderingContext2D { Ok(()) } - fn fetch_image_data(&self, - image_element: &HTMLImageElement) - -> Option<(Vec<u8>, Size2D<i32>)> { + fn fetch_image_data(&self, image_element: &HTMLImageElement) -> Option<(Vec<u8>, Size2D<i32>)> { let url = match image_element.get_url() { Some(url) => url, None => return None, @@ -349,7 +405,7 @@ impl CanvasRenderingContext2D { let img = match self.request_image_from_cache(url) { ImageResponse::Loaded(img) => img, ImageResponse::PlaceholderLoaded(_) | ImageResponse::None => { - return None + return None; } }; @@ -379,7 +435,8 @@ impl CanvasRenderingContext2D { return None; } - Some(Rect::new(Point2D::new(x as f32, y as f32), Size2D::new(w as f32, h as f32))) + Some(Rect::new(Point2D::new(x as f32, y as f32), + Size2D::new(w as f32, h as f32))) } pub fn get_renderer_id(&self) -> usize { @@ -609,8 +666,11 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { } // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage - fn DrawImage(&self, image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D, - dx: f64, dy: f64) -> Fallible<()> { + fn DrawImage(&self, + image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D, + dx: f64, + dy: f64) + -> Fallible<()> { if !(dx.is_finite() && dy.is_finite()) { return Ok(()); } @@ -619,10 +679,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { } // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage - fn DrawImage_(&self, image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D, - dx: f64, dy: f64, dw: f64, dh: f64) -> Fallible<()> { - if !(dx.is_finite() && dy.is_finite() && - dw.is_finite() && dh.is_finite()) { + fn DrawImage_(&self, + image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D, + dx: f64, + dy: f64, + dw: f64, + dh: f64) + -> Fallible<()> { + if !(dx.is_finite() && dy.is_finite() && dw.is_finite() && dh.is_finite()) { return Ok(()); } @@ -630,15 +694,31 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { } // https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage - fn DrawImage__(&self, image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D, - sx: f64, sy: f64, sw: f64, sh: f64, - dx: f64, dy: f64, dw: f64, dh: f64) -> Fallible<()> { + fn DrawImage__(&self, + image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D, + sx: f64, + sy: f64, + sw: f64, + sh: f64, + dx: f64, + dy: f64, + dw: f64, + dh: f64) + -> Fallible<()> { if !(sx.is_finite() && sy.is_finite() && sw.is_finite() && sh.is_finite() && dx.is_finite() && dy.is_finite() && dw.is_finite() && dh.is_finite()) { return Ok(()); } - self.draw_image(image, sx, sy, Some(sw), Some(sh), dx, dy, Some(dw), Some(dh)) + self.draw_image(image, + sx, + sy, + Some(sw), + Some(sh), + dx, + dy, + Some(dw), + Some(dh)) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-moveto @@ -647,9 +727,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { return; } - let msg = CanvasMsg::Canvas2d( - Canvas2dMsg::MoveTo( - Point2D::new(x as f32, y as f32))); + let msg = CanvasMsg::Canvas2d(Canvas2dMsg::MoveTo(Point2D::new(x as f32, y as f32))); self.ipc_renderer.send(msg).unwrap(); } @@ -659,9 +737,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { return; } - let msg = CanvasMsg::Canvas2d( - Canvas2dMsg::LineTo( - Point2D::new(x as f32, y as f32))); + let msg = CanvasMsg::Canvas2d(Canvas2dMsg::LineTo(Point2D::new(x as f32, y as f32))); self.ipc_renderer.send(msg).unwrap(); } @@ -677,15 +753,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { // https://html.spec.whatwg.org/multipage/#dom-context-2d-quadraticcurveto fn QuadraticCurveTo(&self, cpx: f64, cpy: f64, x: f64, y: f64) { - if !(cpx.is_finite() && cpy.is_finite() && - x.is_finite() && y.is_finite()) { + if !(cpx.is_finite() && cpy.is_finite() && x.is_finite() && y.is_finite()) { return; } - let msg = CanvasMsg::Canvas2d( - Canvas2dMsg::QuadraticCurveTo( - Point2D::new(cpx as f32, cpy as f32), - Point2D::new(x as f32, y as f32))); + let msg = CanvasMsg::Canvas2d(Canvas2dMsg::QuadraticCurveTo(Point2D::new(cpx as f32, + cpy as f32), + Point2D::new(x as f32, + y as f32))); self.ipc_renderer.send(msg).unwrap(); } @@ -696,17 +771,16 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { return; } - let msg = CanvasMsg::Canvas2d( - Canvas2dMsg::BezierCurveTo( - Point2D::new(cp1x as f32, cp1y as f32), - Point2D::new(cp2x as f32, cp2y as f32), - Point2D::new(x as f32, y as f32))); + let msg = CanvasMsg::Canvas2d(Canvas2dMsg::BezierCurveTo(Point2D::new(cp1x as f32, + cp1y as f32), + Point2D::new(cp2x as f32, + cp2y as f32), + Point2D::new(x as f32, y as f32))); self.ipc_renderer.send(msg).unwrap(); } // https://html.spec.whatwg.org/multipage/#dom-context-2d-arc - fn Arc(&self, x: f64, y: f64, r: f64, - start: f64, end: f64, ccw: bool) -> Fallible<()> { + fn Arc(&self, x: f64, y: f64, r: f64, start: f64, end: f64, ccw: bool) -> Fallible<()> { if !([x, y, r, start, end].iter().all(|x| x.is_finite())) { return Ok(()); } @@ -715,10 +789,11 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { return Err(Error::IndexSize); } - let msg = CanvasMsg::Canvas2d( - Canvas2dMsg::Arc( - Point2D::new(x as f32, y as f32), r as f32, - start as f32, end as f32, ccw)); + let msg = CanvasMsg::Canvas2d(Canvas2dMsg::Arc(Point2D::new(x as f32, y as f32), + r as f32, + start as f32, + end as f32, + ccw)); self.ipc_renderer.send(msg).unwrap(); Ok(()) @@ -733,11 +808,9 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { return Err(Error::IndexSize); } - let msg = CanvasMsg::Canvas2d( - Canvas2dMsg::ArcTo( - Point2D::new(cp1x as f32, cp1y as f32), - Point2D::new(cp2x as f32, cp2y as f32), - r as f32)); + let msg = CanvasMsg::Canvas2d(Canvas2dMsg::ArcTo(Point2D::new(cp1x as f32, cp1y as f32), + Point2D::new(cp2x as f32, cp2y as f32), + r as f32)); self.ipc_renderer.send(msg).unwrap(); Ok(()) } @@ -783,8 +856,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { } }, StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient) => { - self.state.borrow_mut().stroke_style = CanvasFillOrStrokeStyle::Gradient( - JS::from_ref(gradient.r())); + self.state.borrow_mut().stroke_style = + CanvasFillOrStrokeStyle::Gradient(JS::from_ref(gradient.r())); let msg = CanvasMsg::Canvas2d( Canvas2dMsg::SetStrokeStyle(gradient.to_fill_or_stroke_style())); self.ipc_renderer.send(msg).unwrap(); @@ -820,8 +893,8 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { } } StringOrCanvasGradientOrCanvasPattern::eCanvasGradient(gradient) => { - self.state.borrow_mut().fill_style = CanvasFillOrStrokeStyle::Gradient( - JS::from_rooted(&gradient)); + self.state.borrow_mut().fill_style = + CanvasFillOrStrokeStyle::Gradient(JS::from_rooted(&gradient)); let msg = CanvasMsg::Canvas2d( Canvas2dMsg::SetFillStyle(gradient.to_fill_or_stroke_style())); self.ipc_renderer.send(msg).unwrap(); @@ -836,7 +909,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { // https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata fn CreateImageData(&self, sw: Finite<f64>, sh: Finite<f64>) -> Fallible<Root<ImageData>> { if *sw == 0.0 || *sh == 0.0 { - return Err(Error::IndexSize) + return Err(Error::IndexSize); } let sw = cmp::max(1, sw.abs().to_u32().unwrap()); @@ -846,7 +919,10 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { // https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata fn CreateImageData_(&self, imagedata: &ImageData) -> Fallible<Root<ImageData>> { - Ok(ImageData::new(self.global.root().r(), imagedata.Width(), imagedata.Height(), None)) + Ok(ImageData::new(self.global.root().r(), + imagedata.Width(), + imagedata.Height(), + None)) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata @@ -854,14 +930,15 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { sx: Finite<f64>, sy: Finite<f64>, sw: Finite<f64>, - sh: Finite<f64>) -> Fallible<Root<ImageData>> { + sh: Finite<f64>) + -> Fallible<Root<ImageData>> { let mut sx = *sx; let mut sy = *sy; let mut sw = *sw; let mut sh = *sh; if sw == 0.0 || sh == 0.0 { - return Err(Error::IndexSize) + return Err(Error::IndexSize); } if sw < 0.0 { @@ -899,48 +976,81 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { // https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata fn PutImageData(&self, imagedata: &ImageData, dx: Finite<f64>, dy: Finite<f64>) { - self.PutImageData_(imagedata, dx, dy, Finite::wrap(0f64), Finite::wrap(0f64), - Finite::wrap(imagedata.Width() as f64), Finite::wrap(imagedata.Height() as f64)) + self.PutImageData_(imagedata, + dx, + dy, + Finite::wrap(0f64), + Finite::wrap(0f64), + Finite::wrap(imagedata.Width() as f64), + Finite::wrap(imagedata.Height() as f64)) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata - fn PutImageData_(&self, imagedata: &ImageData, dx: Finite<f64>, dy: Finite<f64>, - dirtyX: Finite<f64>, dirtyY: Finite<f64>, dirtyWidth: Finite<f64>, dirtyHeight: Finite<f64>) { + fn PutImageData_(&self, + imagedata: &ImageData, + dx: Finite<f64>, + dy: Finite<f64>, + dirtyX: Finite<f64>, + dirtyY: Finite<f64>, + dirtyWidth: Finite<f64>, + dirtyHeight: Finite<f64>) { let data = imagedata.get_data_array(&self.global.root().r()); let offset = Point2D::new(*dx, *dy); - let image_data_size = Size2D::new(imagedata.Width() as f64, - imagedata.Height() as f64); + let image_data_size = Size2D::new(imagedata.Width() as f64, imagedata.Height() as f64); let dirty_rect = Rect::new(Point2D::new(*dirtyX, *dirtyY), Size2D::new(*dirtyWidth, *dirtyHeight)); - let msg = CanvasMsg::Canvas2d(Canvas2dMsg::PutImageData(data, offset, image_data_size, dirty_rect)); + let msg = CanvasMsg::Canvas2d(Canvas2dMsg::PutImageData(data, + offset, + image_data_size, + dirty_rect)); self.ipc_renderer.send(msg).unwrap(); self.mark_as_dirty(); } // https://html.spec.whatwg.org/multipage/#dom-context-2d-createlineargradient - fn CreateLinearGradient(&self, x0: Finite<f64>, y0: Finite<f64>, - x1: Finite<f64>, y1: Finite<f64>) -> Root<CanvasGradient> { + fn CreateLinearGradient(&self, + x0: Finite<f64>, + y0: Finite<f64>, + x1: Finite<f64>, + y1: Finite<f64>) + -> Root<CanvasGradient> { CanvasGradient::new(self.global.root().r(), - CanvasGradientStyle::Linear(LinearGradientStyle::new(*x0, *y0, *x1, *y1, Vec::new()))) + CanvasGradientStyle::Linear(LinearGradientStyle::new(*x0, + *y0, + *x1, + *y1, + Vec::new()))) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-createradialgradient - fn CreateRadialGradient(&self, x0: Finite<f64>, y0: Finite<f64>, r0: Finite<f64>, - x1: Finite<f64>, y1: Finite<f64>, r1: Finite<f64>) + fn CreateRadialGradient(&self, + x0: Finite<f64>, + y0: Finite<f64>, + r0: Finite<f64>, + x1: Finite<f64>, + y1: Finite<f64>, + r1: Finite<f64>) -> Fallible<Root<CanvasGradient>> { if *r0 < 0. || *r1 < 0. { return Err(Error::IndexSize); } Ok(CanvasGradient::new(self.global.root().r(), - CanvasGradientStyle::Radial( - RadialGradientStyle::new(*x0, *y0, *r0, *x1, *y1, *r1, Vec::new())))) + CanvasGradientStyle::Radial(RadialGradientStyle::new(*x0, + *y0, + *r0, + *x1, + *y1, + *r1, + Vec::new())))) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern - fn CreatePattern(&self, image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D, - repetition: DOMString) -> Fallible<Root<CanvasPattern>> { + fn CreatePattern(&self, + image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D, + repetition: DOMString) + -> Fallible<Root<CanvasPattern>> { let (image_data, image_size) = match image { HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLImageElement(image) => { // https://html.spec.whatwg.org/multipage/#img-error @@ -967,14 +1077,11 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { Some((data, size)) => (data, size), None => return Err(Error::InvalidState), } - }, + } }; if let Ok(rep) = RepetitionStyle::from_str(&repetition) { - return Ok(CanvasPattern::new(self.global.root().r(), - image_data, - image_size, - rep)); + return Ok(CanvasPattern::new(self.global.root().r(), image_data, image_size, rep)); } return Err(Error::Syntax); } @@ -1121,8 +1228,11 @@ pub fn parse_color(string: &str) -> Result<RGBA, ()> { let mut parser = Parser::new(&string); match CSSColor::parse(&mut parser) { Ok(CSSColor::RGBA(rgba)) => { - if parser.is_exhausted() { Ok(rgba) } - else { Err(()) } + if parser.is_exhausted() { + Ok(rgba) + } else { + Err(()) + } }, _ => Err(()), } @@ -1135,18 +1245,23 @@ fn is_rect_valid(rect: Rect<f64>) -> bool { } // https://html.spec.whatwg.org/multipage/#serialisation-of-a-colour -fn serialize<W>(color: &RGBA, dest: &mut W) -> fmt::Result where W: fmt::Write { +fn serialize<W>(color: &RGBA, dest: &mut W) -> fmt::Result + where W: fmt::Write +{ let red = (color.red * 255.).round() as u8; let green = (color.green * 255.).round() as u8; let blue = (color.blue * 255.).round() as u8; if color.alpha == 1f32 { - write!(dest, "#{:x}{:x}{:x}{:x}{:x}{:x}", - red >> 4, red & 0xF, - green >> 4, green & 0xF, - blue >> 4, blue & 0xF) + write!(dest, + "#{:x}{:x}{:x}{:x}{:x}{:x}", + red >> 4, + red & 0xF, + green >> 4, + green & 0xF, + blue >> 4, + blue & 0xF) } else { - write!(dest, "rgba({}, {}, {}, {})", - red, green, blue, color.alpha) + write!(dest, "rgba({}, {}, {}, {})", red, green, blue, color.alpha) } } |