From 82c7d71811c072a29fb73df49664490dcba2d82f Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 4 Oct 2018 16:29:45 +0200 Subject: [PATCH] Improve gl.putImageData This commit should allow us to send smaller blobs to the canvas thread, I made it into its own commit just to try=wpt. --- components/canvas/canvas_data.rs | 9 ++---- .../script/dom/canvasrenderingcontext2d.rs | 30 +++++++++++++++++-- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index 31db18a2e0b..d4f083ae1e8 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -454,14 +454,13 @@ impl<'a> CanvasData<'a> { imagedata: Vec, offset: Vector2D, image_data_size: Size2D, - dirty_rect: Rect, + dest_rect: Rect, ) { assert_eq!(image_data_size.width * image_data_size.height * 4, imagedata.len() as i32); - let dest_rect = dirty_rect.translate(&offset); let image_size = image_data_size; - let first_pixel = dest_rect.origin - offset; + let first_pixel = dest_rect.origin; let mut src_line = (first_pixel.y * (image_size.width * 4) + first_pixel.x * 4) as usize; let mut dest = @@ -487,9 +486,7 @@ impl<'a> CanvasData<'a> { dest_rect.size, dest_rect.size.width * 4, SurfaceFormat::B8G8R8A8) { - self.drawtarget.copy_surface(source_surface, - Rect::new(Point2D::new(0, 0), dest_rect.size), - dest_rect.origin); + self.drawtarget.copy_surface(source_surface, Rect::from_size(dest_rect.size), offset.to_point()); } } diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 31298ccb648..9adbaa3a734 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -31,7 +31,7 @@ use dom::htmlcanvaselement::{CanvasContext, HTMLCanvasElement}; use dom::imagedata::ImageData; use dom::node::{Node, NodeDamage, window_from_node}; use dom_struct::dom_struct; -use euclid::{Transform2D, Point2D, Vector2D, Rect, Size2D, vec2}; +use euclid::{Transform2D, Point2D, Rect, Size2D, vec2}; use ipc_channel::ipc::{self, IpcSender}; use net_traits::image::base::PixelFormat; use net_traits::image_cache::CanRequestImages; @@ -1206,6 +1206,9 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { mut dirty_width: i32, mut dirty_height: i32, ) { + // FIXME(nox): There are many arithmetic operations here that can + // overflow or underflow, this should probably be audited. + let imagedata_size = Size2D::new(imagedata.Width() as i32, imagedata.Height() as i32); if imagedata_size.width <= 0 || imagedata_size.height <= 0 { return; @@ -1227,6 +1230,21 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { dirty_height = -dirty_height; } + // Ignore any pixel that would be drawn before the beginning of the + // canvas surface. + let mut dest_x = dx + dirty_x; + let mut dest_y = dy + dirty_y; + if dest_x < 0 { + dirty_x -= dest_x; + dirty_width += dest_x; + dest_x = 0; + } + if dest_y < 0 { + dirty_y -= dest_y; + dirty_height += dest_y; + dest_y = 0; + } + // Step 4. if dirty_x < 0 { dirty_width += dirty_x; @@ -1245,6 +1263,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { dirty_height = imagedata_size.height - dirty_y; } + // We take care of ignoring any pixel that would be drawn after the end + // of the canvas surface. + let canvas_size = self.canvas.as_ref().map_or(Size2D::zero(), |c| c.get_size()).to_i32(); + let origin = Point2D::new(dest_x, dest_y); + let drawable_size = (origin - canvas_size.to_vector().to_point()).to_size().abs(); + dirty_width = dirty_width.min(drawable_size.width); + dirty_height = dirty_height.min(drawable_size.height); + // Step 6. if dirty_width <= 0 || dirty_height <= 0 { return; @@ -1257,7 +1283,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { // Step 7. self.send_canvas_2d_msg(Canvas2dMsg::PutImageData( buffer.into(), - Vector2D::new(dx, dy), + origin.to_vector(), imagedata_size, Rect::new( Point2D::new(dirty_x, dirty_y),