geometry.rs

  1use super::scene::{Path, PathVertex};
  2use crate::{color::Color, json::ToJson};
  3use derive_more::Neg;
  4pub use pathfinder_geometry::*;
  5use rect::RectF;
  6use refineable::Refineable;
  7use serde::{Deserialize, Deserializer};
  8use serde_json::json;
  9use std::fmt::Debug;
 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.).into(),
198            height: pixels(0.).into(),
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<T: Clone + Default + Debug> Edges<T> {
239    pub fn uniform(value: T) -> Self {
240        Self {
241            top: value.clone(),
242            right: value.clone(),
243            bottom: value.clone(),
244            left: value.clone(),
245        }
246    }
247}
248
249impl Edges<Length> {
250    pub fn auto() -> Self {
251        Self {
252            top: Length::Auto,
253            right: Length::Auto,
254            bottom: Length::Auto,
255            left: Length::Auto,
256        }
257    }
258
259    pub fn zero() -> Self {
260        Self {
261            top: pixels(0.).into(),
262            right: pixels(0.).into(),
263            bottom: pixels(0.).into(),
264            left: pixels(0.).into(),
265        }
266    }
267
268    pub fn to_taffy(
269        &self,
270        rem_size: f32,
271    ) -> taffy::geometry::Rect<taffy::style::LengthPercentageAuto> {
272        taffy::geometry::Rect {
273            top: self.top.to_taffy(rem_size),
274            right: self.right.to_taffy(rem_size),
275            bottom: self.bottom.to_taffy(rem_size),
276            left: self.left.to_taffy(rem_size),
277        }
278    }
279}
280
281impl Edges<DefiniteLength> {
282    pub fn zero() -> Self {
283        Self {
284            top: pixels(0.).into(),
285            right: pixels(0.).into(),
286            bottom: pixels(0.).into(),
287            left: pixels(0.).into(),
288        }
289    }
290
291    pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
292        taffy::geometry::Rect {
293            top: self.top.to_taffy(rem_size),
294            right: self.right.to_taffy(rem_size),
295            bottom: self.bottom.to_taffy(rem_size),
296            left: self.left.to_taffy(rem_size),
297        }
298    }
299}
300
301impl Edges<AbsoluteLength> {
302    pub fn zero() -> Self {
303        Self {
304            top: pixels(0.),
305            right: pixels(0.),
306            bottom: pixels(0.),
307            left: pixels(0.),
308        }
309    }
310
311    pub fn to_taffy(&self, rem_size: f32) -> taffy::geometry::Rect<taffy::style::LengthPercentage> {
312        taffy::geometry::Rect {
313            top: self.top.to_taffy(rem_size),
314            right: self.right.to_taffy(rem_size),
315            bottom: self.bottom.to_taffy(rem_size),
316            left: self.left.to_taffy(rem_size),
317        }
318    }
319
320    pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
321        Edges {
322            top: self.top.to_pixels(rem_size),
323            right: self.right.to_pixels(rem_size),
324            bottom: self.bottom.to_pixels(rem_size),
325            left: self.left.to_pixels(rem_size),
326        }
327    }
328}
329
330impl Edges<f32> {
331    pub fn is_empty(&self) -> bool {
332        self.top == 0.0 && self.right == 0.0 && self.bottom == 0.0 && self.left == 0.0
333    }
334}
335
336#[derive(Clone, Copy, Neg)]
337pub enum AbsoluteLength {
338    Pixels(f32),
339    Rems(f32),
340}
341
342impl std::fmt::Debug for AbsoluteLength {
343    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
344        match self {
345            AbsoluteLength::Pixels(pixels) => write!(f, "{}px", pixels),
346            AbsoluteLength::Rems(rems) => write!(f, "{}rems", rems),
347        }
348    }
349}
350
351impl AbsoluteLength {
352    pub fn to_pixels(&self, rem_size: f32) -> f32 {
353        match self {
354            AbsoluteLength::Pixels(pixels) => *pixels,
355            AbsoluteLength::Rems(rems) => rems * rem_size,
356        }
357    }
358
359    pub fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
360        match self {
361            AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
362            AbsoluteLength::Rems(rems) => taffy::style::LengthPercentage::Length(rems * rem_size),
363        }
364    }
365}
366
367impl Default for AbsoluteLength {
368    fn default() -> Self {
369        Self::Pixels(0.0)
370    }
371}
372
373/// A non-auto length that can be defined in pixels, rems, or percent of parent.
374#[derive(Clone, Copy, Neg)]
375pub enum DefiniteLength {
376    Absolute(AbsoluteLength),
377    Relative(f32), // 0. to 1.
378}
379
380impl DefiniteLength {
381    fn to_taffy(&self, rem_size: f32) -> taffy::style::LengthPercentage {
382        match self {
383            DefiniteLength::Absolute(length) => match length {
384                AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(*pixels),
385                AbsoluteLength::Rems(rems) => {
386                    taffy::style::LengthPercentage::Length(rems * rem_size)
387                }
388            },
389            DefiniteLength::Relative(fraction) => {
390                taffy::style::LengthPercentage::Percent(*fraction)
391            }
392        }
393    }
394}
395
396impl std::fmt::Debug for DefiniteLength {
397    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
398        match self {
399            DefiniteLength::Absolute(length) => std::fmt::Debug::fmt(length, f),
400            DefiniteLength::Relative(fract) => write!(f, "{}%", (fract * 100.0) as i32),
401        }
402    }
403}
404
405impl From<AbsoluteLength> for DefiniteLength {
406    fn from(length: AbsoluteLength) -> Self {
407        Self::Absolute(length)
408    }
409}
410
411impl Default for DefiniteLength {
412    fn default() -> Self {
413        Self::Absolute(AbsoluteLength::default())
414    }
415}
416
417/// A length that can be defined in pixels, rems, percent of parent, or auto.
418#[derive(Clone, Copy, Neg)]
419pub enum Length {
420    Definite(DefiniteLength),
421    Auto,
422}
423
424impl std::fmt::Debug for Length {
425    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
426        match self {
427            Length::Definite(definite_length) => write!(f, "{:?}", definite_length),
428            Length::Auto => write!(f, "auto"),
429        }
430    }
431}
432
433pub fn relative(fraction: f32) -> DefiniteLength {
434    DefiniteLength::Relative(fraction)
435}
436
437pub fn rems(rems: f32) -> AbsoluteLength {
438    AbsoluteLength::Rems(rems)
439}
440
441pub fn pixels(pixels: f32) -> AbsoluteLength {
442    AbsoluteLength::Pixels(pixels)
443}
444
445pub fn auto() -> Length {
446    Length::Auto
447}
448
449impl Length {
450    pub fn to_taffy(&self, rem_size: f32) -> taffy::prelude::LengthPercentageAuto {
451        match self {
452            Length::Definite(length) => length.to_taffy(rem_size).into(),
453            Length::Auto => taffy::prelude::LengthPercentageAuto::Auto,
454        }
455    }
456}
457
458impl From<DefiniteLength> for Length {
459    fn from(length: DefiniteLength) -> Self {
460        Self::Definite(length)
461    }
462}
463
464impl From<AbsoluteLength> for Length {
465    fn from(length: AbsoluteLength) -> Self {
466        Self::Definite(length.into())
467    }
468}
469
470impl Default for Length {
471    fn default() -> Self {
472        Self::Definite(DefiniteLength::default())
473    }
474}
475
476impl From<()> for Length {
477    fn from(_: ()) -> Self {
478        Self::Definite(DefiniteLength::default())
479    }
480}