aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnthony Ramine <n.oxyde@gmail.com>2018-10-08 12:19:10 +0200
committerAnthony Ramine <n.oxyde@gmail.com>2018-10-08 12:19:10 +0200
commit551c405b0fc03350109b560f75169edf43284297 (patch)
treee6cbaa95a06cbd7a8a045debad0480baeeb6a8f1
parent77c28bdfc9050c645eaae02b0f11636fc73a11fb (diff)
downloadservo-551c405b0fc03350109b560f75169edf43284297.tar.gz
servo-551c405b0fc03350109b560f75169edf43284297.zip
Avoid ctx.getImageData in canvas.toDataURL
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs35
-rw-r--r--components/script/dom/htmlcanvaselement.rs16
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?