Add GenericDrawTarget trait

This commit is contained in:
pylbrecht 2019-05-17 19:33:26 +02:00 committed by Josh Matthews
parent d1397c0b20
commit 7ad5149e50

View file

@ -2,14 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use azure::azure::AzFloat; use azure::azure::{AzFloat, AzGradientStop, AzIntSize};
use azure::azure_hl;
use azure::azure_hl::SurfacePattern; use azure::azure_hl::SurfacePattern;
use azure::azure_hl::{AntialiasMode, AsAzurePoint, CapStyle, CompositionOp, JoinStyle}; use azure::azure_hl::{AntialiasMode, AsAzurePoint, CapStyle, JoinStyle};
use azure::azure_hl::{ use azure::azure_hl::{BackendType, DrawTarget};
BackendType, DrawOptions, DrawTarget, Pattern, StrokeOptions, SurfaceFormat, use azure::azure_hl::{ColorPattern, DrawSurfaceOptions, Filter, PathBuilder};
}; use azure::azure_hl::{ExtendMode, LinearGradientPattern, RadialGradientPattern};
use azure::azure_hl::{Color, ColorPattern, DrawSurfaceOptions, Filter, Path, PathBuilder};
use azure::azure_hl::{ExtendMode, GradientStop, LinearGradientPattern, RadialGradientPattern};
use canvas_traits::canvas::*; use canvas_traits::canvas::*;
use cssparser::RGBA; use cssparser::RGBA;
use euclid::{Point2D, Rect, Size2D, Transform2D, Vector2D}; use euclid::{Point2D, Rect, Size2D, Transform2D, Vector2D};
@ -37,7 +36,7 @@ enum PathState {
/// Path in user-space. If a transform has been applied but /// Path in user-space. If a transform has been applied but
/// but no further path operations have occurred, it is stored /// but no further path operations have occurred, it is stored
/// in the optional field. /// in the optional field.
UserSpacePath(Path, Option<Transform2D<AzFloat>>), UserSpacePath(azure_hl::Path, Option<Transform2D<AzFloat>>),
} }
impl PathState { impl PathState {
@ -48,7 +47,7 @@ impl PathState {
} }
} }
fn path(&self) -> &Path { fn path(&self) -> &azure_hl::Path {
match *self { match *self {
PathState::UserSpacePath(ref p, _) => p, PathState::UserSpacePath(ref p, _) => p,
PathState::UserSpacePathBuilder(..) | PathState::DeviceSpacePathBuilder(..) => { PathState::UserSpacePathBuilder(..) | PathState::DeviceSpacePathBuilder(..) => {
@ -160,6 +159,234 @@ impl<'a> PathBuilderRef<'a> {
} }
} }
// TODO(pylbrecht)
// This defines required methods for DrawTarget of azure and raqote
// The prototypes are derived from azure's methods.
trait GenericDrawTarget {
fn clear_rect(&self, rect: &Rect<f32>);
fn copy_surface(&self, surface: SourceSurface, source: Rect<i32>, destination: Point2D<i32>);
fn create_gradient_stops(
&self,
gradient_stops: &[GradientStop],
extend_mode: ExtendMode,
) -> GradientStops;
fn create_path_builder(&self);
fn create_similar_draw_target(
&self,
size: Size2D<i32>,
format: SurfaceFormat,
) -> Box<GenericDrawTarget>;
fn create_source_surface_from_data(&self);
fn draw_surface_with_shadow(
&self,
surface: SourceSurface,
dest: &Point2D<f32>,
color: &Color,
offset: Vector2D<f32>,
sigma: f32,
operator: CompositionOp,
);
fn fill(&self, path: &Path, pattern: PatternRef, draw_options: &DrawOptions);
fn fill_rect(&self, rect: &Rect<f32>, pattern: PatternRef, draw_options: Option<&DrawOptions>);
fn get_format(&self) -> SurfaceFormat;
fn get_size(&self) -> IntSize;
fn get_transform(&self) -> Transform2D<f32>;
fn pop_clip(&self);
fn push_clip(&self, path: &Path);
fn set_transform(&self, matrix: &Transform2D<f32>);
fn snapshot(&self) -> SourceSurface;
fn stroke(
&self,
path: &Path,
pattern: PatternRef,
stroke_options: &StrokeOptions,
draw_options: &DrawOptions,
);
fn stroke_line(
&self,
start: Point2D<f32>,
end: Point2D<f32>,
pattern: PatternRef,
stroke_options: &StrokeOptions,
draw_options: &DrawOptions,
);
fn stroke_rect(
&self,
rect: &Rect<f32>,
pattern: PatternRef,
stroke_options: &StrokeOptions,
draw_options: &DrawOptions,
);
}
enum GradientStop {
Azure(AzGradientStop),
Raqote(()),
}
impl GradientStop {
fn as_azure(&self) -> &AzGradientStop {
match self {
GradientStop::Azure(s) => s,
_ => unreachable!(),
}
}
}
enum GradientStops {
Azure(azure_hl::GradientStops),
Raqote(()),
}
impl GradientStops {
fn as_azure(&self) -> &azure_hl::GradientStops {
match self {
GradientStops::Azure(s) => s,
_ => unreachable!(),
}
}
}
enum Color {
Azure(azure_hl::Color),
Raqote(()),
}
impl Color {
fn as_azure(&self) -> &azure_hl::Color {
match self {
Color::Azure(s) => s,
_ => unreachable!(),
}
}
}
enum CompositionOp {
Azure(azure_hl::CompositionOp),
Raqote(()),
}
impl CompositionOp {
fn as_azure(&self) -> &azure_hl::CompositionOp {
match self {
CompositionOp::Azure(s) => s,
_ => unreachable!(),
}
}
}
enum SurfaceFormat {
Azure(azure_hl::SurfaceFormat),
Raqote(()),
}
impl SurfaceFormat {
fn as_azure(&self) -> &azure_hl::SurfaceFormat {
match self {
SurfaceFormat::Azure(s) => s,
_ => unreachable!(),
}
}
}
enum SourceSurface {
Azure(azure_hl::SourceSurface),
Raqote(()),
}
impl SourceSurface {
fn as_azure(&self) -> &azure_hl::SourceSurface {
match self {
SourceSurface::Azure(s) => s,
_ => unreachable!(),
}
}
}
enum IntSize {
Azure(AzIntSize),
Raqote(()),
}
impl IntSize {
fn as_azure(&self) -> &AzIntSize {
match self {
IntSize::Azure(s) => s,
_ => unreachable!(),
}
}
}
enum Path {
Azure(azure_hl::Path),
Raqote(()),
}
impl Path {
fn as_azure(&self) -> &azure_hl::Path {
match self {
Path::Azure(p) => p,
_ => unreachable!(),
}
}
}
enum Pattern {
Azure(azure_hl::Pattern),
Raqote(()),
}
enum PatternRef<'a> {
Azure(azure_hl::PatternRef<'a>),
Raqote(()),
}
impl<'a> PatternRef<'a> {
fn as_azure(&self) -> &azure_hl::PatternRef<'a> {
match self {
PatternRef::Azure(p) => p,
_ => unreachable!(),
}
}
}
impl Pattern {
fn as_azure(&self) -> &azure_hl::Pattern {
match self {
Pattern::Azure(p) => p,
_ => unreachable!(),
}
}
}
enum DrawOptions {
Azure(azure_hl::DrawOptions),
Raqote(()),
}
impl DrawOptions {
fn as_azure(&self) -> &azure_hl::DrawOptions {
match self {
DrawOptions::Azure(options) => options,
_ => unreachable!(),
}
}
}
enum StrokeOptions<'a> {
Azure(azure_hl::StrokeOptions<'a>),
Raqote(()),
}
impl<'a> StrokeOptions<'a> {
fn as_azure_ref(&self) -> &azure_hl::StrokeOptions<'a> {
match self {
StrokeOptions::Azure(options) => options,
_ => unreachable!(),
}
}
}
pub struct CanvasData<'a> { pub struct CanvasData<'a> {
drawtarget: DrawTarget, drawtarget: DrawTarget,
path_state: Option<PathState>, path_state: Option<PathState>,
@ -264,7 +491,7 @@ impl<'a> CanvasData<'a> {
let draw_rect = Rect::new( let draw_rect = Rect::new(
rect.origin, rect.origin,
match self.state.fill_style { match self.state.fill_style {
Pattern::Surface(ref surface) => { azure_hl::Pattern::Surface(ref surface) => {
let surface_size = surface.size(); let surface_size = surface.size();
match (surface.repeat_x, surface.repeat_y) { match (surface.repeat_x, surface.repeat_y) {
(true, true) => rect.size, (true, true) => rect.size,
@ -320,7 +547,7 @@ impl<'a> CanvasData<'a> {
_ => CapStyle::Butt, _ => CapStyle::Butt,
}; };
let stroke_opts = StrokeOptions::new( let stroke_opts = azure_hl::StrokeOptions::new(
self.state.stroke_opts.line_width, self.state.stroke_opts.line_width,
self.state.stroke_opts.line_join, self.state.stroke_opts.line_join,
cap, cap,
@ -411,7 +638,7 @@ impl<'a> CanvasData<'a> {
assert!(self.path_state.as_ref().unwrap().is_path()) assert!(self.path_state.as_ref().unwrap().is_path())
} }
fn path(&self) -> &Path { fn path(&self) -> &azure_hl::Path {
self.path_state self.path_state
.as_ref() .as_ref()
.expect("Should have called ensure_path()") .expect("Should have called ensure_path()")
@ -710,7 +937,11 @@ impl<'a> CanvasData<'a> {
pub fn create(size: Size2D<u64>) -> DrawTarget { pub fn create(size: Size2D<u64>) -> DrawTarget {
// FIXME(nox): Why is the size made of i32 values? // FIXME(nox): Why is the size made of i32 values?
DrawTarget::new(BackendType::Skia, size.to_i32(), SurfaceFormat::B8G8R8A8) DrawTarget::new(
BackendType::Skia,
size.to_i32(),
azure_hl::SurfaceFormat::B8G8R8A8,
)
} }
pub fn recreate(&mut self, size: Size2D<u32>) { pub fn recreate(&mut self, size: Size2D<u32>) {
@ -793,7 +1024,7 @@ impl<'a> CanvasData<'a> {
&imagedata, &imagedata,
rect.size.to_i32(), rect.size.to_i32(),
rect.size.width as i32 * 4, rect.size.width as i32 * 4,
SurfaceFormat::B8G8R8A8, azure_hl::SurfaceFormat::B8G8R8A8,
) )
.unwrap(); .unwrap();
self.drawtarget.copy_surface( self.drawtarget.copy_surface(
@ -815,7 +1046,7 @@ impl<'a> CanvasData<'a> {
self.state.shadow_blur = value; self.state.shadow_blur = value;
} }
pub fn set_shadow_color(&mut self, value: Color) { pub fn set_shadow_color(&mut self, value: azure_hl::Color) {
self.state.shadow_color = value; self.state.shadow_color = value;
} }
@ -904,25 +1135,25 @@ impl<'a> Drop for CanvasData<'a> {
#[derive(Clone)] #[derive(Clone)]
struct CanvasPaintState<'a> { struct CanvasPaintState<'a> {
draw_options: DrawOptions, draw_options: azure_hl::DrawOptions,
fill_style: Pattern, fill_style: azure_hl::Pattern,
stroke_style: Pattern, stroke_style: azure_hl::Pattern,
stroke_opts: StrokeOptions<'a>, stroke_opts: azure_hl::StrokeOptions<'a>,
/// The current 2D transform matrix. /// The current 2D transform matrix.
transform: Transform2D<f32>, transform: Transform2D<f32>,
shadow_offset_x: f64, shadow_offset_x: f64,
shadow_offset_y: f64, shadow_offset_y: f64,
shadow_blur: f64, shadow_blur: f64,
shadow_color: Color, shadow_color: azure_hl::Color,
} }
impl<'a> CanvasPaintState<'a> { impl<'a> CanvasPaintState<'a> {
fn new(antialias: AntialiasMode) -> CanvasPaintState<'a> { fn new(antialias: AntialiasMode) -> CanvasPaintState<'a> {
CanvasPaintState { CanvasPaintState {
draw_options: DrawOptions::new(1.0, CompositionOp::Over, antialias), draw_options: azure_hl::DrawOptions::new(1.0, azure_hl::CompositionOp::Over, antialias),
fill_style: Pattern::Color(ColorPattern::new(Color::black())), fill_style: azure_hl::Pattern::Color(ColorPattern::new(azure_hl::Color::black())),
stroke_style: Pattern::Color(ColorPattern::new(Color::black())), stroke_style: azure_hl::Pattern::Color(ColorPattern::new(azure_hl::Color::black())),
stroke_opts: StrokeOptions::new( stroke_opts: azure_hl::StrokeOptions::new(
1.0, 1.0,
JoinStyle::MiterOrBevel, JoinStyle::MiterOrBevel,
CapStyle::Butt, CapStyle::Butt,
@ -933,13 +1164,13 @@ impl<'a> CanvasPaintState<'a> {
shadow_offset_x: 0.0, shadow_offset_x: 0.0,
shadow_offset_y: 0.0, shadow_offset_y: 0.0,
shadow_blur: 0.0, shadow_blur: 0.0,
shadow_color: Color::transparent(), shadow_color: azure_hl::Color::transparent(),
} }
} }
} }
fn is_zero_size_gradient(pattern: &Pattern) -> bool { fn is_zero_size_gradient(pattern: &azure_hl::Pattern) -> bool {
if let &Pattern::LinearGradient(ref gradient) = pattern { if let &azure_hl::Pattern::LinearGradient(ref gradient) = pattern {
if gradient.is_zero_size() { if gradient.is_zero_size() {
return true; return true;
} }
@ -959,7 +1190,7 @@ fn write_image(
image_size: Size2D<f64>, image_size: Size2D<f64>,
dest_rect: Rect<f64>, dest_rect: Rect<f64>,
smoothing_enabled: bool, smoothing_enabled: bool,
composition_op: CompositionOp, composition_op: azure_hl::CompositionOp,
global_alpha: f32, global_alpha: f32,
) { ) {
if image_data.is_empty() { if image_data.is_empty() {
@ -983,11 +1214,12 @@ fn write_image(
&image_data, &image_data,
image_size, image_size,
image_size.width * 4, image_size.width * 4,
SurfaceFormat::B8G8R8A8, azure_hl::SurfaceFormat::B8G8R8A8,
) )
.unwrap(); .unwrap();
let draw_surface_options = DrawSurfaceOptions::new(filter, true); let draw_surface_options = DrawSurfaceOptions::new(filter, true);
let draw_options = DrawOptions::new(global_alpha, composition_op, AntialiasMode::None); let draw_options =
azure_hl::DrawOptions::new(global_alpha, composition_op, AntialiasMode::None);
draw_target.draw_surface( draw_target.draw_surface(
source_surface, source_surface,
dest_rect.to_azure_style(), dest_rect.to_azure_style(),
@ -1085,53 +1317,53 @@ impl ToAzureStyle for LineJoinStyle {
} }
impl ToAzureStyle for CompositionStyle { impl ToAzureStyle for CompositionStyle {
type Target = CompositionOp; type Target = azure_hl::CompositionOp;
fn to_azure_style(self) -> CompositionOp { fn to_azure_style(self) -> azure_hl::CompositionOp {
match self { match self {
CompositionStyle::SrcIn => CompositionOp::In, CompositionStyle::SrcIn => azure_hl::CompositionOp::In,
CompositionStyle::SrcOut => CompositionOp::Out, CompositionStyle::SrcOut => azure_hl::CompositionOp::Out,
CompositionStyle::SrcOver => CompositionOp::Over, CompositionStyle::SrcOver => azure_hl::CompositionOp::Over,
CompositionStyle::SrcAtop => CompositionOp::Atop, CompositionStyle::SrcAtop => azure_hl::CompositionOp::Atop,
CompositionStyle::DestIn => CompositionOp::DestIn, CompositionStyle::DestIn => azure_hl::CompositionOp::DestIn,
CompositionStyle::DestOut => CompositionOp::DestOut, CompositionStyle::DestOut => azure_hl::CompositionOp::DestOut,
CompositionStyle::DestOver => CompositionOp::DestOver, CompositionStyle::DestOver => azure_hl::CompositionOp::DestOver,
CompositionStyle::DestAtop => CompositionOp::DestAtop, CompositionStyle::DestAtop => azure_hl::CompositionOp::DestAtop,
CompositionStyle::Copy => CompositionOp::Source, CompositionStyle::Copy => azure_hl::CompositionOp::Source,
CompositionStyle::Lighter => CompositionOp::Add, CompositionStyle::Lighter => azure_hl::CompositionOp::Add,
CompositionStyle::Xor => CompositionOp::Xor, CompositionStyle::Xor => azure_hl::CompositionOp::Xor,
} }
} }
} }
impl ToAzureStyle for BlendingStyle { impl ToAzureStyle for BlendingStyle {
type Target = CompositionOp; type Target = azure_hl::CompositionOp;
fn to_azure_style(self) -> CompositionOp { fn to_azure_style(self) -> azure_hl::CompositionOp {
match self { match self {
BlendingStyle::Multiply => CompositionOp::Multiply, BlendingStyle::Multiply => azure_hl::CompositionOp::Multiply,
BlendingStyle::Screen => CompositionOp::Screen, BlendingStyle::Screen => azure_hl::CompositionOp::Screen,
BlendingStyle::Overlay => CompositionOp::Overlay, BlendingStyle::Overlay => azure_hl::CompositionOp::Overlay,
BlendingStyle::Darken => CompositionOp::Darken, BlendingStyle::Darken => azure_hl::CompositionOp::Darken,
BlendingStyle::Lighten => CompositionOp::Lighten, BlendingStyle::Lighten => azure_hl::CompositionOp::Lighten,
BlendingStyle::ColorDodge => CompositionOp::ColorDodge, BlendingStyle::ColorDodge => azure_hl::CompositionOp::ColorDodge,
BlendingStyle::ColorBurn => CompositionOp::ColorBurn, BlendingStyle::ColorBurn => azure_hl::CompositionOp::ColorBurn,
BlendingStyle::HardLight => CompositionOp::HardLight, BlendingStyle::HardLight => azure_hl::CompositionOp::HardLight,
BlendingStyle::SoftLight => CompositionOp::SoftLight, BlendingStyle::SoftLight => azure_hl::CompositionOp::SoftLight,
BlendingStyle::Difference => CompositionOp::Difference, BlendingStyle::Difference => azure_hl::CompositionOp::Difference,
BlendingStyle::Exclusion => CompositionOp::Exclusion, BlendingStyle::Exclusion => azure_hl::CompositionOp::Exclusion,
BlendingStyle::Hue => CompositionOp::Hue, BlendingStyle::Hue => azure_hl::CompositionOp::Hue,
BlendingStyle::Saturation => CompositionOp::Saturation, BlendingStyle::Saturation => azure_hl::CompositionOp::Saturation,
BlendingStyle::Color => CompositionOp::Color, BlendingStyle::Color => azure_hl::CompositionOp::Color,
BlendingStyle::Luminosity => CompositionOp::Luminosity, BlendingStyle::Luminosity => azure_hl::CompositionOp::Luminosity,
} }
} }
} }
impl ToAzureStyle for CompositionOrBlending { impl ToAzureStyle for CompositionOrBlending {
type Target = CompositionOp; type Target = azure_hl::CompositionOp;
fn to_azure_style(self) -> CompositionOp { fn to_azure_style(self) -> azure_hl::CompositionOp {
match self { match self {
CompositionOrBlending::Composition(op) => op.to_azure_style(), CompositionOrBlending::Composition(op) => op.to_azure_style(),
CompositionOrBlending::Blending(op) => op.to_azure_style(), CompositionOrBlending::Blending(op) => op.to_azure_style(),
@ -1140,26 +1372,26 @@ impl ToAzureStyle for CompositionOrBlending {
} }
pub trait ToAzurePattern { pub trait ToAzurePattern {
fn to_azure_pattern(&self, drawtarget: &DrawTarget) -> Option<Pattern>; fn to_azure_pattern(&self, drawtarget: &DrawTarget) -> Option<azure_hl::Pattern>;
} }
impl ToAzurePattern for FillOrStrokeStyle { impl ToAzurePattern for FillOrStrokeStyle {
fn to_azure_pattern(&self, drawtarget: &DrawTarget) -> Option<Pattern> { fn to_azure_pattern(&self, drawtarget: &DrawTarget) -> Option<azure_hl::Pattern> {
Some(match *self { Some(match *self {
FillOrStrokeStyle::Color(ref color) => { FillOrStrokeStyle::Color(ref color) => {
Pattern::Color(ColorPattern::new(color.to_azure_style())) azure_hl::Pattern::Color(ColorPattern::new(color.to_azure_style()))
}, },
FillOrStrokeStyle::LinearGradient(ref linear_gradient_style) => { FillOrStrokeStyle::LinearGradient(ref linear_gradient_style) => {
let gradient_stops: Vec<GradientStop> = linear_gradient_style let gradient_stops: Vec<azure_hl::GradientStop> = linear_gradient_style
.stops .stops
.iter() .iter()
.map(|s| GradientStop { .map(|s| azure_hl::GradientStop {
offset: s.offset as AzFloat, offset: s.offset as AzFloat,
color: s.color.to_azure_style(), color: s.color.to_azure_style(),
}) })
.collect(); .collect();
Pattern::LinearGradient(LinearGradientPattern::new( azure_hl::Pattern::LinearGradient(LinearGradientPattern::new(
&Point2D::new( &Point2D::new(
linear_gradient_style.x0 as AzFloat, linear_gradient_style.x0 as AzFloat,
linear_gradient_style.y0 as AzFloat, linear_gradient_style.y0 as AzFloat,
@ -1173,16 +1405,16 @@ impl ToAzurePattern for FillOrStrokeStyle {
)) ))
}, },
FillOrStrokeStyle::RadialGradient(ref radial_gradient_style) => { FillOrStrokeStyle::RadialGradient(ref radial_gradient_style) => {
let gradient_stops: Vec<GradientStop> = radial_gradient_style let gradient_stops: Vec<azure_hl::GradientStop> = radial_gradient_style
.stops .stops
.iter() .iter()
.map(|s| GradientStop { .map(|s| azure_hl::GradientStop {
offset: s.offset as AzFloat, offset: s.offset as AzFloat,
color: s.color.to_azure_style(), color: s.color.to_azure_style(),
}) })
.collect(); .collect();
Pattern::RadialGradient(RadialGradientPattern::new( azure_hl::Pattern::RadialGradient(RadialGradientPattern::new(
&Point2D::new( &Point2D::new(
radial_gradient_style.x0 as AzFloat, radial_gradient_style.x0 as AzFloat,
radial_gradient_style.y0 as AzFloat, radial_gradient_style.y0 as AzFloat,
@ -1203,9 +1435,9 @@ impl ToAzurePattern for FillOrStrokeStyle {
// FIXME(nox): Why are those i32 values? // FIXME(nox): Why are those i32 values?
surface_style.surface_size.to_i32(), surface_style.surface_size.to_i32(),
surface_style.surface_size.width as i32 * 4, surface_style.surface_size.width as i32 * 4,
SurfaceFormat::B8G8R8A8, azure_hl::SurfaceFormat::B8G8R8A8,
)?; )?;
Pattern::Surface(SurfacePattern::new( azure_hl::Pattern::Surface(SurfacePattern::new(
source_surface.azure_source_surface, source_surface.azure_source_surface,
surface_style.repeat_x, surface_style.repeat_x,
surface_style.repeat_y, surface_style.repeat_y,
@ -1217,10 +1449,10 @@ impl ToAzurePattern for FillOrStrokeStyle {
} }
impl ToAzureStyle for RGBA { impl ToAzureStyle for RGBA {
type Target = Color; type Target = azure_hl::Color;
fn to_azure_style(self) -> Color { fn to_azure_style(self) -> azure_hl::Color {
Color::rgba( azure_hl::Color::rgba(
self.red_f32() as AzFloat, self.red_f32() as AzFloat,
self.green_f32() as AzFloat, self.green_f32() as AzFloat,
self.blue_f32() as AzFloat, self.blue_f32() as AzFloat,