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}