mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
style: Support keywords [x|y|z] on rotate.
Update the parser and the serialization to support the keywords, [x|y|z]. Differential Revision: https://phabricator.services.mozilla.com/D11531
This commit is contained in:
parent
f486ef7e47
commit
41d2f7f3a2
4 changed files with 85 additions and 8 deletions
|
@ -8,6 +8,7 @@ use super::animated::ToAnimatedValue;
|
||||||
use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
|
use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
|
||||||
use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
|
use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
|
||||||
use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize};
|
use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize};
|
||||||
|
use super::generics::transform::IsParallelTo;
|
||||||
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
|
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
|
||||||
use super::specified;
|
use super::specified;
|
||||||
use super::{CSSFloat, CSSInteger};
|
use super::{CSSFloat, CSSInteger};
|
||||||
|
@ -22,6 +23,7 @@ use crate::Atom;
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
use crate::Prefix;
|
use crate::Prefix;
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
|
use self::transform::DirectionVector;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
@ -459,6 +461,16 @@ trivial_to_computed_value!(Box<str>);
|
||||||
/// A `<number>` value.
|
/// A `<number>` value.
|
||||||
pub type Number = CSSFloat;
|
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.
|
/// A wrapper of Number, but the value >= 0.
|
||||||
pub type NonNegativeNumber = NonNegative<CSSFloat>;
|
pub type NonNegativeNumber = NonNegative<CSSFloat>;
|
||||||
|
|
||||||
|
|
|
@ -538,7 +538,6 @@ pub fn get_normalized_vector_and_angle<T: Zero>(
|
||||||
SpecifiedValueInfo,
|
SpecifiedValueInfo,
|
||||||
ToAnimatedZero,
|
ToAnimatedZero,
|
||||||
ToComputedValue,
|
ToComputedValue,
|
||||||
ToCss,
|
|
||||||
)]
|
)]
|
||||||
/// A value of the `Rotate` property
|
/// A value of the `Rotate` property
|
||||||
///
|
///
|
||||||
|
@ -552,6 +551,53 @@ pub enum Rotate<Number, Angle> {
|
||||||
Rotate3D(Number, Number, 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(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
ComputeSquaredDistance,
|
ComputeSquaredDistance,
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
//!
|
//!
|
||||||
//! TODO(emilio): Enhance docs.
|
//! TODO(emilio): Enhance docs.
|
||||||
|
|
||||||
|
use super::computed::transform::DirectionVector;
|
||||||
use super::computed::{Context, ToComputedValue};
|
use super::computed::{Context, ToComputedValue};
|
||||||
use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
|
use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
|
||||||
use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize};
|
use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize};
|
||||||
|
use super::generics::transform::IsParallelTo;
|
||||||
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
|
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
|
||||||
use super::{Auto, CSSFloat, CSSInteger, Either};
|
use super::{Auto, CSSFloat, CSSInteger, Either};
|
||||||
use crate::context::QuirksMode;
|
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 SpecifiedValueInfo for Number {}
|
||||||
|
|
||||||
impl From<Number> for f32 {
|
impl From<Number> for f32 {
|
||||||
|
|
|
@ -358,17 +358,24 @@ impl Parse for Rotate {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse <angle> or [ x | y | z | <number>{3} ] && <angle>.
|
// 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
|
// 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}`
|
// two cases. i.e. `<number>{3} <angle>` or `<angle> <number>{3}`
|
||||||
let angle = input.try(|i| specified::Angle::parse(context, i)).ok();
|
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((
|
Ok((
|
||||||
Number::parse(context, i)?,
|
Number::parse(context, i)?,
|
||||||
Number::parse(context, i)?,
|
Number::parse(context, i)?,
|
||||||
Number::parse(context, i)?,
|
Number::parse(context, i)?,
|
||||||
))
|
))
|
||||||
|
})
|
||||||
}).ok();
|
}).ok();
|
||||||
let angle = match angle {
|
let angle = match angle {
|
||||||
Some(a) => a,
|
Some(a) => a,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue