Add SVGLength which accepts context-value, and use it for stroke-{width,dashoffset}. r?manishearth
draft
Add SVGLength which accepts context-value, and use it for stroke-{width,dashoffset}. r?manishearth
MozReview-Commit-ID: JP1Ib1ohNNg
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -556,16 +556,67 @@ def set_gecko_property(ffi_name, expr):
% if need_clone:
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
convert_nscolor_to_rgba(${get_gecko_property(gecko_ffi_name)})
}
% endif
</%def>
+<%def name="impl_svg_length(ident, gecko_ffi_name, need_clone=False)">
+ pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
+ use values::generics::svg::SVGLength;
+ use gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE;
+ self.gecko.mContextFlags &= !CONTEXT_VALUE;
+ let length = match v {
+ SVGLength::Length(length) => {
+ self.gecko.mContextFlags &= !CONTEXT_VALUE;
+ length
+ }
+ SVGLength::ContextValue => {
+ self.gecko.mContextFlags |= CONTEXT_VALUE;
+ match longhands::${ident}::get_initial_value() {
+ SVGLength::Length(length) => length,
+ _ => unreachable!(),
+ }
+ }
+ };
+ match length {
+ Either::First(number) =>
+ self.gecko.${gecko_ffi_name}.set_value(CoordDataValue::Factor(number)),
+ Either::Second(lop) => self.gecko.${gecko_ffi_name}.set(lop),
+ }
+ }
+
+ pub fn copy_${ident}_from(&mut self, other: &Self) {
+ use gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE;
+ self.gecko.${gecko_ffi_name}.copy_from(&other.gecko.${gecko_ffi_name});
+ self.gecko.mContextFlags =
+ (self.gecko.mContextFlags & !CONTEXT_VALUE) |
+ (other.gecko.mContextFlags & CONTEXT_VALUE);
+ }
+
+ pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
+ use values::generics::svg::SVGLength;
+ 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(number),
+ CoordDataValue::Coord(coord) => Either::Second(LengthOrPercentage::Length(Au(coord))),
+ CoordDataValue::Percent(p) => Either::Second(LengthOrPercentage::Percentage(Percentage(p))),
+ CoordDataValue::Calc(calc) => Either::Second(LengthOrPercentage::Calc(calc.into())),
+ _ => unreachable!(),
+ };
+ SVGLength::Length(length)
+ }
+</%def>
+
<%def name="impl_svg_paint(ident, gecko_ffi_name, need_clone=False)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, mut v: longhands::${ident}::computed_value::T) {
use values::generics::svg::SVGPaintKind;
use self::structs::nsStyleSVGPaintType;
use self::structs::nsStyleSVGFallbackType;
let ref mut paint = ${get_gecko_property(gecko_ffi_name)};
@@ -911,16 +962,17 @@ impl Clone for ${style_struct.gecko_stru
"LengthOrNormal": impl_style_coord,
"MaxLength": impl_style_coord,
"MozLength": impl_style_coord,
"Number": impl_simple,
"Integer": impl_simple,
"Opacity": impl_simple,
"Color": impl_color,
"RGBAColor": impl_rgba_color,
+ "SVGLength": impl_svg_length,
"SVGPaint": impl_svg_paint,
"UrlOrNone": impl_css_url,
}
def longhand_method(longhand):
args = dict(ident=longhand.ident, gecko_ffi_name=longhand.gecko_ffi_name,
need_clone=longhand.need_clone)
@@ -4511,17 +4563,17 @@ clip-path
<% impl_common_image_layer_properties("mask") %>
<% impl_simple_image_array_property("mode", "mask", "mMask", "mMaskMode", "SVG") %>
<% impl_simple_image_array_property("composite", "mask", "mMask", "mComposite", "SVG") %>
<% impl_shape_source("clip_path", "mClipPath") %>
</%self:impl_trait>
<%self:impl_trait style_struct_name="InheritedSVG"
- skip_longhands="paint-order stroke-dasharray stroke-dashoffset stroke-width -moz-context-properties"
+ skip_longhands="paint-order stroke-dasharray -moz-context-properties"
skip_additionals="*">
pub fn set_paint_order(&mut self, v: longhands::paint_order::computed_value::T) {
use self::longhands::paint_order;
if v.0 == 0 {
self.gecko.mPaintOrder = structs::NS_STYLE_PAINT_ORDER_NORMAL as u8;
} else {
let mut order = 0;
@@ -4579,56 +4631,16 @@ clip-path
CoordDataValue::Calc(calc) =>
vec.push(Either::Second(LengthOrPercentage::Calc(calc.into()))),
_ => unreachable!(),
}
}
longhands::stroke_dasharray::computed_value::T(vec)
}
- pub fn set_stroke_dashoffset(&mut self, v: longhands::stroke_dashoffset::computed_value::T) {
- match v {
- Either::First(number) => self.gecko.mStrokeDashoffset.set_value(CoordDataValue::Factor(number)),
- Either::Second(lop) => self.gecko.mStrokeDashoffset.set(lop),
- }
- }
-
- ${impl_coord_copy('stroke_dashoffset', 'mStrokeDashoffset')}
-
- pub fn clone_stroke_dashoffset(&self) -> longhands::stroke_dashoffset::computed_value::T {
- use values::computed::LengthOrPercentage;
- match self.gecko.mStrokeDashoffset.as_value() {
- CoordDataValue::Factor(number) => Either::First(number),
- CoordDataValue::Coord(coord) => Either::Second(LengthOrPercentage::Length(Au(coord))),
- CoordDataValue::Percent(p) => Either::Second(LengthOrPercentage::Percentage(Percentage(p))),
- CoordDataValue::Calc(calc) => Either::Second(LengthOrPercentage::Calc(calc.into())),
- _ => unreachable!(),
- }
- }
-
- pub fn set_stroke_width(&mut self, v: longhands::stroke_width::computed_value::T) {
- match v {
- Either::First(number) => self.gecko.mStrokeWidth.set_value(CoordDataValue::Factor(number)),
- Either::Second(lop) => self.gecko.mStrokeWidth.set(lop),
- }
- }
-
- ${impl_coord_copy('stroke_width', 'mStrokeWidth')}
-
- pub fn clone_stroke_width(&self) -> longhands::stroke_width::computed_value::T {
- use values::computed::LengthOrPercentage;
- match self.gecko.mStrokeWidth.as_value() {
- CoordDataValue::Factor(number) => Either::First(number),
- CoordDataValue::Coord(coord) => Either::Second(LengthOrPercentage::Length(Au(coord))),
- CoordDataValue::Percent(p) => Either::Second(LengthOrPercentage::Percentage(Percentage(p))),
- CoordDataValue::Calc(calc) => Either::Second(LengthOrPercentage::Calc(calc.into())),
- _ => unreachable!(),
- }
- }
-
#[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();
unsafe {
bindings::Gecko_nsStyleSVG_SetContextPropertiesLength(&mut self.gecko, v.len() as u32);
--- 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::{SVGPaint, SVGPaintKind};
+use values::generics::svg::{SVGLength, SVGPaint, SVGPaintKind};
/// 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, ()>;
@@ -3033,16 +3033,52 @@ impl ToAnimatedZero for IntermediateSVGP
SVGPaintKind::None |
SVGPaintKind::ContextFill |
SVGPaintKind::ContextStroke => Ok(self.clone()),
_ => Err(()),
}
}
}
+impl<LengthType> Animatable for SVGLength<LengthType>
+ where LengthType: Animatable + Clone
+{
+ #[inline]
+ fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+ match (self, other) {
+ (&SVGLength::Length(ref this), &SVGLength::Length(ref other)) => {
+ this.add_weighted(&other, self_portion, other_portion).map(SVGLength::Length)
+ }
+ _ => {
+ Ok(if self_portion > other_portion { self.clone() } else { other.clone() })
+ }
+ }
+ }
+
+ #[inline]
+ fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
+ match (self, other) {
+ (&SVGLength::Length(ref this), &SVGLength::Length(ref other)) => {
+ this.compute_distance(other)
+ }
+ _ => Err(())
+ }
+ }
+}
+
+impl<LengthType> ToAnimatedZero for SVGLength<LengthType> where LengthType : ToAnimatedZero {
+ #[inline]
+ 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),
+ }
+ }
+}
+
<%
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
@@ -59,18 +59,18 @@
"stroke", "SVGPaint",
"Default::default()",
products="gecko",
animation_value_type="IntermediateSVGPaint",
boxed=True,
spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint")}
${helpers.predefined_type(
- "stroke-width", "LengthOrPercentageOrNumber",
- "Either::First(1.0)",
+ "stroke-width", "SVGLength",
+ "Au::from_px(1).into()",
"parse_non_negative",
products="gecko",
animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")}
${helpers.single_keyword("stroke-linecap", "butt round square",
products="gecko", animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty")}
@@ -96,18 +96,18 @@
vector=True,
products="gecko",
animation_value_type="ComputedValue",
separator="CommaWithSpace",
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing",
)}
${helpers.predefined_type(
- "stroke-dashoffset", "LengthOrPercentageOrNumber",
- "Either::First(0.0)",
+ "stroke-dashoffset", "SVGLength",
+ "Au(0).into()",
products="gecko",
animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}
// Section 14 - Clipping, Masking and Compositing
${helpers.single_keyword("clip-rule", "nonzero evenodd",
products="gecko",
gecko_enum_prefix="StyleFillRule",
--- 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::{SVGPaint, SVGPaintKind};
+pub use self::svg::{SVGLength, SVGPaint, SVGPaintKind};
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
@@ -1,15 +1,17 @@
/* 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/. */
//! Computed types for SVG properties.
-use values::RGBA;
+use app_units::Au;
+use values::{Either, RGBA};
+use values::computed::LengthOrPercentageOrNumber;
use values::generics::svg as generic;
/// Computed SVG Paint value
pub type SVGPaint = generic::SVGPaint<RGBA>;
/// Computed SVG Paint Kind value
pub type SVGPaintKind = generic::SVGPaintKind<RGBA>;
impl Default for SVGPaint {
@@ -26,8 +28,17 @@ impl SVGPaint {
pub fn black() -> Self {
let rgba = RGBA::from_floats(0., 0., 0., 1.);
SVGPaint {
kind: generic::SVGPaintKind::Color(rgba),
fallback: None,
}
}
}
+
+/// <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()))
+ }
+}
--- a/servo/components/style/values/generics/svg.rs
+++ b/servo/components/style/values/generics/svg.rs
@@ -89,8 +89,18 @@ impl<ColorType: Parse> Parse for SVGPain
kind: SVGPaintKind::Color(color),
fallback: None,
})
} else {
Err(StyleParseError::UnspecifiedError.into())
}
}
}
+
+/// An SVG length value supports `context-value` in addition to length.
+#[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,
+}
--- 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::{SVGPaint, SVGPaintKind};
+pub use self::svg::{SVGLength, SVGPaint, SVGPaintKind};
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,16 +1,68 @@
/* 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 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);
/// Specified SVG Paint Kind value
pub type SVGPaintKind = generic::SVGPaintKind<RGBAColor>;
+
+#[cfg(feature = "gecko")]
+fn is_context_value_enabled() -> bool {
+ use gecko_bindings::structs::mozilla;
+ unsafe { mozilla::StylePrefs_sOpentypeSVGEnabled }
+}
+#[cfg(not(feature = "gecko"))]
+fn is_context_value_enabled() -> bool {
+ false
+}
+
+fn parse_context_value<'i, 't, T>(input: &mut Parser<'i, 't>, value: T)
+ -> Result<T, ParseError<'i>> {
+ if is_context_value_enabled() {
+ if input.expect_ident_matching("context-value").is_ok() {
+ return Ok(value);
+ }
+ }
+ Err(StyleParseError::UnspecifiedError.into())
+}
+
+/// <length> | <percentage> | <number> | context-value
+pub type SVGLength = generic::SVGLength<LengthOrPercentageOrNumber>;
+
+impl Parse for SVGLength {
+ fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
+ -> Result<Self, ParseError<'i>> {
+ input.try(|i| LengthOrPercentageOrNumber::parse(context, i))
+ .map(Into::into)
+ .or_else(|_| parse_context_value(input, generic::SVGLength::ContextValue))
+ }
+}
+
+impl SVGLength {
+ /// parse a non-negative SVG length
+ pub fn parse_non_negative<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
+ -> Result<Self, ParseError<'i>> {
+ input.try(|i| LengthOrPercentageOrNumber::parse_non_negative(context, i))
+ .map(Into::into)
+ .or_else(|_| parse_context_value(input, generic::SVGLength::ContextValue))
+ }
+}
+
+impl From<LengthOrPercentageOrNumber> for SVGLength {
+ fn from(length: LengthOrPercentageOrNumber) -> Self {
+ generic::SVGLength::Length(length)
+ }
+}