diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index c2dd009c764..c4a20d1ee11 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -51,7 +51,6 @@ use style::computed_values::{background_attachment, background_clip, background_ use style::computed_values::{background_repeat, border_style, cursor}; use style::computed_values::{image_rendering, overflow_x, pointer_events, position, visibility}; use style::computed_values::filter::Filter; -use style::computed_values::text_shadow::TextShadow; use style::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode}; use style::properties::{self, ServoComputedValues}; use style::properties::longhands::border_image_repeat::computed_value::RepeatKeyword; @@ -59,7 +58,7 @@ use style::properties::style_structs; use style::servo::restyle_damage::REPAINT; use style::values::{Either, RGBA}; use style::values::computed::{Gradient, GradientItem, LengthOrPercentage}; -use style::values::computed::{LengthOrPercentageOrAuto, NumberOrPercentage, Position}; +use style::values::computed::{LengthOrPercentageOrAuto, NumberOrPercentage, Position, Shadow}; use style::values::computed::image::{EndingShape, LineDirection}; use style::values::generics::background::BackgroundSize; use style::values::generics::image::{Circle, Ellipse, EndingShape as GenericEndingShape}; @@ -504,7 +503,7 @@ pub trait FragmentDisplayListBuilding { state: &mut DisplayListBuildState, text_fragment: &ScannedTextFragmentInfo, stacking_relative_content_box: &Rect, - text_shadow: Option<&TextShadow>, + text_shadow: Option<&Shadow>, clip: &Rect); /// Creates the display item for a text decoration: underline, overline, or line-through. @@ -1949,7 +1948,7 @@ impl FragmentDisplayListBuilding for Fragment { state: &mut DisplayListBuildState, text_fragment: &ScannedTextFragmentInfo, stacking_relative_content_box: &Rect, - text_shadow: Option<&TextShadow>, + text_shadow: Option<&Shadow>, clip: &Rect) { // TODO(emilio): Allow changing more properties by ::selection let text_color = if let Some(shadow) = text_shadow { diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 3c8e359e4de..048f1b95979 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -64,7 +64,7 @@ use std::mem::{forget, transmute, zeroed}; use std::ptr; use stylearc::Arc; use std::cmp; -use values::computed::ToComputedValue; +use values::computed::{Shadow, ToComputedValue}; use values::{Either, Auto, KeyframesName}; use computed_values::border_style; @@ -3310,7 +3310,7 @@ fn static_assert() { <%self:impl_trait style_struct_name="Effects" skip_longhands="box-shadow clip filter"> pub fn set_box_shadow(&mut self, v: I) - where I: IntoIterator, + where I: IntoIterator, I::IntoIter: ExactSizeIterator { let v = v.into_iter(); @@ -3344,7 +3344,7 @@ fn static_assert() { pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T { let buf = self.gecko.mBoxShadow.iter().map(|shadow| { - longhands::box_shadow::single_value::computed_value::T { + Shadow { offset_x: Au(shadow.mXOffset), offset_y: Au(shadow.mYOffset), blur_radius: Au(shadow.mRadius), @@ -3617,12 +3617,15 @@ fn static_assert() { ${impl_keyword('text_align', 'mTextAlign', text_align_keyword, need_clone=False)} ${impl_keyword_clone('text_align', 'mTextAlign', text_align_keyword)} - pub fn set_text_shadow(&mut self, v: longhands::text_shadow::computed_value::T) { - self.gecko.mTextShadow.replace_with_new(v.0.len() as u32); + pub fn set_text_shadow(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + { + let v = v.into_iter(); - for (servo, gecko_shadow) in v.0.into_iter() - .zip(self.gecko.mTextShadow.iter_mut()) { + self.gecko.mTextShadow.replace_with_new(v.len() as u32); + for (servo, gecko_shadow) in v.zip(self.gecko.mTextShadow.iter_mut()) { gecko_shadow.mXOffset = servo.offset_x.0; gecko_shadow.mYOffset = servo.offset_y.0; gecko_shadow.mRadius = servo.blur_radius.0; @@ -3645,15 +3648,15 @@ fn static_assert() { } pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T { - let buf = self.gecko.mTextShadow.iter().map(|shadow| { - longhands::text_shadow::computed_value::TextShadow { + Shadow { offset_x: Au(shadow.mXOffset), offset_y: Au(shadow.mYOffset), blur_radius: Au(shadow.mRadius), + spread_radius: Au(0), color: Color::RGBA(convert_nscolor_to_rgba(shadow.mColor)), + inset: false, } - }).collect(); longhands::text_shadow::computed_value::T(buf) } diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index d98b66b8e29..81db00885c9 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -19,9 +19,7 @@ use properties::longhands::background_size::computed_value::T as BackgroundSizeL use properties::longhands::font_weight::computed_value::T as FontWeight; use properties::longhands::font_stretch::computed_value::T as FontStretch; use properties::longhands::text_shadow::computed_value::T as TextShadowList; -use properties::longhands::text_shadow::computed_value::TextShadow; use properties::longhands::box_shadow::computed_value::T as BoxShadowList; -use properties::longhands::box_shadow::single_value::computed_value::T as BoxShadow; use properties::longhands::transform::computed_value::ComputedMatrix; use properties::longhands::transform::computed_value::ComputedOperation as TransformOperation; use properties::longhands::transform::computed_value::T as TransformList; @@ -40,7 +38,7 @@ use values::{Auto, Either}; use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone}; use values::computed::{BorderCornerRadius, ClipRect}; use values::computed::{CalcLengthOrPercentage, Context, ComputedValueAsSpecified}; -use values::computed::{LengthOrPercentage, MaxLength, MozLength, ToComputedValue}; +use values::computed::{LengthOrPercentage, MaxLength, MozLength, Shadow, ToComputedValue}; use values::generics::{SVGPaint, SVGPaintKind}; use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use values::generics::position as generic_position; @@ -1457,132 +1455,6 @@ impl Animatable for ClipRect { } } -<%def name="impl_animatable_for_shadow(item, transparent_color)"> - impl Animatable for ${item} { - #[inline] - fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result { - % if "Box" in item: - // It can't be interpolated if inset does not match. - if self.inset != other.inset { - return Err(()); - } - % endif - - let x = try!(self.offset_x.add_weighted(&other.offset_x, self_portion, other_portion)); - let y = try!(self.offset_y.add_weighted(&other.offset_y, self_portion, other_portion)); - let color = try!(self.color.add_weighted(&other.color, self_portion, other_portion)); - let blur = try!(self.blur_radius.add_weighted(&other.blur_radius, - self_portion, other_portion)); - % if "Box" in item: - let spread = try!(self.spread_radius.add_weighted(&other.spread_radius, - self_portion, other_portion)); - % endif - - Ok(${item} { - offset_x: x, - offset_y: y, - blur_radius: blur, - color: color, - % if "Box" in item: - spread_radius: spread, - inset: self.inset, - % endif - }) - } - - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - self.compute_squared_distance(other).map(|sd| sd.sqrt()) - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - % if "Box" in item: - if self.inset != other.inset { - return Err(()); - } - % endif - let list = [ try!(self.offset_x.compute_distance(&other.offset_x)), - try!(self.offset_y.compute_distance(&other.offset_y)), - try!(self.blur_radius.compute_distance(&other.blur_radius)), - try!(self.color.compute_distance(&other.color)), - % if "Box" in item: - try!(self.spread_radius.compute_distance(&other.spread_radius)), - % endif - ]; - Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff)) - } - } - - /// https://drafts.csswg.org/css-transitions/#animtype-shadow-list - impl Animatable for ${item}List { - #[inline] - fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result { - // The inset value must change - % if "Box" in item: - let mut zero = ${item} { - % else: - let zero = ${item} { - % endif - offset_x: Au(0), - offset_y: Au(0), - blur_radius: Au(0), - color: ${transparent_color}, - % if "Box" in item: - spread_radius: Au(0), - inset: false, - % endif - }; - - let max_len = cmp::max(self.0.len(), other.0.len()); - - let mut result = if max_len > 1 { - SmallVec::from_vec(Vec::with_capacity(max_len)) - } else { - SmallVec::new() - }; - - for i in 0..max_len { - let shadow = match (self.0.get(i), other.0.get(i)) { - (Some(shadow), Some(other)) - => try!(shadow.add_weighted(other, self_portion, other_portion)), - (Some(shadow), None) => { - % if "Box" in item: - zero.inset = shadow.inset; - % endif - shadow.add_weighted(&zero, self_portion, other_portion).unwrap() - } - (None, Some(shadow)) => { - % if "Box" in item: - zero.inset = shadow.inset; - % endif - zero.add_weighted(&shadow, self_portion, other_portion).unwrap() - } - (None, None) => unreachable!(), - }; - result.push(shadow); - } - - Ok(${item}List(result)) - } - - fn add(&self, other: &Self) -> Result { - let len = self.0.len() + other.0.len(); - - let mut result = if len > 1 { - SmallVec::from_vec(Vec::with_capacity(len)) - } else { - SmallVec::new() - }; - - result.extend(self.0.iter().cloned()); - result.extend(other.0.iter().cloned()); - - Ok(${item}List(result)) - } - } - - /// Check if it's possible to do a direct numerical interpolation /// between these two transform lists. /// http://dev.w3.org/csswg/css-transforms/#transform-transform-animation @@ -2922,74 +2794,183 @@ impl Animatable for IntermediateSVGPaintKind { } } -<%def name="impl_intermediate_type_for_shadow(type)"> - #[derive(Copy, Clone, Debug, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - #[allow(missing_docs)] - /// Intermediate type for box-shadow and text-shadow. - /// The difference between normal shadow type is that this type uses - /// IntermediateColor instead of ParserColor. - pub struct Intermediate${type}Shadow { - pub offset_x: Au, - pub offset_y: Au, - pub blur_radius: Au, - pub color: IntermediateColor, - % if type == "Box": - pub spread_radius: Au, - pub inset: bool, - % endif +#[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[allow(missing_docs)] +/// Intermediate type for box-shadow and text-shadow. +/// The difference between normal shadow type is that this type uses +/// IntermediateColor instead of ParserColor. +pub struct IntermediateShadow { + pub offset_x: Au, + pub offset_y: Au, + pub blur_radius: Au, + pub spread_radius: Au, + pub color: IntermediateColor, + pub inset: bool, +} + +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[allow(missing_docs)] +/// Intermediate type for box-shadow list and text-shadow list. +pub struct IntermediateShadowList(pub SmallVec<[IntermediateShadow; 1]>); + +type ShadowList = SmallVec<[Shadow; 1]>; + +impl From for ShadowList { + fn from(shadow_list: IntermediateShadowList) -> Self { + shadow_list.0.into_iter().map(|s| s.into()).collect() } +} - #[derive(Clone, Debug, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - #[allow(missing_docs)] - /// Intermediate type for box-shadow list and text-shadow list. - pub struct Intermediate${type}ShadowList(pub SmallVec<[Intermediate${type}Shadow; 1]>); +impl From for IntermediateShadowList { + fn from(shadow_list: ShadowList) -> IntermediateShadowList { + IntermediateShadowList(shadow_list.into_iter().map(|s| s.into()).collect()) + } +} - impl From for ${type}ShadowList { - fn from(shadow_list: Intermediate${type}ShadowList) -> ${type}ShadowList { - ${type}ShadowList(shadow_list.0.into_iter().map(|s| s.into()).collect()) +% for ty in "Box Text".split(): +impl From for ${ty}ShadowList { + #[inline] + fn from(shadow_list: IntermediateShadowList) -> Self { + ${ty}ShadowList(shadow_list.into()) + } +} + +impl From<${ty}ShadowList> for IntermediateShadowList { + #[inline] + fn from(shadow_list: ${ty}ShadowList) -> IntermediateShadowList { + shadow_list.0.into() + } +} +% endfor + +impl From for Shadow { + fn from(shadow: IntermediateShadow) -> Shadow { + Shadow { + offset_x: shadow.offset_x, + offset_y: shadow.offset_y, + blur_radius: shadow.blur_radius, + spread_radius: shadow.spread_radius, + color: shadow.color.into(), + inset: shadow.inset, } } +} - impl From<${type}ShadowList> for Intermediate${type}ShadowList { - fn from(shadow_list: ${type}ShadowList) -> Intermediate${type}ShadowList { - Intermediate${type}ShadowList(shadow_list.0.into_iter().map(|s| s.into()).collect()) +impl From for IntermediateShadow { + fn from(shadow: Shadow) -> IntermediateShadow { + IntermediateShadow { + offset_x: shadow.offset_x, + offset_y: shadow.offset_y, + blur_radius: shadow.blur_radius, + spread_radius: shadow.spread_radius, + color: shadow.color.into(), + inset: shadow.inset, } } +} - impl From for ${type}Shadow { - fn from(shadow: Intermediate${type}Shadow) -> ${type}Shadow { - ${type}Shadow { - offset_x: shadow.offset_x, - offset_y: shadow.offset_y, - blur_radius: shadow.blur_radius, - color: shadow.color.into(), - % if type == "Box": - spread_radius: shadow.spread_radius, - inset: shadow.inset, - % endif - } +impl Animatable for IntermediateShadow { + #[inline] + fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result { + // It can't be interpolated if inset does not match. + if self.inset != other.inset { + return Err(()); } + + let x = try!(self.offset_x.add_weighted(&other.offset_x, self_portion, other_portion)); + let y = try!(self.offset_y.add_weighted(&other.offset_y, self_portion, other_portion)); + let color = try!(self.color.add_weighted(&other.color, self_portion, other_portion)); + let blur = try!(self.blur_radius.add_weighted(&other.blur_radius, + self_portion, other_portion)); + let spread = try!(self.spread_radius.add_weighted(&other.spread_radius, + self_portion, other_portion)); + + Ok(IntermediateShadow { + offset_x: x, + offset_y: y, + blur_radius: blur, + spread_radius: spread, + color: color, + inset: self.inset, + }) } - impl From<${type}Shadow> for Intermediate${type}Shadow { - fn from(shadow: ${type}Shadow) -> Intermediate${type}Shadow { - Intermediate${type}Shadow { - offset_x: shadow.offset_x, - offset_y: shadow.offset_y, - blur_radius: shadow.blur_radius, - color: shadow.color.into(), - % if type == "Box": - spread_radius: shadow.spread_radius, - inset: shadow.inset, - % endif - } - } + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) } - ${impl_animatable_for_shadow('Intermediate%sShadow' % type, - 'IntermediateColor::IntermediateRGBA(IntermediateRGBA::transparent())')} - -${impl_intermediate_type_for_shadow('Box')} -${impl_intermediate_type_for_shadow('Text')} + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result { + if self.inset != other.inset { + return Err(()); + } + let list = [ try!(self.offset_x.compute_distance(&other.offset_x)), + try!(self.offset_y.compute_distance(&other.offset_y)), + try!(self.blur_radius.compute_distance(&other.blur_radius)), + try!(self.color.compute_distance(&other.color)), + try!(self.spread_radius.compute_distance(&other.spread_radius)), + ]; + Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff)) + } +} + +/// https://drafts.csswg.org/css-transitions/#animtype-shadow-list +impl Animatable for IntermediateShadowList { + #[inline] + fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result { + // The inset value must change + let mut zero = IntermediateShadow { + offset_x: Au(0), + offset_y: Au(0), + blur_radius: Au(0), + spread_radius: Au(0), + color: IntermediateColor::IntermediateRGBA(IntermediateRGBA::transparent()), + inset: false, + }; + + let max_len = cmp::max(self.0.len(), other.0.len()); + + let mut result = if max_len > 1 { + SmallVec::from_vec(Vec::with_capacity(max_len)) + } else { + SmallVec::new() + }; + + for i in 0..max_len { + let shadow = match (self.0.get(i), other.0.get(i)) { + (Some(shadow), Some(other)) => + try!(shadow.add_weighted(other, self_portion, other_portion)), + (Some(shadow), None) => { + zero.inset = shadow.inset; + shadow.add_weighted(&zero, self_portion, other_portion).unwrap() + } + (None, Some(shadow)) => { + zero.inset = shadow.inset; + zero.add_weighted(&shadow, self_portion, other_portion).unwrap() + } + (None, None) => unreachable!(), + }; + result.push(shadow); + } + + Ok(IntermediateShadowList(result)) + } + + fn add(&self, other: &Self) -> Result { + let len = self.0.len() + other.0.len(); + + let mut result = if len > 1 { + SmallVec::from_vec(Vec::with_capacity(len)) + } else { + SmallVec::new() + }; + + result.extend(self.0.iter().cloned()); + result.extend(other.0.iter().cloned()); + + Ok(IntermediateShadowList(result)) + } +} diff --git a/components/style/properties/longhand/effects.mako.rs b/components/style/properties/longhand/effects.mako.rs index d78d1911ff3..ecb6fe0720f 100644 --- a/components/style/properties/longhand/effects.mako.rs +++ b/components/style/properties/longhand/effects.mako.rs @@ -15,7 +15,7 @@ ${helpers.predefined_type("opacity", spec="https://drafts.csswg.org/css-color/#opacity")} <%helpers:vector_longhand name="box-shadow" allow_empty="True" - animation_value_type="IntermediateBoxShadowList" + animation_value_type="IntermediateShadowList" extra_prefixes="webkit" ignored_when_colors_disabled="True" spec="https://drafts.csswg.org/css-backgrounds/#box-shadow"> diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index 690d50d7908..9b4004712ec 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -401,149 +401,20 @@ ${helpers.predefined_type("word-spacing", % endif -<%helpers:longhand name="text-shadow" - animation_value_type="IntermediateTextShadowList", - ignored_when_colors_disabled="True", - spec="https://drafts.csswg.org/css-text-decor/#propdef-text-shadow"> - use cssparser; - use std::fmt; - use style_traits::ToCss; - use values::specified::Shadow; - - #[derive(Clone, Debug, HasViewportPercentage, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct SpecifiedValue(Vec); - - #[derive(Clone, Debug, HasViewportPercentage, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct SpecifiedTextShadow { - pub offset_x: specified::Length, - pub offset_y: specified::Length, - pub blur_radius: specified::Length, - pub color: Option, - } - - impl From for SpecifiedTextShadow { - fn from(shadow: Shadow) -> SpecifiedTextShadow { - SpecifiedTextShadow { - offset_x: shadow.offset_x, - offset_y: shadow.offset_y, - blur_radius: shadow.blur_radius, - color: shadow.color, - } - } - } - +<%helpers:vector_longhand name="text-shadow" allow_empty="True" + animation_value_type="IntermediateShadowList" + ignored_when_colors_disabled="True" + spec="https://drafts.csswg.org/css-backgrounds/#box-shadow"> + pub type SpecifiedValue = specified::Shadow; pub mod computed_value { - use app_units::Au; - use cssparser::Color; - use smallvec::SmallVec; - - #[derive(Clone, PartialEq, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct T(pub SmallVec<[TextShadow; 1]>); - - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - #[derive(Clone, PartialEq, Debug, ToCss)] - pub struct TextShadow { - pub offset_x: Au, - pub offset_y: Au, - pub blur_radius: Au, - pub color: Color, - } + use values::computed::Shadow; + pub type T = Shadow; } - impl ToCss for computed_value::T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut iter = self.0.iter(); - match iter.next() { - Some(shadow) => shadow.to_css(dest)?, - None => return dest.write_str("none"), - } - for shadow in iter { - dest.write_str(", ")?; - shadow.to_css(dest)?; - } - Ok(()) - } + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + specified::Shadow::parse(context, input, true) } - - impl ToCss for SpecifiedValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - let mut iter = self.0.iter(); - match iter.next() { - Some(shadow) => shadow.to_css(dest)?, - None => return dest.write_str("none"), - } - for shadow in iter { - dest.write_str(", ")?; - shadow.to_css(dest)?; - } - Ok(()) - } - } - - impl ToCss for SpecifiedTextShadow { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - self.offset_x.to_css(dest)?; - dest.write_str(" ")?; - self.offset_y.to_css(dest)?; - dest.write_str(" ")?; - self.blur_radius.to_css(dest)?; - - if let Some(ref color) = self.color { - dest.write_str(" ")?; - color.to_css(dest)?; - } - Ok(()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - use smallvec::SmallVec; - computed_value::T(SmallVec::new()) - } - - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { - if input.try(|input| input.expect_ident_matching("none")).is_ok() { - Ok(SpecifiedValue(Vec::new())) - } else { - input.parse_comma_separated(|i| { - Ok(SpecifiedTextShadow::from(Shadow::parse(context, i, true)?)) - }).map(SpecifiedValue) - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - fn to_computed_value(&self, context: &Context) -> computed_value::T { - computed_value::T(self.0.iter().map(|value| { - computed_value::TextShadow { - offset_x: value.offset_x.to_computed_value(context), - offset_y: value.offset_y.to_computed_value(context), - blur_radius: value.blur_radius.to_computed_value(context), - color: value.color - .as_ref() - .map(|color| color.to_computed_value(context)) - .unwrap_or(cssparser::Color::CurrentColor), - } - }).collect()) - } - - fn from_computed_value(computed: &computed_value::T) -> Self { - SpecifiedValue(computed.0.iter().map(|value| { - SpecifiedTextShadow { - offset_x: ToComputedValue::from_computed_value(&value.offset_x), - offset_y: ToComputedValue::from_computed_value(&value.offset_y), - blur_radius: ToComputedValue::from_computed_value(&value.blur_radius), - color: Some(ToComputedValue::from_computed_value(&value.color)), - } - }).collect()) - } - } - + <%helpers:longhand name="text-emphasis-style" products="gecko" need_clone="True" boxed="True" animation_value_type="none"