зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
88a492c12c
Коммит
683a0b2820
|
@ -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]
|
||||
|
|
Загрузка…
Ссылка в новой задаче