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 vert_buf: Vec<_> = vert.into_iter().collect();
181
182 let mut paint = Paint::default();
183 let color = style.color();
184 paint.set_color(Color::from_argb(
185 (255. * color.alpha) as u8,
186 color.rgb.0,
187 color.rgb.1,
188 color.rgb.2,
189 ));
190 let mut path = PathBuilder::new();
191 let first = vert_buf[0];
192 path.move_to(first);
193
194 for pos in &vert_buf[1..] {
195 path.line_to(*pos);
196 }
197 let path = path.detach();
198 self.canvas.draw_path(&path, &paint);
199
200 Ok(())
201 }
202
203 fn draw_text<TStyle: BackendTextStyle>(
204 &mut self,
205 text: &str,
206 style: &TStyle,
207 pos: BackendCoord,
208 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
209 let mut builder =
210 ParagraphBuilder::new(&ParagraphStyle::default(), self.font_collection.clone());
211 let mut text_style = TextStyle::new();
212 let color = style.color();
213 text_style.set_color(Color::from_argb(
214 (255. * color.alpha) as u8,
215 color.rgb.0,
216 color.rgb.1,
217 color.rgb.2,
218 ));
219 text_style.set_font_families(&[style.family().as_str()]);
220 text_style.set_font_size(style.size() as f32);
221 builder.push_style(&text_style);
222 builder.add_text(text);
223 let mut paragraph = builder.build();
224 paragraph.layout(f32::MAX);
225
226 let mut pos = (pos.0 as f32, pos.1 as f32);
227 match style.anchor().h_pos {
228 HPos::Left => {}
229 HPos::Center => {
230 pos.0 -= paragraph.max_intrinsic_width() / 2.0;
231 }
232 HPos::Right => {
233 pos.0 -= paragraph.max_intrinsic_width();
234 }
235 }
236 match style.anchor().v_pos {
237 VPos::Top => {}
238 VPos::Center => {
239 pos.1 -= paragraph.height() / 2.0;
240 }
241 VPos::Bottom => {
242 pos.1 -= paragraph.height();
243 }
244 }
245
246 paragraph.paint(self.canvas, pos);
247 Ok(())
248 }
249
250 fn estimate_text_size<TStyle: BackendTextStyle>(
251 &self,
252 text: &str,
253 style: &TStyle,
254 ) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>> {
255 let mut builder =
256 ParagraphBuilder::new(&ParagraphStyle::default(), self.font_collection.clone());
257 let mut text_style = TextStyle::new();
258 let color = style.color();
259 text_style.set_color(Color::from_argb(
260 (255. * color.alpha) as u8,
261 color.rgb.0,
262 color.rgb.1,
263 color.rgb.2,
264 ));
265 text_style.set_font_families(&[style.family().as_str()]);
266 text_style.set_font_size(style.size() as f32);
267 builder.push_style(&text_style);
268 builder.add_text(text);
269 let mut paragraph = builder.build();
270 paragraph.layout(f32::MAX);
271 Ok((
272 paragraph.max_intrinsic_width() as u32,
273 paragraph.height() as u32,
274 ))
275 }
276
277 fn draw_pixel(
278 &mut self,
279 _point: plotters_backend::BackendCoord,
280 _color: plotters_backend::BackendColor,
281 ) -> Result<(), plotters_backend::DrawingErrorKind<Self::ErrorType>> {
282 todo!()
283 }
284
285 fn get_size(&self) -> (u32, u32) {
286 (self.size.0 as u32, self.size.1 as u32)
287 }
288
289 fn ensure_prepared(
290 &mut self,
291 ) -> Result<(), plotters_backend::DrawingErrorKind<Self::ErrorType>> {
292 Ok(())
293 }
294
295 fn present(&mut self) -> Result<(), plotters_backend::DrawingErrorKind<Self::ErrorType>> {
296 Ok(())
297 }
298}