Skip to content

Commit

Permalink
Add SVGLengthOrPercentageOrNumber for stroke-*.
Browse files Browse the repository at this point in the history
We need to use enum instead of Either since we can't interpolate stroke-* between
unitless length and unit length(e.g. '5' -> '10px').

This coomit make following:

 * Introduce SVGLengthOrPercentageOrNumber on computed and specified values.
 * Make SVGLengthOrPercentageOrNumber animatable.
 * Make stroke-dasharray not-accumulate.
  • Loading branch information
mantaroh committed Aug 18, 2017
1 parent 6988c74 commit 1c574cf
Show file tree
Hide file tree
Showing 6 changed files with 286 additions and 45 deletions.
50 changes: 32 additions & 18 deletions components/style/properties/gecko.mako.rs
Expand Up @@ -588,7 +588,7 @@ def set_gecko_property(ffi_name, expr):
// set on mContextFlags, and the length field is set to the initial value.

pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
use values::generics::svg::SVGLength;
use values::generics::svg::{SVGLength, SvgLengthOrPercentageOrNumber};
use gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE;
let length = match v {
SVGLength::Length(length) => {
Expand All @@ -604,9 +604,10 @@ def set_gecko_property(ffi_name, expr):
}
};
match length {
Either::First(number) =>
self.gecko.${gecko_ffi_name}.set_value(CoordDataValue::Factor(From::from(number))),
Either::Second(lop) => self.gecko.${gecko_ffi_name}.set(lop),
SvgLengthOrPercentageOrNumber::LengthOrPercentage(lop) =>
self.gecko.${gecko_ffi_name}.set(lop),
SvgLengthOrPercentageOrNumber::Number(num) =>
self.gecko.${gecko_ffi_name}.set_value(CoordDataValue::Factor(num.into())),
}
}

Expand All @@ -623,21 +624,28 @@ def set_gecko_property(ffi_name, expr):
}

pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
use values::generics::svg::SVGLength;
use values::generics::svg::{SVGLength, SvgLengthOrPercentageOrNumber};
use values::computed::LengthOrPercentage;
use gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE;
if (self.gecko.mContextFlags & CONTEXT_VALUE) != 0 {
return SVGLength::ContextValue;
}
let length = match self.gecko.${gecko_ffi_name}.as_value() {
CoordDataValue::Factor(number) => Either::First(From::from(number)),
CoordDataValue::Coord(coord) => Either::Second(From::from(LengthOrPercentage::Length(Au(coord)))),
CoordDataValue::Percent(p) => Either::Second(From::from(LengthOrPercentage::Percentage(Percentage(p)))),
CoordDataValue::Calc(calc) => Either::Second(From::from(LengthOrPercentage::Calc(calc.into()))),
CoordDataValue::Factor(number) =>
SvgLengthOrPercentageOrNumber::Number(number),
CoordDataValue::Coord(coord) =>
SvgLengthOrPercentageOrNumber::LengthOrPercentage(
LengthOrPercentage::Length(Au(coord))),
CoordDataValue::Percent(p) =>
SvgLengthOrPercentageOrNumber::LengthOrPercentage(
LengthOrPercentage::Percentage(Percentage(p))),
CoordDataValue::Calc(calc) =>
SvgLengthOrPercentageOrNumber::LengthOrPercentage(
LengthOrPercentage::Calc(calc.into())),
_ => unreachable!("Unexpected coordinate {:?} in ${ident}",
self.gecko.${gecko_ffi_name}.as_value()),
};
SVGLength::Length(length)
SVGLength::Length(length.into())
}
</%def>

Expand Down Expand Up @@ -5141,7 +5149,7 @@ clip-path

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;
use values::generics::svg::{SVGStrokeDashArray, SvgLengthOrPercentageOrNumber};

match v {
SVGStrokeDashArray::Values(v) => {
Expand All @@ -5152,8 +5160,10 @@ clip-path
}
for (gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v) {
match servo {
Either::First(number) => gecko.set_value(CoordDataValue::Factor(number.into())),
Either::Second(lop) => gecko.set(lop),
SvgLengthOrPercentageOrNumber::LengthOrPercentage(lop) =>
gecko.set(lop),
SvgLengthOrPercentageOrNumber::Number(num) =>
gecko.set_value(CoordDataValue::Factor(num.into())),
}
}
}
Expand Down Expand Up @@ -5183,7 +5193,7 @@ 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;
use values::generics::svg::{SVGStrokeDashArray, SvgLengthOrPercentageOrNumber};

if self.gecko.mContextFlags & CONTEXT_VALUE != 0 {
debug_assert_eq!(self.gecko.mStrokeDasharray.len(), 0);
Expand All @@ -5192,13 +5202,17 @@ clip-path
let mut vec = vec![];
for gecko in self.gecko.mStrokeDasharray.iter() {
match gecko.as_value() {
CoordDataValue::Factor(number) => vec.push(Either::First(number.into())),
CoordDataValue::Factor(number) =>
vec.push(SvgLengthOrPercentageOrNumber::Number(number.into())),
CoordDataValue::Coord(coord) =>
vec.push(Either::Second(LengthOrPercentage::Length(Au(coord)).into())),
vec.push(SvgLengthOrPercentageOrNumber::LengthOrPercentage(
LengthOrPercentage::Length(Au(coord)).into())),
CoordDataValue::Percent(p) =>
vec.push(Either::Second(LengthOrPercentage::Percentage(Percentage(p)).into())),
vec.push(SvgLengthOrPercentageOrNumber::LengthOrPercentage(
LengthOrPercentage::Percentage(Percentage(p)).into())),
CoordDataValue::Calc(calc) =>
vec.push(Either::Second(LengthOrPercentage::Calc(calc.into()).into())),
vec.push(SvgLengthOrPercentageOrNumber::LengthOrPercentage(
LengthOrPercentage::Calc(calc.into()).into())),
_ => unreachable!(),
}
}
Expand Down
149 changes: 142 additions & 7 deletions components/style/properties/helpers/animated_properties.mako.rs
Expand Up @@ -43,18 +43,20 @@ use values::animated::effects::BoxShadowList as AnimatedBoxShadowList;
use values::animated::effects::Filter as AnimatedFilter;
use values::animated::effects::FilterList as AnimatedFilterList;
use values::animated::effects::TextShadowList as AnimatedTextShadowList;
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
use values::computed::{BorderCornerRadius, ClipRect};
use values::computed::{CalcLengthOrPercentage, Context, ComputedValueAsSpecified, ComputedUrl};
use values::computed::{LengthOrPercentage, MaxLength, MozLength, Percentage, ToComputedValue};
use values::computed::{NonNegativeAu, NonNegativeNumber, PositiveIntegerOrAuto};
use values::computed::{Angle, BorderCornerRadius, CalcLengthOrPercentage};
use values::computed::{ClipRect, Context, ComputedUrl, ComputedValueAsSpecified};
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
use values::computed::{LengthOrPercentageOrNone, MaxLength, MozLength, NonNegativeAu};
use values::computed::{NonNegativeNumber, Number, NumberOrPercentage, Percentage};
use values::computed::{PositiveIntegerOrAuto, ToComputedValue};
use values::computed::length::{NonNegativeLengthOrAuto, NonNegativeLengthOrNormal};
use values::computed::length::NonNegativeLengthOrPercentage;
use values::distance::{ComputeSquaredDistance, SquaredDistance};
use values::generics::{GreaterThanOrEqualToOne, NonNegative};
use values::generics::effects::Filter;
use values::generics::position as generic_position;
use values::generics::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray};
use values::generics::svg::{SVGLength, SvgLengthOrPercentageOrNumber, SVGPaint};
use values::generics::svg::{SVGPaintKind, SVGStrokeDashArray, SVGOpacity};

/// A trait used to implement various procedures used during animation.
pub trait Animatable: Sized {
Expand Down Expand Up @@ -781,6 +783,7 @@ impl ToAnimatedZero for AnimationValue {
impl RepeatableListAnimatable for LengthOrPercentage {}
impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {}
impl RepeatableListAnimatable for Either<NonNegativeNumber, NonNegativeLengthOrPercentage> {}
impl RepeatableListAnimatable for SvgLengthOrPercentageOrNumber<NonNegativeLengthOrPercentage, NonNegativeNumber> {}

macro_rules! repeated_vec_impl {
($($ty:ty),*) => {
Expand Down Expand Up @@ -1016,7 +1019,12 @@ impl Animatable for LengthOrPercentage {
impl ToAnimatedZero for LengthOrPercentage {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(LengthOrPercentage::zero())
match self {
&LengthOrPercentage::Length(_) | &LengthOrPercentage::Calc(_) =>
Ok(LengthOrPercentage::zero()),
&LengthOrPercentage::Percentage(_) =>
Ok(LengthOrPercentage::Percentage(Percentage::zero())),
}
}
}

Expand Down Expand Up @@ -2496,6 +2504,120 @@ impl ToAnimatedZero for IntermediateSVGPaintKind {
}
}

impl From<NonNegativeLengthOrPercentage> for NumberOrPercentage {
fn from(lop: NonNegativeLengthOrPercentage) -> NumberOrPercentage {
lop.0.into()
}
}

impl From<NonNegativeNumber> for NumberOrPercentage {
fn from(num: NonNegativeNumber) -> NumberOrPercentage {
num.0.into()
}
}

impl From<LengthOrPercentage> for NumberOrPercentage {
fn from(lop: LengthOrPercentage) -> NumberOrPercentage {
match lop {
LengthOrPercentage::Length(len) => NumberOrPercentage::Number(len.to_f32_px()),
LengthOrPercentage::Percentage(p) => NumberOrPercentage::Percentage(p),
LengthOrPercentage::Calc(_) => {
panic!("We dont't expected calc interpolation for SvgLengthOrPercentageOrNumber");
},
}
}
}

impl From<Number> for NumberOrPercentage {
fn from(num: Number) -> NumberOrPercentage {
NumberOrPercentage::Number(num)
}
}

fn convert_to_number_or_percentage<LengthOrPercentageType, NumberType>(
from: SvgLengthOrPercentageOrNumber<LengthOrPercentageType, NumberType>)
-> NumberOrPercentage
where LengthOrPercentageType: Into<NumberOrPercentage>,
NumberType: Into<NumberOrPercentage>
{
match from {
SvgLengthOrPercentageOrNumber::LengthOrPercentage(lop) => {
lop.into()
}
SvgLengthOrPercentageOrNumber::Number(num) => {
num.into()
}
}
}

fn convert_from_number_or_percentage<LengthOrPercentageType, NumberType>(
from: NumberOrPercentage)
-> SvgLengthOrPercentageOrNumber<LengthOrPercentageType, NumberType>
where LengthOrPercentageType: From<LengthOrPercentage>,
NumberType: From<Number>
{
match from {
NumberOrPercentage::Number(num) =>
SvgLengthOrPercentageOrNumber::Number(num.into()),
NumberOrPercentage::Percentage(p) =>
SvgLengthOrPercentageOrNumber::LengthOrPercentage(
(LengthOrPercentage::Percentage(p)).into())
}
}

impl <LengthOrPercentageType, NumberType> Animatable for
SvgLengthOrPercentageOrNumber<LengthOrPercentageType, NumberType>
where LengthOrPercentageType: Animatable + Into<NumberOrPercentage> + From<LengthOrPercentage> + Copy,
NumberType: Animatable + Into<NumberOrPercentage> + From<Number>,
SvgLengthOrPercentageOrNumber<LengthOrPercentageType, NumberType>: Copy,
LengthOrPercentage: From<LengthOrPercentageType>
{
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
if self.has_calc() || other.has_calc() {
// TODO: We need to treat calc value.
// https://bugzilla.mozilla.org/show_bug.cgi?id=1386967
return Err(());
}

let from_value = convert_to_number_or_percentage(*self);
let to_value = convert_to_number_or_percentage(*other);

match (from_value, to_value) {
(NumberOrPercentage::Number(from),
NumberOrPercentage::Number(to)) => {
from.add_weighted(&to, self_portion, other_portion)
.map(|num| NumberOrPercentage::Number(num))
.map(|nop| convert_from_number_or_percentage(nop))
},
(NumberOrPercentage::Percentage(from),
NumberOrPercentage::Percentage(to)) => {
from.add_weighted(&to, self_portion, other_portion)
.map(|p| NumberOrPercentage::Percentage(p))
.map(|nop| convert_from_number_or_percentage(nop))
},
_ => Err(()),
}
}
}

impl <LengthOrPercentageType, NumberType> ToAnimatedZero for
SvgLengthOrPercentageOrNumber<LengthOrPercentageType, NumberType>
where LengthOrPercentageType: ToAnimatedZero, NumberType: ToAnimatedZero
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
match self {
&SvgLengthOrPercentageOrNumber::LengthOrPercentage(ref lop) =>
lop.to_animated_zero()
.map(SvgLengthOrPercentageOrNumber::LengthOrPercentage),
&SvgLengthOrPercentageOrNumber::Number(ref num) =>
num.to_animated_zero()
.map(SvgLengthOrPercentageOrNumber::Number),
}
}
}

impl<LengthType> Animatable for SVGLength<LengthType>
where LengthType: Animatable + Clone
{
Expand All @@ -2522,6 +2644,7 @@ impl<LengthType> ToAnimatedZero for SVGLength<LengthType> where LengthType : ToA
}
}

/// https://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty
impl<LengthType> Animatable for SVGStrokeDashArray<LengthType>
where LengthType : RepeatableListAnimatable + Clone
{
Expand All @@ -2537,6 +2660,18 @@ impl<LengthType> Animatable for SVGStrokeDashArray<LengthType>
}
}
}

/// stroke-dasharray is non-additive
#[inline]
fn add(&self, _other: &Self) -> Result<Self, ()> {
Err(())
}

/// stroke-dasharray is non-additive
#[inline]
fn accumulate(&self, _other: &Self, _count: u64) -> Result<Self, ()> {
Err(())
}
}

impl<LengthType> ToAnimatedZero for SVGStrokeDashArray<LengthType>
Expand Down
7 changes: 7 additions & 0 deletions components/style/values/computed/length.rs
Expand Up @@ -606,6 +606,13 @@ impl From<LengthOrPercentage> for NonNegativeLengthOrPercentage {
}
}

impl From<NonNegativeLengthOrPercentage> for LengthOrPercentage {
#[inline]
fn from(lop: NonNegativeLengthOrPercentage) -> LengthOrPercentage {
lop.0
}
}

impl NonNegativeLengthOrPercentage {
/// Get zero value.
#[inline]
Expand Down
43 changes: 34 additions & 9 deletions components/style/values/computed/svg.rs
Expand Up @@ -5,10 +5,10 @@
//! Computed types for SVG properties.

use app_units::Au;
use values::{Either, RGBA};
use values::computed::{LengthOrPercentageOrNumber, Opacity};
use values::computed::{NonNegativeAu, NonNegativeLengthOrPercentageOrNumber};
use values::computed::ComputedUrl;
use values::RGBA;
use values::computed::{ComputedUrl, LengthOrPercentage, NonNegativeAu};
use values::computed::{NonNegativeNumber, NonNegativeLengthOrPercentage, Number};
use values::computed::Opacity;
use values::generics::svg as generic;

/// Computed SVG Paint value
Expand Down Expand Up @@ -36,26 +36,51 @@ impl SVGPaint {
}
}

/// A value of <length> | <percentage> | <number> for stroke-dashoffset.
/// https://www.w3.org/TR/SVG11/painting.html#StrokeProperties
pub type SvgLengthOrPercentageOrNumber =
generic::SvgLengthOrPercentageOrNumber<LengthOrPercentage, Number>;

/// <length> | <percentage> | <number> | context-value
pub type SVGLength = generic::SVGLength<LengthOrPercentageOrNumber>;
pub type SVGLength = generic::SVGLength<SvgLengthOrPercentageOrNumber>;

impl From<Au> for SVGLength {
fn from(length: Au) -> Self {
generic::SVGLength::Length(Either::Second(length.into()))
generic::SVGLength::Length(
generic::SvgLengthOrPercentageOrNumber::LengthOrPercentage(length.into()))
}
}

/// A value of <length> | <percentage> | <number> for stroke-width/stroke-dasharray.
/// https://www.w3.org/TR/SVG11/painting.html#StrokeProperties
pub type NonNegativeSvgLengthOrPercentageOrNumber =
generic::SvgLengthOrPercentageOrNumber<NonNegativeLengthOrPercentage, NonNegativeNumber>;

impl Into<NonNegativeSvgLengthOrPercentageOrNumber> for SvgLengthOrPercentageOrNumber {
fn into(self) -> NonNegativeSvgLengthOrPercentageOrNumber {
match self {
generic::SvgLengthOrPercentageOrNumber::LengthOrPercentage(lop) =>{
generic::SvgLengthOrPercentageOrNumber::LengthOrPercentage(lop.into())
},
generic::SvgLengthOrPercentageOrNumber::Number(num) => {
generic::SvgLengthOrPercentageOrNumber::Number(num.into())
},
}
}
}

/// An non-negative wrapper of SVGLength.
pub type SVGWidth = generic::SVGLength<NonNegativeLengthOrPercentageOrNumber>;
pub type SVGWidth = generic::SVGLength<NonNegativeSvgLengthOrPercentageOrNumber>;

impl From<NonNegativeAu> for SVGWidth {
fn from(length: NonNegativeAu) -> Self {
generic::SVGLength::Length(Either::Second(length.into()))
generic::SVGLength::Length(
generic::SvgLengthOrPercentageOrNumber::LengthOrPercentage(length.into()))
}
}

/// [ <length> | <percentage> | <number> ]# | context-value
pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<NonNegativeLengthOrPercentageOrNumber>;
pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<NonNegativeSvgLengthOrPercentageOrNumber>;

impl Default for SVGStrokeDashArray {
fn default() -> Self {
Expand Down

0 comments on commit 1c574cf

Please sign in to comment.