Skip to content

Commit

Permalink
Improve gl.putImageData
Browse files Browse the repository at this point in the history
This commit should allow us to send smaller blobs to the canvas thread,
I made it into its own commit just to try=wpt.
  • Loading branch information
nox committed Oct 5, 2018
1 parent 3d910fe commit 82c7d71
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 8 deletions.
9 changes: 3 additions & 6 deletions components/canvas/canvas_data.rs
Expand Up @@ -454,14 +454,13 @@ impl<'a> CanvasData<'a> {
imagedata: Vec<u8>,
offset: Vector2D<i32>,
image_data_size: Size2D<i32>,
dirty_rect: Rect<i32>,
dest_rect: Rect<i32>,
) {
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 =
Expand All @@ -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());
}
}

Expand Down
30 changes: 28 additions & 2 deletions components/script/dom/canvasrenderingcontext2d.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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),
Expand Down

0 comments on commit 82c7d71

Please sign in to comment.