mirror of
https://github.com/servo/servo.git
synced 2025-06-25 09:34:32 +01:00
Auto merge of #13122 - Manishearth:basic-shape-position-redux, r=SimonSapin
Handle specialized serialization of <position> in basic shapes 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 <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13122) <!-- Reviewable:end -->
This commit is contained in:
commit
6c68680581
2 changed files with 99 additions and 8 deletions
|
@ -16,7 +16,7 @@ use values::computed::basic_shape as computed_basic_shape;
|
||||||
use values::computed::{Context, ToComputedValue, ComputedValueAsSpecified};
|
use values::computed::{Context, ToComputedValue, ComputedValueAsSpecified};
|
||||||
use values::specified::UrlExtraData;
|
use values::specified::UrlExtraData;
|
||||||
use values::specified::position::{Keyword, Position};
|
use values::specified::position::{Keyword, Position};
|
||||||
use values::specified::{BorderRadiusSize, LengthOrPercentage};
|
use values::specified::{BorderRadiusSize, LengthOrPercentage, Percentage};
|
||||||
|
|
||||||
/// A shape source, for some reference box
|
/// 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)]
|
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
/// https://drafts.csswg.org/css-shapes/#funcdef-circle
|
/// https://drafts.csswg.org/css-shapes/#funcdef-circle
|
||||||
|
@ -286,7 +369,7 @@ impl ToCss for Circle {
|
||||||
try!(dest.write_str(" "));
|
try!(dest.write_str(" "));
|
||||||
}
|
}
|
||||||
try!(dest.write_str("at "));
|
try!(dest.write_str("at "));
|
||||||
try!(self.position.to_css(dest));
|
try!(serialize_basicshape_position(&self.position, dest));
|
||||||
dest.write_str(")")
|
dest.write_str(")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,7 +438,7 @@ impl ToCss for Ellipse {
|
||||||
try!(dest.write_str(" "));
|
try!(dest.write_str(" "));
|
||||||
}
|
}
|
||||||
try!(dest.write_str("at "));
|
try!(dest.write_str("at "));
|
||||||
try!(self.position.to_css(dest));
|
try!(serialize_basicshape_position(&self.position, dest));
|
||||||
dest.write_str(")")
|
dest.write_str(")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,6 @@ fn test_border_radius() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_circle() {
|
fn test_circle() {
|
||||||
/*
|
|
||||||
assert_roundtrip_basicshape!(Circle::parse, "circle(at center)", "circle(at 50% 50%)");
|
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()", "circle(at 50% 50%)");
|
||||||
assert_roundtrip_basicshape!(Circle::parse, "circle(at left bottom)", "circle(at 0% 100%)");
|
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)",
|
assert_roundtrip_basicshape!(Circle::parse, "circle(calc(1px + 50%) at center)",
|
||||||
"circle(calc(1px + 50%) at 50% 50%)");
|
"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]
|
#[test]
|
||||||
fn test_ellipse() {
|
fn test_ellipse() {
|
||||||
/*
|
|
||||||
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(at center)", "ellipse(at 50% 50%)");
|
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()", "ellipse(at 50% 50%)");
|
||||||
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(at left bottom)", "ellipse(at 0% 100%)");
|
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(20px 10% at center)", "ellipse(20px 10% at 50% 50%)");
|
||||||
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(calc(1px + 50%) 10px at center)",
|
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(calc(1px + 50%) 10px at center)",
|
||||||
"ellipse(calc(1px + 50%) 10px at 50% 50%)");
|
"ellipse(calc(1px + 50%) 10px at 50% 50%)");
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue