Commit 94b54b2b authored by Boris Chiou's avatar Boris Chiou
Browse files

Bug 1504327 - Support keywords [x|y|z] on rotate. r=emilio

Update the parser and the serialization to support the keywords, [x|y|z].

Differential Revision: https://phabricator.services.mozilla.com/D11531

--HG--
extra : moz-landing-system : lando
parent d7917233
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -6359,13 +6359,17 @@ if (IsCSSPropertyPrefEnabled("layout.css.individual-transform.enabled")) {
    type: CSS_TYPE_LONGHAND,
    initial_values: [ "none" ],
    other_values: [ "45deg", "45grad", "72rad", "0.25turn", ".57rad",
                    "0 0 0 0rad", "0 0 1 45deg", "0 0 1 0rad", "0rad 0 0 1",
                    "0 0 0 0rad", "0 0 1 45deg", "0 0 1 0rad",
                    "0rad 0 0 1", "10rad 10 20 30",
                    "x 10rad", "y 10rad", "z 10rad",
                    "10rad x", "10rad y", "10rad z",
                    /* valid calc() values */
                    "calc(1) 0 0 calc(45deg + 5rad)",
                    "0 1 0 calc(400grad + 1rad)",
                    "calc(0.5turn + 10deg)"],
    invalid_values: [ "0", "7", "0, 0, 1, 45deg", "0 0 45deg", "0 0 20rad",
                      "0 0 0 0",
                      "0 0 0 0", "x x 10rad", "x y 10rad", "0 0 1 10rad z",
                      "0 0 1 z 10rad", "z 0 0 1 10rad", "0 0 z 1 10rad",
                      /* invalid calc() values */
                      "0.5 1 0 calc(45deg + 10)", "calc(0.5turn + 10%)"],
  };
+12 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ use super::animated::ToAnimatedValue;
use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize};
use super::generics::transform::IsParallelTo;
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
use super::specified;
use super::{CSSFloat, CSSInteger};
@@ -22,6 +23,7 @@ use crate::Atom;
#[cfg(feature = "servo")]
use crate::Prefix;
use euclid::Size2D;
use self::transform::DirectionVector;
use std::cell::RefCell;
use std::cmp;
use std::f32;
@@ -459,6 +461,16 @@ trivial_to_computed_value!(Box<str>);
/// A `<number>` value.
pub type Number = CSSFloat;

impl IsParallelTo for (Number, Number, Number) {
    fn is_parallel_to(&self, vector: &DirectionVector) -> bool {
        use euclid::approxeq::ApproxEq;
        // If a and b is parallel, the angle between them is 0deg, so
        // a x b = |a|*|b|*sin(0)*n = 0 * n, |a x b| == 0.
        let self_vector = DirectionVector::new(self.0, self.1, self.2);
        self_vector.cross(*vector).square_length().approx_eq(&0.0f32)
    }
}

/// A wrapper of Number, but the value >= 0.
pub type NonNegativeNumber = NonNegative<CSSFloat>;

+47 −1
Original line number Diff line number Diff line
@@ -538,7 +538,6 @@ pub fn get_normalized_vector_and_angle<T: Zero>(
    SpecifiedValueInfo,
    ToAnimatedZero,
    ToComputedValue,
    ToCss,
)]
/// A value of the `Rotate` property
///
@@ -552,6 +551,53 @@ pub enum Rotate<Number, Angle> {
    Rotate3D(Number, Number, Number, Angle),
}

/// A trait to check if the current 3D vector is parallel to the DirectionVector.
/// This is especially for serialization on Rotate.
pub trait IsParallelTo {
    /// Returns true if this is parallel to the vector.
    fn is_parallel_to(&self, vector: &computed::transform::DirectionVector) -> bool;
}

impl<Number, Angle> ToCss for Rotate<Number, Angle>
where
    Number: Copy + ToCss,
    Angle: ToCss,
    (Number, Number, Number): IsParallelTo,
{
    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    where
        W: fmt::Write,
    {
        use crate::values::computed::transform::DirectionVector;
        match *self {
            Rotate::None => dest.write_str("none"),
            Rotate::Rotate(ref angle) => angle.to_css(dest),
            Rotate::Rotate3D(x, y, z, ref angle) => {
                // If a 3d rotation is specified, the property must serialize with an axis
                // specified. If the axis is parallel with the x, y, or z axises, it must
                // serialize as the appropriate keyword.
                // https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization
                let v = (x, y, z);
                if v.is_parallel_to(&DirectionVector::new(1., 0., 0.)) {
                    dest.write_char('x')?;
                } else if v.is_parallel_to(&DirectionVector::new(0., 1., 0.)) {
                    dest.write_char('y')?;
                } else if v.is_parallel_to(&DirectionVector::new(0., 0., 1.)) {
                    dest.write_char('z')?;
                } else {
                    x.to_css(dest)?;
                    dest.write_char(' ')?;
                    y.to_css(dest)?;
                    dest.write_char(' ')?;
                    z.to_css(dest)?;
                }
                dest.write_char(' ')?;
                angle.to_css(dest)
            },
        }
    }
}

#[derive(
    Clone,
    ComputeSquaredDistance,
+12 −0
Original line number Diff line number Diff line
@@ -6,9 +6,11 @@
//!
//! TODO(emilio): Enhance docs.

use super::computed::transform::DirectionVector;
use super::computed::{Context, ToComputedValue};
use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize};
use super::generics::transform::IsParallelTo;
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
use super::{Auto, CSSFloat, CSSInteger, Either};
use crate::context::QuirksMode;
@@ -292,6 +294,16 @@ impl ToCss for Number {
    }
}

impl IsParallelTo for (Number, Number, Number) {
    fn is_parallel_to(&self, vector: &DirectionVector) -> bool {
        use euclid::approxeq::ApproxEq;
        // If a and b is parallel, the angle between them is 0deg, so
        // a x b = |a|*|b|*sin(0)*n = 0 * n, |a x b| == 0.
        let self_vector = DirectionVector::new(self.0.get(), self.1.get(), self.2.get());
        self_vector.cross(*vector).square_length().approx_eq(&0.0f32)
    }
}

impl SpecifiedValueInfo for Number {}

impl From<Number> for f32 {
+14 −7
Original line number Diff line number Diff line
@@ -358,17 +358,24 @@ impl Parse for Rotate {
        }

        // Parse <angle> or [ x | y | z | <number>{3} ] && <angle>.
        // TODO: Bug 1504327: Parse [x|y|z] keywords.
        //
        // The rotate axis and angle could be in any order, so we parse angle twice to cover
        // two cases. i.e. `<number>{3} <angle>` or `<angle> <number>{3}`
        let angle = input.try(|i| specified::Angle::parse(context, i)).ok();
        let axis = input.try(|i| -> Result<_, ParseError> {
        let axis = input.try(|i| {
            Ok(try_match_ident_ignore_ascii_case! { i,
                "x" => (Number::new(1.), Number::new(0.), Number::new(0.)),
                "y" => (Number::new(0.), Number::new(1.), Number::new(0.)),
                "z" => (Number::new(0.), Number::new(0.), Number::new(1.)),
            })
        }).or_else(|_: ParseError| -> Result<_, ParseError> {
            input.try(|i| {
                Ok((
                    Number::parse(context, i)?,
                    Number::parse(context, i)?,
                    Number::parse(context, i)?,
                ))
            })
        }).ok();
        let angle = match angle {
            Some(a) => a,
Loading