Auto merge of #17940 - upsuper:context-value, r=Manishearth

stylo: Support context values for SVG properties

This is the Servo side change of [bug 1338764](https://bugzilla.mozilla.org/show_bug.cgi?id=1338764).

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17940)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-08-01 19:35:47 -05:00 committed by GitHub
commit ddd779d5b7
13 changed files with 654 additions and 255 deletions

View file

@ -172,6 +172,9 @@ unsafe impl Sync for nsStyleQuoteValues {}
use gecko_bindings::structs::nsStyleSVG;
unsafe impl Send for nsStyleSVG {}
unsafe impl Sync for nsStyleSVG {}
use gecko_bindings::structs::nsStyleSVGOpacitySource;
unsafe impl Send for nsStyleSVGOpacitySource {}
unsafe impl Sync for nsStyleSVGOpacitySource {}
use gecko_bindings::structs::nsStyleSVGPaint;
unsafe impl Send for nsStyleSVGPaint {}
unsafe impl Sync for nsStyleSVGPaint {}

View file

@ -13741,39 +13741,14 @@ pub mod root {
pub mContextPropsBits: u8,
pub mContextFlags: u8,
}
pub const nsStyleSVG_FILL_OPACITY_SOURCE_MASK:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::FILL_OPACITY_SOURCE_MASK;
pub const nsStyleSVG_STROKE_OPACITY_SOURCE_MASK:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::STROKE_OPACITY_SOURCE_MASK;
pub const nsStyleSVG_STROKE_DASHARRAY_CONTEXT:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::STROKE_DASHARRAY_CONTEXT;
pub const nsStyleSVG_STROKE_DASHOFFSET_CONTEXT:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::STROKE_DASHOFFSET_CONTEXT;
pub const nsStyleSVG_STROKE_WIDTH_CONTEXT: root::nsStyleSVG__bindgen_ty_1
=
nsStyleSVG__bindgen_ty_1::STROKE_WIDTH_CONTEXT;
pub const nsStyleSVG_FILL_OPACITY_SOURCE_SHIFT:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::FILL_OPACITY_SOURCE_SHIFT;
pub const nsStyleSVG_STROKE_OPACITY_SOURCE_SHIFT:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::STROKE_OPACITY_SOURCE_SHIFT;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum nsStyleSVG__bindgen_ty_1 {
FILL_OPACITY_SOURCE_MASK = 3,
STROKE_OPACITY_SOURCE_MASK = 12,
STROKE_DASHARRAY_CONTEXT = 16,
STROKE_DASHOFFSET_CONTEXT = 32,
STROKE_WIDTH_CONTEXT = 64,
FILL_OPACITY_SOURCE_SHIFT = 0,
STROKE_OPACITY_SOURCE_SHIFT = 2,
}
pub const nsStyleSVG_kHasFinishStyle: bool = false;
pub const nsStyleSVG_FILL_OPACITY_SOURCE_MASK: u8 = 3;
pub const nsStyleSVG_STROKE_OPACITY_SOURCE_MASK: u8 = 12;
pub const nsStyleSVG_STROKE_DASHARRAY_CONTEXT: u8 = 16;
pub const nsStyleSVG_STROKE_DASHOFFSET_CONTEXT: u8 = 32;
pub const nsStyleSVG_STROKE_WIDTH_CONTEXT: u8 = 64;
pub const nsStyleSVG_FILL_OPACITY_SOURCE_SHIFT: u8 = 0;
pub const nsStyleSVG_STROKE_OPACITY_SOURCE_SHIFT: u8 = 2;
#[test]
fn bindgen_test_layout_nsStyleSVG() {
assert_eq!(::std::mem::size_of::<nsStyleSVG>() , 128usize , concat ! (
@ -31553,6 +31528,13 @@ pub mod root {
eStyleSVGFallbackType_None = 1,
eStyleSVGFallbackType_Color = 2,
}
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum nsStyleSVGOpacitySource {
eStyleSVGOpacitySource_Normal = 0,
eStyleSVGOpacitySource_ContextFillOpacity = 1,
eStyleSVGOpacitySource_ContextStrokeOpacity = 2,
}
#[repr(C)]
#[derive(Debug)]
pub struct nsStyleSVGPaint {

View file

@ -13532,39 +13532,14 @@ pub mod root {
pub mContextPropsBits: u8,
pub mContextFlags: u8,
}
pub const nsStyleSVG_FILL_OPACITY_SOURCE_MASK:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::FILL_OPACITY_SOURCE_MASK;
pub const nsStyleSVG_STROKE_OPACITY_SOURCE_MASK:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::STROKE_OPACITY_SOURCE_MASK;
pub const nsStyleSVG_STROKE_DASHARRAY_CONTEXT:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::STROKE_DASHARRAY_CONTEXT;
pub const nsStyleSVG_STROKE_DASHOFFSET_CONTEXT:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::STROKE_DASHOFFSET_CONTEXT;
pub const nsStyleSVG_STROKE_WIDTH_CONTEXT: root::nsStyleSVG__bindgen_ty_1
=
nsStyleSVG__bindgen_ty_1::STROKE_WIDTH_CONTEXT;
pub const nsStyleSVG_FILL_OPACITY_SOURCE_SHIFT:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::FILL_OPACITY_SOURCE_SHIFT;
pub const nsStyleSVG_STROKE_OPACITY_SOURCE_SHIFT:
root::nsStyleSVG__bindgen_ty_1 =
nsStyleSVG__bindgen_ty_1::STROKE_OPACITY_SOURCE_SHIFT;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum nsStyleSVG__bindgen_ty_1 {
FILL_OPACITY_SOURCE_MASK = 3,
STROKE_OPACITY_SOURCE_MASK = 12,
STROKE_DASHARRAY_CONTEXT = 16,
STROKE_DASHOFFSET_CONTEXT = 32,
STROKE_WIDTH_CONTEXT = 64,
FILL_OPACITY_SOURCE_SHIFT = 0,
STROKE_OPACITY_SOURCE_SHIFT = 2,
}
pub const nsStyleSVG_kHasFinishStyle: bool = false;
pub const nsStyleSVG_FILL_OPACITY_SOURCE_MASK: u8 = 3;
pub const nsStyleSVG_STROKE_OPACITY_SOURCE_MASK: u8 = 12;
pub const nsStyleSVG_STROKE_DASHARRAY_CONTEXT: u8 = 16;
pub const nsStyleSVG_STROKE_DASHOFFSET_CONTEXT: u8 = 32;
pub const nsStyleSVG_STROKE_WIDTH_CONTEXT: u8 = 64;
pub const nsStyleSVG_FILL_OPACITY_SOURCE_SHIFT: u8 = 0;
pub const nsStyleSVG_STROKE_OPACITY_SOURCE_SHIFT: u8 = 2;
#[test]
fn bindgen_test_layout_nsStyleSVG() {
assert_eq!(::std::mem::size_of::<nsStyleSVG>() , 128usize , concat ! (
@ -31061,6 +31036,13 @@ pub mod root {
eStyleSVGFallbackType_None = 1,
eStyleSVGFallbackType_Color = 2,
}
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum nsStyleSVGOpacitySource {
eStyleSVGOpacitySource_Normal = 0,
eStyleSVGOpacitySource_ContextFillOpacity = 1,
eStyleSVGOpacitySource_ContextStrokeOpacity = 2,
}
#[repr(C)]
#[derive(Debug)]
pub struct nsStyleSVGPaint {

View file

@ -54,6 +54,14 @@ impl nsStyleCoord_CalcValue {
}
}
impl PartialEq for nsStyleCoord_CalcValue {
fn eq(&self, other: &Self) -> bool {
self.mLength == other.mLength &&
self.mPercent == other.mPercent &&
self.mHasPercent == other.mHasPercent
}
}
impl nsStyleSides {
/// Immutably get the `nsStyleCoord`-like object representing the side at
/// index `index`.
@ -192,11 +200,11 @@ impl<'a> CoordDataMut for CornersDataMut<'a> {
}
}
#[derive(Copy, Clone)]
/// Enum representing the tagged union that is CoordData.
///
/// In release mode this should never actually exist in the code, and will be
/// optimized out by threading matches and inlining.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum CoordDataValue {
/// eStyleUnit_Null
Null,

View file

@ -576,10 +576,129 @@ 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_opacity(ident, gecko_ffi_name, need_clone=False)">
<% source_prefix = ident.split("_")[0].upper() + "_OPACITY_SOURCE" %>
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
use gecko_bindings::structs::nsStyleSVG_${source_prefix}_MASK as MASK;
use gecko_bindings::structs::nsStyleSVG_${source_prefix}_SHIFT as SHIFT;
use gecko_bindings::structs::nsStyleSVGOpacitySource::*;
use values::generics::svg::SVGOpacity;
self.gecko.mContextFlags &= !MASK;
match v {
SVGOpacity::Opacity(opacity) => {
self.gecko.mContextFlags |=
(eStyleSVGOpacitySource_Normal as u8) << SHIFT;
self.gecko.${gecko_ffi_name} = opacity;
}
SVGOpacity::ContextFillOpacity => {
self.gecko.mContextFlags |=
(eStyleSVGOpacitySource_ContextFillOpacity as u8) << SHIFT;
self.gecko.${gecko_ffi_name} = 1.;
}
SVGOpacity::ContextStrokeOpacity => {
self.gecko.mContextFlags |=
(eStyleSVGOpacitySource_ContextStrokeOpacity as u8) << SHIFT;
self.gecko.${gecko_ffi_name} = 1.;
}
}
}
pub fn copy_${ident}_from(&mut self, other: &Self) {
use gecko_bindings::structs::nsStyleSVG_${source_prefix}_MASK as MASK;
self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name};
self.gecko.mContextFlags =
(self.gecko.mContextFlags & !MASK) |
(other.gecko.mContextFlags & MASK);
}
pub fn reset_${ident}(&mut self, other: &Self) {
self.copy_${ident}_from(other)
}
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
use gecko_bindings::structs::nsStyleSVG_${source_prefix}_MASK as MASK;
use gecko_bindings::structs::nsStyleSVG_${source_prefix}_SHIFT as SHIFT;
use gecko_bindings::structs::nsStyleSVGOpacitySource::*;
use values::generics::svg::SVGOpacity;
let source = (self.gecko.mContextFlags & MASK) >> SHIFT;
if source == eStyleSVGOpacitySource_Normal as u8 {
return SVGOpacity::Opacity(self.gecko.${gecko_ffi_name});
} else {
debug_assert_eq!(self.gecko.${gecko_ffi_name}, 1.0);
if source == eStyleSVGOpacitySource_ContextFillOpacity as u8 {
SVGOpacity::ContextFillOpacity
} else {
debug_assert_eq!(source, eStyleSVGOpacitySource_ContextStrokeOpacity as u8);
SVGOpacity::ContextStrokeOpacity
}
}
}
</%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::SVGPaintKind;
use values::generics::svg::SVGPaintKind;
use self::structs::nsStyleSVGPaintType;
use self::structs::nsStyleSVGFallbackType;
@ -632,7 +751,7 @@ def set_gecko_property(ffi_name, expr):
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
use values::generics::{SVGPaint, SVGPaintKind};
use values::generics::svg::{SVGPaint, SVGPaintKind};
use values::specified::url::SpecifiedUrl;
use self::structs::nsStyleSVGPaintType;
use self::structs::nsStyleSVGFallbackType;
@ -965,6 +1084,8 @@ impl Clone for ${style_struct.gecko_struct_name} {
"Opacity": impl_simple,
"Color": impl_color,
"RGBAColor": impl_rgba_color,
"SVGLength": impl_svg_length,
"SVGOpacity": impl_svg_opacity,
"SVGPaint": impl_svg_paint,
"UrlOrNone": impl_css_url,
}
@ -4896,7 +5017,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;
@ -4922,27 +5043,41 @@ clip-path
${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);
}
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) {
@ -4950,8 +5085,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() {
@ -4965,47 +5106,7 @@ clip-path
_ => 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!(),
}
SVGStrokeDashArray::Values(vec)
}
#[allow(non_snake_case)]

View file

@ -43,10 +43,10 @@ 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::{SVGPaint, SVGPaintKind};
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use values::generics::effects::Filter;
use values::generics::position as generic_position;
use values::generics::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray};
/// A trait used to implement various procedures used during animation.
pub trait Animatable: Sized {
@ -3038,6 +3038,123 @@ 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),
}
}
}
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),
}
}
}
impl<OpacityType> Animatable for SVGOpacity<OpacityType>
where OpacityType: Animatable + Clone
{
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (self, other) {
(&SVGOpacity::Opacity(ref this), &SVGOpacity::Opacity(ref other)) => {
this.add_weighted(other, self_portion, other_portion).map(SVGOpacity::Opacity)
}
_ => {
Ok(if self_portion > other_portion { self.clone() } else { other.clone() })
}
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (self, other) {
(&SVGOpacity::Opacity(ref this), &SVGOpacity::Opacity(ref other)) => {
this.compute_distance(other)
}
_ => Err(())
}
}
}
impl<OpacityType> ToAnimatedZero for SVGOpacity<OpacityType>
where OpacityType: ToAnimatedZero + Clone
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
match self {
&SVGOpacity::Opacity(ref opacity) =>
opacity.to_animated_zero().map(SVGOpacity::Opacity),
other => Ok(other.clone()),
}
}
}
<%
FILTER_FUNCTIONS = [ 'Blur', 'Brightness', 'Contrast', 'Grayscale',
'HueRotate', 'Invert', 'Opacity', 'Saturate',

View file

@ -39,7 +39,7 @@ ${helpers.predefined_type(
boxed=True,
spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint")}
${helpers.predefined_type("fill-opacity", "Opacity", "1.0",
${helpers.predefined_type("fill-opacity", "SVGOpacity", "Default::default()",
products="gecko", animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty")}
@ -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")}
@ -84,26 +85,24 @@ ${helpers.predefined_type("stroke-miterlimit", "Number", "4.0",
animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")}
${helpers.predefined_type("stroke-opacity", "Opacity", "1.0",
${helpers.predefined_type("stroke-opacity", "SVGOpacity", "Default::default()",
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", "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")}

View file

@ -17,7 +17,7 @@ use std::f64;
use std::f64::consts::PI;
use std::fmt;
use style_traits::ToCss;
use super::{CSSFloat, CSSInteger, RGBA};
use super::{CSSFloat, CSSInteger};
use super::generics::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
use super::generics::grid::TrackList as GenericTrackList;
@ -44,6 +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, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray};
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing};
pub use self::transform::{TimingFunction, TransformOrigin};
@ -61,6 +62,7 @@ pub mod gecko;
pub mod length;
pub mod position;
pub mod rect;
pub mod svg;
pub mod text;
pub mod transform;
@ -454,31 +456,6 @@ impl IntegerOrAuto {
}
}
/// Computed SVG Paint value
pub type SVGPaint = ::values::generics::SVGPaint<RGBA>;
/// Computed SVG Paint Kind value
pub type SVGPaintKind = ::values::generics::SVGPaintKind<RGBA>;
impl Default for SVGPaint {
fn default() -> Self {
SVGPaint {
kind: ::values::generics::SVGPaintKind::None,
fallback: None,
}
}
}
impl SVGPaint {
/// Opaque black color
pub fn black() -> Self {
let rgba = RGBA::from_floats(0., 0., 0., 1.);
SVGPaint {
kind: ::values::generics::SVGPaintKind::Color(rgba),
fallback: None,
}
}
}
/// <length> | <percentage> | <number>
pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>;

View file

@ -0,0 +1,62 @@
/* 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 app_units::Au;
use values::{Either, RGBA};
use values::computed::{LengthOrPercentageOrNumber, Opacity};
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 {
fn default() -> Self {
SVGPaint {
kind: generic::SVGPaintKind::None,
fallback: None,
}
}
}
impl SVGPaint {
/// Opaque black color
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()))
}
}
/// [ <length> | <percentage> | <number> ]# | context-value
pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<LengthOrPercentageOrNumber>;
impl Default for SVGStrokeDashArray {
fn default() -> Self {
generic::SVGStrokeDashArray::Values(vec![])
}
}
/// <opacity-value> | context-fill-opacity | context-stroke-opacity
pub type SVGOpacity = generic::SVGOpacity<Opacity>;
impl Default for SVGOpacity {
fn default() -> Self {
generic::SVGOpacity::Opacity(1.)
}
}

View file

@ -11,7 +11,6 @@ use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::{Comma, OneOrMoreSeparated, ParseError, StyleParseError, ToCss};
use super::CustomIdent;
use values::specified::url::SpecifiedUrl;
pub mod background;
pub mod basic_shape;
@ -24,6 +23,7 @@ pub mod grid;
pub mod image;
pub mod position;
pub mod rect;
pub mod svg;
pub mod text;
pub mod transform;
@ -252,90 +252,3 @@ impl ToCss for FontSettingTagFloat {
self.0.to_css(dest)
}
}
/// An SVG paint value
///
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
pub struct SVGPaint<ColorType> {
/// The paint source
pub kind: SVGPaintKind<ColorType>,
/// The fallback color
pub fallback: Option<ColorType>,
}
/// An SVG paint value without the fallback
///
/// Whereas the spec only allows PaintServer
/// to have a fallback, Gecko lets the context
/// properties have a fallback as well.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
pub enum SVGPaintKind<ColorType> {
/// `none`
None,
/// `<color>`
Color(ColorType),
/// `url(...)`
PaintServer(SpecifiedUrl),
/// `context-fill`
ContextFill,
/// `context-stroke`
ContextStroke,
}
impl<ColorType> SVGPaintKind<ColorType> {
/// Parse a keyword value only
fn parse_ident<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
try_match_ident_ignore_ascii_case! { input.expect_ident()?,
"none" => Ok(SVGPaintKind::None),
"context-fill" => Ok(SVGPaintKind::ContextFill),
"context-stroke" => Ok(SVGPaintKind::ContextStroke),
}
}
}
/// Parse SVGPaint's fallback.
/// fallback is keyword(none) or Color.
/// https://svgwg.org/svg2-draft/painting.html#SpecifyingPaint
fn parse_fallback<'i, 't, ColorType: Parse>(context: &ParserContext,
input: &mut Parser<'i, 't>)
-> Option<ColorType> {
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
None
} else {
input.try(|i| ColorType::parse(context, i)).ok()
}
}
impl<ColorType: Parse> Parse for SVGPaint<ColorType> {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
Ok(SVGPaint {
kind: SVGPaintKind::PaintServer(url),
fallback: parse_fallback(context, input),
})
} else if let Ok(kind) = input.try(SVGPaintKind::parse_ident) {
if let SVGPaintKind::None = kind {
Ok(SVGPaint {
kind: kind,
fallback: None,
})
} else {
Ok(SVGPaint {
kind: kind,
fallback: parse_fallback(context, input),
})
}
} else if let Ok(color) = input.try(|i| ColorType::parse(context, i)) {
Ok(SVGPaint {
kind: SVGPaintKind::Color(color),
fallback: None,
})
} else {
Err(StyleParseError::UnspecifiedError.into())
}
}
}

View file

@ -0,0 +1,153 @@
/* 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/. */
//! Generic types for CSS values in SVG
use cssparser::Parser;
use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::{ParseError, StyleParseError, ToCss};
use values::specified::url::SpecifiedUrl;
/// An SVG paint value
///
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
pub struct SVGPaint<ColorType> {
/// The paint source
pub kind: SVGPaintKind<ColorType>,
/// The fallback color
pub fallback: Option<ColorType>,
}
/// An SVG paint value without the fallback
///
/// Whereas the spec only allows PaintServer
/// to have a fallback, Gecko lets the context
/// properties have a fallback as well.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
pub enum SVGPaintKind<ColorType> {
/// `none`
None,
/// `<color>`
Color(ColorType),
/// `url(...)`
PaintServer(SpecifiedUrl),
/// `context-fill`
ContextFill,
/// `context-stroke`
ContextStroke,
}
impl<ColorType> SVGPaintKind<ColorType> {
/// Parse a keyword value only
fn parse_ident<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
try_match_ident_ignore_ascii_case! { input.expect_ident()?,
"none" => Ok(SVGPaintKind::None),
"context-fill" => Ok(SVGPaintKind::ContextFill),
"context-stroke" => Ok(SVGPaintKind::ContextStroke),
}
}
}
/// Parse SVGPaint's fallback.
/// fallback is keyword(none) or Color.
/// https://svgwg.org/svg2-draft/painting.html#SpecifyingPaint
fn parse_fallback<'i, 't, ColorType: Parse>(context: &ParserContext,
input: &mut Parser<'i, 't>)
-> Option<ColorType> {
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
None
} else {
input.try(|i| ColorType::parse(context, i)).ok()
}
}
impl<ColorType: Parse> Parse for SVGPaint<ColorType> {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
Ok(SVGPaint {
kind: SVGPaintKind::PaintServer(url),
fallback: parse_fallback(context, input),
})
} else if let Ok(kind) = input.try(SVGPaintKind::parse_ident) {
if let SVGPaintKind::None = kind {
Ok(SVGPaint {
kind: kind,
fallback: None,
})
} else {
Ok(SVGPaint {
kind: kind,
fallback: parse_fallback(context, input),
})
}
} else if let Ok(color) = input.try(|i| ColorType::parse(context, i)) {
Ok(SVGPaint {
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,
}
/// 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,
}
impl<LengthType> ToCss for SVGStrokeDashArray<LengthType> where LengthType: ToCss {
fn to_css<W>(&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")
}
}
}
}
/// An SVG opacity value accepts `context-{fill,stroke}-opacity` in
/// addition to opacity value.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, HasViewportPercentage, ToComputedValue, ToCss)]
pub enum SVGOpacity<OpacityType> {
/// `<opacity-value>`
Opacity(OpacityType),
/// `context-fill-opacity`
ContextFillOpacity,
/// `context-stroke-opacity`
ContextStrokeOpacity,
}

View file

@ -43,6 +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, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray};
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing};
pub use self::transform::{TimingFunction, TransformOrigin};
pub use super::generics::grid::GridLine;
@ -64,6 +65,7 @@ pub mod image;
pub mod length;
pub mod position;
pub mod rect;
pub mod svg;
pub mod text;
pub mod transform;
@ -703,14 +705,6 @@ pub type TrackList = GenericTrackList<LengthOrPercentage>;
/// `<grid-template-rows> | <grid-template-columns>`
pub type GridTemplateComponent = GenericGridTemplateComponent<LengthOrPercentage>;
no_viewport_percentage!(SVGPaint);
/// Specified SVG Paint value
pub type SVGPaint = ::values::generics::SVGPaint<RGBAColor>;
/// Specified SVG Paint Kind value
pub type SVGPaintKind = ::values::generics::SVGPaintKind<RGBAColor>;
/// <length> | <percentage> | <number>
pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>;

View file

@ -0,0 +1,108 @@
/* 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::{CommaWithSpace, ParseError, Separator, StyleParseError};
use values::generics::svg as generic;
use values::specified::{LengthOrPercentageOrNumber, Opacity};
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 {
// 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)
}
}
/// [ <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)
}
}
}
/// <opacity-value> | context-fill-opacity | context-stroke-opacity
pub type SVGOpacity = generic::SVGOpacity<Opacity>;
impl Parse for SVGOpacity {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
if let Ok(opacity) = input.try(|i| Opacity::parse(context, i)) {
Ok(generic::SVGOpacity::Opacity(opacity))
} else if is_context_value_enabled() {
try_match_ident_ignore_ascii_case! { input.expect_ident()?,
"context-fill-opacity" => Ok(generic::SVGOpacity::ContextFillOpacity),
"context-stroke-opacity" => Ok(generic::SVGOpacity::ContextStrokeOpacity),
}
} else {
Err(StyleParseError::UnspecifiedError.into())
}
}
}