tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

helpers.mako.rs (37535B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 <%!
      6    from data import Keyword, to_rust_ident, to_phys, to_camel_case, SYSTEM_FONT_LONGHANDS
      7    from data import (LOGICAL_CORNERS, PHYSICAL_CORNERS, LOGICAL_SIDES,
      8                      PHYSICAL_SIDES, LOGICAL_SIZES, LOGICAL_AXES)
      9 %>
     10 
     11 <%def name="predefined_type(name, type, initial_value, parse_method='parse',
     12            vector=False, none_value=None, initial_specified_value=None,
     13            allow_quirks='No', **kwargs)">
     14    <%def name="predefined_type_inner(name, type, initial_value, parse_method)">
     15        #[allow(unused_imports)]
     16        use app_units::Au;
     17        #[allow(unused_imports)]
     18        use crate::values::specified::AllowQuirks;
     19        #[allow(unused_imports)]
     20        use crate::Zero;
     21        #[allow(unused_imports)]
     22        use smallvec::SmallVec;
     23        pub use crate::values::specified::${type} as SpecifiedValue;
     24        pub mod computed_value {
     25            pub use crate::values::computed::${type} as T;
     26        }
     27        % if initial_value:
     28        #[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} }
     29        % endif
     30        % if initial_specified_value:
     31        #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { ${initial_specified_value} }
     32        % endif
     33        #[allow(unused_variables)]
     34        #[inline]
     35        pub fn parse<'i, 't>(
     36            context: &ParserContext,
     37            input: &mut Parser<'i, 't>,
     38        ) -> Result<SpecifiedValue, ParseError<'i>> {
     39            % if allow_quirks != "No":
     40            specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::${allow_quirks})
     41            % elif parse_method != "parse":
     42            specified::${type}::${parse_method}(context, input)
     43            % else:
     44            <specified::${type} as crate::parser::Parse>::parse(context, input)
     45            % endif
     46        }
     47    </%def>
     48    % if vector:
     49        <%call
     50            expr="vector_longhand(name, predefined_type=type, allow_empty=not initial_value, none_value=none_value, **kwargs)"
     51        >
     52            ${predefined_type_inner(name, type, initial_value, parse_method)}
     53            % if caller:
     54            ${caller.body()}
     55            % endif
     56        </%call>
     57    % else:
     58        <%call expr="longhand(name, predefined_type=type, **kwargs)">
     59            ${predefined_type_inner(name, type, initial_value, parse_method)}
     60            % if caller:
     61            ${caller.body()}
     62            % endif
     63        </%call>
     64    % endif
     65 </%def>
     66 
     67 // The setup here is roughly:
     68 //
     69 //  * UnderlyingList is the list that is stored in the computed value. This may
     70 //    be a shared ArcSlice if the property is inherited.
     71 //  * UnderlyingOwnedList is the list that is used for animation.
     72 //  * Specified values always use OwnedSlice, since it's more compact.
     73 //  * computed_value::List is just a convenient alias that you can use for the
     74 //    computed value list, since this is in the computed_value module.
     75 //
     76 // If simple_vector_bindings is true, then we don't use the complex iterator
     77 // machinery and set_foo_from, and just compute the value like any other
     78 // longhand.
     79 <%def name="vector_longhand(name, vector_animation_type=None, allow_empty=False,
     80                            none_value=None, simple_vector_bindings=False, separator='Comma',
     81                            **kwargs)">
     82    <%call expr="longhand(name, vector=True,
     83                          simple_vector_bindings=simple_vector_bindings, **kwargs)">
     84        #[allow(unused_imports)]
     85        use smallvec::SmallVec;
     86 
     87        pub mod single_value {
     88            #[allow(unused_imports)]
     89            use cssparser::{Parser, BasicParseError};
     90            #[allow(unused_imports)]
     91            use crate::parser::{Parse, ParserContext};
     92            #[allow(unused_imports)]
     93            use crate::properties::ShorthandId;
     94            #[allow(unused_imports)]
     95            use selectors::parser::SelectorParseErrorKind;
     96            #[allow(unused_imports)]
     97            use style_traits::{ParseError, StyleParseErrorKind};
     98            #[allow(unused_imports)]
     99            use crate::values::computed::{Context, ToComputedValue};
    100            #[allow(unused_imports)]
    101            use crate::values::{computed, specified};
    102            ${caller.body()}
    103        }
    104 
    105        /// The definition of the computed value for ${name}.
    106        pub mod computed_value {
    107            #[allow(unused_imports)]
    108            use crate::values::animated::ToAnimatedValue;
    109            #[allow(unused_imports)]
    110            use crate::values::resolved::ToResolvedValue;
    111            #[allow(unused_imports)]
    112            use crate::derives::*;
    113            pub use super::single_value::computed_value as single_value;
    114            pub use self::single_value::T as SingleComputedValue;
    115            % if not allow_empty:
    116            use smallvec::SmallVec;
    117            % endif
    118            use crate::values::computed::ComputedVecIter;
    119 
    120            <%
    121                is_shared_list = allow_empty and \
    122                    data.longhands_by_name[name].style_struct.inherited
    123            %>
    124 
    125            // FIXME(emilio): Add an OwnedNonEmptySlice type, and figure out
    126            // something for transition-name, which is the only remaining user
    127            // of NotInitial.
    128            pub type UnderlyingList<T> =
    129                % if allow_empty:
    130                % if data.longhands_by_name[name].style_struct.inherited:
    131                    crate::ArcSlice<T>;
    132                % else:
    133                    crate::OwnedSlice<T>;
    134                % endif
    135                % else:
    136                    SmallVec<[T; 1]>;
    137                % endif
    138 
    139            pub type UnderlyingOwnedList<T> =
    140                % if allow_empty:
    141                    crate::OwnedSlice<T>;
    142                % else:
    143                    SmallVec<[T; 1]>;
    144                % endif
    145 
    146 
    147            /// The generic type defining the animated and resolved values for
    148            /// this property.
    149            ///
    150            /// Making this type generic allows the compiler to figure out the
    151            /// animated value for us, instead of having to implement it
    152            /// manually for every type we care about.
    153            #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToResolvedValue, ToCss, ToTyped)]
    154            % if separator == "Comma":
    155            #[css(comma)]
    156            % endif
    157            pub struct OwnedList<T>(
    158                % if not allow_empty:
    159                #[css(iterable)]
    160                % else:
    161                #[css(if_empty = "none", iterable)]
    162                % endif
    163                pub UnderlyingOwnedList<T>,
    164            );
    165 
    166            /// The computed value for this property.
    167            % if not is_shared_list:
    168            pub type ComputedList = OwnedList<single_value::T>;
    169            pub use self::OwnedList as List;
    170            % else:
    171            pub use self::ComputedList as List;
    172 
    173            #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToTyped)]
    174            % if separator == "Comma":
    175            #[css(comma)]
    176            % endif
    177            pub struct ComputedList(
    178                % if not allow_empty:
    179                #[css(iterable)]
    180                % else:
    181                #[css(if_empty = "none", iterable)]
    182                % endif
    183                % if is_shared_list:
    184                #[ignore_malloc_size_of = "Arc"]
    185                % endif
    186                pub UnderlyingList<single_value::T>,
    187            );
    188 
    189            type ResolvedList = <OwnedList<single_value::T> as ToResolvedValue>::ResolvedValue;
    190            impl ToResolvedValue for ComputedList {
    191                type ResolvedValue = ResolvedList;
    192 
    193                fn to_resolved_value(self, context: &crate::values::resolved::Context) -> Self::ResolvedValue {
    194                    OwnedList(
    195                        self.0
    196                            .iter()
    197                            .cloned()
    198                            .map(|v| v.to_resolved_value(context))
    199                            .collect()
    200                    )
    201                }
    202 
    203                fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
    204                    % if not is_shared_list:
    205                    use std::iter::FromIterator;
    206                    % endif
    207                    let iter =
    208                        resolved.0.into_iter().map(ToResolvedValue::from_resolved_value);
    209                    ComputedList(UnderlyingList::from_iter(iter))
    210                }
    211            }
    212            % endif
    213 
    214            % if simple_vector_bindings:
    215            impl From<ComputedList> for UnderlyingList<single_value::T> {
    216                #[inline]
    217                fn from(l: ComputedList) -> Self {
    218                    l.0
    219                }
    220            }
    221            impl From<UnderlyingList<single_value::T>> for ComputedList {
    222                #[inline]
    223                fn from(l: UnderlyingList<single_value::T>) -> Self {
    224                    List(l)
    225                }
    226            }
    227            % endif
    228 
    229            % if vector_animation_type:
    230            use crate::values::animated::{Animate, ToAnimatedZero, Procedure, lists};
    231            use crate::values::distance::{SquaredDistance, ComputeSquaredDistance};
    232 
    233            // FIXME(emilio): For some reason rust thinks that this alias is
    234            // unused, even though it's clearly used below?
    235            #[allow(unused)]
    236            type AnimatedList = <OwnedList<single_value::T> as ToAnimatedValue>::AnimatedValue;
    237            % if is_shared_list:
    238            impl ToAnimatedValue for ComputedList {
    239                type AnimatedValue = AnimatedList;
    240 
    241                fn to_animated_value(self, context: &crate::values::animated::Context) -> Self::AnimatedValue {
    242                    OwnedList(
    243                        self.0.iter().map(|v| v.clone().to_animated_value(context)).collect()
    244                    )
    245                }
    246 
    247                fn from_animated_value(animated: Self::AnimatedValue) -> Self {
    248                    let iter =
    249                        animated.0.into_iter().map(ToAnimatedValue::from_animated_value);
    250                    ComputedList(UnderlyingList::from_iter(iter))
    251                }
    252            }
    253            % endif
    254 
    255            impl ToAnimatedZero for AnimatedList {
    256                fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
    257            }
    258 
    259            impl Animate for AnimatedList {
    260                fn animate(
    261                    &self,
    262                    other: &Self,
    263                    procedure: Procedure,
    264                ) -> Result<Self, ()> {
    265                    Ok(OwnedList(
    266                        lists::${vector_animation_type}::animate(&self.0, &other.0, procedure)?
    267                    ))
    268                }
    269            }
    270            impl ComputeSquaredDistance for AnimatedList {
    271                fn compute_squared_distance(
    272                    &self,
    273                    other: &Self,
    274                ) -> Result<SquaredDistance, ()> {
    275                    lists::${vector_animation_type}::squared_distance(&self.0, &other.0)
    276                }
    277            }
    278            % endif
    279 
    280            /// The computed value, effectively a list of single values.
    281            pub use self::ComputedList as T;
    282 
    283            pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>;
    284        }
    285 
    286        /// The specified value of ${name}.
    287        #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, ToTyped)]
    288        % if none_value:
    289        #[value_info(other_values = "none")]
    290        % endif
    291        % if separator == "Comma":
    292        #[css(comma)]
    293        % endif
    294        pub struct SpecifiedValue(
    295            % if not allow_empty:
    296            #[css(iterable)]
    297            % else:
    298            #[css(if_empty = "none", iterable)]
    299            % endif
    300            pub crate::OwnedSlice<single_value::SpecifiedValue>,
    301        );
    302 
    303        pub fn get_initial_value() -> computed_value::T {
    304            % if allow_empty:
    305                computed_value::List(Default::default())
    306            % else:
    307                let mut v = SmallVec::new();
    308                v.push(single_value::get_initial_value());
    309                computed_value::List(v)
    310            % endif
    311        }
    312 
    313        pub fn parse<'i, 't>(
    314            context: &ParserContext,
    315            input: &mut Parser<'i, 't>,
    316        ) -> Result<SpecifiedValue, ParseError<'i>> {
    317            use style_traits::Separator;
    318 
    319            % if allow_empty or none_value:
    320            if input.try_parse(|input| input.expect_ident_matching("none")).is_ok() {
    321                % if allow_empty:
    322                return Ok(SpecifiedValue(Default::default()))
    323                % else:
    324                return Ok(SpecifiedValue(crate::OwnedSlice::from(vec![${none_value}])))
    325                % endif
    326            }
    327            % endif
    328 
    329            let v = style_traits::${separator}::parse(input, |parser| {
    330                single_value::parse(context, parser)
    331            })?;
    332            Ok(SpecifiedValue(v.into()))
    333        }
    334 
    335        pub use self::single_value::SpecifiedValue as SingleSpecifiedValue;
    336 
    337        % if not simple_vector_bindings and engine == "gecko":
    338        impl SpecifiedValue {
    339            fn compute_iter<'a, 'cx, 'cx_a>(
    340                &'a self,
    341                context: &'cx Context<'cx_a>,
    342            ) -> computed_value::Iter<'a, 'cx, 'cx_a> {
    343                computed_value::Iter::new(context, &self.0)
    344            }
    345        }
    346        % endif
    347 
    348        impl ToComputedValue for SpecifiedValue {
    349            type ComputedValue = computed_value::T;
    350 
    351            #[inline]
    352            fn to_computed_value(&self, context: &Context) -> computed_value::T {
    353                % if not is_shared_list:
    354                use std::iter::FromIterator;
    355                % endif
    356                computed_value::List(computed_value::UnderlyingList::from_iter(
    357                    self.0.iter().map(|i| i.to_computed_value(context))
    358                ))
    359            }
    360 
    361            #[inline]
    362            fn from_computed_value(computed: &computed_value::T) -> Self {
    363                let iter = computed.0.iter().map(ToComputedValue::from_computed_value);
    364                SpecifiedValue(iter.collect())
    365            }
    366        }
    367    </%call>
    368 </%def>
    369 <%def name="longhand(*args, **kwargs)">
    370    <%
    371        property = data.declare_longhand(*args, **kwargs)
    372        if property is None:
    373            return ""
    374    %>
    375    /// ${property.spec}
    376    pub mod ${property.ident} {
    377        #[allow(unused_imports)]
    378        use crate::derives::*;
    379        #[allow(unused_imports)]
    380        use cssparser::{Parser, BasicParseError, Token};
    381        #[allow(unused_imports)]
    382        use crate::parser::{Parse, ParserContext};
    383        #[allow(unused_imports)]
    384        use crate::properties::{UnparsedValue, ShorthandId};
    385        #[allow(unused_imports)]
    386        use crate::error_reporting::ParseErrorReporter;
    387        #[allow(unused_imports)]
    388        use crate::properties::longhands;
    389        #[allow(unused_imports)]
    390        use crate::properties::{LonghandId, LonghandIdSet};
    391        #[allow(unused_imports)]
    392        use crate::properties::{CSSWideKeyword, ComputedValues, PropertyDeclaration};
    393        #[allow(unused_imports)]
    394        use crate::properties::style_structs;
    395        #[allow(unused_imports)]
    396        use selectors::parser::SelectorParseErrorKind;
    397        #[allow(unused_imports)]
    398        use servo_arc::Arc;
    399        #[allow(unused_imports)]
    400        use style_traits::{ParseError, StyleParseErrorKind};
    401        #[allow(unused_imports)]
    402        use crate::values::computed::{Context, ToComputedValue};
    403        #[allow(unused_imports)]
    404        use crate::values::{computed, generics, specified};
    405        #[allow(unused_imports)]
    406        use crate::Atom;
    407        ${caller.body()}
    408        #[allow(unused_variables)]
    409        pub unsafe fn cascade_property(
    410            declaration: &PropertyDeclaration,
    411            context: &mut computed::Context,
    412        ) {
    413            % if property.logical:
    414            declaration.debug_crash("Should physicalize before entering here");
    415            % else:
    416            context.for_non_inherited_property = ${"false" if property.style_struct.inherited else "true"};
    417            % if property.logical_group:
    418            debug_assert_eq!(
    419                declaration.id().as_longhand().unwrap().logical_group(),
    420                LonghandId::${property.camel_case}.logical_group(),
    421            );
    422            % else:
    423            debug_assert_eq!(
    424                declaration.id().as_longhand().unwrap(),
    425                LonghandId::${property.camel_case},
    426            );
    427            % endif
    428            let specified_value = match *declaration {
    429                PropertyDeclaration::CSSWideKeyword(ref wk) => {
    430                    match wk.keyword {
    431                        % if not property.style_struct.inherited:
    432                        CSSWideKeyword::Unset |
    433                        % endif
    434                        CSSWideKeyword::Initial => {
    435                            % if not property.style_struct.inherited:
    436                                declaration.debug_crash("Unexpected initial or unset for non-inherited property");
    437                            % else:
    438                                context.builder.reset_${property.ident}();
    439                            % endif
    440                        },
    441                        % if property.style_struct.inherited:
    442                        CSSWideKeyword::Unset |
    443                        % endif
    444                        CSSWideKeyword::Inherit => {
    445                            % if not property.style_struct.inherited:
    446                                context.rule_cache_conditions.borrow_mut().set_uncacheable();
    447                            % endif
    448                            % if property.is_zoom_dependent():
    449                                if !context.builder.effective_zoom_for_inheritance.is_one() {
    450                                    let old_zoom = context.builder.effective_zoom;
    451                                    context.builder.effective_zoom = context.builder.effective_zoom_for_inheritance;
    452                                    let computed = context.builder.inherited_style.clone_${property.ident}();
    453                                    let specified = ToComputedValue::from_computed_value(&computed);
    454                                    % if property.boxed:
    455                                    let specified = Box::new(specified);
    456                                    % endif
    457                                    let decl = PropertyDeclaration::${property.camel_case}(specified);
    458                                    cascade_property(&decl, context);
    459                                    context.builder.effective_zoom = old_zoom;
    460                                    return;
    461                                }
    462                            % endif
    463                            % if property.style_struct.inherited:
    464                                declaration.debug_crash("Unexpected inherit or unset for non-zoom-dependent inherited property");
    465                            % else:
    466                                context.builder.inherit_${property.ident}();
    467                            % endif
    468                        }
    469                        CSSWideKeyword::RevertLayer |
    470                        CSSWideKeyword::Revert => {
    471                            declaration.debug_crash("Found revert/revert-layer not dealt with");
    472                        },
    473                    }
    474                    return;
    475                },
    476                #[cfg(debug_assertions)]
    477                PropertyDeclaration::WithVariables(..) => {
    478                    declaration.debug_crash("Found variables not substituted");
    479                    return;
    480                },
    481                _ => unsafe {
    482                    declaration.unchecked_value_as::<${property.specified_type()}>()
    483                },
    484            };
    485 
    486            % if property.ident in SYSTEM_FONT_LONGHANDS and engine == "gecko":
    487            if let Some(sf) = specified_value.get_system() {
    488                longhands::system_font::resolve_system_font(sf, context);
    489            }
    490            % endif
    491 
    492            % if property.is_vector and not property.simple_vector_bindings and engine == "gecko":
    493                // In the case of a vector property we want to pass down an
    494                // iterator so that this can be computed without allocation.
    495                //
    496                // However, computing requires a context, but the style struct
    497                // being mutated is on the context. We temporarily remove it,
    498                // mutate it, and then put it back. Vector longhands cannot
    499                // touch their own style struct whilst computing, else this will
    500                // panic.
    501                let mut s =
    502                    context.builder.take_${data.current_style_struct.name_lower}();
    503                {
    504                    let iter = specified_value.compute_iter(context);
    505                    s.set_${property.ident}(iter);
    506                }
    507                context.builder.put_${data.current_style_struct.name_lower}(s);
    508            % else:
    509                % if property.boxed:
    510                let computed = (**specified_value).to_computed_value(context);
    511                % else:
    512                let computed = specified_value.to_computed_value(context);
    513                % endif
    514                context.builder.set_${property.ident}(computed)
    515            % endif
    516            % endif
    517        }
    518 
    519        pub fn parse_declared<'i, 't>(
    520            context: &ParserContext,
    521            input: &mut Parser<'i, 't>,
    522        ) -> Result<PropertyDeclaration, ParseError<'i>> {
    523            % if property.allow_quirks != "No":
    524                parse_quirky(context, input, specified::AllowQuirks::${property.allow_quirks})
    525            % else:
    526                parse(context, input)
    527            % endif
    528            % if property.boxed:
    529                .map(Box::new)
    530            % endif
    531                .map(PropertyDeclaration::${property.camel_case})
    532        }
    533    }
    534 </%def>
    535 
    536 <%def name="gecko_keyword_conversion(keyword, values=None, type='SpecifiedValue', cast_to=None)">
    537    <%
    538        if not values:
    539            values = keyword.values_for(engine)
    540        maybe_cast = "as %s" % cast_to if cast_to else ""
    541        const_type = cast_to if cast_to else "u32"
    542    %>
    543    #[cfg(feature = "gecko")]
    544    impl ${type} {
    545        /// Obtain a specified value from a Gecko keyword value
    546        ///
    547        /// Intended for use with presentation attributes, not style structs
    548        pub fn from_gecko_keyword(kw: u32) -> Self {
    549            use crate::gecko_bindings::structs;
    550            % for value in values:
    551                // We can't match on enum values if we're matching on a u32
    552                const ${to_rust_ident(value).upper()}: ${const_type}
    553                    = structs::${keyword.gecko_constant(value)} as ${const_type};
    554            % endfor
    555            match kw ${maybe_cast} {
    556                % for value in values:
    557                    ${to_rust_ident(value).upper()} => ${type}::${to_camel_case(value)},
    558                % endfor
    559                _ => panic!("Found unexpected value in style struct for ${keyword.name} property"),
    560            }
    561        }
    562    }
    563 </%def>
    564 
    565 <%def name="gecko_bitflags_conversion(bit_map, gecko_bit_prefix, type, kw_type='u8')">
    566    #[cfg(feature = "gecko")]
    567    impl ${type} {
    568        /// Obtain a specified value from a Gecko keyword value
    569        ///
    570        /// Intended for use with presentation attributes, not style structs
    571        pub fn from_gecko_keyword(kw: ${kw_type}) -> Self {
    572            % for gecko_bit in bit_map.values():
    573            use crate::gecko_bindings::structs::${gecko_bit_prefix}${gecko_bit};
    574            % endfor
    575 
    576            let mut bits = ${type}::empty();
    577            % for servo_bit, gecko_bit in bit_map.items():
    578                if kw & (${gecko_bit_prefix}${gecko_bit} as ${kw_type}) != 0 {
    579                    bits |= ${servo_bit};
    580                }
    581            % endfor
    582            bits
    583        }
    584 
    585        pub fn to_gecko_keyword(self) -> ${kw_type} {
    586            % for gecko_bit in bit_map.values():
    587            use crate::gecko_bindings::structs::${gecko_bit_prefix}${gecko_bit};
    588            % endfor
    589 
    590            let mut bits: ${kw_type} = 0;
    591            // FIXME: if we ensure that the Servo bitflags storage is the same
    592            // as Gecko's one, we can just copy it.
    593            % for servo_bit, gecko_bit in bit_map.items():
    594                if self.contains(${servo_bit}) {
    595                    bits |= ${gecko_bit_prefix}${gecko_bit} as ${kw_type};
    596                }
    597            % endfor
    598            bits
    599        }
    600    }
    601 </%def>
    602 
    603 <%def name="single_keyword(name, values, vector=False,
    604            needs_conversion=False, **kwargs)">
    605    <%
    606        keyword_kwargs = {a: kwargs.pop(a, None) for a in [
    607            'gecko_constant_prefix',
    608            'gecko_enum_prefix',
    609            'extra_gecko_values',
    610            'extra_servo_values',
    611            'gecko_aliases',
    612            'servo_aliases',
    613            'custom_consts',
    614            'gecko_inexhaustive',
    615            'gecko_strip_moz_prefix',
    616        ]}
    617    %>
    618 
    619    <%def name="inner_body(keyword, needs_conversion=False)">
    620        pub use self::computed_value::T as SpecifiedValue;
    621        pub mod computed_value {
    622            #[allow(unused_imports)]
    623            use crate::derives::*;
    624            #[cfg_attr(feature = "servo", derive(Deserialize, Hash, Serialize))]
    625            #[derive(Clone, Copy, Debug, Eq, FromPrimitive, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss, ToResolvedValue, ToShmem, ToTyped)]
    626            pub enum T {
    627            % for variant in keyword.values_for(engine):
    628            <%
    629                aliases = []
    630                for alias, v in keyword.aliases_for(engine).items():
    631                    if variant == v:
    632                        aliases.append(alias)
    633            %>
    634            % if aliases:
    635            #[parse(aliases = "${','.join(sorted(aliases))}")]
    636            % endif
    637            ${to_camel_case(variant)},
    638            % endfor
    639            }
    640        }
    641        #[inline]
    642        pub fn get_initial_value() -> computed_value::T {
    643            computed_value::T::${to_camel_case(values.split()[0])}
    644        }
    645        #[inline]
    646        pub fn get_initial_specified_value() -> SpecifiedValue {
    647            SpecifiedValue::${to_camel_case(values.split()[0])}
    648        }
    649        #[inline]
    650        pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
    651                             -> Result<SpecifiedValue, ParseError<'i>> {
    652            SpecifiedValue::parse(input)
    653        }
    654 
    655        % if needs_conversion:
    656            <%
    657                conversion_values = keyword.values_for(engine) + list(keyword.aliases_for(engine).keys())
    658            %>
    659            ${gecko_keyword_conversion(keyword, values=conversion_values)}
    660        % endif
    661    </%def>
    662    % if vector:
    663        <%call expr="vector_longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
    664            ${inner_body(Keyword(name, values, **keyword_kwargs))}
    665            % if caller:
    666            ${caller.body()}
    667            % endif
    668        </%call>
    669    % else:
    670        <%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
    671            ${inner_body(Keyword(name, values, **keyword_kwargs),
    672                         needs_conversion=needs_conversion)}
    673            % if caller:
    674            ${caller.body()}
    675            % endif
    676        </%call>
    677    % endif
    678 </%def>
    679 
    680 <%def name="shorthand(name, sub_properties, derive_serialize=False,
    681                      derive_value_info=True, **kwargs)">
    682 <%
    683    shorthand = data.declare_shorthand(name, sub_properties.split(), **kwargs)
    684    # mako doesn't accept non-string value in parameters with <% %> form, so
    685    # we have to workaround it this way.
    686    if not isinstance(derive_value_info, bool):
    687        derive_value_info = eval(derive_value_info)
    688 %>
    689    % if shorthand:
    690    /// ${shorthand.spec}
    691    pub mod ${shorthand.ident} {
    692        use cssparser::Parser;
    693        use crate::parser::ParserContext;
    694        use crate::properties::{PropertyDeclaration, SourcePropertyDeclaration, MaybeBoxed, longhands};
    695        #[allow(unused_imports)]
    696        use selectors::parser::SelectorParseErrorKind;
    697        #[allow(unused_imports)]
    698        use std::fmt::{self, Write};
    699        #[allow(unused_imports)]
    700        use style_traits::{ParseError, StyleParseErrorKind};
    701        #[allow(unused_imports)]
    702        use style_traits::{CssWriter, KeywordsCollectFn, SpecifiedValueInfo, ToCss};
    703        #[allow(unused_imports)]
    704        use style_derive::{Animate, ComputeSquaredDistance, ToAnimatedValue, Parse, ToAnimatedZero, ToComputedValue, ToResolvedValue, ToCss, SpecifiedValueInfo, ToTyped};
    705 
    706        % if derive_value_info:
    707        #[derive(SpecifiedValueInfo)]
    708        % endif
    709        pub struct Longhands {
    710            % for sub_property in shorthand.sub_properties:
    711                pub ${sub_property.ident}:
    712                    % if sub_property.boxed:
    713                        Box<
    714                    % endif
    715                    longhands::${sub_property.ident}::SpecifiedValue
    716                    % if sub_property.boxed:
    717                        >
    718                    % endif
    719                    ,
    720            % endfor
    721        }
    722 
    723        /// Represents a serializable set of all of the longhand properties that
    724        /// correspond to a shorthand.
    725        % if derive_serialize:
    726        #[derive(ToCss)]
    727        % endif
    728        pub struct LonghandsToSerialize<'a> {
    729            % for sub_property in shorthand.sub_properties:
    730                pub ${sub_property.ident}:
    731                % if sub_property.may_be_disabled_in(shorthand, engine):
    732                    Option<
    733                % endif
    734                    &'a longhands::${sub_property.ident}::SpecifiedValue,
    735                % if sub_property.may_be_disabled_in(shorthand, engine):
    736                    >,
    737                % endif
    738            % endfor
    739        }
    740 
    741        impl<'a> LonghandsToSerialize<'a> {
    742            /// Tries to get a serializable set of longhands given a set of
    743            /// property declarations.
    744            pub fn from_iter(iter: impl Iterator<Item = &'a PropertyDeclaration>) -> Result<Self, ()> {
    745                // Define all of the expected variables that correspond to the shorthand
    746                % for sub_property in shorthand.sub_properties:
    747                    let mut ${sub_property.ident} =
    748                        None::<&'a longhands::${sub_property.ident}::SpecifiedValue>;
    749                % endfor
    750 
    751                // Attempt to assign the incoming declarations to the expected variables
    752                for declaration in iter {
    753                    match *declaration {
    754                        % for sub_property in shorthand.sub_properties:
    755                            PropertyDeclaration::${sub_property.camel_case}(ref value) => {
    756                                ${sub_property.ident} = Some(value)
    757                            },
    758                        % endfor
    759                        _ => {}
    760                    };
    761                }
    762 
    763                // If any of the expected variables are missing, return an error
    764                match (
    765                    % for sub_property in shorthand.sub_properties:
    766                        ${sub_property.ident},
    767                    % endfor
    768                ) {
    769 
    770                    (
    771                    % for sub_property in shorthand.sub_properties:
    772                        % if sub_property.may_be_disabled_in(shorthand, engine):
    773                        ${sub_property.ident},
    774                        % else:
    775                        Some(${sub_property.ident}),
    776                        % endif
    777                    % endfor
    778                    ) =>
    779                    Ok(LonghandsToSerialize {
    780                        % for sub_property in shorthand.sub_properties:
    781                            ${sub_property.ident},
    782                        % endfor
    783                    }),
    784                    _ => Err(())
    785                }
    786            }
    787        }
    788 
    789        /// Parse the given shorthand and fill the result into the
    790        /// `declarations` vector.
    791        pub fn parse_into<'i, 't>(
    792            declarations: &mut SourcePropertyDeclaration,
    793            context: &ParserContext,
    794            input: &mut Parser<'i, 't>,
    795        ) -> Result<(), ParseError<'i>> {
    796            #[allow(unused_imports)]
    797            use crate::properties::{NonCustomPropertyId, LonghandId};
    798            input.parse_entirely(|input| parse_value(context, input)).map(|longhands| {
    799                % for sub_property in shorthand.sub_properties:
    800                % if sub_property.may_be_disabled_in(shorthand, engine):
    801                if NonCustomPropertyId::from(LonghandId::${sub_property.camel_case})
    802                    .allowed_in_ignoring_rule_type(context) {
    803                % endif
    804                    declarations.push(PropertyDeclaration::${sub_property.camel_case}(
    805                        longhands.${sub_property.ident}
    806                    ));
    807                % if sub_property.may_be_disabled_in(shorthand, engine):
    808                }
    809                % endif
    810                % endfor
    811            })
    812        }
    813 
    814        /// Try to serialize a given shorthand to a string.
    815        pub fn to_css(declarations: &[&PropertyDeclaration], dest: &mut style_traits::CssStringWriter) -> fmt::Result {
    816            match LonghandsToSerialize::from_iter(declarations.iter().cloned()) {
    817                Ok(longhands) => longhands.to_css(&mut CssWriter::new(dest)),
    818                Err(_) => Ok(())
    819            }
    820        }
    821 
    822        ${caller.body()}
    823    }
    824    % endif
    825 </%def>
    826 
    827 // A shorthand of kind `<property-1> <property-2>?` where both properties have
    828 // the same type.
    829 <%def name="two_properties_shorthand(
    830    name,
    831    first_property,
    832    second_property,
    833    parser_function='crate::parser::Parse::parse',
    834    **kwargs
    835 )">
    836 <%call expr="self.shorthand(name, sub_properties=' '.join([first_property, second_property]), **kwargs)">
    837    #[allow(unused_imports)]
    838    use crate::parser::Parse;
    839    #[allow(unused_imports)]
    840    use crate::values::specified;
    841 
    842    fn parse_value<'i, 't>(
    843        context: &ParserContext,
    844        input: &mut Parser<'i, 't>,
    845    ) -> Result<Longhands, ParseError<'i>> {
    846        let parse_one = |c: &ParserContext, input: &mut Parser<'i, 't>| -> Result<
    847            crate::properties::longhands::${to_rust_ident(first_property)}::SpecifiedValue,
    848            ParseError<'i>
    849        > {
    850            ${parser_function}(c, input)
    851        };
    852 
    853        let first = parse_one(context, input)?;
    854        let second =
    855            input.try_parse(|input| parse_one(context, input)).unwrap_or_else(|_| first.clone());
    856        Ok(expanded! {
    857            ${to_rust_ident(first_property)}: first,
    858            ${to_rust_ident(second_property)}: second,
    859        })
    860    }
    861 
    862    impl<'a> ToCss for LonghandsToSerialize<'a>  {
    863        fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
    864            let first = &self.${to_rust_ident(first_property)};
    865            let second = &self.${to_rust_ident(second_property)};
    866 
    867            first.to_css(dest)?;
    868            if first != second {
    869                dest.write_char(' ')?;
    870                second.to_css(dest)?;
    871            }
    872            Ok(())
    873        }
    874    }
    875 </%call>
    876 </%def>
    877 
    878 <%def name="four_sides_shorthand(name, sub_property_pattern,
    879                                 parser_function='crate::parser::Parse::parse',
    880                                 allow_quirks='No', **kwargs)">
    881    <% sub_properties=' '.join(sub_property_pattern % side for side in PHYSICAL_SIDES) %>
    882    <%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)">
    883        #[allow(unused_imports)]
    884        use crate::parser::Parse;
    885        use crate::values::generics::rect::Rect;
    886        #[allow(unused_imports)]
    887        use crate::values::specified;
    888 
    889        fn parse_value<'i, 't>(
    890            context: &ParserContext,
    891            input: &mut Parser<'i, 't>,
    892        ) -> Result<Longhands, ParseError<'i>> {
    893            let rect = Rect::parse_with(context, input, |c, i| -> Result<
    894                crate::properties::longhands::${to_rust_ident(sub_property_pattern % "top")}::SpecifiedValue,
    895                ParseError<'i>
    896            > {
    897            % if allow_quirks != "No":
    898                ${parser_function}_quirky(c, i, specified::AllowQuirks::${allow_quirks})
    899            % else:
    900                ${parser_function}(c, i)
    901            % endif
    902            })?;
    903            Ok(expanded! {
    904                % for index, side in enumerate(["top", "right", "bottom", "left"]):
    905                    ${to_rust_ident(sub_property_pattern % side)}: rect.${index},
    906                % endfor
    907            })
    908        }
    909 
    910        impl<'a> ToCss for LonghandsToSerialize<'a> {
    911            fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    912            where
    913                W: Write,
    914            {
    915                let rect = Rect::new(
    916                    % for side in ["top", "right", "bottom", "left"]:
    917                    &self.${to_rust_ident(sub_property_pattern % side)},
    918                    % endfor
    919                );
    920                rect.to_css(dest)
    921            }
    922        }
    923    </%call>
    924 </%def>