azul_css/
css_properties.rs

1//! Provides a public API with datatypes used to describe style properties of DOM nodes.
2
3use alloc::{boxed::Box, collections::btree_map::BTreeMap, string::String, vec::Vec};
4use core::{
5    cmp::Ordering,
6    ffi::c_void,
7    fmt,
8    hash::{Hash, Hasher},
9    sync::atomic::{AtomicUsize, Ordering as AtomicOrdering},
10};
11
12use crate::{css::CssPropertyValue, AzString, OptionI16, OptionU16, OptionU32, U8Vec};
13
14/// Currently hard-coded: Height of one em in pixels
15pub const EM_HEIGHT: f32 = 16.0;
16pub const PT_TO_PX: f32 = 96.0 / 72.0;
17
18const COMBINED_CSS_PROPERTIES_KEY_MAP: [(CombinedCssPropertyType, &'static str); 12] = [
19    (CombinedCssPropertyType::BorderRadius, "border-radius"),
20    (CombinedCssPropertyType::Overflow, "overflow"),
21    (CombinedCssPropertyType::Padding, "padding"),
22    (CombinedCssPropertyType::Margin, "margin"),
23    (CombinedCssPropertyType::Border, "border"),
24    (CombinedCssPropertyType::BorderLeft, "border-left"),
25    (CombinedCssPropertyType::BorderRight, "border-right"),
26    (CombinedCssPropertyType::BorderTop, "border-top"),
27    (CombinedCssPropertyType::BorderBottom, "border-bottom"),
28    (CombinedCssPropertyType::BoxShadow, "box-shadow"),
29    (CombinedCssPropertyType::BackgroundColor, "background-color"),
30    (CombinedCssPropertyType::BackgroundImage, "background-image"),
31];
32
33/// Map between CSS keys and a statically typed enum
34const CSS_PROPERTY_KEY_MAP: [(CssPropertyType, &'static str); 74] = [
35    (CssPropertyType::Display, "display"),
36    (CssPropertyType::Float, "float"),
37    (CssPropertyType::BoxSizing, "box-sizing"),
38    (CssPropertyType::TextColor, "color"),
39    (CssPropertyType::FontSize, "font-size"),
40    (CssPropertyType::FontFamily, "font-family"),
41    (CssPropertyType::TextAlign, "text-align"),
42    (CssPropertyType::LetterSpacing, "letter-spacing"),
43    (CssPropertyType::LineHeight, "line-height"),
44    (CssPropertyType::WordSpacing, "word-spacing"),
45    (CssPropertyType::TabWidth, "tab-width"),
46    (CssPropertyType::Cursor, "cursor"),
47    (CssPropertyType::Width, "width"),
48    (CssPropertyType::Height, "height"),
49    (CssPropertyType::MinWidth, "min-width"),
50    (CssPropertyType::MinHeight, "min-height"),
51    (CssPropertyType::MaxWidth, "max-width"),
52    (CssPropertyType::MaxHeight, "max-height"),
53    (CssPropertyType::Position, "position"),
54    (CssPropertyType::Top, "top"),
55    (CssPropertyType::Right, "right"),
56    (CssPropertyType::Left, "left"),
57    (CssPropertyType::Bottom, "bottom"),
58    (CssPropertyType::FlexWrap, "flex-wrap"),
59    (CssPropertyType::FlexDirection, "flex-direction"),
60    (CssPropertyType::FlexGrow, "flex-grow"),
61    (CssPropertyType::FlexShrink, "flex-shrink"),
62    (CssPropertyType::JustifyContent, "justify-content"),
63    (CssPropertyType::AlignItems, "align-items"),
64    (CssPropertyType::AlignContent, "align-content"),
65    (CssPropertyType::OverflowX, "overflow-x"),
66    (CssPropertyType::OverflowY, "overflow-y"),
67    (CssPropertyType::PaddingTop, "padding-top"),
68    (CssPropertyType::PaddingLeft, "padding-left"),
69    (CssPropertyType::PaddingRight, "padding-right"),
70    (CssPropertyType::PaddingBottom, "padding-bottom"),
71    (CssPropertyType::MarginTop, "margin-top"),
72    (CssPropertyType::MarginLeft, "margin-left"),
73    (CssPropertyType::MarginRight, "margin-right"),
74    (CssPropertyType::MarginBottom, "margin-bottom"),
75    (CssPropertyType::BackgroundContent, "background"),
76    (CssPropertyType::BackgroundPosition, "background-position"),
77    (CssPropertyType::BackgroundSize, "background-size"),
78    (CssPropertyType::BackgroundRepeat, "background-repeat"),
79    (
80        CssPropertyType::BorderTopLeftRadius,
81        "border-top-left-radius",
82    ),
83    (
84        CssPropertyType::BorderTopRightRadius,
85        "border-top-right-radius",
86    ),
87    (
88        CssPropertyType::BorderBottomLeftRadius,
89        "border-bottom-left-radius",
90    ),
91    (
92        CssPropertyType::BorderBottomRightRadius,
93        "border-bottom-right-radius",
94    ),
95    (CssPropertyType::BorderTopColor, "border-top-color"),
96    (CssPropertyType::BorderRightColor, "border-right-color"),
97    (CssPropertyType::BorderLeftColor, "border-left-color"),
98    (CssPropertyType::BorderBottomColor, "border-bottom-color"),
99    (CssPropertyType::BorderTopStyle, "border-top-style"),
100    (CssPropertyType::BorderRightStyle, "border-right-style"),
101    (CssPropertyType::BorderLeftStyle, "border-left-style"),
102    (CssPropertyType::BorderBottomStyle, "border-bottom-style"),
103    (CssPropertyType::BorderTopWidth, "border-top-width"),
104    (CssPropertyType::BorderRightWidth, "border-right-width"),
105    (CssPropertyType::BorderLeftWidth, "border-left-width"),
106    (CssPropertyType::BorderBottomWidth, "border-bottom-width"),
107    (CssPropertyType::BoxShadowTop, "-azul-box-shadow-top"),
108    (CssPropertyType::BoxShadowRight, "-azul-box-shadow-right"),
109    (CssPropertyType::BoxShadowLeft, "-azul-box-shadow-left"),
110    (CssPropertyType::BoxShadowBottom, "-azul-box-shadow-bottom"),
111    (CssPropertyType::ScrollbarStyle, "-azul-scrollbar-style"),
112    (CssPropertyType::Opacity, "opacity"),
113    (CssPropertyType::Transform, "transform"),
114    (CssPropertyType::PerspectiveOrigin, "perspective-origin"),
115    (CssPropertyType::TransformOrigin, "transform-origin"),
116    (CssPropertyType::BackfaceVisibility, "backface-visibility"),
117    (CssPropertyType::MixBlendMode, "mix-blend-mode"),
118    (CssPropertyType::Filter, "filter"),
119    (CssPropertyType::BackdropFilter, "backdrop-filter"),
120    (CssPropertyType::TextShadow, "text-shadow"),
121];
122
123// The following types are present in webrender, however, azul-css should not
124// depend on webrender, just to have the same types, azul-css should be a standalone crate.
125
126/// Only used for calculations: Rectangle (x, y, width, height) in layout space.
127#[derive(Copy, Clone, PartialEq, PartialOrd)]
128#[repr(C)]
129pub struct LayoutRect {
130    pub origin: LayoutPoint,
131    pub size: LayoutSize,
132}
133
134impl_option!(
135    LayoutRect,
136    OptionLayoutRect,
137    [Debug, Copy, Clone, PartialEq, PartialOrd]
138);
139
140impl_vec!(LayoutRect, LayoutRectVec, LayoutRectVecDestructor);
141impl_vec_clone!(LayoutRect, LayoutRectVec, LayoutRectVecDestructor);
142impl_vec_debug!(LayoutRect, LayoutRectVec);
143impl_vec_mut!(LayoutRect, LayoutRectVec);
144impl_vec_partialeq!(LayoutRect, LayoutRectVec);
145impl_vec_partialord!(LayoutRect, LayoutRectVec);
146
147impl fmt::Debug for LayoutRect {
148    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149        write!(f, "{}", self)
150    }
151}
152
153impl fmt::Display for LayoutRect {
154    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155        write!(f, "{} @ {}", self.size, self.origin)
156    }
157}
158
159impl LayoutRect {
160    #[inline(always)]
161    pub const fn new(origin: LayoutPoint, size: LayoutSize) -> Self {
162        Self { origin, size }
163    }
164    #[inline(always)]
165    pub const fn zero() -> Self {
166        Self::new(LayoutPoint::zero(), LayoutSize::zero())
167    }
168    #[inline(always)]
169    pub const fn max_x(&self) -> isize {
170        self.origin.x + self.size.width
171    }
172    #[inline(always)]
173    pub const fn min_x(&self) -> isize {
174        self.origin.x
175    }
176    #[inline(always)]
177    pub const fn max_y(&self) -> isize {
178        self.origin.y + self.size.height
179    }
180    #[inline(always)]
181    pub const fn min_y(&self) -> isize {
182        self.origin.y
183    }
184    #[inline(always)]
185    pub const fn width(&self) -> isize {
186        self.max_x() - self.min_x()
187    }
188    #[inline(always)]
189    pub const fn height(&self) -> isize {
190        self.max_y() - self.min_y()
191    }
192
193    pub const fn contains(&self, other: &LayoutPoint) -> bool {
194        self.min_x() <= other.x
195            && other.x < self.max_x()
196            && self.min_y() <= other.y
197            && other.y < self.max_y()
198    }
199
200    pub fn contains_f32(&self, other_x: f32, other_y: f32) -> bool {
201        self.min_x() as f32 <= other_x
202            && other_x < self.max_x() as f32
203            && self.min_y() as f32 <= other_y
204            && other_y < self.max_y() as f32
205    }
206
207    /// Same as `contains()`, but returns the (x, y) offset of the hit point
208    ///
209    /// On a regular computer this function takes ~3.2ns to run
210    #[inline]
211    pub const fn hit_test(&self, other: &LayoutPoint) -> Option<LayoutPoint> {
212        let dx_left_edge = other.x - self.min_x();
213        let dx_right_edge = self.max_x() - other.x;
214        let dy_top_edge = other.y - self.min_y();
215        let dy_bottom_edge = self.max_y() - other.y;
216        if dx_left_edge > 0 && dx_right_edge > 0 && dy_top_edge > 0 && dy_bottom_edge > 0 {
217            Some(LayoutPoint::new(dx_left_edge, dy_top_edge))
218        } else {
219            None
220        }
221    }
222
223    /// Faster union for a Vec<LayoutRect>
224    #[inline]
225    pub fn union<I: Iterator<Item = Self>>(mut rects: I) -> Option<Self> {
226        let first = rects.next()?;
227
228        let mut max_width = first.size.width;
229        let mut max_height = first.size.height;
230        let mut min_x = first.origin.x;
231        let mut min_y = first.origin.y;
232
233        while let Some(Self {
234            origin: LayoutPoint { x, y },
235            size: LayoutSize { width, height },
236        }) = rects.next()
237        {
238            let cur_lower_right_x = x + width;
239            let cur_lower_right_y = y + height;
240            max_width = max_width.max(cur_lower_right_x - min_x);
241            max_height = max_height.max(cur_lower_right_y - min_y);
242            min_x = min_x.min(x);
243            min_y = min_y.min(y);
244        }
245
246        Some(Self {
247            origin: LayoutPoint { x: min_x, y: min_y },
248            size: LayoutSize {
249                width: max_width,
250                height: max_height,
251            },
252        })
253    }
254
255    // Returns the scroll rect (not the union rect) of the parent / children
256    #[inline]
257    pub fn get_scroll_rect<I: Iterator<Item = Self>>(&self, children: I) -> Option<Self> {
258        let children_union = Self::union(children)?;
259        Self::union([*self, children_union].iter().map(|r| *r))
260    }
261
262    // Returns if b overlaps a
263    #[inline(always)]
264    pub const fn contains_rect(&self, b: &LayoutRect) -> bool {
265        let a = self;
266
267        let a_x = a.origin.x;
268        let a_y = a.origin.y;
269        let a_width = a.size.width;
270        let a_height = a.size.height;
271
272        let b_x = b.origin.x;
273        let b_y = b.origin.y;
274        let b_width = b.size.width;
275        let b_height = b.size.height;
276
277        b_x >= a_x
278            && b_y >= a_y
279            && b_x + b_width <= a_x + a_width
280            && b_y + b_height <= a_y + a_height
281    }
282}
283
284/// Only used for calculations: Size (width, height) in layout space.
285#[derive(Copy, Default, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
286#[repr(C)]
287pub struct LayoutSize {
288    pub width: isize,
289    pub height: isize,
290}
291
292impl_option!(
293    LayoutSize,
294    OptionLayoutSize,
295    [Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash]
296);
297
298impl fmt::Debug for LayoutSize {
299    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
300        write!(f, "{}", self)
301    }
302}
303
304impl fmt::Display for LayoutSize {
305    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
306        write!(f, "{}x{}", self.width, self.height)
307    }
308}
309
310impl LayoutSize {
311    #[inline(always)]
312    pub const fn new(width: isize, height: isize) -> Self {
313        Self { width, height }
314    }
315    #[inline(always)]
316    pub const fn zero() -> Self {
317        Self::new(0, 0)
318    }
319    #[inline]
320    pub fn round(width: f32, height: f32) -> Self {
321        Self {
322            width: libm::roundf(width) as isize,
323            height: libm::roundf(height) as isize,
324        }
325    }
326}
327
328/// Only used for calculations: Point coordinate (x, y) in layout space.
329#[derive(Copy, Default, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
330#[repr(C)]
331pub struct LayoutPoint {
332    pub x: isize,
333    pub y: isize,
334}
335
336impl fmt::Debug for LayoutPoint {
337    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
338        write!(f, "{}", self)
339    }
340}
341
342impl fmt::Display for LayoutPoint {
343    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
344        write!(f, "({}, {})", self.x, self.y)
345    }
346}
347
348impl LayoutPoint {
349    #[inline(always)]
350    pub const fn new(x: isize, y: isize) -> Self {
351        Self { x, y }
352    }
353    #[inline(always)]
354    pub const fn zero() -> Self {
355        Self::new(0, 0)
356    }
357}
358
359impl_option!(
360    LayoutPoint,
361    OptionLayoutPoint,
362    [Debug, Copy, Clone, PartialEq, PartialOrd]
363);
364
365/// Represents a parsed pair of `5px, 10px` values - useful for border radius calculation
366#[derive(Default, Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
367pub struct PixelSize {
368    pub width: PixelValue,
369    pub height: PixelValue,
370}
371
372impl PixelSize {
373    pub const fn new(width: PixelValue, height: PixelValue) -> Self {
374        Self { width, height }
375    }
376
377    pub const fn zero() -> Self {
378        Self::new(PixelValue::const_px(0), PixelValue::const_px(0))
379    }
380}
381
382/// Offsets of the border-width calculations
383#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
384#[repr(C)]
385pub struct LayoutSideOffsets {
386    pub top: FloatValue,
387    pub right: FloatValue,
388    pub bottom: FloatValue,
389    pub left: FloatValue,
390}
391
392/// u8-based color, range 0 to 255 (similar to webrenders ColorU)
393#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
394#[repr(C)]
395pub struct ColorU {
396    pub r: u8,
397    pub g: u8,
398    pub b: u8,
399    pub a: u8,
400}
401
402impl Default for ColorU {
403    fn default() -> Self {
404        ColorU::BLACK
405    }
406}
407
408impl fmt::Display for ColorU {
409    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
410        write!(
411            f,
412            "rgba({}, {}, {}, {})",
413            self.r,
414            self.g,
415            self.b,
416            self.a as f32 / 255.0
417        )
418    }
419}
420
421impl ColorU {
422    pub const ALPHA_TRANSPARENT: u8 = 0;
423    pub const ALPHA_OPAQUE: u8 = 255;
424
425    pub const RED: ColorU = ColorU {
426        r: 255,
427        g: 0,
428        b: 0,
429        a: Self::ALPHA_OPAQUE,
430    };
431    pub const GREEN: ColorU = ColorU {
432        r: 0,
433        g: 255,
434        b: 0,
435        a: Self::ALPHA_OPAQUE,
436    };
437    pub const BLUE: ColorU = ColorU {
438        r: 0,
439        g: 0,
440        b: 255,
441        a: Self::ALPHA_OPAQUE,
442    };
443    pub const WHITE: ColorU = ColorU {
444        r: 255,
445        g: 255,
446        b: 255,
447        a: Self::ALPHA_OPAQUE,
448    };
449    pub const BLACK: ColorU = ColorU {
450        r: 0,
451        g: 0,
452        b: 0,
453        a: Self::ALPHA_OPAQUE,
454    };
455    pub const TRANSPARENT: ColorU = ColorU {
456        r: 0,
457        g: 0,
458        b: 0,
459        a: Self::ALPHA_TRANSPARENT,
460    };
461
462    pub const fn new_rgb(r: u8, g: u8, b: u8) -> Self {
463        Self { r, g, b, a: 255 }
464    }
465
466    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
467        Self {
468            r: libm::roundf(self.r as f32 + (other.r as f32 - self.r as f32) * t) as u8,
469            g: libm::roundf(self.g as f32 + (other.g as f32 - self.g as f32) * t) as u8,
470            b: libm::roundf(self.b as f32 + (other.b as f32 - self.b as f32) * t) as u8,
471            a: libm::roundf(self.a as f32 + (other.a as f32 - self.a as f32) * t) as u8,
472        }
473    }
474
475    pub const fn has_alpha(&self) -> bool {
476        self.a != Self::ALPHA_OPAQUE
477    }
478
479    pub fn to_hash(&self) -> String {
480        format!("#{:02x}{:02x}{:02x}{:02x}", self.r, self.g, self.b, self.a)
481    }
482
483    pub fn write_hash(&self, f: &mut fmt::Formatter) -> fmt::Result {
484        write!(
485            f,
486            "#{:02x}{:02x}{:02x}{:02x}",
487            self.r, self.g, self.b, self.a
488        )
489    }
490}
491
492/// f32-based color, range 0.0 to 1.0 (similar to webrenders ColorF)
493#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
494pub struct ColorF {
495    pub r: f32,
496    pub g: f32,
497    pub b: f32,
498    pub a: f32,
499}
500
501impl Default for ColorF {
502    fn default() -> Self {
503        ColorF::BLACK
504    }
505}
506
507impl fmt::Display for ColorF {
508    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
509        write!(
510            f,
511            "rgba({}, {}, {}, {})",
512            self.r * 255.0,
513            self.g * 255.0,
514            self.b * 255.0,
515            self.a
516        )
517    }
518}
519
520impl ColorF {
521    pub const ALPHA_TRANSPARENT: f32 = 0.0;
522    pub const ALPHA_OPAQUE: f32 = 1.0;
523
524    pub const WHITE: ColorF = ColorF {
525        r: 1.0,
526        g: 1.0,
527        b: 1.0,
528        a: Self::ALPHA_OPAQUE,
529    };
530    pub const BLACK: ColorF = ColorF {
531        r: 0.0,
532        g: 0.0,
533        b: 0.0,
534        a: Self::ALPHA_OPAQUE,
535    };
536    pub const TRANSPARENT: ColorF = ColorF {
537        r: 0.0,
538        g: 0.0,
539        b: 0.0,
540        a: Self::ALPHA_TRANSPARENT,
541    };
542}
543
544impl From<ColorU> for ColorF {
545    fn from(input: ColorU) -> ColorF {
546        ColorF {
547            r: (input.r as f32) / 255.0,
548            g: (input.g as f32) / 255.0,
549            b: (input.b as f32) / 255.0,
550            a: (input.a as f32) / 255.0,
551        }
552    }
553}
554
555impl From<ColorF> for ColorU {
556    fn from(input: ColorF) -> ColorU {
557        ColorU {
558            r: (input.r.min(1.0) * 255.0) as u8,
559            g: (input.g.min(1.0) * 255.0) as u8,
560            b: (input.b.min(1.0) * 255.0) as u8,
561            a: (input.a.min(1.0) * 255.0) as u8,
562        }
563    }
564}
565
566#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
567pub enum BorderDetails {
568    Normal(NormalBorder),
569    NinePatch(NinePatchBorder),
570}
571
572/// Represents a normal `border` property (no image border / nine-patch border)
573#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
574pub struct NormalBorder {
575    pub left: BorderSide,
576    pub right: BorderSide,
577    pub top: BorderSide,
578    pub bottom: BorderSide,
579    pub radius: Option<(
580        StyleBorderTopLeftRadius,
581        StyleBorderTopRightRadius,
582        StyleBorderBottomLeftRadius,
583        StyleBorderBottomRightRadius,
584    )>,
585}
586
587#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
588#[repr(C)]
589pub struct BorderSide {
590    pub color: ColorU,
591    pub style: BorderStyle,
592}
593
594/// What direction should a `box-shadow` be clipped in (inset or outset)
595#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
596#[repr(C)]
597pub enum BoxShadowClipMode {
598    Outset,
599    Inset,
600}
601
602impl fmt::Display for BoxShadowClipMode {
603    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
604        use self::BoxShadowClipMode::*;
605        match self {
606            Outset => write!(f, "outset"),
607            Inset => write!(f, "inset"),
608        }
609    }
610}
611
612/// Whether a `gradient` should be repeated or clamped to the edges.
613#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
614#[repr(C)]
615pub enum ExtendMode {
616    Clamp,
617    Repeat,
618}
619
620impl Default for ExtendMode {
621    fn default() -> Self {
622        ExtendMode::Clamp
623    }
624}
625
626/// Style of a `border`: solid, double, dash, ridge, etc.
627#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
628#[repr(C)]
629pub enum BorderStyle {
630    None,
631    Solid,
632    Double,
633    Dotted,
634    Dashed,
635    Hidden,
636    Groove,
637    Ridge,
638    Inset,
639    Outset,
640}
641
642impl fmt::Display for BorderStyle {
643    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
644        use self::BorderStyle::*;
645        match self {
646            None => write!(f, "none"),
647            Solid => write!(f, "solid"),
648            Double => write!(f, "double"),
649            Dotted => write!(f, "dotted"),
650            Dashed => write!(f, "dashed"),
651            Hidden => write!(f, "hidden"),
652            Groove => write!(f, "groove"),
653            Ridge => write!(f, "ridge"),
654            Inset => write!(f, "inset"),
655            Outset => write!(f, "outset"),
656        }
657    }
658}
659
660impl BorderStyle {
661    pub fn normalize_border(self) -> Option<BorderStyleNoNone> {
662        match self {
663            BorderStyle::None => None,
664            BorderStyle::Solid => Some(BorderStyleNoNone::Solid),
665            BorderStyle::Double => Some(BorderStyleNoNone::Double),
666            BorderStyle::Dotted => Some(BorderStyleNoNone::Dotted),
667            BorderStyle::Dashed => Some(BorderStyleNoNone::Dashed),
668            BorderStyle::Hidden => Some(BorderStyleNoNone::Hidden),
669            BorderStyle::Groove => Some(BorderStyleNoNone::Groove),
670            BorderStyle::Ridge => Some(BorderStyleNoNone::Ridge),
671            BorderStyle::Inset => Some(BorderStyleNoNone::Inset),
672            BorderStyle::Outset => Some(BorderStyleNoNone::Outset),
673        }
674    }
675}
676
677#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
678pub enum BorderStyleNoNone {
679    Solid,
680    Double,
681    Dotted,
682    Dashed,
683    Hidden,
684    Groove,
685    Ridge,
686    Inset,
687    Outset,
688}
689
690impl Default for BorderStyle {
691    fn default() -> Self {
692        BorderStyle::Solid
693    }
694}
695
696#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
697pub struct NinePatchBorder {
698    // not implemented or parse-able yet, so no fields!
699}
700
701macro_rules! derive_debug_zero {
702    ($struct:ident) => {
703        impl fmt::Debug for $struct {
704            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
705                write!(f, "{:?}", self.inner)
706            }
707        }
708    };
709}
710
711macro_rules! derive_display_zero {
712    ($struct:ident) => {
713        impl fmt::Display for $struct {
714            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
715                write!(f, "{}", self.inner)
716            }
717        }
718    };
719}
720
721/// Creates `pt`, `px` and `em` constructors for any struct that has a
722/// `PixelValue` as it's self.0 field.
723macro_rules! impl_pixel_value {
724    ($struct:ident) => {
725        derive_debug_zero!($struct);
726        derive_display_zero!($struct);
727
728        impl $struct {
729            #[inline]
730            pub const fn zero() -> Self {
731                Self {
732                    inner: PixelValue::zero(),
733                }
734            }
735
736            /// Same as `PixelValue::px()`, but only accepts whole numbers,
737            /// since using `f32` in const fn is not yet stabilized.
738            #[inline]
739            pub const fn const_px(value: isize) -> Self {
740                Self {
741                    inner: PixelValue::const_px(value),
742                }
743            }
744
745            /// Same as `PixelValue::em()`, but only accepts whole numbers,
746            /// since using `f32` in const fn is not yet stabilized.
747            #[inline]
748            pub const fn const_em(value: isize) -> Self {
749                Self {
750                    inner: PixelValue::const_em(value),
751                }
752            }
753
754            /// Same as `PixelValue::pt()`, but only accepts whole numbers,
755            /// since using `f32` in const fn is not yet stabilized.
756            #[inline]
757            pub const fn const_pt(value: isize) -> Self {
758                Self {
759                    inner: PixelValue::const_pt(value),
760                }
761            }
762
763            /// Same as `PixelValue::pt()`, but only accepts whole numbers,
764            /// since using `f32` in const fn is not yet stabilized.
765            #[inline]
766            pub const fn const_percent(value: isize) -> Self {
767                Self {
768                    inner: PixelValue::const_percent(value),
769                }
770            }
771
772            #[inline]
773            pub const fn const_from_metric(metric: SizeMetric, value: isize) -> Self {
774                Self {
775                    inner: PixelValue::const_from_metric(metric, value),
776                }
777            }
778
779            #[inline]
780            pub fn px(value: f32) -> Self {
781                Self {
782                    inner: PixelValue::px(value),
783                }
784            }
785
786            #[inline]
787            pub fn em(value: f32) -> Self {
788                Self {
789                    inner: PixelValue::em(value),
790                }
791            }
792
793            #[inline]
794            pub fn pt(value: f32) -> Self {
795                Self {
796                    inner: PixelValue::pt(value),
797                }
798            }
799
800            #[inline]
801            pub fn percent(value: f32) -> Self {
802                Self {
803                    inner: PixelValue::percent(value),
804                }
805            }
806
807            #[inline]
808            pub fn from_metric(metric: SizeMetric, value: f32) -> Self {
809                Self {
810                    inner: PixelValue::from_metric(metric, value),
811                }
812            }
813
814            #[inline]
815            pub fn interpolate(&self, other: &Self, t: f32) -> Self {
816                $struct {
817                    inner: self.inner.interpolate(&other.inner, t),
818                }
819            }
820        }
821    };
822}
823
824macro_rules! impl_percentage_value {
825    ($struct:ident) => {
826        impl ::core::fmt::Display for $struct {
827            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
828                write!(f, "{}%", self.inner.get())
829            }
830        }
831
832        impl ::core::fmt::Debug for $struct {
833            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
834                write!(f, "{}%", self.inner.get())
835            }
836        }
837
838        impl $struct {
839            /// Same as `PercentageValue::new()`, but only accepts whole numbers,
840            /// since using `f32` in const fn is not yet stabilized.
841            #[inline]
842            pub const fn const_new(value: isize) -> Self {
843                Self {
844                    inner: PercentageValue::const_new(value),
845                }
846            }
847
848            #[inline]
849            pub fn new(value: f32) -> Self {
850                Self {
851                    inner: PercentageValue::new(value),
852                }
853            }
854
855            #[inline]
856            pub fn interpolate(&self, other: &Self, t: f32) -> Self {
857                $struct {
858                    inner: self.inner.interpolate(&other.inner, t),
859                }
860            }
861        }
862    };
863}
864
865macro_rules! impl_float_value {
866    ($struct:ident) => {
867        impl $struct {
868            /// Same as `FloatValue::new()`, but only accepts whole numbers,
869            /// since using `f32` in const fn is not yet stabilized.
870            pub const fn const_new(value: isize) -> Self {
871                Self {
872                    inner: FloatValue::const_new(value),
873                }
874            }
875
876            pub fn new(value: f32) -> Self {
877                Self {
878                    inner: FloatValue::new(value),
879                }
880            }
881
882            pub fn get(&self) -> f32 {
883                self.inner.get()
884            }
885
886            #[inline]
887            pub fn interpolate(&self, other: &Self, t: f32) -> Self {
888                Self {
889                    inner: self.inner.interpolate(&other.inner, t),
890                }
891            }
892        }
893
894        impl From<f32> for $struct {
895            fn from(val: f32) -> Self {
896                Self {
897                    inner: FloatValue::from(val),
898                }
899            }
900        }
901
902        impl ::core::fmt::Display for $struct {
903            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
904                write!(f, "{}", self.inner.get())
905            }
906        }
907
908        impl ::core::fmt::Debug for $struct {
909            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
910                write!(f, "{}", self.inner.get())
911            }
912        }
913    };
914}
915
916#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
917pub enum CombinedCssPropertyType {
918    BorderRadius,
919    Overflow,
920    Margin,
921    Border,
922    BorderLeft,
923    BorderRight,
924    BorderTop,
925    BorderBottom,
926    Padding,
927    BoxShadow,
928    BackgroundColor, // BackgroundContent::Colo
929    BackgroundImage, // BackgroundContent::Colo
930}
931
932impl fmt::Display for CombinedCssPropertyType {
933    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
934        let key = COMBINED_CSS_PROPERTIES_KEY_MAP
935            .iter()
936            .find(|(v, _)| *v == *self)
937            .and_then(|(k, _)| Some(k))
938            .unwrap();
939        write!(f, "{}", key)
940    }
941}
942
943impl CombinedCssPropertyType {
944    /// Parses a CSS key, such as `width` from a string:
945    ///
946    /// # Example
947    ///
948    /// ```rust
949    /// # use azul_css::{CombinedCssPropertyType, get_css_key_map};
950    /// let map = get_css_key_map();
951    /// assert_eq!(
952    ///     Some(CombinedCssPropertyType::Border),
953    ///     CombinedCssPropertyType::from_str("border", &map)
954    /// );
955    /// ```
956    pub fn from_str(input: &str, map: &CssKeyMap) -> Option<Self> {
957        let input = input.trim();
958        map.shorthands.get(input).map(|x| *x)
959    }
960
961    /// Returns the original string that was used to construct this `CssPropertyType`.
962    pub fn to_str(&self, map: &CssKeyMap) -> &'static str {
963        map.shorthands
964            .iter()
965            .find(|(_, v)| *v == self)
966            .map(|(k, _)| k)
967            .unwrap()
968    }
969}
970
971#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
972pub struct CssKeyMap {
973    // Contains all keys that have no shorthand
974    pub non_shorthands: BTreeMap<&'static str, CssPropertyType>,
975    // Contains all keys that act as a shorthand for other types
976    pub shorthands: BTreeMap<&'static str, CombinedCssPropertyType>,
977}
978
979impl CssKeyMap {
980    pub fn get() -> Self {
981        get_css_key_map()
982    }
983}
984
985/// Returns a map useful for parsing the keys of CSS stylesheets
986pub fn get_css_key_map() -> CssKeyMap {
987    CssKeyMap {
988        non_shorthands: CSS_PROPERTY_KEY_MAP.iter().map(|(v, k)| (*k, *v)).collect(),
989        shorthands: COMBINED_CSS_PROPERTIES_KEY_MAP
990            .iter()
991            .map(|(v, k)| (*k, *v))
992            .collect(),
993    }
994}
995
996/// Represents a CSS key (for example `"border-radius"` => `BorderRadius`).
997/// You can also derive this key from a `CssProperty` by calling `CssProperty::get_type()`.
998#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
999#[repr(C)]
1000pub enum CssPropertyType {
1001    TextColor,
1002    FontSize,
1003    FontFamily,
1004    TextAlign,
1005    LetterSpacing,
1006    LineHeight,
1007    WordSpacing,
1008    TabWidth,
1009    Cursor,
1010    Display,
1011    Float,
1012    BoxSizing,
1013    Width,
1014    Height,
1015    MinWidth,
1016    MinHeight,
1017    MaxWidth,
1018    MaxHeight,
1019    Position,
1020    Top,
1021    Right,
1022    Left,
1023    Bottom,
1024    FlexWrap,
1025    FlexDirection,
1026    FlexGrow,
1027    FlexShrink,
1028    JustifyContent,
1029    AlignItems,
1030    AlignContent,
1031    BackgroundContent,
1032    BackgroundPosition,
1033    BackgroundSize,
1034    BackgroundRepeat,
1035    OverflowX,
1036    OverflowY,
1037    PaddingTop,
1038    PaddingLeft,
1039    PaddingRight,
1040    PaddingBottom,
1041    MarginTop,
1042    MarginLeft,
1043    MarginRight,
1044    MarginBottom,
1045    BorderTopLeftRadius,
1046    BorderTopRightRadius,
1047    BorderBottomLeftRadius,
1048    BorderBottomRightRadius,
1049    BorderTopColor,
1050    BorderRightColor,
1051    BorderLeftColor,
1052    BorderBottomColor,
1053    BorderTopStyle,
1054    BorderRightStyle,
1055    BorderLeftStyle,
1056    BorderBottomStyle,
1057    BorderTopWidth,
1058    BorderRightWidth,
1059    BorderLeftWidth,
1060    BorderBottomWidth,
1061    BoxShadowLeft,
1062    BoxShadowRight,
1063    BoxShadowTop,
1064    BoxShadowBottom,
1065    ScrollbarStyle,
1066    Opacity,
1067    Transform,
1068    TransformOrigin,
1069    PerspectiveOrigin,
1070    BackfaceVisibility,
1071    MixBlendMode,
1072    Filter,
1073    BackdropFilter,
1074    TextShadow,
1075}
1076
1077impl CssPropertyType {
1078    /// Parses a CSS key, such as `width` from a string:
1079    ///
1080    /// # Example
1081    ///
1082    /// ```rust
1083    /// # use azul_css::{CssPropertyType, get_css_key_map};
1084    /// let map = get_css_key_map();
1085    /// assert_eq!(
1086    ///     Some(CssPropertyType::Width),
1087    ///     CssPropertyType::from_str("width", &map)
1088    /// );
1089    /// assert_eq!(
1090    ///     Some(CssPropertyType::JustifyContent),
1091    ///     CssPropertyType::from_str("justify-content", &map)
1092    /// );
1093    /// assert_eq!(None, CssPropertyType::from_str("asdfasdfasdf", &map));
1094    /// ```
1095    pub fn from_str(input: &str, map: &CssKeyMap) -> Option<Self> {
1096        let input = input.trim();
1097        map.non_shorthands.get(input).and_then(|x| Some(*x))
1098    }
1099
1100    /// Returns the original string that was used to construct this `CssPropertyType`.
1101    pub fn to_str(&self) -> &'static str {
1102        match self {
1103            CssPropertyType::TextColor => "color",
1104            CssPropertyType::FontSize => "font-size",
1105            CssPropertyType::FontFamily => "font-family",
1106            CssPropertyType::TextAlign => "text-align",
1107            CssPropertyType::LetterSpacing => "letter-spacing",
1108            CssPropertyType::LineHeight => "line-height",
1109            CssPropertyType::WordSpacing => "word-spacing",
1110            CssPropertyType::TabWidth => "tab-width",
1111            CssPropertyType::Cursor => "cursor",
1112            CssPropertyType::Display => "display",
1113            CssPropertyType::Float => "float",
1114            CssPropertyType::BoxSizing => "box-sizing",
1115            CssPropertyType::Width => "width",
1116            CssPropertyType::Height => "height",
1117            CssPropertyType::MinWidth => "min-width",
1118            CssPropertyType::MinHeight => "min-height",
1119            CssPropertyType::MaxWidth => "max-width",
1120            CssPropertyType::MaxHeight => "max-height",
1121            CssPropertyType::Position => "position",
1122            CssPropertyType::Top => "top",
1123            CssPropertyType::Right => "right",
1124            CssPropertyType::Left => "left",
1125            CssPropertyType::Bottom => "bottom",
1126            CssPropertyType::FlexWrap => "flex-wrap",
1127            CssPropertyType::FlexDirection => "flex-direction",
1128            CssPropertyType::FlexGrow => "flex-grow",
1129            CssPropertyType::FlexShrink => "flex-shrink",
1130            CssPropertyType::JustifyContent => "justify-content",
1131            CssPropertyType::AlignItems => "align-items",
1132            CssPropertyType::AlignContent => "align-content",
1133            CssPropertyType::BackgroundContent => "background",
1134            CssPropertyType::BackgroundPosition => "background-position",
1135            CssPropertyType::BackgroundSize => "background-size",
1136            CssPropertyType::BackgroundRepeat => "background-repeat",
1137            CssPropertyType::OverflowX => "overflow-x",
1138            CssPropertyType::OverflowY => "overflow-y",
1139            CssPropertyType::PaddingTop => "padding-top",
1140            CssPropertyType::PaddingLeft => "padding-left",
1141            CssPropertyType::PaddingRight => "padding-right",
1142            CssPropertyType::PaddingBottom => "padding-bottom",
1143            CssPropertyType::MarginTop => "margin-top",
1144            CssPropertyType::MarginLeft => "margin-left",
1145            CssPropertyType::MarginRight => "margin-right",
1146            CssPropertyType::MarginBottom => "margin-bottom",
1147            CssPropertyType::BorderTopLeftRadius => "border-top-left-radius",
1148            CssPropertyType::BorderTopRightRadius => "border-top-right-radius",
1149            CssPropertyType::BorderBottomLeftRadius => "border-bottom-left-radius",
1150            CssPropertyType::BorderBottomRightRadius => "border-bottom-right-radius",
1151            CssPropertyType::BorderTopColor => "border-top-color",
1152            CssPropertyType::BorderRightColor => "border-right-color",
1153            CssPropertyType::BorderLeftColor => "border-left-color",
1154            CssPropertyType::BorderBottomColor => "border-bottom-color",
1155            CssPropertyType::BorderTopStyle => "border-top-style",
1156            CssPropertyType::BorderRightStyle => "border-right-style",
1157            CssPropertyType::BorderLeftStyle => "border-left-style",
1158            CssPropertyType::BorderBottomStyle => "border-bottom-style",
1159            CssPropertyType::BorderTopWidth => "border-top-width",
1160            CssPropertyType::BorderRightWidth => "border-right-width",
1161            CssPropertyType::BorderLeftWidth => "border-left-width",
1162            CssPropertyType::BorderBottomWidth => "border-bottom-width",
1163            CssPropertyType::BoxShadowLeft => "-azul-box-shadow-left",
1164            CssPropertyType::BoxShadowRight => "-azul-box-shadow-right",
1165            CssPropertyType::BoxShadowTop => "-azul-box-shadow-top",
1166            CssPropertyType::BoxShadowBottom => "-azul-box-shadow-bottom",
1167            CssPropertyType::ScrollbarStyle => "-azul-scrollbar-style",
1168            CssPropertyType::Opacity => "opacity",
1169            CssPropertyType::Transform => "transform",
1170            CssPropertyType::TransformOrigin => "transform-origin",
1171            CssPropertyType::PerspectiveOrigin => "perspective-origin",
1172            CssPropertyType::BackfaceVisibility => "backface-visibility",
1173            CssPropertyType::MixBlendMode => "mix-blend-mode",
1174            CssPropertyType::Filter => "filter",
1175            CssPropertyType::BackdropFilter => "backdrop-filter",
1176            CssPropertyType::TextShadow => "text-shadow",
1177        }
1178    }
1179
1180    /// Returns whether this property will be inherited during cascading
1181    pub fn is_inheritable(&self) -> bool {
1182        use self::CssPropertyType::*;
1183        match self {
1184            TextColor | FontFamily | FontSize | LineHeight | TextAlign => true,
1185            _ => false,
1186        }
1187    }
1188
1189    /// Returns whether this property can trigger a re-layout (important for incremental layout and
1190    /// caching layouted DOMs).
1191    pub fn can_trigger_relayout(&self) -> bool {
1192        use self::CssPropertyType::*;
1193
1194        // Since the border can be larger than the content,
1195        // in which case the content needs to be re-layouted, assume true for Border
1196
1197        // FontFamily, FontSize, LetterSpacing and LineHeight can affect
1198        // the text layout and therefore the screen layout
1199
1200        match self {
1201            TextColor
1202            | Cursor
1203            | BackgroundContent
1204            | BackgroundPosition
1205            | BackgroundSize
1206            | BackgroundRepeat
1207            | BorderTopLeftRadius
1208            | BorderTopRightRadius
1209            | BorderBottomLeftRadius
1210            | BorderBottomRightRadius
1211            | BorderTopColor
1212            | BorderRightColor
1213            | BorderLeftColor
1214            | BorderBottomColor
1215            | BorderTopStyle
1216            | BorderRightStyle
1217            | BorderLeftStyle
1218            | BorderBottomStyle
1219            | BoxShadowLeft
1220            | BoxShadowRight
1221            | BoxShadowTop
1222            | BoxShadowBottom
1223            | ScrollbarStyle
1224            | Opacity
1225            | Transform
1226            | TransformOrigin
1227            | PerspectiveOrigin
1228            | BackfaceVisibility
1229            | MixBlendMode
1230            | Filter
1231            | BackdropFilter
1232            | TextShadow => false,
1233            _ => true,
1234        }
1235    }
1236
1237    /// Returns whether the property is a GPU property (currently only opacity and transforms)
1238    pub fn is_gpu_only_property(&self) -> bool {
1239        match self {
1240            CssPropertyType::Opacity |
1241            CssPropertyType::Transform /* | CssPropertyType::Color */ => true,
1242            _ => false
1243        }
1244    }
1245}
1246
1247impl fmt::Debug for CssPropertyType {
1248    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1249        write!(f, "{}", self.to_str())
1250    }
1251}
1252
1253impl fmt::Display for CssPropertyType {
1254    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1255        write!(f, "{}", self.to_str())
1256    }
1257}
1258
1259/// Represents one parsed CSS key-value pair, such as `"width: 20px"` =>
1260/// `CssProperty::Width(LayoutWidth::px(20.0))`
1261#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1262#[repr(C, u8)]
1263pub enum CssProperty {
1264    TextColor(StyleTextColorValue),
1265    FontSize(StyleFontSizeValue),
1266    FontFamily(StyleFontFamilyVecValue),
1267    TextAlign(StyleTextAlignValue),
1268    LetterSpacing(StyleLetterSpacingValue),
1269    LineHeight(StyleLineHeightValue),
1270    WordSpacing(StyleWordSpacingValue),
1271    TabWidth(StyleTabWidthValue),
1272    Cursor(StyleCursorValue),
1273    Display(LayoutDisplayValue),
1274    Float(LayoutFloatValue),
1275    BoxSizing(LayoutBoxSizingValue),
1276    Width(LayoutWidthValue),
1277    Height(LayoutHeightValue),
1278    MinWidth(LayoutMinWidthValue),
1279    MinHeight(LayoutMinHeightValue),
1280    MaxWidth(LayoutMaxWidthValue),
1281    MaxHeight(LayoutMaxHeightValue),
1282    Position(LayoutPositionValue),
1283    Top(LayoutTopValue),
1284    Right(LayoutRightValue),
1285    Left(LayoutLeftValue),
1286    Bottom(LayoutBottomValue),
1287    FlexWrap(LayoutFlexWrapValue),
1288    FlexDirection(LayoutFlexDirectionValue),
1289    FlexGrow(LayoutFlexGrowValue),
1290    FlexShrink(LayoutFlexShrinkValue),
1291    JustifyContent(LayoutJustifyContentValue),
1292    AlignItems(LayoutAlignItemsValue),
1293    AlignContent(LayoutAlignContentValue),
1294    BackgroundContent(StyleBackgroundContentVecValue),
1295    BackgroundPosition(StyleBackgroundPositionVecValue),
1296    BackgroundSize(StyleBackgroundSizeVecValue),
1297    BackgroundRepeat(StyleBackgroundRepeatVecValue),
1298    OverflowX(LayoutOverflowValue),
1299    OverflowY(LayoutOverflowValue),
1300    PaddingTop(LayoutPaddingTopValue),
1301    PaddingLeft(LayoutPaddingLeftValue),
1302    PaddingRight(LayoutPaddingRightValue),
1303    PaddingBottom(LayoutPaddingBottomValue),
1304    MarginTop(LayoutMarginTopValue),
1305    MarginLeft(LayoutMarginLeftValue),
1306    MarginRight(LayoutMarginRightValue),
1307    MarginBottom(LayoutMarginBottomValue),
1308    BorderTopLeftRadius(StyleBorderTopLeftRadiusValue),
1309    BorderTopRightRadius(StyleBorderTopRightRadiusValue),
1310    BorderBottomLeftRadius(StyleBorderBottomLeftRadiusValue),
1311    BorderBottomRightRadius(StyleBorderBottomRightRadiusValue),
1312    BorderTopColor(StyleBorderTopColorValue),
1313    BorderRightColor(StyleBorderRightColorValue),
1314    BorderLeftColor(StyleBorderLeftColorValue),
1315    BorderBottomColor(StyleBorderBottomColorValue),
1316    BorderTopStyle(StyleBorderTopStyleValue),
1317    BorderRightStyle(StyleBorderRightStyleValue),
1318    BorderLeftStyle(StyleBorderLeftStyleValue),
1319    BorderBottomStyle(StyleBorderBottomStyleValue),
1320    BorderTopWidth(LayoutBorderTopWidthValue),
1321    BorderRightWidth(LayoutBorderRightWidthValue),
1322    BorderLeftWidth(LayoutBorderLeftWidthValue),
1323    BorderBottomWidth(LayoutBorderBottomWidthValue),
1324    BoxShadowLeft(StyleBoxShadowValue),
1325    BoxShadowRight(StyleBoxShadowValue),
1326    BoxShadowTop(StyleBoxShadowValue),
1327    BoxShadowBottom(StyleBoxShadowValue),
1328    ScrollbarStyle(ScrollbarStyleValue),
1329    Opacity(StyleOpacityValue),
1330    Transform(StyleTransformVecValue),
1331    TransformOrigin(StyleTransformOriginValue),
1332    PerspectiveOrigin(StylePerspectiveOriginValue),
1333    BackfaceVisibility(StyleBackfaceVisibilityValue),
1334    MixBlendMode(StyleMixBlendModeValue),
1335    Filter(StyleFilterVecValue),
1336    BackdropFilter(StyleFilterVecValue),
1337    TextShadow(StyleBoxShadowValue),
1338}
1339
1340impl_option!(
1341    CssProperty,
1342    OptionCssProperty,
1343    copy = false,
1344    [Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord]
1345);
1346
1347macro_rules! css_property_from_type {
1348    ($prop_type:expr, $content_type:ident) => {{
1349        match $prop_type {
1350            CssPropertyType::TextColor => {
1351                CssProperty::TextColor(StyleTextColorValue::$content_type)
1352            }
1353            CssPropertyType::FontSize => CssProperty::FontSize(StyleFontSizeValue::$content_type),
1354            CssPropertyType::FontFamily => {
1355                CssProperty::FontFamily(StyleFontFamilyVecValue::$content_type)
1356            }
1357            CssPropertyType::TextAlign => {
1358                CssProperty::TextAlign(StyleTextAlignValue::$content_type)
1359            }
1360            CssPropertyType::LetterSpacing => {
1361                CssProperty::LetterSpacing(StyleLetterSpacingValue::$content_type)
1362            }
1363            CssPropertyType::LineHeight => {
1364                CssProperty::LineHeight(StyleLineHeightValue::$content_type)
1365            }
1366            CssPropertyType::WordSpacing => {
1367                CssProperty::WordSpacing(StyleWordSpacingValue::$content_type)
1368            }
1369            CssPropertyType::TabWidth => CssProperty::TabWidth(StyleTabWidthValue::$content_type),
1370            CssPropertyType::Cursor => CssProperty::Cursor(StyleCursorValue::$content_type),
1371            CssPropertyType::Display => CssProperty::Display(LayoutDisplayValue::$content_type),
1372            CssPropertyType::Float => CssProperty::Float(LayoutFloatValue::$content_type),
1373            CssPropertyType::BoxSizing => {
1374                CssProperty::BoxSizing(LayoutBoxSizingValue::$content_type)
1375            }
1376            CssPropertyType::Width => CssProperty::Width(LayoutWidthValue::$content_type),
1377            CssPropertyType::Height => CssProperty::Height(LayoutHeightValue::$content_type),
1378            CssPropertyType::MinWidth => CssProperty::MinWidth(LayoutMinWidthValue::$content_type),
1379            CssPropertyType::MinHeight => {
1380                CssProperty::MinHeight(LayoutMinHeightValue::$content_type)
1381            }
1382            CssPropertyType::MaxWidth => CssProperty::MaxWidth(LayoutMaxWidthValue::$content_type),
1383            CssPropertyType::MaxHeight => {
1384                CssProperty::MaxHeight(LayoutMaxHeightValue::$content_type)
1385            }
1386            CssPropertyType::Position => CssProperty::Position(LayoutPositionValue::$content_type),
1387            CssPropertyType::Top => CssProperty::Top(LayoutTopValue::$content_type),
1388            CssPropertyType::Right => CssProperty::Right(LayoutRightValue::$content_type),
1389            CssPropertyType::Left => CssProperty::Left(LayoutLeftValue::$content_type),
1390            CssPropertyType::Bottom => CssProperty::Bottom(LayoutBottomValue::$content_type),
1391            CssPropertyType::FlexWrap => CssProperty::FlexWrap(LayoutFlexWrapValue::$content_type),
1392            CssPropertyType::FlexDirection => {
1393                CssProperty::FlexDirection(LayoutFlexDirectionValue::$content_type)
1394            }
1395            CssPropertyType::FlexGrow => CssProperty::FlexGrow(LayoutFlexGrowValue::$content_type),
1396            CssPropertyType::FlexShrink => {
1397                CssProperty::FlexShrink(LayoutFlexShrinkValue::$content_type)
1398            }
1399            CssPropertyType::JustifyContent => {
1400                CssProperty::JustifyContent(LayoutJustifyContentValue::$content_type)
1401            }
1402            CssPropertyType::AlignItems => {
1403                CssProperty::AlignItems(LayoutAlignItemsValue::$content_type)
1404            }
1405            CssPropertyType::AlignContent => {
1406                CssProperty::AlignContent(LayoutAlignContentValue::$content_type)
1407            }
1408            CssPropertyType::BackgroundContent => {
1409                CssProperty::BackgroundContent(StyleBackgroundContentVecValue::$content_type)
1410            }
1411            CssPropertyType::BackgroundPosition => {
1412                CssProperty::BackgroundPosition(StyleBackgroundPositionVecValue::$content_type)
1413            }
1414            CssPropertyType::BackgroundSize => {
1415                CssProperty::BackgroundSize(StyleBackgroundSizeVecValue::$content_type)
1416            }
1417            CssPropertyType::BackgroundRepeat => {
1418                CssProperty::BackgroundRepeat(StyleBackgroundRepeatVecValue::$content_type)
1419            }
1420            CssPropertyType::OverflowX => {
1421                CssProperty::OverflowX(LayoutOverflowValue::$content_type)
1422            }
1423            CssPropertyType::OverflowY => {
1424                CssProperty::OverflowY(LayoutOverflowValue::$content_type)
1425            }
1426            CssPropertyType::PaddingTop => {
1427                CssProperty::PaddingTop(LayoutPaddingTopValue::$content_type)
1428            }
1429            CssPropertyType::PaddingLeft => {
1430                CssProperty::PaddingLeft(LayoutPaddingLeftValue::$content_type)
1431            }
1432            CssPropertyType::PaddingRight => {
1433                CssProperty::PaddingRight(LayoutPaddingRightValue::$content_type)
1434            }
1435            CssPropertyType::PaddingBottom => {
1436                CssProperty::PaddingBottom(LayoutPaddingBottomValue::$content_type)
1437            }
1438            CssPropertyType::MarginTop => {
1439                CssProperty::MarginTop(LayoutMarginTopValue::$content_type)
1440            }
1441            CssPropertyType::MarginLeft => {
1442                CssProperty::MarginLeft(LayoutMarginLeftValue::$content_type)
1443            }
1444            CssPropertyType::MarginRight => {
1445                CssProperty::MarginRight(LayoutMarginRightValue::$content_type)
1446            }
1447            CssPropertyType::MarginBottom => {
1448                CssProperty::MarginBottom(LayoutMarginBottomValue::$content_type)
1449            }
1450            CssPropertyType::BorderTopLeftRadius => {
1451                CssProperty::BorderTopLeftRadius(StyleBorderTopLeftRadiusValue::$content_type)
1452            }
1453            CssPropertyType::BorderTopRightRadius => {
1454                CssProperty::BorderTopRightRadius(StyleBorderTopRightRadiusValue::$content_type)
1455            }
1456            CssPropertyType::BorderBottomLeftRadius => {
1457                CssProperty::BorderBottomLeftRadius(StyleBorderBottomLeftRadiusValue::$content_type)
1458            }
1459            CssPropertyType::BorderBottomRightRadius => CssProperty::BorderBottomRightRadius(
1460                StyleBorderBottomRightRadiusValue::$content_type,
1461            ),
1462            CssPropertyType::BorderTopColor => {
1463                CssProperty::BorderTopColor(StyleBorderTopColorValue::$content_type)
1464            }
1465            CssPropertyType::BorderRightColor => {
1466                CssProperty::BorderRightColor(StyleBorderRightColorValue::$content_type)
1467            }
1468            CssPropertyType::BorderLeftColor => {
1469                CssProperty::BorderLeftColor(StyleBorderLeftColorValue::$content_type)
1470            }
1471            CssPropertyType::BorderBottomColor => {
1472                CssProperty::BorderBottomColor(StyleBorderBottomColorValue::$content_type)
1473            }
1474            CssPropertyType::BorderTopStyle => {
1475                CssProperty::BorderTopStyle(StyleBorderTopStyleValue::$content_type)
1476            }
1477            CssPropertyType::BorderRightStyle => {
1478                CssProperty::BorderRightStyle(StyleBorderRightStyleValue::$content_type)
1479            }
1480            CssPropertyType::BorderLeftStyle => {
1481                CssProperty::BorderLeftStyle(StyleBorderLeftStyleValue::$content_type)
1482            }
1483            CssPropertyType::BorderBottomStyle => {
1484                CssProperty::BorderBottomStyle(StyleBorderBottomStyleValue::$content_type)
1485            }
1486            CssPropertyType::BorderTopWidth => {
1487                CssProperty::BorderTopWidth(LayoutBorderTopWidthValue::$content_type)
1488            }
1489            CssPropertyType::BorderRightWidth => {
1490                CssProperty::BorderRightWidth(LayoutBorderRightWidthValue::$content_type)
1491            }
1492            CssPropertyType::BorderLeftWidth => {
1493                CssProperty::BorderLeftWidth(LayoutBorderLeftWidthValue::$content_type)
1494            }
1495            CssPropertyType::BorderBottomWidth => {
1496                CssProperty::BorderBottomWidth(LayoutBorderBottomWidthValue::$content_type)
1497            }
1498            CssPropertyType::BoxShadowLeft => {
1499                CssProperty::BoxShadowLeft(StyleBoxShadowValue::$content_type)
1500            }
1501            CssPropertyType::BoxShadowRight => {
1502                CssProperty::BoxShadowRight(StyleBoxShadowValue::$content_type)
1503            }
1504            CssPropertyType::BoxShadowTop => {
1505                CssProperty::BoxShadowTop(StyleBoxShadowValue::$content_type)
1506            }
1507            CssPropertyType::BoxShadowBottom => {
1508                CssProperty::BoxShadowBottom(StyleBoxShadowValue::$content_type)
1509            }
1510            CssPropertyType::ScrollbarStyle => {
1511                CssProperty::ScrollbarStyle(ScrollbarStyleValue::$content_type)
1512            }
1513            CssPropertyType::Opacity => CssProperty::Opacity(StyleOpacityValue::$content_type),
1514            CssPropertyType::Transform => {
1515                CssProperty::Transform(StyleTransformVecValue::$content_type)
1516            }
1517            CssPropertyType::PerspectiveOrigin => {
1518                CssProperty::PerspectiveOrigin(StylePerspectiveOriginValue::$content_type)
1519            }
1520            CssPropertyType::TransformOrigin => {
1521                CssProperty::TransformOrigin(StyleTransformOriginValue::$content_type)
1522            }
1523            CssPropertyType::BackfaceVisibility => {
1524                CssProperty::BackfaceVisibility(StyleBackfaceVisibilityValue::$content_type)
1525            }
1526            CssPropertyType::MixBlendMode => {
1527                CssProperty::MixBlendMode(StyleMixBlendModeValue::$content_type)
1528            }
1529            CssPropertyType::Filter => CssProperty::Filter(StyleFilterVecValue::$content_type),
1530            CssPropertyType::BackdropFilter => {
1531                CssProperty::BackdropFilter(StyleFilterVecValue::$content_type)
1532            }
1533            CssPropertyType::TextShadow => {
1534                CssProperty::TextShadow(StyleBoxShadowValue::$content_type)
1535            }
1536        }
1537    }};
1538}
1539
1540impl CssProperty {
1541    pub fn is_initial(&self) -> bool {
1542        use self::CssProperty::*;
1543        match self {
1544            TextColor(c) => c.is_initial(),
1545            FontSize(c) => c.is_initial(),
1546            FontFamily(c) => c.is_initial(),
1547            TextAlign(c) => c.is_initial(),
1548            LetterSpacing(c) => c.is_initial(),
1549            LineHeight(c) => c.is_initial(),
1550            WordSpacing(c) => c.is_initial(),
1551            TabWidth(c) => c.is_initial(),
1552            Cursor(c) => c.is_initial(),
1553            Display(c) => c.is_initial(),
1554            Float(c) => c.is_initial(),
1555            BoxSizing(c) => c.is_initial(),
1556            Width(c) => c.is_initial(),
1557            Height(c) => c.is_initial(),
1558            MinWidth(c) => c.is_initial(),
1559            MinHeight(c) => c.is_initial(),
1560            MaxWidth(c) => c.is_initial(),
1561            MaxHeight(c) => c.is_initial(),
1562            Position(c) => c.is_initial(),
1563            Top(c) => c.is_initial(),
1564            Right(c) => c.is_initial(),
1565            Left(c) => c.is_initial(),
1566            Bottom(c) => c.is_initial(),
1567            FlexWrap(c) => c.is_initial(),
1568            FlexDirection(c) => c.is_initial(),
1569            FlexGrow(c) => c.is_initial(),
1570            FlexShrink(c) => c.is_initial(),
1571            JustifyContent(c) => c.is_initial(),
1572            AlignItems(c) => c.is_initial(),
1573            AlignContent(c) => c.is_initial(),
1574            BackgroundContent(c) => c.is_initial(),
1575            BackgroundPosition(c) => c.is_initial(),
1576            BackgroundSize(c) => c.is_initial(),
1577            BackgroundRepeat(c) => c.is_initial(),
1578            OverflowX(c) => c.is_initial(),
1579            OverflowY(c) => c.is_initial(),
1580            PaddingTop(c) => c.is_initial(),
1581            PaddingLeft(c) => c.is_initial(),
1582            PaddingRight(c) => c.is_initial(),
1583            PaddingBottom(c) => c.is_initial(),
1584            MarginTop(c) => c.is_initial(),
1585            MarginLeft(c) => c.is_initial(),
1586            MarginRight(c) => c.is_initial(),
1587            MarginBottom(c) => c.is_initial(),
1588            BorderTopLeftRadius(c) => c.is_initial(),
1589            BorderTopRightRadius(c) => c.is_initial(),
1590            BorderBottomLeftRadius(c) => c.is_initial(),
1591            BorderBottomRightRadius(c) => c.is_initial(),
1592            BorderTopColor(c) => c.is_initial(),
1593            BorderRightColor(c) => c.is_initial(),
1594            BorderLeftColor(c) => c.is_initial(),
1595            BorderBottomColor(c) => c.is_initial(),
1596            BorderTopStyle(c) => c.is_initial(),
1597            BorderRightStyle(c) => c.is_initial(),
1598            BorderLeftStyle(c) => c.is_initial(),
1599            BorderBottomStyle(c) => c.is_initial(),
1600            BorderTopWidth(c) => c.is_initial(),
1601            BorderRightWidth(c) => c.is_initial(),
1602            BorderLeftWidth(c) => c.is_initial(),
1603            BorderBottomWidth(c) => c.is_initial(),
1604            BoxShadowLeft(c) => c.is_initial(),
1605            BoxShadowRight(c) => c.is_initial(),
1606            BoxShadowTop(c) => c.is_initial(),
1607            BoxShadowBottom(c) => c.is_initial(),
1608            ScrollbarStyle(c) => c.is_initial(),
1609            Opacity(c) => c.is_initial(),
1610            Transform(c) => c.is_initial(),
1611            TransformOrigin(c) => c.is_initial(),
1612            PerspectiveOrigin(c) => c.is_initial(),
1613            BackfaceVisibility(c) => c.is_initial(),
1614            MixBlendMode(c) => c.is_initial(),
1615            Filter(c) => c.is_initial(),
1616            BackdropFilter(c) => c.is_initial(),
1617            TextShadow(c) => c.is_initial(),
1618        }
1619    }
1620
1621    pub const fn const_none(prop_type: CssPropertyType) -> Self {
1622        css_property_from_type!(prop_type, None)
1623    }
1624    pub const fn const_auto(prop_type: CssPropertyType) -> Self {
1625        css_property_from_type!(prop_type, Auto)
1626    }
1627    pub const fn const_initial(prop_type: CssPropertyType) -> Self {
1628        css_property_from_type!(prop_type, Initial)
1629    }
1630    pub const fn const_inherit(prop_type: CssPropertyType) -> Self {
1631        css_property_from_type!(prop_type, Inherit)
1632    }
1633
1634    pub const fn const_text_color(input: StyleTextColor) -> Self {
1635        CssProperty::TextColor(StyleTextColorValue::Exact(input))
1636    }
1637    pub const fn const_font_size(input: StyleFontSize) -> Self {
1638        CssProperty::FontSize(StyleFontSizeValue::Exact(input))
1639    }
1640    pub const fn const_font_family(input: StyleFontFamilyVec) -> Self {
1641        CssProperty::FontFamily(StyleFontFamilyVecValue::Exact(input))
1642    }
1643    pub const fn const_text_align(input: StyleTextAlign) -> Self {
1644        CssProperty::TextAlign(StyleTextAlignValue::Exact(input))
1645    }
1646    pub const fn const_letter_spacing(input: StyleLetterSpacing) -> Self {
1647        CssProperty::LetterSpacing(StyleLetterSpacingValue::Exact(input))
1648    }
1649    pub const fn const_line_height(input: StyleLineHeight) -> Self {
1650        CssProperty::LineHeight(StyleLineHeightValue::Exact(input))
1651    }
1652    pub const fn const_word_spacing(input: StyleWordSpacing) -> Self {
1653        CssProperty::WordSpacing(StyleWordSpacingValue::Exact(input))
1654    }
1655    pub const fn const_tab_width(input: StyleTabWidth) -> Self {
1656        CssProperty::TabWidth(StyleTabWidthValue::Exact(input))
1657    }
1658    pub const fn const_cursor(input: StyleCursor) -> Self {
1659        CssProperty::Cursor(StyleCursorValue::Exact(input))
1660    }
1661    pub const fn const_display(input: LayoutDisplay) -> Self {
1662        CssProperty::Display(LayoutDisplayValue::Exact(input))
1663    }
1664    pub const fn const_float(input: LayoutFloat) -> Self {
1665        CssProperty::Float(LayoutFloatValue::Exact(input))
1666    }
1667    pub const fn const_box_sizing(input: LayoutBoxSizing) -> Self {
1668        CssProperty::BoxSizing(LayoutBoxSizingValue::Exact(input))
1669    }
1670    pub const fn const_width(input: LayoutWidth) -> Self {
1671        CssProperty::Width(LayoutWidthValue::Exact(input))
1672    }
1673    pub const fn const_height(input: LayoutHeight) -> Self {
1674        CssProperty::Height(LayoutHeightValue::Exact(input))
1675    }
1676    pub const fn const_min_width(input: LayoutMinWidth) -> Self {
1677        CssProperty::MinWidth(LayoutMinWidthValue::Exact(input))
1678    }
1679    pub const fn const_min_height(input: LayoutMinHeight) -> Self {
1680        CssProperty::MinHeight(LayoutMinHeightValue::Exact(input))
1681    }
1682    pub const fn const_max_width(input: LayoutMaxWidth) -> Self {
1683        CssProperty::MaxWidth(LayoutMaxWidthValue::Exact(input))
1684    }
1685    pub const fn const_max_height(input: LayoutMaxHeight) -> Self {
1686        CssProperty::MaxHeight(LayoutMaxHeightValue::Exact(input))
1687    }
1688    pub const fn const_position(input: LayoutPosition) -> Self {
1689        CssProperty::Position(LayoutPositionValue::Exact(input))
1690    }
1691    pub const fn const_top(input: LayoutTop) -> Self {
1692        CssProperty::Top(LayoutTopValue::Exact(input))
1693    }
1694    pub const fn const_right(input: LayoutRight) -> Self {
1695        CssProperty::Right(LayoutRightValue::Exact(input))
1696    }
1697    pub const fn const_left(input: LayoutLeft) -> Self {
1698        CssProperty::Left(LayoutLeftValue::Exact(input))
1699    }
1700    pub const fn const_bottom(input: LayoutBottom) -> Self {
1701        CssProperty::Bottom(LayoutBottomValue::Exact(input))
1702    }
1703    pub const fn const_flex_wrap(input: LayoutFlexWrap) -> Self {
1704        CssProperty::FlexWrap(LayoutFlexWrapValue::Exact(input))
1705    }
1706    pub const fn const_flex_direction(input: LayoutFlexDirection) -> Self {
1707        CssProperty::FlexDirection(LayoutFlexDirectionValue::Exact(input))
1708    }
1709    pub const fn const_flex_grow(input: LayoutFlexGrow) -> Self {
1710        CssProperty::FlexGrow(LayoutFlexGrowValue::Exact(input))
1711    }
1712    pub const fn const_flex_shrink(input: LayoutFlexShrink) -> Self {
1713        CssProperty::FlexShrink(LayoutFlexShrinkValue::Exact(input))
1714    }
1715    pub const fn const_justify_content(input: LayoutJustifyContent) -> Self {
1716        CssProperty::JustifyContent(LayoutJustifyContentValue::Exact(input))
1717    }
1718    pub const fn const_align_items(input: LayoutAlignItems) -> Self {
1719        CssProperty::AlignItems(LayoutAlignItemsValue::Exact(input))
1720    }
1721    pub const fn const_align_content(input: LayoutAlignContent) -> Self {
1722        CssProperty::AlignContent(LayoutAlignContentValue::Exact(input))
1723    }
1724    pub const fn const_background_content(input: StyleBackgroundContentVec) -> Self {
1725        CssProperty::BackgroundContent(StyleBackgroundContentVecValue::Exact(input))
1726    }
1727    pub const fn const_background_position(input: StyleBackgroundPositionVec) -> Self {
1728        CssProperty::BackgroundPosition(StyleBackgroundPositionVecValue::Exact(input))
1729    }
1730    pub const fn const_background_size(input: StyleBackgroundSizeVec) -> Self {
1731        CssProperty::BackgroundSize(StyleBackgroundSizeVecValue::Exact(input))
1732    }
1733    pub const fn const_background_repeat(input: StyleBackgroundRepeatVec) -> Self {
1734        CssProperty::BackgroundRepeat(StyleBackgroundRepeatVecValue::Exact(input))
1735    }
1736    pub const fn const_overflow_x(input: LayoutOverflow) -> Self {
1737        CssProperty::OverflowX(LayoutOverflowValue::Exact(input))
1738    }
1739    pub const fn const_overflow_y(input: LayoutOverflow) -> Self {
1740        CssProperty::OverflowY(LayoutOverflowValue::Exact(input))
1741    }
1742    pub const fn const_padding_top(input: LayoutPaddingTop) -> Self {
1743        CssProperty::PaddingTop(LayoutPaddingTopValue::Exact(input))
1744    }
1745    pub const fn const_padding_left(input: LayoutPaddingLeft) -> Self {
1746        CssProperty::PaddingLeft(LayoutPaddingLeftValue::Exact(input))
1747    }
1748    pub const fn const_padding_right(input: LayoutPaddingRight) -> Self {
1749        CssProperty::PaddingRight(LayoutPaddingRightValue::Exact(input))
1750    }
1751    pub const fn const_padding_bottom(input: LayoutPaddingBottom) -> Self {
1752        CssProperty::PaddingBottom(LayoutPaddingBottomValue::Exact(input))
1753    }
1754    pub const fn const_margin_top(input: LayoutMarginTop) -> Self {
1755        CssProperty::MarginTop(LayoutMarginTopValue::Exact(input))
1756    }
1757    pub const fn const_margin_left(input: LayoutMarginLeft) -> Self {
1758        CssProperty::MarginLeft(LayoutMarginLeftValue::Exact(input))
1759    }
1760    pub const fn const_margin_right(input: LayoutMarginRight) -> Self {
1761        CssProperty::MarginRight(LayoutMarginRightValue::Exact(input))
1762    }
1763    pub const fn const_margin_bottom(input: LayoutMarginBottom) -> Self {
1764        CssProperty::MarginBottom(LayoutMarginBottomValue::Exact(input))
1765    }
1766    pub const fn const_border_top_left_radius(input: StyleBorderTopLeftRadius) -> Self {
1767        CssProperty::BorderTopLeftRadius(StyleBorderTopLeftRadiusValue::Exact(input))
1768    }
1769    pub const fn const_border_top_right_radius(input: StyleBorderTopRightRadius) -> Self {
1770        CssProperty::BorderTopRightRadius(StyleBorderTopRightRadiusValue::Exact(input))
1771    }
1772    pub const fn const_border_bottom_left_radius(input: StyleBorderBottomLeftRadius) -> Self {
1773        CssProperty::BorderBottomLeftRadius(StyleBorderBottomLeftRadiusValue::Exact(input))
1774    }
1775    pub const fn const_border_bottom_right_radius(input: StyleBorderBottomRightRadius) -> Self {
1776        CssProperty::BorderBottomRightRadius(StyleBorderBottomRightRadiusValue::Exact(input))
1777    }
1778    pub const fn const_border_top_color(input: StyleBorderTopColor) -> Self {
1779        CssProperty::BorderTopColor(StyleBorderTopColorValue::Exact(input))
1780    }
1781    pub const fn const_border_right_color(input: StyleBorderRightColor) -> Self {
1782        CssProperty::BorderRightColor(StyleBorderRightColorValue::Exact(input))
1783    }
1784    pub const fn const_border_left_color(input: StyleBorderLeftColor) -> Self {
1785        CssProperty::BorderLeftColor(StyleBorderLeftColorValue::Exact(input))
1786    }
1787    pub const fn const_border_bottom_color(input: StyleBorderBottomColor) -> Self {
1788        CssProperty::BorderBottomColor(StyleBorderBottomColorValue::Exact(input))
1789    }
1790    pub const fn const_border_top_style(input: StyleBorderTopStyle) -> Self {
1791        CssProperty::BorderTopStyle(StyleBorderTopStyleValue::Exact(input))
1792    }
1793    pub const fn const_border_right_style(input: StyleBorderRightStyle) -> Self {
1794        CssProperty::BorderRightStyle(StyleBorderRightStyleValue::Exact(input))
1795    }
1796    pub const fn const_border_left_style(input: StyleBorderLeftStyle) -> Self {
1797        CssProperty::BorderLeftStyle(StyleBorderLeftStyleValue::Exact(input))
1798    }
1799    pub const fn const_border_bottom_style(input: StyleBorderBottomStyle) -> Self {
1800        CssProperty::BorderBottomStyle(StyleBorderBottomStyleValue::Exact(input))
1801    }
1802    pub const fn const_border_top_width(input: LayoutBorderTopWidth) -> Self {
1803        CssProperty::BorderTopWidth(LayoutBorderTopWidthValue::Exact(input))
1804    }
1805    pub const fn const_border_right_width(input: LayoutBorderRightWidth) -> Self {
1806        CssProperty::BorderRightWidth(LayoutBorderRightWidthValue::Exact(input))
1807    }
1808    pub const fn const_border_left_width(input: LayoutBorderLeftWidth) -> Self {
1809        CssProperty::BorderLeftWidth(LayoutBorderLeftWidthValue::Exact(input))
1810    }
1811    pub const fn const_border_bottom_width(input: LayoutBorderBottomWidth) -> Self {
1812        CssProperty::BorderBottomWidth(LayoutBorderBottomWidthValue::Exact(input))
1813    }
1814    pub const fn const_box_shadow_left(input: StyleBoxShadow) -> Self {
1815        CssProperty::BoxShadowLeft(StyleBoxShadowValue::Exact(input))
1816    }
1817    pub const fn const_box_shadow_right(input: StyleBoxShadow) -> Self {
1818        CssProperty::BoxShadowRight(StyleBoxShadowValue::Exact(input))
1819    }
1820    pub const fn const_box_shadow_top(input: StyleBoxShadow) -> Self {
1821        CssProperty::BoxShadowTop(StyleBoxShadowValue::Exact(input))
1822    }
1823    pub const fn const_box_shadow_bottom(input: StyleBoxShadow) -> Self {
1824        CssProperty::BoxShadowBottom(StyleBoxShadowValue::Exact(input))
1825    }
1826    pub const fn const_opacity(input: StyleOpacity) -> Self {
1827        CssProperty::Opacity(StyleOpacityValue::Exact(input))
1828    }
1829    pub const fn const_transform(input: StyleTransformVec) -> Self {
1830        CssProperty::Transform(StyleTransformVecValue::Exact(input))
1831    }
1832    pub const fn const_transform_origin(input: StyleTransformOrigin) -> Self {
1833        CssProperty::TransformOrigin(StyleTransformOriginValue::Exact(input))
1834    }
1835    pub const fn const_perspective_origin(input: StylePerspectiveOrigin) -> Self {
1836        CssProperty::PerspectiveOrigin(StylePerspectiveOriginValue::Exact(input))
1837    }
1838    pub const fn const_backface_visiblity(input: StyleBackfaceVisibility) -> Self {
1839        CssProperty::BackfaceVisibility(StyleBackfaceVisibilityValue::Exact(input))
1840    }
1841}
1842#[derive(Debug, Copy, Clone, PartialEq)]
1843#[repr(C, u8)]
1844pub enum AnimationInterpolationFunction {
1845    Ease,
1846    Linear,
1847    EaseIn,
1848    EaseOut,
1849    EaseInOut,
1850    CubicBezier(SvgCubicCurve),
1851}
1852
1853#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd)]
1854#[repr(C)]
1855pub struct SvgPoint {
1856    pub x: f32,
1857    pub y: f32,
1858}
1859
1860impl_option!(
1861    SvgPoint,
1862    OptionSvgPoint,
1863    [Debug, Clone, PartialEq, PartialOrd]
1864);
1865
1866impl SvgPoint {
1867    #[inline]
1868    pub fn distance(&self, other: Self) -> f64 {
1869        let dx = other.x - self.x;
1870        let dy = other.y - self.y;
1871        libm::hypotf(dx, dy) as f64
1872    }
1873}
1874
1875#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd)]
1876#[repr(C)]
1877pub struct SvgRect {
1878    pub width: f32,
1879    pub height: f32,
1880    pub x: f32,
1881    pub y: f32,
1882    pub radius_top_left: f32,
1883    pub radius_top_right: f32,
1884    pub radius_bottom_left: f32,
1885    pub radius_bottom_right: f32,
1886}
1887
1888impl SvgRect {
1889    pub fn union_with(&mut self, other: &Self) {
1890        let self_max_x = self.x + self.width;
1891        let self_max_y = self.y + self.height;
1892        let self_min_x = self.x;
1893        let self_min_y = self.y;
1894
1895        let other_max_x = other.x + other.width;
1896        let other_max_y = other.y + other.height;
1897        let other_min_x = other.x;
1898        let other_min_y = other.y;
1899
1900        let max_x = self_max_x.max(other_max_x);
1901        let max_y = self_max_y.max(other_max_y);
1902        let min_x = self_min_x.min(other_min_x);
1903        let min_y = self_min_y.min(other_min_y);
1904
1905        self.x = min_x;
1906        self.y = min_y;
1907        self.width = max_x - min_x;
1908        self.height = max_y - min_y;
1909    }
1910
1911    /// Note: does not incorporate rounded edges!
1912    /// Origin of x and y is assumed to be the top left corner
1913    pub fn contains_point(&self, x: f32, y: f32) -> bool {
1914        x > self.x && x < self.x + self.width && y > self.y && y < self.y + self.height
1915    }
1916
1917    /// Expands the rect with a certain amount of padding
1918    pub fn expand(
1919        &self,
1920        padding_top: f32,
1921        padding_bottom: f32,
1922        padding_left: f32,
1923        padding_right: f32,
1924    ) -> SvgRect {
1925        SvgRect {
1926            width: self.width + padding_left + padding_right,
1927            height: self.height + padding_top + padding_bottom,
1928            x: self.x - padding_left,
1929            y: self.y - padding_top,
1930            ..*self
1931        }
1932    }
1933
1934    pub fn get_center(&self) -> SvgPoint {
1935        SvgPoint {
1936            x: self.x + (self.width / 2.0),
1937            y: self.y + (self.height / 2.0),
1938        }
1939    }
1940}
1941
1942#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1943#[repr(C)]
1944pub struct SvgCubicCurve {
1945    pub start: SvgPoint,
1946    pub ctrl_1: SvgPoint,
1947    pub ctrl_2: SvgPoint,
1948    pub end: SvgPoint,
1949}
1950
1951#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
1952#[repr(C)]
1953pub struct SvgVector {
1954    pub x: f64,
1955    pub y: f64,
1956}
1957
1958impl SvgVector {
1959    /// Returns the angle of the vector in degrees
1960    #[inline]
1961    pub fn angle_degrees(&self) -> f64 {
1962        //  y
1963        //  |  /
1964        //  | /
1965        //   / a)
1966        //   ___ x
1967
1968        (-self.x).atan2(self.y).to_degrees()
1969    }
1970
1971    #[inline]
1972    #[must_use = "returns a new vector"]
1973    pub fn normalize(&self) -> Self {
1974        let tangent_length = libm::hypotf(self.x as f32, self.y as f32) as f64;
1975
1976        Self {
1977            x: self.x / tangent_length,
1978            y: self.y / tangent_length,
1979        }
1980    }
1981
1982    /// Rotate the vector 90 degrees counter-clockwise
1983    #[must_use = "returns a new vector"]
1984    #[inline]
1985    pub fn rotate_90deg_ccw(&self) -> Self {
1986        Self {
1987            x: -self.y,
1988            y: self.x,
1989        }
1990    }
1991}
1992
1993const STEP_SIZE: usize = 20;
1994const STEP_SIZE_F64: f64 = 0.05;
1995
1996impl SvgCubicCurve {
1997    pub fn reverse(&mut self) {
1998        let mut temp = self.start;
1999        self.start = self.end;
2000        self.end = temp;
2001        temp = self.ctrl_1;
2002        self.ctrl_1 = self.ctrl_2;
2003        self.ctrl_2 = temp;
2004    }
2005
2006    pub fn get_start(&self) -> SvgPoint {
2007        self.start
2008    }
2009    pub fn get_end(&self) -> SvgPoint {
2010        self.end
2011    }
2012
2013    // evaluate the curve at t
2014    pub fn get_x_at_t(&self, t: f64) -> f64 {
2015        let c_x = 3.0 * (self.ctrl_1.x as f64 - self.start.x as f64);
2016        let b_x = 3.0 * (self.ctrl_2.x as f64 - self.ctrl_1.x as f64) - c_x;
2017        let a_x = self.end.x as f64 - self.start.x as f64 - c_x - b_x;
2018
2019        (a_x * t * t * t) + (b_x * t * t) + (c_x * t) + self.start.x as f64
2020    }
2021
2022    pub fn get_y_at_t(&self, t: f64) -> f64 {
2023        let c_x = 3.0 * (self.ctrl_1.y as f64 - self.start.y as f64);
2024        let b_x = 3.0 * (self.ctrl_2.y as f64 - self.ctrl_1.y as f64) - c_x;
2025        let a_x = self.end.y as f64 - self.start.y as f64 - c_x - b_x;
2026
2027        (a_x * t * t * t) + (b_x * t * t) + (c_x * t) + self.start.y as f64
2028    }
2029
2030    pub fn get_length(&self) -> f64 {
2031        // NOTE: this arc length parametrization is not very precise, but fast
2032        let mut arc_length = 0.0;
2033        let mut prev_point = self.get_start();
2034
2035        for i in 0..STEP_SIZE {
2036            let t_next = (i + 1) as f64 * STEP_SIZE_F64;
2037            let next_point = SvgPoint {
2038                x: self.get_x_at_t(t_next) as f32,
2039                y: self.get_y_at_t(t_next) as f32,
2040            };
2041            arc_length += prev_point.distance(next_point);
2042            prev_point = next_point;
2043        }
2044
2045        arc_length
2046    }
2047
2048    pub fn get_t_at_offset(&self, offset: f64) -> f64 {
2049        // step through the line until the offset is reached,
2050        // then interpolate linearly between the
2051        // current at the last sampled point
2052        let mut arc_length = 0.0;
2053        let mut t_current = 0.0;
2054        let mut prev_point = self.get_start();
2055
2056        for i in 0..STEP_SIZE {
2057            let t_next = (i + 1) as f64 * STEP_SIZE_F64;
2058            let next_point = SvgPoint {
2059                x: self.get_x_at_t(t_next) as f32,
2060                y: self.get_y_at_t(t_next) as f32,
2061            };
2062
2063            let distance = prev_point.distance(next_point);
2064
2065            arc_length += distance;
2066
2067            // linearly interpolate between last t and current t
2068            if arc_length > offset {
2069                let remaining = arc_length - offset;
2070                return t_current + (remaining / distance) * STEP_SIZE_F64;
2071            }
2072
2073            prev_point = next_point;
2074            t_current = t_next;
2075        }
2076
2077        t_current
2078    }
2079
2080    pub fn get_tangent_vector_at_t(&self, t: f64) -> SvgVector {
2081        // 1. Calculate the derivative of the bezier curve.
2082        //
2083        // This means that we go from 4 points to 3 points and redistribute
2084        // the weights of the control points according to the formula:
2085        //
2086        // w'0 = 3 * (w1-w0)
2087        // w'1 = 3 * (w2-w1)
2088        // w'2 = 3 * (w3-w2)
2089
2090        let w0 = SvgPoint {
2091            x: self.ctrl_1.x - self.start.x,
2092            y: self.ctrl_1.y - self.start.y,
2093        };
2094
2095        let w1 = SvgPoint {
2096            x: self.ctrl_2.x - self.ctrl_1.x,
2097            y: self.ctrl_2.y - self.ctrl_1.y,
2098        };
2099
2100        let w2 = SvgPoint {
2101            x: self.end.x - self.ctrl_2.x,
2102            y: self.end.y - self.ctrl_2.y,
2103        };
2104
2105        let quadratic_curve = SvgQuadraticCurve {
2106            start: w0,
2107            ctrl: w1,
2108            end: w2,
2109        };
2110
2111        // The first derivative of a cubic bezier curve is a quadratic
2112        // bezier curve. Luckily, the first derivative is also the tangent
2113        // vector (slope) of the curve. So all we need to do is to sample the
2114        // quadratic curve at t
2115        let tangent_vector = SvgVector {
2116            x: quadratic_curve.get_x_at_t(t),
2117            y: quadratic_curve.get_y_at_t(t),
2118        };
2119
2120        tangent_vector.normalize()
2121    }
2122
2123    pub fn get_bounds(&self) -> SvgRect {
2124        let min_x = self
2125            .start
2126            .x
2127            .min(self.end.x)
2128            .min(self.ctrl_1.x)
2129            .min(self.ctrl_2.x);
2130        let max_x = self
2131            .start
2132            .x
2133            .max(self.end.x)
2134            .max(self.ctrl_1.x)
2135            .max(self.ctrl_2.x);
2136
2137        let min_y = self
2138            .start
2139            .y
2140            .min(self.end.y)
2141            .min(self.ctrl_1.y)
2142            .min(self.ctrl_2.y);
2143        let max_y = self
2144            .start
2145            .y
2146            .max(self.end.y)
2147            .max(self.ctrl_1.y)
2148            .max(self.ctrl_2.y);
2149
2150        let width = (max_x - min_x).abs();
2151        let height = (max_y - min_y).abs();
2152
2153        SvgRect {
2154            width,
2155            height,
2156            x: min_x,
2157            y: min_y,
2158            ..SvgRect::default()
2159        }
2160    }
2161}
2162
2163#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
2164#[repr(C)]
2165pub struct SvgQuadraticCurve {
2166    pub start: SvgPoint,
2167    pub ctrl: SvgPoint,
2168    pub end: SvgPoint,
2169}
2170
2171impl SvgQuadraticCurve {
2172    pub fn reverse(&mut self) {
2173        let mut temp = self.start;
2174        self.start = self.end;
2175        self.end = temp;
2176    }
2177    pub fn get_start(&self) -> SvgPoint {
2178        self.start
2179    }
2180    pub fn get_end(&self) -> SvgPoint {
2181        self.end
2182    }
2183    pub fn get_bounds(&self) -> SvgRect {
2184        let min_x = self.start.x.min(self.end.x).min(self.ctrl.x);
2185        let max_x = self.start.x.max(self.end.x).max(self.ctrl.x);
2186
2187        let min_y = self.start.y.min(self.end.y).min(self.ctrl.y);
2188        let max_y = self.start.y.max(self.end.y).max(self.ctrl.y);
2189
2190        let width = (max_x - min_x).abs();
2191        let height = (max_y - min_y).abs();
2192
2193        SvgRect {
2194            width,
2195            height,
2196            x: min_x,
2197            y: min_y,
2198            ..SvgRect::default()
2199        }
2200    }
2201
2202    pub fn get_x_at_t(&self, t: f64) -> f64 {
2203        let one_minus = 1.0 - t;
2204        let one_minus_squared = one_minus * one_minus;
2205        let t_squared = t * t;
2206
2207        1.0 * one_minus_squared * 1.0 * self.start.x as f64
2208            + 2.0 * one_minus * t * self.ctrl.x as f64
2209            + 3.0 * 1.0 * t_squared * self.end.x as f64
2210    }
2211
2212    pub fn get_y_at_t(&self, t: f64) -> f64 {
2213        let one_minus = 1.0 - t;
2214        let one_minus_squared = one_minus * one_minus;
2215        let t_squared = t * t;
2216
2217        1.0 * one_minus_squared * 1.0 * self.start.y as f64
2218            + 2.0 * one_minus * t * self.ctrl.y as f64
2219            + 3.0 * 1.0 * t_squared * self.end.y as f64
2220    }
2221
2222    pub fn get_length(&self) -> f64 {
2223        self.to_cubic().get_length()
2224    }
2225
2226    pub fn get_t_at_offset(&self, offset: f64) -> f64 {
2227        self.to_cubic().get_t_at_offset(offset)
2228    }
2229
2230    pub fn get_tangent_vector_at_t(&self, t: f64) -> SvgVector {
2231        self.to_cubic().get_tangent_vector_at_t(t)
2232    }
2233
2234    fn to_cubic(&self) -> SvgCubicCurve {
2235        SvgCubicCurve {
2236            start: self.start,
2237            ctrl_1: SvgPoint {
2238                x: self.start.x + (0.75 * self.ctrl.x - self.start.x),
2239                y: self.start.y + (0.75 * self.ctrl.y - self.start.y),
2240            },
2241            ctrl_2: SvgPoint {
2242                x: self.start.x + (0.75 * self.end.x - self.ctrl.x),
2243                y: self.start.y + (0.75 * self.end.y - self.ctrl.y),
2244            },
2245            end: self.end,
2246        }
2247    }
2248}
2249
2250impl AnimationInterpolationFunction {
2251    pub const fn get_curve(self) -> SvgCubicCurve {
2252        match self {
2253            AnimationInterpolationFunction::Ease => SvgCubicCurve {
2254                start: SvgPoint { x: 0.0, y: 0.0 },
2255                ctrl_1: SvgPoint { x: 0.25, y: 0.1 },
2256                ctrl_2: SvgPoint { x: 0.25, y: 1.0 },
2257                end: SvgPoint { x: 1.0, y: 1.0 },
2258            },
2259            AnimationInterpolationFunction::Linear => SvgCubicCurve {
2260                start: SvgPoint { x: 0.0, y: 0.0 },
2261                ctrl_1: SvgPoint { x: 0.0, y: 0.0 },
2262                ctrl_2: SvgPoint { x: 1.0, y: 1.0 },
2263                end: SvgPoint { x: 1.0, y: 1.0 },
2264            },
2265            AnimationInterpolationFunction::EaseIn => SvgCubicCurve {
2266                start: SvgPoint { x: 0.0, y: 0.0 },
2267                ctrl_1: SvgPoint { x: 0.42, y: 0.0 },
2268                ctrl_2: SvgPoint { x: 1.0, y: 1.0 },
2269                end: SvgPoint { x: 1.0, y: 1.0 },
2270            },
2271            AnimationInterpolationFunction::EaseOut => SvgCubicCurve {
2272                start: SvgPoint { x: 0.0, y: 0.0 },
2273                ctrl_1: SvgPoint { x: 0.0, y: 0.0 },
2274                ctrl_2: SvgPoint { x: 0.58, y: 1.0 },
2275                end: SvgPoint { x: 1.0, y: 1.0 },
2276            },
2277            AnimationInterpolationFunction::EaseInOut => SvgCubicCurve {
2278                start: SvgPoint { x: 0.0, y: 0.0 },
2279                ctrl_1: SvgPoint { x: 0.42, y: 0.0 },
2280                ctrl_2: SvgPoint { x: 0.58, y: 1.0 },
2281                end: SvgPoint { x: 1.0, y: 1.0 },
2282            },
2283            AnimationInterpolationFunction::CubicBezier(c) => c,
2284        }
2285    }
2286
2287    pub fn evaluate(self, t: f64) -> f32 {
2288        self.get_curve().get_y_at_t(t) as f32
2289    }
2290}
2291
2292#[derive(Debug, Clone, PartialEq)]
2293#[repr(C)]
2294pub struct InterpolateResolver {
2295    pub interpolate_func: AnimationInterpolationFunction,
2296    pub parent_rect_width: f32,
2297    pub parent_rect_height: f32,
2298    pub current_rect_width: f32,
2299    pub current_rect_height: f32,
2300}
2301
2302impl CssProperty {
2303    pub fn key(&self) -> &'static str {
2304        self.get_type().to_str()
2305    }
2306
2307    pub fn value(&self) -> String {
2308        match self {
2309            CssProperty::TextColor(v) => v.get_css_value_fmt(),
2310            CssProperty::FontSize(v) => v.get_css_value_fmt(),
2311            CssProperty::FontFamily(v) => v.get_css_value_fmt(),
2312            CssProperty::TextAlign(v) => v.get_css_value_fmt(),
2313            CssProperty::LetterSpacing(v) => v.get_css_value_fmt(),
2314            CssProperty::LineHeight(v) => v.get_css_value_fmt(),
2315            CssProperty::WordSpacing(v) => v.get_css_value_fmt(),
2316            CssProperty::TabWidth(v) => v.get_css_value_fmt(),
2317            CssProperty::Cursor(v) => v.get_css_value_fmt(),
2318            CssProperty::Display(v) => v.get_css_value_fmt(),
2319            CssProperty::Float(v) => v.get_css_value_fmt(),
2320            CssProperty::BoxSizing(v) => v.get_css_value_fmt(),
2321            CssProperty::Width(v) => v.get_css_value_fmt(),
2322            CssProperty::Height(v) => v.get_css_value_fmt(),
2323            CssProperty::MinWidth(v) => v.get_css_value_fmt(),
2324            CssProperty::MinHeight(v) => v.get_css_value_fmt(),
2325            CssProperty::MaxWidth(v) => v.get_css_value_fmt(),
2326            CssProperty::MaxHeight(v) => v.get_css_value_fmt(),
2327            CssProperty::Position(v) => v.get_css_value_fmt(),
2328            CssProperty::Top(v) => v.get_css_value_fmt(),
2329            CssProperty::Right(v) => v.get_css_value_fmt(),
2330            CssProperty::Left(v) => v.get_css_value_fmt(),
2331            CssProperty::Bottom(v) => v.get_css_value_fmt(),
2332            CssProperty::FlexWrap(v) => v.get_css_value_fmt(),
2333            CssProperty::FlexDirection(v) => v.get_css_value_fmt(),
2334            CssProperty::FlexGrow(v) => v.get_css_value_fmt(),
2335            CssProperty::FlexShrink(v) => v.get_css_value_fmt(),
2336            CssProperty::JustifyContent(v) => v.get_css_value_fmt(),
2337            CssProperty::AlignItems(v) => v.get_css_value_fmt(),
2338            CssProperty::AlignContent(v) => v.get_css_value_fmt(),
2339            CssProperty::BackgroundContent(v) => v.get_css_value_fmt(),
2340            CssProperty::BackgroundPosition(v) => v.get_css_value_fmt(),
2341            CssProperty::BackgroundSize(v) => v.get_css_value_fmt(),
2342            CssProperty::BackgroundRepeat(v) => v.get_css_value_fmt(),
2343            CssProperty::OverflowX(v) => v.get_css_value_fmt(),
2344            CssProperty::OverflowY(v) => v.get_css_value_fmt(),
2345            CssProperty::PaddingTop(v) => v.get_css_value_fmt(),
2346            CssProperty::PaddingLeft(v) => v.get_css_value_fmt(),
2347            CssProperty::PaddingRight(v) => v.get_css_value_fmt(),
2348            CssProperty::PaddingBottom(v) => v.get_css_value_fmt(),
2349            CssProperty::MarginTop(v) => v.get_css_value_fmt(),
2350            CssProperty::MarginLeft(v) => v.get_css_value_fmt(),
2351            CssProperty::MarginRight(v) => v.get_css_value_fmt(),
2352            CssProperty::MarginBottom(v) => v.get_css_value_fmt(),
2353            CssProperty::BorderTopLeftRadius(v) => v.get_css_value_fmt(),
2354            CssProperty::BorderTopRightRadius(v) => v.get_css_value_fmt(),
2355            CssProperty::BorderBottomLeftRadius(v) => v.get_css_value_fmt(),
2356            CssProperty::BorderBottomRightRadius(v) => v.get_css_value_fmt(),
2357            CssProperty::BorderTopColor(v) => v.get_css_value_fmt(),
2358            CssProperty::BorderRightColor(v) => v.get_css_value_fmt(),
2359            CssProperty::BorderLeftColor(v) => v.get_css_value_fmt(),
2360            CssProperty::BorderBottomColor(v) => v.get_css_value_fmt(),
2361            CssProperty::BorderTopStyle(v) => v.get_css_value_fmt(),
2362            CssProperty::BorderRightStyle(v) => v.get_css_value_fmt(),
2363            CssProperty::BorderLeftStyle(v) => v.get_css_value_fmt(),
2364            CssProperty::BorderBottomStyle(v) => v.get_css_value_fmt(),
2365            CssProperty::BorderTopWidth(v) => v.get_css_value_fmt(),
2366            CssProperty::BorderRightWidth(v) => v.get_css_value_fmt(),
2367            CssProperty::BorderLeftWidth(v) => v.get_css_value_fmt(),
2368            CssProperty::BorderBottomWidth(v) => v.get_css_value_fmt(),
2369            CssProperty::BoxShadowLeft(v) => v.get_css_value_fmt(),
2370            CssProperty::BoxShadowRight(v) => v.get_css_value_fmt(),
2371            CssProperty::BoxShadowTop(v) => v.get_css_value_fmt(),
2372            CssProperty::BoxShadowBottom(v) => v.get_css_value_fmt(),
2373            CssProperty::ScrollbarStyle(v) => v.get_css_value_fmt(),
2374            CssProperty::Opacity(v) => v.get_css_value_fmt(),
2375            CssProperty::Transform(v) => v.get_css_value_fmt(),
2376            CssProperty::TransformOrigin(v) => v.get_css_value_fmt(),
2377            CssProperty::PerspectiveOrigin(v) => v.get_css_value_fmt(),
2378            CssProperty::BackfaceVisibility(v) => v.get_css_value_fmt(),
2379            CssProperty::MixBlendMode(v) => v.get_css_value_fmt(),
2380            CssProperty::Filter(v) => v.get_css_value_fmt(),
2381            CssProperty::BackdropFilter(v) => v.get_css_value_fmt(),
2382            CssProperty::TextShadow(v) => v.get_css_value_fmt(),
2383        }
2384    }
2385
2386    pub fn format_css(&self) -> String {
2387        format!("{}: {};", self.key(), self.value())
2388    }
2389
2390    pub fn interpolate(
2391        &self,
2392        other: &Self,
2393        t: f32,
2394        interpolate_resolver: &InterpolateResolver,
2395    ) -> Self {
2396        if t <= 0.0 {
2397            return self.clone();
2398        } else if t >= 1.0 {
2399            return other.clone();
2400        }
2401
2402        // Map from linear interpolation function to Easing curve
2403        let t: f32 = interpolate_resolver.interpolate_func.evaluate(t as f64);
2404
2405        let t = t.max(0.0).min(1.0);
2406
2407        match (self, other) {
2408            (CssProperty::TextColor(col_start), CssProperty::TextColor(col_end)) => {
2409                let col_start = col_start.get_property().copied().unwrap_or_default();
2410                let col_end = col_end.get_property().copied().unwrap_or_default();
2411                CssProperty::text_color(col_start.interpolate(&col_end, t))
2412            }
2413            (CssProperty::FontSize(fs_start), CssProperty::FontSize(fs_end)) => {
2414                let fs_start = fs_start.get_property().copied().unwrap_or_default();
2415                let fs_end = fs_end.get_property().copied().unwrap_or_default();
2416                CssProperty::font_size(fs_start.interpolate(&fs_end, t))
2417            }
2418            (CssProperty::LetterSpacing(ls_start), CssProperty::LetterSpacing(ls_end)) => {
2419                let ls_start = ls_start.get_property().copied().unwrap_or_default();
2420                let ls_end = ls_end.get_property().copied().unwrap_or_default();
2421                CssProperty::letter_spacing(ls_start.interpolate(&ls_end, t))
2422            }
2423            (CssProperty::LineHeight(lh_start), CssProperty::LineHeight(lh_end)) => {
2424                let lh_start = lh_start.get_property().copied().unwrap_or_default();
2425                let lh_end = lh_end.get_property().copied().unwrap_or_default();
2426                CssProperty::line_height(lh_start.interpolate(&lh_end, t))
2427            }
2428            (CssProperty::WordSpacing(ws_start), CssProperty::WordSpacing(ws_end)) => {
2429                let ws_start = ws_start.get_property().copied().unwrap_or_default();
2430                let ws_end = ws_end.get_property().copied().unwrap_or_default();
2431                CssProperty::word_spacing(ws_start.interpolate(&ws_end, t))
2432            }
2433            (CssProperty::TabWidth(tw_start), CssProperty::TabWidth(tw_end)) => {
2434                let tw_start = tw_start.get_property().copied().unwrap_or_default();
2435                let tw_end = tw_end.get_property().copied().unwrap_or_default();
2436                CssProperty::tab_width(tw_start.interpolate(&tw_end, t))
2437            }
2438            (CssProperty::Width(start), CssProperty::Width(end)) => {
2439                let start = start
2440                    .get_property()
2441                    .copied()
2442                    .unwrap_or(LayoutWidth::px(interpolate_resolver.current_rect_width));
2443                let end = end.get_property().copied().unwrap_or_default();
2444                CssProperty::Width(CssPropertyValue::Exact(start.interpolate(&end, t)))
2445            }
2446            (CssProperty::Height(start), CssProperty::Height(end)) => {
2447                let start = start
2448                    .get_property()
2449                    .copied()
2450                    .unwrap_or(LayoutHeight::px(interpolate_resolver.current_rect_height));
2451                let end = end.get_property().copied().unwrap_or_default();
2452                CssProperty::Height(CssPropertyValue::Exact(start.interpolate(&end, t)))
2453            }
2454            (CssProperty::MinWidth(start), CssProperty::MinWidth(end)) => {
2455                let start = start.get_property().copied().unwrap_or_default();
2456                let end = end.get_property().copied().unwrap_or_default();
2457                CssProperty::MinWidth(CssPropertyValue::Exact(start.interpolate(&end, t)))
2458            }
2459            (CssProperty::MinHeight(start), CssProperty::MinHeight(end)) => {
2460                let start = start.get_property().copied().unwrap_or_default();
2461                let end = end.get_property().copied().unwrap_or_default();
2462                CssProperty::MinHeight(CssPropertyValue::Exact(start.interpolate(&end, t)))
2463            }
2464            (CssProperty::MaxWidth(start), CssProperty::MaxWidth(end)) => {
2465                let start = start.get_property().copied().unwrap_or_default();
2466                let end = end.get_property().copied().unwrap_or_default();
2467                CssProperty::MaxWidth(CssPropertyValue::Exact(start.interpolate(&end, t)))
2468            }
2469            (CssProperty::MaxHeight(start), CssProperty::MaxHeight(end)) => {
2470                let start = start.get_property().copied().unwrap_or_default();
2471                let end = end.get_property().copied().unwrap_or_default();
2472                CssProperty::MaxHeight(CssPropertyValue::Exact(start.interpolate(&end, t)))
2473            }
2474            (CssProperty::Top(start), CssProperty::Top(end)) => {
2475                let start = start.get_property().copied().unwrap_or_default();
2476                let end = end.get_property().copied().unwrap_or_default();
2477                CssProperty::Top(CssPropertyValue::Exact(start.interpolate(&end, t)))
2478            }
2479            (CssProperty::Right(start), CssProperty::Right(end)) => {
2480                let start = start.get_property().copied().unwrap_or_default();
2481                let end = end.get_property().copied().unwrap_or_default();
2482                CssProperty::Right(CssPropertyValue::Exact(start.interpolate(&end, t)))
2483            }
2484            (CssProperty::Left(start), CssProperty::Left(end)) => {
2485                let start = start.get_property().copied().unwrap_or_default();
2486                let end = end.get_property().copied().unwrap_or_default();
2487                CssProperty::Left(CssPropertyValue::Exact(start.interpolate(&end, t)))
2488            }
2489            (CssProperty::Bottom(start), CssProperty::Bottom(end)) => {
2490                let start = start.get_property().copied().unwrap_or_default();
2491                let end = end.get_property().copied().unwrap_or_default();
2492                CssProperty::Bottom(CssPropertyValue::Exact(start.interpolate(&end, t)))
2493            }
2494            (CssProperty::FlexGrow(start), CssProperty::FlexGrow(end)) => {
2495                let start = start.get_property().copied().unwrap_or_default();
2496                let end = end.get_property().copied().unwrap_or_default();
2497                CssProperty::FlexGrow(CssPropertyValue::Exact(start.interpolate(&end, t)))
2498            }
2499            (CssProperty::FlexShrink(start), CssProperty::FlexShrink(end)) => {
2500                let start = start.get_property().copied().unwrap_or_default();
2501                let end = end.get_property().copied().unwrap_or_default();
2502                CssProperty::FlexShrink(CssPropertyValue::Exact(start.interpolate(&end, t)))
2503            }
2504            (CssProperty::PaddingTop(start), CssProperty::PaddingTop(end)) => {
2505                let start = start.get_property().copied().unwrap_or_default();
2506                let end = end.get_property().copied().unwrap_or_default();
2507                CssProperty::PaddingTop(CssPropertyValue::Exact(start.interpolate(&end, t)))
2508            }
2509            (CssProperty::PaddingLeft(start), CssProperty::PaddingLeft(end)) => {
2510                let start = start.get_property().copied().unwrap_or_default();
2511                let end = end.get_property().copied().unwrap_or_default();
2512                CssProperty::PaddingLeft(CssPropertyValue::Exact(start.interpolate(&end, t)))
2513            }
2514            (CssProperty::PaddingRight(start), CssProperty::PaddingRight(end)) => {
2515                let start = start.get_property().copied().unwrap_or_default();
2516                let end = end.get_property().copied().unwrap_or_default();
2517                CssProperty::PaddingRight(CssPropertyValue::Exact(start.interpolate(&end, t)))
2518            }
2519            (CssProperty::PaddingBottom(start), CssProperty::PaddingBottom(end)) => {
2520                let start = start.get_property().copied().unwrap_or_default();
2521                let end = end.get_property().copied().unwrap_or_default();
2522                CssProperty::PaddingBottom(CssPropertyValue::Exact(start.interpolate(&end, t)))
2523            }
2524            (CssProperty::MarginTop(start), CssProperty::MarginTop(end)) => {
2525                let start = start.get_property().copied().unwrap_or_default();
2526                let end = end.get_property().copied().unwrap_or_default();
2527                CssProperty::MarginTop(CssPropertyValue::Exact(start.interpolate(&end, t)))
2528            }
2529            (CssProperty::MarginLeft(start), CssProperty::MarginLeft(end)) => {
2530                let start = start.get_property().copied().unwrap_or_default();
2531                let end = end.get_property().copied().unwrap_or_default();
2532                CssProperty::MarginLeft(CssPropertyValue::Exact(start.interpolate(&end, t)))
2533            }
2534            (CssProperty::MarginRight(start), CssProperty::MarginRight(end)) => {
2535                let start = start.get_property().copied().unwrap_or_default();
2536                let end = end.get_property().copied().unwrap_or_default();
2537                CssProperty::MarginRight(CssPropertyValue::Exact(start.interpolate(&end, t)))
2538            }
2539            (CssProperty::MarginBottom(start), CssProperty::MarginBottom(end)) => {
2540                let start = start.get_property().copied().unwrap_or_default();
2541                let end = end.get_property().copied().unwrap_or_default();
2542                CssProperty::MarginBottom(CssPropertyValue::Exact(start.interpolate(&end, t)))
2543            }
2544            (CssProperty::BorderTopLeftRadius(start), CssProperty::BorderTopLeftRadius(end)) => {
2545                let start = start.get_property().copied().unwrap_or_default();
2546                let end = end.get_property().copied().unwrap_or_default();
2547                CssProperty::BorderTopLeftRadius(CssPropertyValue::Exact(
2548                    start.interpolate(&end, t),
2549                ))
2550            }
2551            (CssProperty::BorderTopRightRadius(start), CssProperty::BorderTopRightRadius(end)) => {
2552                let start = start.get_property().copied().unwrap_or_default();
2553                let end = end.get_property().copied().unwrap_or_default();
2554                CssProperty::BorderTopRightRadius(CssPropertyValue::Exact(
2555                    start.interpolate(&end, t),
2556                ))
2557            }
2558            (
2559                CssProperty::BorderBottomLeftRadius(start),
2560                CssProperty::BorderBottomLeftRadius(end),
2561            ) => {
2562                let start = start.get_property().copied().unwrap_or_default();
2563                let end = end.get_property().copied().unwrap_or_default();
2564                CssProperty::BorderBottomLeftRadius(CssPropertyValue::Exact(
2565                    start.interpolate(&end, t),
2566                ))
2567            }
2568            (
2569                CssProperty::BorderBottomRightRadius(start),
2570                CssProperty::BorderBottomRightRadius(end),
2571            ) => {
2572                let start = start.get_property().copied().unwrap_or_default();
2573                let end = end.get_property().copied().unwrap_or_default();
2574                CssProperty::BorderBottomRightRadius(CssPropertyValue::Exact(
2575                    start.interpolate(&end, t),
2576                ))
2577            }
2578            (CssProperty::BorderTopColor(start), CssProperty::BorderTopColor(end)) => {
2579                let start = start.get_property().copied().unwrap_or_default();
2580                let end = end.get_property().copied().unwrap_or_default();
2581                CssProperty::BorderTopColor(CssPropertyValue::Exact(start.interpolate(&end, t)))
2582            }
2583            (CssProperty::BorderRightColor(start), CssProperty::BorderRightColor(end)) => {
2584                let start = start.get_property().copied().unwrap_or_default();
2585                let end = end.get_property().copied().unwrap_or_default();
2586                CssProperty::BorderRightColor(CssPropertyValue::Exact(start.interpolate(&end, t)))
2587            }
2588            (CssProperty::BorderLeftColor(start), CssProperty::BorderLeftColor(end)) => {
2589                let start = start.get_property().copied().unwrap_or_default();
2590                let end = end.get_property().copied().unwrap_or_default();
2591                CssProperty::BorderLeftColor(CssPropertyValue::Exact(start.interpolate(&end, t)))
2592            }
2593            (CssProperty::BorderBottomColor(start), CssProperty::BorderBottomColor(end)) => {
2594                let start = start.get_property().copied().unwrap_or_default();
2595                let end = end.get_property().copied().unwrap_or_default();
2596                CssProperty::BorderBottomColor(CssPropertyValue::Exact(start.interpolate(&end, t)))
2597            }
2598            (CssProperty::BorderTopWidth(start), CssProperty::BorderTopWidth(end)) => {
2599                let start = start.get_property().copied().unwrap_or_default();
2600                let end = end.get_property().copied().unwrap_or_default();
2601                CssProperty::BorderTopWidth(CssPropertyValue::Exact(start.interpolate(&end, t)))
2602            }
2603            (CssProperty::BorderRightWidth(start), CssProperty::BorderRightWidth(end)) => {
2604                let start = start.get_property().copied().unwrap_or_default();
2605                let end = end.get_property().copied().unwrap_or_default();
2606                CssProperty::BorderRightWidth(CssPropertyValue::Exact(start.interpolate(&end, t)))
2607            }
2608            (CssProperty::BorderLeftWidth(start), CssProperty::BorderLeftWidth(end)) => {
2609                let start = start.get_property().copied().unwrap_or_default();
2610                let end = end.get_property().copied().unwrap_or_default();
2611                CssProperty::BorderLeftWidth(CssPropertyValue::Exact(start.interpolate(&end, t)))
2612            }
2613            (CssProperty::BorderBottomWidth(start), CssProperty::BorderBottomWidth(end)) => {
2614                let start = start.get_property().copied().unwrap_or_default();
2615                let end = end.get_property().copied().unwrap_or_default();
2616                CssProperty::BorderBottomWidth(CssPropertyValue::Exact(start.interpolate(&end, t)))
2617            }
2618            (CssProperty::Opacity(start), CssProperty::Opacity(end)) => {
2619                let start = start.get_property().copied().unwrap_or_default();
2620                let end = end.get_property().copied().unwrap_or_default();
2621                CssProperty::Opacity(CssPropertyValue::Exact(start.interpolate(&end, t)))
2622            }
2623            (CssProperty::TransformOrigin(start), CssProperty::TransformOrigin(end)) => {
2624                let start = start.get_property().copied().unwrap_or_default();
2625                let end = end.get_property().copied().unwrap_or_default();
2626                CssProperty::TransformOrigin(CssPropertyValue::Exact(start.interpolate(&end, t)))
2627            }
2628            (CssProperty::PerspectiveOrigin(start), CssProperty::PerspectiveOrigin(end)) => {
2629                let start = start.get_property().copied().unwrap_or_default();
2630                let end = end.get_property().copied().unwrap_or_default();
2631                CssProperty::PerspectiveOrigin(CssPropertyValue::Exact(start.interpolate(&end, t)))
2632            }
2633            /*
2634            animate transform:
2635            CssProperty::Transform(CssPropertyValue<StyleTransformVec>),
2636
2637            animate box shadow:
2638            CssProperty::BoxShadowLeft(CssPropertyValue<StyleBoxShadow>),
2639            CssProperty::BoxShadowRight(CssPropertyValue<StyleBoxShadow>),
2640            CssProperty::BoxShadowTop(CssPropertyValue<StyleBoxShadow>),
2641            CssProperty::BoxShadowBottom(CssPropertyValue<StyleBoxShadow>),
2642
2643            animate background:
2644            CssProperty::BackgroundContent(CssPropertyValue<StyleBackgroundContentVec>),
2645            CssProperty::BackgroundPosition(CssPropertyValue<StyleBackgroundPositionVec>),
2646            CssProperty::BackgroundSize(CssPropertyValue<StyleBackgroundSizeVec>),
2647            */
2648            (_, _) => {
2649                // not animatable, fallback
2650                if t > 0.5 {
2651                    other.clone()
2652                } else {
2653                    self.clone()
2654                }
2655            }
2656        }
2657    }
2658}
2659
2660impl_vec!(CssProperty, CssPropertyVec, CssPropertyVecDestructor);
2661impl_vec_debug!(CssProperty, CssPropertyVec);
2662impl_vec_partialord!(CssProperty, CssPropertyVec);
2663impl_vec_ord!(CssProperty, CssPropertyVec);
2664impl_vec_clone!(CssProperty, CssPropertyVec, CssPropertyVecDestructor);
2665impl_vec_partialeq!(CssProperty, CssPropertyVec);
2666impl_vec_eq!(CssProperty, CssPropertyVec);
2667impl_vec_hash!(CssProperty, CssPropertyVec);
2668
2669macro_rules! css_property_from_type {
2670    ($prop_type:expr, $content_type:ident) => {{
2671        match $prop_type {
2672            CssPropertyType::TextColor => CssProperty::TextColor(CssPropertyValue::$content_type),
2673            CssPropertyType::FontSize => CssProperty::FontSize(CssPropertyValue::$content_type),
2674            CssPropertyType::FontFamily => CssProperty::FontFamily(CssPropertyValue::$content_type),
2675            CssPropertyType::TextAlign => CssProperty::TextAlign(CssPropertyValue::$content_type),
2676            CssPropertyType::LetterSpacing => {
2677                CssProperty::LetterSpacing(CssPropertyValue::$content_type)
2678            }
2679            CssPropertyType::LineHeight => CssProperty::LineHeight(CssPropertyValue::$content_type),
2680            CssPropertyType::WordSpacing => {
2681                CssProperty::WordSpacing(CssPropertyValue::$content_type)
2682            }
2683            CssPropertyType::TabWidth => CssProperty::TabWidth(CssPropertyValue::$content_type),
2684            CssPropertyType::Cursor => CssProperty::Cursor(CssPropertyValue::$content_type),
2685            CssPropertyType::Display => CssProperty::Display(CssPropertyValue::$content_type),
2686            CssPropertyType::Float => CssProperty::Float(CssPropertyValue::$content_type),
2687            CssPropertyType::BoxSizing => CssProperty::BoxSizing(CssPropertyValue::$content_type),
2688            CssPropertyType::Width => CssProperty::Width(CssPropertyValue::$content_type),
2689            CssPropertyType::Height => CssProperty::Height(CssPropertyValue::$content_type),
2690            CssPropertyType::MinWidth => CssProperty::MinWidth(CssPropertyValue::$content_type),
2691            CssPropertyType::MinHeight => CssProperty::MinHeight(CssPropertyValue::$content_type),
2692            CssPropertyType::MaxWidth => CssProperty::MaxWidth(CssPropertyValue::$content_type),
2693            CssPropertyType::MaxHeight => CssProperty::MaxHeight(CssPropertyValue::$content_type),
2694            CssPropertyType::Position => CssProperty::Position(CssPropertyValue::$content_type),
2695            CssPropertyType::Top => CssProperty::Top(CssPropertyValue::$content_type),
2696            CssPropertyType::Right => CssProperty::Right(CssPropertyValue::$content_type),
2697            CssPropertyType::Left => CssProperty::Left(CssPropertyValue::$content_type),
2698            CssPropertyType::Bottom => CssProperty::Bottom(CssPropertyValue::$content_type),
2699            CssPropertyType::FlexWrap => CssProperty::FlexWrap(CssPropertyValue::$content_type),
2700            CssPropertyType::FlexDirection => {
2701                CssProperty::FlexDirection(CssPropertyValue::$content_type)
2702            }
2703            CssPropertyType::FlexGrow => CssProperty::FlexGrow(CssPropertyValue::$content_type),
2704            CssPropertyType::FlexShrink => CssProperty::FlexShrink(CssPropertyValue::$content_type),
2705            CssPropertyType::JustifyContent => {
2706                CssProperty::JustifyContent(CssPropertyValue::$content_type)
2707            }
2708            CssPropertyType::AlignItems => CssProperty::AlignItems(CssPropertyValue::$content_type),
2709            CssPropertyType::AlignContent => {
2710                CssProperty::AlignContent(CssPropertyValue::$content_type)
2711            }
2712            CssPropertyType::OverflowX => CssProperty::OverflowX(CssPropertyValue::$content_type),
2713            CssPropertyType::OverflowY => CssProperty::OverflowY(CssPropertyValue::$content_type),
2714            CssPropertyType::PaddingTop => CssProperty::PaddingTop(CssPropertyValue::$content_type),
2715            CssPropertyType::PaddingLeft => {
2716                CssProperty::PaddingLeft(CssPropertyValue::$content_type)
2717            }
2718            CssPropertyType::PaddingRight => {
2719                CssProperty::PaddingRight(CssPropertyValue::$content_type)
2720            }
2721            CssPropertyType::PaddingBottom => {
2722                CssProperty::PaddingBottom(CssPropertyValue::$content_type)
2723            }
2724            CssPropertyType::MarginTop => CssProperty::MarginTop(CssPropertyValue::$content_type),
2725            CssPropertyType::MarginLeft => CssProperty::MarginLeft(CssPropertyValue::$content_type),
2726            CssPropertyType::MarginRight => {
2727                CssProperty::MarginRight(CssPropertyValue::$content_type)
2728            }
2729            CssPropertyType::MarginBottom => {
2730                CssProperty::MarginBottom(CssPropertyValue::$content_type)
2731            }
2732            CssPropertyType::BackgroundContent => {
2733                CssProperty::BackgroundContent(CssPropertyValue::$content_type)
2734            }
2735            CssPropertyType::BackgroundPosition => {
2736                CssProperty::BackgroundPosition(CssPropertyValue::$content_type)
2737            }
2738            CssPropertyType::BackgroundSize => {
2739                CssProperty::BackgroundSize(CssPropertyValue::$content_type)
2740            }
2741            CssPropertyType::BackgroundRepeat => {
2742                CssProperty::BackgroundRepeat(CssPropertyValue::$content_type)
2743            }
2744            CssPropertyType::BorderTopLeftRadius => {
2745                CssProperty::BorderTopLeftRadius(CssPropertyValue::$content_type)
2746            }
2747            CssPropertyType::BorderTopRightRadius => {
2748                CssProperty::BorderTopRightRadius(CssPropertyValue::$content_type)
2749            }
2750            CssPropertyType::BorderBottomLeftRadius => {
2751                CssProperty::BorderBottomLeftRadius(CssPropertyValue::$content_type)
2752            }
2753            CssPropertyType::BorderBottomRightRadius => {
2754                CssProperty::BorderBottomRightRadius(CssPropertyValue::$content_type)
2755            }
2756            CssPropertyType::BorderTopColor => {
2757                CssProperty::BorderTopColor(CssPropertyValue::$content_type)
2758            }
2759            CssPropertyType::BorderRightColor => {
2760                CssProperty::BorderRightColor(CssPropertyValue::$content_type)
2761            }
2762            CssPropertyType::BorderLeftColor => {
2763                CssProperty::BorderLeftColor(CssPropertyValue::$content_type)
2764            }
2765            CssPropertyType::BorderBottomColor => {
2766                CssProperty::BorderBottomColor(CssPropertyValue::$content_type)
2767            }
2768            CssPropertyType::BorderTopStyle => {
2769                CssProperty::BorderTopStyle(CssPropertyValue::$content_type)
2770            }
2771            CssPropertyType::BorderRightStyle => {
2772                CssProperty::BorderRightStyle(CssPropertyValue::$content_type)
2773            }
2774            CssPropertyType::BorderLeftStyle => {
2775                CssProperty::BorderLeftStyle(CssPropertyValue::$content_type)
2776            }
2777            CssPropertyType::BorderBottomStyle => {
2778                CssProperty::BorderBottomStyle(CssPropertyValue::$content_type)
2779            }
2780            CssPropertyType::BorderTopWidth => {
2781                CssProperty::BorderTopWidth(CssPropertyValue::$content_type)
2782            }
2783            CssPropertyType::BorderRightWidth => {
2784                CssProperty::BorderRightWidth(CssPropertyValue::$content_type)
2785            }
2786            CssPropertyType::BorderLeftWidth => {
2787                CssProperty::BorderLeftWidth(CssPropertyValue::$content_type)
2788            }
2789            CssPropertyType::BorderBottomWidth => {
2790                CssProperty::BorderBottomWidth(CssPropertyValue::$content_type)
2791            }
2792            CssPropertyType::BoxShadowLeft => {
2793                CssProperty::BoxShadowLeft(CssPropertyValue::$content_type)
2794            }
2795            CssPropertyType::BoxShadowRight => {
2796                CssProperty::BoxShadowRight(CssPropertyValue::$content_type)
2797            }
2798            CssPropertyType::BoxShadowTop => {
2799                CssProperty::BoxShadowTop(CssPropertyValue::$content_type)
2800            }
2801            CssPropertyType::BoxShadowBottom => {
2802                CssProperty::BoxShadowBottom(CssPropertyValue::$content_type)
2803            }
2804            CssPropertyType::ScrollbarStyle => {
2805                CssProperty::ScrollbarStyle(CssPropertyValue::$content_type)
2806            }
2807            CssPropertyType::Opacity => CssProperty::Opacity(CssPropertyValue::$content_type),
2808            CssPropertyType::Transform => CssProperty::Transform(CssPropertyValue::$content_type),
2809            CssPropertyType::PerspectiveOrigin => {
2810                CssProperty::PerspectiveOrigin(CssPropertyValue::$content_type)
2811            }
2812            CssPropertyType::TransformOrigin => {
2813                CssProperty::TransformOrigin(CssPropertyValue::$content_type)
2814            }
2815            CssPropertyType::BackfaceVisibility => {
2816                CssProperty::BackfaceVisibility(CssPropertyValue::$content_type)
2817            }
2818            CssPropertyType::MixBlendMode => {
2819                CssProperty::MixBlendMode(CssPropertyValue::$content_type)
2820            }
2821            CssPropertyType::Filter => CssProperty::Filter(CssPropertyValue::$content_type),
2822            CssPropertyType::BackdropFilter => {
2823                CssProperty::BackdropFilter(CssPropertyValue::$content_type)
2824            }
2825            CssPropertyType::TextShadow => CssProperty::TextShadow(CssPropertyValue::$content_type),
2826        }
2827    }};
2828}
2829
2830impl CssProperty {
2831    /// Return the type (key) of this property as a statically typed enum
2832    pub const fn get_type(&self) -> CssPropertyType {
2833        match &self {
2834            CssProperty::TextColor(_) => CssPropertyType::TextColor,
2835            CssProperty::FontSize(_) => CssPropertyType::FontSize,
2836            CssProperty::FontFamily(_) => CssPropertyType::FontFamily,
2837            CssProperty::TextAlign(_) => CssPropertyType::TextAlign,
2838            CssProperty::LetterSpacing(_) => CssPropertyType::LetterSpacing,
2839            CssProperty::LineHeight(_) => CssPropertyType::LineHeight,
2840            CssProperty::WordSpacing(_) => CssPropertyType::WordSpacing,
2841            CssProperty::TabWidth(_) => CssPropertyType::TabWidth,
2842            CssProperty::Cursor(_) => CssPropertyType::Cursor,
2843            CssProperty::Display(_) => CssPropertyType::Display,
2844            CssProperty::Float(_) => CssPropertyType::Float,
2845            CssProperty::BoxSizing(_) => CssPropertyType::BoxSizing,
2846            CssProperty::Width(_) => CssPropertyType::Width,
2847            CssProperty::Height(_) => CssPropertyType::Height,
2848            CssProperty::MinWidth(_) => CssPropertyType::MinWidth,
2849            CssProperty::MinHeight(_) => CssPropertyType::MinHeight,
2850            CssProperty::MaxWidth(_) => CssPropertyType::MaxWidth,
2851            CssProperty::MaxHeight(_) => CssPropertyType::MaxHeight,
2852            CssProperty::Position(_) => CssPropertyType::Position,
2853            CssProperty::Top(_) => CssPropertyType::Top,
2854            CssProperty::Right(_) => CssPropertyType::Right,
2855            CssProperty::Left(_) => CssPropertyType::Left,
2856            CssProperty::Bottom(_) => CssPropertyType::Bottom,
2857            CssProperty::FlexWrap(_) => CssPropertyType::FlexWrap,
2858            CssProperty::FlexDirection(_) => CssPropertyType::FlexDirection,
2859            CssProperty::FlexGrow(_) => CssPropertyType::FlexGrow,
2860            CssProperty::FlexShrink(_) => CssPropertyType::FlexShrink,
2861            CssProperty::JustifyContent(_) => CssPropertyType::JustifyContent,
2862            CssProperty::AlignItems(_) => CssPropertyType::AlignItems,
2863            CssProperty::AlignContent(_) => CssPropertyType::AlignContent,
2864            CssProperty::BackgroundContent(_) => CssPropertyType::BackgroundContent,
2865            CssProperty::BackgroundPosition(_) => CssPropertyType::BackgroundPosition,
2866            CssProperty::BackgroundSize(_) => CssPropertyType::BackgroundSize,
2867            CssProperty::BackgroundRepeat(_) => CssPropertyType::BackgroundRepeat,
2868            CssProperty::OverflowX(_) => CssPropertyType::OverflowX,
2869            CssProperty::OverflowY(_) => CssPropertyType::OverflowY,
2870            CssProperty::PaddingTop(_) => CssPropertyType::PaddingTop,
2871            CssProperty::PaddingLeft(_) => CssPropertyType::PaddingLeft,
2872            CssProperty::PaddingRight(_) => CssPropertyType::PaddingRight,
2873            CssProperty::PaddingBottom(_) => CssPropertyType::PaddingBottom,
2874            CssProperty::MarginTop(_) => CssPropertyType::MarginTop,
2875            CssProperty::MarginLeft(_) => CssPropertyType::MarginLeft,
2876            CssProperty::MarginRight(_) => CssPropertyType::MarginRight,
2877            CssProperty::MarginBottom(_) => CssPropertyType::MarginBottom,
2878            CssProperty::BorderTopLeftRadius(_) => CssPropertyType::BorderTopLeftRadius,
2879            CssProperty::BorderTopRightRadius(_) => CssPropertyType::BorderTopRightRadius,
2880            CssProperty::BorderBottomLeftRadius(_) => CssPropertyType::BorderBottomLeftRadius,
2881            CssProperty::BorderBottomRightRadius(_) => CssPropertyType::BorderBottomRightRadius,
2882            CssProperty::BorderTopColor(_) => CssPropertyType::BorderTopColor,
2883            CssProperty::BorderRightColor(_) => CssPropertyType::BorderRightColor,
2884            CssProperty::BorderLeftColor(_) => CssPropertyType::BorderLeftColor,
2885            CssProperty::BorderBottomColor(_) => CssPropertyType::BorderBottomColor,
2886            CssProperty::BorderTopStyle(_) => CssPropertyType::BorderTopStyle,
2887            CssProperty::BorderRightStyle(_) => CssPropertyType::BorderRightStyle,
2888            CssProperty::BorderLeftStyle(_) => CssPropertyType::BorderLeftStyle,
2889            CssProperty::BorderBottomStyle(_) => CssPropertyType::BorderBottomStyle,
2890            CssProperty::BorderTopWidth(_) => CssPropertyType::BorderTopWidth,
2891            CssProperty::BorderRightWidth(_) => CssPropertyType::BorderRightWidth,
2892            CssProperty::BorderLeftWidth(_) => CssPropertyType::BorderLeftWidth,
2893            CssProperty::BorderBottomWidth(_) => CssPropertyType::BorderBottomWidth,
2894            CssProperty::BoxShadowLeft(_) => CssPropertyType::BoxShadowLeft,
2895            CssProperty::BoxShadowRight(_) => CssPropertyType::BoxShadowRight,
2896            CssProperty::BoxShadowTop(_) => CssPropertyType::BoxShadowTop,
2897            CssProperty::BoxShadowBottom(_) => CssPropertyType::BoxShadowBottom,
2898            CssProperty::ScrollbarStyle(_) => CssPropertyType::ScrollbarStyle,
2899            CssProperty::Opacity(_) => CssPropertyType::Opacity,
2900            CssProperty::Transform(_) => CssPropertyType::Transform,
2901            CssProperty::PerspectiveOrigin(_) => CssPropertyType::PerspectiveOrigin,
2902            CssProperty::TransformOrigin(_) => CssPropertyType::TransformOrigin,
2903            CssProperty::BackfaceVisibility(_) => CssPropertyType::BackfaceVisibility,
2904            CssProperty::MixBlendMode(_) => CssPropertyType::MixBlendMode,
2905            CssProperty::Filter(_) => CssPropertyType::Filter,
2906            CssProperty::BackdropFilter(_) => CssPropertyType::BackdropFilter,
2907            CssProperty::TextShadow(_) => CssPropertyType::TextShadow,
2908        }
2909    }
2910
2911    // const constructors for easier API access
2912
2913    pub const fn none(prop_type: CssPropertyType) -> Self {
2914        css_property_from_type!(prop_type, None)
2915    }
2916    pub const fn auto(prop_type: CssPropertyType) -> Self {
2917        css_property_from_type!(prop_type, Auto)
2918    }
2919    pub const fn initial(prop_type: CssPropertyType) -> Self {
2920        css_property_from_type!(prop_type, Initial)
2921    }
2922    pub const fn inherit(prop_type: CssPropertyType) -> Self {
2923        css_property_from_type!(prop_type, Inherit)
2924    }
2925
2926    pub const fn text_color(input: StyleTextColor) -> Self {
2927        CssProperty::TextColor(CssPropertyValue::Exact(input))
2928    }
2929    pub const fn font_size(input: StyleFontSize) -> Self {
2930        CssProperty::FontSize(CssPropertyValue::Exact(input))
2931    }
2932    pub const fn font_family(input: StyleFontFamilyVec) -> Self {
2933        CssProperty::FontFamily(CssPropertyValue::Exact(input))
2934    }
2935    pub const fn text_align(input: StyleTextAlign) -> Self {
2936        CssProperty::TextAlign(CssPropertyValue::Exact(input))
2937    }
2938    pub const fn letter_spacing(input: StyleLetterSpacing) -> Self {
2939        CssProperty::LetterSpacing(CssPropertyValue::Exact(input))
2940    }
2941    pub const fn line_height(input: StyleLineHeight) -> Self {
2942        CssProperty::LineHeight(CssPropertyValue::Exact(input))
2943    }
2944    pub const fn word_spacing(input: StyleWordSpacing) -> Self {
2945        CssProperty::WordSpacing(CssPropertyValue::Exact(input))
2946    }
2947    pub const fn tab_width(input: StyleTabWidth) -> Self {
2948        CssProperty::TabWidth(CssPropertyValue::Exact(input))
2949    }
2950    pub const fn cursor(input: StyleCursor) -> Self {
2951        CssProperty::Cursor(CssPropertyValue::Exact(input))
2952    }
2953    pub const fn display(input: LayoutDisplay) -> Self {
2954        CssProperty::Display(CssPropertyValue::Exact(input))
2955    }
2956    pub const fn float(input: LayoutFloat) -> Self {
2957        CssProperty::Float(CssPropertyValue::Exact(input))
2958    }
2959    pub const fn box_sizing(input: LayoutBoxSizing) -> Self {
2960        CssProperty::BoxSizing(CssPropertyValue::Exact(input))
2961    }
2962    pub const fn width(input: LayoutWidth) -> Self {
2963        CssProperty::Width(CssPropertyValue::Exact(input))
2964    }
2965    pub const fn height(input: LayoutHeight) -> Self {
2966        CssProperty::Height(CssPropertyValue::Exact(input))
2967    }
2968    pub const fn min_width(input: LayoutMinWidth) -> Self {
2969        CssProperty::MinWidth(CssPropertyValue::Exact(input))
2970    }
2971    pub const fn min_height(input: LayoutMinHeight) -> Self {
2972        CssProperty::MinHeight(CssPropertyValue::Exact(input))
2973    }
2974    pub const fn max_width(input: LayoutMaxWidth) -> Self {
2975        CssProperty::MaxWidth(CssPropertyValue::Exact(input))
2976    }
2977    pub const fn max_height(input: LayoutMaxHeight) -> Self {
2978        CssProperty::MaxHeight(CssPropertyValue::Exact(input))
2979    }
2980    pub const fn position(input: LayoutPosition) -> Self {
2981        CssProperty::Position(CssPropertyValue::Exact(input))
2982    }
2983    pub const fn top(input: LayoutTop) -> Self {
2984        CssProperty::Top(CssPropertyValue::Exact(input))
2985    }
2986    pub const fn right(input: LayoutRight) -> Self {
2987        CssProperty::Right(CssPropertyValue::Exact(input))
2988    }
2989    pub const fn left(input: LayoutLeft) -> Self {
2990        CssProperty::Left(CssPropertyValue::Exact(input))
2991    }
2992    pub const fn bottom(input: LayoutBottom) -> Self {
2993        CssProperty::Bottom(CssPropertyValue::Exact(input))
2994    }
2995    pub const fn flex_wrap(input: LayoutFlexWrap) -> Self {
2996        CssProperty::FlexWrap(CssPropertyValue::Exact(input))
2997    }
2998    pub const fn flex_direction(input: LayoutFlexDirection) -> Self {
2999        CssProperty::FlexDirection(CssPropertyValue::Exact(input))
3000    }
3001    pub const fn flex_grow(input: LayoutFlexGrow) -> Self {
3002        CssProperty::FlexGrow(CssPropertyValue::Exact(input))
3003    }
3004    pub const fn flex_shrink(input: LayoutFlexShrink) -> Self {
3005        CssProperty::FlexShrink(CssPropertyValue::Exact(input))
3006    }
3007    pub const fn justify_content(input: LayoutJustifyContent) -> Self {
3008        CssProperty::JustifyContent(CssPropertyValue::Exact(input))
3009    }
3010    pub const fn align_items(input: LayoutAlignItems) -> Self {
3011        CssProperty::AlignItems(CssPropertyValue::Exact(input))
3012    }
3013    pub const fn align_content(input: LayoutAlignContent) -> Self {
3014        CssProperty::AlignContent(CssPropertyValue::Exact(input))
3015    }
3016    pub const fn background_content(input: StyleBackgroundContentVec) -> Self {
3017        CssProperty::BackgroundContent(CssPropertyValue::Exact(input))
3018    }
3019    pub const fn background_position(input: StyleBackgroundPositionVec) -> Self {
3020        CssProperty::BackgroundPosition(CssPropertyValue::Exact(input))
3021    }
3022    pub const fn background_size(input: StyleBackgroundSizeVec) -> Self {
3023        CssProperty::BackgroundSize(CssPropertyValue::Exact(input))
3024    }
3025    pub const fn background_repeat(input: StyleBackgroundRepeatVec) -> Self {
3026        CssProperty::BackgroundRepeat(CssPropertyValue::Exact(input))
3027    }
3028    pub const fn overflow_x(input: LayoutOverflow) -> Self {
3029        CssProperty::OverflowX(CssPropertyValue::Exact(input))
3030    }
3031    pub const fn overflow_y(input: LayoutOverflow) -> Self {
3032        CssProperty::OverflowY(CssPropertyValue::Exact(input))
3033    }
3034    pub const fn padding_top(input: LayoutPaddingTop) -> Self {
3035        CssProperty::PaddingTop(CssPropertyValue::Exact(input))
3036    }
3037    pub const fn padding_left(input: LayoutPaddingLeft) -> Self {
3038        CssProperty::PaddingLeft(CssPropertyValue::Exact(input))
3039    }
3040    pub const fn padding_right(input: LayoutPaddingRight) -> Self {
3041        CssProperty::PaddingRight(CssPropertyValue::Exact(input))
3042    }
3043    pub const fn padding_bottom(input: LayoutPaddingBottom) -> Self {
3044        CssProperty::PaddingBottom(CssPropertyValue::Exact(input))
3045    }
3046    pub const fn margin_top(input: LayoutMarginTop) -> Self {
3047        CssProperty::MarginTop(CssPropertyValue::Exact(input))
3048    }
3049    pub const fn margin_left(input: LayoutMarginLeft) -> Self {
3050        CssProperty::MarginLeft(CssPropertyValue::Exact(input))
3051    }
3052    pub const fn margin_right(input: LayoutMarginRight) -> Self {
3053        CssProperty::MarginRight(CssPropertyValue::Exact(input))
3054    }
3055    pub const fn margin_bottom(input: LayoutMarginBottom) -> Self {
3056        CssProperty::MarginBottom(CssPropertyValue::Exact(input))
3057    }
3058    pub const fn border_top_left_radius(input: StyleBorderTopLeftRadius) -> Self {
3059        CssProperty::BorderTopLeftRadius(CssPropertyValue::Exact(input))
3060    }
3061    pub const fn border_top_right_radius(input: StyleBorderTopRightRadius) -> Self {
3062        CssProperty::BorderTopRightRadius(CssPropertyValue::Exact(input))
3063    }
3064    pub const fn border_bottom_left_radius(input: StyleBorderBottomLeftRadius) -> Self {
3065        CssProperty::BorderBottomLeftRadius(CssPropertyValue::Exact(input))
3066    }
3067    pub const fn border_bottom_right_radius(input: StyleBorderBottomRightRadius) -> Self {
3068        CssProperty::BorderBottomRightRadius(CssPropertyValue::Exact(input))
3069    }
3070    pub const fn border_top_color(input: StyleBorderTopColor) -> Self {
3071        CssProperty::BorderTopColor(CssPropertyValue::Exact(input))
3072    }
3073    pub const fn border_right_color(input: StyleBorderRightColor) -> Self {
3074        CssProperty::BorderRightColor(CssPropertyValue::Exact(input))
3075    }
3076    pub const fn border_left_color(input: StyleBorderLeftColor) -> Self {
3077        CssProperty::BorderLeftColor(CssPropertyValue::Exact(input))
3078    }
3079    pub const fn border_bottom_color(input: StyleBorderBottomColor) -> Self {
3080        CssProperty::BorderBottomColor(CssPropertyValue::Exact(input))
3081    }
3082    pub const fn border_top_style(input: StyleBorderTopStyle) -> Self {
3083        CssProperty::BorderTopStyle(CssPropertyValue::Exact(input))
3084    }
3085    pub const fn border_right_style(input: StyleBorderRightStyle) -> Self {
3086        CssProperty::BorderRightStyle(CssPropertyValue::Exact(input))
3087    }
3088    pub const fn border_left_style(input: StyleBorderLeftStyle) -> Self {
3089        CssProperty::BorderLeftStyle(CssPropertyValue::Exact(input))
3090    }
3091    pub const fn border_bottom_style(input: StyleBorderBottomStyle) -> Self {
3092        CssProperty::BorderBottomStyle(CssPropertyValue::Exact(input))
3093    }
3094    pub const fn border_top_width(input: LayoutBorderTopWidth) -> Self {
3095        CssProperty::BorderTopWidth(CssPropertyValue::Exact(input))
3096    }
3097    pub const fn border_right_width(input: LayoutBorderRightWidth) -> Self {
3098        CssProperty::BorderRightWidth(CssPropertyValue::Exact(input))
3099    }
3100    pub const fn border_left_width(input: LayoutBorderLeftWidth) -> Self {
3101        CssProperty::BorderLeftWidth(CssPropertyValue::Exact(input))
3102    }
3103    pub const fn border_bottom_width(input: LayoutBorderBottomWidth) -> Self {
3104        CssProperty::BorderBottomWidth(CssPropertyValue::Exact(input))
3105    }
3106    pub const fn box_shadow_left(input: StyleBoxShadow) -> Self {
3107        CssProperty::BoxShadowLeft(CssPropertyValue::Exact(input))
3108    }
3109    pub const fn box_shadow_right(input: StyleBoxShadow) -> Self {
3110        CssProperty::BoxShadowRight(CssPropertyValue::Exact(input))
3111    }
3112    pub const fn box_shadow_top(input: StyleBoxShadow) -> Self {
3113        CssProperty::BoxShadowTop(CssPropertyValue::Exact(input))
3114    }
3115    pub const fn box_shadow_bottom(input: StyleBoxShadow) -> Self {
3116        CssProperty::BoxShadowBottom(CssPropertyValue::Exact(input))
3117    }
3118    pub const fn opacity(input: StyleOpacity) -> Self {
3119        CssProperty::Opacity(CssPropertyValue::Exact(input))
3120    }
3121    pub const fn transform(input: StyleTransformVec) -> Self {
3122        CssProperty::Transform(CssPropertyValue::Exact(input))
3123    }
3124    pub const fn transform_origin(input: StyleTransformOrigin) -> Self {
3125        CssProperty::TransformOrigin(CssPropertyValue::Exact(input))
3126    }
3127    pub const fn perspective_origin(input: StylePerspectiveOrigin) -> Self {
3128        CssProperty::PerspectiveOrigin(CssPropertyValue::Exact(input))
3129    }
3130    pub const fn backface_visiblity(input: StyleBackfaceVisibility) -> Self {
3131        CssProperty::BackfaceVisibility(CssPropertyValue::Exact(input))
3132    }
3133
3134    // functions that downcast to the concrete CSS type (style)
3135
3136    pub const fn as_background_content(&self) -> Option<&StyleBackgroundContentVecValue> {
3137        match self {
3138            CssProperty::BackgroundContent(f) => Some(f),
3139            _ => None,
3140        }
3141    }
3142    pub const fn as_background_position(&self) -> Option<&StyleBackgroundPositionVecValue> {
3143        match self {
3144            CssProperty::BackgroundPosition(f) => Some(f),
3145            _ => None,
3146        }
3147    }
3148    pub const fn as_background_size(&self) -> Option<&StyleBackgroundSizeVecValue> {
3149        match self {
3150            CssProperty::BackgroundSize(f) => Some(f),
3151            _ => None,
3152        }
3153    }
3154    pub const fn as_background_repeat(&self) -> Option<&StyleBackgroundRepeatVecValue> {
3155        match self {
3156            CssProperty::BackgroundRepeat(f) => Some(f),
3157            _ => None,
3158        }
3159    }
3160    pub const fn as_font_size(&self) -> Option<&StyleFontSizeValue> {
3161        match self {
3162            CssProperty::FontSize(f) => Some(f),
3163            _ => None,
3164        }
3165    }
3166    pub const fn as_font_family(&self) -> Option<&StyleFontFamilyVecValue> {
3167        match self {
3168            CssProperty::FontFamily(f) => Some(f),
3169            _ => None,
3170        }
3171    }
3172    pub const fn as_text_color(&self) -> Option<&StyleTextColorValue> {
3173        match self {
3174            CssProperty::TextColor(f) => Some(f),
3175            _ => None,
3176        }
3177    }
3178    pub const fn as_text_align(&self) -> Option<&StyleTextAlignValue> {
3179        match self {
3180            CssProperty::TextAlign(f) => Some(f),
3181            _ => None,
3182        }
3183    }
3184    pub const fn as_line_height(&self) -> Option<&StyleLineHeightValue> {
3185        match self {
3186            CssProperty::LineHeight(f) => Some(f),
3187            _ => None,
3188        }
3189    }
3190    pub const fn as_letter_spacing(&self) -> Option<&StyleLetterSpacingValue> {
3191        match self {
3192            CssProperty::LetterSpacing(f) => Some(f),
3193            _ => None,
3194        }
3195    }
3196    pub const fn as_word_spacing(&self) -> Option<&StyleWordSpacingValue> {
3197        match self {
3198            CssProperty::WordSpacing(f) => Some(f),
3199            _ => None,
3200        }
3201    }
3202    pub const fn as_tab_width(&self) -> Option<&StyleTabWidthValue> {
3203        match self {
3204            CssProperty::TabWidth(f) => Some(f),
3205            _ => None,
3206        }
3207    }
3208    pub const fn as_cursor(&self) -> Option<&StyleCursorValue> {
3209        match self {
3210            CssProperty::Cursor(f) => Some(f),
3211            _ => None,
3212        }
3213    }
3214    pub const fn as_box_shadow_left(&self) -> Option<&StyleBoxShadowValue> {
3215        match self {
3216            CssProperty::BoxShadowLeft(f) => Some(f),
3217            _ => None,
3218        }
3219    }
3220    pub const fn as_box_shadow_right(&self) -> Option<&StyleBoxShadowValue> {
3221        match self {
3222            CssProperty::BoxShadowRight(f) => Some(f),
3223            _ => None,
3224        }
3225    }
3226    pub const fn as_box_shadow_top(&self) -> Option<&StyleBoxShadowValue> {
3227        match self {
3228            CssProperty::BoxShadowTop(f) => Some(f),
3229            _ => None,
3230        }
3231    }
3232    pub const fn as_box_shadow_bottom(&self) -> Option<&StyleBoxShadowValue> {
3233        match self {
3234            CssProperty::BoxShadowBottom(f) => Some(f),
3235            _ => None,
3236        }
3237    }
3238    pub const fn as_border_top_color(&self) -> Option<&StyleBorderTopColorValue> {
3239        match self {
3240            CssProperty::BorderTopColor(f) => Some(f),
3241            _ => None,
3242        }
3243    }
3244    pub const fn as_border_left_color(&self) -> Option<&StyleBorderLeftColorValue> {
3245        match self {
3246            CssProperty::BorderLeftColor(f) => Some(f),
3247            _ => None,
3248        }
3249    }
3250    pub const fn as_border_right_color(&self) -> Option<&StyleBorderRightColorValue> {
3251        match self {
3252            CssProperty::BorderRightColor(f) => Some(f),
3253            _ => None,
3254        }
3255    }
3256    pub const fn as_border_bottom_color(&self) -> Option<&StyleBorderBottomColorValue> {
3257        match self {
3258            CssProperty::BorderBottomColor(f) => Some(f),
3259            _ => None,
3260        }
3261    }
3262    pub const fn as_border_top_style(&self) -> Option<&StyleBorderTopStyleValue> {
3263        match self {
3264            CssProperty::BorderTopStyle(f) => Some(f),
3265            _ => None,
3266        }
3267    }
3268    pub const fn as_border_left_style(&self) -> Option<&StyleBorderLeftStyleValue> {
3269        match self {
3270            CssProperty::BorderLeftStyle(f) => Some(f),
3271            _ => None,
3272        }
3273    }
3274    pub const fn as_border_right_style(&self) -> Option<&StyleBorderRightStyleValue> {
3275        match self {
3276            CssProperty::BorderRightStyle(f) => Some(f),
3277            _ => None,
3278        }
3279    }
3280    pub const fn as_border_bottom_style(&self) -> Option<&StyleBorderBottomStyleValue> {
3281        match self {
3282            CssProperty::BorderBottomStyle(f) => Some(f),
3283            _ => None,
3284        }
3285    }
3286    pub const fn as_border_top_left_radius(&self) -> Option<&StyleBorderTopLeftRadiusValue> {
3287        match self {
3288            CssProperty::BorderTopLeftRadius(f) => Some(f),
3289            _ => None,
3290        }
3291    }
3292    pub const fn as_border_top_right_radius(&self) -> Option<&StyleBorderTopRightRadiusValue> {
3293        match self {
3294            CssProperty::BorderTopRightRadius(f) => Some(f),
3295            _ => None,
3296        }
3297    }
3298    pub const fn as_border_bottom_left_radius(&self) -> Option<&StyleBorderBottomLeftRadiusValue> {
3299        match self {
3300            CssProperty::BorderBottomLeftRadius(f) => Some(f),
3301            _ => None,
3302        }
3303    }
3304    pub const fn as_border_bottom_right_radius(
3305        &self,
3306    ) -> Option<&StyleBorderBottomRightRadiusValue> {
3307        match self {
3308            CssProperty::BorderBottomRightRadius(f) => Some(f),
3309            _ => None,
3310        }
3311    }
3312    pub const fn as_opacity(&self) -> Option<&StyleOpacityValue> {
3313        match self {
3314            CssProperty::Opacity(f) => Some(f),
3315            _ => None,
3316        }
3317    }
3318    pub const fn as_transform(&self) -> Option<&StyleTransformVecValue> {
3319        match self {
3320            CssProperty::Transform(f) => Some(f),
3321            _ => None,
3322        }
3323    }
3324    pub const fn as_transform_origin(&self) -> Option<&StyleTransformOriginValue> {
3325        match self {
3326            CssProperty::TransformOrigin(f) => Some(f),
3327            _ => None,
3328        }
3329    }
3330    pub const fn as_perspective_origin(&self) -> Option<&StylePerspectiveOriginValue> {
3331        match self {
3332            CssProperty::PerspectiveOrigin(f) => Some(f),
3333            _ => None,
3334        }
3335    }
3336    pub const fn as_backface_visibility(&self) -> Option<&StyleBackfaceVisibilityValue> {
3337        match self {
3338            CssProperty::BackfaceVisibility(f) => Some(f),
3339            _ => None,
3340        }
3341    }
3342    pub const fn as_mix_blend_mode(&self) -> Option<&StyleMixBlendModeValue> {
3343        match self {
3344            CssProperty::MixBlendMode(f) => Some(f),
3345            _ => None,
3346        }
3347    }
3348    pub const fn as_filter(&self) -> Option<&StyleFilterVecValue> {
3349        match self {
3350            CssProperty::Filter(f) => Some(f),
3351            _ => None,
3352        }
3353    }
3354    pub const fn as_backdrop_filter(&self) -> Option<&StyleFilterVecValue> {
3355        match self {
3356            CssProperty::BackdropFilter(f) => Some(f),
3357            _ => None,
3358        }
3359    }
3360    pub const fn as_text_shadow(&self) -> Option<&StyleBoxShadowValue> {
3361        match self {
3362            CssProperty::TextShadow(f) => Some(f),
3363            _ => None,
3364        }
3365    }
3366
3367    // functions that downcast to the concrete CSS type (layout)
3368
3369    pub const fn as_display(&self) -> Option<&LayoutDisplayValue> {
3370        match self {
3371            CssProperty::Display(f) => Some(f),
3372            _ => None,
3373        }
3374    }
3375    pub const fn as_float(&self) -> Option<&LayoutFloatValue> {
3376        match self {
3377            CssProperty::Float(f) => Some(f),
3378            _ => None,
3379        }
3380    }
3381    pub const fn as_box_sizing(&self) -> Option<&LayoutBoxSizingValue> {
3382        match self {
3383            CssProperty::BoxSizing(f) => Some(f),
3384            _ => None,
3385        }
3386    }
3387    pub const fn as_width(&self) -> Option<&LayoutWidthValue> {
3388        match self {
3389            CssProperty::Width(f) => Some(f),
3390            _ => None,
3391        }
3392    }
3393    pub const fn as_height(&self) -> Option<&LayoutHeightValue> {
3394        match self {
3395            CssProperty::Height(f) => Some(f),
3396            _ => None,
3397        }
3398    }
3399    pub const fn as_min_width(&self) -> Option<&LayoutMinWidthValue> {
3400        match self {
3401            CssProperty::MinWidth(f) => Some(f),
3402            _ => None,
3403        }
3404    }
3405    pub const fn as_min_height(&self) -> Option<&LayoutMinHeightValue> {
3406        match self {
3407            CssProperty::MinHeight(f) => Some(f),
3408            _ => None,
3409        }
3410    }
3411    pub const fn as_max_width(&self) -> Option<&LayoutMaxWidthValue> {
3412        match self {
3413            CssProperty::MaxWidth(f) => Some(f),
3414            _ => None,
3415        }
3416    }
3417    pub const fn as_max_height(&self) -> Option<&LayoutMaxHeightValue> {
3418        match self {
3419            CssProperty::MaxHeight(f) => Some(f),
3420            _ => None,
3421        }
3422    }
3423    pub const fn as_position(&self) -> Option<&LayoutPositionValue> {
3424        match self {
3425            CssProperty::Position(f) => Some(f),
3426            _ => None,
3427        }
3428    }
3429    pub const fn as_top(&self) -> Option<&LayoutTopValue> {
3430        match self {
3431            CssProperty::Top(f) => Some(f),
3432            _ => None,
3433        }
3434    }
3435    pub const fn as_bottom(&self) -> Option<&LayoutBottomValue> {
3436        match self {
3437            CssProperty::Bottom(f) => Some(f),
3438            _ => None,
3439        }
3440    }
3441    pub const fn as_right(&self) -> Option<&LayoutRightValue> {
3442        match self {
3443            CssProperty::Right(f) => Some(f),
3444            _ => None,
3445        }
3446    }
3447    pub const fn as_left(&self) -> Option<&LayoutLeftValue> {
3448        match self {
3449            CssProperty::Left(f) => Some(f),
3450            _ => None,
3451        }
3452    }
3453    pub const fn as_padding_top(&self) -> Option<&LayoutPaddingTopValue> {
3454        match self {
3455            CssProperty::PaddingTop(f) => Some(f),
3456            _ => None,
3457        }
3458    }
3459    pub const fn as_padding_bottom(&self) -> Option<&LayoutPaddingBottomValue> {
3460        match self {
3461            CssProperty::PaddingBottom(f) => Some(f),
3462            _ => None,
3463        }
3464    }
3465    pub const fn as_padding_left(&self) -> Option<&LayoutPaddingLeftValue> {
3466        match self {
3467            CssProperty::PaddingLeft(f) => Some(f),
3468            _ => None,
3469        }
3470    }
3471    pub const fn as_padding_right(&self) -> Option<&LayoutPaddingRightValue> {
3472        match self {
3473            CssProperty::PaddingRight(f) => Some(f),
3474            _ => None,
3475        }
3476    }
3477    pub const fn as_margin_top(&self) -> Option<&LayoutMarginTopValue> {
3478        match self {
3479            CssProperty::MarginTop(f) => Some(f),
3480            _ => None,
3481        }
3482    }
3483    pub const fn as_margin_bottom(&self) -> Option<&LayoutMarginBottomValue> {
3484        match self {
3485            CssProperty::MarginBottom(f) => Some(f),
3486            _ => None,
3487        }
3488    }
3489    pub const fn as_margin_left(&self) -> Option<&LayoutMarginLeftValue> {
3490        match self {
3491            CssProperty::MarginLeft(f) => Some(f),
3492            _ => None,
3493        }
3494    }
3495    pub const fn as_margin_right(&self) -> Option<&LayoutMarginRightValue> {
3496        match self {
3497            CssProperty::MarginRight(f) => Some(f),
3498            _ => None,
3499        }
3500    }
3501    pub const fn as_border_top_width(&self) -> Option<&LayoutBorderTopWidthValue> {
3502        match self {
3503            CssProperty::BorderTopWidth(f) => Some(f),
3504            _ => None,
3505        }
3506    }
3507    pub const fn as_border_left_width(&self) -> Option<&LayoutBorderLeftWidthValue> {
3508        match self {
3509            CssProperty::BorderLeftWidth(f) => Some(f),
3510            _ => None,
3511        }
3512    }
3513    pub const fn as_border_right_width(&self) -> Option<&LayoutBorderRightWidthValue> {
3514        match self {
3515            CssProperty::BorderRightWidth(f) => Some(f),
3516            _ => None,
3517        }
3518    }
3519    pub const fn as_border_bottom_width(&self) -> Option<&LayoutBorderBottomWidthValue> {
3520        match self {
3521            CssProperty::BorderBottomWidth(f) => Some(f),
3522            _ => None,
3523        }
3524    }
3525    pub const fn as_overflow_x(&self) -> Option<&LayoutOverflowValue> {
3526        match self {
3527            CssProperty::OverflowX(f) => Some(f),
3528            _ => None,
3529        }
3530    }
3531    pub const fn as_overflow_y(&self) -> Option<&LayoutOverflowValue> {
3532        match self {
3533            CssProperty::OverflowY(f) => Some(f),
3534            _ => None,
3535        }
3536    }
3537    pub const fn as_direction(&self) -> Option<&LayoutFlexDirectionValue> {
3538        match self {
3539            CssProperty::FlexDirection(f) => Some(f),
3540            _ => None,
3541        }
3542    }
3543    pub const fn as_flex_wrap(&self) -> Option<&LayoutFlexWrapValue> {
3544        match self {
3545            CssProperty::FlexWrap(f) => Some(f),
3546            _ => None,
3547        }
3548    }
3549    pub const fn as_flex_grow(&self) -> Option<&LayoutFlexGrowValue> {
3550        match self {
3551            CssProperty::FlexGrow(f) => Some(f),
3552            _ => None,
3553        }
3554    }
3555    pub const fn as_flex_shrink(&self) -> Option<&LayoutFlexShrinkValue> {
3556        match self {
3557            CssProperty::FlexShrink(f) => Some(f),
3558            _ => None,
3559        }
3560    }
3561    pub const fn as_justify_content(&self) -> Option<&LayoutJustifyContentValue> {
3562        match self {
3563            CssProperty::JustifyContent(f) => Some(f),
3564            _ => None,
3565        }
3566    }
3567    pub const fn as_align_items(&self) -> Option<&LayoutAlignItemsValue> {
3568        match self {
3569            CssProperty::AlignItems(f) => Some(f),
3570            _ => None,
3571        }
3572    }
3573    pub const fn as_align_content(&self) -> Option<&LayoutAlignContentValue> {
3574        match self {
3575            CssProperty::AlignContent(f) => Some(f),
3576            _ => None,
3577        }
3578    }
3579}
3580
3581macro_rules! impl_from_css_prop {
3582    ($a:ident, $b:ident:: $enum_type:ident) => {
3583        impl From<$a> for $b {
3584            fn from(e: $a) -> Self {
3585                $b::$enum_type(CssPropertyValue::from(e))
3586            }
3587        }
3588    };
3589}
3590
3591impl_from_css_prop!(StyleTextColor, CssProperty::TextColor);
3592impl_from_css_prop!(StyleFontSize, CssProperty::FontSize);
3593impl_from_css_prop!(StyleFontFamilyVec, CssProperty::FontFamily);
3594impl_from_css_prop!(StyleTextAlign, CssProperty::TextAlign);
3595impl_from_css_prop!(StyleLetterSpacing, CssProperty::LetterSpacing);
3596impl_from_css_prop!(StyleLineHeight, CssProperty::LineHeight);
3597impl_from_css_prop!(StyleWordSpacing, CssProperty::WordSpacing);
3598impl_from_css_prop!(StyleTabWidth, CssProperty::TabWidth);
3599impl_from_css_prop!(StyleCursor, CssProperty::Cursor);
3600impl_from_css_prop!(LayoutDisplay, CssProperty::Display);
3601impl_from_css_prop!(LayoutFloat, CssProperty::Float);
3602impl_from_css_prop!(LayoutBoxSizing, CssProperty::BoxSizing);
3603impl_from_css_prop!(LayoutWidth, CssProperty::Width);
3604impl_from_css_prop!(LayoutHeight, CssProperty::Height);
3605impl_from_css_prop!(LayoutMinWidth, CssProperty::MinWidth);
3606impl_from_css_prop!(LayoutMinHeight, CssProperty::MinHeight);
3607impl_from_css_prop!(LayoutMaxWidth, CssProperty::MaxWidth);
3608impl_from_css_prop!(LayoutMaxHeight, CssProperty::MaxHeight);
3609impl_from_css_prop!(LayoutPosition, CssProperty::Position);
3610impl_from_css_prop!(LayoutTop, CssProperty::Top);
3611impl_from_css_prop!(LayoutRight, CssProperty::Right);
3612impl_from_css_prop!(LayoutLeft, CssProperty::Left);
3613impl_from_css_prop!(LayoutBottom, CssProperty::Bottom);
3614impl_from_css_prop!(LayoutFlexWrap, CssProperty::FlexWrap);
3615impl_from_css_prop!(LayoutFlexDirection, CssProperty::FlexDirection);
3616impl_from_css_prop!(LayoutFlexGrow, CssProperty::FlexGrow);
3617impl_from_css_prop!(LayoutFlexShrink, CssProperty::FlexShrink);
3618impl_from_css_prop!(LayoutJustifyContent, CssProperty::JustifyContent);
3619impl_from_css_prop!(LayoutAlignItems, CssProperty::AlignItems);
3620impl_from_css_prop!(LayoutAlignContent, CssProperty::AlignContent);
3621impl_from_css_prop!(StyleBackgroundContentVec, CssProperty::BackgroundContent);
3622impl_from_css_prop!(StyleBackgroundPositionVec, CssProperty::BackgroundPosition);
3623impl_from_css_prop!(StyleBackgroundSizeVec, CssProperty::BackgroundSize);
3624impl_from_css_prop!(StyleBackgroundRepeatVec, CssProperty::BackgroundRepeat);
3625impl_from_css_prop!(LayoutPaddingTop, CssProperty::PaddingTop);
3626impl_from_css_prop!(LayoutPaddingLeft, CssProperty::PaddingLeft);
3627impl_from_css_prop!(LayoutPaddingRight, CssProperty::PaddingRight);
3628impl_from_css_prop!(LayoutPaddingBottom, CssProperty::PaddingBottom);
3629impl_from_css_prop!(LayoutMarginTop, CssProperty::MarginTop);
3630impl_from_css_prop!(LayoutMarginLeft, CssProperty::MarginLeft);
3631impl_from_css_prop!(LayoutMarginRight, CssProperty::MarginRight);
3632impl_from_css_prop!(LayoutMarginBottom, CssProperty::MarginBottom);
3633impl_from_css_prop!(StyleBorderTopLeftRadius, CssProperty::BorderTopLeftRadius);
3634impl_from_css_prop!(StyleBorderTopRightRadius, CssProperty::BorderTopRightRadius);
3635impl_from_css_prop!(
3636    StyleBorderBottomLeftRadius,
3637    CssProperty::BorderBottomLeftRadius
3638);
3639impl_from_css_prop!(
3640    StyleBorderBottomRightRadius,
3641    CssProperty::BorderBottomRightRadius
3642);
3643impl_from_css_prop!(StyleBorderTopColor, CssProperty::BorderTopColor);
3644impl_from_css_prop!(StyleBorderRightColor, CssProperty::BorderRightColor);
3645impl_from_css_prop!(StyleBorderLeftColor, CssProperty::BorderLeftColor);
3646impl_from_css_prop!(StyleBorderBottomColor, CssProperty::BorderBottomColor);
3647impl_from_css_prop!(StyleBorderTopStyle, CssProperty::BorderTopStyle);
3648impl_from_css_prop!(StyleBorderRightStyle, CssProperty::BorderRightStyle);
3649impl_from_css_prop!(StyleBorderLeftStyle, CssProperty::BorderLeftStyle);
3650impl_from_css_prop!(StyleBorderBottomStyle, CssProperty::BorderBottomStyle);
3651impl_from_css_prop!(LayoutBorderTopWidth, CssProperty::BorderTopWidth);
3652impl_from_css_prop!(LayoutBorderRightWidth, CssProperty::BorderRightWidth);
3653impl_from_css_prop!(LayoutBorderLeftWidth, CssProperty::BorderLeftWidth);
3654impl_from_css_prop!(LayoutBorderBottomWidth, CssProperty::BorderBottomWidth);
3655impl_from_css_prop!(ScrollbarStyle, CssProperty::ScrollbarStyle);
3656impl_from_css_prop!(StyleOpacity, CssProperty::Opacity);
3657impl_from_css_prop!(StyleTransformVec, CssProperty::Transform);
3658impl_from_css_prop!(StyleTransformOrigin, CssProperty::TransformOrigin);
3659impl_from_css_prop!(StylePerspectiveOrigin, CssProperty::PerspectiveOrigin);
3660impl_from_css_prop!(StyleBackfaceVisibility, CssProperty::BackfaceVisibility);
3661impl_from_css_prop!(StyleMixBlendMode, CssProperty::MixBlendMode);
3662
3663/// Multiplier for floating point accuracy. Elements such as px or %
3664/// are only accurate until a certain number of decimal points, therefore
3665/// they have to be casted to isizes in order to make the f32 values
3666/// hash-able: Css has a relatively low precision here, roughly 5 digits, i.e
3667/// `1.00001 == 1.0`
3668const FP_PRECISION_MULTIPLIER: f32 = 1000.0;
3669const FP_PRECISION_MULTIPLIER_CONST: isize = FP_PRECISION_MULTIPLIER as isize;
3670
3671/// Same as PixelValue, but doesn't allow a "%" sign
3672#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3673#[repr(C)]
3674pub struct PixelValueNoPercent {
3675    pub inner: PixelValue,
3676}
3677
3678impl PixelValueNoPercent {
3679    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
3680        self.inner.scale_for_dpi(scale_factor);
3681    }
3682}
3683
3684impl_option!(
3685    PixelValueNoPercent,
3686    OptionPixelValueNoPercent,
3687    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
3688);
3689
3690impl fmt::Display for PixelValueNoPercent {
3691    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3692        write!(f, "{}", self.inner)
3693    }
3694}
3695
3696impl ::core::fmt::Debug for PixelValueNoPercent {
3697    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
3698        write!(f, "{}", self)
3699    }
3700}
3701
3702impl PixelValueNoPercent {
3703    pub fn to_pixels(&self) -> f32 {
3704        self.inner.to_pixels(0.0)
3705    }
3706}
3707
3708/// FloatValue, but associated with a certain metric (i.e. px, em, etc.)
3709#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3710#[repr(C)]
3711pub struct AngleValue {
3712    pub metric: AngleMetric,
3713    pub number: FloatValue,
3714}
3715
3716impl_option!(
3717    AngleValue,
3718    OptionAngleValue,
3719    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
3720);
3721
3722impl fmt::Debug for AngleValue {
3723    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3724        write!(f, "{}", self)
3725    }
3726}
3727
3728// Manual Debug implementation, because the auto-generated one is nearly unreadable
3729impl fmt::Display for AngleValue {
3730    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3731        write!(f, "{}{}", self.number, self.metric)
3732    }
3733}
3734
3735#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3736#[repr(C)]
3737pub enum AngleMetric {
3738    Degree,
3739    Radians,
3740    Grad,
3741    Turn,
3742    Percent,
3743}
3744
3745impl Default for AngleMetric {
3746    fn default() -> AngleMetric {
3747        AngleMetric::Degree
3748    }
3749}
3750
3751impl fmt::Display for AngleMetric {
3752    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3753        use self::AngleMetric::*;
3754        match self {
3755            Degree => write!(f, "deg"),
3756            Radians => write!(f, "rad"),
3757            Grad => write!(f, "grad"),
3758            Turn => write!(f, "turn"),
3759            Percent => write!(f, "%"),
3760        }
3761    }
3762}
3763
3764impl AngleValue {
3765    #[inline]
3766    pub const fn zero() -> Self {
3767        const ZERO_DEG: AngleValue = AngleValue::const_deg(0);
3768        ZERO_DEG
3769    }
3770
3771    /// Same as `PixelValue::px()`, but only accepts whole numbers,
3772    /// since using `f32` in const fn is not yet stabilized.
3773    #[inline]
3774    pub const fn const_deg(value: isize) -> Self {
3775        Self::const_from_metric(AngleMetric::Degree, value)
3776    }
3777
3778    /// Same as `PixelValue::em()`, but only accepts whole numbers,
3779    /// since using `f32` in const fn is not yet stabilized.
3780    #[inline]
3781    pub const fn const_rad(value: isize) -> Self {
3782        Self::const_from_metric(AngleMetric::Radians, value)
3783    }
3784
3785    /// Same as `PixelValue::pt()`, but only accepts whole numbers,
3786    /// since using `f32` in const fn is not yet stabilized.
3787    #[inline]
3788    pub const fn const_grad(value: isize) -> Self {
3789        Self::const_from_metric(AngleMetric::Grad, value)
3790    }
3791
3792    /// Same as `PixelValue::pt()`, but only accepts whole numbers,
3793    /// since using `f32` in const fn is not yet stabilized.
3794    #[inline]
3795    pub const fn const_turn(value: isize) -> Self {
3796        Self::const_from_metric(AngleMetric::Turn, value)
3797    }
3798
3799    #[inline]
3800    pub fn const_percent(value: isize) -> Self {
3801        Self::const_from_metric(AngleMetric::Percent, value)
3802    }
3803
3804    #[inline]
3805    pub const fn const_from_metric(metric: AngleMetric, value: isize) -> Self {
3806        Self {
3807            metric,
3808            number: FloatValue::const_new(value),
3809        }
3810    }
3811
3812    #[inline]
3813    pub fn deg(value: f32) -> Self {
3814        Self::from_metric(AngleMetric::Degree, value)
3815    }
3816
3817    #[inline]
3818    pub fn rad(value: f32) -> Self {
3819        Self::from_metric(AngleMetric::Radians, value)
3820    }
3821
3822    #[inline]
3823    pub fn grad(value: f32) -> Self {
3824        Self::from_metric(AngleMetric::Grad, value)
3825    }
3826
3827    #[inline]
3828    pub fn turn(value: f32) -> Self {
3829        Self::from_metric(AngleMetric::Turn, value)
3830    }
3831
3832    #[inline]
3833    pub fn percent(value: f32) -> Self {
3834        Self::from_metric(AngleMetric::Percent, value)
3835    }
3836
3837    #[inline]
3838    pub fn from_metric(metric: AngleMetric, value: f32) -> Self {
3839        Self {
3840            metric,
3841            number: FloatValue::new(value),
3842        }
3843    }
3844
3845    /// Returns the value of the AngleMetric in degrees
3846    #[inline]
3847    pub fn to_degrees(&self) -> f32 {
3848        let val = match self.metric {
3849            AngleMetric::Degree => self.number.get(),
3850            AngleMetric::Radians => self.number.get() / 400.0 * 360.0,
3851            AngleMetric::Grad => self.number.get() / (2.0 * core::f32::consts::PI) * 360.0,
3852            AngleMetric::Turn => self.number.get() * 360.0,
3853            AngleMetric::Percent => self.number.get() / 100.0 * 360.0,
3854        };
3855
3856        // clamp the degree to a positive value from 0 to 360 (so 410deg = 50deg)
3857        let mut val = val % 360.0;
3858        if val < 0.0 {
3859            val = 360.0 + val;
3860        }
3861        val
3862    }
3863}
3864
3865#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3866#[repr(C)]
3867pub struct PixelValue {
3868    pub metric: SizeMetric,
3869    pub number: FloatValue,
3870}
3871
3872impl PixelValue {
3873    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
3874        self.number = FloatValue::new(self.number.get() * scale_factor);
3875    }
3876}
3877
3878impl fmt::Debug for PixelValue {
3879    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3880        write!(f, "{}{}", self.number, self.metric)
3881    }
3882}
3883
3884// Manual Debug implementation, because the auto-generated one is nearly unreadable
3885impl fmt::Display for PixelValue {
3886    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3887        write!(f, "{}{}", self.number, self.metric)
3888    }
3889}
3890
3891impl fmt::Display for SizeMetric {
3892    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3893        use self::SizeMetric::*;
3894        match self {
3895            Px => write!(f, "px"),
3896            Pt => write!(f, "pt"),
3897            Em => write!(f, "pt"),
3898            Percent => write!(f, "%"),
3899        }
3900    }
3901}
3902
3903impl PixelValue {
3904    #[inline]
3905    pub const fn zero() -> Self {
3906        const ZERO_PX: PixelValue = PixelValue::const_px(0);
3907        ZERO_PX
3908    }
3909
3910    /// Same as `PixelValue::px()`, but only accepts whole numbers,
3911    /// since using `f32` in const fn is not yet stabilized.
3912    #[inline]
3913    pub const fn const_px(value: isize) -> Self {
3914        Self::const_from_metric(SizeMetric::Px, value)
3915    }
3916
3917    /// Same as `PixelValue::em()`, but only accepts whole numbers,
3918    /// since using `f32` in const fn is not yet stabilized.
3919    #[inline]
3920    pub const fn const_em(value: isize) -> Self {
3921        Self::const_from_metric(SizeMetric::Em, value)
3922    }
3923
3924    /// Same as `PixelValue::pt()`, but only accepts whole numbers,
3925    /// since using `f32` in const fn is not yet stabilized.
3926    #[inline]
3927    pub const fn const_pt(value: isize) -> Self {
3928        Self::const_from_metric(SizeMetric::Pt, value)
3929    }
3930
3931    /// Same as `PixelValue::pt()`, but only accepts whole numbers,
3932    /// since using `f32` in const fn is not yet stabilized.
3933    #[inline]
3934    pub const fn const_percent(value: isize) -> Self {
3935        Self::const_from_metric(SizeMetric::Percent, value)
3936    }
3937
3938    #[inline]
3939    pub const fn const_from_metric(metric: SizeMetric, value: isize) -> Self {
3940        Self {
3941            metric,
3942            number: FloatValue::const_new(value),
3943        }
3944    }
3945
3946    #[inline]
3947    pub fn px(value: f32) -> Self {
3948        Self::from_metric(SizeMetric::Px, value)
3949    }
3950
3951    #[inline]
3952    pub fn em(value: f32) -> Self {
3953        Self::from_metric(SizeMetric::Em, value)
3954    }
3955
3956    #[inline]
3957    pub fn pt(value: f32) -> Self {
3958        Self::from_metric(SizeMetric::Pt, value)
3959    }
3960
3961    #[inline]
3962    pub fn percent(value: f32) -> Self {
3963        Self::from_metric(SizeMetric::Percent, value)
3964    }
3965
3966    #[inline]
3967    pub fn from_metric(metric: SizeMetric, value: f32) -> Self {
3968        Self {
3969            metric,
3970            number: FloatValue::new(value),
3971        }
3972    }
3973
3974    #[inline]
3975    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
3976        if self.metric == other.metric {
3977            Self {
3978                metric: self.metric,
3979                number: self.number.interpolate(&other.number, t),
3980            }
3981        } else {
3982            // TODO: how to interpolate between different metrics
3983            // (interpolate between % and em? - currently impossible)
3984            let self_px_interp = self.to_pixels(0.0);
3985            let other_px_interp = other.to_pixels(0.0);
3986            Self::from_metric(
3987                SizeMetric::Px,
3988                self_px_interp + (other_px_interp - self_px_interp) * t,
3989            )
3990        }
3991    }
3992
3993    /// Returns the value of the SizeMetric in pixels
3994    #[inline]
3995    pub fn to_pixels(&self, percent_resolve: f32) -> f32 {
3996        match self.metric {
3997            SizeMetric::Px => self.number.get(),
3998            SizeMetric::Pt => self.number.get() * PT_TO_PX,
3999            SizeMetric::Em => self.number.get() * EM_HEIGHT,
4000            SizeMetric::Percent => self.number.get() / 100.0 * percent_resolve,
4001        }
4002    }
4003}
4004
4005/// Wrapper around FloatValue, represents a percentage instead
4006/// of just being a regular floating-point value, i.e `5` = `5%`
4007#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4008#[repr(C)]
4009pub struct PercentageValue {
4010    number: FloatValue,
4011}
4012
4013impl_option!(
4014    PercentageValue,
4015    OptionPercentageValue,
4016    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
4017);
4018
4019impl fmt::Display for PercentageValue {
4020    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4021        write!(f, "{}%", self.get())
4022    }
4023}
4024
4025impl PercentageValue {
4026    /// Same as `PercentageValue::new()`, but only accepts whole numbers,
4027    /// since using `f32` in const fn is not yet stabilized.
4028    #[inline]
4029    pub const fn const_new(value: isize) -> Self {
4030        Self {
4031            number: FloatValue::const_new(value),
4032        }
4033    }
4034
4035    #[inline]
4036    pub fn new(value: f32) -> Self {
4037        Self {
4038            number: value.into(),
4039        }
4040    }
4041
4042    #[inline]
4043    pub fn get(&self) -> f32 {
4044        self.number.get()
4045    }
4046
4047    #[inline]
4048    pub fn normalized(&self) -> f32 {
4049        self.get() / 100.0
4050    }
4051
4052    #[inline]
4053    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
4054        Self {
4055            number: self.number.interpolate(&other.number, t),
4056        }
4057    }
4058}
4059
4060/// Wrapper around an f32 value that is internally casted to an isize,
4061/// in order to provide hash-ability (to avoid numerical instability).
4062#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4063#[repr(C)]
4064pub struct FloatValue {
4065    pub number: isize,
4066}
4067
4068impl fmt::Display for FloatValue {
4069    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4070        write!(f, "{}", self.get())
4071    }
4072}
4073
4074impl ::core::fmt::Debug for FloatValue {
4075    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
4076        write!(f, "{}", self)
4077    }
4078}
4079
4080impl Default for FloatValue {
4081    fn default() -> Self {
4082        const DEFAULT_FLV: FloatValue = FloatValue::const_new(0);
4083        DEFAULT_FLV
4084    }
4085}
4086
4087impl FloatValue {
4088    /// Same as `FloatValue::new()`, but only accepts whole numbers,
4089    /// since using `f32` in const fn is not yet stabilized.
4090    #[inline]
4091    pub const fn const_new(value: isize) -> Self {
4092        Self {
4093            number: value * FP_PRECISION_MULTIPLIER_CONST,
4094        }
4095    }
4096
4097    #[inline]
4098    pub fn new(value: f32) -> Self {
4099        Self {
4100            number: (value * FP_PRECISION_MULTIPLIER) as isize,
4101        }
4102    }
4103
4104    #[inline]
4105    pub fn get(&self) -> f32 {
4106        self.number as f32 / FP_PRECISION_MULTIPLIER
4107    }
4108
4109    #[inline]
4110    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
4111        let self_val_f32 = self.get();
4112        let other_val_f32 = other.get();
4113        let interpolated = self_val_f32 + ((other_val_f32 - self_val_f32) * t);
4114        Self::new(interpolated)
4115    }
4116}
4117
4118impl From<f32> for FloatValue {
4119    #[inline]
4120    fn from(val: f32) -> Self {
4121        Self::new(val)
4122    }
4123}
4124
4125/// Enum representing the metric associated with a number (px, pt, em, etc.)
4126#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4127#[repr(C)]
4128pub enum SizeMetric {
4129    Px,
4130    Pt,
4131    Em,
4132    Percent,
4133}
4134
4135impl Default for SizeMetric {
4136    fn default() -> Self {
4137        SizeMetric::Px
4138    }
4139}
4140
4141/// Represents a `background-size` attribute
4142#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4143#[repr(C, u8)]
4144pub enum StyleBackgroundSize {
4145    ExactSize([PixelValue; 2]),
4146    Contain,
4147    Cover,
4148}
4149
4150impl StyleBackgroundSize {
4151    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4152        match self {
4153            StyleBackgroundSize::ExactSize(a) => {
4154                for q in a.iter_mut() {
4155                    q.scale_for_dpi(scale_factor);
4156                }
4157            }
4158            _ => {}
4159        }
4160    }
4161}
4162
4163impl Default for StyleBackgroundSize {
4164    fn default() -> Self {
4165        StyleBackgroundSize::Contain
4166    }
4167}
4168
4169impl_vec!(
4170    StyleBackgroundSize,
4171    StyleBackgroundSizeVec,
4172    StyleBackgroundSizeVecDestructor
4173);
4174impl_vec_debug!(StyleBackgroundSize, StyleBackgroundSizeVec);
4175impl_vec_partialord!(StyleBackgroundSize, StyleBackgroundSizeVec);
4176impl_vec_ord!(StyleBackgroundSize, StyleBackgroundSizeVec);
4177impl_vec_clone!(
4178    StyleBackgroundSize,
4179    StyleBackgroundSizeVec,
4180    StyleBackgroundSizeVecDestructor
4181);
4182impl_vec_partialeq!(StyleBackgroundSize, StyleBackgroundSizeVec);
4183impl_vec_eq!(StyleBackgroundSize, StyleBackgroundSizeVec);
4184impl_vec_hash!(StyleBackgroundSize, StyleBackgroundSizeVec);
4185
4186/// Represents a `background-position` attribute
4187#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4188#[repr(C)]
4189pub struct StyleBackgroundPosition {
4190    pub horizontal: BackgroundPositionHorizontal,
4191    pub vertical: BackgroundPositionVertical,
4192}
4193
4194impl StyleBackgroundPosition {
4195    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4196        self.horizontal.scale_for_dpi(scale_factor);
4197        self.vertical.scale_for_dpi(scale_factor);
4198    }
4199}
4200
4201impl_vec!(
4202    StyleBackgroundPosition,
4203    StyleBackgroundPositionVec,
4204    StyleBackgroundPositionVecDestructor
4205);
4206impl_vec_debug!(StyleBackgroundPosition, StyleBackgroundPositionVec);
4207impl_vec_partialord!(StyleBackgroundPosition, StyleBackgroundPositionVec);
4208impl_vec_ord!(StyleBackgroundPosition, StyleBackgroundPositionVec);
4209impl_vec_clone!(
4210    StyleBackgroundPosition,
4211    StyleBackgroundPositionVec,
4212    StyleBackgroundPositionVecDestructor
4213);
4214impl_vec_partialeq!(StyleBackgroundPosition, StyleBackgroundPositionVec);
4215impl_vec_eq!(StyleBackgroundPosition, StyleBackgroundPositionVec);
4216impl_vec_hash!(StyleBackgroundPosition, StyleBackgroundPositionVec);
4217
4218impl Default for StyleBackgroundPosition {
4219    fn default() -> Self {
4220        StyleBackgroundPosition {
4221            horizontal: BackgroundPositionHorizontal::Left,
4222            vertical: BackgroundPositionVertical::Top,
4223        }
4224    }
4225}
4226
4227#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4228#[repr(C, u8)]
4229pub enum BackgroundPositionHorizontal {
4230    Left,
4231    Center,
4232    Right,
4233    Exact(PixelValue),
4234}
4235
4236impl BackgroundPositionHorizontal {
4237    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4238        match self {
4239            BackgroundPositionHorizontal::Exact(s) => {
4240                s.scale_for_dpi(scale_factor);
4241            }
4242            _ => {}
4243        }
4244    }
4245}
4246
4247#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4248#[repr(C, u8)]
4249pub enum BackgroundPositionVertical {
4250    Top,
4251    Center,
4252    Bottom,
4253    Exact(PixelValue),
4254}
4255
4256impl BackgroundPositionVertical {
4257    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4258        match self {
4259            BackgroundPositionVertical::Exact(s) => {
4260                s.scale_for_dpi(scale_factor);
4261            }
4262            _ => {}
4263        }
4264    }
4265}
4266
4267/// Represents a `background-repeat` attribute
4268#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4269#[repr(C)]
4270pub enum StyleBackgroundRepeat {
4271    NoRepeat,
4272    Repeat,
4273    RepeatX,
4274    RepeatY,
4275}
4276
4277impl_vec!(
4278    StyleBackgroundRepeat,
4279    StyleBackgroundRepeatVec,
4280    StyleBackgroundRepeatVecDestructor
4281);
4282impl_vec_debug!(StyleBackgroundRepeat, StyleBackgroundRepeatVec);
4283impl_vec_partialord!(StyleBackgroundRepeat, StyleBackgroundRepeatVec);
4284impl_vec_ord!(StyleBackgroundRepeat, StyleBackgroundRepeatVec);
4285impl_vec_clone!(
4286    StyleBackgroundRepeat,
4287    StyleBackgroundRepeatVec,
4288    StyleBackgroundRepeatVecDestructor
4289);
4290impl_vec_partialeq!(StyleBackgroundRepeat, StyleBackgroundRepeatVec);
4291impl_vec_eq!(StyleBackgroundRepeat, StyleBackgroundRepeatVec);
4292impl_vec_hash!(StyleBackgroundRepeat, StyleBackgroundRepeatVec);
4293
4294impl Default for StyleBackgroundRepeat {
4295    fn default() -> Self {
4296        StyleBackgroundRepeat::Repeat
4297    }
4298}
4299
4300/// Represents a `color` attribute
4301#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4302#[repr(C)]
4303pub struct StyleTextColor {
4304    pub inner: ColorU,
4305}
4306
4307derive_debug_zero!(StyleTextColor);
4308derive_display_zero!(StyleTextColor);
4309
4310impl StyleTextColor {
4311    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
4312        Self {
4313            inner: self.inner.interpolate(&other.inner, t),
4314        }
4315    }
4316}
4317
4318// -- TODO: Technically, border-radius can take two values for each corner!
4319
4320/// Represents a `border-top-width` attribute
4321#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4322#[repr(C)]
4323pub struct StyleBorderTopLeftRadius {
4324    pub inner: PixelValue,
4325}
4326/// Represents a `border-left-width` attribute
4327#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4328#[repr(C)]
4329pub struct StyleBorderBottomLeftRadius {
4330    pub inner: PixelValue,
4331}
4332/// Represents a `border-right-width` attribute
4333#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4334#[repr(C)]
4335pub struct StyleBorderTopRightRadius {
4336    pub inner: PixelValue,
4337}
4338/// Represents a `border-bottom-width` attribute
4339#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4340#[repr(C)]
4341pub struct StyleBorderBottomRightRadius {
4342    pub inner: PixelValue,
4343}
4344
4345impl_pixel_value!(StyleBorderTopLeftRadius);
4346impl_pixel_value!(StyleBorderBottomLeftRadius);
4347impl_pixel_value!(StyleBorderTopRightRadius);
4348impl_pixel_value!(StyleBorderBottomRightRadius);
4349
4350/// Represents a `border-top-width` attribute
4351#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4352#[repr(C)]
4353pub struct LayoutBorderTopWidth {
4354    pub inner: PixelValue,
4355}
4356/// Represents a `border-left-width` attribute
4357#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4358#[repr(C)]
4359pub struct LayoutBorderLeftWidth {
4360    pub inner: PixelValue,
4361}
4362/// Represents a `border-right-width` attribute
4363#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4364#[repr(C)]
4365pub struct LayoutBorderRightWidth {
4366    pub inner: PixelValue,
4367}
4368/// Represents a `border-bottom-width` attribute
4369#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4370#[repr(C)]
4371pub struct LayoutBorderBottomWidth {
4372    pub inner: PixelValue,
4373}
4374
4375impl_pixel_value!(LayoutBorderTopWidth);
4376impl_pixel_value!(LayoutBorderLeftWidth);
4377impl_pixel_value!(LayoutBorderRightWidth);
4378impl_pixel_value!(LayoutBorderBottomWidth);
4379
4380impl CssPropertyValue<StyleBorderTopLeftRadius> {
4381    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4382        match self {
4383            CssPropertyValue::Exact(s) => {
4384                s.scale_for_dpi(scale_factor);
4385            }
4386            _ => {}
4387        }
4388    }
4389}
4390
4391impl CssPropertyValue<StyleBorderTopRightRadius> {
4392    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4393        match self {
4394            CssPropertyValue::Exact(s) => {
4395                s.scale_for_dpi(scale_factor);
4396            }
4397            _ => {}
4398        }
4399    }
4400}
4401
4402impl CssPropertyValue<StyleBorderBottomLeftRadius> {
4403    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4404        match self {
4405            CssPropertyValue::Exact(s) => {
4406                s.scale_for_dpi(scale_factor);
4407            }
4408            _ => {}
4409        }
4410    }
4411}
4412
4413impl CssPropertyValue<StyleBorderBottomRightRadius> {
4414    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4415        match self {
4416            CssPropertyValue::Exact(s) => {
4417                s.scale_for_dpi(scale_factor);
4418            }
4419            _ => {}
4420        }
4421    }
4422}
4423
4424impl CssPropertyValue<LayoutBorderTopWidth> {
4425    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4426        match self {
4427            CssPropertyValue::Exact(s) => {
4428                s.scale_for_dpi(scale_factor);
4429            }
4430            _ => {}
4431        }
4432    }
4433}
4434
4435impl CssPropertyValue<LayoutBorderRightWidth> {
4436    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4437        match self {
4438            CssPropertyValue::Exact(s) => {
4439                s.scale_for_dpi(scale_factor);
4440            }
4441            _ => {}
4442        }
4443    }
4444}
4445
4446impl CssPropertyValue<LayoutBorderBottomWidth> {
4447    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4448        match self {
4449            CssPropertyValue::Exact(s) => {
4450                s.scale_for_dpi(scale_factor);
4451            }
4452            _ => {}
4453        }
4454    }
4455}
4456
4457impl CssPropertyValue<LayoutBorderLeftWidth> {
4458    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4459        match self {
4460            CssPropertyValue::Exact(s) => {
4461                s.scale_for_dpi(scale_factor);
4462            }
4463            _ => {}
4464        }
4465    }
4466}
4467
4468impl StyleBorderTopLeftRadius {
4469    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4470        self.inner.scale_for_dpi(scale_factor);
4471    }
4472}
4473
4474impl StyleBorderTopRightRadius {
4475    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4476        self.inner.scale_for_dpi(scale_factor);
4477    }
4478}
4479
4480impl StyleBorderBottomLeftRadius {
4481    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4482        self.inner.scale_for_dpi(scale_factor);
4483    }
4484}
4485
4486impl StyleBorderBottomRightRadius {
4487    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4488        self.inner.scale_for_dpi(scale_factor);
4489    }
4490}
4491
4492impl LayoutBorderTopWidth {
4493    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4494        self.inner.scale_for_dpi(scale_factor);
4495    }
4496}
4497
4498impl LayoutBorderRightWidth {
4499    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4500        self.inner.scale_for_dpi(scale_factor);
4501    }
4502}
4503
4504impl LayoutBorderBottomWidth {
4505    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4506        self.inner.scale_for_dpi(scale_factor);
4507    }
4508}
4509
4510impl LayoutBorderLeftWidth {
4511    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4512        self.inner.scale_for_dpi(scale_factor);
4513    }
4514}
4515
4516/// Represents a `border-top-width` attribute
4517#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4518#[repr(C)]
4519pub struct StyleBorderTopStyle {
4520    pub inner: BorderStyle,
4521}
4522/// Represents a `border-left-width` attribute
4523#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4524#[repr(C)]
4525pub struct StyleBorderLeftStyle {
4526    pub inner: BorderStyle,
4527}
4528/// Represents a `border-right-width` attribute
4529#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4530#[repr(C)]
4531pub struct StyleBorderRightStyle {
4532    pub inner: BorderStyle,
4533}
4534/// Represents a `border-bottom-width` attribute
4535#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4536#[repr(C)]
4537pub struct StyleBorderBottomStyle {
4538    pub inner: BorderStyle,
4539}
4540
4541derive_debug_zero!(StyleBorderTopStyle);
4542derive_debug_zero!(StyleBorderLeftStyle);
4543derive_debug_zero!(StyleBorderBottomStyle);
4544derive_debug_zero!(StyleBorderRightStyle);
4545
4546derive_display_zero!(StyleBorderTopStyle);
4547derive_display_zero!(StyleBorderLeftStyle);
4548derive_display_zero!(StyleBorderBottomStyle);
4549derive_display_zero!(StyleBorderRightStyle);
4550
4551/// Represents a `border-top-width` attribute
4552#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4553#[repr(C)]
4554pub struct StyleBorderTopColor {
4555    pub inner: ColorU,
4556}
4557/// Represents a `border-left-width` attribute
4558#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4559#[repr(C)]
4560pub struct StyleBorderLeftColor {
4561    pub inner: ColorU,
4562}
4563/// Represents a `border-right-width` attribute
4564#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4565#[repr(C)]
4566pub struct StyleBorderRightColor {
4567    pub inner: ColorU,
4568}
4569/// Represents a `border-bottom-width` attribute
4570#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4571#[repr(C)]
4572pub struct StyleBorderBottomColor {
4573    pub inner: ColorU,
4574}
4575
4576impl StyleBorderTopColor {
4577    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
4578        Self {
4579            inner: self.inner.interpolate(&other.inner, t),
4580        }
4581    }
4582}
4583impl StyleBorderLeftColor {
4584    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
4585        Self {
4586            inner: self.inner.interpolate(&other.inner, t),
4587        }
4588    }
4589}
4590impl StyleBorderRightColor {
4591    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
4592        Self {
4593            inner: self.inner.interpolate(&other.inner, t),
4594        }
4595    }
4596}
4597impl StyleBorderBottomColor {
4598    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
4599        Self {
4600            inner: self.inner.interpolate(&other.inner, t),
4601        }
4602    }
4603}
4604derive_debug_zero!(StyleBorderTopColor);
4605derive_debug_zero!(StyleBorderLeftColor);
4606derive_debug_zero!(StyleBorderRightColor);
4607derive_debug_zero!(StyleBorderBottomColor);
4608
4609derive_display_zero!(StyleBorderTopColor);
4610derive_display_zero!(StyleBorderLeftColor);
4611derive_display_zero!(StyleBorderRightColor);
4612derive_display_zero!(StyleBorderBottomColor);
4613
4614#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4615pub struct StyleBorderSide {
4616    pub border_width: PixelValue,
4617    pub border_style: BorderStyle,
4618    pub border_color: ColorU,
4619}
4620
4621// missing StyleBorderRadius & LayoutRect
4622#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4623#[repr(C)]
4624pub struct StyleBoxShadow {
4625    pub offset: [PixelValueNoPercent; 2],
4626    pub color: ColorU,
4627    pub blur_radius: PixelValueNoPercent,
4628    pub spread_radius: PixelValueNoPercent,
4629    pub clip_mode: BoxShadowClipMode,
4630}
4631
4632impl StyleBoxShadow {
4633    pub fn scale_for_dpi(&mut self, scale_factor: f32) {
4634        for s in self.offset.iter_mut() {
4635            s.scale_for_dpi(scale_factor);
4636        }
4637        self.blur_radius.scale_for_dpi(scale_factor);
4638        self.spread_radius.scale_for_dpi(scale_factor);
4639    }
4640}
4641
4642#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4643#[repr(C, u8)]
4644pub enum StyleBackgroundContent {
4645    LinearGradient(LinearGradient),
4646    RadialGradient(RadialGradient),
4647    ConicGradient(ConicGradient),
4648    Image(AzString),
4649    Color(ColorU),
4650}
4651
4652impl_vec!(
4653    StyleBackgroundContent,
4654    StyleBackgroundContentVec,
4655    StyleBackgroundContentVecDestructor
4656);
4657impl_vec_debug!(StyleBackgroundContent, StyleBackgroundContentVec);
4658impl_vec_partialord!(StyleBackgroundContent, StyleBackgroundContentVec);
4659impl_vec_ord!(StyleBackgroundContent, StyleBackgroundContentVec);
4660impl_vec_clone!(
4661    StyleBackgroundContent,
4662    StyleBackgroundContentVec,
4663    StyleBackgroundContentVecDestructor
4664);
4665impl_vec_partialeq!(StyleBackgroundContent, StyleBackgroundContentVec);
4666impl_vec_eq!(StyleBackgroundContent, StyleBackgroundContentVec);
4667impl_vec_hash!(StyleBackgroundContent, StyleBackgroundContentVec);
4668
4669impl Default for StyleBackgroundContent {
4670    fn default() -> StyleBackgroundContent {
4671        StyleBackgroundContent::Color(ColorU::TRANSPARENT)
4672    }
4673}
4674
4675impl<'a> From<AzString> for StyleBackgroundContent {
4676    fn from(id: AzString) -> Self {
4677        StyleBackgroundContent::Image(id)
4678    }
4679}
4680
4681#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4682#[repr(C)]
4683pub struct LinearGradient {
4684    pub direction: Direction,
4685    pub extend_mode: ExtendMode,
4686    pub stops: NormalizedLinearColorStopVec,
4687}
4688
4689impl Default for LinearGradient {
4690    fn default() -> Self {
4691        Self {
4692            direction: Direction::default(),
4693            extend_mode: ExtendMode::default(),
4694            stops: Vec::new().into(),
4695        }
4696    }
4697}
4698
4699#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4700#[repr(C)]
4701pub struct ConicGradient {
4702    pub extend_mode: ExtendMode,             // default = clamp (no-repeat)
4703    pub center: StyleBackgroundPosition,     // default = center center
4704    pub angle: AngleValue,                   // default = 0deg
4705    pub stops: NormalizedRadialColorStopVec, // default = []
4706}
4707
4708impl Default for ConicGradient {
4709    fn default() -> Self {
4710        Self {
4711            extend_mode: ExtendMode::default(),
4712            center: StyleBackgroundPosition {
4713                horizontal: BackgroundPositionHorizontal::Center,
4714                vertical: BackgroundPositionVertical::Center,
4715            },
4716            angle: AngleValue::default(),
4717            stops: Vec::new().into(),
4718        }
4719    }
4720}
4721
4722// normalized linear color stop
4723#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4724#[repr(C)]
4725pub struct NormalizedLinearColorStop {
4726    pub offset: PercentageValue, // 0 to 100% // -- todo: theoretically this should be PixelValue
4727    pub color: ColorU,
4728}
4729
4730#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4731#[repr(C)]
4732pub struct NormalizedRadialColorStop {
4733    pub angle: AngleValue, // 0 to 360 degrees
4734    pub color: ColorU,
4735}
4736
4737impl LinearColorStop {
4738    pub fn get_normalized_linear_stops(
4739        stops: &[LinearColorStop],
4740    ) -> Vec<NormalizedLinearColorStop> {
4741        const MIN_STOP_DEGREE: f32 = 0.0;
4742        const MAX_STOP_DEGREE: f32 = 100.0;
4743
4744        if stops.is_empty() {
4745            return Vec::new();
4746        }
4747
4748        let self_stops = stops;
4749
4750        let mut stops = self_stops
4751            .iter()
4752            .map(|s| NormalizedLinearColorStop {
4753                offset: s
4754                    .offset
4755                    .as_ref()
4756                    .copied()
4757                    .unwrap_or(PercentageValue::new(MIN_STOP_DEGREE)),
4758                color: s.color,
4759            })
4760            .collect::<Vec<_>>();
4761
4762        let mut stops_to_distribute = 0;
4763        let mut last_stop = None;
4764        let stops_len = stops.len();
4765
4766        for (stop_id, stop) in self_stops.iter().enumerate() {
4767            if let Some(s) = stop.offset.into_option() {
4768                let current_stop_val = s.get();
4769                if stops_to_distribute != 0 {
4770                    let last_stop_val = stops[(stop_id - stops_to_distribute)].offset.get();
4771                    let value_to_add_per_stop = (current_stop_val.max(last_stop_val)
4772                        - last_stop_val)
4773                        / (stops_to_distribute - 1) as f32;
4774                    for (s_id, s) in stops[(stop_id - stops_to_distribute)..stop_id]
4775                        .iter_mut()
4776                        .enumerate()
4777                    {
4778                        s.offset = PercentageValue::new(
4779                            last_stop_val + (s_id as f32 * value_to_add_per_stop),
4780                        );
4781                    }
4782                }
4783                stops_to_distribute = 0;
4784                last_stop = Some(s);
4785            } else {
4786                stops_to_distribute += 1;
4787            }
4788        }
4789
4790        if stops_to_distribute != 0 {
4791            let last_stop_val = last_stop
4792                .unwrap_or(PercentageValue::new(MIN_STOP_DEGREE))
4793                .get();
4794            let value_to_add_per_stop = (MAX_STOP_DEGREE.max(last_stop_val) - last_stop_val)
4795                / (stops_to_distribute - 1) as f32;
4796            for (s_id, s) in stops[(stops_len - stops_to_distribute)..]
4797                .iter_mut()
4798                .enumerate()
4799            {
4800                s.offset =
4801                    PercentageValue::new(last_stop_val + (s_id as f32 * value_to_add_per_stop));
4802            }
4803        }
4804
4805        stops
4806    }
4807}
4808
4809impl RadialColorStop {
4810    pub fn get_normalized_radial_stops(
4811        stops: &[RadialColorStop],
4812    ) -> Vec<NormalizedRadialColorStop> {
4813        const MIN_STOP_DEGREE: f32 = 0.0;
4814        const MAX_STOP_DEGREE: f32 = 360.0;
4815
4816        if stops.is_empty() {
4817            return Vec::new();
4818        }
4819
4820        let self_stops = stops;
4821
4822        let mut stops = self_stops
4823            .iter()
4824            .map(|s| NormalizedRadialColorStop {
4825                angle: s
4826                    .offset
4827                    .as_ref()
4828                    .copied()
4829                    .unwrap_or(AngleValue::deg(MIN_STOP_DEGREE)),
4830                color: s.color,
4831            })
4832            .collect::<Vec<_>>();
4833
4834        let mut stops_to_distribute = 0;
4835        let mut last_stop = None;
4836        let stops_len = stops.len();
4837
4838        for (stop_id, stop) in self_stops.iter().enumerate() {
4839            if let Some(s) = stop.offset.into_option() {
4840                let current_stop_val = s.to_degrees();
4841                if stops_to_distribute != 0 {
4842                    let last_stop_val = stops[(stop_id - stops_to_distribute)].angle.to_degrees();
4843                    let value_to_add_per_stop = (current_stop_val.max(last_stop_val)
4844                        - last_stop_val)
4845                        / (stops_to_distribute - 1) as f32;
4846                    for (s_id, s) in stops[(stop_id - stops_to_distribute)..stop_id]
4847                        .iter_mut()
4848                        .enumerate()
4849                    {
4850                        s.angle =
4851                            AngleValue::deg(last_stop_val + (s_id as f32 * value_to_add_per_stop));
4852                    }
4853                }
4854                stops_to_distribute = 0;
4855                last_stop = Some(s);
4856            } else {
4857                stops_to_distribute += 1;
4858            }
4859        }
4860
4861        if stops_to_distribute != 0 {
4862            let last_stop_val = last_stop
4863                .unwrap_or(AngleValue::deg(MIN_STOP_DEGREE))
4864                .to_degrees();
4865            let value_to_add_per_stop = (MAX_STOP_DEGREE.max(last_stop_val) - last_stop_val)
4866                / (stops_to_distribute - 1) as f32;
4867            for (s_id, s) in stops[(stops_len - stops_to_distribute)..]
4868                .iter_mut()
4869                .enumerate()
4870            {
4871                s.angle = AngleValue::deg(last_stop_val + (s_id as f32 * value_to_add_per_stop));
4872            }
4873        }
4874
4875        stops
4876    }
4877}
4878
4879#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4880#[repr(C)]
4881pub struct RadialGradient {
4882    pub shape: Shape,
4883    pub size: RadialGradientSize,
4884    pub position: StyleBackgroundPosition,
4885    pub extend_mode: ExtendMode,
4886    pub stops: NormalizedLinearColorStopVec,
4887}
4888
4889impl Default for RadialGradient {
4890    fn default() -> Self {
4891        Self {
4892            shape: Shape::default(),
4893            size: RadialGradientSize::default(),
4894            position: StyleBackgroundPosition::default(),
4895            extend_mode: ExtendMode::default(),
4896            stops: Vec::new().into(),
4897        }
4898    }
4899}
4900
4901#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4902#[repr(C)]
4903pub enum RadialGradientSize {
4904    // The gradient's ending shape meets the side of the box closest to its center
4905    // (for circles) or meets both the vertical and horizontal sides closest to the
4906    // center (for ellipses).
4907    ClosestSide,
4908    // The gradient's ending shape is sized so that it exactly meets the closest
4909    // corner of the box from its center
4910    ClosestCorner,
4911    // Similar to closest-side, except the ending shape is sized to meet the side
4912    // of the box farthest from its center (or vertical and horizontal sides)
4913    FarthestSide,
4914    // The default value, the gradient's ending shape is sized so that it exactly
4915    // meets the farthest corner of the box from its center
4916    FarthestCorner,
4917}
4918
4919impl Default for RadialGradientSize {
4920    fn default() -> Self {
4921        RadialGradientSize::FarthestCorner
4922    }
4923}
4924
4925impl RadialGradientSize {
4926    pub fn get_size(&self, parent_rect: LayoutRect, gradient_center: LayoutPosition) -> LayoutSize {
4927        // TODO!
4928        parent_rect.size
4929    }
4930}
4931
4932#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4933#[repr(C)]
4934pub struct DirectionCorners {
4935    pub from: DirectionCorner,
4936    pub to: DirectionCorner,
4937}
4938
4939/// CSS direction (necessary for gradients). Can either be a fixed angle or
4940/// a direction ("to right" / "to left", etc.).
4941#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4942#[repr(C, u8)]
4943pub enum Direction {
4944    Angle(AngleValue),
4945    FromTo(DirectionCorners),
4946}
4947
4948impl Default for Direction {
4949    fn default() -> Self {
4950        Direction::FromTo(DirectionCorners {
4951            from: DirectionCorner::Top,
4952            to: DirectionCorner::Bottom,
4953        })
4954    }
4955}
4956
4957impl Direction {
4958    /// Calculates the points of the gradient stops for angled linear gradients
4959    pub fn to_points(&self, rect: &LayoutRect) -> (LayoutPoint, LayoutPoint) {
4960        match self {
4961            Direction::Angle(angle_value) => {
4962                // note: assumes that the LayoutRect has positive sides
4963
4964                // see: https://hugogiraudel.com/2013/02/04/css-gradients/
4965
4966                let deg = angle_value.to_degrees(); // FloatValue -> f32
4967
4968                let deg = -deg; // negate winding direction
4969
4970                let width_half = rect.size.width as f32 / 2.0;
4971                let height_half = rect.size.height as f32 / 2.0;
4972
4973                // hypotenuse_len is the length of the center of the rect to the corners
4974                let hypotenuse_len = libm::hypotf(width_half, height_half);
4975
4976                // The corner also serves to determine what quadrant we're in
4977                // Get the quadrant (corner) the angle is in and get the degree associated
4978                // with that corner.
4979
4980                let angle_to_top_left = libm::atanf(height_half / width_half).to_degrees();
4981
4982                // We need to calculate the angle from the center to the corner!
4983                let ending_point_degrees = if deg < 90.0 {
4984                    // top left corner
4985                    90.0 - angle_to_top_left
4986                } else if deg < 180.0 {
4987                    // bottom left corner
4988                    90.0 + angle_to_top_left
4989                } else if deg < 270.0 {
4990                    // bottom right corner
4991                    270.0 - angle_to_top_left
4992                } else
4993                /* deg > 270.0 && deg < 360.0 */
4994                {
4995                    // top right corner
4996                    270.0 + angle_to_top_left
4997                };
4998
4999                // assuming deg = 36deg, then degree_diff_to_corner = 9deg
5000                let degree_diff_to_corner = ending_point_degrees as f32 - deg;
5001
5002                // Searched_len is the distance between the center of the rect and the
5003                // ending point of the gradient
5004                let searched_len = libm::fabsf(libm::cosf(
5005                    hypotenuse_len * degree_diff_to_corner.to_radians() as f32,
5006                ));
5007
5008                // TODO: This searched_len is incorrect...
5009
5010                // Once we have the length, we can simply rotate the length by the angle,
5011                // then translate it to the center of the rect
5012                let dx = libm::sinf(deg.to_radians() as f32) * searched_len;
5013                let dy = libm::cosf(deg.to_radians() as f32) * searched_len;
5014
5015                let start_point_location = LayoutPoint {
5016                    x: libm::roundf(width_half + dx) as isize,
5017                    y: libm::roundf(height_half + dy) as isize,
5018                };
5019                let end_point_location = LayoutPoint {
5020                    x: libm::roundf(width_half - dx) as isize,
5021                    y: libm::roundf(height_half - dy) as isize,
5022                };
5023
5024                (start_point_location, end_point_location)
5025            }
5026            Direction::FromTo(ft) => (ft.from.to_point(rect), ft.to.to_point(rect)),
5027        }
5028    }
5029}
5030
5031#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5032#[repr(C)]
5033pub enum Shape {
5034    Ellipse,
5035    Circle,
5036}
5037
5038impl Default for Shape {
5039    fn default() -> Self {
5040        Shape::Ellipse
5041    }
5042}
5043
5044#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5045#[repr(C)]
5046pub enum StyleCursor {
5047    /// `alias`
5048    Alias,
5049    /// `all-scroll`
5050    AllScroll,
5051    /// `cell`
5052    Cell,
5053    /// `col-resize`
5054    ColResize,
5055    /// `context-menu`
5056    ContextMenu,
5057    /// `copy`
5058    Copy,
5059    /// `crosshair`
5060    Crosshair,
5061    /// `default` - note: called "arrow" in winit
5062    Default,
5063    /// `e-resize`
5064    EResize,
5065    /// `ew-resize`
5066    EwResize,
5067    /// `grab`
5068    Grab,
5069    /// `grabbing`
5070    Grabbing,
5071    /// `help`
5072    Help,
5073    /// `move`
5074    Move,
5075    /// `n-resize`
5076    NResize,
5077    /// `ns-resize`
5078    NsResize,
5079    /// `nesw-resize`
5080    NeswResize,
5081    /// `nwse-resize`
5082    NwseResize,
5083    /// `pointer` - note: called "hand" in winit
5084    Pointer,
5085    /// `progress`
5086    Progress,
5087    /// `row-resize`
5088    RowResize,
5089    /// `s-resize`
5090    SResize,
5091    /// `se-resize`
5092    SeResize,
5093    /// `text`
5094    Text,
5095    /// `unset`
5096    Unset,
5097    /// `vertical-text`
5098    VerticalText,
5099    /// `w-resize`
5100    WResize,
5101    /// `wait`
5102    Wait,
5103    /// `zoom-in`
5104    ZoomIn,
5105    /// `zoom-out`
5106    ZoomOut,
5107}
5108
5109impl Default for StyleCursor {
5110    fn default() -> StyleCursor {
5111        StyleCursor::Default
5112    }
5113}
5114
5115#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5116#[repr(C)]
5117pub enum DirectionCorner {
5118    Right,
5119    Left,
5120    Top,
5121    Bottom,
5122    TopRight,
5123    TopLeft,
5124    BottomRight,
5125    BottomLeft,
5126}
5127
5128impl fmt::Display for DirectionCorner {
5129    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5130        write!(
5131            f,
5132            "{}",
5133            match self {
5134                DirectionCorner::Right => "right",
5135                DirectionCorner::Left => "left",
5136                DirectionCorner::Top => "top",
5137                DirectionCorner::Bottom => "bottom",
5138                DirectionCorner::TopRight => "top right",
5139                DirectionCorner::TopLeft => "top left",
5140                DirectionCorner::BottomRight => "bottom right",
5141                DirectionCorner::BottomLeft => "bottom left",
5142            }
5143        )
5144    }
5145}
5146
5147impl DirectionCorner {
5148    pub const fn opposite(&self) -> Self {
5149        use self::DirectionCorner::*;
5150        match *self {
5151            Right => Left,
5152            Left => Right,
5153            Top => Bottom,
5154            Bottom => Top,
5155            TopRight => BottomLeft,
5156            BottomLeft => TopRight,
5157            TopLeft => BottomRight,
5158            BottomRight => TopLeft,
5159        }
5160    }
5161
5162    pub const fn combine(&self, other: &Self) -> Option<Self> {
5163        use self::DirectionCorner::*;
5164        match (*self, *other) {
5165            (Right, Top) | (Top, Right) => Some(TopRight),
5166            (Left, Top) | (Top, Left) => Some(TopLeft),
5167            (Right, Bottom) | (Bottom, Right) => Some(BottomRight),
5168            (Left, Bottom) | (Bottom, Left) => Some(BottomLeft),
5169            _ => None,
5170        }
5171    }
5172
5173    pub const fn to_point(&self, rect: &LayoutRect) -> LayoutPoint {
5174        use self::DirectionCorner::*;
5175        match *self {
5176            Right => LayoutPoint {
5177                x: rect.size.width,
5178                y: rect.size.height / 2,
5179            },
5180            Left => LayoutPoint {
5181                x: 0,
5182                y: rect.size.height / 2,
5183            },
5184            Top => LayoutPoint {
5185                x: rect.size.width / 2,
5186                y: 0,
5187            },
5188            Bottom => LayoutPoint {
5189                x: rect.size.width / 2,
5190                y: rect.size.height,
5191            },
5192            TopRight => LayoutPoint {
5193                x: rect.size.width,
5194                y: 0,
5195            },
5196            TopLeft => LayoutPoint { x: 0, y: 0 },
5197            BottomRight => LayoutPoint {
5198                x: rect.size.width,
5199                y: rect.size.height,
5200            },
5201            BottomLeft => LayoutPoint {
5202                x: 0,
5203                y: rect.size.height,
5204            },
5205        }
5206    }
5207}
5208
5209#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5210pub struct RadialColorStop {
5211    // this is set to None if there was no offset that could be parsed
5212    pub offset: OptionAngleValue,
5213    pub color: ColorU,
5214}
5215
5216impl_vec!(
5217    NormalizedRadialColorStop,
5218    NormalizedRadialColorStopVec,
5219    NormalizedRadialColorStopVecDestructor
5220);
5221impl_vec_debug!(NormalizedRadialColorStop, NormalizedRadialColorStopVec);
5222impl_vec_partialord!(NormalizedRadialColorStop, NormalizedRadialColorStopVec);
5223impl_vec_ord!(NormalizedRadialColorStop, NormalizedRadialColorStopVec);
5224impl_vec_clone!(
5225    NormalizedRadialColorStop,
5226    NormalizedRadialColorStopVec,
5227    NormalizedRadialColorStopVecDestructor
5228);
5229impl_vec_partialeq!(NormalizedRadialColorStop, NormalizedRadialColorStopVec);
5230impl_vec_eq!(NormalizedRadialColorStop, NormalizedRadialColorStopVec);
5231impl_vec_hash!(NormalizedRadialColorStop, NormalizedRadialColorStopVec);
5232
5233#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5234pub struct LinearColorStop {
5235    // this is set to None if there was no offset that could be parsed
5236    pub offset: OptionPercentageValue,
5237    pub color: ColorU,
5238}
5239
5240impl_vec!(
5241    NormalizedLinearColorStop,
5242    NormalizedLinearColorStopVec,
5243    NormalizedLinearColorStopVecDestructor
5244);
5245impl_vec_debug!(NormalizedLinearColorStop, NormalizedLinearColorStopVec);
5246impl_vec_partialord!(NormalizedLinearColorStop, NormalizedLinearColorStopVec);
5247impl_vec_ord!(NormalizedLinearColorStop, NormalizedLinearColorStopVec);
5248impl_vec_clone!(
5249    NormalizedLinearColorStop,
5250    NormalizedLinearColorStopVec,
5251    NormalizedLinearColorStopVecDestructor
5252);
5253impl_vec_partialeq!(NormalizedLinearColorStop, NormalizedLinearColorStopVec);
5254impl_vec_eq!(NormalizedLinearColorStop, NormalizedLinearColorStopVec);
5255impl_vec_hash!(NormalizedLinearColorStop, NormalizedLinearColorStopVec);
5256
5257/// Represents a `width` attribute
5258#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5259#[repr(C)]
5260pub struct LayoutWidth {
5261    pub inner: PixelValue,
5262}
5263/// Represents a `min-width` attribute
5264#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5265#[repr(C)]
5266pub struct LayoutMinWidth {
5267    pub inner: PixelValue,
5268}
5269/// Represents a `max-width` attribute
5270#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5271#[repr(C)]
5272pub struct LayoutMaxWidth {
5273    pub inner: PixelValue,
5274}
5275/// Represents a `height` attribute
5276#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5277#[repr(C)]
5278pub struct LayoutHeight {
5279    pub inner: PixelValue,
5280}
5281/// Represents a `min-height` attribute
5282#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5283#[repr(C)]
5284pub struct LayoutMinHeight {
5285    pub inner: PixelValue,
5286}
5287/// Represents a `max-height` attribute
5288#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5289#[repr(C)]
5290pub struct LayoutMaxHeight {
5291    pub inner: PixelValue,
5292}
5293
5294impl Default for LayoutMaxHeight {
5295    fn default() -> Self {
5296        Self {
5297            inner: PixelValue::px(core::f32::MAX),
5298        }
5299    }
5300}
5301impl Default for LayoutMaxWidth {
5302    fn default() -> Self {
5303        Self {
5304            inner: PixelValue::px(core::f32::MAX),
5305        }
5306    }
5307}
5308
5309impl_pixel_value!(LayoutWidth);
5310impl_pixel_value!(LayoutHeight);
5311impl_pixel_value!(LayoutMinHeight);
5312impl_pixel_value!(LayoutMinWidth);
5313impl_pixel_value!(LayoutMaxWidth);
5314impl_pixel_value!(LayoutMaxHeight);
5315
5316/// Represents a `top` attribute
5317#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5318#[repr(C)]
5319pub struct LayoutTop {
5320    pub inner: PixelValue,
5321}
5322/// Represents a `left` attribute
5323#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5324#[repr(C)]
5325pub struct LayoutLeft {
5326    pub inner: PixelValue,
5327}
5328/// Represents a `right` attribute
5329#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5330#[repr(C)]
5331pub struct LayoutRight {
5332    pub inner: PixelValue,
5333}
5334/// Represents a `bottom` attribute
5335#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5336#[repr(C)]
5337pub struct LayoutBottom {
5338    pub inner: PixelValue,
5339}
5340
5341impl_pixel_value!(LayoutTop);
5342impl_pixel_value!(LayoutBottom);
5343impl_pixel_value!(LayoutRight);
5344impl_pixel_value!(LayoutLeft);
5345
5346/// Represents a `padding-top` attribute
5347#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5348#[repr(C)]
5349pub struct LayoutPaddingTop {
5350    pub inner: PixelValue,
5351}
5352/// Represents a `padding-left` attribute
5353#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5354#[repr(C)]
5355pub struct LayoutPaddingLeft {
5356    pub inner: PixelValue,
5357}
5358/// Represents a `padding-right` attribute
5359#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5360#[repr(C)]
5361pub struct LayoutPaddingRight {
5362    pub inner: PixelValue,
5363}
5364/// Represents a `padding-bottom` attribute
5365#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5366#[repr(C)]
5367pub struct LayoutPaddingBottom {
5368    pub inner: PixelValue,
5369}
5370
5371impl_pixel_value!(LayoutPaddingTop);
5372impl_pixel_value!(LayoutPaddingBottom);
5373impl_pixel_value!(LayoutPaddingRight);
5374impl_pixel_value!(LayoutPaddingLeft);
5375
5376/// Represents a `padding-top` attribute
5377#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5378#[repr(C)]
5379pub struct LayoutMarginTop {
5380    pub inner: PixelValue,
5381}
5382/// Represents a `padding-left` attribute
5383#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5384#[repr(C)]
5385pub struct LayoutMarginLeft {
5386    pub inner: PixelValue,
5387}
5388/// Represents a `padding-right` attribute
5389#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5390#[repr(C)]
5391pub struct LayoutMarginRight {
5392    pub inner: PixelValue,
5393}
5394/// Represents a `padding-bottom` attribute
5395#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5396#[repr(C)]
5397pub struct LayoutMarginBottom {
5398    pub inner: PixelValue,
5399}
5400
5401impl_pixel_value!(LayoutMarginTop);
5402impl_pixel_value!(LayoutMarginBottom);
5403impl_pixel_value!(LayoutMarginRight);
5404impl_pixel_value!(LayoutMarginLeft);
5405
5406/// Represents a `flex-grow` attribute
5407#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5408#[repr(C)]
5409pub struct LayoutFlexGrow {
5410    pub inner: FloatValue,
5411}
5412
5413impl Default for LayoutFlexGrow {
5414    fn default() -> Self {
5415        LayoutFlexGrow {
5416            inner: FloatValue::const_new(0),
5417        }
5418    }
5419}
5420
5421/// Represents a `flex-shrink` attribute
5422#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5423#[repr(C)]
5424pub struct LayoutFlexShrink {
5425    pub inner: FloatValue,
5426}
5427
5428impl Default for LayoutFlexShrink {
5429    fn default() -> Self {
5430        LayoutFlexShrink {
5431            inner: FloatValue::const_new(0),
5432        }
5433    }
5434}
5435
5436impl_float_value!(LayoutFlexGrow);
5437impl_float_value!(LayoutFlexShrink);
5438
5439/// Represents a `flex-direction` attribute - default: `Column`
5440#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5441#[repr(C)]
5442pub enum LayoutFlexDirection {
5443    Row,
5444    RowReverse,
5445    Column,
5446    ColumnReverse,
5447}
5448
5449impl Default for LayoutFlexDirection {
5450    fn default() -> Self {
5451        LayoutFlexDirection::Column
5452    }
5453}
5454
5455impl LayoutFlexDirection {
5456    pub fn get_axis(&self) -> LayoutAxis {
5457        use self::{LayoutAxis::*, LayoutFlexDirection::*};
5458        match self {
5459            Row | RowReverse => Horizontal,
5460            Column | ColumnReverse => Vertical,
5461        }
5462    }
5463
5464    /// Returns true, if this direction is a `column-reverse` or `row-reverse` direction
5465    pub fn is_reverse(&self) -> bool {
5466        *self == LayoutFlexDirection::RowReverse || *self == LayoutFlexDirection::ColumnReverse
5467    }
5468}
5469
5470/// Represents a `flex-direction` attribute - default: `Column`
5471#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5472#[repr(C)]
5473pub enum LayoutBoxSizing {
5474    ContentBox,
5475    BorderBox,
5476}
5477
5478impl Default for LayoutBoxSizing {
5479    fn default() -> Self {
5480        LayoutBoxSizing::ContentBox
5481    }
5482}
5483
5484/// Represents a `line-height` attribute
5485#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5486#[repr(C)]
5487pub struct StyleLineHeight {
5488    pub inner: PercentageValue,
5489}
5490
5491impl_percentage_value!(StyleLineHeight);
5492
5493impl Default for StyleLineHeight {
5494    fn default() -> Self {
5495        Self {
5496            inner: PercentageValue::const_new(100),
5497        }
5498    }
5499}
5500
5501/// Represents a `tab-width` attribute
5502#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5503#[repr(C)]
5504pub struct StyleTabWidth {
5505    pub inner: PercentageValue,
5506}
5507
5508impl_percentage_value!(StyleTabWidth);
5509
5510impl Default for StyleTabWidth {
5511    fn default() -> Self {
5512        Self {
5513            inner: PercentageValue::const_new(100),
5514        }
5515    }
5516}
5517
5518/// Represents a `letter-spacing` attribute
5519#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5520#[repr(C)]
5521pub struct StyleLetterSpacing {
5522    pub inner: PixelValue,
5523}
5524
5525impl Default for StyleLetterSpacing {
5526    fn default() -> Self {
5527        Self {
5528            inner: PixelValue::const_px(0),
5529        }
5530    }
5531}
5532
5533impl_pixel_value!(StyleLetterSpacing);
5534
5535/// Represents a `word-spacing` attribute
5536#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5537#[repr(C)]
5538pub struct StyleWordSpacing {
5539    pub inner: PixelValue,
5540}
5541
5542impl_pixel_value!(StyleWordSpacing);
5543
5544impl Default for StyleWordSpacing {
5545    fn default() -> Self {
5546        Self {
5547            inner: PixelValue::const_px(0),
5548        }
5549    }
5550}
5551
5552/// Same as the `LayoutFlexDirection`, but without the `-reverse` properties, used in the layout
5553/// solver, makes decisions based on horizontal / vertical direction easier to write.
5554/// Use `LayoutFlexDirection::get_axis()` to get the axis for a given `LayoutFlexDirection`.
5555#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5556#[repr(C)]
5557pub enum LayoutAxis {
5558    Horizontal,
5559    Vertical,
5560}
5561
5562/// Represents a `display` attribute
5563#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5564#[repr(C)]
5565pub enum LayoutDisplay {
5566    None,
5567    Flex,
5568    Block,
5569    InlineBlock,
5570}
5571
5572impl Default for LayoutDisplay {
5573    fn default() -> Self {
5574        LayoutDisplay::Flex
5575    }
5576}
5577
5578/// Represents a `float` attribute
5579#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5580#[repr(C)]
5581pub enum LayoutFloat {
5582    Left,
5583    Right,
5584}
5585
5586impl Default for LayoutFloat {
5587    fn default() -> Self {
5588        LayoutFloat::Left
5589    }
5590}
5591
5592/// Represents a `position` attribute - default: `Static`
5593///
5594/// NOTE: No inline positioning is supported.
5595#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5596#[repr(C)]
5597pub enum LayoutPosition {
5598    Static,
5599    Relative,
5600    Absolute,
5601    Fixed,
5602}
5603
5604impl LayoutPosition {
5605    pub fn is_positioned(&self) -> bool {
5606        *self != LayoutPosition::Static
5607    }
5608}
5609
5610impl Default for LayoutPosition {
5611    fn default() -> Self {
5612        LayoutPosition::Static
5613    }
5614}
5615
5616/// Represents a `flex-wrap` attribute - default: `Wrap`
5617#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5618#[repr(C)]
5619pub enum LayoutFlexWrap {
5620    Wrap,
5621    NoWrap,
5622}
5623
5624impl Default for LayoutFlexWrap {
5625    fn default() -> Self {
5626        LayoutFlexWrap::Wrap
5627    }
5628}
5629
5630/// Represents a `justify-content` attribute
5631#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5632#[repr(C)]
5633pub enum LayoutJustifyContent {
5634    /// Default value. Items are positioned at the beginning of the container
5635    Start,
5636    /// Items are positioned at the end of the container
5637    End,
5638    /// Items are positioned at the center of the container
5639    Center,
5640    /// Items are positioned with space between the lines
5641    SpaceBetween,
5642    /// Items are positioned with space before, between, and after the lines
5643    SpaceAround,
5644    /// Items are distributed so that the spacing between any two adjacent alignment subjects,
5645    /// before the first alignment subject, and after the last alignment subject is the same
5646    SpaceEvenly,
5647}
5648
5649impl Default for LayoutJustifyContent {
5650    fn default() -> Self {
5651        LayoutJustifyContent::Start
5652    }
5653}
5654
5655/// Represents a `align-items` attribute
5656#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5657#[repr(C)]
5658pub enum LayoutAlignItems {
5659    /// Items are stretched to fit the container
5660    Stretch,
5661    /// Items are positioned at the center of the container
5662    Center,
5663    /// Items are positioned at the beginning of the container
5664    FlexStart,
5665    /// Items are positioned at the end of the container
5666    FlexEnd,
5667}
5668
5669impl Default for LayoutAlignItems {
5670    fn default() -> Self {
5671        LayoutAlignItems::FlexStart
5672    }
5673}
5674
5675/// Represents a `align-content` attribute
5676#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5677#[repr(C)]
5678pub enum LayoutAlignContent {
5679    /// Default value. Lines stretch to take up the remaining space
5680    Stretch,
5681    /// Lines are packed toward the center of the flex container
5682    Center,
5683    /// Lines are packed toward the start of the flex container
5684    Start,
5685    /// Lines are packed toward the end of the flex container
5686    End,
5687    /// Lines are evenly distributed in the flex container
5688    SpaceBetween,
5689    /// Lines are evenly distributed in the flex container, with half-size spaces on either end
5690    SpaceAround,
5691}
5692
5693impl Default for LayoutAlignContent {
5694    fn default() -> Self {
5695        LayoutAlignContent::Stretch
5696    }
5697}
5698
5699/// Represents a `overflow-x` or `overflow-y` property, see
5700/// [`TextOverflowBehaviour`](./struct.TextOverflowBehaviour.html) - default: `Auto`
5701#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5702#[repr(C)]
5703pub enum LayoutOverflow {
5704    /// Always shows a scroll bar, overflows on scroll
5705    Scroll,
5706    /// Does not show a scroll bar by default, only when text is overflowing
5707    Auto,
5708    /// Never shows a scroll bar, simply clips text
5709    Hidden,
5710    /// Doesn't show a scroll bar, simply overflows the text
5711    Visible,
5712}
5713
5714impl Default for LayoutOverflow {
5715    fn default() -> Self {
5716        LayoutOverflow::Auto
5717    }
5718}
5719
5720impl LayoutOverflow {
5721    /// Returns whether this overflow value needs to display the scrollbars.
5722    ///
5723    /// - `overflow:scroll` always shows the scrollbar
5724    /// - `overflow:auto` only shows the scrollbar when the content is currently overflowing
5725    /// - `overflow:hidden` and `overflow:visible` do not show any scrollbars
5726    pub fn needs_scrollbar(&self, currently_overflowing: bool) -> bool {
5727        use self::LayoutOverflow::*;
5728        match self {
5729            Scroll => true,
5730            Auto => currently_overflowing,
5731            Hidden | Visible => false,
5732        }
5733    }
5734
5735    /// Returns whether this is an `overflow:visible` node
5736    /// (the only overflow type that doesn't clip its children)
5737    pub fn is_overflow_visible(&self) -> bool {
5738        *self == LayoutOverflow::Visible
5739    }
5740
5741    pub fn is_overflow_hidden(&self) -> bool {
5742        *self == LayoutOverflow::Hidden
5743    }
5744}
5745
5746/// Horizontal text alignment enum (left, center, right) - default: `Center`
5747#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5748#[repr(C)]
5749pub enum StyleTextAlign {
5750    Left,
5751    Center,
5752    Right,
5753}
5754
5755impl Default for StyleTextAlign {
5756    fn default() -> Self {
5757        StyleTextAlign::Left
5758    }
5759}
5760
5761/// Vertical text alignment enum (top, center, bottom) - default: `Center`
5762#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5763#[repr(C)]
5764pub enum StyleVerticalAlign {
5765    Top,
5766    Center,
5767    Bottom,
5768}
5769
5770impl Default for StyleVerticalAlign {
5771    fn default() -> Self {
5772        StyleVerticalAlign::Top
5773    }
5774}
5775
5776/// Represents an `opacity` attribute
5777#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5778#[repr(C)]
5779pub struct StyleOpacity {
5780    pub inner: PercentageValue,
5781}
5782
5783impl Default for StyleOpacity {
5784    fn default() -> Self {
5785        StyleOpacity {
5786            inner: PercentageValue::const_new(0),
5787        }
5788    }
5789}
5790
5791impl_percentage_value!(StyleOpacity);
5792
5793/// Represents a `perspective-origin` attribute
5794#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5795#[repr(C)]
5796pub struct StylePerspectiveOrigin {
5797    pub x: PixelValue,
5798    pub y: PixelValue,
5799}
5800
5801impl StylePerspectiveOrigin {
5802    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
5803        Self {
5804            x: self.x.interpolate(&other.x, t),
5805            y: self.y.interpolate(&other.y, t),
5806        }
5807    }
5808}
5809
5810impl Default for StylePerspectiveOrigin {
5811    fn default() -> Self {
5812        StylePerspectiveOrigin {
5813            x: PixelValue::const_px(0),
5814            y: PixelValue::const_px(0),
5815        }
5816    }
5817}
5818
5819/// Represents a `transform-origin` attribute
5820#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5821#[repr(C)]
5822pub struct StyleTransformOrigin {
5823    pub x: PixelValue,
5824    pub y: PixelValue,
5825}
5826
5827impl StyleTransformOrigin {
5828    pub fn interpolate(&self, other: &Self, t: f32) -> Self {
5829        Self {
5830            x: self.x.interpolate(&other.x, t),
5831            y: self.y.interpolate(&other.y, t),
5832        }
5833    }
5834}
5835
5836impl Default for StyleTransformOrigin {
5837    fn default() -> Self {
5838        StyleTransformOrigin {
5839            x: PixelValue::const_percent(50),
5840            y: PixelValue::const_percent(50),
5841        }
5842    }
5843}
5844
5845/// Represents a `backface-visibility` attribute
5846#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5847#[repr(C)]
5848pub enum StyleBackfaceVisibility {
5849    Hidden,
5850    Visible,
5851}
5852
5853impl Default for StyleBackfaceVisibility {
5854    fn default() -> Self {
5855        StyleBackfaceVisibility::Visible
5856    }
5857}
5858
5859/// Represents an `opacity` attribute
5860#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5861#[repr(C, u8)]
5862pub enum StyleTransform {
5863    Matrix(StyleTransformMatrix2D),
5864    Matrix3D(StyleTransformMatrix3D),
5865    Translate(StyleTransformTranslate2D),
5866    Translate3D(StyleTransformTranslate3D),
5867    TranslateX(PixelValue),
5868    TranslateY(PixelValue),
5869    TranslateZ(PixelValue),
5870    Rotate(AngleValue),
5871    Rotate3D(StyleTransformRotate3D),
5872    RotateX(AngleValue),
5873    RotateY(AngleValue),
5874    RotateZ(AngleValue),
5875    Scale(StyleTransformScale2D),
5876    Scale3D(StyleTransformScale3D),
5877    ScaleX(PercentageValue),
5878    ScaleY(PercentageValue),
5879    ScaleZ(PercentageValue),
5880    Skew(StyleTransformSkew2D),
5881    SkewX(PercentageValue),
5882    SkewY(PercentageValue),
5883    Perspective(PixelValue),
5884}
5885
5886impl_vec!(
5887    StyleTransform,
5888    StyleTransformVec,
5889    StyleTransformVecDestructor
5890);
5891impl_vec_debug!(StyleTransform, StyleTransformVec);
5892impl_vec_partialord!(StyleTransform, StyleTransformVec);
5893impl_vec_ord!(StyleTransform, StyleTransformVec);
5894impl_vec_clone!(
5895    StyleTransform,
5896    StyleTransformVec,
5897    StyleTransformVecDestructor
5898);
5899impl_vec_partialeq!(StyleTransform, StyleTransformVec);
5900impl_vec_eq!(StyleTransform, StyleTransformVec);
5901impl_vec_hash!(StyleTransform, StyleTransformVec);
5902
5903#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5904#[repr(C)]
5905pub struct StyleTransformMatrix2D {
5906    pub a: PixelValue,
5907    pub b: PixelValue,
5908    pub c: PixelValue,
5909    pub d: PixelValue,
5910    pub tx: PixelValue,
5911    pub ty: PixelValue,
5912}
5913
5914#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5915#[repr(C)]
5916pub struct StyleTransformMatrix3D {
5917    pub m11: PixelValue,
5918    pub m12: PixelValue,
5919    pub m13: PixelValue,
5920    pub m14: PixelValue,
5921    pub m21: PixelValue,
5922    pub m22: PixelValue,
5923    pub m23: PixelValue,
5924    pub m24: PixelValue,
5925    pub m31: PixelValue,
5926    pub m32: PixelValue,
5927    pub m33: PixelValue,
5928    pub m34: PixelValue,
5929    pub m41: PixelValue,
5930    pub m42: PixelValue,
5931    pub m43: PixelValue,
5932    pub m44: PixelValue,
5933}
5934
5935#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5936#[repr(C)]
5937pub struct StyleTransformTranslate2D {
5938    pub x: PixelValue,
5939    pub y: PixelValue,
5940}
5941
5942#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5943#[repr(C)]
5944pub struct StyleTransformTranslate3D {
5945    pub x: PixelValue,
5946    pub y: PixelValue,
5947    pub z: PixelValue,
5948}
5949
5950#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5951#[repr(C)]
5952pub struct StyleTransformRotate3D {
5953    pub x: PercentageValue,
5954    pub y: PercentageValue,
5955    pub z: PercentageValue,
5956    pub angle: AngleValue,
5957}
5958
5959#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5960#[repr(C)]
5961pub struct StyleTransformScale2D {
5962    pub x: PercentageValue,
5963    pub y: PercentageValue,
5964}
5965
5966#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5967#[repr(C)]
5968pub struct StyleTransformScale3D {
5969    pub x: PercentageValue,
5970    pub y: PercentageValue,
5971    pub z: PercentageValue,
5972}
5973
5974#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5975#[repr(C)]
5976pub struct StyleTransformSkew2D {
5977    pub x: PercentageValue,
5978    pub y: PercentageValue,
5979}
5980
5981pub type StyleBackgroundContentVecValue = CssPropertyValue<StyleBackgroundContentVec>;
5982pub type StyleBackgroundPositionVecValue = CssPropertyValue<StyleBackgroundPositionVec>;
5983pub type StyleBackgroundSizeVecValue = CssPropertyValue<StyleBackgroundSizeVec>;
5984pub type StyleBackgroundRepeatVecValue = CssPropertyValue<StyleBackgroundRepeatVec>;
5985pub type StyleFontSizeValue = CssPropertyValue<StyleFontSize>;
5986pub type StyleFontFamilyVecValue = CssPropertyValue<StyleFontFamilyVec>;
5987pub type StyleTextColorValue = CssPropertyValue<StyleTextColor>;
5988pub type StyleTextAlignValue = CssPropertyValue<StyleTextAlign>;
5989pub type StyleLineHeightValue = CssPropertyValue<StyleLineHeight>;
5990pub type StyleLetterSpacingValue = CssPropertyValue<StyleLetterSpacing>;
5991pub type StyleWordSpacingValue = CssPropertyValue<StyleWordSpacing>;
5992pub type StyleTabWidthValue = CssPropertyValue<StyleTabWidth>;
5993pub type StyleCursorValue = CssPropertyValue<StyleCursor>;
5994pub type StyleBoxShadowValue = CssPropertyValue<StyleBoxShadow>;
5995pub type StyleBorderTopColorValue = CssPropertyValue<StyleBorderTopColor>;
5996pub type StyleBorderLeftColorValue = CssPropertyValue<StyleBorderLeftColor>;
5997pub type StyleBorderRightColorValue = CssPropertyValue<StyleBorderRightColor>;
5998pub type StyleBorderBottomColorValue = CssPropertyValue<StyleBorderBottomColor>;
5999pub type StyleBorderTopStyleValue = CssPropertyValue<StyleBorderTopStyle>;
6000pub type StyleBorderLeftStyleValue = CssPropertyValue<StyleBorderLeftStyle>;
6001pub type StyleBorderRightStyleValue = CssPropertyValue<StyleBorderRightStyle>;
6002pub type StyleBorderBottomStyleValue = CssPropertyValue<StyleBorderBottomStyle>;
6003pub type StyleBorderTopLeftRadiusValue = CssPropertyValue<StyleBorderTopLeftRadius>;
6004pub type StyleBorderTopRightRadiusValue = CssPropertyValue<StyleBorderTopRightRadius>;
6005pub type StyleBorderBottomLeftRadiusValue = CssPropertyValue<StyleBorderBottomLeftRadius>;
6006pub type StyleBorderBottomRightRadiusValue = CssPropertyValue<StyleBorderBottomRightRadius>;
6007pub type StyleOpacityValue = CssPropertyValue<StyleOpacity>;
6008pub type StyleTransformVecValue = CssPropertyValue<StyleTransformVec>;
6009pub type StyleTransformOriginValue = CssPropertyValue<StyleTransformOrigin>;
6010pub type StylePerspectiveOriginValue = CssPropertyValue<StylePerspectiveOrigin>;
6011pub type StyleBackfaceVisibilityValue = CssPropertyValue<StyleBackfaceVisibility>;
6012pub type StyleMixBlendModeValue = CssPropertyValue<StyleMixBlendMode>;
6013pub type StyleFilterVecValue = CssPropertyValue<StyleFilterVec>;
6014pub type ScrollbarStyleValue = CssPropertyValue<ScrollbarStyle>;
6015pub type LayoutDisplayValue = CssPropertyValue<LayoutDisplay>;
6016impl_option!(
6017    LayoutDisplayValue,
6018    OptionLayoutDisplayValue,
6019    copy = false,
6020    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6021);
6022pub type LayoutFloatValue = CssPropertyValue<LayoutFloat>;
6023impl_option!(
6024    LayoutFloatValue,
6025    OptionLayoutFloatValue,
6026    copy = false,
6027    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6028);
6029pub type LayoutBoxSizingValue = CssPropertyValue<LayoutBoxSizing>;
6030impl_option!(
6031    LayoutBoxSizingValue,
6032    OptionLayoutBoxSizingValue,
6033    copy = false,
6034    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6035);
6036pub type LayoutWidthValue = CssPropertyValue<LayoutWidth>;
6037impl_option!(
6038    LayoutWidthValue,
6039    OptionLayoutWidthValue,
6040    copy = false,
6041    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6042);
6043pub type LayoutHeightValue = CssPropertyValue<LayoutHeight>;
6044impl_option!(
6045    LayoutHeightValue,
6046    OptionLayoutHeightValue,
6047    copy = false,
6048    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6049);
6050pub type LayoutMinWidthValue = CssPropertyValue<LayoutMinWidth>;
6051impl_option!(
6052    LayoutMinWidthValue,
6053    OptionLayoutMinWidthValue,
6054    copy = false,
6055    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6056);
6057pub type LayoutMinHeightValue = CssPropertyValue<LayoutMinHeight>;
6058impl_option!(
6059    LayoutMinHeightValue,
6060    OptionLayoutMinHeightValue,
6061    copy = false,
6062    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6063);
6064pub type LayoutMaxWidthValue = CssPropertyValue<LayoutMaxWidth>;
6065impl_option!(
6066    LayoutMaxWidthValue,
6067    OptionLayoutMaxWidthValue,
6068    copy = false,
6069    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6070);
6071pub type LayoutMaxHeightValue = CssPropertyValue<LayoutMaxHeight>;
6072impl_option!(
6073    LayoutMaxHeightValue,
6074    OptionLayoutMaxHeightValue,
6075    copy = false,
6076    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6077);
6078pub type LayoutPositionValue = CssPropertyValue<LayoutPosition>;
6079impl_option!(
6080    LayoutPositionValue,
6081    OptionLayoutPositionValue,
6082    copy = false,
6083    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6084);
6085pub type LayoutTopValue = CssPropertyValue<LayoutTop>;
6086impl_option!(
6087    LayoutTopValue,
6088    OptionLayoutTopValue,
6089    copy = false,
6090    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6091);
6092pub type LayoutBottomValue = CssPropertyValue<LayoutBottom>;
6093impl_option!(
6094    LayoutBottomValue,
6095    OptionLayoutBottomValue,
6096    copy = false,
6097    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6098);
6099pub type LayoutRightValue = CssPropertyValue<LayoutRight>;
6100impl_option!(
6101    LayoutRightValue,
6102    OptionLayoutRightValue,
6103    copy = false,
6104    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6105);
6106pub type LayoutLeftValue = CssPropertyValue<LayoutLeft>;
6107impl_option!(
6108    LayoutLeftValue,
6109    OptionLayoutLeftValue,
6110    copy = false,
6111    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6112);
6113pub type LayoutPaddingTopValue = CssPropertyValue<LayoutPaddingTop>;
6114impl_option!(
6115    LayoutPaddingTopValue,
6116    OptionLayoutPaddingTopValue,
6117    copy = false,
6118    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6119);
6120pub type LayoutPaddingBottomValue = CssPropertyValue<LayoutPaddingBottom>;
6121impl_option!(
6122    LayoutPaddingBottomValue,
6123    OptionLayoutPaddingBottomValue,
6124    copy = false,
6125    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6126);
6127pub type LayoutPaddingLeftValue = CssPropertyValue<LayoutPaddingLeft>;
6128impl_option!(
6129    LayoutPaddingLeftValue,
6130    OptionLayoutPaddingLeftValue,
6131    copy = false,
6132    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6133);
6134pub type LayoutPaddingRightValue = CssPropertyValue<LayoutPaddingRight>;
6135impl_option!(
6136    LayoutPaddingRightValue,
6137    OptionLayoutPaddingRightValue,
6138    copy = false,
6139    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6140);
6141pub type LayoutMarginTopValue = CssPropertyValue<LayoutMarginTop>;
6142impl_option!(
6143    LayoutMarginTopValue,
6144    OptionLayoutMarginTopValue,
6145    copy = false,
6146    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6147);
6148pub type LayoutMarginBottomValue = CssPropertyValue<LayoutMarginBottom>;
6149impl_option!(
6150    LayoutMarginBottomValue,
6151    OptionLayoutMarginBottomValue,
6152    copy = false,
6153    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6154);
6155pub type LayoutMarginLeftValue = CssPropertyValue<LayoutMarginLeft>;
6156impl_option!(
6157    LayoutMarginLeftValue,
6158    OptionLayoutMarginLeftValue,
6159    copy = false,
6160    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6161);
6162pub type LayoutMarginRightValue = CssPropertyValue<LayoutMarginRight>;
6163impl_option!(
6164    LayoutMarginRightValue,
6165    OptionLayoutMarginRightValue,
6166    copy = false,
6167    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6168);
6169pub type LayoutBorderTopWidthValue = CssPropertyValue<LayoutBorderTopWidth>;
6170pub type LayoutBorderLeftWidthValue = CssPropertyValue<LayoutBorderLeftWidth>;
6171pub type LayoutBorderRightWidthValue = CssPropertyValue<LayoutBorderRightWidth>;
6172pub type LayoutBorderBottomWidthValue = CssPropertyValue<LayoutBorderBottomWidth>;
6173pub type LayoutOverflowValue = CssPropertyValue<LayoutOverflow>;
6174impl_option!(
6175    LayoutOverflowValue,
6176    OptionLayoutOverflowValue,
6177    copy = false,
6178    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6179);
6180pub type LayoutFlexDirectionValue = CssPropertyValue<LayoutFlexDirection>;
6181impl_option!(
6182    LayoutFlexDirectionValue,
6183    OptionLayoutFlexDirectionValue,
6184    copy = false,
6185    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6186);
6187pub type LayoutFlexWrapValue = CssPropertyValue<LayoutFlexWrap>;
6188impl_option!(
6189    LayoutFlexWrapValue,
6190    OptionLayoutFlexWrapValue,
6191    copy = false,
6192    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6193);
6194pub type LayoutFlexGrowValue = CssPropertyValue<LayoutFlexGrow>;
6195impl_option!(
6196    LayoutFlexGrowValue,
6197    OptionLayoutFlexGrowValue,
6198    copy = false,
6199    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6200);
6201pub type LayoutFlexShrinkValue = CssPropertyValue<LayoutFlexShrink>;
6202impl_option!(
6203    LayoutFlexShrinkValue,
6204    OptionLayoutFlexShrinkValue,
6205    copy = false,
6206    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6207);
6208pub type LayoutJustifyContentValue = CssPropertyValue<LayoutJustifyContent>;
6209impl_option!(
6210    LayoutJustifyContentValue,
6211    OptionLayoutJustifyContentValue,
6212    copy = false,
6213    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6214);
6215pub type LayoutAlignItemsValue = CssPropertyValue<LayoutAlignItems>;
6216impl_option!(
6217    LayoutAlignItemsValue,
6218    OptionLayoutAlignItemsValue,
6219    copy = false,
6220    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6221);
6222pub type LayoutAlignContentValue = CssPropertyValue<LayoutAlignContent>;
6223impl_option!(
6224    LayoutAlignContentValue,
6225    OptionLayoutAlignContentValue,
6226    copy = false,
6227    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
6228);
6229
6230/// Holds info necessary for layouting / styling scrollbars (-webkit-scrollbar)
6231#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6232#[repr(C)]
6233pub struct ScrollbarInfo {
6234    /// Total width (or height for vertical scrollbars) of the scrollbar in pixels
6235    pub width: LayoutWidth,
6236    /// Padding of the scrollbar tracker, in pixels. The inner bar is `width - padding` pixels
6237    /// wide.
6238    pub padding_left: LayoutPaddingLeft,
6239    /// Padding of the scrollbar (right)
6240    pub padding_right: LayoutPaddingRight,
6241    /// Style of the scrollbar background
6242    /// (`-webkit-scrollbar` / `-webkit-scrollbar-track` / `-webkit-scrollbar-track-piece`
6243    /// combined)
6244    pub track: StyleBackgroundContent,
6245    /// Style of the scrollbar thumbs (the "up" / "down" arrows), (`-webkit-scrollbar-thumb`)
6246    pub thumb: StyleBackgroundContent,
6247    /// Styles the directional buttons on the scrollbar (`-webkit-scrollbar-button`)
6248    pub button: StyleBackgroundContent,
6249    /// If two scrollbars are present, addresses the (usually) bottom corner
6250    /// of the scrollable element, where two scrollbars might meet (`-webkit-scrollbar-corner`)
6251    pub corner: StyleBackgroundContent,
6252    /// Addresses the draggable resizing handle that appears above the
6253    /// `corner` at the bottom corner of some elements (`-webkit-resizer`)
6254    pub resizer: StyleBackgroundContent,
6255}
6256
6257impl Default for ScrollbarInfo {
6258    fn default() -> Self {
6259        ScrollbarInfo {
6260            width: LayoutWidth::px(17.0),
6261            padding_left: LayoutPaddingLeft::px(2.0),
6262            padding_right: LayoutPaddingRight::px(2.0),
6263            track: StyleBackgroundContent::Color(ColorU {
6264                r: 241,
6265                g: 241,
6266                b: 241,
6267                a: 255,
6268            }),
6269            thumb: StyleBackgroundContent::Color(ColorU {
6270                r: 193,
6271                g: 193,
6272                b: 193,
6273                a: 255,
6274            }),
6275            button: StyleBackgroundContent::Color(ColorU {
6276                r: 163,
6277                g: 163,
6278                b: 163,
6279                a: 255,
6280            }),
6281            corner: StyleBackgroundContent::default(),
6282            resizer: StyleBackgroundContent::default(),
6283        }
6284    }
6285}
6286
6287/// Scrollbar style
6288#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6289#[repr(C)]
6290pub struct ScrollbarStyle {
6291    /// Vertical scrollbar style, if any
6292    pub horizontal: ScrollbarInfo,
6293    /// Horizontal scrollbar style, if any
6294    pub vertical: ScrollbarInfo,
6295}
6296
6297/// Represents a `font-size` attribute
6298#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6299#[repr(C)]
6300pub struct StyleFontSize {
6301    pub inner: PixelValue,
6302}
6303
6304impl Default for StyleFontSize {
6305    fn default() -> Self {
6306        Self {
6307            inner: PixelValue::const_em(1),
6308        }
6309    }
6310}
6311
6312impl_pixel_value!(StyleFontSize);
6313
6314#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6315#[repr(C)]
6316pub struct FontMetrics {
6317    // head table
6318    pub units_per_em: u16,
6319    pub font_flags: u16,
6320    pub x_min: i16,
6321    pub y_min: i16,
6322    pub x_max: i16,
6323    pub y_max: i16,
6324
6325    // hhea table
6326    pub ascender: i16,
6327    pub descender: i16,
6328    pub line_gap: i16,
6329    pub advance_width_max: u16,
6330    pub min_left_side_bearing: i16,
6331    pub min_right_side_bearing: i16,
6332    pub x_max_extent: i16,
6333    pub caret_slope_rise: i16,
6334    pub caret_slope_run: i16,
6335    pub caret_offset: i16,
6336    pub num_h_metrics: u16,
6337
6338    // os/2 table
6339    pub x_avg_char_width: i16,
6340    pub us_weight_class: u16,
6341    pub us_width_class: u16,
6342    pub fs_type: u16,
6343    pub y_subscript_x_size: i16,
6344    pub y_subscript_y_size: i16,
6345    pub y_subscript_x_offset: i16,
6346    pub y_subscript_y_offset: i16,
6347    pub y_superscript_x_size: i16,
6348    pub y_superscript_y_size: i16,
6349    pub y_superscript_x_offset: i16,
6350    pub y_superscript_y_offset: i16,
6351    pub y_strikeout_size: i16,
6352    pub y_strikeout_position: i16,
6353    pub s_family_class: i16,
6354    pub panose: [u8; 10],
6355    pub ul_unicode_range1: u32,
6356    pub ul_unicode_range2: u32,
6357    pub ul_unicode_range3: u32,
6358    pub ul_unicode_range4: u32,
6359    pub ach_vend_id: u32,
6360    pub fs_selection: u16,
6361    pub us_first_char_index: u16,
6362    pub us_last_char_index: u16,
6363
6364    // os/2 version 0 table
6365    pub s_typo_ascender: OptionI16,
6366    pub s_typo_descender: OptionI16,
6367    pub s_typo_line_gap: OptionI16,
6368    pub us_win_ascent: OptionU16,
6369    pub us_win_descent: OptionU16,
6370
6371    // os/2 version 1 table
6372    pub ul_code_page_range1: OptionU32,
6373    pub ul_code_page_range2: OptionU32,
6374
6375    // os/2 version 2 table
6376    pub sx_height: OptionI16,
6377    pub s_cap_height: OptionI16,
6378    pub us_default_char: OptionU16,
6379    pub us_break_char: OptionU16,
6380    pub us_max_context: OptionU16,
6381
6382    // os/2 version 3 table
6383    pub us_lower_optical_point_size: OptionU16,
6384    pub us_upper_optical_point_size: OptionU16,
6385}
6386
6387impl Default for FontMetrics {
6388    fn default() -> Self {
6389        FontMetrics::zero()
6390    }
6391}
6392
6393impl FontMetrics {
6394    /// Only for testing, zero-sized font, will always return 0 for every metric (`units_per_em =
6395    /// 1000`)
6396    pub const fn zero() -> Self {
6397        FontMetrics {
6398            units_per_em: 1000,
6399            font_flags: 0,
6400            x_min: 0,
6401            y_min: 0,
6402            x_max: 0,
6403            y_max: 0,
6404            ascender: 0,
6405            descender: 0,
6406            line_gap: 0,
6407            advance_width_max: 0,
6408            min_left_side_bearing: 0,
6409            min_right_side_bearing: 0,
6410            x_max_extent: 0,
6411            caret_slope_rise: 0,
6412            caret_slope_run: 0,
6413            caret_offset: 0,
6414            num_h_metrics: 0,
6415            x_avg_char_width: 0,
6416            us_weight_class: 0,
6417            us_width_class: 0,
6418            fs_type: 0,
6419            y_subscript_x_size: 0,
6420            y_subscript_y_size: 0,
6421            y_subscript_x_offset: 0,
6422            y_subscript_y_offset: 0,
6423            y_superscript_x_size: 0,
6424            y_superscript_y_size: 0,
6425            y_superscript_x_offset: 0,
6426            y_superscript_y_offset: 0,
6427            y_strikeout_size: 0,
6428            y_strikeout_position: 0,
6429            s_family_class: 0,
6430            panose: [0; 10],
6431            ul_unicode_range1: 0,
6432            ul_unicode_range2: 0,
6433            ul_unicode_range3: 0,
6434            ul_unicode_range4: 0,
6435            ach_vend_id: 0,
6436            fs_selection: 0,
6437            us_first_char_index: 0,
6438            us_last_char_index: 0,
6439            s_typo_ascender: OptionI16::None,
6440            s_typo_descender: OptionI16::None,
6441            s_typo_line_gap: OptionI16::None,
6442            us_win_ascent: OptionU16::None,
6443            us_win_descent: OptionU16::None,
6444            ul_code_page_range1: OptionU32::None,
6445            ul_code_page_range2: OptionU32::None,
6446            sx_height: OptionI16::None,
6447            s_cap_height: OptionI16::None,
6448            us_default_char: OptionU16::None,
6449            us_break_char: OptionU16::None,
6450            us_max_context: OptionU16::None,
6451            us_lower_optical_point_size: OptionU16::None,
6452            us_upper_optical_point_size: OptionU16::None,
6453        }
6454    }
6455
6456    /// If set, use `OS/2.sTypoAscender - OS/2.sTypoDescender + OS/2.sTypoLineGap` to calculate the
6457    /// height
6458    ///
6459    /// See [`USE_TYPO_METRICS`](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fss)
6460    pub fn use_typo_metrics(&self) -> bool {
6461        self.fs_selection & (1 << 7) != 0
6462    }
6463
6464    pub fn get_ascender_unscaled(&self) -> i16 {
6465        let use_typo = if !self.use_typo_metrics() {
6466            None
6467        } else {
6468            self.s_typo_ascender.into()
6469        };
6470        match use_typo {
6471            Some(s) => s,
6472            None => self.ascender,
6473        }
6474    }
6475
6476    /// NOTE: descender is NEGATIVE
6477    pub fn get_descender_unscaled(&self) -> i16 {
6478        let use_typo = if !self.use_typo_metrics() {
6479            None
6480        } else {
6481            self.s_typo_descender.into()
6482        };
6483        match use_typo {
6484            Some(s) => s,
6485            None => self.descender,
6486        }
6487    }
6488
6489    pub fn get_line_gap_unscaled(&self) -> i16 {
6490        let use_typo = if !self.use_typo_metrics() {
6491            None
6492        } else {
6493            self.s_typo_line_gap.into()
6494        };
6495        match use_typo {
6496            Some(s) => s,
6497            None => self.line_gap,
6498        }
6499    }
6500
6501    pub fn get_ascender(&self, target_font_size: f32) -> f32 {
6502        self.get_ascender_unscaled() as f32 / self.units_per_em as f32 * target_font_size
6503    }
6504    pub fn get_descender(&self, target_font_size: f32) -> f32 {
6505        self.get_descender_unscaled() as f32 / self.units_per_em as f32 * target_font_size
6506    }
6507    pub fn get_line_gap(&self, target_font_size: f32) -> f32 {
6508        self.get_line_gap_unscaled() as f32 / self.units_per_em as f32 * target_font_size
6509    }
6510
6511    pub fn get_x_min(&self, target_font_size: f32) -> f32 {
6512        self.x_min as f32 / self.units_per_em as f32 * target_font_size
6513    }
6514    pub fn get_y_min(&self, target_font_size: f32) -> f32 {
6515        self.y_min as f32 / self.units_per_em as f32 * target_font_size
6516    }
6517    pub fn get_x_max(&self, target_font_size: f32) -> f32 {
6518        self.x_max as f32 / self.units_per_em as f32 * target_font_size
6519    }
6520    pub fn get_y_max(&self, target_font_size: f32) -> f32 {
6521        self.y_max as f32 / self.units_per_em as f32 * target_font_size
6522    }
6523    pub fn get_advance_width_max(&self, target_font_size: f32) -> f32 {
6524        self.advance_width_max as f32 / self.units_per_em as f32 * target_font_size
6525    }
6526    pub fn get_min_left_side_bearing(&self, target_font_size: f32) -> f32 {
6527        self.min_left_side_bearing as f32 / self.units_per_em as f32 * target_font_size
6528    }
6529    pub fn get_min_right_side_bearing(&self, target_font_size: f32) -> f32 {
6530        self.min_right_side_bearing as f32 / self.units_per_em as f32 * target_font_size
6531    }
6532    pub fn get_x_max_extent(&self, target_font_size: f32) -> f32 {
6533        self.x_max_extent as f32 / self.units_per_em as f32 * target_font_size
6534    }
6535    pub fn get_x_avg_char_width(&self, target_font_size: f32) -> f32 {
6536        self.x_avg_char_width as f32 / self.units_per_em as f32 * target_font_size
6537    }
6538    pub fn get_y_subscript_x_size(&self, target_font_size: f32) -> f32 {
6539        self.y_subscript_x_size as f32 / self.units_per_em as f32 * target_font_size
6540    }
6541    pub fn get_y_subscript_y_size(&self, target_font_size: f32) -> f32 {
6542        self.y_subscript_y_size as f32 / self.units_per_em as f32 * target_font_size
6543    }
6544    pub fn get_y_subscript_x_offset(&self, target_font_size: f32) -> f32 {
6545        self.y_subscript_x_offset as f32 / self.units_per_em as f32 * target_font_size
6546    }
6547    pub fn get_y_subscript_y_offset(&self, target_font_size: f32) -> f32 {
6548        self.y_subscript_y_offset as f32 / self.units_per_em as f32 * target_font_size
6549    }
6550    pub fn get_y_superscript_x_size(&self, target_font_size: f32) -> f32 {
6551        self.y_superscript_x_size as f32 / self.units_per_em as f32 * target_font_size
6552    }
6553    pub fn get_y_superscript_y_size(&self, target_font_size: f32) -> f32 {
6554        self.y_superscript_y_size as f32 / self.units_per_em as f32 * target_font_size
6555    }
6556    pub fn get_y_superscript_x_offset(&self, target_font_size: f32) -> f32 {
6557        self.y_superscript_x_offset as f32 / self.units_per_em as f32 * target_font_size
6558    }
6559    pub fn get_y_superscript_y_offset(&self, target_font_size: f32) -> f32 {
6560        self.y_superscript_y_offset as f32 / self.units_per_em as f32 * target_font_size
6561    }
6562    pub fn get_y_strikeout_size(&self, target_font_size: f32) -> f32 {
6563        self.y_strikeout_size as f32 / self.units_per_em as f32 * target_font_size
6564    }
6565    pub fn get_y_strikeout_position(&self, target_font_size: f32) -> f32 {
6566        self.y_strikeout_position as f32 / self.units_per_em as f32 * target_font_size
6567    }
6568
6569    pub fn get_s_typo_ascender(&self, target_font_size: f32) -> Option<f32> {
6570        self.s_typo_ascender
6571            .map(|s| s as f32 / self.units_per_em as f32 * target_font_size)
6572    }
6573    pub fn get_s_typo_descender(&self, target_font_size: f32) -> Option<f32> {
6574        self.s_typo_descender
6575            .map(|s| s as f32 / self.units_per_em as f32 * target_font_size)
6576    }
6577    pub fn get_s_typo_line_gap(&self, target_font_size: f32) -> Option<f32> {
6578        self.s_typo_line_gap
6579            .map(|s| s as f32 / self.units_per_em as f32 * target_font_size)
6580    }
6581    pub fn get_us_win_ascent(&self, target_font_size: f32) -> Option<f32> {
6582        self.us_win_ascent
6583            .map(|s| s as f32 / self.units_per_em as f32 * target_font_size)
6584    }
6585    pub fn get_us_win_descent(&self, target_font_size: f32) -> Option<f32> {
6586        self.us_win_descent
6587            .map(|s| s as f32 / self.units_per_em as f32 * target_font_size)
6588    }
6589    pub fn get_sx_height(&self, target_font_size: f32) -> Option<f32> {
6590        self.sx_height
6591            .map(|s| s as f32 / self.units_per_em as f32 * target_font_size)
6592    }
6593    pub fn get_s_cap_height(&self, target_font_size: f32) -> Option<f32> {
6594        self.s_cap_height
6595            .map(|s| s as f32 / self.units_per_em as f32 * target_font_size)
6596    }
6597}
6598
6599#[repr(C)]
6600pub struct FontRef {
6601    /// shared pointer to an opaque implementation of the parsed font
6602    pub data: *const FontData,
6603    /// How many copies does this font have (if 0, the font data will be deleted on drop)
6604    pub copies: *const AtomicUsize,
6605    pub run_destructor: bool,
6606}
6607
6608impl fmt::Debug for FontRef {
6609    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6610        write!(f, "printing FontRef 0x{:0x}", self.data as usize)?;
6611        if let Some(d) = unsafe { self.data.as_ref() } {
6612            d.fmt(f)?;
6613        }
6614        if let Some(c) = unsafe { self.copies.as_ref() } {
6615            c.fmt(f)?;
6616        }
6617        Ok(())
6618    }
6619}
6620
6621impl FontRef {
6622    #[inline]
6623    pub fn get_data<'a>(&'a self) -> &'a FontData {
6624        unsafe { &*self.data }
6625    }
6626}
6627
6628impl_option!(
6629    FontRef,
6630    OptionFontRef,
6631    copy = false,
6632    [Debug, Clone, PartialEq, Eq, Hash]
6633);
6634
6635unsafe impl Send for FontRef {}
6636unsafe impl Sync for FontRef {}
6637
6638impl PartialEq for FontRef {
6639    fn eq(&self, rhs: &Self) -> bool {
6640        self.data as usize == rhs.data as usize
6641    }
6642}
6643
6644impl PartialOrd for FontRef {
6645    fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
6646        Some((self.data as usize).cmp(&(other.data as usize)))
6647    }
6648}
6649
6650impl Ord for FontRef {
6651    fn cmp(&self, other: &Self) -> Ordering {
6652        let self_data = self.data as usize;
6653        let other_data = other.data as usize;
6654        self_data.cmp(&other_data)
6655    }
6656}
6657
6658impl Eq for FontRef {}
6659
6660impl Hash for FontRef {
6661    fn hash<H>(&self, state: &mut H)
6662    where
6663        H: Hasher,
6664    {
6665        let self_data = self.data as usize;
6666        self_data.hash(state)
6667    }
6668}
6669
6670impl FontRef {
6671    pub fn new(data: FontData) -> Self {
6672        Self {
6673            data: Box::into_raw(Box::new(data)),
6674            copies: Box::into_raw(Box::new(AtomicUsize::new(1))),
6675            run_destructor: true,
6676        }
6677    }
6678    pub fn get_bytes(&self) -> U8Vec {
6679        self.get_data().bytes.clone()
6680    }
6681}
6682
6683impl Clone for FontRef {
6684    fn clone(&self) -> Self {
6685        unsafe {
6686            self.copies
6687                .as_ref()
6688                .map(|f| f.fetch_add(1, AtomicOrdering::SeqCst));
6689        }
6690        Self {
6691            data: self.data,     // copy the pointer
6692            copies: self.copies, // copy the pointer
6693            run_destructor: true,
6694        }
6695    }
6696}
6697
6698impl Drop for FontRef {
6699    fn drop(&mut self) {
6700        self.run_destructor = false;
6701        unsafe {
6702            let copies = unsafe { (*self.copies).fetch_sub(1, AtomicOrdering::SeqCst) };
6703            if copies == 1 {
6704                let _ = Box::from_raw(self.data as *mut FontData);
6705                let _ = Box::from_raw(self.copies as *mut AtomicUsize);
6706            }
6707        }
6708    }
6709}
6710
6711pub struct FontData {
6712    // T = ParsedFont
6713    /// Bytes of the font file, either &'static (never changing bytes) or a Vec<u8>.
6714    pub bytes: U8Vec,
6715    /// Index of the font in the file (if not known, set to 0) -
6716    /// only relevant if the file is a font collection
6717    pub font_index: u32,
6718    // Since this type has to be defined in the
6719    pub parsed: *const c_void, // *const ParsedFont
6720    // destructor of the ParsedFont
6721    pub parsed_destructor: fn(*mut c_void),
6722}
6723
6724impl fmt::Debug for FontData {
6725    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6726        write!(f, "FontData: {{");
6727        "    bytes: ".fmt(f)?;
6728        self.bytes.len().fmt(f)?;
6729        "    font_index: ".fmt(f)?;
6730        write!(f, "}}")?;
6731        Ok(())
6732    }
6733}
6734
6735unsafe impl Send for FontData {}
6736unsafe impl Sync for FontData {}
6737
6738impl Drop for FontData {
6739    fn drop(&mut self) {
6740        // destroy the ParsedFont
6741        (self.parsed_destructor)(self.parsed as *mut c_void)
6742    }
6743}
6744
6745/// Represents a `font-family` attribute
6746#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6747#[repr(C, u8)]
6748pub enum StyleFontFamily {
6749    /// Native font, such as "Webly Sleeky UI", "monospace", etc.
6750    System(AzString),
6751    /// Font loaded from a file
6752    File(AzString),
6753    /// Reference-counted, already-decoded font,
6754    /// so that specific DOM nodes are required to use this font
6755    Ref(FontRef),
6756}
6757
6758impl StyleFontFamily {
6759    pub(crate) fn as_string(&self) -> String {
6760        match &self {
6761            StyleFontFamily::System(s) => s.clone().into_library_owned_string(),
6762            StyleFontFamily::File(s) => s.clone().into_library_owned_string(),
6763            StyleFontFamily::Ref(s) => format!("{:0x}", s.data as usize),
6764        }
6765    }
6766}
6767
6768impl_vec!(
6769    StyleFontFamily,
6770    StyleFontFamilyVec,
6771    StyleFontFamilyVecDestructor
6772);
6773impl_vec_clone!(
6774    StyleFontFamily,
6775    StyleFontFamilyVec,
6776    StyleFontFamilyVecDestructor
6777);
6778impl_vec_debug!(StyleFontFamily, StyleFontFamilyVec);
6779impl_vec_eq!(StyleFontFamily, StyleFontFamilyVec);
6780impl_vec_ord!(StyleFontFamily, StyleFontFamilyVec);
6781impl_vec_hash!(StyleFontFamily, StyleFontFamilyVec);
6782impl_vec_partialeq!(StyleFontFamily, StyleFontFamilyVec);
6783impl_vec_partialord!(StyleFontFamily, StyleFontFamilyVec);
6784
6785#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6786#[repr(C)]
6787pub enum StyleMixBlendMode {
6788    Normal,
6789    Multiply,
6790    Screen,
6791    Overlay,
6792    Darken,
6793    Lighten,
6794    ColorDodge,
6795    ColorBurn,
6796    HardLight,
6797    SoftLight,
6798    Difference,
6799    Exclusion,
6800    Hue,
6801    Saturation,
6802    Color,
6803    Luminosity,
6804}
6805
6806impl Default for StyleMixBlendMode {
6807    fn default() -> StyleMixBlendMode {
6808        StyleMixBlendMode::Normal
6809    }
6810}
6811
6812impl fmt::Display for StyleMixBlendMode {
6813    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6814        use self::StyleMixBlendMode::*;
6815        write!(
6816            f,
6817            "{}",
6818            match self {
6819                Normal => "normal",
6820                Multiply => "multiply",
6821                Screen => "screen",
6822                Overlay => "overlay",
6823                Darken => "darken",
6824                Lighten => "lighten",
6825                ColorDodge => "color-dodge",
6826                ColorBurn => "color-burn",
6827                HardLight => "hard-light",
6828                SoftLight => "soft-light",
6829                Difference => "difference",
6830                Exclusion => "exclusion",
6831                Hue => "hue",
6832                Saturation => "saturation",
6833                Color => "color",
6834                Luminosity => "luminosity",
6835            }
6836        )
6837    }
6838}
6839
6840#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6841#[repr(C, u8)]
6842pub enum StyleFilter {
6843    Blend(StyleMixBlendMode),
6844    Flood(ColorU),
6845    Blur(StyleBlur),
6846    Opacity(PercentageValue),
6847    ColorMatrix(StyleColorMatrix),
6848    DropShadow(StyleBoxShadow),
6849    ComponentTransfer,
6850    Offset(StyleFilterOffset),
6851    Composite(StyleCompositeFilter),
6852}
6853
6854impl_vec!(StyleFilter, StyleFilterVec, StyleFilterVecDestructor);
6855impl_vec_clone!(StyleFilter, StyleFilterVec, StyleFilterVecDestructor);
6856impl_vec_debug!(StyleFilter, StyleFilterVec);
6857impl_vec_eq!(StyleFilter, StyleFilterVec);
6858impl_vec_ord!(StyleFilter, StyleFilterVec);
6859impl_vec_hash!(StyleFilter, StyleFilterVec);
6860impl_vec_partialeq!(StyleFilter, StyleFilterVec);
6861impl_vec_partialord!(StyleFilter, StyleFilterVec);
6862
6863#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6864#[repr(C)]
6865pub struct StyleBlur {
6866    pub width: PixelValue,
6867    pub height: PixelValue,
6868}
6869
6870#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6871#[repr(C)]
6872pub struct StyleColorMatrix {
6873    pub matrix: [FloatValue; 20],
6874}
6875#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6876#[repr(C)]
6877pub struct StyleFilterOffset {
6878    pub x: PixelValue,
6879    pub y: PixelValue,
6880}
6881
6882#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6883#[repr(C, u8)]
6884pub enum StyleCompositeFilter {
6885    Over,
6886    In,
6887    Atop,
6888    Out,
6889    Xor,
6890    Lighter,
6891    Arithmetic([FloatValue; 4]),
6892}