canvas/
peniko_conversions.rs1use canvas_traits::canvas::*;
6use pixels::{SnapshotAlphaMode, SnapshotPixelFormat};
7use style::color::AbsoluteColor;
8
9use crate::backend::Convert;
10use crate::canvas_data::Filter;
11
12impl Convert<peniko::Font> for fonts::FontDataAndIndex {
13 fn convert(self) -> peniko::Font {
14 use std::sync::Arc;
15 peniko::Font::new(peniko::Blob::new(Arc::new(self.data)), self.index)
16 }
17}
18
19impl Convert<kurbo::Join> for LineJoinStyle {
20 fn convert(self) -> kurbo::Join {
21 match self {
22 LineJoinStyle::Round => kurbo::Join::Round,
23 LineJoinStyle::Bevel => kurbo::Join::Bevel,
24 LineJoinStyle::Miter => kurbo::Join::Miter,
25 }
26 }
27}
28
29impl Convert<kurbo::Cap> for LineCapStyle {
30 fn convert(self) -> kurbo::Cap {
31 match self {
32 LineCapStyle::Butt => kurbo::Cap::Butt,
33 LineCapStyle::Round => kurbo::Cap::Round,
34 LineCapStyle::Square => kurbo::Cap::Square,
35 }
36 }
37}
38
39impl Convert<peniko::Color> for AbsoluteColor {
40 fn convert(self) -> peniko::Color {
41 let srgb = self.into_srgb_legacy();
42 peniko::Color::new([
43 srgb.components.0,
44 srgb.components.1,
45 srgb.components.2,
46 srgb.alpha,
47 ])
48 }
49}
50
51impl Convert<peniko::BlendMode> for CompositionOrBlending {
52 fn convert(self) -> peniko::BlendMode {
53 match self {
54 CompositionOrBlending::Composition(composition_style) => {
55 composition_style.convert().into()
56 },
57 CompositionOrBlending::Blending(blending_style) => blending_style.convert().into(),
58 }
59 }
60}
61
62impl Convert<peniko::Compose> for CompositionStyle {
63 fn convert(self) -> peniko::Compose {
64 match self {
65 CompositionStyle::SourceIn => peniko::Compose::SrcIn,
66 CompositionStyle::SourceOut => peniko::Compose::SrcOut,
67 CompositionStyle::SourceOver => peniko::Compose::SrcOver,
68 CompositionStyle::SourceAtop => peniko::Compose::SrcAtop,
69 CompositionStyle::DestinationIn => peniko::Compose::DestIn,
70 CompositionStyle::DestinationOut => peniko::Compose::DestOut,
71 CompositionStyle::DestinationOver => peniko::Compose::DestOver,
72 CompositionStyle::DestinationAtop => peniko::Compose::DestAtop,
73 CompositionStyle::Copy => peniko::Compose::Copy,
74 CompositionStyle::Lighter => peniko::Compose::Plus,
75 CompositionStyle::Xor => peniko::Compose::Xor,
76 CompositionStyle::Clear => peniko::Compose::Clear,
77 }
78 }
79}
80
81impl Convert<peniko::Mix> for BlendingStyle {
82 fn convert(self) -> peniko::Mix {
83 match self {
84 BlendingStyle::Multiply => peniko::Mix::Multiply,
85 BlendingStyle::Screen => peniko::Mix::Screen,
86 BlendingStyle::Overlay => peniko::Mix::Overlay,
87 BlendingStyle::Darken => peniko::Mix::Darken,
88 BlendingStyle::Lighten => peniko::Mix::Lighten,
89 BlendingStyle::ColorDodge => peniko::Mix::ColorDodge,
90 BlendingStyle::ColorBurn => peniko::Mix::ColorBurn,
91 BlendingStyle::HardLight => peniko::Mix::HardLight,
92 BlendingStyle::SoftLight => peniko::Mix::SoftLight,
93 BlendingStyle::Difference => peniko::Mix::Difference,
94 BlendingStyle::Exclusion => peniko::Mix::Exclusion,
95 BlendingStyle::Hue => peniko::Mix::Hue,
96 BlendingStyle::Saturation => peniko::Mix::Saturation,
97 BlendingStyle::Color => peniko::Mix::Color,
98 BlendingStyle::Luminosity => peniko::Mix::Luminosity,
99 }
100 }
101}
102
103impl Convert<kurbo::Stroke> for LineOptions {
104 fn convert(self) -> kurbo::Stroke {
105 let LineOptions {
106 width,
107 cap_style,
108 join_style,
109 miter_limit,
110 dash,
111 dash_offset,
112 } = self;
113 kurbo::Stroke {
114 width,
115 join: join_style.convert(),
116 miter_limit,
117 start_cap: cap_style.convert(),
118 end_cap: cap_style.convert(),
119 dash_pattern: dash.iter().map(|x| *x as f64).collect(),
120 dash_offset,
121 }
122 }
123}
124
125impl Convert<peniko::Brush> for FillOrStrokeStyle {
126 fn convert(self) -> peniko::Brush {
127 use canvas_traits::canvas::FillOrStrokeStyle::*;
128 match self {
129 Color(absolute_color) => peniko::Brush::Solid(absolute_color.convert()),
130 LinearGradient(style) => {
131 let start = kurbo::Point::new(style.x0, style.y0);
132 let end = kurbo::Point::new(style.x1, style.y1);
133 let mut gradient = peniko::Gradient::new_linear(start, end);
134 gradient.stops = style.stops.convert();
135 peniko::Brush::Gradient(gradient)
136 },
137 RadialGradient(style) => {
138 let center1 = kurbo::Point::new(style.x0, style.y0);
139 let center2 = kurbo::Point::new(style.x1, style.y1);
140 let mut gradient = peniko::Gradient::new_two_point_radial(
141 center1,
142 style.r0 as f32,
143 center2,
144 style.r1 as f32,
145 );
146 gradient.stops = style.stops.convert();
147 peniko::Brush::Gradient(gradient)
148 },
149 Surface(surface_style) => {
150 let data = surface_style
151 .surface_data
152 .to_owned()
153 .to_vec(
154 Some(SnapshotAlphaMode::Transparent {
155 premultiplied: false,
156 }),
157 Some(SnapshotPixelFormat::RGBA),
158 )
159 .0;
160 peniko::Brush::Image(peniko::Image {
161 data: peniko::Blob::from(data),
162 format: peniko::ImageFormat::Rgba8,
163 width: surface_style.surface_size.width,
164 height: surface_style.surface_size.height,
165 x_extend: if surface_style.repeat_x {
166 peniko::Extend::Repeat
167 } else {
168 peniko::Extend::Pad
169 },
170 y_extend: if surface_style.repeat_y {
171 peniko::Extend::Repeat
172 } else {
173 peniko::Extend::Pad
174 },
175 quality: peniko::ImageQuality::Low,
176 alpha: 1.0,
177 })
178 },
179 }
180 }
181}
182
183impl Convert<peniko::color::DynamicColor> for AbsoluteColor {
184 fn convert(self) -> peniko::color::DynamicColor {
185 peniko::color::DynamicColor::from_alpha_color(self.convert())
186 }
187}
188
189impl Convert<peniko::ColorStop> for CanvasGradientStop {
190 fn convert(self) -> peniko::ColorStop {
191 peniko::ColorStop {
192 offset: self.offset as f32,
193 color: self.color.convert(),
194 }
195 }
196}
197
198impl Convert<peniko::ColorStops> for Vec<CanvasGradientStop> {
199 fn convert(self) -> peniko::ColorStops {
200 let mut stops = peniko::ColorStops(self.into_iter().map(|item| item.convert()).collect());
201 stops
203 .0
204 .sort_by(|a, b| a.offset.partial_cmp(&b.offset).unwrap());
205 stops
206 }
207}
208
209impl Convert<peniko::ImageQuality> for Filter {
210 fn convert(self) -> peniko::ImageQuality {
211 match self {
212 Filter::Bilinear => peniko::ImageQuality::Medium,
213 Filter::Nearest => peniko::ImageQuality::Low,
214 }
215 }
216}
217
218impl Convert<peniko::Fill> for FillRule {
219 fn convert(self) -> peniko::Fill {
220 match self {
221 FillRule::Nonzero => peniko::Fill::NonZero,
222 FillRule::Evenodd => peniko::Fill::EvenOdd,
223 }
224 }
225}