diff --git a/Cargo.lock b/Cargo.lock index f70b092b45f..17087b400a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,7 +138,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "azure" version = "0.36.1" -source = "git+https://github.com/servo/rust-azure#37a57b3d862bcf345d1413c7ebb534ff69daab3b" +source = "git+https://github.com/servo/rust-azure#5996612af3139cc3c5eafb019d8218f8ca1634de" dependencies = [ "cmake 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2500,12 +2500,13 @@ dependencies = [ [[package]] name = "libflate" -version = "0.1.19" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3004,7 +3005,7 @@ dependencies = [ "immeta 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libflate 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "libflate 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of 0.0.1", "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3711,7 +3712,7 @@ dependencies = [ [[package]] name = "raqote" version = "0.6.2-alpha.0" -source = "git+https://github.com/jrmuizel/raqote#2d9a0fbb419d10e066fb49e121a45fce1e1f2abe" +source = "git+https://github.com/jrmuizel/raqote#b3675e6cc1ac1d854605918f6613b64636d5e47b" dependencies = [ "euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", "font-kit 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3802,6 +3803,11 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rle-decode-fast" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ron" version = "0.1.7" @@ -4871,6 +4877,11 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "task_info" version = "0.0.1" @@ -6042,7 +6053,7 @@ dependencies = [ "checksum leaky-cow 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40a8225d44241fd324a8af2806ba635fc7c8a7e9a7de4d5cf3ef54e71f5926fc" "checksum libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)" = "ec350a9417dfd244dc9a6c4a71e13895a4db6b92f0b106f07ebbc3f3bc580cee" "checksum libdbus-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "99c78106156a964aadc1c59f7798276967be6705243b60f3ab7e131e3841db88" -"checksum libflate 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "bff3ac7d6f23730d3b533c35ed75eef638167634476a499feef16c428d74b57b" +"checksum libflate 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "45c97cf62125b79dcac52d506acdc4799f21a198597806947fd5f40dc7b93412" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" "checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" "checksum line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" @@ -6154,6 +6165,7 @@ dependencies = [ "checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +"checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" "checksum ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399" "checksum rust-webvr 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab628b77aaacca496483788a5e0184d42af6dc0e938551aa5be20676c84dd196" "checksum rust-webvr-api 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63d01034b181187e7d048ef4c5caaf95d28d0f7973834907fe7dd74b2bfb66e8" @@ -6213,6 +6225,7 @@ dependencies = [ "checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c" "checksum syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "158521e6f544e7e3dcfc370ac180794aa38cb34a1b1e07609376d4adcf429b93" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum tempfile 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" "checksum tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "707feda9f2582d5d680d733e38755547a3e8fb471e7ba11452ecfd9ce93a5d3b" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" diff --git a/components/canvas/azure_backend.rs b/components/canvas/azure_backend.rs index 57e53e6ab7e..fa48d869c40 100644 --- a/components/canvas/azure_backend.rs +++ b/components/canvas/azure_backend.rs @@ -18,6 +18,8 @@ use canvas_traits::canvas::*; use cssparser::RGBA; use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D}; +use std::marker::PhantomData; + pub struct AzureBackend; impl Backend for AzureBackend { @@ -31,7 +33,7 @@ impl Backend for AzureBackend { fn size_from_pattern(&self, rect: &Rect, pattern: &Pattern) -> Option> { match pattern { - Pattern::Azure(azure_hl::Pattern::Surface(ref surface)) => { + Pattern::Azure(azure_hl::Pattern::Surface(ref surface), _) => { let surface_size = surface.size(); let size = match (surface.repeat_x, surface.repeat_y) { (true, true) => rect.size, @@ -43,7 +45,7 @@ impl Backend for AzureBackend { }; Some(size) }, - Pattern::Azure(_) => None, + Pattern::Azure(..) => None, } } @@ -58,7 +60,7 @@ impl Backend for AzureBackend { drawtarget: &dyn GenericDrawTarget, ) { if let Some(pattern) = style.to_azure_pattern(drawtarget) { - state.fill_style = Pattern::Azure(pattern) + state.fill_style = Pattern::Azure(pattern, PhantomData::default()) } } @@ -69,7 +71,7 @@ impl Backend for AzureBackend { drawtarget: &dyn GenericDrawTarget, ) { if let Some(pattern) = style.to_azure_pattern(drawtarget) { - state.stroke_style = Pattern::Azure(pattern) + state.stroke_style = Pattern::Azure(pattern, PhantomData::default()) } } @@ -108,12 +110,14 @@ impl<'a> CanvasPaintState<'a> { azure_hl::CompositionOp::Over, antialias.into_azure(), )), - fill_style: Pattern::Azure(azure_hl::Pattern::Color(ColorPattern::new( - azure_hl::Color::black(), - ))), - stroke_style: Pattern::Azure(azure_hl::Pattern::Color(ColorPattern::new( - azure_hl::Color::black(), - ))), + fill_style: Pattern::Azure( + azure_hl::Pattern::Color(ColorPattern::new(azure_hl::Color::black())), + PhantomData::default(), + ), + stroke_style: Pattern::Azure( + azure_hl::Pattern::Color(ColorPattern::new(azure_hl::Color::black())), + PhantomData::default(), + ), stroke_opts: StrokeOptions::Azure(azure_hl::StrokeOptions::new( 1.0, JoinStyle::MiterOrBevel, @@ -132,14 +136,15 @@ impl<'a> CanvasPaintState<'a> { impl GenericPathBuilder for azure_hl::PathBuilder { fn arc( - &self, + &mut self, origin: Point2D, radius: f32, start_angle: f32, end_angle: f32, anticlockwise: bool, ) { - self.arc( + azure_hl::PathBuilder::arc( + self, origin as Point2D, radius as AzFloat, start_angle as AzFloat, @@ -148,22 +153,23 @@ impl GenericPathBuilder for azure_hl::PathBuilder { ); } fn bezier_curve_to( - &self, + &mut self, control_point1: &Point2D, control_point2: &Point2D, control_point3: &Point2D, ) { - self.bezier_curve_to( + azure_hl::PathBuilder::bezier_curve_to( + self, control_point1 as &Point2D, control_point2 as &Point2D, control_point3 as &Point2D, ); } - fn close(&self) { - self.close(); + fn close(&mut self) { + azure_hl::PathBuilder::close(self); } fn ellipse( - &self, + &mut self, origin: Point2D, radius_x: f32, radius_y: f32, @@ -172,7 +178,8 @@ impl GenericPathBuilder for azure_hl::PathBuilder { end_angle: f32, anticlockwise: bool, ) { - self.ellipse( + azure_hl::PathBuilder::ellipse( + self, origin as Point2D, radius_x as AzFloat, radius_y as AzFloat, @@ -182,34 +189,40 @@ impl GenericPathBuilder for azure_hl::PathBuilder { anticlockwise, ); } - fn get_current_point(&self) -> Point2D { - let AzPoint { x, y } = self.get_current_point(); + fn get_current_point(&mut self) -> Point2D { + let AzPoint { x, y } = azure_hl::PathBuilder::get_current_point(self); Point2D::new(x as f32, y as f32) } - fn line_to(&self, point: Point2D) { - self.line_to(point as Point2D); + fn line_to(&mut self, point: Point2D) { + azure_hl::PathBuilder::line_to(self, point as Point2D); } - fn move_to(&self, point: Point2D) { - self.move_to(point as Point2D); + fn move_to(&mut self, point: Point2D) { + azure_hl::PathBuilder::move_to(self, point as Point2D); } - fn quadratic_curve_to(&self, control_point: &Point2D, end_point: &Point2D) { - self.quadratic_curve_to( + fn quadratic_curve_to(&mut self, control_point: &Point2D, end_point: &Point2D) { + azure_hl::PathBuilder::quadratic_curve_to( + self, control_point as &Point2D, end_point as &Point2D, ); } - fn finish(&self) -> Path { - Path::Azure(self.finish()) + fn finish(&mut self) -> Path { + Path::Azure(azure_hl::PathBuilder::finish(self)) } } impl GenericDrawTarget for azure_hl::DrawTarget { - fn clear_rect(&self, rect: &Rect) { - self.clear_rect(rect as &Rect); + fn clear_rect(&mut self, rect: &Rect) { + azure_hl::DrawTarget::clear_rect(self, rect as &Rect); } - fn copy_surface(&self, surface: SourceSurface, source: Rect, destination: Point2D) { - self.copy_surface(surface.into_azure(), source, destination); + fn copy_surface( + &mut self, + surface: SourceSurface, + source: Rect, + destination: Point2D, + ) { + azure_hl::DrawTarget::copy_surface(self, surface.into_azure(), source, destination); } fn create_gradient_stops( @@ -243,7 +256,7 @@ impl GenericDrawTarget for azure_hl::DrawTarget { .map(|s| SourceSurface::Azure(s)) } fn draw_surface( - &self, + &mut self, surface: SourceSurface, dest: Rect, source: Rect, @@ -256,7 +269,8 @@ impl GenericDrawTarget for azure_hl::DrawTarget { draw_options.as_azure().composition, azure_hl::AntialiasMode::None, ); - self.draw_surface( + azure_hl::DrawTarget::draw_surface( + self, surface.into_azure(), dest.to_azure_style(), source.to_azure_style(), @@ -282,15 +296,22 @@ impl GenericDrawTarget for azure_hl::DrawTarget { operator.into_azure(), ); } - fn fill(&self, path: &Path, pattern: Pattern, draw_options: &DrawOptions) { - self.fill( + fn fill(&mut self, path: &Path, pattern: Pattern, draw_options: &DrawOptions) { + azure_hl::DrawTarget::fill( + self, path.as_azure(), pattern.as_azure().to_pattern_ref(), draw_options.as_azure(), ); } - fn fill_rect(&self, rect: &Rect, pattern: Pattern, draw_options: Option<&DrawOptions>) { - self.fill_rect( + fn fill_rect( + &mut self, + rect: &Rect, + pattern: Pattern, + draw_options: Option<&DrawOptions>, + ) { + azure_hl::DrawTarget::fill_rect( + self, rect as &Rect, pattern.as_azure().to_pattern_ref(), draw_options.map(|x| x.as_azure()), @@ -306,26 +327,27 @@ impl GenericDrawTarget for azure_hl::DrawTarget { fn get_transform(&self) -> Transform2D { self.get_transform() as Transform2D } - fn pop_clip(&self) { - self.pop_clip(); + fn pop_clip(&mut self) { + azure_hl::DrawTarget::pop_clip(self); } - fn push_clip(&self, path: &Path) { - self.push_clip(path.as_azure()); + fn push_clip(&mut self, path: &Path) { + azure_hl::DrawTarget::push_clip(self, path.as_azure()); } - fn set_transform(&self, matrix: &Transform2D) { - self.set_transform(matrix as &Transform2D); + fn set_transform(&mut self, matrix: &Transform2D) { + azure_hl::DrawTarget::set_transform(self, matrix as &Transform2D); } fn snapshot(&self) -> SourceSurface { SourceSurface::Azure(self.snapshot()) } fn stroke( - &self, + &mut self, path: &Path, pattern: Pattern, stroke_options: &StrokeOptions, draw_options: &DrawOptions, ) { - self.stroke( + azure_hl::DrawTarget::stroke( + self, path.as_azure(), pattern.as_azure().to_pattern_ref(), stroke_options.as_azure(), @@ -333,7 +355,7 @@ impl GenericDrawTarget for azure_hl::DrawTarget { ); } fn stroke_line( - &self, + &mut self, start: Point2D, end: Point2D, pattern: Pattern, @@ -354,7 +376,8 @@ impl GenericDrawTarget for azure_hl::DrawTarget { stroke_options.mDashPattern, ); - self.stroke_line( + azure_hl::DrawTarget::stroke_line( + self, start, end, pattern.as_azure().to_pattern_ref(), @@ -363,13 +386,14 @@ impl GenericDrawTarget for azure_hl::DrawTarget { ); } fn stroke_rect( - &self, + &mut self, rect: &Rect, pattern: Pattern, stroke_options: &StrokeOptions, draw_options: &DrawOptions, ) { - self.stroke_rect( + azure_hl::DrawTarget::stroke_rect( + self, rect as &Rect, pattern.as_azure().to_pattern_ref(), stroke_options.as_azure(), @@ -469,10 +493,10 @@ impl Path { } } -impl Pattern { +impl Pattern<'_> { fn as_azure(&self) -> &azure_hl::Pattern { match self { - Pattern::Azure(p) => p, + Pattern::Azure(p, _) => p, } } } @@ -723,10 +747,10 @@ impl ToAzureStyle for RGBA { } } -impl Pattern { +impl Pattern<'_> { pub fn is_zero_size_gradient(&self) -> bool { match *self { - Pattern::Azure(azure_hl::Pattern::LinearGradient(ref gradient)) => { + Pattern::Azure(azure_hl::Pattern::LinearGradient(ref gradient), _) => { gradient.is_zero_size() }, _ => false, diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index 43e48bc8a65..c2feabeac02 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -84,7 +84,7 @@ pub trait Backend { /// azure's and raqote's PathBuilder. pub trait GenericPathBuilder { fn arc( - &self, + &mut self, origin: Point2D, radius: f32, start_angle: f32, @@ -92,14 +92,14 @@ pub trait GenericPathBuilder { anticlockwise: bool, ); fn bezier_curve_to( - &self, + &mut self, control_point1: &Point2D, control_point2: &Point2D, control_point3: &Point2D, ); - fn close(&self); + fn close(&mut self); fn ellipse( - &self, + &mut self, origin: Point2D, radius_x: f32, radius_y: f32, @@ -108,32 +108,32 @@ pub trait GenericPathBuilder { end_angle: f32, anticlockwise: bool, ); - fn get_current_point(&self) -> Point2D; - fn line_to(&self, point: Point2D); - fn move_to(&self, point: Point2D); - fn quadratic_curve_to(&self, control_point: &Point2D, end_point: &Point2D); - fn finish(&self) -> Path; + fn get_current_point(&mut self) -> Point2D; + fn line_to(&mut self, point: Point2D); + fn move_to(&mut self, point: Point2D); + fn quadratic_curve_to(&mut self, control_point: &Point2D, end_point: &Point2D); + fn finish(&mut self) -> Path; } /// A wrapper around a stored PathBuilder and an optional transformation that should be /// applied to any points to ensure they are in the matching device space. struct PathBuilderRef<'a> { - builder: &'a Box, + builder: &'a mut Box, transform: Transform2D, } impl<'a> PathBuilderRef<'a> { - fn line_to(&self, pt: &Point2D) { + fn line_to(&mut self, pt: &Point2D) { let pt = self.transform.transform_point(*pt); self.builder.line_to(pt); } - fn move_to(&self, pt: &Point2D) { + fn move_to(&mut self, pt: &Point2D) { let pt = self.transform.transform_point(*pt); self.builder.move_to(pt); } - fn rect(&self, rect: &Rect) { + fn rect(&mut self, rect: &Rect) { let (first, second, third, fourth) = ( Point2D::new(rect.origin.x, rect.origin.y), Point2D::new(rect.origin.x + rect.size.width, rect.origin.y), @@ -150,14 +150,14 @@ impl<'a> PathBuilderRef<'a> { self.builder.close(); } - fn quadratic_curve_to(&self, cp: &Point2D, endpoint: &Point2D) { + fn quadratic_curve_to(&mut self, cp: &Point2D, endpoint: &Point2D) { self.builder.quadratic_curve_to( &self.transform.transform_point(*cp), &self.transform.transform_point(*endpoint), ) } - fn bezier_curve_to(&self, cp1: &Point2D, cp2: &Point2D, endpoint: &Point2D) { + fn bezier_curve_to(&mut self, cp1: &Point2D, cp2: &Point2D, endpoint: &Point2D) { self.builder.bezier_curve_to( &self.transform.transform_point(*cp1), &self.transform.transform_point(*cp2), @@ -165,14 +165,21 @@ impl<'a> PathBuilderRef<'a> { ) } - fn arc(&self, center: &Point2D, radius: f32, start_angle: f32, end_angle: f32, ccw: bool) { + fn arc( + &mut self, + center: &Point2D, + radius: f32, + start_angle: f32, + end_angle: f32, + ccw: bool, + ) { let center = self.transform.transform_point(*center); self.builder .arc(center, radius, start_angle, end_angle, ccw); } pub fn ellipse( - &self, + &mut self, center: &Point2D, radius_x: f32, radius_y: f32, @@ -193,7 +200,7 @@ impl<'a> PathBuilderRef<'a> { ); } - fn current_point(&self) -> Option> { + fn current_point(&mut self) -> Option> { let inverse = match self.transform.inverse() { Some(i) => i, None => return None, @@ -207,8 +214,13 @@ impl<'a> PathBuilderRef<'a> { // This defines required methods for DrawTarget of azure and raqote // The prototypes are derived from azure's methods. pub trait GenericDrawTarget { - fn clear_rect(&self, rect: &Rect); - fn copy_surface(&self, surface: SourceSurface, source: Rect, destination: Point2D); + fn clear_rect(&mut self, rect: &Rect); + fn copy_surface( + &mut self, + surface: SourceSurface, + source: Rect, + destination: Point2D, + ); fn create_gradient_stops( &self, gradient_stops: Vec, @@ -227,7 +239,7 @@ pub trait GenericDrawTarget { stride: i32, ) -> Option; fn draw_surface( - &self, + &mut self, surface: SourceSurface, dest: Rect, source: Rect, @@ -243,24 +255,24 @@ pub trait GenericDrawTarget { sigma: f32, operator: CompositionOp, ); - fn fill(&self, path: &Path, pattern: Pattern, draw_options: &DrawOptions); - fn fill_rect(&self, rect: &Rect, pattern: Pattern, draw_options: Option<&DrawOptions>); + fn fill(&mut self, path: &Path, pattern: Pattern, draw_options: &DrawOptions); + fn fill_rect(&mut self, rect: &Rect, pattern: Pattern, draw_options: Option<&DrawOptions>); fn get_format(&self) -> SurfaceFormat; fn get_size(&self) -> Size2D; fn get_transform(&self) -> Transform2D; - fn pop_clip(&self); - fn push_clip(&self, path: &Path); - fn set_transform(&self, matrix: &Transform2D); + fn pop_clip(&mut self); + fn push_clip(&mut self, path: &Path); + fn set_transform(&mut self, matrix: &Transform2D); fn snapshot(&self) -> SourceSurface; fn stroke( - &self, + &mut self, path: &Path, pattern: Pattern, stroke_options: &StrokeOptions, draw_options: &DrawOptions, ); fn stroke_line( - &self, + &mut self, start: Point2D, end: Point2D, pattern: Pattern, @@ -268,7 +280,7 @@ pub trait GenericDrawTarget { draw_options: &DrawOptions, ); fn stroke_rect( - &self, + &mut self, rect: &Rect, pattern: Pattern, stroke_options: &StrokeOptions, @@ -305,7 +317,7 @@ pub enum Color { #[cfg(feature = "canvas2d-azure")] Azure(azure::azure_hl::Color), #[cfg(feature = "canvas2d-raqote")] - Raqote(()), + Raqote(raqote::SolidSource), } #[derive(Clone)] @@ -313,7 +325,7 @@ pub enum CompositionOp { #[cfg(feature = "canvas2d-azure")] Azure(azure::azure_hl::CompositionOp), #[cfg(feature = "canvas2d-raqote")] - Raqote(()), + Raqote(raqote::BlendMode), } pub enum SurfaceFormat { @@ -328,22 +340,23 @@ pub enum SourceSurface { #[cfg(feature = "canvas2d-azure")] Azure(azure::azure_hl::SourceSurface), #[cfg(feature = "canvas2d-raqote")] - Raqote(()), + Raqote(Vec), // TODO: See if we can avoid the alloc (probably?) } +#[derive(Clone)] pub enum Path { #[cfg(feature = "canvas2d-azure")] Azure(azure::azure_hl::Path), #[cfg(feature = "canvas2d-raqote")] - Raqote(()), + Raqote(raqote::Path), } #[derive(Clone)] -pub enum Pattern { +pub enum Pattern<'a> { #[cfg(feature = "canvas2d-azure")] - Azure(azure::azure_hl::Pattern), + Azure(azure::azure_hl::Pattern, PhantomData<&'a ()>), #[cfg(feature = "canvas2d-raqote")] - Raqote(()), + Raqote(raqote::Source<'a>), } pub enum DrawSurfaceOptions { @@ -358,7 +371,7 @@ pub enum DrawOptions { #[cfg(feature = "canvas2d-azure")] Azure(azure::azure_hl::DrawOptions), #[cfg(feature = "canvas2d-raqote")] - Raqote(()), + Raqote(raqote::DrawOptions), } #[derive(Clone)] @@ -366,7 +379,7 @@ pub enum StrokeOptions<'a> { #[cfg(feature = "canvas2d-azure")] Azure(azure::azure_hl::StrokeOptions<'a>), #[cfg(feature = "canvas2d-raqote")] - Raqote(PhantomData<&'a ()>), + Raqote(raqote::StrokeStyle, PhantomData<&'a ()>), } #[derive(Clone, Copy)] @@ -425,7 +438,7 @@ impl<'a> CanvasData<'a> { } pub fn draw_image( - &self, + &mut self, image_data: Vec, image_size: Size2D, dest_rect: Rect, @@ -441,14 +454,15 @@ impl<'a> CanvasData<'a> { image_data.into() }; - let writer = |draw_target: &dyn GenericDrawTarget| { + let draw_options = self.state.draw_options.clone(); + let writer = |draw_target: &mut dyn GenericDrawTarget| { write_image( draw_target, image_data, source_rect.size, dest_rect, smoothing_enabled, - &self.state.draw_options, + &draw_options, ); }; @@ -461,7 +475,7 @@ impl<'a> CanvasData<'a> { // TODO(pylbrecht) pass another closure for raqote self.draw_with_shadow(&rect, writer); } else { - writer(&*self.drawtarget); + writer(&mut *self.drawtarget); } } @@ -484,7 +498,7 @@ impl<'a> CanvasData<'a> { ); } - pub fn fill_rect(&self, rect: &Rect) { + pub fn fill_rect(&mut self, rect: &Rect) { if self.state.fill_style.is_zero_size_gradient() { return; // Paint nothing if gradient size is zero. } @@ -497,7 +511,7 @@ impl<'a> CanvasData<'a> { ); if self.need_to_draw_shadow() { - self.draw_with_shadow(&draw_rect, |new_draw_target: &dyn GenericDrawTarget| { + self.draw_with_shadow(&draw_rect, |new_draw_target: &mut dyn GenericDrawTarget| { new_draw_target.fill_rect( &draw_rect, self.state.fill_style.clone(), @@ -513,17 +527,17 @@ impl<'a> CanvasData<'a> { } } - pub fn clear_rect(&self, rect: &Rect) { + pub fn clear_rect(&mut self, rect: &Rect) { self.drawtarget.clear_rect(rect); } - pub fn stroke_rect(&self, rect: &Rect) { + pub fn stroke_rect(&mut self, rect: &Rect) { if self.state.stroke_style.is_zero_size_gradient() { return; // Paint nothing if gradient size is zero. } if self.need_to_draw_shadow() { - self.draw_with_shadow(&rect, |new_draw_target: &dyn GenericDrawTarget| { + self.draw_with_shadow(&rect, |new_draw_target: &mut dyn GenericDrawTarget| { new_draw_target.stroke_rect( rect, self.state.stroke_style.clone(), @@ -532,11 +546,13 @@ impl<'a> CanvasData<'a> { ); }); } else if rect.size.width == 0. || rect.size.height == 0. { + let mut stroke_opts = self.state.stroke_opts.clone(); + stroke_opts.set_line_cap(LineCapStyle::Butt); self.drawtarget.stroke_line( rect.origin, rect.bottom_right(), self.state.stroke_style.clone(), - &self.state.stroke_opts, + &stroke_opts, &self.state.draw_options, ); } else { @@ -569,7 +585,7 @@ impl<'a> CanvasData<'a> { // If a user-space builder exists, create a finished path from it. let new_state = match *self.path_state.as_mut().unwrap() { - PathState::UserSpacePathBuilder(ref builder, ref mut transform) => { + PathState::UserSpacePathBuilder(ref mut builder, ref mut transform) => { Some((builder.finish(), transform.take())) }, PathState::DeviceSpacePathBuilder(..) | PathState::UserSpacePath(..) => None, @@ -594,8 +610,8 @@ impl<'a> CanvasData<'a> { // If a device-space builder is present, create a user-space path from its // finished path by inverting the initial transformation. - let new_state = match self.path_state.as_ref().unwrap() { - PathState::DeviceSpacePathBuilder(ref builder) => { + let new_state = match *self.path_state.as_mut().unwrap() { + PathState::DeviceSpacePathBuilder(ref mut builder) => { let path = builder.finish(); let inverse = match self.drawtarget.get_transform().inverse() { Some(m) => m, @@ -604,7 +620,7 @@ impl<'a> CanvasData<'a> { return; }, }; - let builder = path.transformed_copy_to_builder(&inverse); + let mut builder = path.transformed_copy_to_builder(&inverse); Some(builder.finish()) }, PathState::UserSpacePathBuilder(..) | PathState::UserSpacePath(..) => None, @@ -630,7 +646,7 @@ impl<'a> CanvasData<'a> { self.ensure_path(); self.drawtarget.fill( - &self.path(), + &self.path().clone(), self.state.fill_style.clone(), &self.state.draw_options, ); @@ -643,7 +659,7 @@ impl<'a> CanvasData<'a> { self.ensure_path(); self.drawtarget.stroke( - &self.path(), + &self.path().clone(), self.state.stroke_style.clone(), &self.state.stroke_opts, &self.state.draw_options, @@ -652,7 +668,8 @@ impl<'a> CanvasData<'a> { pub fn clip(&mut self) { self.ensure_path(); - self.drawtarget.push_clip(&self.path()); + let path = self.path().clone(); + self.drawtarget.push_clip(&path); } pub fn is_point_in_path( @@ -694,19 +711,20 @@ impl<'a> CanvasData<'a> { // and overwriting path_state in other ones. The following awkward use of duplicate // matches works around the resulting borrow errors. let new_state = { - match self.path_state.as_ref().unwrap() { - &PathState::UserSpacePathBuilder(_, None) | - &PathState::DeviceSpacePathBuilder(_) => None, - &PathState::UserSpacePathBuilder(ref builder, Some(ref transform)) => { + match *self.path_state.as_mut().unwrap() { + PathState::UserSpacePathBuilder(_, None) | PathState::DeviceSpacePathBuilder(_) => { + None + }, + PathState::UserSpacePathBuilder(ref mut builder, Some(ref transform)) => { let path = builder.finish(); Some(PathState::DeviceSpacePathBuilder( path.transformed_copy_to_builder(transform), )) }, - &PathState::UserSpacePath(ref path, Some(ref transform)) => Some( + PathState::UserSpacePath(ref path, Some(ref transform)) => Some( PathState::DeviceSpacePathBuilder(path.transformed_copy_to_builder(transform)), ), - &PathState::UserSpacePath(ref path, None) => Some(PathState::UserSpacePathBuilder( + PathState::UserSpacePath(ref path, None) => Some(PathState::UserSpacePathBuilder( path.copy_to_builder(), None, )), @@ -716,14 +734,14 @@ impl<'a> CanvasData<'a> { // There's a new builder value that needs to be stored. Some(state) => self.path_state = Some(state), // There's an existing builder value that can be returned immediately. - None => match self.path_state.as_ref().unwrap() { - &PathState::UserSpacePathBuilder(ref builder, None) => { + None => match *self.path_state.as_mut().unwrap() { + PathState::UserSpacePathBuilder(ref mut builder, None) => { return PathBuilderRef { builder, transform: Transform2D::identity(), }; }, - &PathState::DeviceSpacePathBuilder(ref builder) => { + PathState::DeviceSpacePathBuilder(ref mut builder) => { return PathBuilderRef { builder, transform: self.drawtarget.get_transform(), @@ -733,16 +751,16 @@ impl<'a> CanvasData<'a> { }, } - match self.path_state.as_ref().unwrap() { - &PathState::UserSpacePathBuilder(ref builder, None) => PathBuilderRef { + match *self.path_state.as_mut().unwrap() { + PathState::UserSpacePathBuilder(ref mut builder, None) => PathBuilderRef { builder, transform: Transform2D::identity(), }, - &PathState::DeviceSpacePathBuilder(ref builder) => PathBuilderRef { + PathState::DeviceSpacePathBuilder(ref mut builder) => PathBuilderRef { builder, transform: self.drawtarget.get_transform(), }, - &PathState::UserSpacePathBuilder(..) | &PathState::UserSpacePath(..) => unreachable!(), + PathState::UserSpacePathBuilder(..) | PathState::UserSpacePath(..) => unreachable!(), } } @@ -1023,7 +1041,7 @@ impl<'a> CanvasData<'a> { } fn create_draw_target_for_shadow(&self, source_rect: &Rect) -> Box { - let draw_target = self.drawtarget.create_similar_draw_target( + let mut draw_target = self.drawtarget.create_similar_draw_target( &Size2D::new( source_rect.size.width as i32, source_rect.size.height as i32, @@ -1039,11 +1057,11 @@ impl<'a> CanvasData<'a> { fn draw_with_shadow(&self, rect: &Rect, draw_shadow_source: F) where - F: FnOnce(&dyn GenericDrawTarget), + F: FnOnce(&mut dyn GenericDrawTarget), { let shadow_src_rect = self.state.transform.transform_rect(rect); - let new_draw_target = self.create_draw_target_for_shadow(&shadow_src_rect); - draw_shadow_source(&*new_draw_target); + let mut new_draw_target = self.create_draw_target_for_shadow(&shadow_src_rect); + draw_shadow_source(&mut *new_draw_target); self.drawtarget.draw_surface_with_shadow( new_draw_target.snapshot(), &Point2D::new( @@ -1097,8 +1115,8 @@ impl<'a> Drop for CanvasData<'a> { #[derive(Clone)] pub struct CanvasPaintState<'a> { pub draw_options: DrawOptions, - pub fill_style: Pattern, - pub stroke_style: Pattern, + pub fill_style: Pattern<'a>, + pub stroke_style: Pattern<'a>, pub stroke_opts: StrokeOptions<'a>, /// The current 2D transform matrix. pub transform: Transform2D, @@ -1115,7 +1133,7 @@ pub struct CanvasPaintState<'a> { /// dest_rect: Area of the destination target where the pixels will be copied /// smoothing_enabled: It determines if smoothing is applied to the image result fn write_image( - draw_target: &dyn GenericDrawTarget, + draw_target: &mut dyn GenericDrawTarget, image_data: Vec, image_size: Size2D, dest_rect: Rect, diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs index e33203226c8..279402fa77a 100644 --- a/components/canvas/raqote_backend.rs +++ b/components/canvas/raqote_backend.rs @@ -16,46 +16,56 @@ use std::marker::PhantomData; pub struct RaqoteBackend; impl Backend for RaqoteBackend { - fn get_composition_op(&self, _opts: &DrawOptions) -> CompositionOp { - unimplemented!() + fn get_composition_op(&self, opts: &DrawOptions) -> CompositionOp { + CompositionOp::Raqote(opts.as_raqote().blend_mode) } - fn need_to_draw_shadow(&self, _color: &Color) -> bool { - unimplemented!() + fn need_to_draw_shadow(&self, color: &Color) -> bool { + color.as_raqote().a != 0 } - fn size_from_pattern(&self, _rect: &Rect, _pattern: &Pattern) -> Option> { - unimplemented!() + fn size_from_pattern(&self, rect: &Rect, pattern: &Pattern) -> Option> { + match pattern { + Pattern::Raqote(raqote::Source::Image(image, extend, ..)) => match extend { + raqote::ExtendMode::Repeat => Some(rect.size), + _ => Some(Size2D::new(image.width as f32, image.height as f32)), + }, + _ => None, + } } - fn set_shadow_color<'a>(&mut self, _color: RGBA, _state: &mut CanvasPaintState<'a>) { - unimplemented!() + fn set_shadow_color<'a>(&mut self, color: RGBA, state: &mut CanvasPaintState<'a>) { + state.shadow_color = Color::Raqote(color.to_raqote_style()); } fn set_fill_style<'a>( &mut self, - _style: FillOrStrokeStyle, - _state: &mut CanvasPaintState<'a>, + style: FillOrStrokeStyle, + state: &mut CanvasPaintState<'a>, _drawtarget: &dyn GenericDrawTarget, ) { - unimplemented!() + if let Some(source) = style.to_raqote_source() { + state.fill_style = Pattern::Raqote(source); + } } fn set_stroke_style<'a>( &mut self, - _style: FillOrStrokeStyle, - _state: &mut CanvasPaintState<'a>, + style: FillOrStrokeStyle, + state: &mut CanvasPaintState<'a>, _drawtarget: &dyn GenericDrawTarget, ) { - unimplemented!() + if let Some(pattern) = style.to_raqote_source() { + state.stroke_style = Pattern::Raqote(pattern) + } } fn set_global_composition<'a>( &mut self, - _op: CompositionOrBlending, - _state: &mut CanvasPaintState<'a>, + op: CompositionOrBlending, + state: &mut CanvasPaintState<'a>, ) { - unimplemented!() + state.draw_options.as_raqote_mut().blend_mode = op.to_raqote_style(); } fn create_drawtarget(&self, size: Size2D) -> Box { @@ -72,47 +82,95 @@ impl Backend for RaqoteBackend { impl<'a> CanvasPaintState<'a> { pub fn new(_antialias: AntialiasMode) -> CanvasPaintState<'a> { + let solid_src = raqote::SolidSource { + r: 0, + g: 0, + b: 0, + a: 255, + }; CanvasPaintState { - draw_options: DrawOptions::Raqote(()), - fill_style: Pattern::Raqote(()), - stroke_style: Pattern::Raqote(()), - stroke_opts: StrokeOptions::Raqote(PhantomData), + draw_options: DrawOptions::Raqote(raqote::DrawOptions::new()), + fill_style: Pattern::Raqote(raqote::Source::Solid(solid_src)), + stroke_style: Pattern::Raqote(raqote::Source::Solid(solid_src)), + stroke_opts: StrokeOptions::Raqote(Default::default(), PhantomData), transform: Transform2D::identity(), shadow_offset_x: 0.0, shadow_offset_y: 0.0, shadow_blur: 0.0, - shadow_color: Color::Raqote(()), + shadow_color: Color::Raqote(raqote::SolidSource { + r: 0, + g: 0, + b: 0, + a: 0, + }), } } } -impl Pattern { +impl Pattern<'_> { pub fn is_zero_size_gradient(&self) -> bool { - match *self { - Pattern::Raqote(()) => unimplemented!(), + match self { + Pattern::Raqote(p) => { + use raqote::Source::*; + + match p { + LinearGradient(g, ..) | + RadialGradient(g, ..) | + TwoCircleRadialGradient(g, ..) => g.stops.is_empty(), + _ => false, + } + }, + } + } + pub fn as_raqote(&self) -> &raqote::Source { + match self { + Pattern::Raqote(p) => p, } } } impl<'a> StrokeOptions<'a> { pub fn set_line_width(&mut self, _val: f32) { - unimplemented!() + match self { + StrokeOptions::Raqote(options, _) => options.width = _val, + } } pub fn set_miter_limit(&mut self, _val: f32) { - unimplemented!() + match self { + StrokeOptions::Raqote(options, _) => options.miter_limit = _val, + } } - pub fn set_line_join(&mut self, _val: LineJoinStyle) { - unimplemented!() + pub fn set_line_join(&mut self, val: LineJoinStyle) { + match self { + StrokeOptions::Raqote(options, _) => options.join = val.to_raqote_style(), + } } - pub fn set_line_cap(&mut self, _val: LineCapStyle) { - unimplemented!() + pub fn set_line_cap(&mut self, val: LineCapStyle) { + match self { + StrokeOptions::Raqote(options, _) => options.cap = val.to_raqote_style(), + } + } + pub fn as_raqote(&self) -> &raqote::StrokeStyle { + match self { + StrokeOptions::Raqote(options, _) => options, + } } } impl DrawOptions { - pub fn set_alpha(&mut self, _val: f32) { + pub fn set_alpha(&mut self, val: f32) { match self { - DrawOptions::Raqote(()) => unimplemented!(), + DrawOptions::Raqote(draw_options) => draw_options.alpha = val, + } + } + pub fn as_raqote(&self) -> &raqote::DrawOptions { + match self { + DrawOptions::Raqote(options) => options, + } + } + fn as_raqote_mut(&mut self) -> &mut raqote::DrawOptions { + match self { + DrawOptions::Raqote(options) => options, } } } @@ -130,60 +188,108 @@ impl Path { } pub fn copy_to_builder(&self) -> Box { - unimplemented!() + Box::new(PathBuilder(Some(raqote::PathBuilder::from( + self.as_raqote().clone(), + )))) + } + + pub fn as_raqote(&self) -> &raqote::Path { + match self { + Path::Raqote(p) => p, + } } } impl GenericDrawTarget for raqote::DrawTarget { - fn clear_rect(&self, _rect: &Rect) { - unimplemented!() + fn clear_rect(&mut self, rect: &Rect) { + let mut pb = raqote::PathBuilder::new(); + pb.rect( + rect.origin.x, + rect.origin.y, + rect.size.width, + rect.size.height, + ); + let mut options = raqote::DrawOptions::new(); + options.blend_mode = raqote::BlendMode::Clear; + raqote::DrawTarget::fill( + self, + &pb.finish(), + &raqote::Source::Solid(raqote::SolidSource { + r: 0, + g: 0, + b: 0, + a: 0, + }), + &options, + ); } - + #[allow(unsafe_code)] fn copy_surface( - &self, - _surface: SourceSurface, - _source: Rect, - _destination: Point2D, + &mut self, + surface: SourceSurface, + source: Rect, + destination: Point2D, ) { - unimplemented!() + let mut dt = raqote::DrawTarget::new(source.size.width, source.size.height); + let data = surface.as_raqote(); + let s = unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u32, data.len() / 4) }; + dt.get_data_mut().copy_from_slice(s); + raqote::DrawTarget::copy_surface(self, &dt, source.to_box2d(), destination); } - fn create_gradient_stops( &self, _gradient_stops: Vec, _extend_mode: ExtendMode, ) -> GradientStops { - unimplemented!() + unimplemented!(); } - fn create_path_builder(&self) -> Box { - unimplemented!() + Box::new(PathBuilder::new()) } - fn create_similar_draw_target( &self, - _size: &Size2D, + size: &Size2D, _format: SurfaceFormat, ) -> Box { - unimplemented!() + Box::new(raqote::DrawTarget::new(size.width, size.height)) } fn create_source_surface_from_data( &self, - _data: &[u8], + data: &[u8], _size: Size2D, _stride: i32, ) -> Option { - unimplemented!() + Some(SourceSurface::Raqote(data.to_vec())) } + #[allow(unsafe_code)] fn draw_surface( - &self, - _surface: SourceSurface, - _dest: Rect, - _source: Rect, + &mut self, + surface: SourceSurface, + dest: Rect, + source: Rect, _filter: Filter, - _draw_options: &DrawOptions, + draw_options: &DrawOptions, ) { - unimplemented!() + let v = surface.as_raqote(); + let image = raqote::Image { + width: source.size.width as i32, + height: source.size.height as i32, + data: unsafe { + std::slice::from_raw_parts( + v.as_ptr() as *const u32, + v.len() * std::mem::size_of::(), + ) + }, + }; + raqote::DrawTarget::draw_image_with_size_at( + self, + dest.size.width as f32, + dest.size.height as f32, + dest.origin.x as f32, + dest.origin.y as f32, + &image, + draw_options.as_raqote(), + ); } fn draw_surface_with_shadow( &self, @@ -194,69 +300,362 @@ impl GenericDrawTarget for raqote::DrawTarget { _sigma: f32, _operator: CompositionOp, ) { - unimplemented!() + unimplemented!(); } - fn fill(&self, _path: &Path, _pattern: Pattern, _draw_options: &DrawOptions) { - unimplemented!() + fn fill(&mut self, path: &Path, pattern: Pattern, draw_options: &DrawOptions) { + self.fill( + path.as_raqote(), + pattern.as_raqote(), + draw_options.as_raqote(), + ); } - fn fill_rect(&self, _rect: &Rect, _pattern: Pattern, _draw_options: Option<&DrawOptions>) { - unimplemented!() + fn fill_rect( + &mut self, + rect: &Rect, + pattern: Pattern, + draw_options: Option<&DrawOptions>, + ) { + let mut pb = raqote::PathBuilder::new(); + pb.rect( + rect.origin.x, + rect.origin.y, + rect.size.width, + rect.size.height, + ); + let draw_options = if let Some(options) = draw_options { + *options.as_raqote() + } else { + raqote::DrawOptions::new() + }; + + raqote::DrawTarget::fill(self, &pb.finish(), pattern.as_raqote(), &draw_options); } fn get_format(&self) -> SurfaceFormat { - unimplemented!() + SurfaceFormat::Raqote(()) } fn get_size(&self) -> Size2D { - unimplemented!() + Size2D::new(self.width(), self.height()) } fn get_transform(&self) -> Transform2D { - unimplemented!() + *self.get_transform() } - fn pop_clip(&self) { - unimplemented!() + fn pop_clip(&mut self) { + self.pop_clip(); } - fn push_clip(&self, _path: &Path) { - unimplemented!() + fn push_clip(&mut self, path: &Path) { + self.push_clip(path.as_raqote()); } - fn set_transform(&self, _matrix: &Transform2D) { - unimplemented!() + fn set_transform(&mut self, matrix: &Transform2D) { + self.set_transform(matrix); } fn snapshot(&self) -> SourceSurface { - unimplemented!() + unimplemented!(); } fn stroke( - &self, - _path: &Path, - _pattern: Pattern, - _stroke_options: &StrokeOptions, - _draw_options: &DrawOptions, + &mut self, + path: &Path, + pattern: Pattern, + stroke_options: &StrokeOptions, + draw_options: &DrawOptions, ) { - unimplemented!() + self.stroke( + path.as_raqote(), + pattern.as_raqote(), + stroke_options.as_raqote(), + draw_options.as_raqote(), + ); } fn stroke_line( - &self, - _start: Point2D, - _end: Point2D, - _pattern: Pattern, - _stroke_options: &StrokeOptions, - _draw_options: &DrawOptions, + &mut self, + start: Point2D, + end: Point2D, + pattern: Pattern, + stroke_options: &StrokeOptions, + draw_options: &DrawOptions, ) { - unimplemented!() + let mut pb = raqote::PathBuilder::new(); + pb.move_to(start.x, start.y); + pb.line_to(end.x, end.y); + let mut stroke_options = stroke_options.as_raqote().clone(); + let cap = match stroke_options.join { + raqote::LineJoin::Round => raqote::LineCap::Round, + _ => raqote::LineCap::Butt, + }; + stroke_options.cap = cap; + + self.stroke( + &pb.finish(), + pattern.as_raqote(), + &stroke_options, + draw_options.as_raqote(), + ); } fn stroke_rect( - &self, - _rect: &Rect, - _pattern: Pattern, - _stroke_options: &StrokeOptions<'_>, - _draw_options: &DrawOptions, + &mut self, + rect: &Rect, + pattern: Pattern, + stroke_options: &StrokeOptions, + draw_options: &DrawOptions, ) { - unimplemented!() - } + let mut pb = raqote::PathBuilder::new(); + pb.rect( + rect.origin.x, + rect.origin.y, + rect.size.width, + rect.size.height, + ); - fn snapshot_data(&self, _f: &dyn Fn(&[u8]) -> Vec) -> Vec { - unimplemented!() + self.stroke( + &pb.finish(), + pattern.as_raqote(), + stroke_options.as_raqote(), + draw_options.as_raqote(), + ); } - + #[allow(unsafe_code)] + fn snapshot_data(&self, f: &dyn Fn(&[u8]) -> Vec) -> Vec { + let v = self.get_data(); + f(unsafe { + std::slice::from_raw_parts( + v.as_ptr() as *const u8, + v.len() * std::mem::size_of::(), + ) + }) + } + #[allow(unsafe_code)] fn snapshot_data_owned(&self) -> Vec { - unimplemented!() + let v = self.get_data(); + unsafe { + std::slice::from_raw_parts( + v.as_ptr() as *const u8, + v.len() * std::mem::size_of::(), + ) + .into() + } + } +} + +struct PathBuilder(Option); + +impl PathBuilder { + fn new() -> PathBuilder { + PathBuilder(Some(raqote::PathBuilder::new())) + } +} + +impl GenericPathBuilder for PathBuilder { + fn arc( + &mut self, + origin: Point2D, + radius: f32, + start_angle: f32, + end_angle: f32, + _anticlockwise: bool, + ) { + self.0 + .as_mut() + .unwrap() + .arc(origin.x, origin.y, radius, start_angle, end_angle); + } + fn bezier_curve_to( + &mut self, + control_point1: &Point2D, + control_point2: &Point2D, + control_point3: &Point2D, + ) { + self.0.as_mut().unwrap().cubic_to( + control_point1.x, + control_point1.y, + control_point2.x, + control_point2.y, + control_point3.x, + control_point3.y, + ); + } + fn close(&mut self) { + self.0.as_mut().unwrap().close(); + } + fn ellipse( + &mut self, + _origin: Point2D, + _radius_x: f32, + _radius_y: f32, + _rotation_angle: f32, + _start_angle: f32, + _end_angle: f32, + _anticlockwise: bool, + ) { + unimplemented!(); + } + fn get_current_point(&mut self) -> Point2D { + unimplemented!(); + } + fn line_to(&mut self, point: Point2D) { + self.0.as_mut().unwrap().line_to(point.x, point.y); + } + fn move_to(&mut self, point: Point2D) { + self.0.as_mut().unwrap().move_to(point.x, point.y); + } + fn quadratic_curve_to(&mut self, control_point: &Point2D, end_point: &Point2D) { + self.0.as_mut().unwrap().quad_to( + control_point.x, + control_point.y, + end_point.x, + end_point.y, + ); + } + fn finish(&mut self) -> Path { + Path::Raqote(self.0.take().unwrap().finish()) + } +} + +pub trait ToRaqoteStyle { + type Target; + + fn to_raqote_style(self) -> Self::Target; +} + +impl ToRaqoteStyle for LineJoinStyle { + type Target = raqote::LineJoin; + + fn to_raqote_style(self) -> raqote::LineJoin { + match self { + LineJoinStyle::Round => raqote::LineJoin::Round, + LineJoinStyle::Bevel => raqote::LineJoin::Bevel, + LineJoinStyle::Miter => raqote::LineJoin::Miter, + } + } +} + +impl ToRaqoteStyle for LineCapStyle { + type Target = raqote::LineCap; + + fn to_raqote_style(self) -> raqote::LineCap { + match self { + LineCapStyle::Butt => raqote::LineCap::Butt, + LineCapStyle::Round => raqote::LineCap::Round, + LineCapStyle::Square => raqote::LineCap::Square, + } + } +} + +pub trait ToRaqoteSource<'a> { + fn to_raqote_source(self) -> Option>; +} + +impl<'a> ToRaqoteSource<'a> for FillOrStrokeStyle { + #[allow(unsafe_code)] + fn to_raqote_source(self) -> Option> { + use canvas_traits::canvas::FillOrStrokeStyle::*; + + match self { + Color(rgba) => Some(raqote::Source::Solid(raqote::SolidSource { + r: rgba.red, + g: rgba.green, + b: rgba.blue, + a: rgba.alpha, + })), + LinearGradient(_) => unimplemented!(), + RadialGradient(_) => unimplemented!(), + Surface(ref surface) => { + let data = &surface.surface_data[..]; + Some(raqote::Source::Image( + raqote::Image { + data: unsafe { + std::slice::from_raw_parts(data.as_ptr() as *const u32, data.len() / 4) + }, + width: surface.surface_size.width as i32, + height: surface.surface_size.height as i32, + }, + raqote::ExtendMode::Repeat, // TODO: repeat-x, repeat-y ? + raqote::FilterMode::Bilinear, + raqote::Transform::identity(), + )) + }, + } + } +} + +impl Color { + fn as_raqote(&self) -> &raqote::SolidSource { + match self { + Color::Raqote(s) => s, + } + } +} + +impl ToRaqoteStyle for RGBA { + type Target = raqote::SolidSource; + + fn to_raqote_style(self) -> Self::Target { + raqote::SolidSource { + r: self.red, + g: self.green, + b: self.blue, + a: self.alpha, + } + } +} + +impl ToRaqoteStyle for CompositionOrBlending { + type Target = raqote::BlendMode; + + fn to_raqote_style(self) -> Self::Target { + match self { + CompositionOrBlending::Composition(op) => op.to_raqote_style(), + CompositionOrBlending::Blending(op) => op.to_raqote_style(), + } + } +} + +impl ToRaqoteStyle for BlendingStyle { + type Target = raqote::BlendMode; + + fn to_raqote_style(self) -> Self::Target { + match self { + BlendingStyle::Multiply => raqote::BlendMode::Multiply, + BlendingStyle::Screen => raqote::BlendMode::Screen, + BlendingStyle::Overlay => raqote::BlendMode::Overlay, + BlendingStyle::Darken => raqote::BlendMode::Darken, + BlendingStyle::Lighten => raqote::BlendMode::Lighten, + BlendingStyle::ColorDodge => raqote::BlendMode::ColorDodge, + BlendingStyle::HardLight => raqote::BlendMode::HardLight, + BlendingStyle::SoftLight => raqote::BlendMode::SoftLight, + BlendingStyle::Difference => raqote::BlendMode::Difference, + BlendingStyle::Exclusion => raqote::BlendMode::Exclusion, + BlendingStyle::Hue => raqote::BlendMode::Hue, + BlendingStyle::Saturation => raqote::BlendMode::Saturation, + BlendingStyle::Color => raqote::BlendMode::Color, + BlendingStyle::Luminosity => raqote::BlendMode::Luminosity, + BlendingStyle::ColorBurn => unimplemented!("raqote doesn't support colorburn"), + } + } +} + +impl ToRaqoteStyle for CompositionStyle { + type Target = raqote::BlendMode; + + fn to_raqote_style(self) -> Self::Target { + match self { + CompositionStyle::SrcIn => raqote::BlendMode::SrcIn, + CompositionStyle::SrcOut => raqote::BlendMode::SrcOut, + CompositionStyle::SrcOver => raqote::BlendMode::SrcOver, + CompositionStyle::SrcAtop => raqote::BlendMode::SrcAtop, + CompositionStyle::DestIn => raqote::BlendMode::DstIn, + CompositionStyle::DestOut => raqote::BlendMode::DstOut, + CompositionStyle::DestOver => raqote::BlendMode::DstOver, + CompositionStyle::DestAtop => raqote::BlendMode::DstAtop, + CompositionStyle::Copy => raqote::BlendMode::Src, + CompositionStyle::Lighter => raqote::BlendMode::Add, + CompositionStyle::Xor => raqote::BlendMode::Xor, + } + } +} + +impl SourceSurface { + fn as_raqote(&self) -> &Vec { + match self { + SourceSurface::Raqote(s) => s, + } } }