diff options
author | bors-servo <metajack+bors@gmail.com> | 2015-02-22 11:48:46 -0700 |
---|---|---|
committer | bors-servo <metajack+bors@gmail.com> | 2015-02-22 11:48:46 -0700 |
commit | 287f390c4a56dd8c5960df699d45653227b25d6f (patch) | |
tree | 12503aa177afda01e92156174e17b41a948fa284 /components/canvas/canvas_paint_task.rs | |
parent | 3ea09bf2ea8db621107abbc8b358f1c0ce0ffea4 (diff) | |
parent | 325400dce41486ca9bdb4fa8ea07236520e86a50 (diff) | |
download | servo-287f390c4a56dd8c5960df699d45653227b25d6f.tar.gz servo-287f390c4a56dd8c5960df699d45653227b25d6f.zip |
auto merge of #5020 : jdm/servo/canvas, r=jdm
Rebase of #4639.
Diffstat (limited to 'components/canvas/canvas_paint_task.rs')
-rw-r--r-- | components/canvas/canvas_paint_task.rs | 108 |
1 files changed, 107 insertions, 1 deletions
diff --git a/components/canvas/canvas_paint_task.rs b/components/canvas/canvas_paint_task.rs index 095a8d76aca..6d7b0c0fb18 100644 --- a/components/canvas/canvas_paint_task.rs +++ b/components/canvas/canvas_paint_task.rs @@ -3,13 +3,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use azure::azure_hl::{DrawTarget, SurfaceFormat, BackendType, StrokeOptions, DrawOptions}; -use azure::azure_hl::{ColorPattern, PatternRef, JoinStyle, CapStyle}; +use azure::azure_hl::{ColorPattern, PatternRef, JoinStyle, CapStyle, DrawSurfaceOptions, Filter}; +use azure::AzFloat; +use geom::point::Point2D; use geom::rect::Rect; use geom::size::Size2D; use gfx::color; use util::task::spawn_named; +use util::vec::byte_swap; use std::borrow::ToOwned; +use std::ops::Add; use std::sync::mpsc::{channel, Sender}; #[derive(Clone)] @@ -19,6 +23,8 @@ pub enum CanvasMsg { StrokeRect(Rect<f32>), Recreate(Size2D<i32>), SendPixelContents(Sender<Vec<u8>>), + GetImageData(Rect<i32>, Size2D<i32>, Sender<Vec<u8>>), + PutImageData(Vec<u8>, Rect<i32>, Option<Rect<i32>>, Size2D<i32>), Close, } @@ -51,6 +57,9 @@ impl<'a> CanvasPaintTask<'a> { CanvasMsg::ClearRect(ref rect) => painter.clear_rect(rect), CanvasMsg::Recreate(size) => painter.recreate(size), CanvasMsg::SendPixelContents(chan) => painter.send_pixel_contents(chan), + CanvasMsg::GetImageData(dest_rect, canvas_size, chan) => painter.get_image_data(dest_rect, canvas_size, chan), + CanvasMsg::PutImageData(imagedata, image_data_rect, dirty_rect, canvas_size) + => painter.put_image_data(imagedata, image_data_rect, dirty_rect, canvas_size), CanvasMsg::Close => break, } } @@ -85,4 +94,101 @@ impl<'a> CanvasPaintTask<'a> { chan.send(element.to_vec()).unwrap(); }) } + + fn get_image_data(&self, mut dest_rect: Rect<i32>, canvas_size: Size2D<i32>, chan: Sender<Vec<u8>>) { + if dest_rect.size.width < 0 { + dest_rect.size.width = -dest_rect.size.width; + dest_rect.origin.x -= dest_rect.size.width; + } + if dest_rect.size.height < 0 { + dest_rect.size.height = -dest_rect.size.height; + dest_rect.origin.y -= dest_rect.size.height; + } + if dest_rect.size.width == 0 { + dest_rect.size.width = 1; + } + if dest_rect.size.height == 0 { + dest_rect.size.height = 1; + } + + let canvas_rect = Rect(Point2D(0i32, 0i32), canvas_size); + let src_read_rect = canvas_rect.intersection(&dest_rect).unwrap_or(Rect::zero()); + + let mut dest_data = Vec::new(); + //load the canvas data to the source vector + if !src_read_rect.is_empty() && canvas_size.width != 0 && canvas_size.height != 0 { + let data_surface = self.drawtarget.snapshot().get_data_surface(); + let mut src_data = Vec::new(); + data_surface.with_data(|element| { + src_data = element.to_vec(); + }); + + let stride = data_surface.stride(); + + //start offset of the copyable rectangle + let mut src = (src_read_rect.origin.y * stride + src_read_rect.origin.x * 4) as usize; + //copy the data to the destination vector + for _ in range(0, src_read_rect.size.height) { + let row = &src_data[src .. src + (4 * src_read_rect.size.width) as usize]; + dest_data.push_all(row); + src += stride as usize; + } + } + // bgra -> rgba + byte_swap(dest_data.as_mut_slice()); + chan.send(dest_data).unwrap(); + } + + fn put_image_data(&mut self, mut imagedata: Vec<u8>, image_data_rect: Rect<i32>, + dirty_rect: Option<Rect<i32>>, canvas_size: Size2D<i32>) { + + if image_data_rect.size.width <= 0 || image_data_rect.size.height <= 0 { + return + } + + assert!(image_data_rect.size.width * image_data_rect.size.height * 4 == imagedata.len() as i32); + // rgba -> bgra + byte_swap(imagedata.as_mut_slice()); + + let new_image_data_rect = Rect(Point2D(0i32, 0i32), + Size2D(image_data_rect.size.width, image_data_rect.size.height)); + + let new_dirty_rect = match dirty_rect { + Some(mut dirty_rect) => { + if dirty_rect.size.width < 0 { + dirty_rect.origin.x = dirty_rect.origin.x + dirty_rect.size.width; + dirty_rect.size.width = -dirty_rect.size.width; + } + if dirty_rect.size.height < 0 { + dirty_rect.origin.y = dirty_rect.origin.y + dirty_rect.size.height; + dirty_rect.size.height = -dirty_rect.size.height; + } + new_image_data_rect.intersection(&dirty_rect) + }, + None => Some(new_image_data_rect) + }; + + if let Some(new_dirty_rect) = new_dirty_rect { + let moved_dirty_rect = Rect(new_dirty_rect.origin.add(image_data_rect.origin), + new_dirty_rect.size).intersection(&Rect(Point2D(0i32, 0i32), + canvas_size)).unwrap_or(Rect::zero()); + if moved_dirty_rect.is_empty() { + return + } + + let source_surface = self.drawtarget.create_source_surface_from_data(imagedata.as_slice(), + image_data_rect.size, image_data_rect.size.width * 4, SurfaceFormat::B8G8R8A8); + + let draw_surface_options = DrawSurfaceOptions::new(Filter::Linear, true); + let draw_options = DrawOptions::new(1.0f64 as AzFloat, 0); + + self.drawtarget.draw_surface(source_surface, + Rect(Point2D(moved_dirty_rect.origin.x as AzFloat, moved_dirty_rect.origin.y as AzFloat), + Size2D(moved_dirty_rect.size.width as AzFloat, moved_dirty_rect.size.height as AzFloat)), + Rect(Point2D((moved_dirty_rect.origin.x - image_data_rect.origin.x) as AzFloat, + (moved_dirty_rect.origin.y - image_data_rect.origin.y) as AzFloat), + Size2D(moved_dirty_rect.size.width as AzFloat, moved_dirty_rect.size.height as AzFloat)), + draw_surface_options, draw_options); + } + } } |