rsvg/
property_macros.rs

1//! Macros to define CSS properties.
2
3use crate::properties::ComputedValues;
4
5/// Trait which all CSS property types should implement.
6pub 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`] and the `self` value.
17    ///
18    /// The CSS or SVG specs say how to derive this for each property.
19    fn compute(&self, _: &ComputedValues) -> Self;
20}
21
22/// Generates a type for a CSS property.
23///
24/// Writing a property by hand takes a bit of boilerplate:
25///
26/// * Define a type to represent the property's values.
27///
28/// * A [`Parse`] implementation to parse the property.
29///
30/// * A [`Default`] implementation to define the property's *initial* value.
31///
32/// * A [`Property`] implementation to define whether the property
33/// inherits from the parent element, and how the property derives its
34/// computed value.
35///
36/// When going from [`SpecifiedValues`] to [`ComputedValues`],
37/// properties which inherit automatically from the parent element
38/// will just have their values cloned.  Properties which do not
39/// inherit will be reset back to their initial value (i.e. their
40/// [`Default`]).
41///
42/// The default implementation of [`Property::compute()`] is to just
43/// clone the property's value.  Properties which need more
44/// sophisticated computation can override this.
45///
46/// This macro allows defining properties of different kinds; see the following
47/// sections for examples.
48///
49/// # Simple identifiers
50///
51/// Many properties are just sets of identifiers and can be represented
52/// by simple enums.  In this case, you can use the following:
53///
54/// ```text
55/// make_property!(
56///   /// Documentation here.
57///   StrokeLinejoin,
58///   default: Miter,
59///   inherits_automatically: true,
60///
61///   identifiers:
62///     "miter" => Miter,
63///     "round" => Round,
64///     "bevel" => Bevel,
65/// );
66/// ```
67///
68/// This generates a simple enum like the following, with implementations of [`Parse`],
69/// [`Default`], and [`Property`].
70///
71/// ```
72/// pub enum StrokeLinejoin { Miter, Round, Bevel }
73/// ```
74///
75/// # Properties from an existing, general-purpose type
76///
77/// For example, both the `lightingColor` and `floodColor` properties can be represented
78/// with a `Color`, but their intial values are different.  In this case, the macro
79/// can generate a newtype around `Color` for each case:
80///
81/// ```text
82/// make_property!(
83///     /// Documentation here.
84///     FloodColor,
85///     default: Color::RGBA(RGBA::new(0, 0, 0, 0)),
86///     inherits_automatically: false,
87///     newtype_parse: Color,
88/// );
89/// ```
90///
91/// # Properties from custom specific types
92///
93/// For example, font-related properties have custom, complex types that require an
94/// implentation of `Property::compute` that is more than a simple `clone`.  In this case,
95/// define the custom type separately, and use the macro to specify the default value and
96/// the `Property` implementation.
97///
98/// [`Parse`]: crate::parsers::Parse
99/// [`Property`]: crate::property_macros::Property
100/// [`ComputedValues`]: crate::properties::ComputedValues
101/// [`SpecifiedValues`]: crate::properties::SpecifiedValues
102/// [`Property::compute()`]: crate::property_macros::Property::compute
103///
104#[doc(hidden)]
105#[macro_export]
106macro_rules! make_property {
107    ($(#[$attr:meta])*
108     $name: ident,
109     default: $default: ident,
110     inherits_automatically: $inherits_automatically: expr,
111     identifiers:
112     $($str_prop: expr => $variant: ident,)+
113    ) => {
114        $(#[$attr])*
115        #[derive(Debug, Copy, Clone, PartialEq)]
116        #[repr(C)]
117        pub enum $name {
118            $($variant),+
119        }
120
121        impl_default!($name, $name::$default);
122        impl_property!($name, $inherits_automatically);
123
124        impl $crate::parsers::Parse for $name {
125            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, $crate::error::ParseError<'i>> {
126                Ok(parse_identifiers!(
127                    parser,
128                    $($str_prop => $name::$variant,)+
129                )?)
130            }
131        }
132    };
133
134    ($(#[$attr:meta])*
135     $name: ident,
136     default: $default: ident,
137     identifiers: { $($str_prop: expr => $variant: ident,)+ },
138     property_impl: { $prop: item }
139    ) => {
140        $(#[$attr])*
141        #[derive(Debug, Copy, Clone, PartialEq)]
142        #[repr(C)]
143        pub enum $name {
144            $($variant),+
145        }
146
147        impl_default!($name, $name::$default);
148        $prop
149
150        impl $crate::parsers::Parse for $name {
151            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, $crate::error::ParseError<'i>> {
152                Ok(parse_identifiers!(
153                    parser,
154                    $($str_prop => $name::$variant,)+
155                )?)
156            }
157        }
158    };
159
160    ($(#[$attr:meta])*
161     $name: ident,
162     default: $default: expr,
163     inherits_automatically: $inherits_automatically: expr,
164     newtype_parse: $type: ty,
165    ) => {
166        $(#[$attr])*
167        #[derive(Debug, Clone, PartialEq)]
168        pub struct $name(pub $type);
169
170        impl_default!($name, $name($default));
171        impl_property!($name, $inherits_automatically);
172
173        impl $crate::parsers::Parse for $name {
174            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, $crate::error::ParseError<'i>> {
175                Ok($name(<$type as $crate::parsers::Parse>::parse(parser)?))
176            }
177        }
178    };
179
180    ($(#[$attr:meta])*
181     $name: ident,
182     default: $default: expr,
183     property_impl: { $prop: item }
184    ) => {
185        impl_default!($name, $default);
186
187        $prop
188    };
189
190    ($name: ident,
191     default: $default: expr,
192     inherits_automatically: $inherits_automatically: expr,
193    ) => {
194        impl_default!($name, $default);
195        impl_property!($name, $inherits_automatically);
196    };
197
198    ($name: ident,
199     default: $default: expr,
200     inherits_automatically: $inherits_automatically: expr,
201     parse_impl: { $parse: item }
202    ) => {
203        impl_default!($name, $default);
204        impl_property!($name, $inherits_automatically);
205
206        $parse
207    };
208
209    ($(#[$attr:meta])*
210     $name: ident,
211     default: $default: expr,
212     newtype: $type: ty,
213     property_impl: { $prop: item },
214     parse_impl: { $parse: item }
215    ) => {
216        $(#[$attr])*
217        #[derive(Debug, Clone, PartialEq)]
218        pub struct $name(pub $type);
219
220        impl_default!($name, $name($default));
221
222        $prop
223
224        $parse
225    };
226
227    // pending - only XmlLang
228    ($(#[$attr:meta])*
229     $name: ident,
230     default: $default: expr,
231     inherits_automatically: $inherits_automatically: expr,
232     newtype: $type: ty,
233     parse_impl: { $parse: item },
234    ) => {
235        $(#[$attr])*
236        #[derive(Debug, Clone, PartialEq)]
237        pub struct $name(pub $type);
238
239        impl_default!($name, $name($default));
240        impl_property!($name, $inherits_automatically);
241
242        $parse
243    };
244
245    ($(#[$attr:meta])*
246     $name: ident,
247     inherits_automatically: $inherits_automatically: expr,
248     fields: {
249       $($field_name: ident : $field_type: ty, default: $field_default : expr,)+
250     }
251     parse_impl: { $parse: item }
252    ) => {
253        $(#[$attr])*
254        #[derive(Debug, Clone, PartialEq)]
255        pub struct $name {
256            $(pub $field_name: $field_type),+
257        }
258
259        impl_default!($name, $name { $($field_name: $field_default),+ });
260        impl_property!($name, $inherits_automatically);
261
262        $parse
263    };
264}
265
266#[doc(hidden)]
267#[macro_export]
268macro_rules! impl_default {
269    ($name:ident, $default:expr) => {
270        impl Default for $name {
271            fn default() -> $name {
272                $default
273            }
274        }
275    };
276}
277
278#[doc(hidden)]
279#[macro_export]
280macro_rules! impl_property {
281    ($name:ident, $inherits_automatically:expr) => {
282        impl $crate::property_macros::Property for $name {
283            fn inherits_automatically() -> bool {
284                $inherits_automatically
285            }
286
287            fn compute(&self, _v: &$crate::properties::ComputedValues) -> Self {
288                self.clone()
289            }
290        }
291    };
292}