summaryrefslogtreecommitdiff
path: root/rsvg/src/property_macros.rs
diff options
context:
space:
mode:
authorMarge Bot <marge-bot@gnome.org>2023-04-25 23:30:10 +0000
committerMarge Bot <marge-bot@gnome.org>2023-04-25 23:30:10 +0000
commit30567b3eac0148e3e95f5dd011ff76bda5000a99 (patch)
tree7d5c56dc2b20f91ccc77aee4dad07830e7eb429a /rsvg/src/property_macros.rs
parentd597831ff93b09cc41ce4768a833bc6407c95184 (diff)
parent7608c94036d7a44296a7e135f42e84aed20afeb7 (diff)
downloadlibrsvg-30567b3eac0148e3e95f5dd011ff76bda5000a99.tar.gz
Merge branch 'wip/sophie-h/workspace' into 'main'
meta: Move lib and bins into separate crates Closes #950 See merge request GNOME/librsvg!822
Diffstat (limited to 'rsvg/src/property_macros.rs')
-rw-r--r--rsvg/src/property_macros.rs288
1 files changed, 288 insertions, 0 deletions
diff --git a/rsvg/src/property_macros.rs b/rsvg/src/property_macros.rs
new file mode 100644
index 00000000..0a51649e
--- /dev/null
+++ b/rsvg/src/property_macros.rs
@@ -0,0 +1,288 @@
+//! Macros to define CSS properties.
+
+use crate::properties::ComputedValues;
+
+/// Trait which all CSS property types should implement.
+pub trait Property {
+ /// Whether the property's computed value inherits from parent to child elements.
+ ///
+ /// For each property, the CSS or SVG specs say whether the property inherits
+ /// automatically. When a property is not specified in an element, the return value
+ /// of this method determines whether the property's value is copied from the parent
+ /// element (`true`), or whether it resets to the initial/default value (`false`).
+ fn inherits_automatically() -> bool;
+
+ /// Derive the CSS computed value from the parent element's
+ /// [`ComputedValues`][crate::properties::ComputedValues] and the
+ /// `self` value.
+ ///
+ /// The CSS or SVG specs say how to derive this for each property.
+ fn compute(&self, _: &ComputedValues) -> Self;
+}
+
+/// Generates a type for a CSS property.
+///
+/// Writing a property by hand takes a bit of boilerplate:
+///
+/// * Define a type to represent the property's values.
+///
+/// * A [`Parse`] implementation to parse the property.
+///
+/// * A [`Default`] implementation to define the property's *initial* value.
+///
+/// * A [`Property`] implementation to define whether the property
+/// inherits from the parent element, and how the property derives its
+/// computed value.
+///
+/// When going from [`SpecifiedValues`] to [`ComputedValues`],
+/// properties which inherit automatically from the parent element
+/// will just have their values cloned. Properties which do not
+/// inherit will be reset back to their initial value (i.e. their
+/// [`Default`]).
+///
+/// The default implementation of [`Property::compute()`] is to just
+/// clone the property's value. Properties which need more
+/// sophisticated computation can override this.
+///
+/// This macro allows defining properties of different kinds; see the following
+/// sections for examples.
+///
+/// # Simple identifiers
+///
+/// Many properties are just sets of identifiers and can be represented
+/// by simple enums. In this case, you can use the following:
+///
+/// ```text
+/// make_property!(
+/// /// Documentation here.
+/// StrokeLinejoin,
+/// default: Miter,
+/// inherits_automatically: true,
+///
+/// identifiers:
+/// "miter" => Miter,
+/// "round" => Round,
+/// "bevel" => Bevel,
+/// );
+/// ```
+///
+/// This generates a simple enum like the following, with implementations of [`Parse`],
+/// [`Default`], and [`Property`].
+///
+/// ```
+/// pub enum StrokeLinejoin { Miter, Round, Bevel }
+/// ```
+///
+/// # Properties from an existing, general-purpose type
+///
+/// For example, both the `lightingColor` and `floodColor` properties can be represented
+/// with a `cssparser::Color`, but their intial values are different. In this case, the macro
+/// can generate a newtype around `cssparser::Color` for each case:
+///
+/// ```text
+/// make_property!(
+/// /// Documentation here.
+/// FloodColor,
+/// default: cssparser::Color::RGBA(cssparser::RGBA::new(0, 0, 0, 0)),
+/// inherits_automatically: false,
+/// newtype_parse: cssparser::Color,
+/// );
+/// ```
+///
+/// # Properties from custom specific types
+///
+/// For example, font-related properties have custom, complex types that require an
+/// implentation of `Property::compute` that is more than a simple `clone`. In this case,
+/// define the custom type separately, and use the macro to specify the default value and
+/// the `Property` implementation.
+///
+/// [`Parse`]: crate::parsers::Parse
+/// [`Property`]: crate::property_macros::Property
+/// [`ComputedValues`]: crate::properties::ComputedValues
+/// [`SpecifiedValues`]: crate::properties::SpecifiedValues
+/// [`Property::compute()`]: crate::property_macros::Property::compute
+///
+#[macro_export]
+macro_rules! make_property {
+ ($(#[$attr:meta])*
+ $name: ident,
+ default: $default: ident,
+ inherits_automatically: $inherits_automatically: expr,
+ identifiers:
+ $($str_prop: expr => $variant: ident,)+
+ ) => {
+ $(#[$attr])*
+ #[derive(Debug, Copy, Clone, PartialEq)]
+ #[repr(C)]
+ pub enum $name {
+ $($variant),+
+ }
+
+ impl_default!($name, $name::$default);
+ impl_property!($name, $inherits_automatically);
+
+ impl $crate::parsers::Parse for $name {
+ fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, $crate::error::ParseError<'i>> {
+ Ok(parse_identifiers!(
+ parser,
+ $($str_prop => $name::$variant,)+
+ )?)
+ }
+ }
+ };
+
+ ($(#[$attr:meta])*
+ $name: ident,
+ default: $default: ident,
+ identifiers: { $($str_prop: expr => $variant: ident,)+ },
+ property_impl: { $prop: item }
+ ) => {
+ $(#[$attr])*
+ #[derive(Debug, Copy, Clone, PartialEq)]
+ #[repr(C)]
+ pub enum $name {
+ $($variant),+
+ }
+
+ impl_default!($name, $name::$default);
+ $prop
+
+ impl $crate::parsers::Parse for $name {
+ fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, $crate::error::ParseError<'i>> {
+ Ok(parse_identifiers!(
+ parser,
+ $($str_prop => $name::$variant,)+
+ )?)
+ }
+ }
+ };
+
+ ($(#[$attr:meta])*
+ $name: ident,
+ default: $default: expr,
+ inherits_automatically: $inherits_automatically: expr,
+ newtype_parse: $type: ty,
+ ) => {
+ $(#[$attr])*
+ #[derive(Debug, Clone, PartialEq)]
+ pub struct $name(pub $type);
+
+ impl_default!($name, $name($default));
+ impl_property!($name, $inherits_automatically);
+
+ impl $crate::parsers::Parse for $name {
+ fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, $crate::error::ParseError<'i>> {
+ Ok($name(<$type as $crate::parsers::Parse>::parse(parser)?))
+ }
+ }
+ };
+
+ ($(#[$attr:meta])*
+ $name: ident,
+ default: $default: expr,
+ property_impl: { $prop: item }
+ ) => {
+ impl_default!($name, $default);
+
+ $prop
+ };
+
+ ($name: ident,
+ default: $default: expr,
+ inherits_automatically: $inherits_automatically: expr,
+ ) => {
+ impl_default!($name, $default);
+ impl_property!($name, $inherits_automatically);
+ };
+
+ ($name: ident,
+ default: $default: expr,
+ inherits_automatically: $inherits_automatically: expr,
+ parse_impl: { $parse: item }
+ ) => {
+ impl_default!($name, $default);
+ impl_property!($name, $inherits_automatically);
+
+ $parse
+ };
+
+ ($(#[$attr:meta])*
+ $name: ident,
+ default: $default: expr,
+ newtype: $type: ty,
+ property_impl: { $prop: item },
+ parse_impl: { $parse: item }
+ ) => {
+ $(#[$attr])*
+ #[derive(Debug, Clone, PartialEq)]
+ pub struct $name(pub $type);
+
+ impl_default!($name, $name($default));
+
+ $prop
+
+ $parse
+ };
+
+ // pending - only XmlLang
+ ($(#[$attr:meta])*
+ $name: ident,
+ default: $default: expr,
+ inherits_automatically: $inherits_automatically: expr,
+ newtype: $type: ty,
+ parse_impl: { $parse: item },
+ ) => {
+ $(#[$attr])*
+ #[derive(Debug, Clone, PartialEq)]
+ pub struct $name(pub $type);
+
+ impl_default!($name, $name($default));
+ impl_property!($name, $inherits_automatically);
+
+ $parse
+ };
+
+ ($(#[$attr:meta])*
+ $name: ident,
+ inherits_automatically: $inherits_automatically: expr,
+ fields: {
+ $($field_name: ident : $field_type: ty, default: $field_default : expr,)+
+ }
+ parse_impl: { $parse: item }
+ ) => {
+ $(#[$attr])*
+ #[derive(Debug, Clone, PartialEq)]
+ pub struct $name {
+ $(pub $field_name: $field_type),+
+ }
+
+ impl_default!($name, $name { $($field_name: $field_default),+ });
+ impl_property!($name, $inherits_automatically);
+
+ $parse
+ };
+}
+
+macro_rules! impl_default {
+ ($name:ident, $default:expr) => {
+ impl Default for $name {
+ fn default() -> $name {
+ $default
+ }
+ }
+ };
+}
+
+macro_rules! impl_property {
+ ($name:ident, $inherits_automatically:expr) => {
+ impl $crate::property_macros::Property for $name {
+ fn inherits_automatically() -> bool {
+ $inherits_automatically
+ }
+
+ fn compute(&self, _v: &$crate::properties::ComputedValues) -> Self {
+ self.clone()
+ }
+ }
+ };
+}