diff options
-rw-r--r-- | components/canvas/canvas_data.rs | 45 | ||||
-rw-r--r-- | components/canvas/canvas_paint_thread.rs | 14 | ||||
-rw-r--r-- | components/canvas_traits/canvas.rs | 2 | ||||
-rw-r--r-- | components/script/dom/canvasrenderingcontext2d.rs | 13 | ||||
-rw-r--r-- | components/script/dom/imagedata.rs | 33 |
5 files changed, 52 insertions, 55 deletions
diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index d4f083ae1e8..30e6218d604 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -13,6 +13,7 @@ use cssparser::RGBA; use euclid::{Transform2D, Point2D, Vector2D, Rect, Size2D}; use ipc_channel::ipc::{IpcBytesSender, IpcSender}; use num_traits::ToPrimitive; +use pixels; use serde_bytes::ByteBuf; use std::mem; use std::sync::Arc; @@ -451,42 +452,22 @@ impl<'a> CanvasData<'a> { // https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata pub fn put_image_data( &mut self, - imagedata: Vec<u8>, + mut imagedata: Vec<u8>, offset: Vector2D<i32>, - image_data_size: Size2D<i32>, - dest_rect: Rect<i32>, + imagedata_size: Size2D<i32>, ) { - assert_eq!(image_data_size.width * image_data_size.height * 4, imagedata.len() as i32); - - let image_size = image_data_size; - - 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 = - Vec::with_capacity((dest_rect.size.width * dest_rect.size.height * 4) as usize); - - for _ in 0 .. dest_rect.size.height { - let mut src_offset = src_line; - for _ in 0 .. dest_rect.size.width { - let alpha = imagedata[src_offset + 3] as u16; - // add 127 before dividing for more accurate rounding - let premultiply_channel = |channel: u8| (((channel as u16 * alpha) + 127) / 255) as u8; - dest.push(premultiply_channel(imagedata[src_offset + 2])); - dest.push(premultiply_channel(imagedata[src_offset + 1])); - dest.push(premultiply_channel(imagedata[src_offset + 0])); - dest.push(imagedata[src_offset + 3]); - src_offset += 4; - } - src_line += (image_size.width * 4) as usize; - } - + assert_eq!(imagedata_size.area() * 4, imagedata.len() as i32); + pixels::byte_swap_and_premultiply_inplace(&mut imagedata); if let Some(source_surface) = self.drawtarget.create_source_surface_from_data( - &dest, - dest_rect.size, - dest_rect.size.width * 4, + &imagedata, + imagedata_size, + imagedata_size.width * 4, SurfaceFormat::B8G8R8A8) { - self.drawtarget.copy_surface(source_surface, Rect::from_size(dest_rect.size), offset.to_point()); + self.drawtarget.copy_surface( + source_surface, + Rect::from_size(imagedata_size), + offset.to_point(), + ); } } diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index 91164a47cf0..465d2cadd45 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -241,18 +241,8 @@ impl<'a> CanvasPaintThread <'a> { Canvas2dMsg::GetImageData(dest_rect, canvas_size, chan) => { self.canvas(canvas_id).image_data(dest_rect, canvas_size, chan) }, - Canvas2dMsg::PutImageData( - imagedata, - offset, - image_data_size, - dirty_rect, - ) => { - self.canvas(canvas_id).put_image_data( - imagedata.into(), - offset, - image_data_size, - dirty_rect, - ) + Canvas2dMsg::PutImageData(imagedata, offset, imagedata_size) => { + self.canvas(canvas_id).put_image_data(imagedata.into(), offset, imagedata_size) }, Canvas2dMsg::SetShadowOffsetX(value) => { self.canvas(canvas_id).set_shadow_offset_x(value) diff --git a/components/canvas_traits/canvas.rs b/components/canvas_traits/canvas.rs index 6c7022c62a8..b0c2fb4f2bc 100644 --- a/components/canvas_traits/canvas.rs +++ b/components/canvas_traits/canvas.rs @@ -54,7 +54,7 @@ pub enum Canvas2dMsg { IsPointInPath(f64, f64, FillRule, IpcSender<bool>), LineTo(Point2D<f32>), MoveTo(Point2D<f32>), - PutImageData(ByteBuf, Vector2D<i32>, Size2D<i32>, Rect<i32>), + PutImageData(ByteBuf, Vector2D<i32>, Size2D<i32>), QuadraticCurveTo(Point2D<f32>, Point2D<f32>), Rect(Rect<f32>), RestoreContext, diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 15b6eb9560f..1f3b9ab92cd 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -1277,19 +1277,14 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { return; } - // FIXME(nox): There is no need to make a Vec<u8> of all the pixels - // if we didn't want to put the entire image. - let buffer = imagedata.get_data_array(); + let dirty_size = Size2D::new(dirty_width, dirty_height); + let dirty_rect = Rect::new(Point2D::new(dirty_x, dirty_y), dirty_size); // Step 7. self.send_canvas_2d_msg(Canvas2dMsg::PutImageData( - buffer.into(), + imagedata.get_rect(dirty_rect.try_cast().unwrap()).into(), origin.to_vector(), - imagedata_size, - Rect::new( - Point2D::new(dirty_x, dirty_y), - Size2D::new(dirty_width, dirty_height), - ), + dirty_size, )); self.mark_as_dirty(); } diff --git a/components/script/dom/imagedata.rs b/components/script/dom/imagedata.rs index ea65d533ffe..e219845675b 100644 --- a/components/script/dom/imagedata.rs +++ b/components/script/dom/imagedata.rs @@ -9,7 +9,7 @@ use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::bindings::root::DomRoot; use dom::globalscope::GlobalScope; use dom_struct::dom_struct; -use euclid::Size2D; +use euclid::{Rect, Size2D}; use js::jsapi::{Heap, JSContext, JSObject}; use js::rust::Runtime; use js::typedarray::{Uint8ClampedArray, CreateWith}; @@ -149,9 +149,40 @@ impl ImageData { } } + #[allow(unsafe_code)] + pub fn get_rect(&self, rect: Rect<u32>) -> Vec<u8> { + unsafe { + assert!(!rect.is_empty()); + assert!(self.rect().contains_rect(&rect)); + assert!(!self.data.get().is_null()); + let cx = Runtime::get(); + assert!(!cx.is_null()); + typedarray!(in(cx) let array: Uint8ClampedArray = self.data.get()); + let slice = array.as_ref().unwrap().as_slice(); + let area = rect.size.area() as usize; + let first_column_start = rect.origin.x as usize * 4; + let row_length = self.width as usize * 4; + let first_row_start = rect.origin.y as usize * row_length; + if rect.origin.x == 0 && rect.size.width == self.width || rect.size.height == 1 { + let start = first_column_start + first_row_start; + // FIXME(nox): This should be a borrow. + return slice[start..start + area * 4].into(); + } + let mut data = Vec::with_capacity(area * 4); + for row in slice[first_row_start..].chunks(row_length).take(rect.size.height as usize) { + data.extend_from_slice(&row[first_column_start..][..rect.size.width as usize * 4]); + } + data + } + } + pub fn get_size(&self) -> Size2D<u32> { Size2D::new(self.Width(), self.Height()) } + + pub fn rect(&self) -> Rect<u32> { + Rect::from_size(self.get_size()) + } } impl ImageDataMethods for ImageData { |