mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
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:
commit
ddd779d5b7
13 changed files with 654 additions and 255 deletions
|
@ -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 {}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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")}
|
||||
|
||||
|
|
|
@ -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>;
|
||||
|
||||
|
|
62
components/style/values/computed/svg.rs
Normal file
62
components/style/values/computed/svg.rs
Normal 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.)
|
||||
}
|
||||
}
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
153
components/style/values/generics/svg.rs
Normal file
153
components/style/values/generics/svg.rs
Normal 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,
|
||||
}
|
|
@ -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>;
|
||||
|
||||
|
|
108
components/style/values/specified/svg.rs
Normal file
108
components/style/values/specified/svg.rs
Normal 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())
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue