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 Size<Length> {
171 pub fn full() -> Self {
172 Self {
173 width: relative(1.),
174 height: relative(1.),
175 }
176 }
177}
178
179impl<S, T: Clone + Default + Debug> From<taffy::geometry::Size<S>> for Size<T>
180where
181 S: Into<T>,
182{
183 fn from(value: taffy::geometry::Size<S>) -> Self {
184 Self {
185 width: value.width.into(),
186 height: value.height.into(),
187 }
188 }
189}
190
191impl<S, T: Clone + Default + Debug> Into<taffy::geometry::Size<S>> for Size<T>
192where
193 T: Into<S>,
194{
195 fn into(self) -> taffy::geometry::Size<S> {
196 taffy::geometry::Size {
197 width: self.width.into(),
198 height: self.height.into(),
199 }
200 }
201}
202
203impl Size<DefiniteLength> {
204 pub fn zero() -> Self {
205 Self {
206 width: px(0.),
207 height: px(0.),
208 }
209 }
210
211 pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Size<taffy::style::LengthPercentage> {
212 taffy::geometry::Size {
213 width: self.width.to_taffy(rem_size),
214 height: self.height.to_taffy(rem_size),
215 }
216 }
217}
218
219impl Size<Length> {
220 pub fn auto() -> Self {
221 Self {
222 width: Length::Auto,
223 height: Length::Auto,
224 }
225 }
226
227 pub fn to_taffy<T: From<taffy::prelude::LengthPercentageAuto>>(
228 &self,
229 rem_size: f32,
230 ) -> taffy::geometry::Size<T> {
231 taffy::geometry::Size {
232 width: self.width.to_taffy(rem_size).into(),
233 height: self.height.to_taffy(rem_size).into(),
234 }
235 }
236}
237
238#[derive(Clone, Default, Refineable, Debug)]
239#[refineable(debug)]
240pub struct Edges<T: Clone + Default + Debug> {
241 pub top: T,
242 pub right: T,
243 pub bottom: T,
244 pub left: T,
245}
246
247impl Edges<Length> {
248 pub fn auto() -> Self {
249 Self {
250 top: Length::Auto,
251 right: Length::Auto,
252 bottom: Length::Auto,
253 left: Length::Auto,
254 }
255 }
256
257 pub fn zero() -> Self {
258 Self {
259 top: px(0.),
260 right: px(0.),
261 bottom: px(0.),
262 left: px(0.),
263 }
264 }
265
266 pub fn to_taffy(
267 &self,
268 rem_size: f32,
269 ) -> taffy::geometry::Rect<taffy::style::LengthPercentageAuto> {
270 taffy::geometry::Rect {
271 top: self.top.to_taffy(rem_size),
272 right: self.right.to_taffy(rem_size),
273 bottom: self.bottom.to_taffy(rem_size),
274 left: self.left.to_taffy(rem_size),
275 }
276 }
277}
278
279impl Edges<DefiniteLength> {
280 pub fn zero() -> Self {
281 Self {
282 top: px(0.),
283 right: px(0.),
284 bottom: px(0.),
285 left: px(0.),
286 }
287 }
288
289 pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
290 taffy::geometry::Rect {
291 top: self.top.to_taffy(rem_size),
292 right: self.right.to_taffy(rem_size),
293 bottom: self.bottom.to_taffy(rem_size),
294 left: self.left.to_taffy(rem_size),
295 }
296 }
297}
298
299impl Edges<AbsoluteLength> {
300 pub fn zero() -> Self {
301 Self {
302 top: px(0.),
303 right: px(0.),
304 bottom: px(0.),
305 left: px(0.),
306 }
307 }
308
309 pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
310 taffy::geometry::Rect {
311 top: self.top.to_taffy(rem_size),
312 right: self.right.to_taffy(rem_size),
313 bottom: self.bottom.to_taffy(rem_size),
314 left: self.left.to_taffy(rem_size),
315 }
316 }
317
318 pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
319 Edges {
320 top: self.top.to_pixels(rem_size),
321 right: self.right.to_pixels(rem_size),
322 bottom: self.bottom.to_pixels(rem_size),
323 left: self.left.to_pixels(rem_size),
324 }
325 }
326}
327
328impl Edges<f32> {
329 pub fn is_empty(&self) -> bool {
330 self.top == 0.0 && self.right == 0.0 && self.bottom == 0.0 && self.left == 0.0
331 }
332}
333
334#[derive(Clone, Copy)]
335pub enum AbsoluteLength {
336 Pixels(f32),
337 Rems(f32),
338}
339
340impl std::fmt::Debug for AbsoluteLength {
341 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
342 match self {
343 AbsoluteLength::Pixels(pixels) => write!(f, "{}px", pixels),
344 AbsoluteLength::Rems(rems) => write!(f, "{}rems", rems),
345 }
346 }
347}
348
349impl AbsoluteLength {
350 pub fn to_pixels(&self, rem_size: f32) -> f32 {
351 match self {
352 AbsoluteLength::Pixels(pixels) => *pixels,
353 AbsoluteLength::Rems(rems) => rems * rem_size,
354 }
355 }
356
357 pub fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
358 match self {
359 AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
360 AbsoluteLength::Rems(rems) => taffy::style::LengthPercentage::Length(rems * rem_size),
361 }
362 }
363}
364
365impl Default for AbsoluteLength {
366 fn default() -> Self {
367 Self::Pixels(0.0)
368 }
369}
370
371/// A non-auto length that can be defined in pixels, rems, or percent of parent.
372#[derive(Clone, Copy)]
373pub enum DefiniteLength {
374 Absolute(AbsoluteLength),
375 Relative(f32), // 0. to 1.
376}
377
378impl DefiniteLength {
379 fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
380 match self {
381 DefiniteLength::Absolute(length) => match length {
382 AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
383 AbsoluteLength::Rems(rems) => {
384 taffy::style::LengthPercentage::Length(rems * rem_size)
385 }
386 },
387 DefiniteLength::Relative(fraction) => {
388 taffy::style::LengthPercentage::Percent(*fraction)
389 }
390 }
391 }
392}
393
394impl std::fmt::Debug for DefiniteLength {
395 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
396 match self {
397 DefiniteLength::Absolute(length) => std::fmt::Debug::fmt(length, f),
398 DefiniteLength::Relative(fract) => write!(f, "{}%", (fract * 100.0) as i32),
399 }
400 }
401}
402
403impl From<AbsoluteLength> for DefiniteLength {
404 fn from(length: AbsoluteLength) -> Self {
405 Self::Absolute(length)
406 }
407}
408
409impl Default for DefiniteLength {
410 fn default() -> Self {
411 Self::Absolute(AbsoluteLength::default())
412 }
413}
414
415/// A length that can be defined in pixels, rems, percent of parent, or auto.
416#[derive(Clone, Copy)]
417pub enum Length {
418 Definite(DefiniteLength),
419 Auto,
420}
421
422impl std::fmt::Debug for Length {
423 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
424 match self {
425 Length::Definite(definite_length) => write!(f, "{:?}", definite_length),
426 Length::Auto => write!(f, "auto"),
427 }
428 }
429}
430
431pub fn relative<T: From<DefiniteLength>>(fraction: f32) -> T {
432 DefiniteLength::Relative(fraction).into()
433}
434
435pub fn rems<T: From<AbsoluteLength>>(rems: f32) -> T {
436 AbsoluteLength::Rems(rems).into()
437}
438
439pub fn px<T: From<AbsoluteLength>>(pixels: f32) -> T {
440 AbsoluteLength::Pixels(pixels).into()
441}
442
443pub fn pixels<T: From<AbsoluteLength>>(pixels: f32) -> T {
444 AbsoluteLength::Pixels(pixels).into()
445}
446
447pub fn auto() -> Length {
448 Length::Auto
449}
450
451impl Length {
452 pub fn to_taffy(&self, rem_size: f32) -> taffy::prelude::LengthPercentageAuto {
453 match self {
454 Length::Definite(length) => length.to_taffy(rem_size).into(),
455 Length::Auto => taffy::prelude::LengthPercentageAuto::Auto,
456 }
457 }
458}
459
460impl From<DefiniteLength> for Length {
461 fn from(length: DefiniteLength) -> Self {
462 Self::Definite(length)
463 }
464}
465
466impl From<AbsoluteLength> for Length {
467 fn from(length: AbsoluteLength) -> Self {
468 Self::Definite(length.into())
469 }
470}
471
472impl Default for Length {
473 fn default() -> Self {
474 Self::Definite(DefiniteLength::default())
475 }
476}
477
478impl From<()> for Length {
479 fn from(_: ()) -> Self {
480 Self::Definite(DefiniteLength::default())
481 }
482}