servo/components/style/properties/longhand/inherited_table.mako.rs
author Jeremy Chen <jeremychen@mozilla.com>
Wed, 26 Apr 2017 20:46:34 +0800
changeset 568663 a6232f0377c8878e56efec141b6ac809b497b5cf
parent 567399 0719b45506e682b1ae3f2d19aa595e785e416516
child 570040 bb059c15dd418217004416baccc77a8c55d32729
permissions -rw-r--r--
Bug 1354437 - stylo: Make border-spacing animatable. Two things are included in this patch: 1. Implement ComputeDistance for border-spacing, so we could get the right distance while doing animations. 2. Implement clone function for gecko glue code of border-spacing, so we could make animations of border-spacing work properly in stylo build. MozReview-Commit-ID: CPfpDNrOSyt

/* 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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("InheritedTable", inherited=True, gecko_name="TableBorder") %>

${helpers.single_keyword("border-collapse", "separate collapse",
                         gecko_constant_prefix="NS_STYLE_BORDER",
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-tables/#propdef-border-collapse")}
${helpers.single_keyword("empty-cells", "show hide",
                         gecko_constant_prefix="NS_STYLE_TABLE_EMPTY_CELLS",
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-tables/#propdef-empty-cells")}
${helpers.single_keyword("caption-side", "top bottom",
                         extra_gecko_values="right left top-outside bottom-outside",
                         needs_conversion="True",
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-tables/#propdef-caption-side")}

<%helpers:longhand name="border-spacing" animation_value_type="ComputedValue" boxed="True"
                   spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing">
    use app_units::Au;
    use std::fmt;
    use style_traits::ToCss;
    use values::HasViewportPercentage;

    pub mod computed_value {
        use app_units::Au;
        use properties::animated_properties::{ComputeDistance, Interpolate};

        #[derive(Clone, Copy, Debug, PartialEq)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub struct T {
            pub horizontal: Au,
            pub vertical: Au,
        }

        /// https://drafts.csswg.org/css-transitions/#animtype-simple-list
        impl Interpolate for T {
            #[inline]
            fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
                Ok(T {
                    horizontal: try!(self.horizontal.interpolate(&other.horizontal, time)),
                    vertical: try!(self.vertical.interpolate(&other.vertical, time)),
                })
            }
        }

        impl ComputeDistance for T {
            #[inline]
            fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
                self.compute_squared_distance(other).map(|sd| sd.sqrt())
            }

            #[inline]
            fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
                Ok(try!(self.horizontal.compute_squared_distance(&other.horizontal)) +
                   try!(self.vertical.compute_squared_distance(&other.vertical)))
            }
        }
    }

    impl HasViewportPercentage for SpecifiedValue {
        fn has_viewport_percentage(&self) -> bool {
            self.horizontal.has_viewport_percentage() ||
            self.vertical.as_ref().map_or(false, |v| v.has_viewport_percentage())
        }
    }

    #[derive(Clone, Debug, PartialEq)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    pub struct SpecifiedValue {
        pub horizontal: specified::Length,
        pub vertical: Option<specified::Length>,
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T {
            horizontal: Au(0),
            vertical: Au(0),
        }
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result
            where W: fmt::Write,
        {
            try!(self.horizontal.to_css(dest));
            if let Some(vertical) = self.vertical.as_ref() {
                try!(dest.write_str(" "));
                vertical.to_css(dest)?;
            }
            Ok(())
        }
    }

    impl ToCss for computed_value::T {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.horizontal.to_css(dest));
            try!(dest.write_str(" "));
            self.vertical.to_css(dest)
        }
    }

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

        #[inline]
        fn to_computed_value(&self, context: &Context) -> computed_value::T {
            let horizontal = self.horizontal.to_computed_value(context);
            computed_value::T {
                horizontal: horizontal,
                vertical: self.vertical.as_ref().map_or(horizontal, |v| v.to_computed_value(context)),
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> Self {
            SpecifiedValue {
                horizontal: ToComputedValue::from_computed_value(&computed.horizontal),
                vertical: Some(ToComputedValue::from_computed_value(&computed.vertical)),
            }
        }
    }

    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
        let mut first = None;
        let mut second = None;
        match specified::Length::parse_non_negative(context, input) {
            Err(()) => (),
            Ok(length) => {
                first = Some(length);
                if let Ok(len) = input.try(|input| specified::Length::parse_non_negative(context, input)) {
                    second = Some(len);
                }
            }
        }
        match (first, second) {
            (None, None) => Err(()),
            (Some(length), None) => {
                Ok(SpecifiedValue {
                    horizontal: length,
                    vertical: None,
                })
            }
            (Some(horizontal), Some(vertical)) => {
                Ok(SpecifiedValue {
                    horizontal: horizontal,
                    vertical: Some(vertical),
                })
            }
            (None, Some(_)) => unreachable!(),
        }
    }
</%helpers:longhand>