aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/canvas/canvas_data.rs45
-rw-r--r--components/canvas/canvas_paint_thread.rs14
-rw-r--r--components/canvas_traits/canvas.rs2
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs13
-rw-r--r--components/script/dom/imagedata.rs33
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 {