1
//! Macros to define CSS properties.
2

            
3
use crate::properties::ComputedValues;
4

            
5
/// Trait which all CSS property types should implement.
6
pub trait Property {
7
    /// Whether the property's computed value inherits from parent to child elements.
8
    ///
9
    /// For each property, the CSS or SVG specs say whether the property inherits
10
    /// automatically.  When a property is not specified in an element, the return value
11
    /// of this method determines whether the property's value is copied from the parent
12
    /// element (`true`), or whether it resets to the initial/default value (`false`).
13
    fn inherits_automatically() -> bool;
14

            
15
    /// Derive the CSS computed value from the parent element's
16
    /// [`ComputedValues`][crate::properties::ComputedValues] and the
17
    /// `self` value.
18
    ///
19
    /// The CSS or SVG specs say how to derive this for each property.
20
    fn compute(&self, _: &ComputedValues) -> Self;
21
}
22

            
23
/// Generates a type for a CSS property.
24
///
25
/// Writing a property by hand takes a bit of boilerplate:
26
///
27
/// * Define a type to represent the property's values.
28
///
29
/// * A [`Parse`] implementation to parse the property.
30
///
31
/// * A [`Default`] implementation to define the property's *initial* value.
32
///
33
/// * A [`Property`] implementation to define whether the property
34
/// inherits from the parent element, and how the property derives its
35
/// computed value.
36
///
37
/// When going from [`SpecifiedValues`] to [`ComputedValues`],
38
/// properties which inherit automatically from the parent element
39
/// will just have their values cloned.  Properties which do not
40
/// inherit will be reset back to their initial value (i.e. their
41
/// [`Default`]).
42
///
43
/// The default implementation of [`Property::compute()`] is to just
44
/// clone the property's value.  Properties which need more
45
/// sophisticated computation can override this.
46
///
47
/// This macro allows defining properties of different kinds; see the following
48
/// sections for examples.
49
///
50
/// # Simple identifiers
51
///
52
/// Many properties are just sets of identifiers and can be represented
53
/// by simple enums.  In this case, you can use the following:
54
///
55
/// ```text
56
/// make_property!(
57
///   /// Documentation here.
58
///   StrokeLinejoin,
59
///   default: Miter,
60
///   inherits_automatically: true,
61
///
62
///   identifiers:
63
///     "miter" => Miter,
64
///     "round" => Round,
65
///     "bevel" => Bevel,
66
/// );
67
/// ```
68
///
69
/// This generates a simple enum like the following, with implementations of [`Parse`],
70
/// [`Default`], and [`Property`].
71
///
72
/// ```
73
/// pub enum StrokeLinejoin { Miter, Round, Bevel }
74
/// ```
75
///
76
/// # Properties from an existing, general-purpose type
77
///
78
/// For example, both the `lightingColor` and `floodColor` properties can be represented
79
/// with a `cssparser::Color`, but their intial values are different.  In this case, the macro
80
/// can generate a newtype around `cssparser::Color` for each case:
81
///
82
/// ```text
83
/// make_property!(
84
///     /// Documentation here.
85
///     FloodColor,
86
///     default: cssparser::Color::RGBA(cssparser::RGBA::new(0, 0, 0, 0)),
87
///     inherits_automatically: false,
88
///     newtype_parse: cssparser::Color,
89
/// );
90
/// ```
91
///
92
/// # Properties from custom specific types
93
///
94
/// For example, font-related properties have custom, complex types that require an
95
/// implentation of `Property::compute` that is more than a simple `clone`.  In this case,
96
/// define the custom type separately, and use the macro to specify the default value and
97
/// the `Property` implementation.
98
///
99
/// [`Parse`]: crate::parsers::Parse
100
/// [`Property`]: crate::property_macros::Property
101
/// [`ComputedValues`]: crate::properties::ComputedValues
102
/// [`SpecifiedValues`]: crate::properties::SpecifiedValues
103
/// [`Property::compute()`]: crate::property_macros::Property::compute
104
///
105
#[doc(hidden)]
106
#[macro_export]
107
macro_rules! make_property {
108
    ($(#[$attr:meta])*
109
     $name: ident,
110
     default: $default: ident,
111
     inherits_automatically: $inherits_automatically: expr,
112
     identifiers:
113
     $($str_prop: expr => $variant: ident,)+
114
    ) => {
115
        $(#[$attr])*
116
148010209
        #[derive(Debug, Copy, Clone, PartialEq)]
117
        #[repr(C)]
118
        pub enum $name {
119
            $($variant),+
120
        }
121

            
122
        impl_default!($name, $name::$default);
123
        impl_property!($name, $inherits_automatically);
124

            
125
        impl $crate::parsers::Parse for $name {
126
15358
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, $crate::error::ParseError<'i>> {
127
30716
                Ok(parse_identifiers!(
128
                    parser,
129
                    $($str_prop => $name::$variant,)+
130
104
                )?)
131
15358
            }
132
        }
133
    };
134

            
135
    ($(#[$attr:meta])*
136
     $name: ident,
137
     default: $default: ident,
138
     identifiers: { $($str_prop: expr => $variant: ident,)+ },
139
     property_impl: { $prop: item }
140
    ) => {
141
        $(#[$attr])*
142
6824612
        #[derive(Debug, Copy, Clone, PartialEq)]
143
        #[repr(C)]
144
        pub enum $name {
145
            $($variant),+
146
        }
147

            
148
        impl_default!($name, $name::$default);
149
        $prop
150

            
151
        impl $crate::parsers::Parse for $name {
152
555
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, $crate::error::ParseError<'i>> {
153
1110
                Ok(parse_identifiers!(
154
                    parser,
155
                    $($str_prop => $name::$variant,)+
156
                )?)
157
555
            }
158
        }
159
    };
160

            
161
    ($(#[$attr:meta])*
162
     $name: ident,
163
     default: $default: expr,
164
     inherits_automatically: $inherits_automatically: expr,
165
     newtype_parse: $type: ty,
166
    ) => {
167
        $(#[$attr])*
168
344697142
        #[derive(Debug, Clone, PartialEq)]
169
172348571
        pub struct $name(pub $type);
170

            
171
        impl_default!($name, $name($default));
172
        impl_property!($name, $inherits_automatically);
173

            
174
        impl $crate::parsers::Parse for $name {
175
34705
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, $crate::error::ParseError<'i>> {
176
34705
                Ok($name(<$type as $crate::parsers::Parse>::parse(parser)?))
177
34705
            }
178
        }
179
    };
180

            
181
    ($(#[$attr:meta])*
182
     $name: ident,
183
     default: $default: expr,
184
     property_impl: { $prop: item }
185
    ) => {
186
        impl_default!($name, $default);
187

            
188
        $prop
189
    };
190

            
191
    ($name: ident,
192
     default: $default: expr,
193
     inherits_automatically: $inherits_automatically: expr,
194
    ) => {
195
        impl_default!($name, $default);
196
        impl_property!($name, $inherits_automatically);
197
    };
198

            
199
    ($name: ident,
200
     default: $default: expr,
201
     inherits_automatically: $inherits_automatically: expr,
202
     parse_impl: { $parse: item }
203
    ) => {
204
        impl_default!($name, $default);
205
        impl_property!($name, $inherits_automatically);
206

            
207
        $parse
208
    };
209

            
210
    ($(#[$attr:meta])*
211
     $name: ident,
212
     default: $default: expr,
213
     newtype: $type: ty,
214
     property_impl: { $prop: item },
215
     parse_impl: { $parse: item }
216
    ) => {
217
        $(#[$attr])*
218
8855446
        #[derive(Debug, Clone, PartialEq)]
219
4427723
        pub struct $name(pub $type);
220

            
221
        impl_default!($name, $name($default));
222

            
223
        $prop
224

            
225
        $parse
226
    };
227

            
228
    // pending - only XmlLang
229
    ($(#[$attr:meta])*
230
     $name: ident,
231
     default: $default: expr,
232
     inherits_automatically: $inherits_automatically: expr,
233
     newtype: $type: ty,
234
     parse_impl: { $parse: item },
235
    ) => {
236
        $(#[$attr])*
237
11961876
        #[derive(Debug, Clone, PartialEq)]
238
5980938
        pub struct $name(pub $type);
239

            
240
        impl_default!($name, $name($default));
241
        impl_property!($name, $inherits_automatically);
242

            
243
        $parse
244
    };
245

            
246
    ($(#[$attr:meta])*
247
     $name: ident,
248
     inherits_automatically: $inherits_automatically: expr,
249
     fields: {
250
       $($field_name: ident : $field_type: ty, default: $field_default : expr,)+
251
     }
252
     parse_impl: { $parse: item }
253
    ) => {
254
        $(#[$attr])*
255
22529172
        #[derive(Debug, Clone, PartialEq)]
256
        pub struct $name {
257
11264586
            $(pub $field_name: $field_type),+
258
        }
259

            
260
        impl_default!($name, $name { $($field_name: $field_default),+ });
261
        impl_property!($name, $inherits_automatically);
262

            
263
        $parse
264
    };
265
}
266

            
267
#[doc(hidden)]
268
#[macro_export]
269
macro_rules! impl_default {
270
    ($name:ident, $default:expr) => {
271
        impl Default for $name {
272
108066333
            fn default() -> $name {
273
                $default
274
108066333
            }
275
        }
276
    };
277
}
278

            
279
#[doc(hidden)]
280
#[macro_export]
281
macro_rules! impl_property {
282
    ($name:ident, $inherits_automatically:expr) => {
283
        impl $crate::property_macros::Property for $name {
284
85184261
            fn inherits_automatically() -> bool {
285
                $inherits_automatically
286
85184261
            }
287

            
288
86577879
            fn compute(&self, _v: &$crate::properties::ComputedValues) -> Self {
289
86577879
                self.clone()
290
86577879
            }
291
        }
292
    };
293
}