servo: Merge #13122 - Handle specialized serialization of <position> in basic shapes (from Manishearth:basic-shape-position-redux); r=SimonSapin

Fixes #13083

We temporarily broke basic-shape serialization in #13042 when 4-value positions were implemented, since I didn't want to increase the scope of that PR too much.

This fixes it.

r? @SimonSapin

cc @canaltinova

Source-Repo: https://github.com/servo/servo
Source-Revision: 6c68680581afbdd59034cb1535bfd4439cfa7394
This commit is contained in:
Manish Goregaokar 2016-09-01 12:50:32 -05:00
Родитель 88a492c12c
Коммит 683a0b2820
2 изменённых файлов: 99 добавлений и 8 удалений

Просмотреть файл

@ -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(")")
}
}

Просмотреть файл

@ -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%)");
@ -97,14 +96,24 @@ fn test_circle() {
assert_roundtrip_basicshape!(Circle::parse, "circle(calc(1px + 50%) at center)",
"circle(calc(1px + 50%) at 50% 50%)");
assert!(parse(Circle::parse, "circle(at top 40%)").is_err());
*/
assert_roundtrip_basicshape!(Circle::parse, "circle(at right 5px bottom 10px)",
"circle(at right 5px bottom 10px)");
assert_roundtrip_basicshape!(Circle::parse, "circle(at bottom 5px right 10px)",
"circle(at right 10px bottom 5px)");
assert_roundtrip_basicshape!(Circle::parse, "circle(at right 5% top 0px)",
"circle(at 95% 0%)");
assert_roundtrip_basicshape!(Circle::parse, "circle(at right 5% bottom 0px)",
"circle(at 95% 100%)");
assert_roundtrip_basicshape!(Circle::parse, "circle(at right 5% bottom 1px)",
"circle(at right 5% bottom 1px)");
assert_roundtrip_basicshape!(Circle::parse, "circle(at 5% bottom 1px)",
"circle(at left 5% bottom 1px)");
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 +127,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]