mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
There are a few canvas2d-related dependencies that haven't updated, but they only use euclid internally so that's not blocking landing the rest of the changes. Given the size of this patch, I think it's useful to get this landed as-is.
761 lines
24 KiB
Rust
761 lines
24 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* 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/. */
|
|
|
|
use crate::canvas_data::{
|
|
Backend, CanvasPaintState, Color, CompositionOp, DrawOptions, ExtendMode, Filter,
|
|
GenericDrawTarget, GenericPathBuilder, GradientStop, GradientStops, Path, Pattern,
|
|
SourceSurface, StrokeOptions, SurfaceFormat,
|
|
};
|
|
use crate::canvas_paint_thread::AntialiasMode;
|
|
use azure::azure::{AzFloat, AzGradientStop, AzPoint};
|
|
use azure::azure_hl;
|
|
use azure::azure_hl::SurfacePattern;
|
|
use azure::azure_hl::{BackendType, ColorPattern, DrawTarget};
|
|
use azure::azure_hl::{CapStyle, JoinStyle};
|
|
use azure::azure_hl::{LinearGradientPattern, RadialGradientPattern};
|
|
use canvas_traits::canvas::*;
|
|
use cssparser::RGBA;
|
|
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
|
|
|
|
pub struct AzureBackend;
|
|
|
|
impl Backend for AzureBackend {
|
|
fn get_composition_op(&self, opts: &DrawOptions) -> CompositionOp {
|
|
CompositionOp::Azure(opts.as_azure().composition)
|
|
}
|
|
|
|
fn need_to_draw_shadow(&self, color: &Color) -> bool {
|
|
color.as_azure().a != 0.0f32
|
|
}
|
|
|
|
fn size_from_pattern(&self, rect: &Rect<f32>, pattern: &Pattern) -> Option<Size2D<f32>> {
|
|
match pattern {
|
|
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,
|
|
(true, false) => Size2D::new(rect.size.width, surface_size.height as f32),
|
|
(false, true) => Size2D::new(surface_size.width as f32, rect.size.height),
|
|
(false, false) => {
|
|
Size2D::new(surface_size.width as f32, surface_size.height as f32)
|
|
},
|
|
};
|
|
Some(size)
|
|
},
|
|
Pattern::Azure(_) => None,
|
|
}
|
|
}
|
|
|
|
fn set_shadow_color<'a>(&mut self, color: RGBA, state: &mut CanvasPaintState<'a>) {
|
|
state.shadow_color = Color::Azure(color.to_azure_style());
|
|
}
|
|
|
|
fn set_fill_style<'a>(
|
|
&mut self,
|
|
style: FillOrStrokeStyle,
|
|
state: &mut CanvasPaintState<'a>,
|
|
drawtarget: &dyn GenericDrawTarget,
|
|
) {
|
|
if let Some(pattern) = style.to_azure_pattern(drawtarget) {
|
|
state.fill_style = Pattern::Azure(pattern)
|
|
}
|
|
}
|
|
|
|
fn set_stroke_style<'a>(
|
|
&mut self,
|
|
style: FillOrStrokeStyle,
|
|
state: &mut CanvasPaintState<'a>,
|
|
drawtarget: &dyn GenericDrawTarget,
|
|
) {
|
|
if let Some(pattern) = style.to_azure_pattern(drawtarget) {
|
|
state.stroke_style = Pattern::Azure(pattern)
|
|
}
|
|
}
|
|
|
|
fn set_global_composition<'a>(
|
|
&mut self,
|
|
op: CompositionOrBlending,
|
|
state: &mut CanvasPaintState<'a>,
|
|
) {
|
|
state
|
|
.draw_options
|
|
.as_azure_mut()
|
|
.set_composition_op(op.to_azure_style());
|
|
}
|
|
|
|
fn create_drawtarget(&self, size: Size2D<u64>) -> Box<dyn GenericDrawTarget> {
|
|
// FIXME(nox): Why is the size made of i32 values?
|
|
Box::new(DrawTarget::new(
|
|
BackendType::Skia,
|
|
size.to_i32(),
|
|
azure_hl::SurfaceFormat::B8G8R8A8,
|
|
))
|
|
}
|
|
|
|
fn recreate_paint_state<'a>(&self, state: &CanvasPaintState<'a>) -> CanvasPaintState<'a> {
|
|
CanvasPaintState::new(AntialiasMode::from_azure(
|
|
state.draw_options.as_azure().antialias,
|
|
))
|
|
}
|
|
}
|
|
|
|
impl<'a> CanvasPaintState<'a> {
|
|
pub fn new(antialias: AntialiasMode) -> CanvasPaintState<'a> {
|
|
CanvasPaintState {
|
|
draw_options: DrawOptions::Azure(azure_hl::DrawOptions::new(
|
|
1.0,
|
|
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(),
|
|
))),
|
|
stroke_opts: StrokeOptions::Azure(azure_hl::StrokeOptions::new(
|
|
1.0,
|
|
JoinStyle::MiterOrBevel,
|
|
CapStyle::Butt,
|
|
10.0,
|
|
&[],
|
|
)),
|
|
transform: Transform2D::identity(),
|
|
shadow_offset_x: 0.0,
|
|
shadow_offset_y: 0.0,
|
|
shadow_blur: 0.0,
|
|
shadow_color: Color::Azure(azure_hl::Color::transparent()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GenericPathBuilder for azure_hl::PathBuilder {
|
|
fn arc(
|
|
&self,
|
|
origin: Point2D<f32>,
|
|
radius: f32,
|
|
start_angle: f32,
|
|
end_angle: f32,
|
|
anticlockwise: bool,
|
|
) {
|
|
self.arc(
|
|
origin as Point2D<AzFloat>,
|
|
radius as AzFloat,
|
|
start_angle as AzFloat,
|
|
end_angle as AzFloat,
|
|
anticlockwise,
|
|
);
|
|
}
|
|
fn bezier_curve_to(
|
|
&self,
|
|
control_point1: &Point2D<f32>,
|
|
control_point2: &Point2D<f32>,
|
|
control_point3: &Point2D<f32>,
|
|
) {
|
|
self.bezier_curve_to(
|
|
control_point1 as &Point2D<AzFloat>,
|
|
control_point2 as &Point2D<AzFloat>,
|
|
control_point3 as &Point2D<AzFloat>,
|
|
);
|
|
}
|
|
fn close(&self) {
|
|
self.close();
|
|
}
|
|
fn ellipse(
|
|
&self,
|
|
origin: Point2D<f32>,
|
|
radius_x: f32,
|
|
radius_y: f32,
|
|
rotation_angle: f32,
|
|
start_angle: f32,
|
|
end_angle: f32,
|
|
anticlockwise: bool,
|
|
) {
|
|
self.ellipse(
|
|
origin as Point2D<AzFloat>,
|
|
radius_x as AzFloat,
|
|
radius_y as AzFloat,
|
|
rotation_angle as AzFloat,
|
|
start_angle as AzFloat,
|
|
end_angle as AzFloat,
|
|
anticlockwise,
|
|
);
|
|
}
|
|
fn get_current_point(&self) -> Point2D<f32> {
|
|
let AzPoint { x, y } = self.get_current_point();
|
|
Point2D::new(x as f32, y as f32)
|
|
}
|
|
fn line_to(&self, point: Point2D<f32>) {
|
|
self.line_to(point as Point2D<AzFloat>);
|
|
}
|
|
fn move_to(&self, point: Point2D<f32>) {
|
|
self.move_to(point as Point2D<AzFloat>);
|
|
}
|
|
fn quadratic_curve_to(&self, control_point: &Point2D<f32>, end_point: &Point2D<f32>) {
|
|
self.quadratic_curve_to(
|
|
control_point as &Point2D<AzFloat>,
|
|
end_point as &Point2D<AzFloat>,
|
|
);
|
|
}
|
|
fn finish(&self) -> Path {
|
|
Path::Azure(self.finish())
|
|
}
|
|
}
|
|
|
|
impl GenericDrawTarget for azure_hl::DrawTarget {
|
|
fn clear_rect(&self, rect: &Rect<f32>) {
|
|
self.clear_rect(rect as &Rect<AzFloat>);
|
|
}
|
|
|
|
fn copy_surface(&self, surface: SourceSurface, source: Rect<i32>, destination: Point2D<i32>) {
|
|
self.copy_surface(surface.into_azure(), source, destination);
|
|
}
|
|
|
|
fn create_gradient_stops(
|
|
&self,
|
|
gradient_stops: Vec<GradientStop>,
|
|
extend_mode: ExtendMode,
|
|
) -> GradientStops {
|
|
let gradient_stops: Vec<AzGradientStop> =
|
|
gradient_stops.into_iter().map(|x| x.into_azure()).collect();
|
|
GradientStops::Azure(self.create_gradient_stops(&gradient_stops, extend_mode.into_azure()))
|
|
}
|
|
|
|
fn create_path_builder(&self) -> Box<dyn GenericPathBuilder> {
|
|
Box::new(self.create_path_builder())
|
|
}
|
|
|
|
fn create_similar_draw_target(
|
|
&self,
|
|
size: &Size2D<i32>,
|
|
format: SurfaceFormat,
|
|
) -> Box<dyn GenericDrawTarget> {
|
|
Box::new(self.create_similar_draw_target(size, format.into_azure()))
|
|
}
|
|
fn create_source_surface_from_data(
|
|
&self,
|
|
data: &[u8],
|
|
size: Size2D<i32>,
|
|
stride: i32,
|
|
) -> Option<SourceSurface> {
|
|
self.create_source_surface_from_data(data, size, stride, azure_hl::SurfaceFormat::B8G8R8A8)
|
|
.map(|s| SourceSurface::Azure(s))
|
|
}
|
|
fn draw_surface(
|
|
&self,
|
|
surface: SourceSurface,
|
|
dest: Rect<f64>,
|
|
source: Rect<f64>,
|
|
filter: Filter,
|
|
draw_options: &DrawOptions,
|
|
) {
|
|
let surf_options = azure_hl::DrawSurfaceOptions::new(filter.as_azure(), true);
|
|
let draw_options = azure_hl::DrawOptions::new(
|
|
draw_options.as_azure().alpha,
|
|
draw_options.as_azure().composition,
|
|
azure_hl::AntialiasMode::None,
|
|
);
|
|
self.draw_surface(
|
|
surface.into_azure(),
|
|
dest.to_azure_style(),
|
|
source.to_azure_style(),
|
|
surf_options,
|
|
draw_options,
|
|
);
|
|
}
|
|
fn draw_surface_with_shadow(
|
|
&self,
|
|
surface: SourceSurface,
|
|
dest: &Point2D<f32>,
|
|
color: &Color,
|
|
offset: &Vector2D<f32>,
|
|
sigma: f32,
|
|
operator: CompositionOp,
|
|
) {
|
|
self.draw_surface_with_shadow(
|
|
surface.into_azure(),
|
|
dest as &Point2D<AzFloat>,
|
|
color.as_azure(),
|
|
offset as &Vector2D<AzFloat>,
|
|
sigma as AzFloat,
|
|
operator.into_azure(),
|
|
);
|
|
}
|
|
fn fill(&self, path: &Path, pattern: Pattern, draw_options: &DrawOptions) {
|
|
self.fill(
|
|
path.as_azure(),
|
|
pattern.as_azure().to_pattern_ref(),
|
|
draw_options.as_azure(),
|
|
);
|
|
}
|
|
fn fill_rect(&self, rect: &Rect<f32>, pattern: Pattern, draw_options: Option<&DrawOptions>) {
|
|
self.fill_rect(
|
|
rect as &Rect<AzFloat>,
|
|
pattern.as_azure().to_pattern_ref(),
|
|
draw_options.map(|x| x.as_azure()),
|
|
);
|
|
}
|
|
fn get_format(&self) -> SurfaceFormat {
|
|
SurfaceFormat::Azure(self.get_format())
|
|
}
|
|
fn get_size(&self) -> Size2D<i32> {
|
|
let size = self.get_size();
|
|
Size2D::new(size.width, size.height)
|
|
}
|
|
fn get_transform(&self) -> Transform2D<f32> {
|
|
self.get_transform() as Transform2D<f32>
|
|
}
|
|
fn pop_clip(&self) {
|
|
self.pop_clip();
|
|
}
|
|
fn push_clip(&self, path: &Path) {
|
|
self.push_clip(path.as_azure());
|
|
}
|
|
fn set_transform(&self, matrix: &Transform2D<f32>) {
|
|
self.set_transform(matrix as &Transform2D<AzFloat>);
|
|
}
|
|
fn snapshot(&self) -> SourceSurface {
|
|
SourceSurface::Azure(self.snapshot())
|
|
}
|
|
fn stroke(
|
|
&self,
|
|
path: &Path,
|
|
pattern: Pattern,
|
|
stroke_options: &StrokeOptions,
|
|
draw_options: &DrawOptions,
|
|
) {
|
|
self.stroke(
|
|
path.as_azure(),
|
|
pattern.as_azure().to_pattern_ref(),
|
|
stroke_options.as_azure(),
|
|
draw_options.as_azure(),
|
|
);
|
|
}
|
|
fn stroke_line(
|
|
&self,
|
|
start: Point2D<f32>,
|
|
end: Point2D<f32>,
|
|
pattern: Pattern,
|
|
stroke_options: &StrokeOptions,
|
|
draw_options: &DrawOptions,
|
|
) {
|
|
let stroke_options = stroke_options.as_azure();
|
|
let cap = match stroke_options.line_join {
|
|
JoinStyle::Round => CapStyle::Round,
|
|
_ => CapStyle::Butt,
|
|
};
|
|
|
|
let stroke_opts = azure_hl::StrokeOptions::new(
|
|
stroke_options.line_width,
|
|
stroke_options.line_join,
|
|
cap,
|
|
stroke_options.miter_limit,
|
|
stroke_options.mDashPattern,
|
|
);
|
|
|
|
self.stroke_line(
|
|
start,
|
|
end,
|
|
pattern.as_azure().to_pattern_ref(),
|
|
&stroke_opts,
|
|
draw_options.as_azure(),
|
|
);
|
|
}
|
|
fn stroke_rect(
|
|
&self,
|
|
rect: &Rect<f32>,
|
|
pattern: Pattern,
|
|
stroke_options: &StrokeOptions,
|
|
draw_options: &DrawOptions,
|
|
) {
|
|
self.stroke_rect(
|
|
rect as &Rect<AzFloat>,
|
|
pattern.as_azure().to_pattern_ref(),
|
|
stroke_options.as_azure(),
|
|
draw_options.as_azure(),
|
|
);
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
fn snapshot_data(&self, f: &dyn Fn(&[u8]) -> Vec<u8>) -> Vec<u8> {
|
|
unsafe { f(self.snapshot().get_data_surface().data()) }
|
|
}
|
|
|
|
#[allow(unsafe_code)]
|
|
fn snapshot_data_owned(&self) -> Vec<u8> {
|
|
unsafe { self.snapshot().get_data_surface().data().into() }
|
|
}
|
|
}
|
|
|
|
impl AntialiasMode {
|
|
fn into_azure(self) -> azure_hl::AntialiasMode {
|
|
match self {
|
|
AntialiasMode::Default => azure_hl::AntialiasMode::Default,
|
|
AntialiasMode::None => azure_hl::AntialiasMode::None,
|
|
}
|
|
}
|
|
|
|
fn from_azure(val: azure_hl::AntialiasMode) -> AntialiasMode {
|
|
match val {
|
|
azure_hl::AntialiasMode::Default => AntialiasMode::Default,
|
|
azure_hl::AntialiasMode::None => AntialiasMode::None,
|
|
v => unimplemented!("{:?} is unsupported", v),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ExtendMode {
|
|
fn into_azure(self) -> azure_hl::ExtendMode {
|
|
match self {
|
|
ExtendMode::Azure(m) => m,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GradientStop {
|
|
fn into_azure(self) -> AzGradientStop {
|
|
match self {
|
|
GradientStop::Azure(s) => s,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GradientStops {
|
|
fn into_azure(self) -> azure_hl::GradientStops {
|
|
match self {
|
|
GradientStops::Azure(s) => s,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Color {
|
|
fn as_azure(&self) -> &azure_hl::Color {
|
|
match self {
|
|
Color::Azure(s) => s,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CompositionOp {
|
|
fn into_azure(self) -> azure_hl::CompositionOp {
|
|
match self {
|
|
CompositionOp::Azure(s) => s,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SurfaceFormat {
|
|
fn into_azure(self) -> azure_hl::SurfaceFormat {
|
|
match self {
|
|
SurfaceFormat::Azure(s) => s,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SourceSurface {
|
|
fn into_azure(self) -> azure_hl::SourceSurface {
|
|
match self {
|
|
SourceSurface::Azure(s) => s,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Path {
|
|
fn as_azure(&self) -> &azure_hl::Path {
|
|
match self {
|
|
Path::Azure(p) => p,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Pattern {
|
|
fn as_azure(&self) -> &azure_hl::Pattern {
|
|
match self {
|
|
Pattern::Azure(p) => p,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DrawOptions {
|
|
fn as_azure(&self) -> &azure_hl::DrawOptions {
|
|
match self {
|
|
DrawOptions::Azure(options) => options,
|
|
}
|
|
}
|
|
fn as_azure_mut(&mut self) -> &mut azure_hl::DrawOptions {
|
|
match self {
|
|
DrawOptions::Azure(options) => options,
|
|
}
|
|
}
|
|
pub fn set_alpha(&mut self, val: f32) {
|
|
match self {
|
|
DrawOptions::Azure(options) => options.alpha = val as AzFloat,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> StrokeOptions<'a> {
|
|
pub fn as_azure(&self) -> &azure_hl::StrokeOptions<'a> {
|
|
match self {
|
|
StrokeOptions::Azure(options) => options,
|
|
}
|
|
}
|
|
pub fn set_line_width(&mut self, val: f32) {
|
|
match self {
|
|
StrokeOptions::Azure(options) => options.line_width = val as AzFloat,
|
|
}
|
|
}
|
|
pub fn set_miter_limit(&mut self, val: f32) {
|
|
match self {
|
|
StrokeOptions::Azure(options) => options.miter_limit = val as AzFloat,
|
|
}
|
|
}
|
|
pub fn set_line_join(&mut self, val: LineJoinStyle) {
|
|
match self {
|
|
StrokeOptions::Azure(options) => options.line_join = val.to_azure_style(),
|
|
}
|
|
}
|
|
pub fn set_line_cap(&mut self, val: LineCapStyle) {
|
|
match self {
|
|
StrokeOptions::Azure(options) => options.line_cap = val.to_azure_style(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait ToAzureStyle {
|
|
type Target;
|
|
fn to_azure_style(self) -> Self::Target;
|
|
}
|
|
|
|
impl ToAzureStyle for Rect<f64> {
|
|
type Target = Rect<f32>;
|
|
|
|
fn to_azure_style(self) -> Rect<f32> {
|
|
Rect::new(
|
|
Point2D::new(self.origin.x as f32, self.origin.y as f32),
|
|
Size2D::new(self.size.width as f32, self.size.height as f32),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl ToAzureStyle for LineCapStyle {
|
|
type Target = CapStyle;
|
|
|
|
fn to_azure_style(self) -> CapStyle {
|
|
match self {
|
|
LineCapStyle::Butt => CapStyle::Butt,
|
|
LineCapStyle::Round => CapStyle::Round,
|
|
LineCapStyle::Square => CapStyle::Square,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ToAzureStyle for LineJoinStyle {
|
|
type Target = JoinStyle;
|
|
|
|
fn to_azure_style(self) -> JoinStyle {
|
|
match self {
|
|
LineJoinStyle::Round => JoinStyle::Round,
|
|
LineJoinStyle::Bevel => JoinStyle::Bevel,
|
|
LineJoinStyle::Miter => JoinStyle::Miter,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ToAzureStyle for CompositionStyle {
|
|
type Target = azure_hl::CompositionOp;
|
|
|
|
fn to_azure_style(self) -> azure_hl::CompositionOp {
|
|
match self {
|
|
CompositionStyle::SrcIn => azure_hl::CompositionOp::In,
|
|
CompositionStyle::SrcOut => azure_hl::CompositionOp::Out,
|
|
CompositionStyle::SrcOver => azure_hl::CompositionOp::Over,
|
|
CompositionStyle::SrcAtop => azure_hl::CompositionOp::Atop,
|
|
CompositionStyle::DestIn => azure_hl::CompositionOp::DestIn,
|
|
CompositionStyle::DestOut => azure_hl::CompositionOp::DestOut,
|
|
CompositionStyle::DestOver => azure_hl::CompositionOp::DestOver,
|
|
CompositionStyle::DestAtop => azure_hl::CompositionOp::DestAtop,
|
|
CompositionStyle::Copy => azure_hl::CompositionOp::Source,
|
|
CompositionStyle::Lighter => azure_hl::CompositionOp::Add,
|
|
CompositionStyle::Xor => azure_hl::CompositionOp::Xor,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ToAzureStyle for BlendingStyle {
|
|
type Target = azure_hl::CompositionOp;
|
|
|
|
fn to_azure_style(self) -> azure_hl::CompositionOp {
|
|
match self {
|
|
BlendingStyle::Multiply => azure_hl::CompositionOp::Multiply,
|
|
BlendingStyle::Screen => azure_hl::CompositionOp::Screen,
|
|
BlendingStyle::Overlay => azure_hl::CompositionOp::Overlay,
|
|
BlendingStyle::Darken => azure_hl::CompositionOp::Darken,
|
|
BlendingStyle::Lighten => azure_hl::CompositionOp::Lighten,
|
|
BlendingStyle::ColorDodge => azure_hl::CompositionOp::ColorDodge,
|
|
BlendingStyle::ColorBurn => azure_hl::CompositionOp::ColorBurn,
|
|
BlendingStyle::HardLight => azure_hl::CompositionOp::HardLight,
|
|
BlendingStyle::SoftLight => azure_hl::CompositionOp::SoftLight,
|
|
BlendingStyle::Difference => azure_hl::CompositionOp::Difference,
|
|
BlendingStyle::Exclusion => azure_hl::CompositionOp::Exclusion,
|
|
BlendingStyle::Hue => azure_hl::CompositionOp::Hue,
|
|
BlendingStyle::Saturation => azure_hl::CompositionOp::Saturation,
|
|
BlendingStyle::Color => azure_hl::CompositionOp::Color,
|
|
BlendingStyle::Luminosity => azure_hl::CompositionOp::Luminosity,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ToAzureStyle for CompositionOrBlending {
|
|
type Target = azure_hl::CompositionOp;
|
|
|
|
fn to_azure_style(self) -> azure_hl::CompositionOp {
|
|
match self {
|
|
CompositionOrBlending::Composition(op) => op.to_azure_style(),
|
|
CompositionOrBlending::Blending(op) => op.to_azure_style(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait ToAzurePattern {
|
|
fn to_azure_pattern(&self, drawtarget: &dyn GenericDrawTarget) -> Option<azure_hl::Pattern>;
|
|
}
|
|
|
|
impl ToAzurePattern for FillOrStrokeStyle {
|
|
fn to_azure_pattern(&self, drawtarget: &dyn GenericDrawTarget) -> Option<azure_hl::Pattern> {
|
|
Some(match *self {
|
|
FillOrStrokeStyle::Color(ref color) => {
|
|
azure_hl::Pattern::Color(ColorPattern::new(color.to_azure_style()))
|
|
},
|
|
FillOrStrokeStyle::LinearGradient(ref linear_gradient_style) => {
|
|
let gradient_stops: Vec<GradientStop> = linear_gradient_style
|
|
.stops
|
|
.iter()
|
|
.map(|s| {
|
|
GradientStop::Azure(azure_hl::GradientStop {
|
|
offset: s.offset as f32,
|
|
color: s.color.to_azure_style(),
|
|
})
|
|
})
|
|
.collect();
|
|
|
|
azure_hl::Pattern::LinearGradient(LinearGradientPattern::new(
|
|
&Point2D::new(
|
|
linear_gradient_style.x0 as f32,
|
|
linear_gradient_style.y0 as f32,
|
|
),
|
|
&Point2D::new(
|
|
linear_gradient_style.x1 as f32,
|
|
linear_gradient_style.y1 as f32,
|
|
),
|
|
drawtarget
|
|
.create_gradient_stops(
|
|
gradient_stops,
|
|
ExtendMode::Azure(azure_hl::ExtendMode::Clamp),
|
|
)
|
|
.into_azure(),
|
|
&Transform2D::identity(),
|
|
))
|
|
},
|
|
FillOrStrokeStyle::RadialGradient(ref radial_gradient_style) => {
|
|
let gradient_stops: Vec<GradientStop> = radial_gradient_style
|
|
.stops
|
|
.iter()
|
|
.map(|s| {
|
|
GradientStop::Azure(azure_hl::GradientStop {
|
|
offset: s.offset as f32,
|
|
color: s.color.to_azure_style(),
|
|
})
|
|
})
|
|
.collect();
|
|
|
|
azure_hl::Pattern::RadialGradient(RadialGradientPattern::new(
|
|
&Point2D::new(
|
|
radial_gradient_style.x0 as f32,
|
|
radial_gradient_style.y0 as f32,
|
|
),
|
|
&Point2D::new(
|
|
radial_gradient_style.x1 as f32,
|
|
radial_gradient_style.y1 as f32,
|
|
),
|
|
radial_gradient_style.r0 as f32,
|
|
radial_gradient_style.r1 as f32,
|
|
drawtarget
|
|
.create_gradient_stops(
|
|
gradient_stops,
|
|
ExtendMode::Azure(azure_hl::ExtendMode::Clamp),
|
|
)
|
|
.into_azure(),
|
|
&Transform2D::identity(),
|
|
))
|
|
},
|
|
FillOrStrokeStyle::Surface(ref surface_style) => {
|
|
let source_surface = drawtarget
|
|
.create_source_surface_from_data(
|
|
&surface_style.surface_data,
|
|
// FIXME(nox): Why are those i32 values?
|
|
surface_style.surface_size.to_i32(),
|
|
surface_style.surface_size.width as i32 * 4,
|
|
)?
|
|
.into_azure();
|
|
azure_hl::Pattern::Surface(SurfacePattern::new(
|
|
source_surface.azure_source_surface,
|
|
surface_style.repeat_x,
|
|
surface_style.repeat_y,
|
|
&Transform2D::identity(),
|
|
))
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
impl ToAzureStyle for RGBA {
|
|
type Target = azure_hl::Color;
|
|
|
|
fn to_azure_style(self) -> azure_hl::Color {
|
|
azure_hl::Color::rgba(
|
|
self.red_f32() as f32,
|
|
self.green_f32() as f32,
|
|
self.blue_f32() as f32,
|
|
self.alpha_f32() as f32,
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Pattern {
|
|
pub fn is_zero_size_gradient(&self) -> bool {
|
|
match *self {
|
|
Pattern::Azure(azure_hl::Pattern::LinearGradient(ref gradient)) => {
|
|
gradient.is_zero_size()
|
|
},
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Filter {
|
|
fn as_azure(&self) -> azure_hl::Filter {
|
|
match *self {
|
|
Filter::Linear => azure_hl::Filter::Linear,
|
|
Filter::Point => azure_hl::Filter::Point,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Path {
|
|
pub fn transformed_copy_to_builder(
|
|
&self,
|
|
transform: &Transform2D<f32>,
|
|
) -> Box<dyn GenericPathBuilder> {
|
|
Box::new(self.as_azure().transformed_copy_to_builder(transform))
|
|
}
|
|
|
|
pub fn contains_point(&self, x: f64, y: f64, path_transform: &Transform2D<f32>) -> bool {
|
|
self.as_azure().contains_point(x, y, path_transform)
|
|
}
|
|
|
|
pub fn copy_to_builder(&self) -> Box<dyn GenericPathBuilder> {
|
|
Box::new(self.as_azure().copy_to_builder())
|
|
}
|
|
}
|