1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
pub use self::definitions::ComputedValues;
use self::definitions::LonghandId;
pub use self::definitions::{property_data_by_name, LonghandDeclaration};
pub use self::definitions::{ComputedValuesForEarlyCascade, ComputedValuesForLateCascade};
use crate::geom::{flow_relative, physical};
use crate::style::errors::PropertyParseError;
use crate::style::values::{self, CssWideKeyword, Direction, Display, WritingMode};
use crate::style::values::{CascadeContext, EarlyCascadeContext};
use cssparser::{Color, RGBA};
use std::sync::Arc;

#[macro_use]
mod macros;

mod definitions;

impl ComputedValues {
    pub fn anonymous_inheriting_from(parent_style: Option<&Self>) -> Arc<Self> {
        Self::new(parent_style, None)
    }

    pub fn post_cascade_fixups(&mut self) {
        let b = Arc::make_mut(&mut self.border);
        b.border_top_width.fixup(b.border_top_style);
        b.border_left_width.fixup(b.border_left_style);
        b.border_bottom_width.fixup(b.border_bottom_style);
        b.border_right_width.fixup(b.border_right_style);

        Display::fixup(self);
    }

    pub fn writing_mode(&self) -> (WritingMode, Direction) {
        // FIXME: For now, this is the only supported mode
        (WritingMode::HorizontalTb, Direction::Ltr)
    }

    pub fn box_offsets(&self) -> flow_relative::Sides<values::LengthOrPercentageOrAuto> {
        physical::Sides {
            top: self.box_.top,
            left: self.box_.left,
            bottom: self.box_.bottom,
            right: self.box_.right,
        }
        .to_flow_relative(self.writing_mode())
    }

    pub fn box_size(&self) -> flow_relative::Vec2<values::LengthOrPercentageOrAuto> {
        physical::Vec2 {
            x: self.box_.width,
            y: self.box_.height,
        }
        .size_to_flow_relative(self.writing_mode())
    }

    pub fn padding(&self) -> flow_relative::Sides<values::LengthOrPercentage> {
        physical::Sides {
            top: self.padding.padding_top,
            left: self.padding.padding_left,
            bottom: self.padding.padding_bottom,
            right: self.padding.padding_right,
        }
        .to_flow_relative(self.writing_mode())
    }

    pub fn border_width(&self) -> flow_relative::Sides<values::LengthOrPercentage> {
        physical::Sides {
            top: self.border.border_top_width.0,
            left: self.border.border_left_width.0,
            bottom: self.border.border_bottom_width.0,
            right: self.border.border_right_width.0,
        }
        .to_flow_relative(self.writing_mode())
    }

    pub fn margin(&self) -> flow_relative::Sides<values::LengthOrPercentageOrAuto> {
        physical::Sides {
            top: self.margin.margin_top,
            left: self.margin.margin_left,
            bottom: self.margin.margin_bottom,
            right: self.margin.margin_right,
        }
        .to_flow_relative(self.writing_mode())
    }

    pub fn to_rgba(&self, color: Color) -> RGBA {
        match color {
            Color::RGBA(rgba) => rgba,
            Color::CurrentColor => self.color.color,
        }
    }
}

pub trait Phase {
    fn select(&self, p: PerPhase<bool>) -> bool;
    fn cascade(&mut self, declaration: &LonghandDeclaration);
}

impl Phase for EarlyCascadeContext<'_> {
    fn select(&self, p: PerPhase<bool>) -> bool {
        p.early
    }

    fn cascade(&mut self, declaration: &LonghandDeclaration) {
        declaration.if_early_cascade_into(self)
    }
}

impl Phase for CascadeContext<'_> {
    fn select(&self, p: PerPhase<bool>) -> bool {
        p.late
    }

    fn cascade(&mut self, declaration: &LonghandDeclaration) {
        declaration.if_late_cascade_into(self)
    }
}

#[derive(Default, Copy, Clone, Debug)]
pub struct PerPhase<T> {
    pub early: T,
    pub late: T,
}

type FnParseProperty = for<'i, 't> fn(
    &mut cssparser::Parser<'i, 't>,
    &mut Vec<LonghandDeclaration>,
) -> Result<PerPhase<bool>, PropertyParseError<'i>>;

pub struct PropertyData {
    pub longhands: &'static [LonghandId],
    pub parse: FnParseProperty,
}

trait ValueOrInitial<T> {
    fn into<F>(self, id: LonghandId, constructor: F) -> LonghandDeclaration
    where
        F: Fn(T) -> LonghandDeclaration;
}

impl<T> ValueOrInitial<T> for T {
    fn into<F>(self, _id: LonghandId, constructor: F) -> LonghandDeclaration
    where
        F: Fn(T) -> LonghandDeclaration,
    {
        constructor(self)
    }
}

impl<T> ValueOrInitial<T> for Option<T> {
    fn into<F>(self, id: LonghandId, constructor: F) -> LonghandDeclaration
    where
        F: Fn(T) -> LonghandDeclaration,
    {
        match self {
            Some(value) => constructor(value),
            None => LonghandDeclaration::CssWide(id, CssWideKeyword::Initial),
        }
    }
}