1use std::fmt::Debug;
2
3use super::scene::{Path, PathVertex};
4use crate::{color::Color, json::ToJson};
5pub use pathfinder_geometry::*;
6use rect::RectF;
7use refineable::Refineable;
8use serde::{Deserialize, Deserializer};
9use serde_json::json;
10use vector::{vec2f, Vector2F};
11
12pub struct PathBuilder {
13 vertices: Vec<PathVertex>,
14 start: Vector2F,
15 current: Vector2F,
16 contour_count: usize,
17 bounds: RectF,
18}
19
20enum PathVertexKind {
21 Solid,
22 Quadratic,
23}
24
25impl Default for PathBuilder {
26 fn default() -> Self {
27 PathBuilder::new()
28 }
29}
30
31impl PathBuilder {
32 pub fn new() -> Self {
33 Self {
34 vertices: Vec::new(),
35 start: vec2f(0., 0.),
36 current: vec2f(0., 0.),
37 contour_count: 0,
38 bounds: RectF::default(),
39 }
40 }
41
42 pub fn reset(&mut self, point: Vector2F) {
43 self.vertices.clear();
44 self.start = point;
45 self.current = point;
46 self.contour_count = 0;
47 }
48
49 pub fn line_to(&mut self, point: Vector2F) {
50 self.contour_count += 1;
51 if self.contour_count > 1 {
52 self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
53 }
54
55 self.current = point;
56 }
57
58 pub fn curve_to(&mut self, point: Vector2F, ctrl: Vector2F) {
59 self.contour_count += 1;
60 if self.contour_count > 1 {
61 self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
62 }
63
64 self.push_triangle(self.current, ctrl, point, PathVertexKind::Quadratic);
65 self.current = point;
66 }
67
68 pub fn build(mut self, color: Color, clip_bounds: Option<RectF>) -> Path {
69 if let Some(clip_bounds) = clip_bounds {
70 self.bounds = self.bounds.intersection(clip_bounds).unwrap_or_default();
71 }
72 Path {
73 bounds: self.bounds,
74 color,
75 vertices: self.vertices,
76 }
77 }
78
79 fn push_triangle(&mut self, a: Vector2F, b: Vector2F, c: Vector2F, kind: PathVertexKind) {
80 if self.vertices.is_empty() {
81 self.bounds = RectF::new(a, Vector2F::zero());
82 }
83 self.bounds = self.bounds.union_point(a).union_point(b).union_point(c);
84
85 match kind {
86 PathVertexKind::Solid => {
87 self.vertices.push(PathVertex {
88 xy_position: a,
89 st_position: vec2f(0., 1.),
90 });
91 self.vertices.push(PathVertex {
92 xy_position: b,
93 st_position: vec2f(0., 1.),
94 });
95 self.vertices.push(PathVertex {
96 xy_position: c,
97 st_position: vec2f(0., 1.),
98 });
99 }
100 PathVertexKind::Quadratic => {
101 self.vertices.push(PathVertex {
102 xy_position: a,
103 st_position: vec2f(0., 0.),
104 });
105 self.vertices.push(PathVertex {
106 xy_position: b,
107 st_position: vec2f(0.5, 0.),
108 });
109 self.vertices.push(PathVertex {
110 xy_position: c,
111 st_position: vec2f(1., 1.),
112 });
113 }
114 }
115 }
116}
117
118pub fn deserialize_vec2f<'de, D>(deserializer: D) -> Result<Vector2F, D::Error>
119where
120 D: Deserializer<'de>,
121{
122 let [x, y]: [f32; 2] = Deserialize::deserialize(deserializer)?;
123 Ok(vec2f(x, y))
124}
125
126impl ToJson for Vector2F {
127 fn to_json(&self) -> serde_json::Value {
128 json!([self.x(), self.y()])
129 }
130}
131
132impl ToJson for RectF {
133 fn to_json(&self) -> serde_json::Value {
134 json!({"origin": self.origin().to_json(), "size": self.size().to_json()})
135 }
136}
137
138#[derive(Refineable, Debug)]
139#[refineable(debug)]
140pub struct Point<T: Clone + Default + Debug> {
141 pub x: T,
142 pub y: T,
143}
144
145impl<T: Clone + Default + Debug> Clone for Point<T> {
146 fn clone(&self) -> Self {
147 Self {
148 x: self.x.clone(),
149 y: self.y.clone(),
150 }
151 }
152}
153
154impl<T: Clone + Default + Debug> Into<taffy::geometry::Point<T>> for Point<T> {
155 fn into(self) -> taffy::geometry::Point<T> {
156 taffy::geometry::Point {
157 x: self.x,
158 y: self.y,
159 }
160 }
161}
162
163#[derive(Refineable, Clone, Debug)]
164#[refineable(debug)]
165pub struct Size<T: Clone + Default + Debug> {
166 pub width: T,
167 pub height: T,
168}
169
170impl<S, T: Clone + Default + Debug> From<taffy::geometry::Size<S>> for Size<T>
171where
172 S: Into<T>,
173{
174 fn from(value: taffy::geometry::Size<S>) -> Self {
175 Self {
176 width: value.width.into(),
177 height: value.height.into(),
178 }
179 }
180}
181
182impl<S, T: Clone + Default + Debug> Into<taffy::geometry::Size<S>> for Size<T>
183where
184 T: Into<S>,
185{
186 fn into(self) -> taffy::geometry::Size<S> {
187 taffy::geometry::Size {
188 width: self.width.into(),
189 height: self.height.into(),
190 }
191 }
192}
193
194impl Size<DefiniteLength> {
195 pub fn zero() -> Self {
196 Self {
197 width: pixels(0.),
198 height: pixels(0.),
199 }
200 }
201
202 pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Size<taffy::style::LengthPercentage> {
203 taffy::geometry::Size {
204 width: self.width.to_taffy(rem_size),
205 height: self.height.to_taffy(rem_size),
206 }
207 }
208}
209
210impl Size<Length> {
211 pub fn auto() -> Self {
212 Self {
213 width: Length::Auto,
214 height: Length::Auto,
215 }
216 }
217
218 pub fn to_taffy<T: From<taffy::prelude::LengthPercentageAuto>>(
219 &self,
220 rem_size: f32,
221 ) -> taffy::geometry::Size<T> {
222 taffy::geometry::Size {
223 width: self.width.to_taffy(rem_size).into(),
224 height: self.height.to_taffy(rem_size).into(),
225 }
226 }
227}
228
229#[derive(Clone, Default, Refineable, Debug)]
230#[refineable(debug)]
231pub struct Edges<T: Clone + Default + Debug> {
232 pub top: T,
233 pub right: T,
234 pub bottom: T,
235 pub left: T,
236}
237
238impl Edges<Length> {
239 pub fn auto() -> Self {
240 Self {
241 top: Length::Auto,
242 right: Length::Auto,
243 bottom: Length::Auto,
244 left: Length::Auto,
245 }
246 }
247
248 pub fn zero() -> Self {
249 Self {
250 top: pixels(0.),
251 right: pixels(0.),
252 bottom: pixels(0.),
253 left: pixels(0.),
254 }
255 }
256
257 pub fn to_taffy(
258 &self,
259 rem_size: f32,
260 ) -> taffy::geometry::Rect<taffy::style::LengthPercentageAuto> {
261 taffy::geometry::Rect {
262 top: self.top.to_taffy(rem_size),
263 right: self.right.to_taffy(rem_size),
264 bottom: self.bottom.to_taffy(rem_size),
265 left: self.left.to_taffy(rem_size),
266 }
267 }
268}
269
270impl Edges<DefiniteLength> {
271 pub fn zero() -> Self {
272 Self {
273 top: pixels(0.),
274 right: pixels(0.),
275 bottom: pixels(0.),
276 left: pixels(0.),
277 }
278 }
279
280 pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
281 taffy::geometry::Rect {
282 top: self.top.to_taffy(rem_size),
283 right: self.right.to_taffy(rem_size),
284 bottom: self.bottom.to_taffy(rem_size),
285 left: self.left.to_taffy(rem_size),
286 }
287 }
288}
289
290impl Edges<AbsoluteLength> {
291 pub fn zero() -> Self {
292 Self {
293 top: pixels(0.),
294 right: pixels(0.),
295 bottom: pixels(0.),
296 left: pixels(0.),
297 }
298 }
299
300 pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
301 taffy::geometry::Rect {
302 top: self.top.to_taffy(rem_size),
303 right: self.right.to_taffy(rem_size),
304 bottom: self.bottom.to_taffy(rem_size),
305 left: self.left.to_taffy(rem_size),
306 }
307 }
308
309 pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
310 Edges {
311 top: self.top.to_pixels(rem_size),
312 right: self.right.to_pixels(rem_size),
313 bottom: self.bottom.to_pixels(rem_size),
314 left: self.left.to_pixels(rem_size),
315 }
316 }
317}
318
319impl Edges<f32> {
320 pub fn is_empty(&self) -> bool {
321 self.top == 0.0 && self.right == 0.0 && self.bottom == 0.0 && self.left == 0.0
322 }
323}
324
325#[derive(Clone, Copy)]
326pub enum AbsoluteLength {
327 Pixels(f32),
328 Rems(f32),
329}
330
331impl std::fmt::Debug for AbsoluteLength {
332 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
333 match self {
334 AbsoluteLength::Pixels(pixels) => write!(f, "{}px", pixels),
335 AbsoluteLength::Rems(rems) => write!(f, "{}rems", rems),
336 }
337 }
338}
339
340impl AbsoluteLength {
341 pub fn to_pixels(&self, rem_size: f32) -> f32 {
342 match self {
343 AbsoluteLength::Pixels(pixels) => *pixels,
344 AbsoluteLength::Rems(rems) => rems * rem_size,
345 }
346 }
347
348 pub fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
349 match self {
350 AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
351 AbsoluteLength::Rems(rems) => taffy::style::LengthPercentage::Length(rems * rem_size),
352 }
353 }
354}
355
356impl Default for AbsoluteLength {
357 fn default() -> Self {
358 Self::Pixels(0.0)
359 }
360}
361
362/// A non-auto length that can be defined in pixels, rems, or percent of parent.
363#[derive(Clone, Copy)]
364pub enum DefiniteLength {
365 Absolute(AbsoluteLength),
366 Relative(f32), // 0. to 1.
367}
368
369impl DefiniteLength {
370 fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
371 match self {
372 DefiniteLength::Absolute(length) => match length {
373 AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
374 AbsoluteLength::Rems(rems) => {
375 taffy::style::LengthPercentage::Length(rems * rem_size)
376 }
377 },
378 DefiniteLength::Relative(fraction) => {
379 taffy::style::LengthPercentage::Percent(*fraction)
380 }
381 }
382 }
383}
384
385impl std::fmt::Debug for DefiniteLength {
386 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
387 match self {
388 DefiniteLength::Absolute(length) => std::fmt::Debug::fmt(length, f),
389 DefiniteLength::Relative(fract) => write!(f, "{}%", (fract * 100.0) as i32),
390 }
391 }
392}
393
394impl From<AbsoluteLength> for DefiniteLength {
395 fn from(length: AbsoluteLength) -> Self {
396 Self::Absolute(length)
397 }
398}
399
400impl Default for DefiniteLength {
401 fn default() -> Self {
402 Self::Absolute(AbsoluteLength::default())
403 }
404}
405
406/// A length that can be defined in pixels, rems, percent of parent, or auto.
407#[derive(Clone, Copy)]
408pub enum Length {
409 Definite(DefiniteLength),
410 Auto,
411}
412
413impl std::fmt::Debug for Length {
414 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
415 match self {
416 Length::Definite(definite_length) => write!(f, "{:?}", definite_length),
417 Length::Auto => write!(f, "auto"),
418 }
419 }
420}
421
422pub fn relative<T: From<DefiniteLength>>(fraction: f32) -> T {
423 DefiniteLength::Relative(fraction).into()
424}
425
426pub fn rems<T: From<AbsoluteLength>>(rems: f32) -> T {
427 AbsoluteLength::Rems(rems).into()
428}
429
430pub fn pixels<T: From<AbsoluteLength>>(pixels: f32) -> T {
431 AbsoluteLength::Pixels(pixels).into()
432}
433
434pub fn auto() -> Length {
435 Length::Auto
436}
437
438impl Length {
439 pub fn to_taffy(&self, rem_size: f32) -> taffy::prelude::LengthPercentageAuto {
440 match self {
441 Length::Definite(length) => length.to_taffy(rem_size).into(),
442 Length::Auto => taffy::prelude::LengthPercentageAuto::Auto,
443 }
444 }
445}
446
447impl From<DefiniteLength> for Length {
448 fn from(length: DefiniteLength) -> Self {
449 Self::Definite(length)
450 }
451}
452
453impl From<AbsoluteLength> for Length {
454 fn from(length: AbsoluteLength) -> Self {
455 Self::Definite(length.into())
456 }
457}
458
459impl Default for Length {
460 fn default() -> Self {
461 Self::Definite(DefiniteLength::default())
462 }
463}
464
465impl From<()> for Length {
466 fn from(_: ()) -> Self {
467 Self::Definite(DefiniteLength::default())
468 }
469}