From 7827ca6bb5faa78dbaf108e1cd6c499a966e52bc Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 2 Aug 2017 09:27:48 +1000 Subject: [PATCH] Make stroke-dasharray accept context-value. --- components/style/properties/gecko.mako.rs | 46 +++++++++++++------ .../helpers/animated_properties.mako.rs | 44 +++++++++++++++++- .../properties/longhand/inherited_svg.mako.rs | 7 +-- components/style/values/computed/mod.rs | 2 +- components/style/values/computed/svg.rs | 9 ++++ components/style/values/generics/svg.rs | 36 ++++++++++++++- components/style/values/specified/mod.rs | 2 +- components/style/values/specified/svg.rs | 20 +++++++- 8 files changed, 143 insertions(+), 23 deletions(-) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index dc2f8df4ab1..09bb7d8397e 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -4981,27 +4981,41 @@ clip-path ${impl_simple_copy('paint_order', 'mPaintOrder')} - pub fn set_stroke_dasharray(&mut self, v: I) - where I: IntoIterator, - I::IntoIter: ExactSizeIterator - { - let v = v.into_iter(); - unsafe { - bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, v.len() as u32); - } + pub fn set_stroke_dasharray(&mut self, v: longhands::stroke_dasharray::computed_value::T) { + use gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE; + use values::generics::svg::SVGStrokeDashArray; - for (mut gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v) { - match servo { - Either::First(number) => gecko.set_value(CoordDataValue::Factor(number)), - Either::Second(lop) => gecko.set(lop), + match v { + SVGStrokeDashArray::Values(v) => { + let v = v.into_iter(); + self.gecko.mContextFlags &= !CONTEXT_VALUE; + unsafe { + bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, v.len() as u32); + } + for (mut gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v) { + match servo { + Either::First(number) => gecko.set_value(CoordDataValue::Factor(number)), + Either::Second(lop) => gecko.set(lop), + } + } + } + SVGStrokeDashArray::ContextValue => { + self.gecko.mContextFlags |= CONTEXT_VALUE; + unsafe { + bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, 0); + } } } } pub fn copy_stroke_dasharray_from(&mut self, other: &Self) { + use gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE; unsafe { bindings::Gecko_nsStyleSVG_CopyDashArray(&mut self.gecko, &other.gecko); } + self.gecko.mContextFlags = + (self.gecko.mContextFlags & !CONTEXT_VALUE) | + (other.gecko.mContextFlags & CONTEXT_VALUE); } pub fn reset_stroke_dasharray(&mut self, other: &Self) { @@ -5009,8 +5023,14 @@ clip-path } pub fn clone_stroke_dasharray(&self) -> longhands::stroke_dasharray::computed_value::T { + use gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE; use values::computed::LengthOrPercentage; + use values::generics::svg::SVGStrokeDashArray; + if self.gecko.mContextFlags & CONTEXT_VALUE != 0 { + debug_assert_eq!(self.gecko.mStrokeDasharray.len(), 0); + return SVGStrokeDashArray::ContextValue; + } let mut vec = vec![]; for gecko in self.gecko.mStrokeDasharray.iter() { match gecko.as_value() { @@ -5024,7 +5044,7 @@ clip-path _ => unreachable!(), } } - longhands::stroke_dasharray::computed_value::T(vec) + SVGStrokeDashArray::Values(vec) } #[allow(non_snake_case)] diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index e457a9c7b06..3ddbac0b2b7 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -46,7 +46,7 @@ use values::computed::{LengthOrPercentage, MaxLength, MozLength, Percentage, ToC use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use values::generics::effects::Filter; use values::generics::position as generic_position; -use values::generics::svg::{SVGLength, SVGPaint, SVGPaintKind}; +use values::generics::svg::{SVGLength, SVGPaint, SVGPaintKind, SVGStrokeDashArray}; /// A trait used to implement various procedures used during animation. pub trait Animatable: Sized { @@ -3074,6 +3074,48 @@ impl ToAnimatedZero for SVGLength where LengthType : ToA } } +impl Animatable for SVGStrokeDashArray + where LengthType : RepeatableListAnimatable + Clone +{ + #[inline] + fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result { + match (self, other) { + (&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other))=> { + this.add_weighted(other, self_portion, other_portion) + .map(SVGStrokeDashArray::Values) + } + _ => { + Ok(if self_portion > other_portion { self.clone() } else { other.clone() }) + } + } + } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + match (self, other) { + (&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other)) => { + this.compute_distance(other) + } + _ => Err(()) + } + } +} + +impl ToAnimatedZero for SVGStrokeDashArray + where LengthType : ToAnimatedZero + Clone +{ + #[inline] + fn to_animated_zero(&self) -> Result { + match self { + &SVGStrokeDashArray::Values(ref values) => { + values.iter().map(ToAnimatedZero::to_animated_zero) + .collect::, ()>>().map(SVGStrokeDashArray::Values) + } + &SVGStrokeDashArray::ContextValue => Ok(SVGStrokeDashArray::ContextValue), + } + } +} + <% FILTER_FUNCTIONS = [ 'Blur', 'Brightness', 'Contrast', 'Grayscale', 'HueRotate', 'Invert', 'Opacity', 'Saturate', diff --git a/components/style/properties/longhand/inherited_svg.mako.rs b/components/style/properties/longhand/inherited_svg.mako.rs index 89e12afa594..5e95b81f8c5 100644 --- a/components/style/properties/longhand/inherited_svg.mako.rs +++ b/components/style/properties/longhand/inherited_svg.mako.rs @@ -91,13 +91,10 @@ ${helpers.predefined_type("stroke-opacity", "Opacity", "1.0", ${helpers.predefined_type( "stroke-dasharray", - "LengthOrPercentageOrNumber", - None, - "parse_non_negative", - vector=True, + "SVGStrokeDashArray", + "Default::default()", products="gecko", animation_value_type="ComputedValue", - separator="CommaWithSpace", spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing", )} diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 2c57ee214bb..e795e46436b 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -44,7 +44,7 @@ pub use super::specified::url::SpecifiedUrl; pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNone, LengthOrNumber, LengthOrPercentage}; pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength, Percentage}; pub use self::position::Position; -pub use self::svg::{SVGLength, SVGPaint, SVGPaintKind}; +pub use self::svg::{SVGLength, SVGPaint, SVGPaintKind, SVGStrokeDashArray}; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing}; pub use self::transform::{TimingFunction, TransformOrigin}; diff --git a/components/style/values/computed/svg.rs b/components/style/values/computed/svg.rs index 2a25922be91..c75df522adc 100644 --- a/components/style/values/computed/svg.rs +++ b/components/style/values/computed/svg.rs @@ -42,3 +42,12 @@ impl From for SVGLength { generic::SVGLength::Length(Either::Second(length.into())) } } + +/// [ | | ]# | context-value +pub type SVGStrokeDashArray = generic::SVGStrokeDashArray; + +impl Default for SVGStrokeDashArray { + fn default() -> Self { + generic::SVGStrokeDashArray::Values(vec![]) + } +} diff --git a/components/style/values/generics/svg.rs b/components/style/values/generics/svg.rs index 3310673383f..4ed833a9600 100644 --- a/components/style/values/generics/svg.rs +++ b/components/style/values/generics/svg.rs @@ -6,7 +6,8 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; -use style_traits::{ParseError, StyleParseError}; +use std::fmt; +use style_traits::{ParseError, StyleParseError, ToCss}; use values::specified::url::SpecifiedUrl; /// An SVG paint value @@ -104,3 +105,36 @@ pub enum SVGLength { /// `context-value` ContextValue, } + +/// Generic value for stroke-dasharray. +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, PartialEq, HasViewportPercentage, ToComputedValue)] +pub enum SVGStrokeDashArray { + /// `[ | | ]#` + Values(Vec), + /// `context-value` + ContextValue, +} + +impl ToCss for SVGStrokeDashArray where LengthType: ToCss { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self { + &SVGStrokeDashArray::Values(ref values) => { + let mut iter = values.iter(); + if let Some(first) = iter.next() { + first.to_css(dest)?; + for item in iter { + dest.write_str(", ")?; + item.to_css(dest)?; + } + Ok(()) + } else { + dest.write_str("none") + } + } + &SVGStrokeDashArray::ContextValue => { + dest.write_str("context-value") + } + } + } +} diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 232c61426c0..ae806c24c10 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -43,7 +43,7 @@ pub use self::length::{LengthOrPercentageOrNone, MaxLength, MozLength}; pub use self::length::{NoCalcLength, Percentage, ViewportPercentageLength}; pub use self::rect::LengthOrNumberRect; pub use self::position::{Position, PositionComponent}; -pub use self::svg::{SVGLength, SVGPaint, SVGPaintKind}; +pub use self::svg::{SVGLength, SVGPaint, SVGPaintKind, SVGStrokeDashArray}; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing}; pub use self::transform::{TimingFunction, TransformOrigin}; pub use super::generics::grid::GridLine; diff --git a/components/style/values/specified/svg.rs b/components/style/values/specified/svg.rs index 2d2b75f1c0c..7c364f59773 100644 --- a/components/style/values/specified/svg.rs +++ b/components/style/values/specified/svg.rs @@ -6,7 +6,7 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; -use style_traits::{ParseError, StyleParseError}; +use style_traits::{CommaWithSpace, ParseError, Separator, StyleParseError}; use values::generics::svg as generic; use values::specified::LengthOrPercentageOrNumber; use values::specified::color::RGBAColor; @@ -69,3 +69,21 @@ impl From for SVGLength { generic::SVGLength::Length(length) } } + +/// [ | | ]# | context-value +pub type SVGStrokeDashArray = generic::SVGStrokeDashArray; + +impl Parse for SVGStrokeDashArray { + fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) + -> Result> { + if let Ok(values) = input.try(|i| CommaWithSpace::parse(i, |i| { + LengthOrPercentageOrNumber::parse_non_negative(context, i) + })) { + Ok(generic::SVGStrokeDashArray::Values(values)) + } else if let Ok(_) = input.try(|i| i.expect_ident_matching("none")) { + Ok(generic::SVGStrokeDashArray::Values(vec![])) + } else { + parse_context_value(input, generic::SVGStrokeDashArray::ContextValue) + } + } +}