azul_css/
css_properties.rs

1//! Provides a public API with datatypes used to describe style properties of DOM nodes.
2
3use std::collections::BTreeMap;
4use std::fmt;
5use crate::css::CssPropertyValue;
6
7pub trait FormatAsCssValue {
8    fn format_as_css_value(&self, f: &mut fmt::Formatter) -> fmt::Result;
9}
10
11/// Currently hard-coded: Height of one em in pixels
12pub const EM_HEIGHT: f32 = 16.0;
13pub const PT_TO_PX: f32 = 96.0 / 72.0;
14
15const COMBINED_CSS_PROPERTIES_KEY_MAP: [(CombinedCssPropertyType, &'static str);10] = [
16    (CombinedCssPropertyType::BorderRadius,         "border-radius"),
17    (CombinedCssPropertyType::Overflow,             "overflow"),
18    (CombinedCssPropertyType::Padding,              "padding"),
19    (CombinedCssPropertyType::Margin,               "margin"),
20    (CombinedCssPropertyType::Border,               "border"),
21    (CombinedCssPropertyType::BorderLeft,           "border-left"),
22    (CombinedCssPropertyType::BorderRight,          "border-right"),
23    (CombinedCssPropertyType::BorderTop,            "border-top"),
24    (CombinedCssPropertyType::BorderBottom,         "border-bottom"),
25    (CombinedCssPropertyType::BoxShadow,            "box-shadow"),
26];
27
28/// Map between CSS keys and a statically typed enum
29const CSS_PROPERTY_KEY_MAP: [(CssPropertyType, &'static str);66] = [
30
31    (CssPropertyType::Display,              "display"),
32    (CssPropertyType::Float,                "float"),
33    (CssPropertyType::BoxSizing,            "box-sizing"),
34
35    (CssPropertyType::TextColor,            "color"),
36    (CssPropertyType::FontSize,             "font-size"),
37    (CssPropertyType::FontFamily,           "font-family"),
38    (CssPropertyType::TextAlign,            "text-align"),
39
40    (CssPropertyType::LetterSpacing,        "letter-spacing"),
41    (CssPropertyType::LineHeight,           "line-height"),
42    (CssPropertyType::WordSpacing,          "word-spacing"),
43    (CssPropertyType::TabWidth,             "tab-width"),
44    (CssPropertyType::Cursor,               "cursor"),
45
46    (CssPropertyType::Width,                "width"),
47    (CssPropertyType::Height,               "height"),
48    (CssPropertyType::MinWidth,             "min-width"),
49    (CssPropertyType::MinHeight,            "min-height"),
50    (CssPropertyType::MaxWidth,             "max-width"),
51    (CssPropertyType::MaxHeight,            "max-height"),
52
53    (CssPropertyType::Position,             "position"),
54    (CssPropertyType::Top,                  "top"),
55    (CssPropertyType::Right,                "right"),
56    (CssPropertyType::Left,                 "left"),
57    (CssPropertyType::Bottom,               "bottom"),
58
59    (CssPropertyType::FlexWrap,             "flex-wrap"),
60    (CssPropertyType::FlexDirection,        "flex-direction"),
61    (CssPropertyType::FlexGrow,             "flex-grow"),
62    (CssPropertyType::FlexShrink,           "flex-shrink"),
63    (CssPropertyType::JustifyContent,       "justify-content"),
64    (CssPropertyType::AlignItems,           "align-items"),
65    (CssPropertyType::AlignContent,         "align-content"),
66
67    (CssPropertyType::OverflowX,            "overflow-x"),
68    (CssPropertyType::OverflowY,            "overflow-y"),
69
70    (CssPropertyType::PaddingTop,           "padding-top"),
71    (CssPropertyType::PaddingLeft,          "padding-left"),
72    (CssPropertyType::PaddingRight,         "padding-right"),
73    (CssPropertyType::PaddingBottom,        "padding-bottom"),
74
75    (CssPropertyType::MarginTop,            "margin-top"),
76    (CssPropertyType::MarginLeft,           "margin-left"),
77    (CssPropertyType::MarginRight,          "margin-right"),
78    (CssPropertyType::MarginBottom,         "margin-bottom"),
79
80    (CssPropertyType::Background,           "background"),
81    (CssPropertyType::BackgroundImage,      "background-image"),
82    (CssPropertyType::BackgroundColor,      "background-color"),
83    (CssPropertyType::BackgroundPosition,   "background-position"),
84    (CssPropertyType::BackgroundSize,       "background-size"),
85    (CssPropertyType::BackgroundRepeat,     "background-repeat"),
86
87    (CssPropertyType::BorderTopLeftRadius,      "border-top-left-radius"),
88    (CssPropertyType::BorderTopRightRadius,     "border-top-right-radius"),
89    (CssPropertyType::BorderBottomLeftRadius,   "border-bottom-left-radius"),
90    (CssPropertyType::BorderBottomRightRadius,  "border-bottom-right-radius"),
91
92    (CssPropertyType::BorderTopColor,           "border-top-color"),
93    (CssPropertyType::BorderRightColor,         "border-right-color"),
94    (CssPropertyType::BorderLeftColor,          "border-left-color"),
95    (CssPropertyType::BorderBottomColor,        "border-bottom-color"),
96
97    (CssPropertyType::BorderTopStyle,           "border-top-style"),
98    (CssPropertyType::BorderRightStyle,         "border-right-style"),
99    (CssPropertyType::BorderLeftStyle,          "border-left-style"),
100    (CssPropertyType::BorderBottomStyle,        "border-bottom-style"),
101
102    (CssPropertyType::BorderTopWidth,           "border-top-width"),
103    (CssPropertyType::BorderRightWidth,         "border-right-width"),
104    (CssPropertyType::BorderLeftWidth,          "border-left-width"),
105    (CssPropertyType::BorderBottomWidth,        "border-bottom-width"),
106
107    (CssPropertyType::BoxShadowTop, "box-shadow-top"),
108    (CssPropertyType::BoxShadowRight, "box-shadow-right"),
109    (CssPropertyType::BoxShadowLeft, "box-shadow-left"),
110    (CssPropertyType::BoxShadowBottom, "box-shadow-bottom"),
111];
112
113// The following types are present in webrender, however, azul-css should not
114// depend on webrender, just to have the same types, azul-css should be a standalone crate.
115
116/// Only used for calculations: Rectangle (x, y, width, height) in layout space.
117#[derive(Copy, Clone, PartialEq, PartialOrd)]
118pub struct LayoutRect { pub origin: LayoutPoint, pub size: LayoutSize }
119
120impl fmt::Debug for LayoutRect {
121    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122        write!(f, "{}", self)
123    }
124}
125
126impl fmt::Display for LayoutRect {
127    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
128        write!(f, "{} @ {}", self.size, self.origin)
129    }
130}
131
132impl LayoutRect {
133    #[inline(always)]
134    pub fn new(origin: LayoutPoint, size: LayoutSize) -> Self { Self { origin, size } }
135    #[inline(always)]
136    pub fn zero() -> Self { Self::new(LayoutPoint::zero(), LayoutSize::zero()) }
137    #[inline(always)]
138    pub fn max_x(&self) -> f32 { self.origin.x + self.size.width }
139    #[inline(always)]
140    pub fn min_x(&self) -> f32 { self.origin.x }
141    #[inline(always)]
142    pub fn max_y(&self) -> f32 { self.origin.y + self.size.height }
143    #[inline(always)]
144    pub fn min_y(&self) -> f32 { self.origin.y }
145    #[inline(always)]
146    pub fn contains(&self, other: &LayoutPoint) -> bool {
147        self.min_x() <= other.x && other.x < self.max_x() &&
148        self.min_y() <= other.y && other.y < self.max_y()
149    }
150
151    /// Faster union for a Vec<LayoutRect>
152    #[inline]
153    pub fn union<I: Iterator<Item=Self>>(mut rects: I) -> Option<Self> {
154        let first = rects.next()?;
155
156        let mut max_width = first.size.width;
157        let mut max_height = first.size.height;
158        let mut min_x = first.origin.x;
159        let mut min_y = first.origin.y;
160
161        while let Some(Self { origin: LayoutPoint { x, y }, size: LayoutSize { width, height } }) = rects.next() {
162            let cur_lower_right_x = x + width;
163            let cur_lower_right_y = y + height;
164            max_width = max_width.max(cur_lower_right_x - min_x);
165            max_height = max_height.max(cur_lower_right_y - min_y);
166            min_x = min_x.min(x);
167            min_y = min_y.min(y);
168        }
169
170        Some(Self {
171            origin: LayoutPoint { x: min_x, y: min_y },
172            size: LayoutSize { width: max_width, height: max_height },
173        })
174    }
175
176    // Returns the scroll rect (not the union rect) of the parent / children
177    #[inline]
178    pub fn get_scroll_rect<I: Iterator<Item=Self>>(&self, children: I) -> Option<Self> {
179        let children_union = Self::union(children)?;
180        Self::union([*self, children_union].iter().map(|r| *r))
181    }
182
183    // Returns if b overlaps a
184    #[inline(always)]
185    pub fn contains_rect(&self, b: &LayoutRect) -> bool {
186
187        let a = self;
188
189        let a_x         = a.origin.x;
190        let a_y         = a.origin.y;
191        let a_width     = a.size.width;
192        let a_height    = a.size.height;
193
194        let b_x         = b.origin.x;
195        let b_y         = b.origin.y;
196        let b_width     = b.size.width;
197        let b_height    = b.size.height;
198
199        b_x >= a_x &&
200        b_y >= a_y &&
201        b_x + b_width <= a_x + a_width &&
202        b_y + b_height <= a_y + a_height
203    }
204}
205
206/// Only used for calculations: Size (width, height) in layout space.
207#[derive(Copy, Clone, PartialEq, PartialOrd)]
208pub struct LayoutSize { pub width: f32, pub height: f32 }
209
210impl fmt::Debug for LayoutSize {
211    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212        write!(f, "{}", self)
213    }
214}
215
216impl fmt::Display for LayoutSize {
217    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
218        write!(f, "{}x{}", self.width, self.height)
219    }
220}
221
222impl LayoutSize {
223    #[inline(always)]
224    pub const fn new(width: f32, height: f32) -> Self { Self { width, height } }
225    #[inline(always)]
226    pub const fn zero() -> Self { Self::new(0.0, 0.0) }
227}
228
229/// Only used for calculations: Point coordinate (x, y) in layout space.
230#[derive(Copy, Clone, PartialEq, PartialOrd)]
231pub struct LayoutPoint { pub x: f32, pub y: f32 }
232
233impl fmt::Debug for LayoutPoint {
234    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
235        write!(f, "{}", self)
236    }
237}
238
239impl fmt::Display for LayoutPoint {
240    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
241        write!(f, "({}, {})", self.x, self.y)
242    }
243}
244
245impl LayoutPoint {
246    #[inline(always)]
247    pub const fn new(x: f32, y: f32) -> Self { Self { x, y } }
248    #[inline(always)]
249    pub const fn zero() -> Self { Self::new(0.0, 0.0) }
250}
251
252/// Represents a parsed pair of `5px, 10px` values - useful for border radius calculation
253#[derive(Default, Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
254pub struct PixelSize { pub width: PixelValue, pub height: PixelValue }
255
256impl PixelSize {
257
258    pub const fn new(width: PixelValue, height: PixelValue) -> Self {
259        Self {
260            width,
261            height,
262        }
263    }
264
265    pub const fn zero() -> Self {
266        Self::new(PixelValue::const_px(0), PixelValue::const_px(0))
267    }
268}
269
270/// Offsets of the border-width calculations
271#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
272pub struct LayoutSideOffsets {
273    pub top: FloatValue,
274    pub right: FloatValue,
275    pub bottom: FloatValue,
276    pub left: FloatValue,
277}
278
279/// u8-based color, range 0 to 255 (similar to webrenders ColorU)
280#[derive(Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
281pub struct ColorU { pub r: u8, pub g: u8, pub b: u8, pub a: u8 }
282
283impl Default for ColorU { fn default() -> Self { ColorU::BLACK } }
284
285impl fmt::Debug for ColorU {
286    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
287        write!(f, "rgba({}, {}, {}, {})", self.r, self.g, self.b, self.a as f32 / 255.0)
288    }
289}
290
291impl fmt::Display for ColorU {
292    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
293        write!(f, "rgba({}, {}, {}, {})", self.r, self.g, self.b, self.a as f32 / 255.0)
294    }
295}
296
297impl ColorU {
298    pub const RED: ColorU = ColorU { r: 255, g: 0, b: 0, a: 255 };
299    pub const WHITE: ColorU = ColorU { r: 255, g: 255, b: 255, a: 255 };
300    pub const BLACK: ColorU = ColorU { r: 0, g: 0, b: 0, a: 255 };
301    pub const TRANSPARENT: ColorU = ColorU { r: 0, g: 0, b: 0, a: 0 };
302
303    pub fn write_hash(&self, f: &mut fmt::Formatter) -> fmt::Result {
304        write!(f, "#{:x}{:x}{:x}{:x}", self.r, self.g, self.b, self.a)
305    }
306}
307
308/// f32-based color, range 0.0 to 1.0 (similar to webrenders ColorF)
309#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
310pub struct ColorF { pub r: f32, pub g: f32, pub b: f32, pub a: f32 }
311
312impl Default for ColorF { fn default() -> Self { ColorF::BLACK } }
313
314impl fmt::Display for ColorF {
315    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
316        write!(f, "rgba({}, {}, {}, {})", self.r * 255.0, self.g * 255.0, self.b * 255.0, self.a)
317    }
318}
319
320impl ColorF {
321    pub const WHITE: ColorF = ColorF { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
322    pub const BLACK: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.0, a: 1.0 };
323    pub const TRANSPARENT: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.0, a: 0.0 };
324}
325
326impl From<ColorU> for ColorF {
327    fn from(input: ColorU) -> ColorF {
328        ColorF {
329            r: (input.r as f32) / 255.0,
330            g: (input.g as f32) / 255.0,
331            b: (input.b as f32) / 255.0,
332            a: (input.a as f32) / 255.0,
333        }
334    }
335}
336
337impl From<ColorF> for ColorU {
338    fn from(input: ColorF) -> ColorU {
339        ColorU {
340            r: (input.r.min(1.0) * 255.0) as u8,
341            g: (input.g.min(1.0) * 255.0) as u8,
342            b: (input.b.min(1.0) * 255.0) as u8,
343            a: (input.a.min(1.0) * 255.0) as u8,
344        }
345    }
346}
347
348#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
349pub enum BorderDetails {
350    Normal(NormalBorder),
351    NinePatch(NinePatchBorder),
352}
353
354/// Represents a normal `border` property (no image border / nine-patch border)
355#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
356pub struct NormalBorder {
357    pub left: BorderSide,
358    pub right: BorderSide,
359    pub top: BorderSide,
360    pub bottom: BorderSide,
361    pub radius: Option<(
362        StyleBorderTopLeftRadius,
363        StyleBorderTopRightRadius,
364        StyleBorderBottomLeftRadius,
365        StyleBorderBottomRightRadius,
366    )>,
367}
368
369#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
370pub struct BorderSide {
371    pub color: ColorU,
372    pub style: BorderStyle,
373}
374
375/// What direction should a `box-shadow` be clipped in (inset or outset)
376#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
377pub enum BoxShadowClipMode {
378    Outset,
379    Inset,
380}
381
382impl fmt::Display for BoxShadowClipMode {
383    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
384        use self::BoxShadowClipMode::*;
385        match self {
386            Outset => write!(f, "outset"),
387            Inset => write!(f, "inset"),
388        }
389    }
390}
391
392/// Whether a `gradient` should be repeated or clamped to the edges.
393#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
394pub enum ExtendMode {
395    Clamp,
396    Repeat,
397}
398
399/// Style of a `border`: solid, double, dash, ridge, etc.
400#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
401pub enum BorderStyle {
402    None,
403    Solid,
404    Double,
405    Dotted,
406    Dashed,
407    Hidden,
408    Groove,
409    Ridge,
410    Inset,
411    Outset,
412}
413
414impl fmt::Display for BorderStyle {
415    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
416        use self::BorderStyle::*;
417        match self {
418            None => write!(f, "none"),
419            Solid => write!(f, "solid"),
420            Double => write!(f, "double"),
421            Dotted => write!(f, "dotted"),
422            Dashed => write!(f, "dashed"),
423            Hidden => write!(f, "hidden"),
424            Groove => write!(f, "groove"),
425            Ridge => write!(f, "ridge"),
426            Inset => write!(f, "inset"),
427            Outset => write!(f, "outset"),
428        }
429    }
430}
431
432impl BorderStyle {
433    pub fn normalize_border(self) -> Option<BorderStyleNoNone> {
434        match self {
435            BorderStyle::None => None,
436            BorderStyle::Solid => Some(BorderStyleNoNone::Solid),
437            BorderStyle::Double => Some(BorderStyleNoNone::Double),
438            BorderStyle::Dotted => Some(BorderStyleNoNone::Dotted),
439            BorderStyle::Dashed => Some(BorderStyleNoNone::Dashed),
440            BorderStyle::Hidden => Some(BorderStyleNoNone::Hidden),
441            BorderStyle::Groove => Some(BorderStyleNoNone::Groove),
442            BorderStyle::Ridge => Some(BorderStyleNoNone::Ridge),
443            BorderStyle::Inset => Some(BorderStyleNoNone::Inset),
444            BorderStyle::Outset => Some(BorderStyleNoNone::Outset),
445        }
446    }
447}
448
449#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
450pub enum BorderStyleNoNone {
451    Solid,
452    Double,
453    Dotted,
454    Dashed,
455    Hidden,
456    Groove,
457    Ridge,
458    Inset,
459    Outset,
460}
461
462
463impl Default for BorderStyle {
464    fn default() -> Self {
465        BorderStyle::Solid
466    }
467}
468
469#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
470pub struct NinePatchBorder {
471    // not implemented or parse-able yet, so no fields!
472}
473
474macro_rules! derive_debug_zero {($struct:ident) => (
475    impl fmt::Debug for $struct {
476        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
477            write!(f, "{:?}", self.0)
478        }
479    }
480)}
481
482macro_rules! derive_display_zero {($struct:ident) => (
483    impl fmt::Display for $struct {
484        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
485            write!(f, "{}", self.0)
486        }
487    }
488)}
489
490/// Creates `pt`, `px` and `em` constructors for any struct that has a
491/// `PixelValue` as it's self.0 field.
492macro_rules! impl_pixel_value {($struct:ident) => (
493
494    derive_debug_zero!($struct);
495    derive_display_zero!($struct);
496
497    impl $struct {
498        #[inline]
499        pub fn px(value: f32) -> Self {
500            $struct(PixelValue::px(value))
501        }
502
503        #[inline]
504        pub fn em(value: f32) -> Self {
505            $struct(PixelValue::em(value))
506        }
507
508        #[inline]
509        pub fn pt(value: f32) -> Self {
510            $struct(PixelValue::pt(value))
511        }
512    }
513
514    impl FormatAsCssValue for $struct {
515        fn format_as_css_value(&self, f: &mut fmt::Formatter) -> fmt::Result {
516            self.0.format_as_css_value(f)
517        }
518    }
519)}
520
521macro_rules! impl_percentage_value{($struct:ident) => (
522    impl ::std::fmt::Display for $struct {
523        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
524            write!(f, "{}%", self.0.get())
525        }
526    }
527
528    impl ::std::fmt::Debug for $struct {
529        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
530            write!(f, "{}%", self.0.get())
531        }
532    }
533
534    impl FormatAsCssValue for $struct {
535        fn format_as_css_value(&self, f: &mut fmt::Formatter) -> fmt::Result {
536            write!(f, "{}%", self.0.get())
537        }
538    }
539)}
540
541macro_rules! impl_float_value{($struct:ident) => (
542    impl ::std::fmt::Display for $struct {
543        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
544            write!(f, "{}", self.0.get())
545        }
546    }
547
548    impl ::std::fmt::Debug for $struct {
549        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
550            write!(f, "{}", self.0.get())
551        }
552    }
553
554    impl FormatAsCssValue for $struct {
555        fn format_as_css_value(&self, f: &mut fmt::Formatter) -> fmt::Result {
556            write!(f, "{}", self.0.get())
557        }
558    }
559)}
560
561#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
562pub enum CombinedCssPropertyType {
563    BorderRadius,
564    Overflow,
565    Margin,
566    Border,
567    BorderLeft,
568    BorderRight,
569    BorderTop,
570    BorderBottom,
571    Padding,
572    BoxShadow,
573}
574
575impl fmt::Display for CombinedCssPropertyType {
576    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
577        let key = COMBINED_CSS_PROPERTIES_KEY_MAP.iter().find(|(v, _)| *v == *self).and_then(|(k, _)| Some(k)).unwrap();
578        write!(f, "{}", key)
579    }
580}
581
582impl CombinedCssPropertyType {
583
584    /// Parses a CSS key, such as `width` from a string:
585    ///
586    /// # Example
587    ///
588    /// ```rust
589    /// # use azul_css::{CombinedCssPropertyType, get_css_key_map};
590    /// let map = get_css_key_map();
591    /// assert_eq!(Some(CombinedCssPropertyType::Border), CombinedCssPropertyType::from_str("border", &map));
592    /// ```
593    pub fn from_str(input: &str, map: &CssKeyMap) -> Option<Self> {
594        let input = input.trim();
595        map.shorthands.get(input).map(|x| *x)
596    }
597
598    /// Returns the original string that was used to construct this `CssPropertyType`.
599    pub fn to_str(&self, map: &CssKeyMap) -> &'static str {
600        map.shorthands.iter().find(|(_, v)| *v == self).map(|(k, _)| k).unwrap()
601    }
602}
603
604#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
605pub struct CssKeyMap {
606    // Contains all keys that have no shorthand
607    pub non_shorthands: BTreeMap<&'static str, CssPropertyType>,
608    // Contains all keys that act as a shorthand for other types
609    pub shorthands: BTreeMap<&'static str, CombinedCssPropertyType>,
610}
611
612/// Returns a map useful for parsing the keys of CSS stylesheets
613pub fn get_css_key_map() -> CssKeyMap {
614    CssKeyMap {
615        non_shorthands: CSS_PROPERTY_KEY_MAP.iter().map(|(v, k)| (*k, *v)).collect(),
616        shorthands: COMBINED_CSS_PROPERTIES_KEY_MAP.iter().map(|(v, k)| (*k, *v)).collect(),
617    }
618}
619
620/// Represents a CSS key (for example `"border-radius"` => `BorderRadius`).
621/// You can also derive this key from a `CssProperty` by calling `CssProperty::get_type()`.
622#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
623pub enum CssPropertyType {
624
625    TextColor,
626    FontSize,
627    FontFamily,
628    TextAlign,
629
630    LetterSpacing,
631    LineHeight,
632    WordSpacing,
633    TabWidth,
634    Cursor,
635
636    Display,
637    Float,
638    BoxSizing,
639    Width,
640    Height,
641    MinWidth,
642    MinHeight,
643    MaxWidth,
644    MaxHeight,
645
646    Position,
647    Top,
648    Right,
649    Left,
650    Bottom,
651
652    FlexWrap,
653    FlexDirection,
654    FlexGrow,
655    FlexShrink,
656    JustifyContent,
657    AlignItems,
658    AlignContent,
659
660    OverflowX,
661    OverflowY,
662
663    PaddingTop,
664    PaddingLeft,
665    PaddingRight,
666    PaddingBottom,
667
668    MarginTop,
669    MarginLeft,
670    MarginRight,
671    MarginBottom,
672
673    Background,
674    BackgroundImage, // -> BackgroundContent::Image
675    BackgroundColor, // -> BackgroundContent::Color
676    BackgroundPosition,
677    BackgroundSize,
678    BackgroundRepeat,
679
680    BorderTopLeftRadius,
681    BorderTopRightRadius,
682    BorderBottomLeftRadius,
683    BorderBottomRightRadius,
684
685    BorderTopColor,
686    BorderRightColor,
687    BorderLeftColor,
688    BorderBottomColor,
689
690    BorderTopStyle,
691    BorderRightStyle,
692    BorderLeftStyle,
693    BorderBottomStyle,
694
695    BorderTopWidth,
696    BorderRightWidth,
697    BorderLeftWidth,
698    BorderBottomWidth,
699
700    BoxShadowLeft,
701    BoxShadowRight,
702    BoxShadowTop,
703    BoxShadowBottom,
704}
705
706impl CssPropertyType {
707
708    /// Parses a CSS key, such as `width` from a string:
709    ///
710    /// # Example
711    ///
712    /// ```rust
713    /// # use azul_css::{CssPropertyType, get_css_key_map};
714    /// let map = get_css_key_map();
715    /// assert_eq!(Some(CssPropertyType::Width), CssPropertyType::from_str("width", &map));
716    /// assert_eq!(Some(CssPropertyType::JustifyContent), CssPropertyType::from_str("justify-content", &map));
717    /// assert_eq!(None, CssPropertyType::from_str("asdfasdfasdf", &map));
718    /// ```
719    pub fn from_str(input: &str, map: &CssKeyMap) -> Option<Self> {
720        let input = input.trim();
721        map.non_shorthands.get(input).and_then(|x| Some(*x))
722    }
723
724    /// Returns the original string that was used to construct this `CssPropertyType`.
725    pub fn to_str(&self, map: &CssKeyMap) -> &'static str {
726        map.non_shorthands.iter().find(|(_, v)| *v == self).and_then(|(k, _)| Some(k)).unwrap()
727    }
728
729    /// Returns whether this property will be inherited during cascading
730    pub fn is_inheritable(&self) -> bool {
731        use self::CssPropertyType::*;
732        match self {
733            | TextColor
734            | FontFamily
735            | FontSize
736            | LineHeight
737            | TextAlign => true,
738            _ => false,
739        }
740    }
741
742    /// Returns whether this property can trigger a re-layout (important for incremental layout and caching layouted DOMs).
743    pub fn can_trigger_relayout(&self) -> bool {
744
745        use self::CssPropertyType::*;
746
747        // Since the border can be larger than the content,
748        // in which case the content needs to be re-layouted, assume true for Border
749
750        // FontFamily, FontSize, LetterSpacing and LineHeight can affect
751        // the text layout and therefore the screen layout
752
753        match self {
754            | TextColor
755            | Cursor
756            | Background
757            | BackgroundPosition
758            | BackgroundSize
759            | BackgroundRepeat
760            | BackgroundImage
761            | BorderTopLeftRadius
762            | BorderTopRightRadius
763            | BorderBottomLeftRadius
764            | BorderBottomRightRadius
765            | BorderTopColor
766            | BorderRightColor
767            | BorderLeftColor
768            | BorderBottomColor
769            | BorderTopStyle
770            | BorderRightStyle
771            | BorderLeftStyle
772            | BorderBottomStyle
773            | BoxShadowLeft
774            | BoxShadowRight
775            | BoxShadowTop
776            | BoxShadowBottom
777            => false,
778            _ => true,
779        }
780    }
781}
782
783impl fmt::Display for CssPropertyType {
784    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
785        let key = CSS_PROPERTY_KEY_MAP.iter().find(|(v, _)| *v == *self).and_then(|(k, _)| Some(k)).unwrap();
786        write!(f, "{}", key)
787    }
788}
789
790/// Represents one parsed CSS key-value pair, such as `"width: 20px"` => `CssProperty::Width(LayoutWidth::px(20.0))`
791#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
792pub enum CssProperty {
793
794    TextColor(CssPropertyValue<StyleTextColor>),
795    FontSize(CssPropertyValue<StyleFontSize>),
796    FontFamily(CssPropertyValue<StyleFontFamily>),
797    TextAlign(CssPropertyValue<StyleTextAlignmentHorz>),
798
799    LetterSpacing(CssPropertyValue<StyleLetterSpacing>),
800    LineHeight(CssPropertyValue<StyleLineHeight>),
801    WordSpacing(CssPropertyValue<StyleWordSpacing>),
802    TabWidth(CssPropertyValue<StyleTabWidth>),
803    Cursor(CssPropertyValue<StyleCursor>),
804
805    Display(CssPropertyValue<LayoutDisplay>),
806    Float(CssPropertyValue<LayoutFloat>),
807    BoxSizing(CssPropertyValue<LayoutBoxSizing>),
808
809    Width(CssPropertyValue<LayoutWidth>),
810    Height(CssPropertyValue<LayoutHeight>),
811    MinWidth(CssPropertyValue<LayoutMinWidth>),
812    MinHeight(CssPropertyValue<LayoutMinHeight>),
813    MaxWidth(CssPropertyValue<LayoutMaxWidth>),
814    MaxHeight(CssPropertyValue<LayoutMaxHeight>),
815
816    Position(CssPropertyValue<LayoutPosition>),
817    Top(CssPropertyValue<LayoutTop>),
818    Right(CssPropertyValue<LayoutRight>),
819    Left(CssPropertyValue<LayoutLeft>),
820    Bottom(CssPropertyValue<LayoutBottom>),
821
822    FlexWrap(CssPropertyValue<LayoutWrap>),
823    FlexDirection(CssPropertyValue<LayoutDirection>),
824    FlexGrow(CssPropertyValue<LayoutFlexGrow>),
825    FlexShrink(CssPropertyValue<LayoutFlexShrink>),
826    JustifyContent(CssPropertyValue<LayoutJustifyContent>),
827    AlignItems(CssPropertyValue<LayoutAlignItems>),
828    AlignContent(CssPropertyValue<LayoutAlignContent>),
829
830    BackgroundContent(CssPropertyValue<StyleBackgroundContent>),
831    BackgroundPosition(CssPropertyValue<StyleBackgroundPosition>),
832    BackgroundSize(CssPropertyValue<StyleBackgroundSize>),
833    BackgroundRepeat(CssPropertyValue<StyleBackgroundRepeat>),
834
835    OverflowX(CssPropertyValue<Overflow>),
836    OverflowY(CssPropertyValue<Overflow>),
837
838    PaddingTop(CssPropertyValue<LayoutPaddingTop>),
839    PaddingLeft(CssPropertyValue<LayoutPaddingLeft>),
840    PaddingRight(CssPropertyValue<LayoutPaddingRight>),
841    PaddingBottom(CssPropertyValue<LayoutPaddingBottom>),
842
843    MarginTop(CssPropertyValue<LayoutMarginTop>),
844    MarginLeft(CssPropertyValue<LayoutMarginLeft>),
845    MarginRight(CssPropertyValue<LayoutMarginRight>),
846    MarginBottom(CssPropertyValue<LayoutMarginBottom>),
847
848    BorderTopLeftRadius(CssPropertyValue<StyleBorderTopLeftRadius>),
849    BorderTopRightRadius(CssPropertyValue<StyleBorderTopRightRadius>),
850    BorderBottomLeftRadius(CssPropertyValue<StyleBorderBottomLeftRadius>),
851    BorderBottomRightRadius(CssPropertyValue<StyleBorderBottomRightRadius>),
852
853    BorderTopColor(CssPropertyValue<StyleBorderTopColor>),
854    BorderRightColor(CssPropertyValue<StyleBorderRightColor>),
855    BorderLeftColor(CssPropertyValue<StyleBorderLeftColor>),
856    BorderBottomColor(CssPropertyValue<StyleBorderBottomColor>),
857
858    BorderTopStyle(CssPropertyValue<StyleBorderTopStyle>),
859    BorderRightStyle(CssPropertyValue<StyleBorderRightStyle>),
860    BorderLeftStyle(CssPropertyValue<StyleBorderLeftStyle>),
861    BorderBottomStyle(CssPropertyValue<StyleBorderBottomStyle>),
862
863    BorderTopWidth(CssPropertyValue<StyleBorderTopWidth>),
864    BorderRightWidth(CssPropertyValue<StyleBorderRightWidth>),
865    BorderLeftWidth(CssPropertyValue<StyleBorderLeftWidth>),
866    BorderBottomWidth(CssPropertyValue<StyleBorderBottomWidth>),
867
868    BoxShadowLeft(CssPropertyValue<BoxShadowPreDisplayItem>),
869    BoxShadowRight(CssPropertyValue<BoxShadowPreDisplayItem>),
870    BoxShadowTop(CssPropertyValue<BoxShadowPreDisplayItem>),
871    BoxShadowBottom(CssPropertyValue<BoxShadowPreDisplayItem>),
872}
873
874macro_rules! css_property_from_type {($prop_type:expr, $content_type:ident) => ({
875    match $prop_type {
876        CssPropertyType::TextColor => CssProperty::TextColor(CssPropertyValue::$content_type),
877        CssPropertyType::FontSize => CssProperty::FontSize(CssPropertyValue::$content_type),
878        CssPropertyType::FontFamily => CssProperty::FontFamily(CssPropertyValue::$content_type),
879        CssPropertyType::TextAlign => CssProperty::TextAlign(CssPropertyValue::$content_type),
880        CssPropertyType::LetterSpacing => CssProperty::LetterSpacing(CssPropertyValue::$content_type),
881        CssPropertyType::LineHeight => CssProperty::LineHeight(CssPropertyValue::$content_type),
882        CssPropertyType::WordSpacing => CssProperty::WordSpacing(CssPropertyValue::$content_type),
883        CssPropertyType::TabWidth => CssProperty::TabWidth(CssPropertyValue::$content_type),
884        CssPropertyType::Cursor => CssProperty::Cursor(CssPropertyValue::$content_type),
885        CssPropertyType::Display => CssProperty::Display(CssPropertyValue::$content_type),
886        CssPropertyType::Float => CssProperty::Float(CssPropertyValue::$content_type),
887        CssPropertyType::BoxSizing => CssProperty::BoxSizing(CssPropertyValue::$content_type),
888        CssPropertyType::Width => CssProperty::Width(CssPropertyValue::$content_type),
889        CssPropertyType::Height => CssProperty::Height(CssPropertyValue::$content_type),
890        CssPropertyType::MinWidth => CssProperty::MinWidth(CssPropertyValue::$content_type),
891        CssPropertyType::MinHeight => CssProperty::MinHeight(CssPropertyValue::$content_type),
892        CssPropertyType::MaxWidth => CssProperty::MaxWidth(CssPropertyValue::$content_type),
893        CssPropertyType::MaxHeight => CssProperty::MaxHeight(CssPropertyValue::$content_type),
894        CssPropertyType::Position => CssProperty::Position(CssPropertyValue::$content_type),
895        CssPropertyType::Top => CssProperty::Top(CssPropertyValue::$content_type),
896        CssPropertyType::Right => CssProperty::Right(CssPropertyValue::$content_type),
897        CssPropertyType::Left => CssProperty::Left(CssPropertyValue::$content_type),
898        CssPropertyType::Bottom => CssProperty::Bottom(CssPropertyValue::$content_type),
899        CssPropertyType::FlexWrap => CssProperty::FlexWrap(CssPropertyValue::$content_type),
900        CssPropertyType::FlexDirection => CssProperty::FlexDirection(CssPropertyValue::$content_type),
901        CssPropertyType::FlexGrow => CssProperty::FlexGrow(CssPropertyValue::$content_type),
902        CssPropertyType::FlexShrink => CssProperty::FlexShrink(CssPropertyValue::$content_type),
903        CssPropertyType::JustifyContent => CssProperty::JustifyContent(CssPropertyValue::$content_type),
904        CssPropertyType::AlignItems => CssProperty::AlignItems(CssPropertyValue::$content_type),
905        CssPropertyType::AlignContent => CssProperty::AlignContent(CssPropertyValue::$content_type),
906        CssPropertyType::OverflowX => CssProperty::OverflowX(CssPropertyValue::$content_type),
907        CssPropertyType::OverflowY => CssProperty::OverflowY(CssPropertyValue::$content_type),
908        CssPropertyType::PaddingTop => CssProperty::PaddingTop(CssPropertyValue::$content_type),
909        CssPropertyType::PaddingLeft => CssProperty::PaddingLeft(CssPropertyValue::$content_type),
910        CssPropertyType::PaddingRight => CssProperty::PaddingRight(CssPropertyValue::$content_type),
911        CssPropertyType::PaddingBottom => CssProperty::PaddingBottom(CssPropertyValue::$content_type),
912        CssPropertyType::MarginTop => CssProperty::MarginTop(CssPropertyValue::$content_type),
913        CssPropertyType::MarginLeft => CssProperty::MarginLeft(CssPropertyValue::$content_type),
914        CssPropertyType::MarginRight => CssProperty::MarginRight(CssPropertyValue::$content_type),
915        CssPropertyType::MarginBottom => CssProperty::MarginBottom(CssPropertyValue::$content_type),
916        CssPropertyType::Background => CssProperty::BackgroundContent(CssPropertyValue::$content_type),
917        CssPropertyType::BackgroundImage => CssProperty::BackgroundContent(CssPropertyValue::$content_type), // -> BackgroundContent::Image
918        CssPropertyType::BackgroundColor => CssProperty::BackgroundContent(CssPropertyValue::$content_type), // -> BackgroundContent::Color
919        CssPropertyType::BackgroundPosition => CssProperty::BackgroundPosition(CssPropertyValue::$content_type),
920        CssPropertyType::BackgroundSize => CssProperty::BackgroundSize(CssPropertyValue::$content_type),
921        CssPropertyType::BackgroundRepeat => CssProperty::BackgroundRepeat(CssPropertyValue::$content_type),
922        CssPropertyType::BorderTopLeftRadius => CssProperty::BorderTopLeftRadius(CssPropertyValue::$content_type),
923        CssPropertyType::BorderTopRightRadius => CssProperty::BorderTopRightRadius(CssPropertyValue::$content_type),
924        CssPropertyType::BorderBottomLeftRadius => CssProperty::BorderBottomLeftRadius(CssPropertyValue::$content_type),
925        CssPropertyType::BorderBottomRightRadius => CssProperty::BorderBottomRightRadius(CssPropertyValue::$content_type),
926        CssPropertyType::BorderTopColor => CssProperty::BorderTopColor(CssPropertyValue::$content_type),
927        CssPropertyType::BorderRightColor => CssProperty::BorderRightColor(CssPropertyValue::$content_type),
928        CssPropertyType::BorderLeftColor => CssProperty::BorderLeftColor(CssPropertyValue::$content_type),
929        CssPropertyType::BorderBottomColor => CssProperty::BorderBottomColor(CssPropertyValue::$content_type),
930        CssPropertyType::BorderTopStyle => CssProperty::BorderTopStyle(CssPropertyValue::$content_type),
931        CssPropertyType::BorderRightStyle => CssProperty::BorderRightStyle(CssPropertyValue::$content_type),
932        CssPropertyType::BorderLeftStyle => CssProperty::BorderLeftStyle(CssPropertyValue::$content_type),
933        CssPropertyType::BorderBottomStyle => CssProperty::BorderBottomStyle(CssPropertyValue::$content_type),
934        CssPropertyType::BorderTopWidth => CssProperty::BorderTopWidth(CssPropertyValue::$content_type),
935        CssPropertyType::BorderRightWidth => CssProperty::BorderRightWidth(CssPropertyValue::$content_type),
936        CssPropertyType::BorderLeftWidth => CssProperty::BorderLeftWidth(CssPropertyValue::$content_type),
937        CssPropertyType::BorderBottomWidth => CssProperty::BorderBottomWidth(CssPropertyValue::$content_type),
938        CssPropertyType::BoxShadowLeft => CssProperty::BoxShadowLeft(CssPropertyValue::$content_type),
939        CssPropertyType::BoxShadowRight => CssProperty::BoxShadowRight(CssPropertyValue::$content_type),
940        CssPropertyType::BoxShadowTop => CssProperty::BoxShadowTop(CssPropertyValue::$content_type),
941        CssPropertyType::BoxShadowBottom => CssProperty::BoxShadowBottom(CssPropertyValue::$content_type),
942    }
943})}
944
945impl CssProperty {
946
947    /// Return the type (key) of this property as a statically typed enum
948    pub fn get_type(&self) -> CssPropertyType {
949        match &self {
950            CssProperty::TextColor(_) => CssPropertyType::TextColor,
951            CssProperty::FontSize(_) => CssPropertyType::FontSize,
952            CssProperty::FontFamily(_) => CssPropertyType::FontFamily,
953            CssProperty::TextAlign(_) => CssPropertyType::TextAlign,
954            CssProperty::LetterSpacing(_) => CssPropertyType::LetterSpacing,
955            CssProperty::LineHeight(_) => CssPropertyType::LineHeight,
956            CssProperty::WordSpacing(_) => CssPropertyType::WordSpacing,
957            CssProperty::TabWidth(_) => CssPropertyType::TabWidth,
958            CssProperty::Cursor(_) => CssPropertyType::Cursor,
959            CssProperty::Display(_) => CssPropertyType::Display,
960            CssProperty::Float(_) => CssPropertyType::Float,
961            CssProperty::BoxSizing(_) => CssPropertyType::BoxSizing,
962            CssProperty::Width(_) => CssPropertyType::Width,
963            CssProperty::Height(_) => CssPropertyType::Height,
964            CssProperty::MinWidth(_) => CssPropertyType::MinWidth,
965            CssProperty::MinHeight(_) => CssPropertyType::MinHeight,
966            CssProperty::MaxWidth(_) => CssPropertyType::MaxWidth,
967            CssProperty::MaxHeight(_) => CssPropertyType::MaxHeight,
968            CssProperty::Position(_) => CssPropertyType::Position,
969            CssProperty::Top(_) => CssPropertyType::Top,
970            CssProperty::Right(_) => CssPropertyType::Right,
971            CssProperty::Left(_) => CssPropertyType::Left,
972            CssProperty::Bottom(_) => CssPropertyType::Bottom,
973            CssProperty::FlexWrap(_) => CssPropertyType::FlexWrap,
974            CssProperty::FlexDirection(_) => CssPropertyType::FlexDirection,
975            CssProperty::FlexGrow(_) => CssPropertyType::FlexGrow,
976            CssProperty::FlexShrink(_) => CssPropertyType::FlexShrink,
977            CssProperty::JustifyContent(_) => CssPropertyType::JustifyContent,
978            CssProperty::AlignItems(_) => CssPropertyType::AlignItems,
979            CssProperty::AlignContent(_) => CssPropertyType::AlignContent,
980
981            CssProperty::BackgroundContent(_) => CssPropertyType::BackgroundImage, // TODO: wrong!
982            CssProperty::BackgroundPosition(_) => CssPropertyType::BackgroundPosition,
983            CssProperty::BackgroundSize(_) => CssPropertyType::BackgroundSize,
984            CssProperty::BackgroundRepeat(_) => CssPropertyType::BackgroundRepeat,
985
986            CssProperty::OverflowX(_) => CssPropertyType::OverflowX,
987            CssProperty::OverflowY(_) => CssPropertyType::OverflowY,
988            CssProperty::PaddingTop(_) => CssPropertyType::PaddingTop,
989            CssProperty::PaddingLeft(_) => CssPropertyType::PaddingLeft,
990            CssProperty::PaddingRight(_) => CssPropertyType::PaddingRight,
991            CssProperty::PaddingBottom(_) => CssPropertyType::PaddingBottom,
992            CssProperty::MarginTop(_) => CssPropertyType::MarginTop,
993            CssProperty::MarginLeft(_) => CssPropertyType::MarginLeft,
994            CssProperty::MarginRight(_) => CssPropertyType::MarginRight,
995            CssProperty::MarginBottom(_) => CssPropertyType::MarginBottom,
996            CssProperty::BorderTopLeftRadius(_) => CssPropertyType::BorderTopLeftRadius,
997            CssProperty::BorderTopRightRadius(_) => CssPropertyType::BorderTopRightRadius,
998            CssProperty::BorderBottomLeftRadius(_) => CssPropertyType::BorderBottomLeftRadius,
999            CssProperty::BorderBottomRightRadius(_) => CssPropertyType::BorderBottomRightRadius,
1000            CssProperty::BorderTopColor(_) => CssPropertyType::BorderTopColor,
1001            CssProperty::BorderRightColor(_) => CssPropertyType::BorderRightColor,
1002            CssProperty::BorderLeftColor(_) => CssPropertyType::BorderLeftColor,
1003            CssProperty::BorderBottomColor(_) => CssPropertyType::BorderBottomColor,
1004            CssProperty::BorderTopStyle(_) => CssPropertyType::BorderTopStyle,
1005            CssProperty::BorderRightStyle(_) => CssPropertyType::BorderRightStyle,
1006            CssProperty::BorderLeftStyle(_) => CssPropertyType::BorderLeftStyle,
1007            CssProperty::BorderBottomStyle(_) => CssPropertyType::BorderBottomStyle,
1008            CssProperty::BorderTopWidth(_) => CssPropertyType::BorderTopWidth,
1009            CssProperty::BorderRightWidth(_) => CssPropertyType::BorderRightWidth,
1010            CssProperty::BorderLeftWidth(_) => CssPropertyType::BorderLeftWidth,
1011            CssProperty::BorderBottomWidth(_) => CssPropertyType::BorderBottomWidth,
1012            CssProperty::BoxShadowLeft(_) => CssPropertyType::BoxShadowLeft,
1013            CssProperty::BoxShadowRight(_) => CssPropertyType::BoxShadowRight,
1014            CssProperty::BoxShadowTop(_) => CssPropertyType::BoxShadowTop,
1015            CssProperty::BoxShadowBottom(_) => CssPropertyType::BoxShadowBottom,
1016        }
1017    }
1018
1019    pub fn none(prop_type: CssPropertyType) -> Self {
1020        css_property_from_type!(prop_type, None)
1021    }
1022
1023    pub fn auto(prop_type: CssPropertyType) -> Self {
1024        css_property_from_type!(prop_type, Auto)
1025    }
1026
1027    pub fn initial(prop_type: CssPropertyType) -> Self {
1028        css_property_from_type!(prop_type, Initial)
1029    }
1030
1031    pub fn inherit(prop_type: CssPropertyType) -> Self {
1032        css_property_from_type!(prop_type, Inherit)
1033    }
1034
1035
1036    /// Creates a `text_color` CSS attribute
1037    pub const fn text_color(input: StyleTextColor) -> Self { CssProperty::TextColor(CssPropertyValue::Exact(input)) }
1038
1039    /// Creates a `font_size` CSS attribute
1040    pub const fn font_size(input: StyleFontSize) -> Self { CssProperty::FontSize(CssPropertyValue::Exact(input)) }
1041
1042    /// Creates a `font_family` CSS attribute
1043    pub const fn font_family(input: StyleFontFamily) -> Self { CssProperty::FontFamily(CssPropertyValue::Exact(input)) }
1044
1045    /// Creates a `text_align` CSS attribute
1046    pub const fn text_align(input: StyleTextAlignmentHorz) -> Self { CssProperty::TextAlign(CssPropertyValue::Exact(input)) }
1047
1048    /// Creates a `letter_spacing` CSS attribute
1049    pub const fn letter_spacing(input: StyleLetterSpacing) -> Self { CssProperty::LetterSpacing(CssPropertyValue::Exact(input)) }
1050
1051    /// Creates a `line_height` CSS attribute
1052    pub const fn line_height(input: StyleLineHeight) -> Self { CssProperty::LineHeight(CssPropertyValue::Exact(input)) }
1053
1054    /// Creates a `word_spacing` CSS attribute
1055    pub const fn word_spacing(input: StyleWordSpacing) -> Self { CssProperty::WordSpacing(CssPropertyValue::Exact(input)) }
1056
1057    /// Creates a `tab_width` CSS attribute
1058    pub const fn tab_width(input: StyleTabWidth) -> Self { CssProperty::TabWidth(CssPropertyValue::Exact(input)) }
1059
1060    /// Creates a `cursor` CSS attribute
1061    pub const fn cursor(input: StyleCursor) -> Self { CssProperty::Cursor(CssPropertyValue::Exact(input)) }
1062
1063    /// Creates a `display` CSS attribute
1064    pub const fn display(input: LayoutDisplay) -> Self { CssProperty::Display(CssPropertyValue::Exact(input)) }
1065
1066    /// Creates a `float` CSS attribute
1067    pub const fn float(input: LayoutFloat) -> Self { CssProperty::Float(CssPropertyValue::Exact(input)) }
1068
1069    /// Creates a `box_sizing` CSS attribute
1070    pub const fn box_sizing(input: LayoutBoxSizing) -> Self { CssProperty::BoxSizing(CssPropertyValue::Exact(input)) }
1071
1072    /// Creates a `width` CSS attribute
1073    pub const fn width(input: LayoutWidth) -> Self { CssProperty::Width(CssPropertyValue::Exact(input)) }
1074
1075    /// Creates a `height` CSS attribute
1076    pub const fn height(input: LayoutHeight) -> Self { CssProperty::Height(CssPropertyValue::Exact(input)) }
1077
1078    /// Creates a `min_width` CSS attribute
1079    pub const fn min_width(input: LayoutMinWidth) -> Self { CssProperty::MinWidth(CssPropertyValue::Exact(input)) }
1080
1081    /// Creates a `min_height` CSS attribute
1082    pub const fn min_height(input: LayoutMinHeight) -> Self { CssProperty::MinHeight(CssPropertyValue::Exact(input)) }
1083
1084    /// Creates a `max_width` CSS attribute
1085    pub const fn max_width(input: LayoutMaxWidth) -> Self { CssProperty::MaxWidth(CssPropertyValue::Exact(input)) }
1086
1087    /// Creates a `max_height` CSS attribute
1088    pub const fn max_height(input: LayoutMaxHeight) -> Self { CssProperty::MaxHeight(CssPropertyValue::Exact(input)) }
1089
1090    /// Creates a `position` CSS attribute
1091    pub const fn position(input: LayoutPosition) -> Self { CssProperty::Position(CssPropertyValue::Exact(input)) }
1092
1093    /// Creates a `top` CSS attribute
1094    pub const fn top(input: LayoutTop) -> Self { CssProperty::Top(CssPropertyValue::Exact(input)) }
1095
1096    /// Creates a `right` CSS attribute
1097    pub const fn right(input: LayoutRight) -> Self { CssProperty::Right(CssPropertyValue::Exact(input)) }
1098
1099    /// Creates a `left` CSS attribute
1100    pub const fn left(input: LayoutLeft) -> Self { CssProperty::Left(CssPropertyValue::Exact(input)) }
1101
1102    /// Creates a `bottom` CSS attribute
1103    pub const fn bottom(input: LayoutBottom) -> Self { CssProperty::Bottom(CssPropertyValue::Exact(input)) }
1104
1105    /// Creates a `flex_wrap` CSS attribute
1106    pub const fn flex_wrap(input: LayoutWrap) -> Self { CssProperty::FlexWrap(CssPropertyValue::Exact(input)) }
1107
1108    /// Creates a `flex_direction` CSS attribute
1109    pub const fn flex_direction(input: LayoutDirection) -> Self { CssProperty::FlexDirection(CssPropertyValue::Exact(input)) }
1110
1111    /// Creates a `flex_grow` CSS attribute
1112    pub const fn flex_grow(input: LayoutFlexGrow) -> Self { CssProperty::FlexGrow(CssPropertyValue::Exact(input)) }
1113
1114    /// Creates a `flex_shrink` CSS attribute
1115    pub const fn flex_shrink(input: LayoutFlexShrink) -> Self { CssProperty::FlexShrink(CssPropertyValue::Exact(input)) }
1116
1117    /// Creates a `justify_content` CSS attribute
1118    pub const fn justify_content(input: LayoutJustifyContent) -> Self { CssProperty::JustifyContent(CssPropertyValue::Exact(input)) }
1119
1120    /// Creates a `align_items` CSS attribute
1121    pub const fn align_items(input: LayoutAlignItems) -> Self { CssProperty::AlignItems(CssPropertyValue::Exact(input)) }
1122
1123    /// Creates a `align_content` CSS attribute
1124    pub const fn align_content(input: LayoutAlignContent) -> Self { CssProperty::AlignContent(CssPropertyValue::Exact(input)) }
1125
1126    /// Creates a `background_content` CSS attribute
1127    pub const fn background_content(input: StyleBackgroundContent) -> Self { CssProperty::BackgroundContent(CssPropertyValue::Exact(input)) }
1128
1129    /// Creates a `background_position` CSS attribute
1130    pub const fn background_position(input: StyleBackgroundPosition) -> Self { CssProperty::BackgroundPosition(CssPropertyValue::Exact(input)) }
1131
1132    /// Creates a `background_size` CSS attribute
1133    pub const fn background_size(input: StyleBackgroundSize) -> Self { CssProperty::BackgroundSize(CssPropertyValue::Exact(input)) }
1134
1135    /// Creates a `background_repeat` CSS attribute
1136    pub const fn background_repeat(input: StyleBackgroundRepeat) -> Self { CssProperty::BackgroundRepeat(CssPropertyValue::Exact(input)) }
1137
1138    /// Creates a `overflow_x` CSS attribute
1139    pub const fn overflow_x(input: Overflow) -> Self { CssProperty::OverflowX(CssPropertyValue::Exact(input)) }
1140
1141    /// Creates a `overflow_y` CSS attribute
1142    pub const fn overflow_y(input: Overflow) -> Self { CssProperty::OverflowY(CssPropertyValue::Exact(input)) }
1143
1144    /// Creates a `padding_top` CSS attribute
1145    pub const fn padding_top(input: LayoutPaddingTop) -> Self { CssProperty::PaddingTop(CssPropertyValue::Exact(input)) }
1146
1147    /// Creates a `padding_left` CSS attribute
1148    pub const fn padding_left(input: LayoutPaddingLeft) -> Self { CssProperty::PaddingLeft(CssPropertyValue::Exact(input)) }
1149
1150    /// Creates a `padding_right` CSS attribute
1151    pub const fn padding_right(input: LayoutPaddingRight) -> Self { CssProperty::PaddingRight(CssPropertyValue::Exact(input)) }
1152
1153    /// Creates a `padding_bottom` CSS attribute
1154    pub const fn padding_bottom(input: LayoutPaddingBottom) -> Self { CssProperty::PaddingBottom(CssPropertyValue::Exact(input)) }
1155
1156    /// Creates a `margin_top` CSS attribute
1157    pub const fn margin_top(input: LayoutMarginTop) -> Self { CssProperty::MarginTop(CssPropertyValue::Exact(input)) }
1158
1159    /// Creates a `margin_left` CSS attribute
1160    pub const fn margin_left(input: LayoutMarginLeft) -> Self { CssProperty::MarginLeft(CssPropertyValue::Exact(input)) }
1161
1162    /// Creates a `margin_right` CSS attribute
1163    pub const fn margin_right(input: LayoutMarginRight) -> Self { CssProperty::MarginRight(CssPropertyValue::Exact(input)) }
1164
1165    /// Creates a `margin_bottom` CSS attribute
1166    pub const fn margin_bottom(input: LayoutMarginBottom) -> Self { CssProperty::MarginBottom(CssPropertyValue::Exact(input)) }
1167
1168    /// Creates a `border_top_left_radius` CSS attribute
1169    pub const fn border_top_left_radius(input: StyleBorderTopLeftRadius) -> Self { CssProperty::BorderTopLeftRadius(CssPropertyValue::Exact(input)) }
1170
1171    /// Creates a `border_top_right_radius` CSS attribute
1172    pub const fn border_top_right_radius(input: StyleBorderTopRightRadius) -> Self { CssProperty::BorderTopRightRadius(CssPropertyValue::Exact(input)) }
1173
1174    /// Creates a `border_bottom_left_radius` CSS attribute
1175    pub const fn border_bottom_left_radius(input: StyleBorderBottomLeftRadius) -> Self { CssProperty::BorderBottomLeftRadius(CssPropertyValue::Exact(input)) }
1176
1177    /// Creates a `border_bottom_right_radius` CSS attribute
1178    pub const fn border_bottom_right_radius(input: StyleBorderBottomRightRadius) -> Self { CssProperty::BorderBottomRightRadius(CssPropertyValue::Exact(input)) }
1179
1180    /// Creates a `border_top_color` CSS attribute
1181    pub const fn border_top_color(input: StyleBorderTopColor) -> Self { CssProperty::BorderTopColor(CssPropertyValue::Exact(input)) }
1182
1183    /// Creates a `border_right_color` CSS attribute
1184    pub const fn border_right_color(input: StyleBorderRightColor) -> Self { CssProperty::BorderRightColor(CssPropertyValue::Exact(input)) }
1185
1186    /// Creates a `border_left_color` CSS attribute
1187    pub const fn border_left_color(input: StyleBorderLeftColor) -> Self { CssProperty::BorderLeftColor(CssPropertyValue::Exact(input)) }
1188
1189    /// Creates a `border_bottom_color` CSS attribute
1190    pub const fn border_bottom_color(input: StyleBorderBottomColor) -> Self { CssProperty::BorderBottomColor(CssPropertyValue::Exact(input)) }
1191
1192    /// Creates a `border_top_style` CSS attribute
1193    pub const fn border_top_style(input: StyleBorderTopStyle) -> Self { CssProperty::BorderTopStyle(CssPropertyValue::Exact(input)) }
1194
1195    /// Creates a `border_right_style` CSS attribute
1196    pub const fn border_right_style(input: StyleBorderRightStyle) -> Self { CssProperty::BorderRightStyle(CssPropertyValue::Exact(input)) }
1197
1198    /// Creates a `border_left_style` CSS attribute
1199    pub const fn border_left_style(input: StyleBorderLeftStyle) -> Self { CssProperty::BorderLeftStyle(CssPropertyValue::Exact(input)) }
1200
1201    /// Creates a `border_bottom_style` CSS attribute
1202    pub const fn border_bottom_style(input: StyleBorderBottomStyle) -> Self { CssProperty::BorderBottomStyle(CssPropertyValue::Exact(input)) }
1203
1204    /// Creates a `border_top_width` CSS attribute
1205    pub const fn border_top_width(input: StyleBorderTopWidth) -> Self { CssProperty::BorderTopWidth(CssPropertyValue::Exact(input)) }
1206
1207    /// Creates a `border_right_width` CSS attribute
1208    pub const fn border_right_width(input: StyleBorderRightWidth) -> Self { CssProperty::BorderRightWidth(CssPropertyValue::Exact(input)) }
1209
1210    /// Creates a `border_left_width` CSS attribute
1211    pub const fn border_left_width(input: StyleBorderLeftWidth) -> Self { CssProperty::BorderLeftWidth(CssPropertyValue::Exact(input)) }
1212
1213    /// Creates a `border_bottom_width` CSS attribute
1214    pub const fn border_bottom_width(input: StyleBorderBottomWidth) -> Self { CssProperty::BorderBottomWidth(CssPropertyValue::Exact(input)) }
1215
1216    /// Creates a `box_shadow_left` CSS attribute
1217    pub const fn box_shadow_left(input: BoxShadowPreDisplayItem) -> Self { CssProperty::BoxShadowLeft(CssPropertyValue::Exact(input)) }
1218
1219    /// Creates a `box_shadow_right` CSS attribute
1220    pub const fn box_shadow_right(input: BoxShadowPreDisplayItem) -> Self { CssProperty::BoxShadowRight(CssPropertyValue::Exact(input)) }
1221
1222    /// Creates a `box_shadow_top` CSS attribute
1223    pub const fn box_shadow_top(input: BoxShadowPreDisplayItem) -> Self { CssProperty::BoxShadowTop(CssPropertyValue::Exact(input)) }
1224
1225    /// Creates a `box_shadow_bottom` CSS attribute
1226    pub const fn box_shadow_bottom(input: BoxShadowPreDisplayItem) -> Self { CssProperty::BoxShadowBottom(CssPropertyValue::Exact(input)) }
1227
1228}
1229
1230macro_rules! impl_from_css_prop {
1231    ($a:ident, $b:ident::$enum_type:ident) => {
1232        impl From<$a> for $b {
1233            fn from(e: $a) -> Self {
1234                $b::$enum_type(CssPropertyValue::from(e))
1235            }
1236        }
1237    };
1238}
1239
1240impl_from_css_prop!(StyleTextColor, CssProperty::TextColor);
1241impl_from_css_prop!(StyleFontSize, CssProperty::FontSize);
1242impl_from_css_prop!(StyleFontFamily, CssProperty::FontFamily);
1243impl_from_css_prop!(StyleTextAlignmentHorz, CssProperty::TextAlign);
1244impl_from_css_prop!(StyleLetterSpacing, CssProperty::LetterSpacing);
1245impl_from_css_prop!(StyleLineHeight, CssProperty::LineHeight);
1246impl_from_css_prop!(StyleWordSpacing, CssProperty::WordSpacing);
1247impl_from_css_prop!(StyleTabWidth, CssProperty::TabWidth);
1248impl_from_css_prop!(StyleCursor, CssProperty::Cursor);
1249impl_from_css_prop!(LayoutDisplay, CssProperty::Display);
1250impl_from_css_prop!(LayoutFloat, CssProperty::Float);
1251impl_from_css_prop!(LayoutBoxSizing, CssProperty::BoxSizing);
1252impl_from_css_prop!(LayoutWidth, CssProperty::Width);
1253impl_from_css_prop!(LayoutHeight, CssProperty::Height);
1254impl_from_css_prop!(LayoutMinWidth, CssProperty::MinWidth);
1255impl_from_css_prop!(LayoutMinHeight, CssProperty::MinHeight);
1256impl_from_css_prop!(LayoutMaxWidth, CssProperty::MaxWidth);
1257impl_from_css_prop!(LayoutMaxHeight, CssProperty::MaxHeight);
1258impl_from_css_prop!(LayoutPosition, CssProperty::Position);
1259impl_from_css_prop!(LayoutTop, CssProperty::Top);
1260impl_from_css_prop!(LayoutRight, CssProperty::Right);
1261impl_from_css_prop!(LayoutLeft, CssProperty::Left);
1262impl_from_css_prop!(LayoutBottom, CssProperty::Bottom);
1263impl_from_css_prop!(LayoutWrap, CssProperty::FlexWrap);
1264impl_from_css_prop!(LayoutDirection, CssProperty::FlexDirection);
1265impl_from_css_prop!(LayoutFlexGrow, CssProperty::FlexGrow);
1266impl_from_css_prop!(LayoutFlexShrink, CssProperty::FlexShrink);
1267impl_from_css_prop!(LayoutJustifyContent, CssProperty::JustifyContent);
1268impl_from_css_prop!(LayoutAlignItems, CssProperty::AlignItems);
1269impl_from_css_prop!(LayoutAlignContent, CssProperty::AlignContent);
1270impl_from_css_prop!(StyleBackgroundContent, CssProperty::BackgroundContent);
1271impl_from_css_prop!(StyleBackgroundPosition, CssProperty::BackgroundPosition);
1272impl_from_css_prop!(StyleBackgroundSize, CssProperty::BackgroundSize);
1273impl_from_css_prop!(StyleBackgroundRepeat, CssProperty::BackgroundRepeat);
1274impl_from_css_prop!(LayoutPaddingTop, CssProperty::PaddingTop);
1275impl_from_css_prop!(LayoutPaddingLeft, CssProperty::PaddingLeft);
1276impl_from_css_prop!(LayoutPaddingRight, CssProperty::PaddingRight);
1277impl_from_css_prop!(LayoutPaddingBottom, CssProperty::PaddingBottom);
1278impl_from_css_prop!(LayoutMarginTop, CssProperty::MarginTop);
1279impl_from_css_prop!(LayoutMarginLeft, CssProperty::MarginLeft);
1280impl_from_css_prop!(LayoutMarginRight, CssProperty::MarginRight);
1281impl_from_css_prop!(LayoutMarginBottom, CssProperty::MarginBottom);
1282impl_from_css_prop!(StyleBorderTopLeftRadius, CssProperty::BorderTopLeftRadius);
1283impl_from_css_prop!(StyleBorderTopRightRadius, CssProperty::BorderTopRightRadius);
1284impl_from_css_prop!(StyleBorderBottomLeftRadius, CssProperty::BorderBottomLeftRadius);
1285impl_from_css_prop!(StyleBorderBottomRightRadius, CssProperty::BorderBottomRightRadius);
1286impl_from_css_prop!(StyleBorderTopColor, CssProperty::BorderTopColor);
1287impl_from_css_prop!(StyleBorderRightColor, CssProperty::BorderRightColor);
1288impl_from_css_prop!(StyleBorderLeftColor, CssProperty::BorderLeftColor);
1289impl_from_css_prop!(StyleBorderBottomColor, CssProperty::BorderBottomColor);
1290impl_from_css_prop!(StyleBorderTopStyle, CssProperty::BorderTopStyle);
1291impl_from_css_prop!(StyleBorderRightStyle, CssProperty::BorderRightStyle);
1292impl_from_css_prop!(StyleBorderLeftStyle, CssProperty::BorderLeftStyle);
1293impl_from_css_prop!(StyleBorderBottomStyle, CssProperty::BorderBottomStyle);
1294impl_from_css_prop!(StyleBorderTopWidth, CssProperty::BorderTopWidth);
1295impl_from_css_prop!(StyleBorderRightWidth, CssProperty::BorderRightWidth);
1296impl_from_css_prop!(StyleBorderLeftWidth, CssProperty::BorderLeftWidth);
1297impl_from_css_prop!(StyleBorderBottomWidth, CssProperty::BorderBottomWidth);
1298
1299/// Multiplier for floating point accuracy. Elements such as px or %
1300/// are only accurate until a certain number of decimal points, therefore
1301/// they have to be casted to isizes in order to make the f32 values
1302/// hash-able: Css has a relatively low precision here, roughly 5 digits, i.e
1303/// `1.00001 == 1.0`
1304const FP_PRECISION_MULTIPLIER: f32 = 1000.0;
1305const FP_PRECISION_MULTIPLIER_CONST: isize = FP_PRECISION_MULTIPLIER as isize;
1306
1307/// Same as PixelValue, but doesn't allow a "%" sign
1308#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1309pub struct PixelValueNoPercent(pub PixelValue);
1310
1311impl fmt::Display for PixelValueNoPercent {
1312    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1313        write!(f, "{}", self.0)
1314    }
1315}
1316
1317impl PixelValueNoPercent {
1318    pub fn to_pixels(&self) -> f32 {
1319        self.0.to_pixels(0.0)
1320    }
1321}
1322
1323/// FloatValue, but associated with a certain metric (i.e. px, em, etc.)
1324#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1325pub struct PixelValue {
1326    pub metric: SizeMetric,
1327    pub number: FloatValue,
1328}
1329
1330impl fmt::Debug for PixelValue {
1331    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1332        write!(f, "{}{}", self.number, self.metric)
1333    }
1334}
1335
1336// Manual Debug implementation, because the auto-generated one is nearly unreadable
1337impl fmt::Display for PixelValue {
1338    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1339        write!(f, "{}{}", self.number, self.metric)
1340    }
1341}
1342
1343impl FormatAsCssValue for PixelValue {
1344    fn format_as_css_value(&self, f: &mut fmt::Formatter) -> fmt::Result {
1345        write!(f, "{}{}", self.number, self.metric)
1346    }
1347}
1348
1349impl fmt::Display for SizeMetric {
1350    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1351        use self::SizeMetric::*;
1352        match self {
1353            Px => write!(f, "px"),
1354            Pt => write!(f, "pt"),
1355            Em => write!(f, "pt"),
1356            Percent => write!(f, "%"),
1357        }
1358    }
1359}
1360
1361impl PixelValue {
1362
1363    #[inline]
1364    pub const fn zero() -> Self {
1365        const ZERO_PX: PixelValue = PixelValue::const_px(0);
1366        ZERO_PX
1367    }
1368
1369    /// Same as `PixelValue::px()`, but only accepts whole numbers,
1370    /// since using `f32` in const fn is not yet stabilized.
1371    #[inline]
1372    pub const fn const_px(value: isize) -> Self {
1373        Self::const_from_metric(SizeMetric::Px, value)
1374    }
1375
1376    /// Same as `PixelValue::em()`, but only accepts whole numbers,
1377    /// since using `f32` in const fn is not yet stabilized.
1378    #[inline]
1379    pub const fn const_em(value: isize) -> Self {
1380        Self::const_from_metric(SizeMetric::Em, value)
1381    }
1382
1383    /// Same as `PixelValue::pt()`, but only accepts whole numbers,
1384    /// since using `f32` in const fn is not yet stabilized.
1385    #[inline]
1386    pub const fn const_pt(value: isize) -> Self {
1387        Self::const_from_metric(SizeMetric::Pt, value)
1388    }
1389
1390    /// Same as `PixelValue::pt()`, but only accepts whole numbers,
1391    /// since using `f32` in const fn is not yet stabilized.
1392    #[inline]
1393    pub const fn const_percent(value: isize) -> Self {
1394        Self::const_from_metric(SizeMetric::Percent, value)
1395    }
1396
1397    #[inline]
1398    pub const fn const_from_metric(metric: SizeMetric, value: isize) -> Self {
1399        Self {
1400            metric: metric,
1401            number: FloatValue::const_new(value),
1402        }
1403    }
1404
1405    #[inline]
1406    pub fn px(value: f32) -> Self {
1407        Self::from_metric(SizeMetric::Px, value)
1408    }
1409
1410    #[inline]
1411    pub fn em(value: f32) -> Self {
1412        Self::from_metric(SizeMetric::Em, value)
1413    }
1414
1415    #[inline]
1416    pub fn pt(value: f32) -> Self {
1417        Self::from_metric(SizeMetric::Pt, value)
1418    }
1419
1420    #[inline]
1421    pub fn percent(value: f32) -> Self {
1422        Self::from_metric(SizeMetric::Percent, value)
1423    }
1424
1425    #[inline]
1426    pub fn from_metric(metric: SizeMetric, value: f32) -> Self {
1427        Self {
1428            metric: metric,
1429            number: FloatValue::new(value),
1430        }
1431    }
1432
1433    /// Returns the value of the SizeMetric in pixels
1434    #[inline]
1435    pub fn to_pixels(&self, percent_resolve: f32) -> f32 {
1436        match self.metric {
1437            SizeMetric::Px => self.number.get(),
1438            SizeMetric::Pt => self.number.get() * PT_TO_PX,
1439            SizeMetric::Em => self.number.get() * EM_HEIGHT,
1440            SizeMetric::Percent => self.number.get() / 100.0 * percent_resolve,
1441        }
1442    }
1443}
1444
1445/// Wrapper around FloatValue, represents a percentage instead
1446/// of just being a regular floating-point value, i.e `5` = `5%`
1447#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1448pub struct PercentageValue {
1449    number: FloatValue,
1450}
1451
1452impl fmt::Display for PercentageValue {
1453    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1454        write!(f, "{}%", self.get())
1455    }
1456}
1457
1458impl PercentageValue {
1459
1460    /// Same as `PercentageValue::new()`, but only accepts whole numbers,
1461    /// since using `f32` in const fn is not yet stabilized.
1462    pub const fn const_new(value: isize) -> Self {
1463        Self { number: FloatValue::const_new(value) }
1464    }
1465
1466    pub fn new(value: f32) -> Self {
1467        Self { number: value.into() }
1468    }
1469
1470    pub fn get(&self) -> f32 {
1471        self.number.get()
1472    }
1473}
1474
1475/// Wrapper around an f32 value that is internally casted to an isize,
1476/// in order to provide hash-ability (to avoid numerical instability).
1477#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1478pub struct FloatValue {
1479    pub number: isize,
1480}
1481
1482impl fmt::Display for FloatValue {
1483    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1484        write!(f, "{}", self.get())
1485    }
1486}
1487
1488impl Default for FloatValue {
1489    fn default() -> Self {
1490        const DEFAULT_FLV: FloatValue = FloatValue::const_new(0);
1491        DEFAULT_FLV
1492    }
1493}
1494
1495impl FloatValue {
1496
1497    /// Same as `FloatValue::new()`, but only accepts whole numbers,
1498    /// since using `f32` in const fn is not yet stabilized.
1499    pub const fn const_new(value: isize)  -> Self {
1500        Self { number: value * FP_PRECISION_MULTIPLIER_CONST }
1501    }
1502
1503    pub fn new(value: f32) -> Self {
1504        Self { number: (value * FP_PRECISION_MULTIPLIER) as isize }
1505    }
1506
1507    pub fn get(&self) -> f32 {
1508        self.number as f32 / FP_PRECISION_MULTIPLIER
1509    }
1510}
1511
1512impl From<f32> for FloatValue {
1513    fn from(val: f32) -> Self {
1514        Self::new(val)
1515    }
1516}
1517
1518/// Enum representing the metric associated with a number (px, pt, em, etc.)
1519#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1520pub enum SizeMetric {
1521    Px,
1522    Pt,
1523    Em,
1524    Percent,
1525}
1526
1527impl Default for SizeMetric {
1528    fn default() -> Self { SizeMetric::Px }
1529}
1530
1531/// Represents a `background-size` attribute
1532#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1533pub enum StyleBackgroundSize {
1534    ExactSize(PixelValue, PixelValue),
1535    Contain,
1536    Cover,
1537}
1538
1539/// Represents a `background-position` attribute
1540#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1541pub struct StyleBackgroundPosition {
1542    pub horizontal: BackgroundPositionHorizontal,
1543    pub vertical: BackgroundPositionVertical,
1544}
1545
1546impl Default for StyleBackgroundPosition {
1547    fn default() -> Self {
1548        StyleBackgroundPosition {
1549            horizontal: BackgroundPositionHorizontal::Left,
1550            vertical: BackgroundPositionVertical::Top,
1551        }
1552    }
1553}
1554
1555#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1556pub enum BackgroundPositionHorizontal {
1557    Left,
1558    Center,
1559    Right,
1560    Exact(PixelValue),
1561}
1562
1563#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1564pub enum BackgroundPositionVertical {
1565    Top,
1566    Center,
1567    Bottom,
1568    Exact(PixelValue),
1569}
1570
1571/// Represents a `background-repeat` attribute
1572#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1573pub enum StyleBackgroundRepeat {
1574    NoRepeat,
1575    Repeat,
1576    RepeatX,
1577    RepeatY,
1578}
1579
1580impl Default for StyleBackgroundRepeat {
1581    fn default() -> Self {
1582        StyleBackgroundRepeat::Repeat
1583    }
1584}
1585
1586/// Represents a `color` attribute
1587#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1588pub struct StyleTextColor(pub ColorU);
1589
1590derive_debug_zero!(StyleTextColor);
1591derive_display_zero!(StyleTextColor);
1592
1593// -- TODO: Technically, border-radius can take two values for each corner!
1594
1595/// Represents a `border-top-width` attribute
1596#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1597pub struct StyleBorderTopLeftRadius(pub PixelValue);
1598/// Represents a `border-left-width` attribute
1599#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1600pub struct StyleBorderBottomLeftRadius(pub PixelValue);
1601/// Represents a `border-right-width` attribute
1602#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1603pub struct StyleBorderTopRightRadius(pub PixelValue);
1604/// Represents a `border-bottom-width` attribute
1605#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1606pub struct StyleBorderBottomRightRadius(pub PixelValue);
1607
1608impl_pixel_value!(StyleBorderTopLeftRadius);
1609impl_pixel_value!(StyleBorderBottomLeftRadius);
1610impl_pixel_value!(StyleBorderTopRightRadius);
1611impl_pixel_value!(StyleBorderBottomRightRadius);
1612
1613/// Represents a `border-top-width` attribute
1614#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1615pub struct StyleBorderTopWidth(pub PixelValue);
1616/// Represents a `border-left-width` attribute
1617#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1618pub struct StyleBorderLeftWidth(pub PixelValue);
1619/// Represents a `border-right-width` attribute
1620#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1621pub struct StyleBorderRightWidth(pub PixelValue);
1622/// Represents a `border-bottom-width` attribute
1623#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1624pub struct StyleBorderBottomWidth(pub PixelValue);
1625
1626impl_pixel_value!(StyleBorderTopWidth);
1627impl_pixel_value!(StyleBorderLeftWidth);
1628impl_pixel_value!(StyleBorderRightWidth);
1629impl_pixel_value!(StyleBorderBottomWidth);
1630
1631/// Represents a `border-top-width` attribute
1632#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1633pub struct StyleBorderTopStyle(pub BorderStyle);
1634/// Represents a `border-left-width` attribute
1635#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1636pub struct StyleBorderLeftStyle(pub BorderStyle);
1637/// Represents a `border-right-width` attribute
1638#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1639pub struct StyleBorderRightStyle(pub BorderStyle);
1640/// Represents a `border-bottom-width` attribute
1641#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1642pub struct StyleBorderBottomStyle(pub BorderStyle);
1643
1644derive_debug_zero!(StyleBorderTopStyle);
1645derive_debug_zero!(StyleBorderLeftStyle);
1646derive_debug_zero!(StyleBorderBottomStyle);
1647derive_debug_zero!(StyleBorderRightStyle);
1648
1649derive_display_zero!(StyleBorderTopStyle);
1650derive_display_zero!(StyleBorderLeftStyle);
1651derive_display_zero!(StyleBorderBottomStyle);
1652derive_display_zero!(StyleBorderRightStyle);
1653
1654/// Represents a `border-top-width` attribute
1655#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1656pub struct StyleBorderTopColor(pub ColorU);
1657/// Represents a `border-left-width` attribute
1658#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1659pub struct StyleBorderLeftColor(pub ColorU);
1660/// Represents a `border-right-width` attribute
1661#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1662pub struct StyleBorderRightColor(pub ColorU);
1663/// Represents a `border-bottom-width` attribute
1664#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1665pub struct StyleBorderBottomColor(pub ColorU);
1666
1667derive_debug_zero!(StyleBorderTopColor);
1668derive_debug_zero!(StyleBorderLeftColor);
1669derive_debug_zero!(StyleBorderRightColor);
1670derive_debug_zero!(StyleBorderBottomColor);
1671
1672derive_display_zero!(StyleBorderTopColor);
1673derive_display_zero!(StyleBorderLeftColor);
1674derive_display_zero!(StyleBorderRightColor);
1675derive_display_zero!(StyleBorderBottomColor);
1676
1677#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1678pub struct StyleBorderSide {
1679    pub border_width: PixelValue,
1680    pub border_style: BorderStyle,
1681    pub border_color: ColorU,
1682}
1683
1684// missing StyleBorderRadius & LayoutRect
1685#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1686pub struct BoxShadowPreDisplayItem {
1687    pub offset: [PixelValueNoPercent;2],
1688    pub color: ColorU,
1689    pub blur_radius: PixelValueNoPercent,
1690    pub spread_radius: PixelValueNoPercent,
1691    pub clip_mode: BoxShadowClipMode,
1692}
1693
1694impl fmt::Display for BoxShadowPreDisplayItem {
1695    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1696        if self.clip_mode == BoxShadowClipMode::Inset {
1697            write!(f, "{} ", self.clip_mode)?;
1698        }
1699        write!(f, "{} {} {} {} {}",
1700            self.offset[0], self.offset[1],
1701            self.blur_radius, self.spread_radius, self.color,
1702        )
1703    }
1704}
1705
1706#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1707pub enum StyleBackgroundContent {
1708    LinearGradient(LinearGradient),
1709    RadialGradient(RadialGradient),
1710    Image(CssImageId),
1711    Color(ColorU),
1712}
1713
1714impl fmt::Debug for StyleBackgroundContent {
1715    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1716        use self::StyleBackgroundContent::*;
1717        match self {
1718            LinearGradient(l) => write!(f, "{}", l),
1719            RadialGradient(r) => write!(f, "{}", r),
1720            Image(id) => write!(f, "image({})", id),
1721            Color(c) => write!(f, "{}", c),
1722        }
1723    }
1724}
1725
1726impl StyleBackgroundContent {
1727    pub fn get_css_image_id(&self) -> Option<&CssImageId> {
1728        match self {
1729            StyleBackgroundContent::Image(i) => Some(i),
1730            _ => None,
1731        }
1732    }
1733}
1734
1735impl<'a> From<CssImageId> for StyleBackgroundContent {
1736    fn from(id: CssImageId) -> Self {
1737        StyleBackgroundContent::Image(id)
1738    }
1739}
1740
1741#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1742pub struct LinearGradient {
1743    pub direction: Direction,
1744    pub extend_mode: ExtendMode,
1745    pub stops: Vec<GradientStopPre>,
1746}
1747
1748impl fmt::Display for LinearGradient {
1749    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1750        let prefix = match self.extend_mode {
1751            ExtendMode::Clamp => "linear-gradient",
1752            ExtendMode::Repeat => "repeating-linear-gradient",
1753        };
1754
1755        write!(f, "{}({}", prefix, self.direction)?;
1756        for s in &self.stops {
1757            write!(f, ", {}", s)?;
1758        }
1759        write!(f, ")")
1760    }
1761}
1762
1763#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1764pub struct RadialGradient {
1765    pub shape: Shape,
1766    pub extend_mode: ExtendMode,
1767    pub stops: Vec<GradientStopPre>,
1768}
1769
1770impl fmt::Display for RadialGradient {
1771    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1772        let prefix = match self.extend_mode {
1773            ExtendMode::Clamp => "radial-gradient",
1774            ExtendMode::Repeat => "repeating-radial-gradient",
1775        };
1776
1777        write!(f, "{}({}", prefix, self.shape)?;
1778        for s in &self.stops {
1779            write!(f, ", {}", s)?;
1780        }
1781        write!(f, ")")
1782    }
1783}
1784
1785/// CSS direction (necessary for gradients). Can either be a fixed angle or
1786/// a direction ("to right" / "to left", etc.).
1787#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1788pub enum Direction {
1789    Angle(FloatValue),
1790    FromTo(DirectionCorner, DirectionCorner),
1791}
1792
1793impl fmt::Display for Direction {
1794    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1795        use self::Direction::*;
1796        match self {
1797            Angle(d) => write!(f, "{}deg", d.get()),
1798            FromTo(_, t) => write!(f, "to {}", t),
1799        }
1800    }
1801}
1802
1803impl Direction {
1804
1805    /// Calculates the points of the gradient stops for angled linear gradients
1806    pub fn to_points(&self, rect: &LayoutRect)
1807    -> (LayoutPoint, LayoutPoint)
1808    {
1809        match self {
1810            Direction::Angle(deg) => {
1811                // note: assumes that the LayoutRect has positive sides
1812
1813                // see: https://hugogiraudel.com/2013/02/04/css-gradients/
1814
1815                let deg = deg.get(); // FloatValue -> f32
1816
1817                let deg = -deg; // negate winding direction
1818
1819                let width_half = rect.size.width as usize / 2;
1820                let height_half = rect.size.height as usize / 2;
1821
1822                // hypotenuse_len is the length of the center of the rect to the corners
1823                let hypotenuse_len = (((width_half * width_half) + (height_half * height_half)) as f64).sqrt();
1824
1825                // The corner also serves to determine what quadrant we're in
1826                // Get the quadrant (corner) the angle is in and get the degree associated
1827                // with that corner.
1828
1829                let angle_to_top_left = (height_half as f64 / width_half as f64).atan().to_degrees();
1830
1831                // We need to calculate the angle from the center to the corner!
1832                let ending_point_degrees = if deg < 90.0 {
1833                    // top left corner
1834                    90.0 - angle_to_top_left
1835                } else if deg < 180.0 {
1836                    // bottom left corner
1837                    90.0 + angle_to_top_left
1838                } else if deg < 270.0 {
1839                    // bottom right corner
1840                    270.0 - angle_to_top_left
1841                } else /* deg > 270.0 && deg < 360.0 */ {
1842                    // top right corner
1843                    270.0 + angle_to_top_left
1844                };
1845
1846                // assuming deg = 36deg, then degree_diff_to_corner = 9deg
1847                let degree_diff_to_corner = ending_point_degrees - deg as f64;
1848
1849                // Searched_len is the distance between the center of the rect and the
1850                // ending point of the gradient
1851                let searched_len = (hypotenuse_len * degree_diff_to_corner.to_radians().cos()).abs();
1852
1853                // TODO: This searched_len is incorrect...
1854
1855                // Once we have the length, we can simply rotate the length by the angle,
1856                // then translate it to the center of the rect
1857                let dx = deg.to_radians().sin() * searched_len as f32;
1858                let dy = deg.to_radians().cos() * searched_len as f32;
1859
1860                let start_point_location = LayoutPoint { x: width_half as f32 + dx, y: height_half as f32 + dy };
1861                let end_point_location = LayoutPoint { x: width_half as f32 - dx, y: height_half as f32 - dy };
1862
1863                (start_point_location, end_point_location)
1864            },
1865            Direction::FromTo(from, to) => {
1866                (from.to_point(rect), to.to_point(rect))
1867            }
1868        }
1869    }
1870}
1871
1872#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1873pub enum Shape {
1874    Ellipse,
1875    Circle,
1876}
1877
1878impl fmt::Display for Shape {
1879    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1880        use self::Shape::*;
1881        match self {
1882            Ellipse => write!(f, "ellipse"),
1883            Circle => write!(f, "circle"),
1884        }
1885    }
1886}
1887
1888#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1889pub enum StyleCursor {
1890    /// `alias`
1891    Alias,
1892    /// `all-scroll`
1893    AllScroll,
1894    /// `cell`
1895    Cell,
1896    /// `col-resize`
1897    ColResize,
1898    /// `context-menu`
1899    ContextMenu,
1900    /// `copy`
1901    Copy,
1902    /// `crosshair`
1903    Crosshair,
1904    /// `default` - note: called "arrow" in winit
1905    Default,
1906    /// `e-resize`
1907    EResize,
1908    /// `ew-resize`
1909    EwResize,
1910    /// `grab`
1911    Grab,
1912    /// `grabbing`
1913    Grabbing,
1914    /// `help`
1915    Help,
1916    /// `move`
1917    Move,
1918    /// `n-resize`
1919    NResize,
1920    /// `ns-resize`
1921    NsResize,
1922    /// `nesw-resize`
1923    NeswResize,
1924    /// `nwse-resize`
1925    NwseResize,
1926    /// `pointer` - note: called "hand" in winit
1927    Pointer,
1928    /// `progress`
1929    Progress,
1930    /// `row-resize`
1931    RowResize,
1932    /// `s-resize`
1933    SResize,
1934    /// `se-resize`
1935    SeResize,
1936    /// `text`
1937    Text,
1938    /// `unset`
1939    Unset,
1940    /// `vertical-text`
1941    VerticalText,
1942    /// `w-resize`
1943    WResize,
1944    /// `wait`
1945    Wait,
1946    /// `zoom-in`
1947    ZoomIn,
1948    /// `zoom-out`
1949    ZoomOut,
1950}
1951
1952impl Default for StyleCursor {
1953    fn default() -> StyleCursor {
1954        StyleCursor::Default
1955    }
1956}
1957
1958#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1959pub enum DirectionCorner {
1960    Right,
1961    Left,
1962    Top,
1963    Bottom,
1964    TopRight,
1965    TopLeft,
1966    BottomRight,
1967    BottomLeft,
1968}
1969
1970impl fmt::Display for DirectionCorner {
1971    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1972        use self::DirectionCorner::*;
1973        match self {
1974            Right =>  write!(f, "right"),
1975            Left =>  write!(f, "left"),
1976            Top =>  write!(f, "top"),
1977            Bottom =>  write!(f, "bottom"),
1978            TopRight =>  write!(f, "top right"),
1979            TopLeft =>  write!(f, "top left"),
1980            BottomRight =>  write!(f, "bottom right"),
1981            BottomLeft =>  write!(f, "bottom left"),
1982        }
1983    }
1984}
1985
1986impl DirectionCorner {
1987
1988    pub fn opposite(&self) -> Self {
1989        use self::DirectionCorner::*;
1990        match *self {
1991            Right => Left,
1992            Left => Right,
1993            Top => Bottom,
1994            Bottom => Top,
1995            TopRight => BottomLeft,
1996            BottomLeft => TopRight,
1997            TopLeft => BottomRight,
1998            BottomRight => TopLeft,
1999        }
2000    }
2001
2002    pub fn combine(&self, other: &Self) -> Option<Self> {
2003        use self::DirectionCorner::*;
2004        match (*self, *other) {
2005            (Right, Top) | (Top, Right) => Some(TopRight),
2006            (Left, Top) | (Top, Left) => Some(TopLeft),
2007            (Right, Bottom) | (Bottom, Right) => Some(BottomRight),
2008            (Left, Bottom) | (Bottom, Left) => Some(BottomLeft),
2009            _ => { None }
2010        }
2011    }
2012
2013    pub fn to_point(&self, rect: &LayoutRect) -> LayoutPoint
2014    {
2015        use self::DirectionCorner::*;
2016        match *self {
2017            Right       => LayoutPoint { x: rect.size.width,          y: rect.size.height / 2.0     },
2018            Left        => LayoutPoint { x: 0.0,                      y: rect.size.height / 2.0     },
2019            Top         => LayoutPoint { x: rect.size.width / 2.0,    y: 0.0                        },
2020            Bottom      => LayoutPoint { x: rect.size.width / 2.0,    y: rect.size.height           },
2021            TopRight    => LayoutPoint { x: rect.size.width,          y: 0.0                        },
2022            TopLeft     => LayoutPoint { x: 0.0,                      y: 0.0                        },
2023            BottomRight => LayoutPoint { x: rect.size.width,          y: rect.size.height           },
2024            BottomLeft  => LayoutPoint { x: 0.0,                      y: rect.size.height           },
2025        }
2026    }
2027}
2028
2029#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2030pub enum GradientType {
2031    LinearGradient,
2032    RepeatingLinearGradient,
2033    RadialGradient,
2034    RepeatingRadialGradient,
2035}
2036
2037/// Note: In theory, we could take a reference here,
2038/// but this leads to horrible lifetime issues.
2039///
2040/// Ownership allows the `Css` struct to be independent
2041/// of the original source text. For example, when parsing a style
2042/// from CSS, the original string can be deallocated afterwards.
2043#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2044pub struct CssImageId(pub String);
2045
2046impl fmt::Display for CssImageId {
2047    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2048        write!(f, "{}", self.0)
2049    }
2050}
2051
2052
2053#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2054pub struct GradientStopPre {
2055    // this is set to None if there was no offset that could be parsed
2056    pub offset: Option<PercentageValue>,
2057    pub color: ColorU,
2058}
2059
2060impl fmt::Display for GradientStopPre {
2061    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2062        self.color.write_hash(f)?;
2063        if let Some(offset) = self.offset {
2064            write!(f, " {}", offset)?;
2065        }
2066        Ok(())
2067    }
2068}
2069
2070/// Represents a `width` attribute
2071#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2072pub struct LayoutWidth(pub PixelValue);
2073/// Represents a `min-width` attribute
2074#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2075pub struct LayoutMinWidth(pub PixelValue);
2076/// Represents a `max-width` attribute
2077#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2078pub struct LayoutMaxWidth(pub PixelValue);
2079/// Represents a `height` attribute
2080#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2081pub struct LayoutHeight(pub PixelValue);
2082/// Represents a `min-height` attribute
2083#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2084pub struct LayoutMinHeight(pub PixelValue);
2085/// Represents a `max-height` attribute
2086#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2087pub struct LayoutMaxHeight(pub PixelValue);
2088
2089impl_pixel_value!(LayoutWidth);
2090impl_pixel_value!(LayoutHeight);
2091impl_pixel_value!(LayoutMinHeight);
2092impl_pixel_value!(LayoutMinWidth);
2093impl_pixel_value!(LayoutMaxWidth);
2094impl_pixel_value!(LayoutMaxHeight);
2095
2096/// Represents a `top` attribute
2097#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2098pub struct LayoutTop(pub PixelValue);
2099/// Represents a `left` attribute
2100#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2101pub struct LayoutLeft(pub PixelValue);
2102/// Represents a `right` attribute
2103#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2104pub struct LayoutRight(pub PixelValue);
2105/// Represents a `bottom` attribute
2106#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2107pub struct LayoutBottom(pub PixelValue);
2108
2109impl_pixel_value!(LayoutTop);
2110impl_pixel_value!(LayoutBottom);
2111impl_pixel_value!(LayoutRight);
2112impl_pixel_value!(LayoutLeft);
2113
2114/// Represents a `padding-top` attribute
2115#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2116pub struct LayoutPaddingTop(pub PixelValue);
2117/// Represents a `padding-left` attribute
2118#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2119pub struct LayoutPaddingLeft(pub PixelValue);
2120/// Represents a `padding-right` attribute
2121#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2122pub struct LayoutPaddingRight(pub PixelValue);
2123/// Represents a `padding-bottom` attribute
2124#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2125pub struct LayoutPaddingBottom(pub PixelValue);
2126
2127impl_pixel_value!(LayoutPaddingTop);
2128impl_pixel_value!(LayoutPaddingBottom);
2129impl_pixel_value!(LayoutPaddingRight);
2130impl_pixel_value!(LayoutPaddingLeft);
2131
2132/// Represents a `padding-top` attribute
2133#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2134pub struct LayoutMarginTop(pub PixelValue);
2135/// Represents a `padding-left` attribute
2136#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2137pub struct LayoutMarginLeft(pub PixelValue);
2138/// Represents a `padding-right` attribute
2139#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2140pub struct LayoutMarginRight(pub PixelValue);
2141/// Represents a `padding-bottom` attribute
2142#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2143pub struct LayoutMarginBottom(pub PixelValue);
2144
2145impl_pixel_value!(LayoutMarginTop);
2146impl_pixel_value!(LayoutMarginBottom);
2147impl_pixel_value!(LayoutMarginRight);
2148impl_pixel_value!(LayoutMarginLeft);
2149
2150/// Represents a `flex-grow` attribute
2151#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2152pub struct LayoutFlexGrow(pub FloatValue);
2153
2154impl Default for LayoutFlexGrow {
2155    fn default() -> Self {
2156        LayoutFlexGrow(FloatValue::const_new(0))
2157    }
2158}
2159
2160/// Represents a `flex-shrink` attribute
2161#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2162pub struct LayoutFlexShrink(pub FloatValue);
2163
2164impl Default for LayoutFlexShrink {
2165    fn default() -> Self {
2166        LayoutFlexShrink(FloatValue::const_new(0))
2167    }
2168}
2169
2170impl_float_value!(LayoutFlexGrow);
2171impl_float_value!(LayoutFlexShrink);
2172
2173/// Represents a `flex-direction` attribute - default: `Column`
2174#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2175pub enum LayoutDirection {
2176    Row,
2177    RowReverse,
2178    Column,
2179    ColumnReverse,
2180}
2181
2182impl Default for LayoutDirection {
2183    fn default() -> Self {
2184        LayoutDirection::Row
2185    }
2186}
2187
2188impl LayoutDirection {
2189    pub fn get_axis(&self) -> LayoutAxis {
2190        use self::{LayoutAxis::*, LayoutDirection::*};
2191        match self {
2192            Row | RowReverse => Horizontal,
2193            Column | ColumnReverse => Vertical,
2194        }
2195    }
2196
2197    /// Returns true, if this direction is a `column-reverse` or `row-reverse` direction
2198    pub fn is_reverse(&self) -> bool {
2199        *self == LayoutDirection::RowReverse || *self == LayoutDirection::ColumnReverse
2200    }
2201}
2202
2203/// Represents a `flex-direction` attribute - default: `Column`
2204#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2205pub enum LayoutBoxSizing {
2206    ContentBox,
2207    BorderBox,
2208}
2209
2210impl Default for LayoutBoxSizing {
2211    fn default() -> Self {
2212        LayoutBoxSizing::ContentBox
2213    }
2214}
2215
2216/// Represents a `line-height` attribute
2217#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2218pub struct StyleLineHeight(pub PercentageValue);
2219/// Represents a `tab-width` attribute
2220#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2221pub struct StyleTabWidth(pub PercentageValue);
2222
2223impl_percentage_value!(StyleTabWidth);
2224impl_percentage_value!(StyleLineHeight);
2225
2226/// Represents a `letter-spacing` attribute
2227#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2228pub struct StyleLetterSpacing(pub PixelValue);
2229/// Represents a `word-spacing` attribute
2230#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2231pub struct StyleWordSpacing(pub PixelValue);
2232
2233impl_pixel_value!(StyleLetterSpacing);
2234impl_pixel_value!(StyleWordSpacing);
2235
2236/// Same as the `LayoutDirection`, but without the `-reverse` properties, used in the layout solver,
2237/// makes decisions based on horizontal / vertical direction easier to write.
2238/// Use `LayoutDirection::get_axis()` to get the axis for a given `LayoutDirection`.
2239#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2240pub enum LayoutAxis {
2241    Horizontal,
2242    Vertical,
2243}
2244
2245/// Represents a `display` attribute
2246#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2247pub enum LayoutDisplay {
2248    Flex,
2249    Block,
2250    InlineBlock,
2251}
2252
2253impl Default for LayoutDisplay {
2254    fn default() -> Self {
2255        LayoutDisplay::Block
2256    }
2257}
2258
2259/// Represents a `float` attribute
2260#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2261pub enum LayoutFloat {
2262    Left,
2263    Right,
2264}
2265
2266impl Default for LayoutFloat {
2267    fn default() -> Self {
2268        LayoutFloat::Left
2269    }
2270}
2271
2272
2273/// Represents a `position` attribute - default: `Static`
2274///
2275/// NOTE: No inline positioning is supported.
2276#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2277pub enum LayoutPosition {
2278    Static,
2279    Relative,
2280    Absolute,
2281    Fixed,
2282}
2283
2284impl Default for LayoutPosition {
2285    fn default() -> Self {
2286        LayoutPosition::Static
2287    }
2288}
2289
2290/// Represents a `flex-wrap` attribute - default: `Wrap`
2291#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2292pub enum LayoutWrap {
2293    Wrap,
2294    NoWrap,
2295}
2296
2297impl Default for LayoutWrap {
2298    fn default() -> Self {
2299        LayoutWrap::Wrap
2300    }
2301}
2302
2303/// Represents a `justify-content` attribute
2304#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2305pub enum LayoutJustifyContent {
2306    /// Default value. Items are positioned at the beginning of the container
2307    Start,
2308    /// Items are positioned at the end of the container
2309    End,
2310    /// Items are positioned at the center of the container
2311    Center,
2312    /// Items are positioned with space between the lines
2313    SpaceBetween,
2314    /// Items are positioned with space before, between, and after the lines
2315    SpaceAround,
2316    /// Items are distributed so that the spacing between any two adjacent alignment subjects,
2317    /// before the first alignment subject, and after the last alignment subject is the same
2318    SpaceEvenly,
2319}
2320
2321impl Default for LayoutJustifyContent {
2322    fn default() -> Self {
2323        LayoutJustifyContent::Start
2324    }
2325}
2326
2327/// Represents a `align-items` attribute
2328#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2329pub enum LayoutAlignItems {
2330    /// Items are stretched to fit the container
2331    Stretch,
2332    /// Items are positioned at the center of the container
2333    Center,
2334    /// Items are positioned at the beginning of the container
2335    Start,
2336    /// Items are positioned at the end of the container
2337    End,
2338}
2339
2340impl Default for LayoutAlignItems {
2341    fn default() -> Self {
2342        LayoutAlignItems::Start
2343    }
2344}
2345
2346/// Represents a `align-content` attribute
2347#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2348pub enum LayoutAlignContent {
2349    /// Default value. Lines stretch to take up the remaining space
2350    Stretch,
2351    /// Lines are packed toward the center of the flex container
2352    Center,
2353    /// Lines are packed toward the start of the flex container
2354    Start,
2355    /// Lines are packed toward the end of the flex container
2356    End,
2357    /// Lines are evenly distributed in the flex container
2358    SpaceBetween,
2359    /// Lines are evenly distributed in the flex container, with half-size spaces on either end
2360    SpaceAround,
2361}
2362
2363impl Default for LayoutAlignContent {
2364    fn default() -> Self {
2365        LayoutAlignContent::Stretch
2366    }
2367}
2368
2369/// Represents a `overflow-x` or `overflow-y` property, see
2370/// [`TextOverflowBehaviour`](./struct.TextOverflowBehaviour.html) - default: `Auto`
2371#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2372pub enum Overflow {
2373    /// Always shows a scroll bar, overflows on scroll
2374    Scroll,
2375    /// Does not show a scroll bar by default, only when text is overflowing
2376    Auto,
2377    /// Never shows a scroll bar, simply clips text
2378    Hidden,
2379    /// Doesn't show a scroll bar, simply overflows the text
2380    Visible,
2381}
2382
2383impl Default for Overflow {
2384    fn default() -> Self {
2385        Overflow::Auto
2386    }
2387}
2388
2389impl Overflow {
2390
2391    /// Returns whether this overflow value needs to display the scrollbars.
2392    ///
2393    /// - `overflow:scroll` always shows the scrollbar
2394    /// - `overflow:auto` only shows the scrollbar when the content is currently overflowing
2395    /// - `overflow:hidden` and `overflow:visible` do not show any scrollbars
2396    pub fn needs_scrollbar(&self, currently_overflowing: bool) -> bool {
2397        use self::Overflow::*;
2398        match self {
2399            Scroll => true,
2400            Auto => currently_overflowing,
2401            Hidden | Visible => false,
2402        }
2403    }
2404
2405    /// Returns whether this is an `overflow:visible` node
2406    /// (the only overflow type that doesn't clip its children)
2407    pub fn is_overflow_visible(&self) -> bool {
2408        *self == Overflow::Visible
2409    }
2410}
2411
2412/// Horizontal text alignment enum (left, center, right) - default: `Center`
2413#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2414pub enum StyleTextAlignmentHorz {
2415    Left,
2416    Center,
2417    Right,
2418}
2419
2420impl Default for StyleTextAlignmentHorz {
2421    fn default() -> Self {
2422        StyleTextAlignmentHorz::Left
2423    }
2424}
2425
2426/// Vertical text alignment enum (top, center, bottom) - default: `Center`
2427#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2428pub enum StyleTextAlignmentVert {
2429    Top,
2430    Center,
2431    Bottom,
2432}
2433
2434impl Default for StyleTextAlignmentVert {
2435    fn default() -> Self {
2436        StyleTextAlignmentVert::Top
2437    }
2438}
2439
2440/// Stylistic options of the rectangle that don't influence the layout
2441#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2442pub struct RectStyle {
2443
2444    pub background: Option<CssPropertyValue<StyleBackgroundContent>>,
2445    pub background_position: Option<CssPropertyValue<StyleBackgroundPosition>>,
2446    pub background_size: Option<CssPropertyValue<StyleBackgroundSize>>,
2447    pub background_repeat: Option<CssPropertyValue<StyleBackgroundRepeat>>,
2448    pub font_size: Option<CssPropertyValue<StyleFontSize>>,
2449    pub font_family: Option<CssPropertyValue<StyleFontFamily>>,
2450    pub text_color: Option<CssPropertyValue<StyleTextColor>>,
2451    pub text_align: Option<CssPropertyValue<StyleTextAlignmentHorz>>,
2452    pub line_height: Option<CssPropertyValue<StyleLineHeight>>,
2453    pub letter_spacing: Option<CssPropertyValue<StyleLetterSpacing>>,
2454    pub word_spacing: Option<CssPropertyValue<StyleWordSpacing>>,
2455    pub tab_width: Option<CssPropertyValue<StyleTabWidth>>,
2456    pub cursor: Option<CssPropertyValue<StyleCursor>>,
2457
2458    pub box_shadow_left: Option<CssPropertyValue<BoxShadowPreDisplayItem>>,
2459    pub box_shadow_right: Option<CssPropertyValue<BoxShadowPreDisplayItem>>,
2460    pub box_shadow_top: Option<CssPropertyValue<BoxShadowPreDisplayItem>>,
2461    pub box_shadow_bottom: Option<CssPropertyValue<BoxShadowPreDisplayItem>>,
2462
2463    pub border_top_color: Option<CssPropertyValue<StyleBorderTopColor>>,
2464    pub border_left_color: Option<CssPropertyValue<StyleBorderLeftColor>>,
2465    pub border_right_color: Option<CssPropertyValue<StyleBorderRightColor>>,
2466    pub border_bottom_color: Option<CssPropertyValue<StyleBorderBottomColor>>,
2467
2468    pub border_top_style: Option<CssPropertyValue<StyleBorderTopStyle>>,
2469    pub border_left_style: Option<CssPropertyValue<StyleBorderLeftStyle>>,
2470    pub border_right_style: Option<CssPropertyValue<StyleBorderRightStyle>>,
2471    pub border_bottom_style: Option<CssPropertyValue<StyleBorderBottomStyle>>,
2472
2473    pub border_top_left_radius: Option<CssPropertyValue<StyleBorderTopLeftRadius>>,
2474    pub border_top_right_radius: Option<CssPropertyValue<StyleBorderTopRightRadius>>,
2475    pub border_bottom_left_radius: Option<CssPropertyValue<StyleBorderBottomLeftRadius>>,
2476    pub border_bottom_right_radius: Option<CssPropertyValue<StyleBorderBottomRightRadius>>,
2477}
2478
2479// Layout constraints for a given rectangle, such as "width", "min-width", "height", etc.
2480#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2481pub struct RectLayout {
2482    pub display: Option<CssPropertyValue<LayoutDisplay>>,
2483    pub float: Option<CssPropertyValue<LayoutFloat>>,
2484    pub box_sizing: Option<CssPropertyValue<LayoutBoxSizing>>,
2485
2486    pub width: Option<CssPropertyValue<LayoutWidth>>,
2487    pub height: Option<CssPropertyValue<LayoutHeight>>,
2488    pub min_width: Option<CssPropertyValue<LayoutMinWidth>>,
2489    pub min_height: Option<CssPropertyValue<LayoutMinHeight>>,
2490    pub max_width: Option<CssPropertyValue<LayoutMaxWidth>>,
2491    pub max_height: Option<CssPropertyValue<LayoutMaxHeight>>,
2492
2493    pub position: Option<CssPropertyValue<LayoutPosition>>,
2494    pub top: Option<CssPropertyValue<LayoutTop>>,
2495    pub bottom: Option<CssPropertyValue<LayoutBottom>>,
2496    pub right: Option<CssPropertyValue<LayoutRight>>,
2497    pub left: Option<CssPropertyValue<LayoutLeft>>,
2498
2499    pub padding_top: Option<CssPropertyValue<LayoutPaddingTop>>,
2500    pub padding_bottom: Option<CssPropertyValue<LayoutPaddingBottom>>,
2501    pub padding_left: Option<CssPropertyValue<LayoutPaddingLeft>>,
2502    pub padding_right: Option<CssPropertyValue<LayoutPaddingRight>>,
2503
2504    pub margin_top: Option<CssPropertyValue<LayoutMarginTop>>,
2505    pub margin_bottom: Option<CssPropertyValue<LayoutMarginBottom>>,
2506    pub margin_left: Option<CssPropertyValue<LayoutMarginLeft>>,
2507    pub margin_right: Option<CssPropertyValue<LayoutMarginRight>>,
2508
2509    pub border_top_width: Option<CssPropertyValue<StyleBorderTopWidth>>,
2510    pub border_left_width: Option<CssPropertyValue<StyleBorderLeftWidth>>,
2511    pub border_right_width: Option<CssPropertyValue<StyleBorderRightWidth>>,
2512    pub border_bottom_width: Option<CssPropertyValue<StyleBorderBottomWidth>>,
2513
2514    pub overflow_x: Option<CssPropertyValue<Overflow>>,
2515    pub overflow_y: Option<CssPropertyValue<Overflow>>,
2516
2517    pub direction: Option<CssPropertyValue<LayoutDirection>>,
2518    pub wrap: Option<CssPropertyValue<LayoutWrap>>,
2519    pub flex_grow: Option<CssPropertyValue<LayoutFlexGrow>>,
2520    pub flex_shrink: Option<CssPropertyValue<LayoutFlexShrink>>,
2521    pub justify_content: Option<CssPropertyValue<LayoutJustifyContent>>,
2522    pub align_items: Option<CssPropertyValue<LayoutAlignItems>>,
2523    pub align_content: Option<CssPropertyValue<LayoutAlignContent>>,
2524}
2525
2526/// Holds info necessary for layouting / styling scrollbars (-webkit-scrollbar)
2527#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2528pub struct ScrollbarInfo {
2529    /// Total width (or height for vertical scrollbars) of the scrollbar in pixels
2530    pub width: LayoutWidth,
2531    /// Padding of the scrollbar tracker, in pixels. The inner bar is `width - padding` pixels wide.
2532    pub padding_left: LayoutPaddingLeft,
2533    pub padding_right: LayoutPaddingRight,
2534    /// Style of the scrollbar background
2535    /// (`-webkit-scrollbar` / `-webkit-scrollbar-track` / `-webkit-scrollbar-track-piece` combined)
2536    pub track: RectStyle,
2537    /// Style of the scrollbar thumbs (the "up" / "down" arrows), (`-webkit-scrollbar-thumb`)
2538    pub thumb: RectStyle,
2539    /// Styles the directional buttons on the scrollbar (`-webkit-scrollbar-button`)
2540    pub button: RectStyle,
2541    /// If two scrollbars are present, addresses the (usually) bottom corner
2542    /// of the scrollable element, where two scrollbars might meet (`-webkit-scrollbar-corner`)
2543    pub corner: RectStyle,
2544    /// Addresses the draggable resizing handle that appears above the
2545    /// `corner` at the bottom corner of some elements (`-webkit-resizer`)
2546    pub resizer: RectStyle,
2547}
2548
2549impl Default for ScrollbarInfo {
2550    fn default() -> Self {
2551        ScrollbarInfo {
2552            width: LayoutWidth(PixelValue::px(17.0)),
2553            padding_left: LayoutPaddingLeft(PixelValue::px(2.0)),
2554            padding_right: LayoutPaddingRight(PixelValue::px(2.0)),
2555            track: RectStyle {
2556                background: Some(CssPropertyValue::Exact(StyleBackgroundContent::Color(ColorU {
2557                    r: 241, g: 241, b: 241, a: 255
2558                }))),
2559                .. Default::default()
2560            },
2561            thumb: RectStyle {
2562                background: Some(CssPropertyValue::Exact(StyleBackgroundContent::Color(ColorU {
2563                    r: 193, g: 193, b: 193, a: 255
2564                }))),
2565                .. Default::default()
2566            },
2567            button: RectStyle {
2568                background: Some(CssPropertyValue::Exact(StyleBackgroundContent::Color(ColorU {
2569                    r: 163, g: 163, b: 163, a: 255
2570                }))),
2571                .. Default::default()
2572            },
2573            corner: RectStyle::default(),
2574            resizer: RectStyle::default(),
2575        }
2576    }
2577}
2578
2579/// Width and height of the scrollbars at the side of the text field.
2580///
2581/// This information is necessary in order to reserve space at
2582/// the side of the text field so that the text doesn't overlap the scrollbar.
2583/// In some cases (when the scrollbar is set to "auto"), the scrollbar space
2584/// is only taken up when the text overflows the rectangle itself.
2585#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2586pub struct ScrollbarStyle {
2587    /// Vertical scrollbar style, if any
2588    pub horizontal: Option<ScrollbarInfo>,
2589    /// Horizontal scrollbar style, if any
2590    pub vertical: Option<ScrollbarInfo>,
2591}
2592
2593impl RectStyle {
2594
2595    pub fn get_horizontal_scrollbar_style(&self) -> ScrollbarInfo {
2596        ScrollbarInfo::default()
2597    }
2598
2599    pub fn get_vertical_scrollbar_style(&self) -> ScrollbarInfo {
2600        ScrollbarInfo::default()
2601    }
2602
2603    pub fn has_box_shadow(&self) -> bool {
2604        self.box_shadow_left.and_then(|bs| bs.get_property().map(|_| ())).is_some() ||
2605        self.box_shadow_right.and_then(|bs| bs.get_property().map(|_| ())).is_some() ||
2606        self.box_shadow_top.and_then(|bs| bs.get_property().map(|_| ())).is_some() ||
2607        self.box_shadow_bottom.and_then(|bs| bs.get_property().map(|_| ())).is_some()
2608    }
2609
2610    pub fn has_border(&self) -> bool {
2611        self.border_left_style.and_then(|bs| bs.get_property_or_default()).is_some() ||
2612        self.border_right_style.and_then(|bs| bs.get_property_or_default()).is_some() ||
2613        self.border_top_style.and_then(|bs| bs.get_property_or_default()).is_some() ||
2614        self.border_bottom_style.and_then(|bs| bs.get_property_or_default()).is_some()
2615    }
2616}
2617
2618impl RectLayout {
2619
2620    pub fn is_horizontal_overflow_visible(&self) -> bool {
2621        self.overflow_x.map(|css_prop| css_prop.get_property().map(|overflow| overflow.is_overflow_visible()).unwrap_or_default()) == Some(true)
2622    }
2623
2624    pub fn is_vertical_overflow_visible(&self) -> bool {
2625        self.overflow_y.map(|css_prop| css_prop.get_property().map(|overflow| overflow.is_overflow_visible()).unwrap_or_default()) == Some(true)
2626    }
2627}
2628
2629/// Represents a `font-size` attribute
2630#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2631pub struct StyleFontSize(pub PixelValue);
2632
2633impl_pixel_value!(StyleFontSize);
2634
2635/// Represents a `font-family` attribute
2636#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2637pub struct StyleFontFamily {
2638    // fonts in order of precedence, i.e. "Webly Sleeky UI", "monospace", etc.
2639    pub fonts: Vec<FontId>
2640}
2641
2642#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2643pub struct FontId(pub String);
2644
2645impl FontId {
2646    pub fn get_str(&self) -> &str {
2647        &self.0
2648    }
2649}