Skip to content

Commit

Permalink
Stylo - support image-orientation property
Browse files Browse the repository at this point in the history
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 w3c/csswg-drafts#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
  • Loading branch information
chenpighead committed Apr 11, 2017
1 parent b5a0032 commit 5332d4b
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 21 deletions.
29 changes: 28 additions & 1 deletion components/style/properties/gecko.mako.rs
Expand Up @@ -2776,6 +2776,34 @@ fn static_assert() {
}
</%self:impl_trait>

<%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>

<%self:impl_trait style_struct_name="InheritedTable"
skip_longhands="border-spacing">
Expand All @@ -2789,7 +2817,6 @@ fn static_assert() {
self.gecko.mBorderSpacingCol = other.gecko.mBorderSpacingCol;
self.gecko.mBorderSpacingRow = other.gecko.mBorderSpacingRow;
}

</%self:impl_trait>


Expand Down
19 changes: 10 additions & 9 deletions components/style/properties/longhand/box.mako.rs
Expand Up @@ -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<SpecifiedValue,()> {
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(SpecifiedValue(Vec::new()))
Expand Down Expand Up @@ -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(())
}))
Expand All @@ -1503,17 +1504,17 @@ ${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(())
}))
},
"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));
Expand All @@ -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(())
}))
Expand Down
20 changes: 11 additions & 9 deletions components/style/properties/longhand/inherited_box.mako.rs
Expand Up @@ -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">
Expand Down Expand Up @@ -199,21 +199,23 @@ ${helpers.single_keyword("image-rendering",
}
}

// from-image | <angle> | [<angle>? flip]
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
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 <angle> | <angle>? flip
// Handle <angle> | <angle> 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 })
}
}
</%helpers:longhand>
Expand Down
17 changes: 16 additions & 1 deletion components/style/values/specified/mod.rs
Expand Up @@ -430,7 +430,6 @@ impl Parse for Angle {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
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)
},
Expand All @@ -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<Self, ()> {
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)]
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/style/parsing/inherited_box.rs
Expand Up @@ -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 });
Expand Down

0 comments on commit 5332d4b

Please sign in to comment.