From 6102159a4b4e3f7fe5b817ea7576731a5f902492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Thu, 20 Oct 2016 22:25:20 +0300 Subject: [PATCH 1/3] Implement parsing/serialization for text-emphasis-style --- .../longhand/inherited_text.mako.rs | 175 ++++++++++++++++++ .../style/properties/properties.mako.rs | 3 +- tests/unit/style/parsing/inherited_text.rs | 58 ++++++ tests/unit/style/parsing/mod.rs | 1 + 4 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 tests/unit/style/parsing/inherited_text.rs 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; From 769129f5c23dcd86a34ea6a2ae6311875bb80e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Sat, 22 Oct 2016 01:37:52 +0300 Subject: [PATCH 2/3] Add gecko glue for text-emphasis-style --- components/style/properties/gecko.mako.rs | 51 +++++++++++++++- .../longhand/inherited_text.mako.rs | 58 +++++++++++-------- .../style/properties/properties.mako.rs | 2 +- 3 files changed, 86 insertions(+), 25 deletions(-) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 24602685308..52e547640be 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1573,7 +1573,7 @@ fn static_assert() { <%self:impl_trait style_struct_name="InheritedText" - skip_longhands="text-align text-shadow line-height letter-spacing word-spacing"> + skip_longhands="text-align text-emphasis-style text-shadow line-height letter-spacing word-spacing"> <% text_align_keyword = Keyword("text-align", "start end left right center justify -moz-center -moz-left " + "-moz-right match-parent") %> @@ -1671,6 +1671,55 @@ fn static_assert() { <%call expr="impl_coord_copy('word_spacing', 'mWordSpacing')"> + fn clear_text_emphasis_style_if_string(&mut self) { + use nsstring::nsString; + if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 { + self.gecko.mTextEmphasisStyleString.assign(&nsString::new()); + self.gecko.mTextEmphasisStyle = structs::NS_STYLE_TEXT_EMPHASIS_STYLE_NONE as u8; + } + } + + pub fn set_text_emphasis_style(&mut self, v: longhands::text_emphasis_style::computed_value::T) { + use nsstring::nsCString; + use properties::longhands::text_emphasis_style::computed_value::T; + use properties::longhands::text_emphasis_style::ShapeKeyword; + + self.clear_text_emphasis_style_if_string(); + let (te, s) = match v { + T::None => (structs::NS_STYLE_TEXT_EMPHASIS_STYLE_NONE, ""), + T::Keyword(ref keyword) => { + let fill = if keyword.fill { + structs::NS_STYLE_TEXT_EMPHASIS_STYLE_FILLED + } else { + structs::NS_STYLE_TEXT_EMPHASIS_STYLE_OPEN + }; + let shape = match keyword.shape { + ShapeKeyword::Dot => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_DOT, + ShapeKeyword::Circle => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_CIRCLE, + ShapeKeyword::DoubleCircle => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_DOUBLE_CIRCLE, + ShapeKeyword::Triangle => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_TRIANGLE, + ShapeKeyword::Sesame => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_SESAME, + }; + + (shape | fill, keyword.shape.char(keyword.fill)) + }, + T::String(ref s) => { + (structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING, &**s) + }, + }; + self.gecko.mTextEmphasisStyleString.assign_utf8(&nsCString::from(s)); + self.gecko.mTextEmphasisStyle = te as u8; + } + + pub fn copy_text_emphasis_style_from(&mut self, other: &Self) { + self.clear_text_emphasis_style_if_string(); + if other.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 { + self.gecko.mTextEmphasisStyleString + .assign(&other.gecko.mTextEmphasisStyleString) + } + self.gecko.mTextEmphasisStyle = other.gecko.mTextEmphasisStyle; + } + <%self:impl_trait style_struct_name="Text" diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index 0a6e1266b59..535486ea48e 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -737,7 +737,7 @@ ${helpers.single_keyword("text-align-last", } -<%helpers:longhand name="text-emphasis-style" products="none" animatable="False"> +<%helpers:longhand name="text-emphasis-style" products="gecko" need_clone="True" animatable="False"> use computed_values::writing_mode::T as writing_mode; use cssparser::ToCss; use std::fmt; @@ -836,6 +836,18 @@ ${helpers.single_keyword("text-align-last", "triangle" => Triangle, "sesame" => Sesame); + impl ShapeKeyword { + pub fn char(&self, fill: bool) -> &str { + match *self { + ShapeKeyword::Dot => if fill { "\u{2022}" } else { "\u{25e6}" }, + ShapeKeyword::Circle => if fill { "\u{25cf}" } else { "\u{25cb}" }, + ShapeKeyword::DoubleCircle => if fill { "\u{25c9}" } else { "\u{25ce}" }, + ShapeKeyword::Triangle => if fill { "\u{25b2}" } else { "\u{25b3}" }, + ShapeKeyword::Sesame => if fill { "\u{fe45}" } else { "\u{fe46}" }, + } + } + } + #[inline] pub fn get_initial_value() -> computed_value::T { computed_value::T::None @@ -849,7 +861,7 @@ ${helpers.single_keyword("text-align-last", match *self { SpecifiedValue::Keyword(ref keyword) => { let default_shape = if context.style().get_inheritedbox() - .writing_mode == writing_mode::horizontal_tb { + .clone_writing_mode() == writing_mode::horizontal_tb { ShapeKeyword::Circle } else { ShapeKeyword::Sesame @@ -888,28 +900,28 @@ ${helpers.single_keyword("text-align-last", 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); - } + return Ok(SpecifiedValue::String(s.into_owned())); + } - // 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() - })) - } + // 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() + })) } } diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index b8f0d4ebd9f..bfa7c7e9edf 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -1640,7 +1640,7 @@ pub fn cascade(viewport_size: Size2D, PropertyDeclaration::Position(_) | PropertyDeclaration::Float(_) | PropertyDeclaration::TextDecoration${'' if product == 'servo' else 'Line'}(_) | - PropertyDeclaration::TextEmphasisStyle(_) + PropertyDeclaration::WritingMode(_) ); if % if category_to_cascade_now == "early": From 6dc2c36310ec13606a6d4bef656d501b4272eb96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Sun, 23 Oct 2016 02:38:36 +0300 Subject: [PATCH 3/3] Change KeywordValue to enum --- .../longhand/inherited_text.mako.rs | 75 +++++++++++-------- tests/unit/style/parsing/inherited_text.rs | 22 ++---- 2 files changed, 48 insertions(+), 49 deletions(-) diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index 535486ea48e..2d9c93dc836 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -750,14 +750,14 @@ ${helpers.single_keyword("text-align-last", #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum T { - Keyword(Keyword), + Keyword(KeywordValue), None, String(String), } #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct Keyword { + pub struct KeywordValue { pub fill: bool, pub shape: super::ShapeKeyword, } @@ -766,7 +766,7 @@ ${helpers.single_keyword("text-align-last", #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum SpecifiedValue { - Keyword(Keyword), + Keyword(KeywordValue), None, String(String), } @@ -792,24 +792,23 @@ ${helpers.single_keyword("text-align-last", #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct Keyword { - pub fill: Option, - pub shape: Option, + pub enum KeywordValue { + Fill(bool), + Shape(ShapeKeyword), + FillAndShape(bool, ShapeKeyword), } - impl ToCss for Keyword { + impl ToCss for KeywordValue { 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 let Some(fill) = self.fill() { if fill { try!(dest.write_str("filled")); } else { try!(dest.write_str("open")); } } - if let Some(shape) = self.shape { - if has_fill { + if let Some(shape) = self.shape() { + if self.fill().is_some() { try!(dest.write_str(" ")); } try!(shape.to_css(dest)); @@ -817,7 +816,7 @@ ${helpers.single_keyword("text-align-last", Ok(()) } } - impl ToCss for computed_value::Keyword { + impl ToCss for computed_value::KeywordValue { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { if self.fill { try!(dest.write_str("filled")); @@ -829,6 +828,23 @@ ${helpers.single_keyword("text-align-last", } } + impl KeywordValue { + fn fill(&self) -> Option { + match *self { + KeywordValue::Fill(fill) | + KeywordValue::FillAndShape(fill,_) => Some(fill), + _ => None, + } + } + fn shape(&self) -> Option { + match *self { + KeywordValue::Shape(shape) | + KeywordValue::FillAndShape(_, shape) => Some(shape), + _ => None, + } + } + } + define_css_keyword_enum!(ShapeKeyword: "dot" => Dot, "circle" => Circle, @@ -866,16 +882,14 @@ ${helpers.single_keyword("text-align-last", } else { ShapeKeyword::Sesame }; - computed_value::T::Keyword(computed_value::Keyword { - fill: keyword.fill.unwrap_or(true), - shape: keyword.shape.unwrap_or(default_shape) + computed_value::T::Keyword(computed_value::KeywordValue { + 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() }; + let string = s.chars().next().as_ref().map(ToString::to_string).unwrap_or_default(); computed_value::T::String(string) } } @@ -883,10 +897,8 @@ ${helpers.single_keyword("text-align-last", #[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::Keyword(ref keyword) => + SpecifiedValue::Keyword(KeywordValue::FillAndShape(keyword.fill,keyword.shape)), computed_value::T::None => SpecifiedValue::None, computed_value::T::String(ref string) => SpecifiedValue::String(string.clone()) } @@ -910,19 +922,18 @@ ${helpers.single_keyword("text-align-last", } else if input.try(|input| input.expect_ident_matching("open")).is_ok() { Some(false) } else { None }; - if let Err(_) = shape { + if shape.is_err() { 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() - })) - } + let keyword_value = match (fill, shape) { + (Some(fill), Ok(shape)) => KeywordValue::FillAndShape(fill,shape), + (Some(fill), Err(_)) => KeywordValue::Fill(fill), + (None, Ok(shape)) => KeywordValue::Shape(shape), + _ => return Err(()), + }; + Ok(SpecifiedValue::Keyword(keyword_value)) } diff --git a/tests/unit/style/parsing/inherited_text.rs b/tests/unit/style/parsing/inherited_text.rs index fe8e6f5faff..4248107b0c0 100644 --- a/tests/unit/style/parsing/inherited_text.rs +++ b/tests/unit/style/parsing/inherited_text.rs @@ -11,37 +11,25 @@ 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}; + use style::properties::longhands::text_emphasis_style::{ShapeKeyword, SpecifiedValue, KeywordValue}; 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 - }); + let fill_struct = SpecifiedValue::Keyword(KeywordValue::Fill(false)); 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) - }); + let shape_struct = SpecifiedValue::Keyword(KeywordValue::Shape(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) - }); + let fill_shape_struct = SpecifiedValue::Keyword(KeywordValue::FillAndShape(true, 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) - }); + let shape_fill_struct = SpecifiedValue::Keyword(KeywordValue::FillAndShape(true, ShapeKeyword::Dot)); assert_eq!(shape_fill, shape_fill_struct); let a_string = parse_longhand!(text_emphasis_style, "\"a\"");