mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Add SVGLength which accepts context-value, and use it for stroke-{width,dashoffset}.
This commit is contained in:
parent
3991e7d344
commit
aa80859a71
8 changed files with 182 additions and 49 deletions
|
@ -576,6 +576,64 @@ def set_gecko_property(ffi_name, expr):
|
|||
% endif
|
||||
</%def>
|
||||
|
||||
<%def name="impl_svg_length(ident, gecko_ffi_name, need_clone=False)">
|
||||
// When context-value is used on an SVG length, the corresponding flag is
|
||||
// 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 gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as 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!("Initial value should not be context-value"),
|
||||
}
|
||||
}
|
||||
};
|
||||
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 reset_${ident}(&mut self, other: &Self) {
|
||||
self.copy_${ident}_from(other)
|
||||
}
|
||||
|
||||
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!("Unexpected coordinate {:?} in ${ident}",
|
||||
self.gecko.${gecko_ffi_name}.as_value()),
|
||||
};
|
||||
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) {
|
||||
|
@ -965,6 +1023,7 @@ impl Clone for ${style_struct.gecko_struct_name} {
|
|||
"Opacity": impl_simple,
|
||||
"Color": impl_color,
|
||||
"RGBAColor": impl_rgba_color,
|
||||
"SVGLength": impl_svg_length,
|
||||
"SVGPaint": impl_svg_paint,
|
||||
"UrlOrNone": impl_css_url,
|
||||
}
|
||||
|
@ -4896,7 +4955,7 @@ clip-path
|
|||
</%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;
|
||||
|
@ -4968,46 +5027,6 @@ clip-path
|
|||
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>,
|
||||
|
|
|
@ -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::{SVGPaint, SVGPaintKind};
|
||||
use values::generics::svg::{SVGLength, SVGPaint, SVGPaintKind};
|
||||
|
||||
/// A trait used to implement various procedures used during animation.
|
||||
pub trait Animatable: Sized {
|
||||
|
@ -3038,6 +3038,42 @@ impl ToAnimatedZero for IntermediateSVGPaintKind {
|
|||
}
|
||||
}
|
||||
|
||||
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',
|
||||
|
|
|
@ -64,10 +64,11 @@ ${helpers.predefined_type(
|
|||
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",
|
||||
boxed="True",
|
||||
animation_value_type="ComputedValue",
|
||||
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")}
|
||||
|
||||
|
@ -101,9 +102,10 @@ ${helpers.predefined_type(
|
|||
)}
|
||||
|
||||
${helpers.predefined_type(
|
||||
"stroke-dashoffset", "LengthOrPercentageOrNumber",
|
||||
"Either::First(0.0)",
|
||||
"stroke-dashoffset", "SVGLength",
|
||||
"Au(0).into()",
|
||||
products="gecko",
|
||||
boxed="True",
|
||||
animation_value_type="ComputedValue",
|
||||
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}
|
||||
|
||||
|
|
|
@ -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::{SVGPaint, SVGPaintKind};
|
||||
pub use self::svg::{SVGLength, SVGPaint, SVGPaintKind};
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing};
|
||||
pub use self::transform::{TimingFunction, TransformOrigin};
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
//! 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
|
||||
|
@ -31,3 +33,12 @@ 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()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,3 +94,13 @@ impl<ColorType: Parse> Parse for SVGPaint<ColorType> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
|
|
@ -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::{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;
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
|
||||
//! 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
|
||||
|
@ -14,3 +18,54 @@ no_viewport_percentage!(SVGPaint);
|
|||
|
||||
/// Specified SVG Paint Kind value
|
||||
pub type SVGPaintKind = generic::SVGPaintKind<RGBAColor>;
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
fn is_context_value_enabled() -> bool {
|
||||
// The prefs can only be mutated on the main thread, so it is safe
|
||||
// to read whenever we are on the main thread or the main thread is
|
||||
// blocked.
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue