<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%! from data import Keyword, to_rust_ident, to_camel_case, LOGICAL_SIDES, PHYSICAL_SIDES, LOGICAL_SIZES %>

<%def name="predefined_type(name, type, initial_value, parse_method='parse',
            needs_context=True, vector=False, initial_specified_value=None, **kwargs)">
    <%def name="predefined_type_inner(name, type, initial_value, parse_method)">
        #[allow(unused_imports)]
        use app_units::Au;
        use cssparser::{Color as CSSParserColor, RGBA};
        pub use values::specified::${type} as SpecifiedValue;
        pub mod computed_value {
            pub use values::computed::${type} as T;
        }
        #[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} }
        % if initial_specified_value:
        #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { ${initial_specified_value} }
        % endif
        #[allow(unused_variables)]
        #[inline] pub fn parse(context: &ParserContext, input: &mut Parser)
                               -> Result<SpecifiedValue, ()> {
            % if needs_context:
            specified::${type}::${parse_method}(context, input)
            % else:
            specified::${type}::${parse_method}(input)
            % endif
        }
    </%def>
    % if vector:
        <%call expr="vector_longhand(name, predefined_type=type, **kwargs)">
            ${predefined_type_inner(name, type, initial_value, parse_method)}
        </%call>
    % else:
        <%call expr="longhand(name, predefined_type=type, **kwargs)">
            ${predefined_type_inner(name, type, initial_value, parse_method)}
        </%call>
    % endif
</%def>

// FIXME (Manishearth): Add computed_value_as_specified argument
// and handle the empty case correctly
<%doc>
    To be used in cases where we have a grammar like
    "<thing> [ , <thing> ]*". `gecko_only` should be set
    to True for cases where Servo takes a single value
    and Stylo supports vector values.

    Setting allow_empty to False allows for cases where the vector
    is empty. The grammar for these is usually "none | <thing> [ , <thing> ]*".
    We assume that the default/initial value is an empty vector for these.
    `initial_value` need not be defined for these.
</%doc>
<%def name="vector_longhand(name, gecko_only=False, allow_empty=False,
            delegate_animate=False, space_separated_allowed=False, **kwargs)">
    <%call expr="longhand(name, **kwargs)">
        % if not gecko_only:
            use std::fmt;
            use values::HasViewportPercentage;
            use style_traits::ToCss;

            impl HasViewportPercentage for SpecifiedValue {
                fn has_viewport_percentage(&self) -> bool {
                    let &SpecifiedValue(ref vec) = self;
                    vec.iter().any(|ref x| x.has_viewport_percentage())
                }
            }

            pub mod single_value {
                use cssparser::Parser;
                use parser::{Parse, ParserContext, ParserContextExtraData};
                use properties::{DeclaredValue, ShorthandId};
                use values::computed::{Context, ToComputedValue};
                use values::{computed, specified};
                use values::{Auto, Either, None_, Normal};
                ${caller.body()}
            }

            /// The definition of the computed value for ${name}.
            pub mod computed_value {
                pub use super::single_value::computed_value as single_value;
                pub use self::single_value::T as SingleComputedValue;
                /// The computed value, effectively a list of single values.
                #[derive(Debug, Clone, PartialEq)]
                #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
                pub struct T(pub Vec<single_value::T>);

                % if delegate_animate:
                    use properties::animated_properties::Interpolate;
                    impl Interpolate for T {
                        fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
                            self.0.interpolate(&other.0, progress).map(T)
                        }
                    }
                % endif
            }

            impl ToCss for computed_value::T {
                fn to_css<W>(&self, dest: &mut W) -> fmt::Result
                    where W: fmt::Write,
                {
                    let mut iter = self.0.iter();
                    if let Some(val) = iter.next() {
                        try!(val.to_css(dest));
                    } else {
                        % if allow_empty:
                            try!(dest.write_str("none"));
                        % else:
                            warn!("Found empty value for property ${name}");
                        % endif
                    }
                    for i in iter {
                        try!(dest.write_str(", "));
                        try!(i.to_css(dest));
                    }
                    Ok(())
                }
            }

            /// The specified value of ${name}.
            #[derive(Debug, Clone, PartialEq)]
            #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
            pub struct SpecifiedValue(pub Vec<single_value::SpecifiedValue>);

            impl ToCss for SpecifiedValue {
                fn to_css<W>(&self, dest: &mut W) -> fmt::Result
                    where W: fmt::Write,
                {
                    let mut iter = self.0.iter();
                    if let Some(val) = iter.next() {
                        try!(val.to_css(dest));
                    } else {
                        % if allow_empty:
                            try!(dest.write_str("none"));
                        % else:
                            warn!("Found empty value for property ${name}");
                        % endif
                    }
                    for i in iter {
                        try!(dest.write_str(", "));
                        try!(i.to_css(dest));
                    }
                    Ok(())
                }
            }

            pub fn get_initial_value() -> computed_value::T {
                % if allow_empty:
                    computed_value::T(vec![])
                % else:
                    computed_value::T(vec![single_value::get_initial_value()])
                % endif
            }

            pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
                use parser::parse_space_or_comma_separated;

                <%
                    parse_func = "Parser::parse_comma_separated"
                    if space_separated_allowed:
                        parse_func = "parse_space_or_comma_separated"
                %>
                % if allow_empty:
                    if input.try(|input| input.expect_ident_matching("none")).is_ok() {
                        Ok(SpecifiedValue(Vec::new()))
                    } else {
                        ${parse_func}(input, |parser| {
                            single_value::parse(context, parser)
                        }).map(SpecifiedValue)
                    }
                % else:
                    ${parse_func}(input, |parser| {
                        single_value::parse(context, parser)
                    }).map(SpecifiedValue)
                % endif
            }

            pub use self::single_value::SpecifiedValue as SingleSpecifiedValue;

            impl ToComputedValue for SpecifiedValue {
                type ComputedValue = computed_value::T;

                #[inline]
                fn to_computed_value(&self, context: &Context) -> computed_value::T {
                    computed_value::T(self.0.iter().map(|x| x.to_computed_value(context)).collect())
                }
                #[inline]
                fn from_computed_value(computed: &computed_value::T) -> Self {
                    SpecifiedValue(computed.0.iter()
                                       .map(|x| ToComputedValue::from_computed_value(x))
                                       .collect())
                }
            }
        % else:
            ${caller.body()}
        % endif
    </%call>
</%def>

<%def name="longhand(*args, **kwargs)">
    <%
        property = data.declare_longhand(*args, **kwargs)
        if property is None:
            return ""
    %>
    /// ${property.spec}
    pub mod ${property.ident} {
        #![allow(unused_imports)]
        % if not property.derived_from:
            use cssparser::Parser;
            use parser::{Parse, ParserContext, ParserContextExtraData};
            use properties::{DeclaredValue, UnparsedValue, ShorthandId};
        % endif
        use values::{Auto, Either, None_, Normal};
        use cascade_info::CascadeInfo;
        use error_reporting::ParseErrorReporter;
        use properties::longhands;
        use properties::LonghandIdSet;
        use properties::{CSSWideKeyword, ComputedValues, PropertyDeclaration};
        use properties::style_structs;
        use std::boxed::Box as StdBox;
        use std::collections::HashMap;
        use std::sync::Arc;
        use values::computed::{Context, ToComputedValue};
        use values::{computed, specified};
        use Atom;
        ${caller.body()}
        #[allow(unused_variables)]
        pub fn cascade_property(declaration: &PropertyDeclaration,
                                inherited_style: &ComputedValues,
                                default_style: &Arc<ComputedValues>,
                                context: &mut computed::Context,
                                cacheable: &mut bool,
                                cascade_info: &mut Option<<&mut CascadeInfo>,
                                error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
            let declared_value = match *declaration {
                PropertyDeclaration::${property.camel_case}(ref declared_value) => {
                    declared_value
                }
                _ => panic!("entered the wrong cascade_property() implementation"),
            };

            % if not property.derived_from:
                {
                    let custom_props = context.style().custom_properties();
                    ::properties::substitute_variables_${property.ident}(
                        declared_value, &custom_props,
                    |value| {
                        if let Some(ref mut cascade_info) = *cascade_info {
                            cascade_info.on_cascade_property(&declaration,
                                                             &value);
                        }
                        % if property.logical:
                            let wm = context.style.writing_mode;
                        % endif
                        <% maybe_wm = ", wm" if property.logical else "" %>
                        match *value {
                            DeclaredValue::Value(ref specified_value) => {
                                let computed = specified_value.to_computed_value(context);
                                % if property.has_uncacheable_values:
                                context.mutate_style().mutate_${data.current_style_struct.name_lower}()
                                                      .set_${property.ident}(computed, cacheable ${maybe_wm});
                                % else:
                                context.mutate_style().mutate_${data.current_style_struct.name_lower}()
                                                      .set_${property.ident}(computed ${maybe_wm});
                                % endif
                            }
                            DeclaredValue::WithVariables(_) => unreachable!(),
                            DeclaredValue::CSSWideKeyword(keyword) => match keyword {
                                % if not data.current_style_struct.inherited:
                                CSSWideKeyword::Unset |
                                % endif
                                CSSWideKeyword::Initial => {
                                    // We assume that it's faster to use copy_*_from rather than
                                    // set_*(get_initial_value());
                                    let initial_struct = default_style
                                                        .get_${data.current_style_struct.name_lower}();
                                    context.mutate_style().mutate_${data.current_style_struct.name_lower}()
                                                        .copy_${property.ident}_from(initial_struct ${maybe_wm});
                                },
                                % if data.current_style_struct.inherited:
                                CSSWideKeyword::Unset |
                                % endif
                                CSSWideKeyword::Inherit => {
                                    // This is a bit slow, but this is rare so it shouldn't
                                    // matter.
                                    //
                                    // FIXME: is it still?
                                    *cacheable = false;
                                    let inherited_struct =
                                        inherited_style.get_${data.current_style_struct.name_lower}();
                                    context.mutate_style().mutate_${data.current_style_struct.name_lower}()
                                        .copy_${property.ident}_from(inherited_struct ${maybe_wm});
                                }
                            }
                        }
                    }, error_reporter);
                }

                % if property.custom_cascade:
                    cascade_property_custom(declaration,
                                            inherited_style,
                                            context,
                                            cacheable,
                                            error_reporter);
                % endif
            % else:
                // Do not allow stylesheets to set derived properties.
            % endif
        }
        % if not property.derived_from:
            pub fn parse_specified(context: &ParserContext, input: &mut Parser)
                % if property.boxed:
                                   -> Result<DeclaredValue<Box<SpecifiedValue>>, ()> {
                    parse(context, input).map(|result| DeclaredValue::Value(Box::new(result)))
                % else:
                                   -> Result<DeclaredValue<SpecifiedValue>, ()> {
                    parse(context, input).map(DeclaredValue::Value)
                % endif
            }
            pub fn parse_declared(context: &ParserContext, input: &mut Parser)
                               % if property.boxed:
                                   -> Result<DeclaredValue<Box<SpecifiedValue>>, ()> {
                               % else:
                                   -> Result<DeclaredValue<SpecifiedValue>, ()> {
                               % endif
                match input.try(|i| CSSWideKeyword::parse(context, i)) {
                    Ok(keyword) => Ok(DeclaredValue::CSSWideKeyword(keyword)),
                    Err(()) => {
                        input.look_for_var_functions();
                        let start = input.position();
                        let specified = parse_specified(context, input);
                        if specified.is_err() {
                            while let Ok(_) = input.next() {}  // Look for var() after the error.
                        }
                        let var = input.seen_var_functions();
                        if specified.is_err() && var {
                            input.reset(start);
                            let (first_token_type, css) = try!(
                                ::custom_properties::parse_non_custom_with_var(input));
                            return Ok(DeclaredValue::WithVariables(Box::new(UnparsedValue {
                                css: css.into_owned(),
                                first_token_type: first_token_type,
                                base_url: context.base_url.clone(),
                                from_shorthand: None,
                            })))
                        }
                        specified
                    }
                }
            }
        % endif
    }
</%def>

<%def name="single_keyword(name, values, vector=False, **kwargs)">
    <%call expr="single_keyword_computed(name, values, vector, **kwargs)">
        use values::computed::ComputedValueAsSpecified;
        use values::HasViewportPercentage;
        impl ComputedValueAsSpecified for SpecifiedValue {}
        no_viewport_percentage!(SpecifiedValue);
    </%call>
</%def>

<%def name="gecko_keyword_conversion(keyword, values=None, type='SpecifiedValue')">
    <%
        if not values:
            values = keyword.values_for(product)
    %>
    #[cfg(feature = "gecko")]
    impl ${type} {
        /// Obtain a specified value from a Gecko keyword value
        ///
        /// Intended for use with presentation attributes, not style structs
        pub fn from_gecko_keyword(kw: u32) -> Self {
            use gecko_bindings::structs;
            % if keyword.gecko_enum_prefix:
                % for value in values:
                    // We can't match on enum values if we're matching on a u32
                    const ${to_rust_ident(value).upper()}: u32
                        = structs::${keyword.gecko_enum_prefix}::${to_camel_case(value)} as u32;
                % endfor
                match kw {
                    % for value in values:
                        ${to_rust_ident(value).upper()} => ${type}::${to_rust_ident(value)},
                    % endfor
                    x => panic!("Found unexpected value in style struct for ${keyword.name} property: {:?}", x),
                }
            % else:
                match kw {
                    % for value in values:
                        structs::${keyword.gecko_constant(value)} => ${type}::${to_rust_ident(value)},
                    % endfor
                    x => panic!("Found unexpected value in style struct for ${keyword.name} property: {:?}", x),
                }
            % endif
        }
    }
</%def>

<%def name="single_keyword_computed(name, values, vector=False,
            extra_specified=None, needs_conversion=False, **kwargs)">
    <%
        keyword_kwargs = {a: kwargs.pop(a, None) for a in [
            'gecko_constant_prefix', 'gecko_enum_prefix',
            'extra_gecko_values', 'extra_servo_values',
            'custom_consts', 'gecko_inexhaustive',
        ]}
    %>

    <%def name="inner_body(keyword, extra_specified=None, needs_conversion=False)">
        % if extra_specified:
            use style_traits::ToCss;
            define_css_keyword_enum! { SpecifiedValue:
                % for value in keyword.values_for(product) + extra_specified.split():
                    "${value}" => ${to_rust_ident(value)},
                % endfor
            }
        % else:
            pub use self::computed_value::T as SpecifiedValue;
        % endif
        pub mod computed_value {
            use style_traits::ToCss;
            define_css_keyword_enum! { T:
                % for value in data.longhands_by_name[name].keyword.values_for(product):
                    "${value}" => ${to_rust_ident(value)},
                % endfor
            }
        }
        #[inline]
        pub fn get_initial_value() -> computed_value::T {
            computed_value::T::${to_rust_ident(values.split()[0])}
        }
        #[inline]
        pub fn get_initial_specified_value() -> SpecifiedValue {
            SpecifiedValue::${to_rust_ident(values.split()[0])}
        }
        #[inline]
        pub fn parse(_context: &ParserContext, input: &mut Parser)
                     -> Result<SpecifiedValue, ()> {
            SpecifiedValue::parse(input)
        }
        impl Parse for SpecifiedValue {
            #[inline]
            fn parse(_context: &ParserContext, input: &mut Parser)
                         -> Result<SpecifiedValue, ()> {
                SpecifiedValue::parse(input)
            }
        }

        % if needs_conversion:
            <%
                conversion_values = keyword.values_for(product)
                if extra_specified:
                    conversion_values += extra_specified.split()
            %>
            ${gecko_keyword_conversion(keyword, values=conversion_values)}
        % endif
    </%def>
    % if vector:
        <%call expr="vector_longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
            ${inner_body(Keyword(name, values, **keyword_kwargs))}
            ${caller.body()}
        </%call>
    % else:
        <%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
            ${inner_body(Keyword(name, values, **keyword_kwargs),
                         extra_specified=extra_specified, needs_conversion=needs_conversion)}
            ${caller.body()}
        </%call>
    % endif
</%def>

<%def name="shorthand(name, sub_properties, experimental=False, **kwargs)">
<%
    shorthand = data.declare_shorthand(name, sub_properties.split(), experimental=experimental,
                                       **kwargs)
%>
    % if shorthand:
    /// ${shorthand.spec}
    pub mod ${shorthand.ident} {
        #[allow(unused_imports)]
        use cssparser::Parser;
        use parser::ParserContext;
        use properties::{DeclaredValue, PropertyDeclaration};
        use properties::{ShorthandId, UnparsedValue, longhands};
        use properties::declaration_block::Importance;
        use std::fmt;
        use style_traits::ToCss;

        pub struct Longhands {
            % for sub_property in shorthand.sub_properties:
                pub ${sub_property.ident}: longhands::${sub_property.ident}::SpecifiedValue,
            % endfor
        }

        /// Represents a serializable set of all of the longhand properties that
        /// correspond to a shorthand.
        pub struct LonghandsToSerialize<'a> {
            % for sub_property in shorthand.sub_properties:
                % if sub_property.boxed:
                    pub ${sub_property.ident}:
                        &'a Box<longhands::${sub_property.ident}::SpecifiedValue>,
                % else:
                    pub ${sub_property.ident}:
                        &'a longhands::${sub_property.ident}::SpecifiedValue,
                % endif
            % endfor
        }

        impl<'a> LonghandsToSerialize<'a> {
            /// Tries to get a serializable set of longhands given a set of
            /// property declarations.
            pub fn from_iter<I>(iter: I) -> Result<Self, ()>
                where I: Iterator<Item=&'a PropertyDeclaration>,
            {
                // Define all of the expected variables that correspond to the shorthand
                % for sub_property in shorthand.sub_properties:
                    let mut ${sub_property.ident} = None;
                % endfor

                // Attempt to assign the incoming declarations to the expected variables
                for longhand in iter {
                    match *longhand {
                        % for sub_property in shorthand.sub_properties:
                            PropertyDeclaration::${sub_property.camel_case}(DeclaredValue::Value(ref value)) => {
                                ${sub_property.ident} = Some(value)
                            },
                        % endfor
                        _ => {}
                    };
                }

                // If any of the expected variables are missing, return an error
                match (
                    % for sub_property in shorthand.sub_properties:
                        ${sub_property.ident},<commit_msg>style: Remove unneeded indirection in LonghandsToSerialize.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%! from data import Keyword, to_rust_ident, to_camel_case, LOGICAL_SIDES, PHYSICAL_SIDES, LOGICAL_SIZES %>

<%def name="predefined_type(name, type, initial_value, parse_method='parse',
            needs_context=True, vector=False, initial_specified_value=None, **kwargs)">
    <%def name="predefined_type_inner(name, type, initial_value, parse_method)">
        #[allow(unused_imports)]
        use app_units::Au;
        use cssparser::{Color as CSSParserColor, RGBA};
        pub use values::specified::${type} as SpecifiedValue;
        pub mod computed_value {
            pub use values::computed::${type} as T;
        }
        #[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} }
        % if initial_specified_value:
        #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { ${initial_specified_value} }
        % endif
        #[allow(unused_variables)]
        #[inline] pub fn parse(context: &ParserContext, input: &mut Parser)
                               -> Result<SpecifiedValue, ()> {
            % if needs_context:
            specified::${type}::${parse_method}(context, input)
            % else:
            specified::${type}::${parse_method}(input)
            % endif
        }
    </%def>
    % if vector:
        <%call expr="vector_longhand(name, predefined_type=type, **kwargs)">
            ${predefined_type_inner(name, type, initial_value, parse_method)}
        </%call>
    % else:
        <%call expr="longhand(name, predefined_type=type, **kwargs)">
            ${predefined_type_inner(name, type, initial_value, parse_method)}
        </%call>
    % endif
</%def>

// FIXME (Manishearth): Add computed_value_as_specified argument
// and handle the empty case correctly
<%doc>
    To be used in cases where we have a grammar like
    "<thing> [ , <thing> ]*". `gecko_only` should be set
    to True for cases where Servo takes a single value
    and Stylo supports vector values.

    Setting allow_empty to False allows for cases where the vector
    is empty. The grammar for these is usually "none | <thing> [ , <thing> ]*".
    We assume that the default/initial value is an empty vector for these.
    `initial_value` need not be defined for these.
</%doc>
<%def name="vector_longhand(name, gecko_only=False, allow_empty=False,
            delegate_animate=False, space_separated_allowed=False, **kwargs)">
    <%call expr="longhand(name, **kwargs)">
        % if not gecko_only:
            use std::fmt;
            use values::HasViewportPercentage;
            use style_traits::ToCss;

            impl HasViewportPercentage for SpecifiedValue {
                fn has_viewport_percentage(&self) -> bool {
                    let &SpecifiedValue(ref vec) = self;
                    vec.iter().any(|ref x| x.has_viewport_percentage())
                }
            }

            pub mod single_value {
                use cssparser::Parser;
                use parser::{Parse, ParserContext, ParserContextExtraData};
                use properties::{DeclaredValue, ShorthandId};
                use values::computed::{Context, ToComputedValue};
                use values::{computed, specified};
                use values::{Auto, Either, None_, Normal};
                ${caller.body()}
            }

            /// The definition of the computed value for ${name}.
            pub mod computed_value {
                pub use super::single_value::computed_value as single_value;
                pub use self::single_value::T as SingleComputedValue;
                /// The computed value, effectively a list of single values.
                #[derive(Debug, Clone, PartialEq)]
                #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
                pub struct T(pub Vec<single_value::T>);

                % if delegate_animate:
                    use properties::animated_properties::Interpolate;
                    impl Interpolate for T {
                        fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
                            self.0.interpolate(&other.0, progress).map(T)
                        }
                    }
                % endif
            }

            impl ToCss for computed_value::T {
                fn to_css<W>(&self, dest: &mut W) -> fmt::Result
                    where W: fmt::Write,
                {
                    let mut iter = self.0.iter();
                    if let Some(val) = iter.next() {
                        try!(val.to_css(dest));
                    } else {
                        % if allow_empty:
                            try!(dest.write_str("none"));
                        % else:
                            warn!("Found empty value for property ${name}");
                        % endif
                    }
                    for i in iter {
                        try!(dest.write_str(", "));
                        try!(i.to_css(dest));
                    }
                    Ok(())
                }
            }

            /// The specified value of ${name}.
            #[derive(Debug, Clone, PartialEq)]
            #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
            pub struct SpecifiedValue(pub Vec<single_value::SpecifiedValue>);

            impl ToCss for SpecifiedValue {
                fn to_css<W>(&self, dest: &mut W) -> fmt::Result
                    where W: fmt::Write,
                {
                    let mut iter = self.0.iter();
                    if let Some(val) = iter.next() {
                        try!(val.to_css(dest));
                    } else {
                        % if allow_empty:
                            try!(dest.write_str("none"));
                        % else:
                            warn!("Found empty value for property ${name}");
                        % endif
                    }
                    for i in iter {
                        try!(dest.write_str(", "));
                        try!(i.to_css(dest));
                    }
                    Ok(())
                }
            }

            pub fn get_initial_value() -> computed_value::T {
                % if allow_empty:
                    computed_value::T(vec![])
                % else:
                    computed_value::T(vec![single_value::get_initial_value()])
                % endif
            }

            pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
                use parser::parse_space_or_comma_separated;

                <%
                    parse_func = "Parser::parse_comma_separated"
                    if space_separated_allowed:
                        parse_func = "parse_space_or_comma_separated"
                %>
                % if allow_empty:
                    if input.try(|input| input.expect_ident_matching("none")).is_ok() {
                        Ok(SpecifiedValue(Vec::new()))
                    } else {
                        ${parse_func}(input, |parser| {
                            single_value::parse(context, parser)
                        }).map(SpecifiedValue)
                    }
                % else:
                    ${parse_func}(input, |parser| {
                        single_value::parse(context, parser)
                    }).map(SpecifiedValue)
                % endif
            }

            pub use self::single_value::SpecifiedValue as SingleSpecifiedValue;

            impl ToComputedValue for SpecifiedValue {
                type ComputedValue = computed_value::T;

                #[inline]
                fn to_computed_value(&self, context: &Context) -> computed_value::T {
                    computed_value::T(self.0.iter().map(|x| x.to_computed_value(context)).collect())
                }
                #[inline]
                fn from_computed_value(computed: &computed_value::T) -> Self {
                    SpecifiedValue(computed.0.iter()
                                       .map(|x| ToComputedValue::from_computed_value(x))
                                       .collect())
                }
            }
        % else:
            ${caller.body()}
        % endif
    </%call>
</%def>

<%def name="longhand(*args, **kwargs)">
    <%
        property = data.declare_longhand(*args, **kwargs)
        if property is None:
            return ""
    %>
    /// ${property.spec}
    pub mod ${property.ident} {
        #![allow(unused_imports)]
        % if not property.derived_from:
            use cssparser::Parser;
            use parser::{Parse, ParserContext, ParserContextExtraData};
            use properties::{DeclaredValue, UnparsedValue, ShorthandId};
        % endif
        use values::{Auto, Either, None_, Normal};
        use cascade_info::CascadeInfo;
        use error_reporting::ParseErrorReporter;
        use properties::longhands;
        use properties::LonghandIdSet;
        use properties::{CSSWideKeyword, ComputedValues, PropertyDeclaration};
        use properties::style_structs;
        use std::boxed::Box as StdBox;
        use std::collections::HashMap;
        use std::sync::Arc;
        use values::computed::{Context, ToComputedValue};
        use values::{computed, specified};
        use Atom;
        ${caller.body()}
        #[allow(unused_variables)]
        pub fn cascade_property(declaration: &PropertyDeclaration,
                                inherited_style: &ComputedValues,
                                default_style: &Arc<ComputedValues>,
                                context: &mut computed::Context,
                                cacheable: &mut bool,
                                cascade_info: &mut Option<<&mut CascadeInfo>,
                                error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
            let declared_value = match *declaration {
                PropertyDeclaration::${property.camel_case}(ref declared_value) => {
                    declared_value
                }
                _ => panic!("entered the wrong cascade_property() implementation"),
            };

            % if not property.derived_from:
                {
                    let custom_props = context.style().custom_properties();
                    ::properties::substitute_variables_${property.ident}(
                        declared_value, &custom_props,
                    |value| {
                        if let Some(ref mut cascade_info) = *cascade_info {
                            cascade_info.on_cascade_property(&declaration,
                                                             &value);
                        }
                        % if property.logical:
                            let wm = context.style.writing_mode;
                        % endif
                        <% maybe_wm = ", wm" if property.logical else "" %>
                        match *value {
                            DeclaredValue::Value(ref specified_value) => {
                                let computed = specified_value.to_computed_value(context);
                                % if property.has_uncacheable_values:
                                context.mutate_style().mutate_${data.current_style_struct.name_lower}()
                                                      .set_${property.ident}(computed, cacheable ${maybe_wm});
                                % else:
                                context.mutate_style().mutate_${data.current_style_struct.name_lower}()
                                                      .set_${property.ident}(computed ${maybe_wm});
                                % endif
                            }
                            DeclaredValue::WithVariables(_) => unreachable!(),
                            DeclaredValue::CSSWideKeyword(keyword) => match keyword {
                                % if not data.current_style_struct.inherited:
                                CSSWideKeyword::Unset |
                                % endif
                                CSSWideKeyword::Initial => {
                                    // We assume that it's faster to use copy_*_from rather than
                                    // set_*(get_initial_value());
                                    let initial_struct = default_style
                                                        .get_${data.current_style_struct.name_lower}();
                                    context.mutate_style().mutate_${data.current_style_struct.name_lower}()
                                                        .copy_${property.ident}_from(initial_struct ${maybe_wm});
                                },
                                % if data.current_style_struct.inherited:
                                CSSWideKeyword::Unset |
                                % endif
                                CSSWideKeyword::Inherit => {
                                    // This is a bit slow, but this is rare so it shouldn't
                                    // matter.
                                    //
                                    // FIXME: is it still?
                                    *cacheable = false;
                                    let inherited_struct =
                                        inherited_style.get_${data.current_style_struct.name_lower}();
                                    context.mutate_style().mutate_${data.current_style_struct.name_lower}()
                                        .copy_${property.ident}_from(inherited_struct ${maybe_wm});
                                }
                            }
                        }
                    }, error_reporter);
                }

                % if property.custom_cascade:
                    cascade_property_custom(declaration,
                                            inherited_style,
                                            context,
                                            cacheable,
                                            error_reporter);
                % endif
            % else:
                // Do not allow stylesheets to set derived properties.
            % endif
        }
        % if not property.derived_from:
            pub fn parse_specified(context: &ParserContext, input: &mut Parser)
                % if property.boxed:
                                   -> Result<DeclaredValue<Box<SpecifiedValue>>, ()> {
                    parse(context, input).map(|result| DeclaredValue::Value(Box::new(result)))
                % else:
                                   -> Result<DeclaredValue<SpecifiedValue>, ()> {
                    parse(context, input).map(DeclaredValue::Value)
                % endif
            }
            pub fn parse_declared(context: &ParserContext, input: &mut Parser)
                               % if property.boxed:
                                   -> Result<DeclaredValue<Box<SpecifiedValue>>, ()> {
                               % else:
                                   -> Result<DeclaredValue<SpecifiedValue>, ()> {
                               % endif
                match input.try(|i| CSSWideKeyword::parse(context, i)) {
                    Ok(keyword) => Ok(DeclaredValue::CSSWideKeyword(keyword)),
                    Err(()) => {
                        input.look_for_var_functions();
                        let start = input.position();
                        let specified = parse_specified(context, input);
                        if specified.is_err() {
                            while let Ok(_) = input.next() {}  // Look for var() after the error.
                        }
                        let var = input.seen_var_functions();
                        if specified.is_err() && var {
                            input.reset(start);
                            let (first_token_type, css) = try!(
                                ::custom_properties::parse_non_custom_with_var(input));
                            return Ok(DeclaredValue::WithVariables(Box::new(UnparsedValue {
                                css: css.into_owned(),
                                first_token_type: first_token_type,
                                base_url: context.base_url.clone(),
                                from_shorthand: None,
                            })))
                        }
                        specified
                    }
                }
            }
        % endif
    }
</%def>

<%def name="single_keyword(name, values, vector=False, **kwargs)">
    <%call expr="single_keyword_computed(name, values, vector, **kwargs)">
        use values::computed::ComputedValueAsSpecified;
        use values::HasViewportPercentage;
        impl ComputedValueAsSpecified for SpecifiedValue {}
        no_viewport_percentage!(SpecifiedValue);
    </%call>
</%def>

<%def name="gecko_keyword_conversion(keyword, values=None, type='SpecifiedValue')">
    <%
        if not values:
            values = keyword.values_for(product)
    %>
    #[cfg(feature = "gecko")]
    impl ${type} {
        /// Obtain a specified value from a Gecko keyword value
        ///
        /// Intended for use with presentation attributes, not style structs
        pub fn from_gecko_keyword(kw: u32) -> Self {
            use gecko_bindings::structs;
            % if keyword.gecko_enum_prefix:
                % for value in values:
                    // We can't match on enum values if we're matching on a u32
                    const ${to_rust_ident(value).upper()}: u32
                        = structs::${keyword.gecko_enum_prefix}::${to_camel_case(value)} as u32;
                % endfor
                match kw {
                    % for value in values:
                        ${to_rust_ident(value).upper()} => ${type}::${to_rust_ident(value)},
                    % endfor
                    x => panic!("Found unexpected value in style struct for ${keyword.name} property: {:?}", x),
                }
            % else:
                match kw {
                    % for value in values:
                        structs::${keyword.gecko_constant(value)} => ${type}::${to_rust_ident(value)},
                    % endfor
                    x => panic!("Found unexpected value in style struct for ${keyword.name} property: {:?}", x),
                }
            % endif
        }
    }
</%def>

<%def name="single_keyword_computed(name, values, vector=False,
            extra_specified=None, needs_conversion=False, **kwargs)">
    <%
        keyword_kwargs = {a: kwargs.pop(a, None) for a in [
            'gecko_constant_prefix', 'gecko_enum_prefix',
            'extra_gecko_values', 'extra_servo_values',
            'custom_consts', 'gecko_inexhaustive',
        ]}
    %>

    <%def name="inner_body(keyword, extra_specified=None, needs_conversion=False)">
        % if extra_specified:
            use style_traits::ToCss;
            define_css_keyword_enum! { SpecifiedValue:
                % for value in keyword.values_for(product) + extra_specified.split():
                    "${value}" => ${to_rust_ident(value)},
                % endfor
            }
        % else:
            pub use self::computed_value::T as SpecifiedValue;
        % endif
        pub mod computed_value {
            use style_traits::ToCss;
            define_css_keyword_enum! { T:
                % for value in data.longhands_by_name[name].keyword.values_for(product):
                    "${value}" => ${to_rust_ident(value)},
                % endfor
            }
        }
        #[inline]
        pub fn get_initial_value() -> computed_value::T {
            computed_value::T::${to_rust_ident(values.split()[0])}
        }
        #[inline]
        pub fn get_initial_specified_value() -> SpecifiedValue {
            SpecifiedValue::${to_rust_ident(values.split()[0])}
        }
        #[inline]
        pub fn parse(_context: &ParserContext, input: &mut Parser)
                     -> Result<SpecifiedValue, ()> {
            SpecifiedValue::parse(input)
        }
        impl Parse for SpecifiedValue {
            #[inline]
            fn parse(_context: &ParserContext, input: &mut Parser)
                         -> Result<SpecifiedValue, ()> {
                SpecifiedValue::parse(input)
            }
        }

        % if needs_conversion:
            <%
                conversion_values = keyword.values_for(product)
                if extra_specified:
                    conversion_values += extra_specified.split()
            %>
            ${gecko_keyword_conversion(keyword, values=conversion_values)}
        % endif
    </%def>
    % if vector:
        <%call expr="vector_longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
            ${inner_body(Keyword(name, values, **keyword_kwargs))}
            ${caller.body()}
        </%call>
    % else:
        <%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)">
            ${inner_body(Keyword(name, values, **keyword_kwargs),
                         extra_specified=extra_specified, needs_conversion=needs_conversion)}
            ${caller.body()}
        </%call>
    % endif
</%def>

<%def name="shorthand(name, sub_properties, experimental=False, **kwargs)">
<%
    shorthand = data.declare_shorthand(name, sub_properties.split(), experimental=experimental,
                                       **kwargs)
%>
    % if shorthand:
    /// ${shorthand.spec}
    pub mod ${shorthand.ident} {
        #[allow(unused_imports)]
        use cssparser::Parser;
        use parser::ParserContext;
        use properties::{DeclaredValue, PropertyDeclaration};
        use properties::{ShorthandId, UnparsedValue, longhands};
        use properties::declaration_block::Importance;
        use std::fmt;
        use style_traits::ToCss;

        pub struct Longhands {
            % for sub_property in shorthand.sub_properties:
                pub ${sub_property.ident}: longhands::${sub_property.ident}::SpecifiedValue,
            % endfor
        }

        /// Represents a serializable set of all of the longhand properties that
        /// correspond to a shorthand.
        pub struct LonghandsToSerialize<'a> {
            % for sub_property in shorthand.sub_properties:
                pub ${sub_property.ident}:
                    &'a longhands::${sub_property.ident}::SpecifiedValue,
            % endfor
        }

        impl<'a> LonghandsToSerialize<'a> {
            /// Tries to get a serializable set of longhands given a set of
            /// property declarations.
            pub fn from_iter<I>(iter: I) -> Result<Self, ()>
                where I: Iterator<Item=&'a PropertyDeclaration>,
            {
                // Define all of the expected variables that correspond to the shorthand
                % for sub_property in shorthand.sub_properties:
                    let mut ${sub_property.ident} = None;
                % endfor

                // Attempt to assign the incoming declarations to the expected variables
                for longhand in iter {
                    match *longhand {
                        % for sub_property in shorthand.sub_properties:
                            PropertyDeclaration::${sub_property.camel_case}(DeclaredValue::Value(ref value)) => {
                                ${sub_property.ident} = Some(value)
                            },
                        % endfor
                        _ => {}
                    };
                }

                // If any of the expected variables are missing, return an error
                match (
                    % for sub_property in shorthand.sub_properties:
                        ${sub_property.ident},
{'fraction_non_alphanumeric': 0.10185702751381902, 'fraction_numerical': 0.0009109165062211457, 'mean_word_length': 1.3744777073194712, 'pattern_counts': {'":': 0, '<': 148, '<?xml version=': 0, '>': 222, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 102, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4430205', 'n_tokens_mistral': 12353, 'n_tokens_neox': 11650, 'n_words': 2500}