Auto merge of #14189 - canaltinova:border-image-shorthand, r=Manishearth

Implement border-image shorthand

<!-- Please describe your changes on the following line: -->
Implementation of border-image shorthand.
r? Manishearth

---
<!-- 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

<!-- 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/14189)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-11-14 11:17:54 -06:00 committed by GitHub
commit e9fa69bb2d
4 changed files with 246 additions and 1 deletions

View file

@ -107,6 +107,11 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
computed_value::T(None)
}
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue(None)
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
@ -141,7 +146,7 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
use values::specified::LengthOrNumber;
use values::specified::{LengthOrNumber, Number};
impl HasViewportPercentage for SpecifiedValue {
fn has_viewport_percentage(&self) -> bool {
@ -196,6 +201,11 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
computed::LengthOrNumber::Number(0.0))
}
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue(vec![LengthOrNumber::Number(Number(0.0))])
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
@ -301,6 +311,11 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
computed_value::T(RepeatKeyword::Stretch, RepeatKeyword::Stretch)
}
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue(RepeatKeyword::Stretch, None)
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
@ -449,6 +464,11 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
computed_value::SingleComputedValue::Number(1.0))
}
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue(vec![SingleSpecifiedValue::Number(Number(1.0))])
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
@ -640,6 +660,14 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
}
}
#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue {
corners: vec![PercentageOrNumber::Percentage(Percentage(1.0))],
fill: false,
}
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;

View file

@ -181,3 +181,131 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
}
}
</%helpers:shorthand>
// https://drafts.csswg.org/css-backgrounds-3/#border-image
<%helpers:shorthand name="border-image" products="gecko" sub_properties="border-image-outset
border-image-repeat border-image-slice border-image-source border-image-width">
use properties::longhands::{border_image_outset, border_image_repeat, border_image_slice};
use properties::longhands::{border_image_source, border_image_width};
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
% for name in "outset repeat slice source width".split():
let mut border_image_${name} = border_image_${name}::get_initial_specified_value();
% endfor
try!(input.try(|input| {
% for name in "outset repeat slice source width".split():
let mut ${name} = None;
% endfor
loop {
if slice.is_none() {
if let Ok(value) = input.try(|input| border_image_slice::parse(context, input)) {
slice = Some(value);
// Parse border image width and outset, if applicable.
let maybe_width_outset: Result<_, ()> = input.try(|input| {
try!(input.expect_delim('/'));
// Parse border image width, if applicable.
let w = input.try(|input|
border_image_width::parse(context, input)).ok();
// Parse border image outset if applicable.
let o = input.try(|input| {
try!(input.expect_delim('/'));
border_image_outset::parse(context, input)
}).ok();
Ok((w, o))
});
if let Ok((w, o)) = maybe_width_outset {
width = w;
outset = o;
}
continue
}
}
% for name in "source repeat".split():
if ${name}.is_none() {
if let Ok(value) = input.try(|input| border_image_${name}::parse(context, input)) {
${name} = Some(value);
continue
}
}
% endfor
break
}
let mut any = false;
% for name in "outset repeat slice source width".split():
any = any || ${name}.is_some();
% endfor
if any {
% for name in "outset repeat slice source width".split():
if let Some(b_${name}) = ${name} {
border_image_${name} = b_${name};
}
% endfor
Ok(())
} else {
Err(())
}
}));
Ok(Longhands {
% for name in "outset repeat slice source width".split():
border_image_${name}: Some(border_image_${name}),
% endfor
})
}
impl<'a> LonghandsToSerialize<'a> {
fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
% for name in "outset repeat slice source width".split():
let ${name} = if let DeclaredValue::Value(ref value) = *self.border_image_${name} {
Some(value)
} else {
None
};
% endfor
if let Some(source) = source {
try!(source.to_css(dest));
} else {
try!(write!(dest, "none"));
}
try!(write!(dest, " "));
if let Some(slice) = slice {
try!(slice.to_css(dest));
} else {
try!(write!(dest, "100%"));
}
try!(write!(dest, " / "));
if let Some(width) = width {
try!(width.to_css(dest));
} else {
try!(write!(dest, "1"));
}
try!(write!(dest, " / "));
if let Some(outset) = outset {
try!(outset.to_css(dest));
} else {
try!(write!(dest, "0"));
}
try!(write!(dest, " "));
if let Some(repeat) = repeat {
try!(repeat.to_css(dest));
} else {
try!(write!(dest, "stretch"));
}
Ok(())
}
}
</%helpers:shorthand>

View file

@ -0,0 +1,88 @@
/* 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::{border_image_outset, border_image_repeat, border_image_slice};
use style::properties::longhands::{border_image_source, border_image_width};
use style::properties::shorthands::border_image;
use style::stylesheets::Origin;
use url::Url;
#[test]
fn border_image_shorhand_should_parse_when_all_properties_specified() {
let url = Url::parse("http://localhost").unwrap();
let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill / 20px 40px / 10px \
round stretch");
let result = border_image::parse_value(&context, &mut parser).unwrap();
assert_eq!(result.border_image_source.unwrap(),
parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
assert_eq!(result.border_image_slice.unwrap(), parse_longhand!(border_image_slice, "30 30% 45 fill"));
assert_eq!(result.border_image_width.unwrap(), parse_longhand!(border_image_width, "20px 40px"));
assert_eq!(result.border_image_outset.unwrap(), parse_longhand!(border_image_outset, "10px"));
assert_eq!(result.border_image_repeat.unwrap(), parse_longhand!(border_image_repeat, "round stretch"));
}
#[test]
fn border_image_shorhand_should_parse_without_width() {
let url = Url::parse("http://localhost").unwrap();
let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill / / 10px round stretch");
let result = border_image::parse_value(&context, &mut parser).unwrap();
assert_eq!(result.border_image_source.unwrap(),
parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
assert_eq!(result.border_image_slice.unwrap(), parse_longhand!(border_image_slice, "30 30% 45 fill"));
assert_eq!(result.border_image_outset.unwrap(), parse_longhand!(border_image_outset, "10px"));
assert_eq!(result.border_image_repeat.unwrap(), parse_longhand!(border_image_repeat, "round stretch"));
assert_eq!(result.border_image_width.unwrap(), border_image_width::get_initial_specified_value());
}
#[test]
fn border_image_shorhand_should_parse_without_outset() {
let url = Url::parse("http://localhost").unwrap();
let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill / 20px 40px round");
let result = border_image::parse_value(&context, &mut parser).unwrap();
assert_eq!(result.border_image_source.unwrap(),
parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
assert_eq!(result.border_image_slice.unwrap(), parse_longhand!(border_image_slice, "30 30% 45 fill"));
assert_eq!(result.border_image_width.unwrap(), parse_longhand!(border_image_width, "20px 40px"));
assert_eq!(result.border_image_repeat.unwrap(), parse_longhand!(border_image_repeat, "round"));
assert_eq!(result.border_image_outset.unwrap(), border_image_outset::get_initial_specified_value());
}
#[test]
fn border_image_shorhand_should_parse_without_width_or_outset() {
let url = Url::parse("http://localhost").unwrap();
let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill round");
let result = border_image::parse_value(&context, &mut parser).unwrap();
assert_eq!(result.border_image_source.unwrap(),
parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
assert_eq!(result.border_image_slice.unwrap(), parse_longhand!(border_image_slice, "30 30% 45 fill"));
assert_eq!(result.border_image_repeat.unwrap(), parse_longhand!(border_image_repeat, "round"));
assert_eq!(result.border_image_width.unwrap(), border_image_width::get_initial_specified_value());
assert_eq!(result.border_image_outset.unwrap(), border_image_outset::get_initial_specified_value());
}
#[test]
fn border_image_shorhand_should_parse_with_just_source() {
let url = Url::parse("http://localhost").unwrap();
let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
let mut parser = Parser::new("linear-gradient(red, blue)");
let result = border_image::parse_value(&context, &mut parser).unwrap();
assert_eq!(result.border_image_source.unwrap(),
parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
assert_eq!(result.border_image_slice.unwrap(), border_image_slice::get_initial_specified_value());
assert_eq!(result.border_image_width.unwrap(), border_image_width::get_initial_specified_value());
assert_eq!(result.border_image_outset.unwrap(), border_image_outset::get_initial_specified_value());
assert_eq!(result.border_image_repeat.unwrap(), border_image_repeat::get_initial_specified_value());
}

View file

@ -62,6 +62,7 @@ macro_rules! parse_longhand {
}
mod basic_shape;
mod border;
mod font;
mod image;
mod inherited_text;