From ace082b13319161886799b25e6f7fc178cece299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Sun, 13 Nov 2016 01:46:22 +0300 Subject: [PATCH 1/2] Implement border-image shorthand --- .../style/properties/longhand/border.mako.rs | 30 +++- .../style/properties/shorthand/border.mako.rs | 128 ++++++++++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index b0b8d0701ad..390767a7699 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -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; diff --git a/components/style/properties/shorthand/border.mako.rs b/components/style/properties/shorthand/border.mako.rs index ef04ab474f0..40318441827 100644 --- a/components/style/properties/shorthand/border.mako.rs +++ b/components/style/properties/shorthand/border.mako.rs @@ -180,3 +180,131 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) } } + +// 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 { + % 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(&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(()) + } + } + From e408b0e75cf40a7116fc6c2a29daa6acaf3242b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Sun, 13 Nov 2016 02:04:01 +0300 Subject: [PATCH 2/2] Add parsing tests for border-image shorthand --- tests/unit/style/parsing/border.rs | 88 ++++++++++++++++++++++++++++++ tests/unit/style/parsing/mod.rs | 1 + 2 files changed, 89 insertions(+) create mode 100644 tests/unit/style/parsing/border.rs diff --git a/tests/unit/style/parsing/border.rs b/tests/unit/style/parsing/border.rs new file mode 100644 index 00000000000..0739cb0eb78 --- /dev/null +++ b/tests/unit/style/parsing/border.rs @@ -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()); +} diff --git a/tests/unit/style/parsing/mod.rs b/tests/unit/style/parsing/mod.rs index f2fed25b7fd..47a52d470f6 100644 --- a/tests/unit/style/parsing/mod.rs +++ b/tests/unit/style/parsing/mod.rs @@ -62,6 +62,7 @@ macro_rules! parse_longhand { } mod basic_shape; +mod border; mod font; mod image; mod inherited_text;