geometry.rs

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