mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Auto merge of #13336 - canaltinova:mask, r=Manishearth
Implement parsing for mask shorthand <!-- Please describe your changes on the following line: --> Implement parsing for mask shorthand. It doesn't contain tests yet. I'll write and update the PR. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #13235 (github issue number if applicable). <!-- Either: --> - [x] There are tests for these changes <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- 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/13336) <!-- Reviewable:end -->
This commit is contained in:
commit
47fa31562a
6 changed files with 463 additions and 8 deletions
|
@ -94,10 +94,9 @@ ${helpers.single_keyword("mask-repeat",
|
||||||
|
|
||||||
<%helpers:longhand name="mask-position" products="gecko" animatable="True">
|
<%helpers:longhand name="mask-position" products="gecko" animatable="True">
|
||||||
use properties::longhands::background_position;
|
use properties::longhands::background_position;
|
||||||
pub mod computed_value {
|
pub use ::properties::longhands::background_position::SpecifiedValue;
|
||||||
pub type T = ::properties::longhands::background_position::computed_value::T;
|
pub use ::properties::longhands::background_position::single_value as single_value;
|
||||||
}
|
pub use ::properties::longhands::background_position::computed_value as computed_value;
|
||||||
pub type SpecifiedValue = background_position::SpecifiedValue;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
|
@ -127,10 +126,9 @@ ${helpers.single_keyword("mask-origin",
|
||||||
|
|
||||||
<%helpers:longhand name="mask-size" products="gecko" animatable="True">
|
<%helpers:longhand name="mask-size" products="gecko" animatable="True">
|
||||||
use properties::longhands::background_size;
|
use properties::longhands::background_size;
|
||||||
pub mod computed_value {
|
pub use ::properties::longhands::background_size::SpecifiedValue;
|
||||||
pub type T = ::properties::longhands::background_size::computed_value::T;
|
pub use ::properties::longhands::background_size::single_value as single_value;
|
||||||
}
|
pub use ::properties::longhands::background_size::computed_value as computed_value;
|
||||||
pub type SpecifiedValue = background_size::SpecifiedValue;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
|
|
|
@ -130,6 +130,7 @@ pub mod shorthands {
|
||||||
<%include file="/shorthand/inherited_text.mako.rs" />
|
<%include file="/shorthand/inherited_text.mako.rs" />
|
||||||
<%include file="/shorthand/list.mako.rs" />
|
<%include file="/shorthand/list.mako.rs" />
|
||||||
<%include file="/shorthand/margin.mako.rs" />
|
<%include file="/shorthand/margin.mako.rs" />
|
||||||
|
<%include file="/shorthand/mask.mako.rs" />
|
||||||
<%include file="/shorthand/outline.mako.rs" />
|
<%include file="/shorthand/outline.mako.rs" />
|
||||||
<%include file="/shorthand/padding.mako.rs" />
|
<%include file="/shorthand/padding.mako.rs" />
|
||||||
<%include file="/shorthand/position.mako.rs" />
|
<%include file="/shorthand/position.mako.rs" />
|
||||||
|
|
195
components/style/properties/shorthand/mask.mako.rs
Normal file
195
components/style/properties/shorthand/mask.mako.rs
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||||
|
|
||||||
|
<%helpers:shorthand name="mask" products="gecko"
|
||||||
|
sub_properties="mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position
|
||||||
|
mask-size mask-image">
|
||||||
|
use properties::longhands::{mask_mode, mask_repeat, mask_clip, mask_origin, mask_composite, mask_position};
|
||||||
|
use properties::longhands::{mask_size, mask_image};
|
||||||
|
|
||||||
|
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
|
||||||
|
% for name in "image mode position size repeat origin clip composite".split():
|
||||||
|
let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::new());
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
try!(input.parse_comma_separated(|input| {
|
||||||
|
% for name in "image mode position size repeat origin clip composite".split():
|
||||||
|
let mut ${name} = None;
|
||||||
|
% endfor
|
||||||
|
loop {
|
||||||
|
if image.is_none() {
|
||||||
|
if let Ok(value) = input.try(|input| mask_image::single_value
|
||||||
|
::parse(context, input)) {
|
||||||
|
image = Some(value);
|
||||||
|
|
||||||
|
// Parse mask mode, if applicable.
|
||||||
|
mode = input.try(|input| mask_mode::single_value::parse(context, input)).ok();
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if position.is_none() {
|
||||||
|
if let Ok(value) = input.try(|input| mask_position::single_value
|
||||||
|
::parse(context, input)) {
|
||||||
|
position = Some(value);
|
||||||
|
|
||||||
|
// Parse mask size, if applicable.
|
||||||
|
size = input.try(|input| {
|
||||||
|
try!(input.expect_delim('/'));
|
||||||
|
mask_size::single_value::parse(context, input)
|
||||||
|
}).ok();
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
% for name in "repeat origin clip composite".split():
|
||||||
|
if ${name}.is_none() {
|
||||||
|
if let Ok(value) = input.try(|input| mask_${name}::single_value
|
||||||
|
::parse(context, input)) {
|
||||||
|
${name} = Some(value);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
% endfor
|
||||||
|
break
|
||||||
|
}
|
||||||
|
let mut any = false;
|
||||||
|
% for name in "image mode position size repeat origin clip composite".split():
|
||||||
|
any = any || ${name}.is_some();
|
||||||
|
% endfor
|
||||||
|
if any {
|
||||||
|
% for name in "image mode position size repeat origin clip composite".split():
|
||||||
|
if let Some(m_${name}) = ${name} {
|
||||||
|
mask_${name}.0.push(m_${name});
|
||||||
|
} else {
|
||||||
|
mask_${name}.0.push(mask_${name}::single_value
|
||||||
|
::get_initial_specified_value());
|
||||||
|
}
|
||||||
|
% endfor
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
Ok(Longhands {
|
||||||
|
% for name in "image mode position size repeat origin clip composite".split():
|
||||||
|
mask_${name}: Some(mask_${name}),
|
||||||
|
% endfor
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LonghandsToSerialize<'a> {
|
||||||
|
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
// mako doesn't like ampersands following `<`
|
||||||
|
fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
|
||||||
|
match *x {
|
||||||
|
DeclaredValue::Value(ref val) => Some(val),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use std::cmp;
|
||||||
|
let mut len = 0;
|
||||||
|
% for name in "image mode position size repeat origin clip composite".split():
|
||||||
|
len = cmp::max(len, extract_value(self.mask_${name}).map(|i| i.0.len())
|
||||||
|
.unwrap_or(0));
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
// There should be at least one declared value
|
||||||
|
if len == 0 {
|
||||||
|
return dest.write_str("")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..len {
|
||||||
|
% for name in "image mode position size repeat origin clip composite".split():
|
||||||
|
let ${name} = if let DeclaredValue::Value(ref arr) = *self.mask_${name} {
|
||||||
|
arr.0.get(i % arr.0.len())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
if let Some(image) = image {
|
||||||
|
try!(image.to_css(dest));
|
||||||
|
} else {
|
||||||
|
try!(write!(dest, "none"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(write!(dest, " "));
|
||||||
|
|
||||||
|
if let Some(mode) = mode {
|
||||||
|
try!(mode.to_css(dest));
|
||||||
|
} else {
|
||||||
|
try!(write!(dest, "match-source"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(write!(dest, " "));
|
||||||
|
|
||||||
|
try!(position.unwrap_or(&mask_position::single_value
|
||||||
|
::get_initial_specified_value())
|
||||||
|
.to_css(dest));
|
||||||
|
|
||||||
|
if let Some(size) = size {
|
||||||
|
try!(write!(dest, " / "));
|
||||||
|
try!(size.to_css(dest));
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(write!(dest, " "));
|
||||||
|
|
||||||
|
if let Some(repeat) = repeat {
|
||||||
|
try!(repeat.to_css(dest));
|
||||||
|
} else {
|
||||||
|
try!(write!(dest, "repeat"));
|
||||||
|
}
|
||||||
|
|
||||||
|
match (origin, clip) {
|
||||||
|
(Some(origin), Some(clip)) => {
|
||||||
|
use properties::longhands::mask_origin::single_value::computed_value::T as Origin;
|
||||||
|
use properties::longhands::mask_clip::single_value::computed_value::T as Clip;
|
||||||
|
|
||||||
|
try!(write!(dest, " "));
|
||||||
|
|
||||||
|
match (origin, clip) {
|
||||||
|
(&Origin::padding_box, &Clip::padding_box) => {
|
||||||
|
try!(origin.to_css(dest));
|
||||||
|
},
|
||||||
|
(&Origin::border_box, &Clip::border_box) => {
|
||||||
|
try!(origin.to_css(dest));
|
||||||
|
},
|
||||||
|
(&Origin::content_box, &Clip::content_box) => {
|
||||||
|
try!(origin.to_css(dest));
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
try!(origin.to_css(dest));
|
||||||
|
try!(write!(dest, " "));
|
||||||
|
try!(clip.to_css(dest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(Some(origin), _) => {
|
||||||
|
try!(write!(dest, " "));
|
||||||
|
try!(origin.to_css(dest));
|
||||||
|
},
|
||||||
|
(_, Some(clip)) => {
|
||||||
|
try!(write!(dest, " "));
|
||||||
|
try!(clip.to_css(dest));
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
try!(write!(dest, " "));
|
||||||
|
|
||||||
|
if let Some(composite) = composite {
|
||||||
|
try!(composite.to_css(dest));
|
||||||
|
} else {
|
||||||
|
try!(write!(dest, "add"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</%helpers:shorthand>
|
122
tests/unit/style/parsing/mask.rs
Normal file
122
tests/unit/style/parsing/mask.rs
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/* 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 cssparser::Parser;
|
||||||
|
use media_queries::CSSErrorReporterTest;
|
||||||
|
use style::parser::ParserContext;
|
||||||
|
use style::properties::longhands::{mask_clip, mask_composite, mask_image, mask_mode};
|
||||||
|
use style::properties::longhands::{mask_origin, mask_position, mask_repeat, mask_size};
|
||||||
|
use style::properties::shorthands::mask;
|
||||||
|
use style::stylesheets::Origin;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
macro_rules! parse_longhand {
|
||||||
|
($name:ident, $s:expr) => {{
|
||||||
|
let url = Url::parse("http://localhost").unwrap();
|
||||||
|
let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
|
||||||
|
$name::parse(&context, &mut Parser::new($s)).unwrap()
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mask_shorthand_should_parse_all_available_properties_when_specified() {
|
||||||
|
let url = Url::parse("http://localhost").unwrap();
|
||||||
|
let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
|
||||||
|
let mut parser = Parser::new("url(\"http://servo/test.png\") luminance 7px 4px / 70px 50px \
|
||||||
|
repeat-x padding-box border-box subtract");
|
||||||
|
let result = mask::parse_value(&context, &mut parser).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.mask_image.unwrap(), parse_longhand!(mask_image, "url(\"http://servo/test.png\")"));
|
||||||
|
assert_eq!(result.mask_mode.unwrap(), parse_longhand!(mask_mode, "luminance"));
|
||||||
|
assert_eq!(result.mask_position.unwrap(), parse_longhand!(mask_position, "7px 4px"));
|
||||||
|
assert_eq!(result.mask_size.unwrap(), parse_longhand!(mask_size, "70px 50px"));
|
||||||
|
assert_eq!(result.mask_repeat.unwrap(), parse_longhand!(mask_repeat, "repeat-x"));
|
||||||
|
assert_eq!(result.mask_origin.unwrap(), parse_longhand!(mask_origin, "padding-box"));
|
||||||
|
assert_eq!(result.mask_clip.unwrap(), parse_longhand!(mask_clip, "border-box"));
|
||||||
|
assert_eq!(result.mask_composite.unwrap(), parse_longhand!(mask_composite, "subtract"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mask_shorthand_should_parse_when_some_fields_set() {
|
||||||
|
let url = Url::parse("http://localhost").unwrap();
|
||||||
|
let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
|
||||||
|
let mut parser = Parser::new("14px 40px repeat-y");
|
||||||
|
let result = mask::parse_value(&context, &mut parser).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.mask_position.unwrap(), parse_longhand!(mask_position, "14px 40px"));
|
||||||
|
assert_eq!(result.mask_repeat.unwrap(), parse_longhand!(mask_repeat, "repeat-y"));
|
||||||
|
|
||||||
|
let mut parser = Parser::new("url(\"http://servo/test.png\") repeat add");
|
||||||
|
let result = mask::parse_value(&context, &mut parser).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.mask_image.unwrap(), parse_longhand!(mask_image, "url(\"http://servo/test.png\")"));
|
||||||
|
assert_eq!(result.mask_repeat.unwrap(), parse_longhand!(mask_repeat, "repeat"));
|
||||||
|
assert_eq!(result.mask_composite.unwrap(), parse_longhand!(mask_composite, "add"));
|
||||||
|
|
||||||
|
let mut parser = Parser::new("intersect");
|
||||||
|
let result = mask::parse_value(&context, &mut parser).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.mask_composite.unwrap(), parse_longhand!(mask_composite, "intersect"));
|
||||||
|
|
||||||
|
let mut parser = Parser::new("url(\"http://servo/test.png\")");
|
||||||
|
let result = mask::parse_value(&context, &mut parser).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.mask_image.unwrap(), parse_longhand!(mask_image, "url(\"http://servo/test.png\")"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mask_shorthand_should_parse_position_and_size_correctly() {
|
||||||
|
let url = Url::parse("http://localhost").unwrap();
|
||||||
|
let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
|
||||||
|
let mut parser = Parser::new("7px 4px");
|
||||||
|
let result = mask::parse_value(&context, &mut parser).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.mask_position.unwrap(), parse_longhand!(mask_position, "7px 4px"));
|
||||||
|
|
||||||
|
let mut parser = Parser::new("7px 4px / 30px 20px");
|
||||||
|
let result = mask::parse_value(&context, &mut parser).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.mask_position.unwrap(), parse_longhand!(mask_position, "7px 4px"));
|
||||||
|
assert_eq!(result.mask_size.unwrap(), parse_longhand!(mask_size, "30px 20px"));
|
||||||
|
|
||||||
|
let mut parser = Parser::new("/ 30px 20px");
|
||||||
|
assert!(mask::parse_value(&context, &mut parser).is_err());
|
||||||
|
|
||||||
|
let mut parser = Parser::new("match-source repeat-x / 30px 20px");
|
||||||
|
assert!(mask::parse_value(&context, &mut parser).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mask_shorthand_should_parse_origin_and_clip_correctly() {
|
||||||
|
let url = Url::parse("http://localhost").unwrap();
|
||||||
|
let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
|
||||||
|
let mut parser = Parser::new("padding-box content-box");
|
||||||
|
let result = mask::parse_value(&context, &mut parser).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.mask_origin.unwrap(), parse_longhand!(mask_origin, "padding-box"));
|
||||||
|
assert_eq!(result.mask_clip.unwrap(), parse_longhand!(mask_clip, "content-box"));
|
||||||
|
|
||||||
|
let mut parser = Parser::new("padding-box padding-box");
|
||||||
|
let result = mask::parse_value(&context, &mut parser).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.mask_origin.unwrap(), parse_longhand!(mask_origin, "padding-box"));
|
||||||
|
assert_eq!(result.mask_clip.unwrap(), parse_longhand!(mask_clip, "padding-box"));
|
||||||
|
|
||||||
|
let mut parser = Parser::new("padding-box");
|
||||||
|
let result = mask::parse_value(&context, &mut parser).unwrap();
|
||||||
|
|
||||||
|
// TODO(#13466): We should fix origin/clip parsing behavior.
|
||||||
|
assert_eq!(result.mask_origin.unwrap(), parse_longhand!(mask_origin, "padding-box"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mask_shorthand_should_not_parse_when_mode_specified_but_image_not() {
|
||||||
|
let url = Url::parse("http://localhost").unwrap();
|
||||||
|
let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
|
||||||
|
let mut parser = Parser::new("luminance 7px 4px repeat-x padding");
|
||||||
|
assert!(mask::parse_value(&context, &mut parser).is_err());
|
||||||
|
|
||||||
|
let mut parser = Parser::new("alpha");
|
||||||
|
assert!(mask::parse_value(&context, &mut parser).is_err());
|
||||||
|
}
|
|
@ -33,5 +33,6 @@ macro_rules! assert_roundtrip {
|
||||||
|
|
||||||
|
|
||||||
mod basic_shape;
|
mod basic_shape;
|
||||||
|
mod mask;
|
||||||
mod position;
|
mod position;
|
||||||
mod selectors;
|
mod selectors;
|
||||||
|
|
|
@ -865,4 +865,142 @@ mod shorthand_serialization {
|
||||||
assert_eq!(serialization, "background: rgb(255, 0, 0) none repeat-x scroll 0px 0px;");
|
assert_eq!(serialization, "background: rgb(255, 0, 0) none repeat-x scroll 0px 0px;");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod mask {
|
||||||
|
use style::properties::longhands::mask_clip as clip;
|
||||||
|
use style::properties::longhands::mask_composite as composite;
|
||||||
|
use style::properties::longhands::mask_image as image;
|
||||||
|
use style::properties::longhands::mask_mode as mode;
|
||||||
|
use style::properties::longhands::mask_origin as origin;
|
||||||
|
use style::properties::longhands::mask_position as position;
|
||||||
|
use style::properties::longhands::mask_repeat as repeat;
|
||||||
|
use style::properties::longhands::mask_size as size;
|
||||||
|
use style::values::specified::Image;
|
||||||
|
use style::values::specified::position::Position;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
macro_rules! single_vec_value_typedef {
|
||||||
|
($name:ident, $path:expr) => {
|
||||||
|
DeclaredValue::Value($name::SpecifiedValue(
|
||||||
|
vec![$path]
|
||||||
|
))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! single_vec_keyword_value {
|
||||||
|
($name:ident, $kw:ident) => {
|
||||||
|
DeclaredValue::Value($name::SpecifiedValue(
|
||||||
|
vec![$name::single_value::SpecifiedValue::$kw]
|
||||||
|
))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! single_vec_variant_value {
|
||||||
|
($name:ident, $variant:expr) => {
|
||||||
|
DeclaredValue::Value($name::SpecifiedValue(
|
||||||
|
vec![$variant]
|
||||||
|
))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mask_should_serialize_all_available_properties_when_specified() {
|
||||||
|
let mut properties = Vec::new();
|
||||||
|
|
||||||
|
let image = single_vec_value_typedef!(image,
|
||||||
|
image::single_value::SpecifiedValue::Image(
|
||||||
|
Image::Url(Url::parse("http://servo/test.png").unwrap(),
|
||||||
|
UrlExtraData {})));
|
||||||
|
|
||||||
|
let mode = single_vec_keyword_value!(mode, luminance);
|
||||||
|
|
||||||
|
let position = single_vec_value_typedef!(position,
|
||||||
|
Position {
|
||||||
|
horiz_keyword: None,
|
||||||
|
horiz_position: Some(LengthOrPercentage::Length(Length::from_px(7f32))),
|
||||||
|
vert_keyword: None,
|
||||||
|
vert_position: Some(LengthOrPercentage::Length(Length::from_px(4f32)))
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let size = single_vec_variant_value!(size,
|
||||||
|
size::single_value::SpecifiedValue::Explicit(
|
||||||
|
size::single_value::ExplicitSize {
|
||||||
|
width: LengthOrPercentageOrAuto::Length(Length::from_px(70f32)),
|
||||||
|
height: LengthOrPercentageOrAuto::Length(Length::from_px(50f32))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
let repeat = single_vec_keyword_value!(repeat, repeat_x);
|
||||||
|
let origin = single_vec_keyword_value!(origin, padding_box);
|
||||||
|
let clip = single_vec_keyword_value!(clip, border_box);
|
||||||
|
let composite = single_vec_keyword_value!(composite, subtract);
|
||||||
|
|
||||||
|
properties.push(PropertyDeclaration::MaskImage(image));
|
||||||
|
properties.push(PropertyDeclaration::MaskMode(mode));
|
||||||
|
properties.push(PropertyDeclaration::MaskPosition(position));
|
||||||
|
properties.push(PropertyDeclaration::MaskSize(size));
|
||||||
|
properties.push(PropertyDeclaration::MaskRepeat(repeat));
|
||||||
|
properties.push(PropertyDeclaration::MaskOrigin(origin));
|
||||||
|
properties.push(PropertyDeclaration::MaskClip(clip));
|
||||||
|
properties.push(PropertyDeclaration::MaskComposite(composite));
|
||||||
|
|
||||||
|
let serialization = shorthand_properties_to_string(properties);
|
||||||
|
assert_eq!(
|
||||||
|
serialization,
|
||||||
|
"mask: url(\"http://servo/test.png\") luminance 7px 4px / 70px 50px \
|
||||||
|
repeat-x padding-box border-box subtract;"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mask_should_combine_origin_and_clip_properties_when_equal() {
|
||||||
|
let mut properties = Vec::new();
|
||||||
|
|
||||||
|
let image = single_vec_value_typedef!(image,
|
||||||
|
image::single_value::SpecifiedValue::Image(
|
||||||
|
Image::Url(Url::parse("http://servo/test.png").unwrap(),
|
||||||
|
UrlExtraData {})));
|
||||||
|
|
||||||
|
let mode = single_vec_keyword_value!(mode, luminance);
|
||||||
|
|
||||||
|
let position = single_vec_value_typedef!(position,
|
||||||
|
Position {
|
||||||
|
horiz_keyword: None,
|
||||||
|
horiz_position: Some(LengthOrPercentage::Length(Length::from_px(7f32))),
|
||||||
|
vert_keyword: None,
|
||||||
|
vert_position: Some(LengthOrPercentage::Length(Length::from_px(4f32)))
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let size = single_vec_variant_value!(size,
|
||||||
|
size::single_value::SpecifiedValue::Explicit(
|
||||||
|
size::single_value::ExplicitSize {
|
||||||
|
width: LengthOrPercentageOrAuto::Length(Length::from_px(70f32)),
|
||||||
|
height: LengthOrPercentageOrAuto::Length(Length::from_px(50f32))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
let repeat = single_vec_keyword_value!(repeat, repeat_x);
|
||||||
|
let origin = single_vec_keyword_value!(origin, padding_box);
|
||||||
|
let clip = single_vec_keyword_value!(clip, padding_box);
|
||||||
|
let composite = single_vec_keyword_value!(composite, subtract);
|
||||||
|
|
||||||
|
properties.push(PropertyDeclaration::MaskImage(image));
|
||||||
|
properties.push(PropertyDeclaration::MaskMode(mode));
|
||||||
|
properties.push(PropertyDeclaration::MaskPosition(position));
|
||||||
|
properties.push(PropertyDeclaration::MaskSize(size));
|
||||||
|
properties.push(PropertyDeclaration::MaskRepeat(repeat));
|
||||||
|
properties.push(PropertyDeclaration::MaskOrigin(origin));
|
||||||
|
properties.push(PropertyDeclaration::MaskClip(clip));
|
||||||
|
properties.push(PropertyDeclaration::MaskComposite(composite));
|
||||||
|
|
||||||
|
let serialization = shorthand_properties_to_string(properties);
|
||||||
|
assert_eq!(
|
||||||
|
serialization,
|
||||||
|
"mask: url(\"http://servo/test.png\") luminance 7px 4px / 70px 50px \
|
||||||
|
repeat-x padding-box subtract;"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue