diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index c4006efea5f..0a6e1266b59 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -737,7 +737,182 @@ ${helpers.single_keyword("text-align-last", } +<%helpers:longhand name="text-emphasis-style" products="none" animatable="False"> + use computed_values::writing_mode::T as writing_mode; + use cssparser::ToCss; + use std::fmt; + use values::LocalToCss; + use values::NoViewportPercentage; + impl NoViewportPercentage for SpecifiedValue {} + + pub mod computed_value { + #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub enum T { + Keyword(Keyword), + None, + String(String), + } + + #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub struct Keyword { + pub fill: bool, + pub shape: super::ShapeKeyword, + } + } + + #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub enum SpecifiedValue { + Keyword(Keyword), + None, + String(String), + } + + impl ToCss for computed_value::T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + computed_value::T::Keyword(ref keyword) => keyword.to_css(dest), + computed_value::T::None => dest.write_str("none"), + computed_value::T::String(ref string) => write!(dest, "\"{}\"", string), + } + } + } + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Keyword(ref keyword) => keyword.to_css(dest), + SpecifiedValue::None => dest.write_str("none"), + SpecifiedValue::String(ref string) => write!(dest, "\"{}\"", string), + } + } + } + + #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub struct Keyword { + pub fill: Option, + pub shape: Option, + } + + impl ToCss for Keyword { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut has_fill = false; + if let Some(fill) = self.fill { + has_fill = true; + if fill { + try!(dest.write_str("filled")); + } else { + try!(dest.write_str("open")); + } + } + if let Some(shape) = self.shape { + if has_fill { + try!(dest.write_str(" ")); + } + try!(shape.to_css(dest)); + } + Ok(()) + } + } + impl ToCss for computed_value::Keyword { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if self.fill { + try!(dest.write_str("filled")); + } else { + try!(dest.write_str("open")); + } + try!(dest.write_str(" ")); + self.shape.to_css(dest) + } + } + + define_css_keyword_enum!(ShapeKeyword: + "dot" => Dot, + "circle" => Circle, + "double-circle" => DoubleCircle, + "triangle" => Triangle, + "sesame" => Sesame); + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T::None + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Context) -> computed_value::T { + match *self { + SpecifiedValue::Keyword(ref keyword) => { + let default_shape = if context.style().get_inheritedbox() + .writing_mode == writing_mode::horizontal_tb { + ShapeKeyword::Circle + } else { + ShapeKeyword::Sesame + }; + computed_value::T::Keyword(computed_value::Keyword { + fill: keyword.fill.unwrap_or(true), + shape: keyword.shape.unwrap_or(default_shape) + }) + }, + SpecifiedValue::None => computed_value::T::None, + SpecifiedValue::String(ref s) => { + let string = if s.len() > 1 { + s.chars().nth(0).unwrap().to_string() + } else { s.clone() }; + computed_value::T::String(string) + } + } + } + #[inline] + fn from_computed_value(computed: &computed_value::T) -> Self { + match *computed { + computed_value::T::Keyword(ref keyword) => SpecifiedValue::Keyword(Keyword { + fill: Some(keyword.fill), + shape: Some(keyword.shape) + }), + computed_value::T::None => SpecifiedValue::None, + computed_value::T::String(ref string) => SpecifiedValue::String(string.clone()) + } + } + } + + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + return Ok(SpecifiedValue::None); + } + + if let Ok(s) = input.try(|input| input.expect_string()) { + // Handle + Ok(SpecifiedValue::String(s.into_owned())) + } else { + // Handle a pair of keywords + let mut shape = input.try(ShapeKeyword::parse); + let fill = if input.try(|input| input.expect_ident_matching("filled")).is_ok() { + Some(true) + } else if input.try(|input| input.expect_ident_matching("open")).is_ok() { + Some(false) + } else { None }; + if let Err(_) = shape { + shape = input.try(ShapeKeyword::parse); + } + + // At least one of shape or fill must be handled + if let (None, Err(_)) = (fill, shape) { + Err(()) + } else { + Ok(SpecifiedValue::Keyword(Keyword { + fill: fill, + shape: shape.ok() + })) + } + } + } + // TODO(pcwalton): `full-width` ${helpers.single_keyword("text-transform", diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 613fe4e203e..b8f0d4ebd9f 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -1639,7 +1639,8 @@ pub fn cascade(viewport_size: Size2D, PropertyDeclaration::Color(_) | PropertyDeclaration::Position(_) | PropertyDeclaration::Float(_) | - PropertyDeclaration::TextDecoration${'' if product == 'servo' else 'Line'}(_) + PropertyDeclaration::TextDecoration${'' if product == 'servo' else 'Line'}(_) | + PropertyDeclaration::TextEmphasisStyle(_) ); if % if category_to_cascade_now == "early": diff --git a/tests/unit/style/parsing/inherited_text.rs b/tests/unit/style/parsing/inherited_text.rs new file mode 100644 index 00000000000..fe8e6f5faff --- /dev/null +++ b/tests/unit/style/parsing/inherited_text.rs @@ -0,0 +1,58 @@ +/* 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::stylesheets::Origin; +use url::Url; + +#[test] +fn text_emphasis_style_longhand_should_parse_properly() { + use style::properties::longhands::text_emphasis_style; + use style::properties::longhands::text_emphasis_style::{ShapeKeyword, SpecifiedValue, Keyword}; + + let none = parse_longhand!(text_emphasis_style, "none"); + assert_eq!(none, SpecifiedValue::None); + + let fill = parse_longhand!(text_emphasis_style, "open"); + let fill_struct = SpecifiedValue::Keyword(Keyword { + fill: Some(false), + shape: None + }); + assert_eq!(fill, fill_struct); + + let shape = parse_longhand!(text_emphasis_style, "triangle"); + let shape_struct = SpecifiedValue::Keyword(Keyword { + fill: None, + shape: Some(ShapeKeyword::Triangle) + }); + assert_eq!(shape, shape_struct); + + let fill_shape = parse_longhand!(text_emphasis_style, "filled dot"); + let fill_shape_struct = SpecifiedValue::Keyword(Keyword { + fill: Some(true), + shape: Some(ShapeKeyword::Dot) + }); + assert_eq!(fill_shape, fill_shape_struct); + + let shape_fill = parse_longhand!(text_emphasis_style, "dot filled"); + let shape_fill_struct = SpecifiedValue::Keyword(Keyword { + fill: Some(true), + shape: Some(ShapeKeyword::Dot) + }); + assert_eq!(shape_fill, shape_fill_struct); + + let a_string = parse_longhand!(text_emphasis_style, "\"a\""); + let a_string_struct = SpecifiedValue::String("a".to_string()); + assert_eq!(a_string, a_string_struct); + + let chinese_string = parse_longhand!(text_emphasis_style, "\"点\""); + let chinese_string_struct = SpecifiedValue::String("点".to_string()); + assert_eq!(chinese_string, chinese_string_struct); + + let unicode_string = parse_longhand!(text_emphasis_style, "\"\\25B2\""); + let unicode_string_struct = SpecifiedValue::String("▲".to_string()); + assert_eq!(unicode_string, unicode_string_struct); +} diff --git a/tests/unit/style/parsing/mod.rs b/tests/unit/style/parsing/mod.rs index c481ea865da..27c64180a59 100644 --- a/tests/unit/style/parsing/mod.rs +++ b/tests/unit/style/parsing/mod.rs @@ -63,6 +63,7 @@ macro_rules! parse_longhand { mod basic_shape; mod image; +mod inherited_text; mod mask; mod position; mod selectors;