aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2016-08-30 13:56:25 +0530
committerManish Goregaokar <manishsmail@gmail.com>2016-09-01 13:59:59 +0530
commit7c9aff33c59e5a8685c96f111dbb177e930004fd (patch)
tree3e3f0a38f5ef1a53c86cfb641afcb08bc372c64f
parentb8d725d2079945a18c9b40250a2a722379dad966 (diff)
downloadservo-7c9aff33c59e5a8685c96f111dbb177e930004fd.tar.gz
servo-7c9aff33c59e5a8685c96f111dbb177e930004fd.zip
Handle specialized serialization of <position> in basic shapes (fixes #13083)
-rw-r--r--components/style/values/specified/basic_shape.rs89
-rw-r--r--tests/unit/style/parsing/basic_shape.rs5
2 files changed, 86 insertions, 8 deletions
diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs
index e683b30e726..11da6b80598 100644
--- a/components/style/values/specified/basic_shape.rs
+++ b/components/style/values/specified/basic_shape.rs
@@ -16,7 +16,7 @@ use values::computed::basic_shape as computed_basic_shape;
use values::computed::{Context, ToComputedValue, ComputedValueAsSpecified};
use values::specified::UrlExtraData;
use values::specified::position::{Keyword, Position};
-use values::specified::{BorderRadiusSize, LengthOrPercentage};
+use values::specified::{BorderRadiusSize, LengthOrPercentage, Percentage};
/// A shape source, for some reference box
///
@@ -241,6 +241,89 @@ impl ToComputedValue for InsetRect {
}
}
+/// https://drafts.csswg.org/css-shapes/#basic-shape-serialization
+///
+/// Positions get serialized differently with basic shapes. Keywords
+/// are converted to percentages where possible. Only the two or four
+/// value forms are used. In case of two keyword-percentage pairs,
+/// the keywords are folded into the percentages
+fn serialize_basicshape_position<W>(position: &Position, dest: &mut W)
+ -> fmt::Result where W: fmt::Write {
+ use values::specified::Length;
+ use values::specified::position::Keyword;
+
+ // keyword-percentage pairs can be folded into a single percentage
+ fn fold_keyword(keyword: Option<Keyword>, length: Option<LengthOrPercentage>)
+ -> Option<LengthOrPercentage> {
+ let pc = match length.map(replace_with_percent) {
+ None => Percentage(0.0), // unspecified length = 0%
+ Some(LengthOrPercentage::Percentage(pc)) => pc,
+ _ => return None
+ };
+ let percent = match keyword {
+ Some(Keyword::Center) => {
+ // center cannot pair with lengths
+ assert!(length.is_none());
+ Percentage(0.5)
+ },
+ Some(Keyword::Left) | Some(Keyword::Top) | None => pc,
+ Some(Keyword::Right) | Some(Keyword::Bottom) => Percentage(1.0 - pc.0),
+ };
+ Some(LengthOrPercentage::Percentage(percent))
+ }
+
+ // 0 length should be replaced with 0%
+ fn replace_with_percent(input: LengthOrPercentage) -> LengthOrPercentage {
+ match input {
+ LengthOrPercentage::Length(Length::Absolute(au)) if au.0 == 0 => {
+ LengthOrPercentage::Percentage(Percentage(0.0))
+ }
+ _ => {
+ input
+ }
+ }
+ }
+
+ fn serialize_position_pair<W>(x: LengthOrPercentage, y: LengthOrPercentage,
+ dest: &mut W) -> fmt::Result where W: fmt::Write {
+ try!(replace_with_percent(x).to_css(dest));
+ try!(dest.write_str(" "));
+ replace_with_percent(y).to_css(dest)
+ }
+
+ match (position.horiz_keyword, position.horiz_position,
+ position.vert_keyword, position.vert_position) {
+ (Some(hk), None, Some(vk), None) => {
+ // two keywords: serialize as two lengths
+ serialize_position_pair(hk.to_length_or_percentage(),
+ vk.to_length_or_percentage(),
+ dest)
+ }
+ (None, Some(hp), None, Some(vp)) => {
+ // two lengths: just serialize regularly
+ serialize_position_pair(hp, vp, dest)
+ }
+ (hk, hp, vk, vp) => {
+ // only fold if both fold; the three-value form isn't
+ // allowed here.
+ if let (Some(x), Some(y)) = (fold_keyword(hk, hp), fold_keyword(vk, vp)) {
+ serialize_position_pair(x, y, dest)
+ } else {
+ // We failed to reduce it to a two-value form,
+ // so we expand it to 4-value
+ let zero = LengthOrPercentage::Percentage(Percentage(0.0));
+ try!(hk.unwrap_or(Keyword::Left).to_css(dest));
+ try!(dest.write_str(" "));
+ try!(replace_with_percent(hp.unwrap_or(zero)).to_css(dest));
+ try!(dest.write_str(" "));
+ try!(vk.unwrap_or(Keyword::Top).to_css(dest));
+ try!(dest.write_str(" "));
+ replace_with_percent(vp.unwrap_or(zero)).to_css(dest)
+ }
+ }
+ }
+}
+
#[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// https://drafts.csswg.org/css-shapes/#funcdef-circle
@@ -286,7 +369,7 @@ impl ToCss for Circle {
try!(dest.write_str(" "));
}
try!(dest.write_str("at "));
- try!(self.position.to_css(dest));
+ try!(serialize_basicshape_position(&self.position, dest));
dest.write_str(")")
}
}
@@ -355,7 +438,7 @@ impl ToCss for Ellipse {
try!(dest.write_str(" "));
}
try!(dest.write_str("at "));
- try!(self.position.to_css(dest));
+ try!(serialize_basicshape_position(&self.position, dest));
dest.write_str(")")
}
}
diff --git a/tests/unit/style/parsing/basic_shape.rs b/tests/unit/style/parsing/basic_shape.rs
index d62e6ee4de6..09caba23942 100644
--- a/tests/unit/style/parsing/basic_shape.rs
+++ b/tests/unit/style/parsing/basic_shape.rs
@@ -77,7 +77,6 @@ fn test_border_radius() {
#[test]
fn test_circle() {
- /*
assert_roundtrip_basicshape!(Circle::parse, "circle(at center)", "circle(at 50% 50%)");
assert_roundtrip_basicshape!(Circle::parse, "circle()", "circle(at 50% 50%)");
assert_roundtrip_basicshape!(Circle::parse, "circle(at left bottom)", "circle(at 0% 100%)");
@@ -98,13 +97,10 @@ fn test_circle() {
"circle(calc(1px + 50%) at 50% 50%)");
assert!(parse(Circle::parse, "circle(at top 40%)").is_err());
- */
-
}
#[test]
fn test_ellipse() {
- /*
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(at center)", "ellipse(at 50% 50%)");
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse()", "ellipse(at 50% 50%)");
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(at left bottom)", "ellipse(at 0% 100%)");
@@ -118,7 +114,6 @@ fn test_ellipse() {
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(20px 10% at center)", "ellipse(20px 10% at 50% 50%)");
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(calc(1px + 50%) 10px at center)",
"ellipse(calc(1px + 50%) 10px at 50% 50%)");
- */
}
#[test]