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