mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
Auto merge of #12680 - Manishearth:basic-shape, r=SimonSapin
style: Add support for parsing and serialization of <basic-shape>s Still WIP: I still need to use this somewhere and make serialization minimal. I'm not sure if I should do either in this PR. The only other browser that handles basic shapes doesn't serialize correctly either (https://bugzilla.mozilla.org/show_bug.cgi?id=1290864), so that's not something we need to get done now. As far as using this somewhere, I have the following options: - Merge this now, work on using it in stylo in a followup. - Just write extensive unit tests for parsing/serialization for now (stylo in a followup) - Use this for clip-path in stylo only (which I intend to do anyway, just not sure if I should do it in this PR) - Use this for clip-path in Servo (I'd rather not do this; this would be a huge change requiring a lot more layout knowledge than I currently have) Thoughts? Review? @SimonSapin @bholley <!-- 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/12680) <!-- Reviewable:end -->
This commit is contained in:
commit
0fc0db67c6
16 changed files with 1188 additions and 181 deletions
|
@ -21,6 +21,7 @@ mod attr;
|
|||
mod cache;
|
||||
mod logical_geometry;
|
||||
mod media_queries;
|
||||
mod parsing;
|
||||
mod properties;
|
||||
mod str;
|
||||
mod stylesheets;
|
||||
|
|
139
tests/unit/style/parsing/basic_shape.rs
Normal file
139
tests/unit/style/parsing/basic_shape.rs
Normal file
|
@ -0,0 +1,139 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use parsing::parse;
|
||||
use style::values::specified::basic_shape::*;
|
||||
|
||||
// Ensure that basic-shape sub-functions parse as both basic shapes
|
||||
// and their individual components
|
||||
macro_rules! assert_roundtrip_basicshape {
|
||||
($fun:expr, $input:expr, $output:expr) => {
|
||||
assert_roundtrip!($fun, $input, $output);
|
||||
assert_roundtrip!(BasicShape::parse, $input, $output);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! assert_border_radius_values {
|
||||
($input:expr; $tlw:expr, $trw:expr, $brw:expr, $blw:expr ;
|
||||
$tlh:expr, $trh:expr, $brh:expr, $blh:expr) => {
|
||||
let input = parse(BorderRadius::parse, $input)
|
||||
.expect(&format!("Failed parsing {} as border radius",
|
||||
$input));
|
||||
assert_eq!(::cssparser::ToCss::to_css_string(&input.top_left.0.width), $tlw);
|
||||
assert_eq!(::cssparser::ToCss::to_css_string(&input.top_right.0.width), $trw);
|
||||
assert_eq!(::cssparser::ToCss::to_css_string(&input.bottom_right.0.width), $brw);
|
||||
assert_eq!(::cssparser::ToCss::to_css_string(&input.bottom_left.0.width), $blw);
|
||||
assert_eq!(::cssparser::ToCss::to_css_string(&input.top_left.0.height), $tlh);
|
||||
assert_eq!(::cssparser::ToCss::to_css_string(&input.top_right.0.height), $trh);
|
||||
assert_eq!(::cssparser::ToCss::to_css_string(&input.bottom_right.0.height), $brh);
|
||||
assert_eq!(::cssparser::ToCss::to_css_string(&input.bottom_left.0.height), $blh);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inset() {
|
||||
// these are actually wrong, we should be serializing to the minimum possible result
|
||||
// the advantage of being wrong is that the roundtrip test actually suffices
|
||||
// for testing the intermediate state
|
||||
assert_roundtrip_basicshape!(InsetRect::parse, "inset(10px)", "inset(10px 10px 10px 10px)");
|
||||
assert_roundtrip_basicshape!(InsetRect::parse, "inset(10px 20%)", "inset(10px 20% 10px 20%)");
|
||||
|
||||
assert_roundtrip_basicshape!(InsetRect::parse, "inset(10px round 10px)",
|
||||
"inset(10px 10px 10px 10px round 10px)");
|
||||
assert_roundtrip_basicshape!(InsetRect::parse, "inset(10px round 10px 20px 30px 40px)",
|
||||
"inset(10px 10px 10px 10px round 10px 20px 30px 40px)");
|
||||
assert_roundtrip_basicshape!(InsetRect::parse, "inset(10px 10px 10px 10px round 10px 20px 30px 40px \
|
||||
/ 1px 2px 3px 4px)",
|
||||
"inset(10px 10px 10px 10px round 10px 20px 30px 40px \
|
||||
/ 1px 2px 3px 4px)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_border_radius() {
|
||||
assert_border_radius_values!("10px";
|
||||
"10px", "10px", "10px", "10px" ;
|
||||
"10px", "10px", "10px", "10px");
|
||||
assert_border_radius_values!("10px 20px";
|
||||
"10px", "20px", "10px", "20px" ;
|
||||
"10px", "20px", "10px", "20px");
|
||||
assert_border_radius_values!("10px 20px 30px";
|
||||
"10px", "20px", "30px", "20px" ;
|
||||
"10px", "20px", "30px", "20px");
|
||||
assert_border_radius_values!("10px 20px 30px 40px";
|
||||
"10px", "20px", "30px", "40px" ;
|
||||
"10px", "20px", "30px", "40px");
|
||||
assert_border_radius_values!("10% / 20px";
|
||||
"10%", "10%", "10%", "10%" ;
|
||||
"20px", "20px", "20px", "20px");
|
||||
assert_border_radius_values!("10px / 20px 30px";
|
||||
"10px", "10px", "10px", "10px" ;
|
||||
"20px", "30px", "20px", "30px");
|
||||
assert_border_radius_values!("10px 20px 30px 40px / 1px 2px 3px 4px";
|
||||
"10px", "20px", "30px", "40px" ;
|
||||
"1px", "2px", "3px", "4px");
|
||||
}
|
||||
|
||||
#[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%)");
|
||||
assert_roundtrip_basicshape!(Circle::parse, "circle(at bottom left)", "circle(at 0% 100%)");
|
||||
assert_roundtrip_basicshape!(Circle::parse, "circle(at top left)", "circle(at 0% 0%)");
|
||||
assert_roundtrip_basicshape!(Circle::parse, "circle(at center left)", "circle(at 0% 50%)");
|
||||
assert_roundtrip_basicshape!(Circle::parse, "circle(at left center)", "circle(at 0% 50%)");
|
||||
assert_roundtrip_basicshape!(Circle::parse, "circle(at top center)", "circle(at 50% 0%)");
|
||||
assert_roundtrip_basicshape!(Circle::parse, "circle(at center top)", "circle(at 50% 0%)");
|
||||
assert_roundtrip_basicshape!(Circle::parse, "circle(at 40% top)", "circle(at 40% 0%)");
|
||||
assert_roundtrip_basicshape!(Circle::parse, "circle(at 10px 100px)", "circle(at 10px 100px)");
|
||||
// closest-side is omitted, because it is the default
|
||||
assert_roundtrip_basicshape!(Circle::parse, "circle(closest-side at center)", "circle(at 50% 50%)");
|
||||
assert_roundtrip_basicshape!(Circle::parse, "circle(farthest-side at center)",
|
||||
"circle(farthest-side at 50% 50%)");
|
||||
assert_roundtrip_basicshape!(Circle::parse, "circle(20px at center)", "circle(20px at 50% 50%)");
|
||||
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());
|
||||
|
||||
}
|
||||
|
||||
#[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%)");
|
||||
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(at bottom left)", "ellipse(at 0% 100%)");
|
||||
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(at 10px 100px)", "ellipse(at 10px 100px)");
|
||||
// closest-side is omitted, because it is the default
|
||||
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(closest-side closest-side at center)",
|
||||
"ellipse(at 50% 50%)");
|
||||
assert_roundtrip_basicshape!(Ellipse::parse, "ellipse(farthest-side closest-side at center)",
|
||||
"ellipse(farthest-side closest-side 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)",
|
||||
"ellipse(calc(1px + 50%) 10px at 50% 50%)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_polygon() {
|
||||
// surprisingly, polygons are only required to have at least one vertex,
|
||||
// not at least 3
|
||||
assert_roundtrip_basicshape!(Polygon::parse, "polygon(10px 10px)", "polygon(10px 10px)");
|
||||
assert_roundtrip_basicshape!(Polygon::parse, "polygon(10px 10px, 10px 10px)", "polygon(10px 10px, 10px 10px)");
|
||||
assert_roundtrip_basicshape!(Polygon::parse, "polygon(nonzero, 10px 10px, 10px 10px)",
|
||||
"polygon(10px 10px, 10px 10px)");
|
||||
assert_roundtrip_basicshape!(Polygon::parse, "polygon(evenodd, 10px 10px, 10px 10px)",
|
||||
"polygon(evenodd, 10px 10px, 10px 10px)");
|
||||
assert_roundtrip_basicshape!(Polygon::parse, "polygon(evenodd, 10px 10px, 10px calc(10px + 50%))",
|
||||
"polygon(evenodd, 10px 10px, 10px calc(10px + 50%))");
|
||||
assert_roundtrip_basicshape!(Polygon::parse, "polygon(evenodd, 10px 10px, 10px 10px, 10px 10px, 10px 10px, 10px \
|
||||
10px, 10px 10px, 10px 10px, 10px 10px, 10px 10px, 10px 10px, \
|
||||
10px 10px, 10px 10px, 10px 10px)",
|
||||
"polygon(evenodd, 10px 10px, 10px 10px, 10px 10px, 10px 10px, 10px \
|
||||
10px, 10px 10px, 10px 10px, 10px 10px, 10px 10px, 10px 10px, \
|
||||
10px 10px, 10px 10px, 10px 10px)");
|
||||
|
||||
assert!(parse(Polygon::parse, "polygon()").is_err());
|
||||
}
|
33
tests/unit/style/parsing/mod.rs
Normal file
33
tests/unit/style/parsing/mod.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Tests for parsing and serialization of values/properties
|
||||
|
||||
use cssparser::Parser;
|
||||
|
||||
fn parse<T, F: Fn(&mut Parser) -> Result<T, ()>>(f: F, s: &str) -> Result<T, ()> {
|
||||
let mut parser = Parser::new(s);
|
||||
f(&mut parser)
|
||||
}
|
||||
|
||||
|
||||
// This is a macro so that the file/line information
|
||||
// is preserved in the panic
|
||||
macro_rules! assert_roundtrip {
|
||||
($fun:expr, $input:expr, $output:expr) => {
|
||||
let parsed = $crate::parsing::parse($fun, $input)
|
||||
.expect(&format!("Failed to parse {}", $input));
|
||||
let serialized = ::cssparser::ToCss::to_css_string(&parsed);
|
||||
assert_eq!(serialized, $output);
|
||||
|
||||
let re_parsed = $crate::parsing::parse($fun, &serialized)
|
||||
.expect(&format!("Failed to parse serialization {}", $input));
|
||||
let re_serialized = ::cssparser::ToCss::to_css_string(&re_parsed);
|
||||
assert_eq!(serialized, re_serialized);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mod basic_shape;
|
||||
mod position;
|
34
tests/unit/style/parsing/position.rs
Normal file
34
tests/unit/style/parsing/position.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use parsing::parse;
|
||||
use style::values::specified::position::*;
|
||||
|
||||
#[test]
|
||||
fn test_position() {
|
||||
// Serialization is not actually specced
|
||||
// though these are the values expected by basic-shape
|
||||
// https://github.com/w3c/csswg-drafts/issues/368
|
||||
assert_roundtrip!(Position::parse, "center", "50% 50%");
|
||||
assert_roundtrip!(Position::parse, "top left", "0% 0%");
|
||||
assert_roundtrip!(Position::parse, "left top", "0% 0%");
|
||||
assert_roundtrip!(Position::parse, "top right", "100% 0%");
|
||||
assert_roundtrip!(Position::parse, "right top", "100% 0%");
|
||||
assert_roundtrip!(Position::parse, "bottom left", "0% 100%");
|
||||
assert_roundtrip!(Position::parse, "left bottom", "0% 100%");
|
||||
assert_roundtrip!(Position::parse, "left center", "0% 50%");
|
||||
assert_roundtrip!(Position::parse, "right center", "100% 50%");
|
||||
assert_roundtrip!(Position::parse, "center top", "50% 0%");
|
||||
assert_roundtrip!(Position::parse, "center bottom", "50% 100%");
|
||||
assert_roundtrip!(Position::parse, "center 10px", "50% 10px");
|
||||
assert_roundtrip!(Position::parse, "center 10%", "50% 10%");
|
||||
assert_roundtrip!(Position::parse, "right 10%", "100% 10%");
|
||||
|
||||
// Only keywords can be reordered
|
||||
assert!(parse(Position::parse, "top 40%").is_err());
|
||||
assert!(parse(Position::parse, "40% left").is_err());
|
||||
|
||||
// we don't yet handle 4-valued positions
|
||||
// https://github.com/servo/servo/issues/12690
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue