Skip to content

Commit

Permalink
servo: Merge #16242 - Implement serialization for transform functions…
Browse files Browse the repository at this point in the history
… (from pyfisch:transform-one); r=emilio

Preserve more information from transform function parsing.
Preserve angle unit while parsing.
Simplify SpecifiedMatrix.
Use the write! macro for formatting with a helper called Css.
Implement ToCss for &T if T implements ToCss.
Add some tests and update others.

closes #15194

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #15194 (github issue number if applicable).

<!-- Either: -->
- [X] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

Source-Repo: https://github.com/servo/servo
Source-Revision: 8747c4e04cdecf79ccf6a3279679f04ad07a6a42

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 3f4383631e4ad912c786e0f028139a8c326c3101
  • Loading branch information
pyfisch committed Apr 4, 2017
1 parent 9280fcd commit aa47b66
Show file tree
Hide file tree
Showing 7 changed files with 459 additions and 289 deletions.
568 changes: 316 additions & 252 deletions servo/components/style/properties/longhand/box.mako.rs

Large diffs are not rendered by default.

105 changes: 73 additions & 32 deletions servo/components/style/values/specified/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,20 +310,48 @@ impl ToCss for BorderRadiusSize {
}
}

#[derive(Clone, PartialEq, PartialOrd, Copy, Debug)]
#[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
/// An angle, normalized to radians.
/// An angle consisting of a value and a unit.
pub struct Angle {
radians: CSSFloat,
value: CSSFloat,
unit: AngleUnit,
was_calc: bool,
}

#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
/// A unit used together with an angle.
pub enum AngleUnit {
/// Degrees, short name "deg".
Degree,
/// Gradians, short name "grad".
Gradian,
/// Radians, short name "rad".
Radian,
/// Turns, short name "turn".
Turn,
}

impl ToCss for AngleUnit {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
use self::AngleUnit::*;
dest.write_str(match *self {
Degree => "deg",
Gradian => "grad",
Radian => "rad",
Turn => "turn",
})
}
}

impl ToCss for Angle {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
if self.was_calc {
dest.write_str("calc(")?;
}
write!(dest, "{}rad", self.radians)?;
self.value.to_css(dest)?;
self.unit.to_css(dest)?;
if self.was_calc {
dest.write_str(")")?;
}
Expand All @@ -339,47 +367,61 @@ impl ToComputedValue for Angle {
}

fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Angle {
radians: computed.radians(),
was_calc: false,
}
Angle::from_radians(computed.radians())
}
}

impl Angle {
/// Returns an angle with the given value in degrees.
pub fn from_degrees(value: CSSFloat) -> Self {
Angle { value: value, unit: AngleUnit::Degree, was_calc: false }
}
/// Returns an angle with the given value in gradians.
pub fn from_gradians(value: CSSFloat) -> Self {
Angle { value: value, unit: AngleUnit::Gradian, was_calc: false }
}
/// Returns an angle with the given value in turns.
pub fn from_turns(value: CSSFloat) -> Self {
Angle { value: value, unit: AngleUnit::Turn, was_calc: false }
}
/// Returns an angle with the given value in radians.
pub fn from_radians(value: CSSFloat) -> Self {
Angle { value: value, unit: AngleUnit::Radian, was_calc: false }
}

#[inline]
#[allow(missing_docs)]
pub fn radians(self) -> f32 {
self.radians
}
use self::AngleUnit::*;

/// Returns an angle value that represents zero radians.
pub fn zero() -> Self {
Self::from_radians(0.0)
const RAD_PER_DEG: CSSFloat = PI / 180.0;
const RAD_PER_GRAD: CSSFloat = PI / 200.0;
const RAD_PER_TURN: CSSFloat = PI * 2.0;

let radians = match self.unit {
Degree => self.value * RAD_PER_DEG,
Gradian => self.value * RAD_PER_GRAD,
Turn => self.value * RAD_PER_TURN,
Radian => self.value,
};
radians.min(f32::MAX).max(f32::MIN)
}

#[inline]
#[allow(missing_docs)]
pub fn from_radians(r: f32) -> Self {
Angle {
radians: r.min(f32::MAX).max(f32::MIN),
was_calc: false,
}
/// Returns an angle value that represents zero.
pub fn zero() -> Self {
Self::from_degrees(0.0)
}

/// Returns an `Angle` parsed from a `calc()` expression.
pub fn from_calc(radians: CSSFloat) -> Self {
Angle {
radians: radians.min(f32::MAX).max(f32::MIN),
value: radians,
unit: AngleUnit::Radian,
was_calc: true,
}
}
}

const RAD_PER_DEG: CSSFloat = PI / 180.0;
const RAD_PER_GRAD: CSSFloat = PI / 200.0;
const RAD_PER_TURN: CSSFloat = PI * 2.0;

impl Parse for Angle {
/// Parses an angle according to CSS-VALUES § 6.1.
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Expand All @@ -397,15 +439,14 @@ impl Parse for Angle {
impl Angle {
#[allow(missing_docs)]
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle, ()> {
let radians = match_ignore_ascii_case! { unit,
"deg" => value * RAD_PER_DEG,
"grad" => value * RAD_PER_GRAD,
"turn" => value * RAD_PER_TURN,
"rad" => value,
let angle = match_ignore_ascii_case! { unit,
"deg" => Angle::from_degrees(value),
"grad" => Angle::from_gradians(value),
"turn" => Angle::from_turns(value),
"rad" => Angle::from_radians(value),
_ => return Err(())
};

Ok(Angle::from_radians(radians))
Ok(angle)
}
}

Expand Down
17 changes: 17 additions & 0 deletions servo/components/style_traits/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ pub trait ToCss {
}
}

impl<'a, T> ToCss for &'a T where T: ToCss + ?Sized {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
(*self).to_css(dest)
}
}

/// Marker trait to automatically implement ToCss for Vec<T>.
pub trait OneOrMoreCommaSeparated {}

Expand Down Expand Up @@ -177,3 +183,14 @@ pub mod specified {
}
}
}


/// Wrap CSS types for serialization with `write!` or `format!` macros.
/// Used by ToCss of SpecifiedOperation.
pub struct Css<T>(pub T);

impl<T: ToCss> fmt::Display for Css<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.to_css(f)
}
}
8 changes: 8 additions & 0 deletions servo/tests/unit/style/parsing/box_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,11 @@ fn test_will_change() {
assert!(parse(will_change::parse, "contents, inherit, initial").is_err());
assert!(parse(will_change::parse, "transform scroll-position").is_err());
}

#[test]
fn test_transform_translate() {
use style::properties::longhands::transform;
assert_roundtrip_with_context!(transform::parse, "translate(2px)");
assert_roundtrip_with_context!(transform::parse, "translate(2px, 5px)");
assert!(parse(transform::parse, "translate(2px foo)").is_err());
}
3 changes: 1 addition & 2 deletions servo/tests/unit/style/parsing/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ fn test_linear_gradient() {
assert_roundtrip_with_context!(Image::parse, "linear-gradient(to right top, red, green)");

// Parsing with <angle>
assert_roundtrip_with_context!(Image::parse, "linear-gradient(45deg, red, green)",
"linear-gradient(0.7853982rad, red, green)");
assert_roundtrip_with_context!(Image::parse, "linear-gradient(45deg, red, green)");

// Parsing with more than two entries in <color-stop-list>
assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, yellow, green)");
Expand Down
5 changes: 2 additions & 3 deletions servo/tests/unit/style/parsing/inherited_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use style::stylesheets::Origin;

#[test]
fn image_orientation_longhand_should_parse_properly() {
use std::f32::consts::PI;
use style::properties::longhands::image_orientation;
use style::properties::longhands::image_orientation::SpecifiedValue;
use style::values::specified::Angle;
Expand All @@ -21,11 +20,11 @@ fn image_orientation_longhand_should_parse_properly() {
assert_eq!(flip, SpecifiedValue { angle: None, flipped: true });

let zero = parse_longhand!(image_orientation, "0deg");
assert_eq!(zero, SpecifiedValue { angle: Some(Angle::from_radians(0.0)), flipped: false });
assert_eq!(zero, SpecifiedValue { angle: Some(Angle::from_degrees(0.0)), flipped: false });

let negative_rad = parse_longhand!(image_orientation, "-1rad");
assert_eq!(negative_rad, SpecifiedValue { angle: Some(Angle::from_radians(-1.0)), flipped: false });

let flip_with_180 = parse_longhand!(image_orientation, "180deg flip");
assert_eq!(flip_with_180, SpecifiedValue { angle: Some(Angle::from_radians(PI)), flipped: true });
assert_eq!(flip_with_180, SpecifiedValue { angle: Some(Angle::from_degrees(180.0)), flipped: true });
}
42 changes: 42 additions & 0 deletions servo/tests/unit/style/properties/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,8 @@ mod shorthand_serialization {

mod transform {
pub use super::*;
use style::properties::longhands::transform::SpecifiedOperation;
use style::values::specified::{Angle, Number};

#[test]
fn should_serialize_none_correctly() {
Expand All @@ -982,6 +984,46 @@ mod shorthand_serialization {
assert_eq!(try_serialize.is_ok(), true);
assert_eq!(s, "none");
}

#[inline(always)]
fn validate_serialization<T: ToCss>(op: &T, expected_string: &'static str) {
let css_string = op.to_css_string();
assert_eq!(css_string, expected_string);
}

#[test]
fn transform_scale() {
validate_serialization(&SpecifiedOperation::Scale(Number::new(1.3), None), "scale(1.3)");
validate_serialization(
&SpecifiedOperation::Scale(Number::new(2.0), Some(Number::new(2.0))),
"scale(2, 2)");
validate_serialization(&SpecifiedOperation::ScaleX(Number::new(42.0)), "scaleX(42)");
validate_serialization(&SpecifiedOperation::ScaleY(Number::new(0.3)), "scaleY(0.3)");
validate_serialization(&SpecifiedOperation::ScaleZ(Number::new(1.0)), "scaleZ(1)");
validate_serialization(
&SpecifiedOperation::Scale3D(Number::new(4.0), Number::new(5.0), Number::new(6.0)),
"scale3d(4, 5, 6)");
}

#[test]
fn transform_skew() {
validate_serialization(
&SpecifiedOperation::Skew(Angle::from_degrees(42.3), None),
"skew(42.3deg)");
validate_serialization(
&SpecifiedOperation::Skew(Angle::from_gradians(-50.0), Some(Angle::from_turns(0.73))),
"skew(-50grad, 0.73turn)");
validate_serialization(
&SpecifiedOperation::SkewX(Angle::from_radians(0.31)), "skewX(0.31rad)");
}

#[test]
fn transform_rotate() {
validate_serialization(
&SpecifiedOperation::Rotate(Angle::from_turns(35.0)),
"rotate(35turn)"
)
}
}

mod quotes {
Expand Down

0 comments on commit aa47b66

Please sign in to comment.