1use std::error::Error;
13
14use freya_engine::prelude::*;
15use plotters_backend::{
16 BackendCoord,
17 BackendStyle,
18 BackendTextStyle,
19 DrawingBackend,
20 DrawingErrorKind,
21 rasterizer,
22 text_anchor::{
23 HPos,
24 VPos,
25 },
26};
27
28#[derive(Debug)]
29pub struct PlotSkiaBackendError;
30
31impl std::fmt::Display for PlotSkiaBackendError {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 f.write_str("Skia backend error.")
34 }
35}
36
37impl Error for PlotSkiaBackendError {}
38
39pub struct PlotSkiaBackend<'a> {
40 size: (i32, i32),
41 canvas: &'a Canvas,
42 font_collection: &'a mut FontCollection,
43}
44
45impl<'a> PlotSkiaBackend<'a> {
46 pub fn new(
47 canvas: &'a Canvas,
48 font_collection: &'a mut FontCollection,
49 size: (i32, i32),
50 ) -> Self {
51 Self {
52 canvas,
53 font_collection,
54 size,
55 }
56 }
57}
58
59impl DrawingBackend for PlotSkiaBackend<'_> {
60 type ErrorType = PlotSkiaBackendError;
61
62 fn draw_line<S: BackendStyle>(
63 &mut self,
64 from: BackendCoord,
65 to: BackendCoord,
66 style: &S,
67 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
68 let mut paint = Paint::default();
69 let color = style.color();
70 paint.set_color(Color::from_argb(
71 (255. * color.alpha) as u8,
72 color.rgb.0,
73 color.rgb.1,
74 color.rgb.2,
75 ));
76 paint.set_stroke_width(style.stroke_width() as f32);
77 self.canvas.draw_line(from, to, &paint);
78 Ok(())
79 }
80
81 fn draw_rect<S: BackendStyle>(
82 &mut self,
83 upper_left: BackendCoord,
84 bottom_right: BackendCoord,
85 style: &S,
86 fill: bool,
87 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
88 let mut paint = Paint::default();
89 let color = style.color();
90 paint.set_color(Color::from_argb(
91 (255. * color.alpha) as u8,
92 color.rgb.0,
93 color.rgb.1,
94 color.rgb.2,
95 ));
96 paint.set_style(if fill {
97 PaintStyle::Fill
98 } else {
99 PaintStyle::Stroke
100 });
101 paint.set_stroke_width(style.stroke_width() as f32);
102 let rect = Rect::new(
103 upper_left.0 as f32,
104 upper_left.1 as f32,
105 bottom_right.0 as f32,
106 bottom_right.1 as f32,
107 );
108 self.canvas.draw_rect(rect, &paint);
109 Ok(())
110 }
111
112 fn draw_path<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
113 &mut self,
114 path: I,
115 style: &S,
116 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
117 if style.color().alpha == 0.0 {
118 return Ok(());
119 }
120
121 if style.stroke_width() == 1 {
123 let mut begin: Option<BackendCoord> = None;
124 for end in path.into_iter() {
125 if let Some(begin) = begin {
126 let result = self.draw_line(begin, end, style);
127 #[allow(clippy::question_mark)]
128 if result.is_err() {
129 return result;
130 }
131 }
132 begin = Some(end);
133 }
134 } else {
135 let p: Vec<_> = path.into_iter().collect();
136 let v = rasterizer::polygonize(&p[..], style.stroke_width());
137 return self.fill_polygon(v, &style.color());
138 }
139 Ok(())
140 }
141
142 fn draw_circle<S: BackendStyle>(
143 &mut self,
144 center: BackendCoord,
145 radius: u32,
146 style: &S,
147 fill: bool,
148 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
149 let radius = radius as f32;
150
151 let mut paint = Paint::default();
152 let color = style.color();
153 paint.set_anti_alias(true);
154 paint.set_style(if fill {
155 PaintStyle::Fill
156 } else {
157 PaintStyle::Stroke
158 });
159 paint.set_color(Color::from_argb(
160 (255.0 * color.alpha) as u8,
161 color.rgb.0,
162 color.rgb.1,
163 color.rgb.2,
164 ));
165
166 if !fill {
167 paint.set_stroke_width(1.0);
168 }
169
170 self.canvas.draw_circle(center, radius, &paint);
171
172 Ok(())
173 }
174
175 fn fill_polygon<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
176 &mut self,
177 vert: I,
178 style: &S,
179 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
180 let mut vert = vert.into_iter();
181 let Some(first) = vert.next() else {
182 return Ok(());
183 };
184
185 let mut paint = Paint::default();
186 let color = style.color();
187 paint.set_color(Color::from_argb(
188 (255. * color.alpha) as u8,
189 color.rgb.0,
190 color.rgb.1,
191 color.rgb.2,
192 ));
193
194 let mut path = PathBuilder::new();
195 path.move_to(first);
196 for pos in vert {
197 path.line_to(pos);
198 }
199 self.canvas.draw_path(&path.detach(), &paint);
200
201 Ok(())
202 }
203
204 fn draw_text<TStyle: BackendTextStyle>(
205 &mut self,
206 text: &str,
207 style: &TStyle,
208 pos: BackendCoord,
209 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
210 let mut builder =
211 ParagraphBuilder::new(&ParagraphStyle::default(), self.font_collection.clone());
212 let mut text_style = TextStyle::new();
213 let color = style.color();
214 text_style.set_color(Color::from_argb(
215 (255. * color.alpha) as u8,
216 color.rgb.0,
217 color.rgb.1,
218 color.rgb.2,
219 ));
220 text_style.set_font_families(&[style.family().as_str()]);
221 text_style.set_font_size(style.size() as f32);
222 builder.push_style(&text_style);
223 builder.add_text(text);
224 let mut paragraph = builder.build();
225 paragraph.layout(f32::MAX);
226
227 let mut pos = (pos.0 as f32, pos.1 as f32);
228 match style.anchor().h_pos {
229 HPos::Left => {}
230 HPos::Center => {
231 pos.0 -= paragraph.max_intrinsic_width() / 2.0;
232 }
233 HPos::Right => {
234 pos.0 -= paragraph.max_intrinsic_width();
235 }
236 }
237 match style.anchor().v_pos {
238 VPos::Top => {}
239 VPos::Center => {
240 pos.1 -= paragraph.height() / 2.0;
241 }
242 VPos::Bottom => {
243 pos.1 -= paragraph.height();
244 }
245 }
246
247 paragraph.paint(self.canvas, pos);
248 Ok(())
249 }
250
251 fn estimate_text_size<TStyle: BackendTextStyle>(
252 &self,
253 text: &str,
254 style: &TStyle,
255 ) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>> {
256 let mut builder =
257 ParagraphBuilder::new(&ParagraphStyle::default(), self.font_collection.clone());
258 let mut text_style = TextStyle::new();
259 let color = style.color();
260 text_style.set_color(Color::from_argb(
261 (255. * color.alpha) as u8,
262 color.rgb.0,
263 color.rgb.1,
264 color.rgb.2,
265 ));
266 text_style.set_font_families(&[style.family().as_str()]);
267 text_style.set_font_size(style.size() as f32);
268 builder.push_style(&text_style);
269 builder.add_text(text);
270 let mut paragraph = builder.build();
271 paragraph.layout(f32::MAX);
272 Ok((
273 paragraph.max_intrinsic_width() as u32,
274 paragraph.height() as u32,
275 ))
276 }
277
278 fn draw_pixel(
279 &mut self,
280 _point: plotters_backend::BackendCoord,
281 _color: plotters_backend::BackendColor,
282 ) -> Result<(), plotters_backend::DrawingErrorKind<Self::ErrorType>> {
283 todo!()
284 }
285
286 fn get_size(&self) -> (u32, u32) {
287 (self.size.0 as u32, self.size.1 as u32)
288 }
289
290 fn ensure_prepared(
291 &mut self,
292 ) -> Result<(), plotters_backend::DrawingErrorKind<Self::ErrorType>> {
293 Ok(())
294 }
295
296 fn present(&mut self) -> Result<(), plotters_backend::DrawingErrorKind<Self::ErrorType>> {
297 Ok(())
298 }
299}