Make stroke-dasharray accept context-value. r?manishearth
draft
Make stroke-dasharray accept context-value. r?manishearth
MozReview-Commit-ID: KAjO8PyLfZb
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -4589,56 +4589,76 @@ clip-path
}
self.gecko.mPaintOrder = order;
}
}
${impl_simple_copy('paint_order', 'mPaintOrder')}
- pub fn set_stroke_dasharray<I>(&mut self, v: I)
- where I: IntoIterator<Item = longhands::stroke_dasharray::computed_value::single_value::T>,
- I::IntoIter: ExactSizeIterator
- {
- let v = v.into_iter();
- 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),
+ 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;
+
+ 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 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() {
CoordDataValue::Factor(number) => vec.push(Either::First(number)),
CoordDataValue::Coord(coord) =>
vec.push(Either::Second(LengthOrPercentage::Length(Au(coord)))),
CoordDataValue::Percent(p) =>
vec.push(Either::Second(LengthOrPercentage::Percentage(Percentage(p)))),
CoordDataValue::Calc(calc) =>
vec.push(Either::Second(LengthOrPercentage::Calc(calc.into()))),
_ => unreachable!(),
}
}
- longhands::stroke_dasharray::computed_value::T(vec)
+ SVGStrokeDashArray::Values(vec)
}
#[allow(non_snake_case)]
pub fn set__moz_context_properties<I>(&mut self, v: I)
where I: IntoIterator<Item = longhands::_moz_context_properties::computed_value::single_value::T>,
I::IntoIter: ExactSizeIterator
{
let v = v.into_iter();
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -41,17 +41,17 @@ use values::animated::effects::FilterLis
use values::animated::effects::TextShadowList as AnimatedTextShadowList;
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
use values::computed::{BorderCornerRadius, ClipRect};
use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSpecified};
use values::computed::{LengthOrPercentage, MaxLength, MozLength, Percentage, ToComputedValue};
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 {
/// Performs a weighted sum of this value and |other|. This is used for
/// interpolation and addition of animation values.
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()>;
@@ -3069,16 +3069,58 @@ impl<LengthType> ToAnimatedZero for SVGL
fn to_animated_zero(&self) -> Result<Self, ()> {
match self {
&SVGLength::Length(ref length) => length.to_animated_zero().map(SVGLength::Length),
&SVGLength::ContextValue => Ok(SVGLength::ContextValue),
}
}
}
+impl<LengthType> Animatable for SVGStrokeDashArray<LengthType>
+ where LengthType : RepeatableListAnimatable + Clone
+{
+ #[inline]
+ fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+ 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<f64, ()> {
+ match (self, other) {
+ (&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other)) => {
+ this.compute_distance(other)
+ }
+ _ => Err(())
+ }
+ }
+}
+
+impl<LengthType> ToAnimatedZero for SVGStrokeDashArray<LengthType>
+ where LengthType : ToAnimatedZero + Clone
+{
+ #[inline]
+ fn to_animated_zero(&self) -> Result<Self, ()> {
+ match self {
+ &SVGStrokeDashArray::Values(ref values) => {
+ values.iter().map(ToAnimatedZero::to_animated_zero)
+ .collect::<Result<Vec<_>, ()>>().map(SVGStrokeDashArray::Values)
+ }
+ &SVGStrokeDashArray::ContextValue => Ok(SVGStrokeDashArray::ContextValue),
+ }
+ }
+}
+
<%
FILTER_FUNCTIONS = [ 'Blur', 'Brightness', 'Contrast', 'Grayscale',
'HueRotate', 'Invert', 'Opacity', 'Saturate',
'Sepia' ]
%>
/// https://drafts.fxtf.org/filters/#animation-of-filters
fn add_weighted_filter_function_impl(from: &AnimatedFilter,
--- a/servo/components/style/properties/longhand/inherited_svg.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_svg.mako.rs
@@ -85,23 +85,20 @@
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")}
${helpers.predefined_type("stroke-opacity", "Opacity", "1.0",
products="gecko", animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")}
${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",
)}
${helpers.predefined_type(
"stroke-dashoffset", "SVGLength",
"Au(0).into()",
products="gecko",
animation_value_type="ComputedValue",
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -39,17 +39,17 @@ pub use super::{Auto, Either, None_};
#[cfg(feature = "gecko")]
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
pub use super::specified::{BorderStyle, UrlOrNone};
pub use super::generics::grid::GridLine;
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};
pub mod background;
pub mod basic_shape;
pub mod border;
pub mod color;
pub mod effects;
--- a/servo/components/style/values/computed/svg.rs
+++ b/servo/components/style/values/computed/svg.rs
@@ -37,8 +37,17 @@ impl SVGPaint {
/// <length> | <percentage> | <number> | context-value
pub type SVGLength = generic::SVGLength<LengthOrPercentageOrNumber>;
impl From<Au> for SVGLength {
fn from(length: Au) -> Self {
generic::SVGLength::Length(Either::Second(length.into()))
}
}
+
+/// [ <length> | <percentage> | <number> ]# | context-value
+pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<LengthOrPercentageOrNumber>;
+
+impl Default for SVGStrokeDashArray {
+ fn default() -> Self {
+ generic::SVGStrokeDashArray::Values(vec![])
+ }
+}
--- a/servo/components/style/values/generics/svg.rs
+++ b/servo/components/style/values/generics/svg.rs
@@ -99,8 +99,18 @@ impl<ColorType: Parse> Parse for SVGPain
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, HasViewportPercentage, ToComputedValue, ToCss)]
pub enum SVGLength<LengthType> {
/// `<length> | <percentage> | <number>`
Length(LengthType),
/// `context-value`
ContextValue,
}
+
+/// Generic value for stroke-dasharray.
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Debug, PartialEq, HasViewportPercentage, ToComputedValue)]
+pub enum SVGStrokeDashArray<LengthType> {
+ /// `[ <length> | <percentage> | <number> ]#`
+ Values(Vec<LengthType>),
+ /// `context-value`
+ ContextValue,
+}
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -38,17 +38,17 @@ pub use self::image::{ColorStop, EndingS
pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect};
pub use self::length::{AbsoluteLength, CalcLengthOrPercentage, CharacterWidth};
pub use self::length::{FontRelativeLength, Length, LengthOrNone, LengthOrNumber};
pub use self::length::{LengthOrPercentage, LengthOrPercentageOrAuto};
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;
pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
#[cfg(feature = "gecko")]
pub mod align;
pub mod background;
--- a/servo/components/style/values/specified/svg.rs
+++ b/servo/components/style/values/specified/svg.rs
@@ -1,17 +1,18 @@
/* 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/. */
//! Specified types for SVG properties.
use cssparser::Parser;
use parser::{Parse, ParserContext};
-use style_traits::{ParseError, StyleParseError};
+use std::fmt;
+use style_traits::{CommaWithSpace, ParseError, Separator, StyleParseError, ToCss};
use values::generics::svg as generic;
use values::specified::LengthOrPercentageOrNumber;
use values::specified::color::RGBAColor;
/// Specified SVG Paint value
pub type SVGPaint = generic::SVGPaint<RGBAColor>;
no_viewport_percentage!(SVGPaint);
@@ -61,8 +62,49 @@ impl SVGLength {
}
}
impl From<LengthOrPercentageOrNumber> for SVGLength {
fn from(length: LengthOrPercentageOrNumber) -> Self {
generic::SVGLength::Length(length)
}
}
+
+/// [ <length> | <percentage> | <number> ]# | context-value
+pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<LengthOrPercentageOrNumber>;
+
+impl Parse for SVGStrokeDashArray {
+ fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
+ -> Result<Self, ParseError<'i>> {
+ 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)
+ }
+ }
+}
+
+impl ToCss for SVGStrokeDashArray {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match self {
+ &generic::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")
+ }
+ }
+ &generic::SVGStrokeDashArray::ContextValue => {
+ dest.write_str("context-value")
+ }
+ }
+ }
+}