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, Debug)]
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<Length> {
234    pub fn auto() -> Self {
235        Self {
236            top: Length::Auto,
237            right: Length::Auto,
238            bottom: Length::Auto,
239            left: Length::Auto,
240        }
241    }
242
243    pub fn zero() -> Self {
244        Self {
245            top: pixels(0.),
246            right: pixels(0.),
247            bottom: pixels(0.),
248            left: pixels(0.),
249        }
250    }
251
252    pub fn to_taffy(
253        &self,
254        rem_size: f32,
255    ) -> taffy::geometry::Rect<taffy::style::LengthPercentageAuto> {
256        taffy::geometry::Rect {
257            top: self.top.to_taffy(rem_size),
258            right: self.right.to_taffy(rem_size),
259            bottom: self.bottom.to_taffy(rem_size),
260            left: self.left.to_taffy(rem_size),
261        }
262    }
263}
264
265impl Edges<DefiniteLength> {
266    pub fn zero() -> Self {
267        Self {
268            top: pixels(0.),
269            right: pixels(0.),
270            bottom: pixels(0.),
271            left: pixels(0.),
272        }
273    }
274
275    pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
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
285impl Edges<AbsoluteLength> {
286    pub fn zero() -> Self {
287        Self {
288            top: pixels(0.),
289            right: pixels(0.),
290            bottom: pixels(0.),
291            left: pixels(0.),
292        }
293    }
294
295    pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
296        taffy::geometry::Rect {
297            top: self.top.to_taffy(rem_size),
298            right: self.right.to_taffy(rem_size),
299            bottom: self.bottom.to_taffy(rem_size),
300            left: self.left.to_taffy(rem_size),
301        }
302    }
303
304    pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
305        Edges {
306            top: self.top.to_pixels(rem_size),
307            right: self.right.to_pixels(rem_size),
308            bottom: self.bottom.to_pixels(rem_size),
309            left: self.left.to_pixels(rem_size),
310        }
311    }
312}
313
314impl Edges<f32> {
315    pub fn is_empty(&self) -> bool {
316        self.top == 0.0 && self.right == 0.0 && self.bottom == 0.0 && self.left == 0.0
317    }
318}
319
320#[derive(Clone, Copy)]
321pub enum AbsoluteLength {
322    Pixels(f32),
323    Rems(f32),
324}
325
326impl AbsoluteLength {
327    pub fn to_pixels(&self, rem_size: f32) -> f32 {
328        match self {
329            AbsoluteLength::Pixels(pixels) => *pixels,
330            AbsoluteLength::Rems(rems) => rems * rem_size,
331        }
332    }
333
334    pub fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
335        match self {
336            AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
337            AbsoluteLength::Rems(rems) => taffy::style::LengthPercentage::Length(rems * rem_size),
338        }
339    }
340}
341
342impl Default for AbsoluteLength {
343    fn default() -> Self {
344        Self::Pixels(0.0)
345    }
346}
347
348/// A non-auto length that can be defined in pixels, rems, or percent of parent.
349#[derive(Clone, Copy)]
350pub enum DefiniteLength {
351    Absolute(AbsoluteLength),
352    Relative(f32), // Percent, from 0 to 100.
353}
354
355impl DefiniteLength {
356    fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
357        match self {
358            DefiniteLength::Absolute(length) => match length {
359                AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
360                AbsoluteLength::Rems(rems) => {
361                    taffy::style::LengthPercentage::Length(rems * rem_size)
362                }
363            },
364            DefiniteLength::Relative(fraction) => {
365                taffy::style::LengthPercentage::Percent(*fraction)
366            }
367        }
368    }
369}
370
371impl From<AbsoluteLength> for DefiniteLength {
372    fn from(length: AbsoluteLength) -> Self {
373        Self::Absolute(length)
374    }
375}
376
377impl Default for DefiniteLength {
378    fn default() -> Self {
379        Self::Absolute(AbsoluteLength::default())
380    }
381}
382
383/// A length that can be defined in pixels, rems, percent of parent, or auto.
384#[derive(Clone, Copy)]
385pub enum Length {
386    Definite(DefiniteLength),
387    Auto,
388}
389
390pub fn relative<T: From<DefiniteLength>>(fraction: f32) -> T {
391    DefiniteLength::Relative(fraction).into()
392}
393
394pub fn rems<T: From<AbsoluteLength>>(rems: f32) -> T {
395    AbsoluteLength::Rems(rems).into()
396}
397
398pub fn pixels<T: From<AbsoluteLength>>(pixels: f32) -> T {
399    AbsoluteLength::Pixels(pixels).into()
400}
401
402pub fn auto() -> Length {
403    Length::Auto
404}
405
406impl Length {
407    pub fn to_taffy(&self, rem_size: f32) -> taffy::prelude::LengthPercentageAuto {
408        match self {
409            Length::Definite(length) => length.to_taffy(rem_size).into(),
410            Length::Auto => taffy::prelude::LengthPercentageAuto::Auto,
411        }
412    }
413}
414
415impl From<DefiniteLength> for Length {
416    fn from(length: DefiniteLength) -> Self {
417        Self::Definite(length)
418    }
419}
420
421impl From<AbsoluteLength> for Length {
422    fn from(length: AbsoluteLength) -> Self {
423        Self::Definite(length.into())
424    }
425}
426
427impl Default for Length {
428    fn default() -> Self {
429        Self::Definite(DefiniteLength::default())
430    }
431}
432
433impl From<()> for Length {
434    fn from(_: ()) -> Self {
435        Self::Definite(DefiniteLength::default())
436    }
437}