geometry.rs

  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}