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 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}