From 5332d4b2659fd0a6186b07b02ee1d3bc9a7432cc Mon Sep 17 00:00:00 2001 From: Jeremy Chen Date: Thu, 6 Apr 2017 16:11:36 +0800 Subject: [PATCH] Stylo - support image-orientation property First, we need to make Servo's image-orientation parser to be agreed with Gecko's. Numbers without any AngleUnit, including unitless 0 angle, should be invalid for image-orientation. However, rotate() and skew() for transform properties accept unitless 0 angle. In order to make all these properties work properly, I fixed Angle::parse() to match Gecko. For the existing users of Angle::parse(), I create Angle::parse_with_unitless() and use it as an alternative for them. Once https://github.com/w3c/csswg-drafts/issues/1162 is resolved, we shall be able to use an unified version of Angle::parse() then. The parser of image-orientation is also fixed to report parsing errors on empty string. Then, with the newly added binding functions support in Gecko side, we shall reuse the same methods from Gecko to pass the computed value from Servo to Gecko. Gecko bug: Bug 1341758 --- components/style/properties/gecko.mako.rs | 29 ++++++++++++++++++- .../style/properties/longhand/box.mako.rs | 19 ++++++------ .../properties/longhand/inherited_box.mako.rs | 20 +++++++------ components/style/values/specified/mod.rs | 17 ++++++++++- tests/unit/style/parsing/inherited_box.rs | 2 +- 5 files changed, 66 insertions(+), 21 deletions(-) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index ff3529bb53b..63f4a5abbfa 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -2776,6 +2776,34 @@ fn static_assert() { } +<%self:impl_trait style_struct_name="InheritedBox" + skip_longhands="image-orientation"> + // FIXME: Gecko uses a tricky way to store computed value of image-orientation + // within an u8. We could inline following glue codes by implementing all + // those tricky parts for Servo as well. But, it's not done yet just for + // convenience. + pub fn set_image_orientation(&mut self, v: longhands::image_orientation::computed_value::T) { + use properties::longhands::image_orientation::computed_value::T; + match v { + T::FromImage => { + unsafe { + bindings::Gecko_SetImageOrientationAsFromImage(&mut self.gecko); + } + }, + T::AngleWithFlipped(ref angle, flipped) => { + unsafe { + bindings::Gecko_SetImageOrientation(&mut self.gecko, angle.radians() as f64, flipped); + } + } + } + } + + pub fn copy_image_orientation_from(&mut self, other: &Self) { + unsafe { + bindings::Gecko_CopyImageOrientationFrom(&mut self.gecko, &other.gecko); + } + } + <%self:impl_trait style_struct_name="InheritedTable" skip_longhands="border-spacing"> @@ -2789,7 +2817,6 @@ fn static_assert() { self.gecko.mBorderSpacingCol = other.gecko.mBorderSpacingCol; self.gecko.mBorderSpacingRow = other.gecko.mBorderSpacingRow; } - diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index a4d78e7f3fc..ffa8c5ebddf 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -1332,6 +1332,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", computed_value::T(None) } + // Allow unitless zero angle for rotate() and skew() to align with gecko pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { if input.try(|input| input.expect_ident_matching("none")).is_ok() { return Ok(SpecifiedValue(Vec::new())) @@ -1469,28 +1470,28 @@ ${helpers.predefined_type("scroll-snap-coordinate", }, "rotate" => { try!(input.parse_nested_block(|input| { - let theta = try!(specified::Angle::parse(context,input)); + let theta = try!(specified::Angle::parse_with_unitless(context,input)); result.push(SpecifiedOperation::Rotate(theta)); Ok(()) })) }, "rotatex" => { try!(input.parse_nested_block(|input| { - let theta = try!(specified::Angle::parse(context,input)); + let theta = try!(specified::Angle::parse_with_unitless(context,input)); result.push(SpecifiedOperation::RotateX(theta)); Ok(()) })) }, "rotatey" => { try!(input.parse_nested_block(|input| { - let theta = try!(specified::Angle::parse(context,input)); + let theta = try!(specified::Angle::parse_with_unitless(context,input)); result.push(SpecifiedOperation::RotateY(theta)); Ok(()) })) }, "rotatez" => { try!(input.parse_nested_block(|input| { - let theta = try!(specified::Angle::parse(context,input)); + let theta = try!(specified::Angle::parse_with_unitless(context,input)); result.push(SpecifiedOperation::RotateZ(theta)); Ok(()) })) @@ -1503,7 +1504,7 @@ ${helpers.predefined_type("scroll-snap-coordinate", try!(input.expect_comma()); let az = try!(specified::parse_number(input)); try!(input.expect_comma()); - let theta = try!(specified::Angle::parse(context,input)); + let theta = try!(specified::Angle::parse_with_unitless(context,input)); // TODO(gw): Check the axis can be normalized!! result.push(SpecifiedOperation::Rotate3D(ax, ay, az, theta)); Ok(()) @@ -1511,9 +1512,9 @@ ${helpers.predefined_type("scroll-snap-coordinate", }, "skew" => { try!(input.parse_nested_block(|input| { - let theta_x = try!(specified::Angle::parse(context, input)); + let theta_x = try!(specified::Angle::parse_with_unitless(context, input)); if input.try(|input| input.expect_comma()).is_ok() { - let theta_y = try!(specified::Angle::parse(context, input)); + let theta_y = try!(specified::Angle::parse_with_unitless(context, input)); result.push(SpecifiedOperation::Skew(theta_x, Some(theta_y))); } else { result.push(SpecifiedOperation::Skew(theta_x, None)); @@ -1523,14 +1524,14 @@ ${helpers.predefined_type("scroll-snap-coordinate", }, "skewx" => { try!(input.parse_nested_block(|input| { - let theta_x = try!(specified::Angle::parse(context,input)); + let theta_x = try!(specified::Angle::parse_with_unitless(context,input)); result.push(SpecifiedOperation::SkewX(theta_x)); Ok(()) })) }, "skewy" => { try!(input.parse_nested_block(|input| { - let theta_y = try!(specified::Angle::parse(context,input)); + let theta_y = try!(specified::Angle::parse_with_unitless(context,input)); result.push(SpecifiedOperation::SkewY(theta_y)); Ok(()) })) diff --git a/components/style/properties/longhand/inherited_box.mako.rs b/components/style/properties/longhand/inherited_box.mako.rs index d57e5d42039..f0d316172e1 100644 --- a/components/style/properties/longhand/inherited_box.mako.rs +++ b/components/style/properties/longhand/inherited_box.mako.rs @@ -83,7 +83,7 @@ ${helpers.single_keyword("image-rendering", // Image Orientation <%helpers:longhand name="image-orientation" - products="None" + products="gecko" animation_type="none" spec="https://drafts.csswg.org/css-images/#propdef-image-orientation, \ /// additional values in https://developer.mozilla.org/en-US/docs/Web/CSS/image-orientation"> @@ -199,21 +199,23 @@ ${helpers.single_keyword("image-rendering", } } + // from-image | | [? flip] pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { if input.try(|input| input.expect_ident_matching("from-image")).is_ok() { // Handle from-image Ok(SpecifiedValue { angle: None, flipped: false }) + } else if input.try(|input| input.expect_ident_matching("flip")).is_ok() { + // Handle flip + Ok(SpecifiedValue { angle: Some(Angle::zero()), flipped: true }) } else { - // Handle | ? flip + // Handle | flip let angle = input.try(|input| Angle::parse(context, input)).ok(); - let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok(); - let explicit_angle = if angle.is_none() && !flipped { - Some(Angle::zero()) - } else { - angle - }; + if angle.is_none() { + return Err(()); + } - Ok(SpecifiedValue { angle: explicit_angle, flipped: flipped }) + let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok(); + Ok(SpecifiedValue { angle: angle, flipped: flipped }) } } diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index f5ba7b7fb1d..89fe279c480 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -430,7 +430,6 @@ impl Parse for Angle { fn parse(_context: &ParserContext, input: &mut Parser) -> Result { match try!(input.next()) { Token::Dimension(ref value, ref unit) => Angle::parse_dimension(value.value, unit), - Token::Number(ref value) if value.value == 0. => Ok(Angle::zero()), Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { input.parse_nested_block(CalcLengthOrPercentage::parse_angle) }, @@ -451,6 +450,22 @@ impl Angle { }; Ok(angle) } + /// Parse an angle, including unitless 0 degree. + /// Note that numbers without any AngleUnit, including unitless 0 + /// angle, should be invalid. However, some properties still accept + /// unitless 0 angle and stores it as '0deg'. We can remove this and + /// get back to the unified version Angle::parse once + /// https://github.com/w3c/csswg-drafts/issues/1162 is resolved. + pub fn parse_with_unitless(_context: &ParserContext, input: &mut Parser) -> Result { + match try!(input.next()) { + Token::Dimension(ref value, ref unit) => Angle::parse_dimension(value.value, unit), + Token::Number(ref value) if value.value == 0. => Ok(Angle::zero()), + Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { + input.parse_nested_block(CalcLengthOrPercentage::parse_angle) + }, + _ => Err(()) + } + } } #[allow(missing_docs)] diff --git a/tests/unit/style/parsing/inherited_box.rs b/tests/unit/style/parsing/inherited_box.rs index dbe364b7adf..749641c79cf 100644 --- a/tests/unit/style/parsing/inherited_box.rs +++ b/tests/unit/style/parsing/inherited_box.rs @@ -17,7 +17,7 @@ fn image_orientation_longhand_should_parse_properly() { assert_eq!(from_image, SpecifiedValue { angle: None, flipped: false }); let flip = parse_longhand!(image_orientation, "flip"); - assert_eq!(flip, SpecifiedValue { angle: None, flipped: true }); + assert_eq!(flip, SpecifiedValue { angle: Some(Angle::from_degrees(0.0)), flipped: true }); let zero = parse_longhand!(image_orientation, "0deg"); assert_eq!(zero, SpecifiedValue { angle: Some(Angle::from_degrees(0.0)), flipped: false });