diff options
author | Anthony Ramine <n.oxyde@gmail.com> | 2018-10-08 12:19:10 +0200 |
---|---|---|
committer | Anthony Ramine <n.oxyde@gmail.com> | 2018-10-08 12:19:10 +0200 |
commit | 551c405b0fc03350109b560f75169edf43284297 (patch) | |
tree | e6cbaa95a06cbd7a8a045debad0480baeeb6a8f1 | |
parent | 77c28bdfc9050c645eaae02b0f11636fc73a11fb (diff) | |
download | servo-551c405b0fc03350109b560f75169edf43284297.tar.gz servo-551c405b0fc03350109b560f75169edf43284297.zip |
Avoid ctx.getImageData in canvas.toDataURL
-rw-r--r-- | components/script/dom/canvasrenderingcontext2d.rs | 35 | ||||
-rw-r--r-- | components/script/dom/htmlcanvaselement.rs | 16 |
2 files changed, 29 insertions, 22 deletions
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 5aa1518932d..2617f9e7ed5 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -575,6 +575,28 @@ impl CanvasRenderingContext2D { fn set_origin_unclean(&self) { self.origin_clean.set(false) } + + pub fn get_rect(&self, rect: Rect<u32>) -> Vec<u8> { + assert!(self.origin_is_clean()); + + // FIXME(nox): This is probably wrong when this is a context for an + // offscreen canvas. + let canvas_size = self.canvas.as_ref().map_or(Size2D::zero(), |c| c.get_size()); + assert!(Rect::from_size(canvas_size).contains_rect(&rect)); + + let (sender, receiver) = ipc::bytes_channel().unwrap(); + self.send_canvas_2d_msg(Canvas2dMsg::GetImageData(rect, canvas_size, sender)); + let mut pixels = receiver.recv().unwrap().to_vec(); + + for chunk in pixels.chunks_mut(4) { + let b = chunk[0]; + chunk[0] = UNPREMULTIPLY_TABLE[256 * (chunk[3] as usize) + chunk[2] as usize]; + chunk[1] = UNPREMULTIPLY_TABLE[256 * (chunk[3] as usize) + chunk[1] as usize]; + chunk[2] = UNPREMULTIPLY_TABLE[256 * (chunk[3] as usize) + b as usize]; + } + + pixels + } } pub trait LayoutCanvasRenderingContext2DHelpers { @@ -1154,18 +1176,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { }, }; - let (sender, receiver) = ipc::bytes_channel().unwrap(); - self.send_canvas_2d_msg(Canvas2dMsg::GetImageData(read_rect, canvas_size, sender)); - let mut pixels = receiver.recv().unwrap().to_vec(); - - for chunk in pixels.chunks_mut(4) { - let b = chunk[0]; - chunk[0] = UNPREMULTIPLY_TABLE[256 * (chunk[3] as usize) + chunk[2] as usize]; - chunk[1] = UNPREMULTIPLY_TABLE[256 * (chunk[3] as usize) + chunk[1] as usize]; - chunk[2] = UNPREMULTIPLY_TABLE[256 * (chunk[3] as usize) + b as usize]; - } - - ImageData::new(&self.global(), size.width, size.height, Some(pixels)) + ImageData::new(&self.global(), size.width, size.height, Some(self.get_rect(read_rect))) } // https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 78e74641347..798c4e9d93c 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -7,7 +7,6 @@ use canvas_traits::canvas::{CanvasMsg, CanvasId, FromScriptMsg}; use canvas_traits::webgl::WebGLVersion; use dom::attr::Attr; use dom::bindings::cell::DomRefCell; -use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods; use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding; use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::{HTMLCanvasElementMethods, RenderingContext}; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLContextAttributes; @@ -27,7 +26,7 @@ use dom::virtualmethods::VirtualMethods; use dom::webgl2renderingcontext::WebGL2RenderingContext; use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext}; use dom_struct::dom_struct; -use euclid::Size2D; +use euclid::{Rect, Size2D}; use html5ever::{LocalName, Prefix}; use image::ColorType; use image::png::PNGEncoder; @@ -354,10 +353,8 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { _quality: HandleValue, ) -> Fallible<USVString> { // Step 1. - if let Some(CanvasContext::Context2d(ref context)) = *self.context.borrow() { - if !context.origin_is_clean() { - return Err(Error::Security); - } + if !self.origin_is_clean() { + return Err(Error::Security); } // Step 2. @@ -366,10 +363,9 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { } // Step 3. - let raw_data = match *self.context.borrow() { + let file = match *self.context.borrow() { Some(CanvasContext::Context2d(ref context)) => { - // FIXME(nox): This shouldn't go through ImageData etc. - context.GetImageData(0, 0, self.Width() as i32, self.Height() as i32)?.to_vec() + context.get_rect(Rect::from_size(self.get_size())) }, Some(CanvasContext::WebGL(ref context)) => { match context.get_image_data(self.Width(), self.Height()) { @@ -392,7 +388,7 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { // FIXME: Only handle image/png for now. let mut png = Vec::new(); PNGEncoder::new(&mut png) - .encode(&raw_data, self.Width(), self.Height(), ColorType::RGBA(8)) + .encode(&file, self.Width(), self.Height(), ColorType::RGBA(8)) .unwrap(); let mut url = "data:image/png;base64,".to_owned(); // FIXME(nox): Should this use base64::URL_SAFE? |