aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-02-18 04:13:59 -0800
committerGitHub <noreply@github.com>2017-02-18 04:13:59 -0800
commitd3ba09e5884b8fb2513dd3fb7d9842de53fc3309 (patch)
tree7e2e0267608627b40554ed728671e0d233defeef
parenteb6082fd7877fd3a14d14369f107a8b840f128d5 (diff)
parent66a28a4f5aec9375aa8c8e92533b14ada1a69b38 (diff)
downloadservo-d3ba09e5884b8fb2513dd3fb7d9842de53fc3309.tar.gz
servo-d3ba09e5884b8fb2513dd3fb7d9842de53fc3309.zip
Auto merge of #15627 - Manishearth:stylo-svg, r=heycam
stylo: Finish all SVG properties reviewed in bug https://bugzilla.mozilla.org/show_bug.cgi?id=1338388 <!-- 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/15627) <!-- Reviewable:end -->
-rw-r--r--components/style/build_gecko.rs6
-rw-r--r--components/style/gecko_bindings/bindings.rs61
-rw-r--r--components/style/gecko_bindings/structs_debug.rs17
-rw-r--r--components/style/gecko_bindings/structs_release.rs17
-rw-r--r--components/style/gecko_bindings/sugar/refptr.rs3
-rw-r--r--components/style/parser.rs16
-rw-r--r--components/style/properties/gecko.mako.rs242
-rw-r--r--components/style/properties/helpers.mako.rs15
-rw-r--r--components/style/properties/longhand/box.mako.rs1
-rw-r--r--components/style/properties/longhand/effects.mako.rs33
-rw-r--r--components/style/properties/longhand/inherited_svg.mako.rs192
-rw-r--r--components/style/properties/shorthand/inherited_svg.mako.rs36
-rw-r--r--components/style/values/computed/length.rs8
-rw-r--r--components/style/values/computed/mod.rs81
-rw-r--r--components/style/values/specified/length.rs28
-rw-r--r--components/style/values/specified/mod.rs169
-rw-r--r--components/style/values/specified/url.rs20
17 files changed, 844 insertions, 101 deletions
diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs
index 15ca0d55c3e..58064f4f897 100644
--- a/components/style/build_gecko.rs
+++ b/components/style/build_gecko.rs
@@ -365,6 +365,7 @@ mod bindings {
"nsStylePadding",
"nsStylePosition",
"nsStyleSVG",
+ "nsStyleSVGPaint",
"nsStyleSVGReset",
"nsStyleTable",
"nsStyleTableBorder",
@@ -383,6 +384,7 @@ mod bindings {
"PropertyValuePair",
"Runnable",
"ServoAttrSnapshot",
+ "ServoBundledURI",
"ServoElementSnapshot",
"SheetParsingMode",
"StaticRefPtr",
@@ -506,6 +508,7 @@ mod bindings {
.whitelisted_function("Servo_.*")
.whitelisted_function("Gecko_.*");
let structs_types = [
+ "mozilla::css::URLValue",
"RawGeckoDocument",
"RawGeckoElement",
"RawGeckoKeyframeList",
@@ -523,6 +526,7 @@ mod bindings {
"FontFamilyList",
"FontFamilyType",
"Keyframe",
+ "ServoBundledURI",
"ServoElementSnapshot",
"SheetParsingMode",
"StyleBasicShape",
@@ -550,6 +554,7 @@ mod bindings {
"nsStyleCoord_CalcValue",
"nsStyleDisplay",
"nsStyleEffects",
+ "nsStyleFilter",
"nsStyleFont",
"nsStyleGradient",
"nsStyleGradientStop",
@@ -565,6 +570,7 @@ mod bindings {
"nsStylePosition",
"nsStyleQuoteValues",
"nsStyleSVG",
+ "nsStyleSVGPaint",
"nsStyleSVGReset",
"nsStyleTable",
"nsStyleTableBorder",
diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs
index 46b7fe63bab..415bf710781 100644
--- a/components/style/gecko_bindings/bindings.rs
+++ b/components/style/gecko_bindings/bindings.rs
@@ -3,6 +3,7 @@
pub use nsstring::{nsACString, nsAString};
type nsACString_internal = nsACString;
type nsAString_internal = nsAString;
+use gecko_bindings::structs::mozilla::css::URLValue;
use gecko_bindings::structs::RawGeckoDocument;
use gecko_bindings::structs::RawGeckoElement;
use gecko_bindings::structs::RawGeckoKeyframeList;
@@ -20,6 +21,7 @@ use gecko_bindings::structs::TraversalRootBehavior;
use gecko_bindings::structs::FontFamilyList;
use gecko_bindings::structs::FontFamilyType;
use gecko_bindings::structs::Keyframe;
+use gecko_bindings::structs::ServoBundledURI;
use gecko_bindings::structs::ServoElementSnapshot;
use gecko_bindings::structs::SheetParsingMode;
use gecko_bindings::structs::StyleBasicShape;
@@ -69,6 +71,9 @@ unsafe impl Sync for nsStyleDisplay {}
use gecko_bindings::structs::nsStyleEffects;
unsafe impl Send for nsStyleEffects {}
unsafe impl Sync for nsStyleEffects {}
+use gecko_bindings::structs::nsStyleFilter;
+unsafe impl Send for nsStyleFilter {}
+unsafe impl Sync for nsStyleFilter {}
use gecko_bindings::structs::nsStyleFont;
unsafe impl Send for nsStyleFont {}
unsafe impl Sync for nsStyleFont {}
@@ -114,6 +119,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::nsStyleSVGPaint;
+unsafe impl Send for nsStyleSVGPaint {}
+unsafe impl Sync for nsStyleSVGPaint {}
use gecko_bindings::structs::nsStyleSVGReset;
unsafe impl Send for nsStyleSVGReset {}
unsafe impl Sync for nsStyleSVGReset {}
@@ -590,11 +598,7 @@ extern "C" {
}
extern "C" {
pub fn Gecko_SetListStyleImage(style_struct: *mut nsStyleList,
- string_bytes: *const u8,
- string_length: u32,
- base_uri: *mut ThreadSafeURIHolder,
- referrer: *mut ThreadSafeURIHolder,
- principal: *mut ThreadSafePrincipalHolder);
+ uri: ServoBundledURI);
}
extern "C" {
pub fn Gecko_CopyListStyleImageFrom(dest: *mut nsStyleList,
@@ -616,17 +620,6 @@ extern "C" {
src: *const nsStyleUserInterface);
}
extern "C" {
- pub fn Gecko_SetMozBinding(style_struct: *mut nsStyleDisplay,
- string_bytes: *const u8, string_length: u32,
- base_uri: *mut ThreadSafeURIHolder,
- referrer: *mut ThreadSafeURIHolder,
- principal: *mut ThreadSafePrincipalHolder);
-}
-extern "C" {
- pub fn Gecko_CopyMozBindingFrom(des: *mut nsStyleDisplay,
- src: *const nsStyleDisplay);
-}
-extern "C" {
pub fn Gecko_GetNodeFlags(node: RawGeckoNodeBorrowed) -> u32;
}
extern "C" {
@@ -708,6 +701,10 @@ extern "C" {
-> *mut StyleBasicShape;
}
extern "C" {
+ pub fn Gecko_StyleClipPath_SetURLValue(clip: *mut StyleClipPath,
+ uri: ServoBundledURI);
+}
+extern "C" {
pub fn Gecko_ResetFilters(effects: *mut nsStyleEffects, new_len: usize);
}
extern "C" {
@@ -715,6 +712,38 @@ extern "C" {
aDest: *mut nsStyleEffects);
}
extern "C" {
+ pub fn Gecko_nsStyleFilter_SetURLValue(effects: *mut nsStyleFilter,
+ uri: ServoBundledURI);
+}
+extern "C" {
+ pub fn Gecko_nsStyleSVGPaint_CopyFrom(dest: *mut nsStyleSVGPaint,
+ src: *const nsStyleSVGPaint);
+}
+extern "C" {
+ pub fn Gecko_nsStyleSVGPaint_SetURLValue(paint: *mut nsStyleSVGPaint,
+ uri: ServoBundledURI);
+}
+extern "C" {
+ pub fn Gecko_nsStyleSVGPaint_Reset(paint: *mut nsStyleSVGPaint);
+}
+extern "C" {
+ pub fn Gecko_nsStyleSVG_SetDashArrayLength(svg: *mut nsStyleSVG,
+ len: u32);
+}
+extern "C" {
+ pub fn Gecko_nsStyleSVG_CopyDashArray(dst: *mut nsStyleSVG,
+ src: *const nsStyleSVG);
+}
+extern "C" {
+ pub fn Gecko_NewURLValue(uri: ServoBundledURI) -> *mut URLValue;
+}
+extern "C" {
+ pub fn Gecko_AddRefCSSURLValueArbitraryThread(aPtr: *mut URLValue);
+}
+extern "C" {
+ pub fn Gecko_ReleaseCSSURLValueArbitraryThread(aPtr: *mut URLValue);
+}
+extern "C" {
pub fn Gecko_FillAllBackgroundLists(layers: *mut nsStyleImageLayers,
max_len: u32);
}
diff --git a/components/style/gecko_bindings/structs_debug.rs b/components/style/gecko_bindings/structs_debug.rs
index cf1c9ce517b..302aa8bb0a1 100644
--- a/components/style/gecko_bindings/structs_debug.rs
+++ b/components/style/gecko_bindings/structs_debug.rs
@@ -25363,6 +25363,23 @@ pub mod root {
pub type ThreadSafePrincipalHolder =
root::nsMainThreadPtrHolder<root::nsIPrincipal>;
pub type ThreadSafeURIHolder = root::nsMainThreadPtrHolder<root::nsIURI>;
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct ServoBundledURI {
+ pub mURLString: *const u8,
+ pub mURLStringLength: u32,
+ pub mBaseURI: *mut root::ThreadSafeURIHolder,
+ pub mReferrer: *mut root::ThreadSafeURIHolder,
+ pub mPrincipal: *mut root::ThreadSafePrincipalHolder,
+ }
+ #[test]
+ fn bindgen_test_layout_ServoBundledURI() {
+ assert_eq!(::std::mem::size_of::<ServoBundledURI>() , 40usize);
+ assert_eq!(::std::mem::align_of::<ServoBundledURI>() , 8usize);
+ }
+ impl Clone for ServoBundledURI {
+ fn clone(&self) -> Self { *self }
+ }
pub type nsMediaFeatureValueGetter =
::std::option::Option<unsafe extern "C" fn(aPresContext:
*mut root::nsPresContext,
diff --git a/components/style/gecko_bindings/structs_release.rs b/components/style/gecko_bindings/structs_release.rs
index d50cc1ee1a0..b7f7be53fb8 100644
--- a/components/style/gecko_bindings/structs_release.rs
+++ b/components/style/gecko_bindings/structs_release.rs
@@ -24719,6 +24719,23 @@ pub mod root {
pub type ThreadSafePrincipalHolder =
root::nsMainThreadPtrHolder<root::nsIPrincipal>;
pub type ThreadSafeURIHolder = root::nsMainThreadPtrHolder<root::nsIURI>;
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct ServoBundledURI {
+ pub mURLString: *const u8,
+ pub mURLStringLength: u32,
+ pub mBaseURI: *mut root::ThreadSafeURIHolder,
+ pub mReferrer: *mut root::ThreadSafeURIHolder,
+ pub mPrincipal: *mut root::ThreadSafePrincipalHolder,
+ }
+ #[test]
+ fn bindgen_test_layout_ServoBundledURI() {
+ assert_eq!(::std::mem::size_of::<ServoBundledURI>() , 40usize);
+ assert_eq!(::std::mem::align_of::<ServoBundledURI>() , 8usize);
+ }
+ impl Clone for ServoBundledURI {
+ fn clone(&self) -> Self { *self }
+ }
pub type nsMediaFeatureValueGetter =
::std::option::Option<unsafe extern "C" fn(aPresContext:
*mut root::nsPresContext,
diff --git a/components/style/gecko_bindings/sugar/refptr.rs b/components/style/gecko_bindings/sugar/refptr.rs
index 1689522e892..0202afb3292 100644
--- a/components/style/gecko_bindings/sugar/refptr.rs
+++ b/components/style/gecko_bindings/sugar/refptr.rs
@@ -264,6 +264,9 @@ impl_threadsafe_refcount!(::gecko_bindings::structs::nsStyleQuoteValues,
impl_threadsafe_refcount!(::gecko_bindings::structs::nsCSSValueSharedList,
Gecko_AddRefCSSValueSharedListArbitraryThread,
Gecko_ReleaseCSSValueSharedListArbitraryThread);
+impl_threadsafe_refcount!(::gecko_bindings::structs::mozilla::css::URLValue,
+ Gecko_AddRefCSSURLValueArbitraryThread,
+ Gecko_ReleaseCSSURLValueArbitraryThread);
/// A Gecko `ThreadSafePrincipalHolder` wrapped in a safe refcounted pointer, to
/// use during stylesheet parsing and style computation.
pub type GeckoArcPrincipal = RefPtr<::gecko_bindings::structs::ThreadSafePrincipalHolder>;
diff --git a/components/style/parser.rs b/components/style/parser.rs
index 12e6290304f..4145650b2c8 100644
--- a/components/style/parser.rs
+++ b/components/style/parser.rs
@@ -110,6 +110,22 @@ impl<T> Parse for Vec<T> where T: Parse + OneOrMoreCommaSeparated {
}
}
+/// Parse a non-empty space-separated or comma-separated list of objects parsed by parse_one
+pub fn parse_space_or_comma_separated<F, T>(input: &mut Parser, mut parse_one: F)
+ -> Result<Vec<T>, ()>
+ where F: FnMut(&mut Parser) -> Result<T, ()> {
+ let first = parse_one(input)?;
+ let mut vec = vec![first];
+ loop {
+ let _ = input.try(|i| i.expect_comma());
+ if let Ok(val) = input.try(|i| parse_one(i)) {
+ vec.push(val)
+ } else {
+ break
+ }
+ }
+ Ok(vec)
+}
impl Parse for UnicodeRange {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
UnicodeRange::parse(input)
diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs
index 722faf11326..2e60378dd1c 100644
--- a/components/style/properties/gecko.mako.rs
+++ b/components/style/properties/gecko.mako.rs
@@ -11,6 +11,7 @@
<%namespace name="helpers" file="/helpers.mako.rs" />
use app_units::Au;
+use cssparser::Color;
use custom_properties::ComputedValuesMap;
use gecko_bindings::bindings;
% for style_struct in data.style_structs:
@@ -25,7 +26,6 @@ use gecko_bindings::bindings::Gecko_CopyFontFamilyFrom;
use gecko_bindings::bindings::Gecko_CopyImageValueFrom;
use gecko_bindings::bindings::Gecko_CopyListStyleImageFrom;
use gecko_bindings::bindings::Gecko_CopyListStyleTypeFrom;
-use gecko_bindings::bindings::Gecko_CopyMozBindingFrom;
use gecko_bindings::bindings::Gecko_EnsureImageLayersLength;
use gecko_bindings::bindings::Gecko_FontFamilyList_AppendGeneric;
use gecko_bindings::bindings::Gecko_FontFamilyList_AppendNamed;
@@ -36,7 +36,6 @@ use gecko_bindings::bindings::Gecko_NewCSSShadowArray;
use gecko_bindings::bindings::Gecko_SetListStyleImage;
use gecko_bindings::bindings::Gecko_SetListStyleImageNone;
use gecko_bindings::bindings::Gecko_SetListStyleType;
-use gecko_bindings::bindings::Gecko_SetMozBinding;
use gecko_bindings::bindings::Gecko_SetNullImageValue;
use gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
use gecko_bindings::bindings::{Gecko_ResetFilters, Gecko_CopyFiltersFrom};
@@ -274,6 +273,19 @@ def set_gecko_property(ffi_name, expr):
}
</%def>
+
+/// Convert a Servo color into an nscolor; with currentColor as 0
+///
+/// Call sites will need to be updated after https://bugzilla.mozilla.org/show_bug.cgi?id=760345
+fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
+ match color {
+ Color::RGBA(rgba) => {
+ convert_rgba_to_nscolor(&rgba)
+ },
+ Color::CurrentColor => 0,
+ }
+}
+
<%def name="impl_color_setter(ident, gecko_ffi_name, complex_color=True)">
#[allow(unreachable_code)]
#[allow(non_snake_case)]
@@ -281,12 +293,7 @@ def set_gecko_property(ffi_name, expr):
% if complex_color:
let result = v.into();
% else:
- use cssparser::Color;
- let result = match v {
- Color::RGBA(rgba) => convert_rgba_to_nscolor(&rgba),
- // FIXME #13547
- Color::CurrentColor => 0,
- };
+ let result = color_to_nscolor_zero_currentcolor(v);
% endif
${set_gecko_property(gecko_ffi_name, "result")}
}
@@ -306,7 +313,6 @@ def set_gecko_property(ffi_name, expr):
% if complex_color:
${get_gecko_property(gecko_ffi_name)}.into()
% else:
- use cssparser::Color;
Color::RGBA(convert_nscolor_to_rgba(${get_gecko_property(gecko_ffi_name)}))
% endif
}
@@ -369,6 +375,58 @@ def set_gecko_property(ffi_name, expr):
% endif
</%def>
+<%def name="impl_svg_paint(ident, gecko_ffi_name, need_clone=False, complex_color=True)">
+ #[allow(non_snake_case)]
+ pub fn set_${ident}(&mut self, mut v: longhands::${ident}::computed_value::T) {
+ use values::computed::SVGPaintKind;
+ use self::structs::nsStyleSVGPaintType;
+
+ let ref mut paint = ${get_gecko_property(gecko_ffi_name)};
+ unsafe {
+ bindings::Gecko_nsStyleSVGPaint_Reset(paint);
+ }
+ let fallback = v.fallback.take();
+ match v.kind {
+ SVGPaintKind::None => return,
+ SVGPaintKind::ContextFill => {
+ paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextFill;
+ }
+ SVGPaintKind::ContextStroke => {
+ paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextStroke;
+ }
+ SVGPaintKind::PaintServer(url) => {
+ unsafe {
+ if let Some(ffi) = url.for_ffi() {
+ bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, ffi);
+ } else {
+ return;
+ }
+ }
+ }
+ SVGPaintKind::Color(color) => {
+ paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_Color;
+ unsafe {
+ *paint.mPaint.mColor.as_mut() = color_to_nscolor_zero_currentcolor(color);
+ }
+ }
+ }
+
+ if let Some(fallback) = fallback {
+ paint.mFallbackColor = color_to_nscolor_zero_currentcolor(fallback);
+ }
+ }
+
+ #[allow(non_snake_case)]
+ pub fn copy_${ident}_from(&mut self, other: &Self) {
+ unsafe {
+ bindings::Gecko_nsStyleSVGPaint_CopyFrom(
+ &mut ${get_gecko_property(gecko_ffi_name)},
+ & ${get_gecko_property(gecko_ffi_name, "other")}
+ );
+ }
+ }
+</%def>
+
<%def name="impl_app_units(ident, gecko_ffi_name, need_clone, round_to_pixels=False)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
@@ -455,6 +513,41 @@ def set_gecko_property(ffi_name, expr):
% endif
</%def>
+<%def name="impl_css_url(ident, gecko_ffi_name, need_clone=False)">
+ #[allow(non_snake_case)]
+ pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
+ use gecko_bindings::sugar::refptr::RefPtr;
+ match v {
+ Either::First(url) => {
+ let refptr = unsafe {
+ if let Some(ffi) = url.for_ffi() {
+ let ptr = bindings::Gecko_NewURLValue(ffi);
+ RefPtr::from_addrefed(ptr)
+ } else {
+ self.gecko.${gecko_ffi_name}.clear();
+ return;
+ }
+ };
+ self.gecko.${gecko_ffi_name}.set_move(refptr)
+ }
+ Either::Second(_none) => {
+ unsafe {
+ self.gecko.${gecko_ffi_name}.clear();
+ }
+ }
+ }
+ }
+ #[allow(non_snake_case)]
+ pub fn copy_${ident}_from(&mut self, other: &Self) {
+ unsafe {
+ self.gecko.${gecko_ffi_name}.set(&other.gecko.${gecko_ffi_name});
+ }
+ }
+ % if need_clone:
+ <% raise Exception("Do not know how to handle clone ") %>
+ % endif
+</%def>
+
<%def name="impl_logical(name, need_clone=False, **kwargs)">
${helpers.logical_setter(name, need_clone)}
</%def>
@@ -543,6 +636,8 @@ impl Debug for ${style_struct.gecko_struct_name} {
"Number": impl_simple,
"Opacity": impl_simple,
"CSSColor": impl_color,
+ "SVGPaint": impl_svg_paint,
+ "UrlOrNone": impl_css_url,
}
def longhand_method(longhand):
@@ -1221,7 +1316,7 @@ fn static_assert() {
animation-name animation-delay animation-duration
animation-direction animation-fill-mode animation-play-state
animation-iteration-count animation-timing-function
- -moz-binding page-break-before page-break-after
+ page-break-before page-break-after
scroll-snap-points-x scroll-snap-points-y transform
scroll-snap-type-y scroll-snap-coordinate
perspective-origin transform-origin""" %>
@@ -1316,33 +1411,6 @@ fn static_assert() {
<%call expr="impl_coord_copy('vertical_align', 'mVerticalAlign')"></%call>
- #[allow(non_snake_case)]
- pub fn set__moz_binding(&mut self, v: longhands::_moz_binding::computed_value::T) {
- use values::Either;
- match v {
- Either::Second(_none) => debug_assert!(self.gecko.mBinding.mRawPtr.is_null()),
- Either::First(ref url) => {
- let extra_data = url.extra_data();
- let (ptr, len) = match url.as_slice_components() {
- Ok(value) => value,
- Err(_) => (ptr::null(), 0),
- };
- unsafe {
- Gecko_SetMozBinding(&mut self.gecko,
- ptr,
- len as u32,
- extra_data.base.get(),
- extra_data.referrer.get(),
- extra_data.principal.get());
- }
- }
- }
- }
- #[allow(non_snake_case)]
- pub fn copy__moz_binding_from(&mut self, other: &Self) {
- unsafe { Gecko_CopyMozBindingFrom(&mut self.gecko, &other.gecko); }
- }
-
// Temp fix for Bugzilla bug 24000.
// Map 'auto' and 'avoid' to false, and 'always', 'left', and 'right' to true.
// "A conforming user agent may interpret the values 'left' and 'right'
@@ -2066,17 +2134,13 @@ fn static_assert() {
}
}
Either::First(ref url) => {
- let (ptr, len) = match url.as_slice_components() {
- Ok(value) | Err(value) => value
- };
- let extra_data = url.extra_data();
unsafe {
- Gecko_SetListStyleImage(&mut self.gecko,
- ptr,
- len as u32,
- extra_data.base.get(),
- extra_data.referrer.get(),
- extra_data.principal.get());
+ if let Some(ffi) = url.for_ffi() {
+ Gecko_SetListStyleImage(&mut self.gecko,
+ ffi);
+ } else {
+ Gecko_SetListStyleImageNone(&mut self.gecko);
+ }
}
// We don't need to record this struct as uncacheable, like when setting
// background-image to a url() value, since only properties in reset structs
@@ -2147,7 +2211,6 @@ fn static_assert() {
<%self:impl_trait style_struct_name="Effects"
skip_longhands="box-shadow filter">
pub fn set_box_shadow(&mut self, v: longhands::box_shadow::computed_value::T) {
- use cssparser::Color;
self.gecko.mBoxShadow.replace_with_new(v.0.len() as u32);
@@ -2178,8 +2241,6 @@ fn static_assert() {
}
pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T {
- use cssparser::Color;
-
let buf = self.gecko.mBoxShadow.iter().map(|shadow| {
longhands::box_shadow::single_value::computed_value::T {
offset_x: Au(shadow.mXOffset),
@@ -2194,7 +2255,6 @@ fn static_assert() {
}
pub fn set_filter(&mut self, v: longhands::filter::computed_value::T) {
- use cssparser::Color;
use properties::longhands::filter::computed_value::Filter::*;
use gecko_bindings::structs::nsCSSShadowArray;
use gecko_bindings::structs::nsStyleFilter;
@@ -2279,6 +2339,13 @@ fn static_assert() {
Color::CurrentColor => 0,
};
}
+ Url(ref url) => {
+ unsafe {
+ if let Some(ffi) = url.for_ffi() {
+ bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, ffi);
+ }
+ }
+ }
}
}
}
@@ -2316,7 +2383,6 @@ fn static_assert() {
${impl_keyword('text_align', 'mTextAlign', text_align_keyword, need_clone=False)}
pub fn set_text_shadow(&mut self, v: longhands::text_shadow::computed_value::T) {
- use cssparser::Color;
self.gecko.mTextShadow.replace_with_new(v.0.len() as u32);
for (servo, gecko_shadow) in v.0.into_iter()
@@ -2344,7 +2410,6 @@ fn static_assert() {
}
pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T {
- use cssparser::Color;
let buf = self.gecko.mTextShadow.iter().map(|shadow| {
longhands::text_shadow::computed_value::TextShadow {
@@ -2636,7 +2701,13 @@ clip-path
clip_path.mType = StyleShapeSourceType::None;
match v {
- ShapeSource::Url(..) => warn!("stylo: clip-path: url() not yet implemented"),
+ ShapeSource::Url(ref url) => {
+ unsafe {
+ if let Some(ffi) = url.for_ffi() {
+ bindings::Gecko_StyleClipPath_SetURLValue(clip_path, ffi);
+ }
+ }
+ }
ShapeSource::None => {} // don't change the type
ShapeSource::Box(reference) => {
clip_path.mReferenceBox = reference.into();
@@ -2726,32 +2797,51 @@ clip-path
Gecko_CopyClipPathValueFrom(&mut self.gecko.mClipPath, &other.gecko.mClipPath);
}
}
+</%self:impl_trait>
- pub fn clone_clip_path(&self) -> longhands::clip_path::computed_value::T {
- use gecko_bindings::structs::StyleShapeSourceType;
- use gecko_bindings::structs::StyleGeometryBox;
- use values::computed::basic_shape::*;
- let ref clip_path = self.gecko.mClipPath;
+<%self:impl_trait style_struct_name="InheritedSVG"
+ skip_longhands="paint-order stroke-dasharray"
+ skip_additionals="*">
+ pub fn set_paint_order(&mut self, v: longhands::paint_order::computed_value::T) {
+ use self::longhands::paint_order;
- match clip_path.mType {
- StyleShapeSourceType::None => ShapeSource::None,
- StyleShapeSourceType::Box => {
- ShapeSource::Box(clip_path.mReferenceBox.into())
- }
- StyleShapeSourceType::URL => {
- warn!("stylo: clip-path: url() not implemented yet");
- Default::default()
- }
- StyleShapeSourceType::Shape => {
- let reference = if let StyleGeometryBox::NoBox = clip_path.mReferenceBox {
- None
- } else {
- Some(clip_path.mReferenceBox.into())
+ if v.0 == 0 {
+ self.gecko.mPaintOrder = structs::NS_STYLE_PAINT_ORDER_NORMAL as u8;
+ } else {
+ let mut order = 0;
+
+ for pos in 0..3 {
+ let geckoval = match v.bits_at(pos) {
+ paint_order::FILL => structs::NS_STYLE_PAINT_ORDER_FILL as u8,
+ paint_order::STROKE => structs::NS_STYLE_PAINT_ORDER_STROKE as u8,
+ paint_order::MARKERS => structs::NS_STYLE_PAINT_ORDER_MARKERS as u8,
+ _ => unreachable!(),
};
- let union = clip_path.__bindgen_anon_1;
- let shape = unsafe { &**union.mBasicShape.as_ref() };
- ShapeSource::Shape(shape.into(), reference)
+ order |= geckoval << (pos * structs::NS_STYLE_PAINT_ORDER_BITWIDTH as u8);
}
+
+ self.gecko.mPaintOrder = order;
+ }
+ }
+
+ ${impl_simple_copy('paint_order', 'mPaintOrder')}
+
+ pub fn set_stroke_dasharray(&mut self, v: longhands::stroke_dasharray::computed_value::T) {
+ unsafe {
+ bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, v.0.len() as u32);
+ }
+
+ for (mut gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v.0.into_iter()) {
+ match servo {
+ Either::First(lop) => gecko.set(lop),
+ Either::Second(number) => gecko.set_value(CoordDataValue::Factor(number)),
+ }
+ }
+ }
+
+ pub fn copy_stroke_dasharray_from(&mut self, other: &Self) {
+ unsafe {
+ bindings::Gecko_nsStyleSVG_CopyDashArray(&mut self.gecko, &other.gecko);
}
}
</%self:impl_trait>
diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs
index e89ebaeb21a..c9b26aa6489 100644
--- a/components/style/properties/helpers.mako.rs
+++ b/components/style/properties/helpers.mako.rs
@@ -66,7 +66,8 @@
We assume that the default/initial value is an empty vector for these.
`initial_value` need not be defined for these.
</%doc>
-<%def name="vector_longhand(name, gecko_only=False, allow_empty=False, delegate_animate=False, **kwargs)">
+<%def name="vector_longhand(name, gecko_only=False, allow_empty=False,
+ delegate_animate=False, space_separated_allowed=False, **kwargs)">
<%call expr="longhand(name, **kwargs)">
% if not gecko_only:
use std::fmt;
@@ -86,6 +87,7 @@
use properties::{CSSWideKeyword, DeclaredValue, ShorthandId};
use values::computed::{Context, ToComputedValue};
use values::{computed, specified};
+ use values::{Auto, Either, None_, Normal};
${caller.body()}
}
@@ -166,16 +168,23 @@
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+ use parser::parse_space_or_comma_separated;
+
+ <%
+ parse_func = "Parser::parse_comma_separated"
+ if space_separated_allowed:
+ parse_func = "parse_space_or_comma_separated"
+ %>
% if allow_empty:
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
Ok(SpecifiedValue(Vec::new()))
} else {
- input.parse_comma_separated(|parser| {
+ ${parse_func}(input, |parser| {
single_value::parse(context, parser)
}).map(SpecifiedValue)
}
% else:
- input.parse_comma_separated(|parser| {
+ ${parse_func}(input, |parser| {
single_value::parse(context, parser)
}).map(SpecifiedValue)
% endif
diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs
index a0284a23bec..6cb2026b1d6 100644
--- a/components/style/properties/longhand/box.mako.rs
+++ b/components/style/properties/longhand/box.mako.rs
@@ -1922,6 +1922,7 @@ ${helpers.single_keyword("-moz-appearance",
${helpers.predefined_type("-moz-binding", "UrlOrNone", "Either::Second(None_)",
products="gecko",
animatable="False",
+ gecko_ffi_name="mBinding",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding)",
disable_when_testing="True",
boxed=True)}
diff --git a/components/style/properties/longhand/effects.mako.rs b/components/style/properties/longhand/effects.mako.rs
index eb4879f7afb..b5dbdf60dc8 100644
--- a/components/style/properties/longhand/effects.mako.rs
+++ b/components/style/properties/longhand/effects.mako.rs
@@ -94,6 +94,7 @@ ${helpers.predefined_type("clip",
use style_traits::{self, ToCss};
use values::{CSSFloat, HasViewportPercentage};
use values::specified::{Angle, CSSColor, Length, Shadow};
+ use values::specified::url::SpecifiedUrl;
impl HasViewportPercentage for SpecifiedValue {
fn has_viewport_percentage(&self) -> bool {
@@ -129,6 +130,7 @@ ${helpers.predefined_type("clip",
Sepia(CSSFloat),
% if product == "gecko":
DropShadow(Shadow),
+ Url(SpecifiedUrl),
% endif
}
@@ -136,7 +138,8 @@ ${helpers.predefined_type("clip",
use app_units::Au;
use values::CSSFloat;
use values::computed::{CSSColor, Shadow};
- use values::specified::{Angle};
+ use values::specified::Angle;
+ use values::specified::url::SpecifiedUrl;
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
@@ -152,6 +155,7 @@ ${helpers.predefined_type("clip",
Sepia(CSSFloat),
% if product == "gecko":
DropShadow(Shadow),
+ Url(SpecifiedUrl),
% endif
}
@@ -262,6 +266,11 @@ ${helpers.predefined_type("clip",
try!(shadow.color.to_css(dest));
try!(dest.write_str(")"));
}
+ computed_value::Filter::Url(ref url) => {
+ dest.write_str("url(")?;
+ url.to_css(dest)?;
+ dest.write_str(")")?;
+ }
% endif
}
Ok(())
@@ -302,6 +311,11 @@ ${helpers.predefined_type("clip",
}
try!(dest.write_str(")"));
}
+ SpecifiedFilter::Url(ref url) => {
+ dest.write_str("url(")?;
+ url.to_css(dest)?;
+ dest.write_str(")")?;
+ }
% endif
}
Ok(())
@@ -319,6 +333,11 @@ ${helpers.predefined_type("clip",
return Ok(SpecifiedValue(filters))
}
loop {
+ % if product == "gecko":
+ if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
+ filters.push(SpecifiedFilter::Url(url));
+ } else
+ % endif
if let Ok(function_name) = input.try(|input| input.expect_function()) {
filters.push(try!(input.parse_nested_block(|input| {
match_ignore_ascii_case! { function_name,
@@ -375,6 +394,9 @@ ${helpers.predefined_type("clip",
SpecifiedFilter::DropShadow(ref shadow) => {
computed_value::Filter::DropShadow(shadow.to_computed_value(context))
},
+ SpecifiedFilter::Url(ref url) => {
+ computed_value::Filter::Url(url.to_computed_value(context))
+ }
% endif
}
}).collect() }
@@ -394,9 +416,14 @@ ${helpers.predefined_type("clip",
computed_value::Filter::Saturate(factor) => SpecifiedFilter::Saturate(factor),
computed_value::Filter::Sepia(factor) => SpecifiedFilter::Sepia(factor),
% if product == "gecko":
- computed_value::Filter::DropShadow(shadow) => {
+ computed_value::Filter::DropShadow(ref shadow) => {
SpecifiedFilter::DropShadow(
- ToComputedValue::from_computed_value(&shadow),
+ ToComputedValue::from_computed_value(shadow),
+ )
+ }
+ computed_value::Filter::Url(ref url) => {
+ SpecifiedFilter::Url(
+ ToComputedValue::from_computed_value(url),
)
}
% endif
diff --git a/components/style/properties/longhand/inherited_svg.mako.rs b/components/style/properties/longhand/inherited_svg.mako.rs
index 56987f0ba75..ffba35e83f3 100644
--- a/components/style/properties/longhand/inherited_svg.mako.rs
+++ b/components/style/properties/longhand/inherited_svg.mako.rs
@@ -33,6 +33,14 @@ ${helpers.single_keyword("color-interpolation-filters", "auto sRGB linearRGB",
animatable=False,
spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty")}
+${helpers.predefined_type(
+ "fill", "SVGPaint",
+ "::values::computed::SVGPaint::black()",
+ products="gecko",
+ animatable=False,
+ boxed=True,
+ spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint")}
+
${helpers.predefined_type("fill-opacity", "Opacity", "1.0",
products="gecko", animatable=False,
spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty")}
@@ -49,6 +57,23 @@ ${helpers.single_keyword("shape-rendering",
animatable=False,
spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty")}
+${helpers.predefined_type(
+ "stroke", "SVGPaint",
+ "Default::default()",
+ products="gecko",
+ animatable=False,
+ boxed=True,
+ spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint")}
+
+${helpers.predefined_type(
+ "stroke-width", "LengthOrPercentage",
+ "computed::LengthOrPercentage::one()",
+ "parse_numbers_are_pixels_non_negative",
+ products="gecko",
+ animatable=True,
+ needs_context=False,
+ spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")}
+
${helpers.single_keyword("stroke-linecap", "butt round square",
products="gecko", animatable=False,
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty")}
@@ -67,6 +92,23 @@ ${helpers.predefined_type("stroke-opacity", "Opacity", "1.0",
products="gecko", animatable=False,
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")}
+${helpers.predefined_type("stroke-dasharray", "LoPOrNumber", "Either::Second(0.0)",
+ "parse_non_negative",
+ vector="True",
+ products="gecko",
+ animatable="False",
+ space_separated_allowed="True",
+ spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}
+
+${helpers.predefined_type(
+ "stroke-dashoffset", "LengthOrPercentage",
+ "computed::LengthOrPercentage::zero()",
+ "parse_numbers_are_pixels",
+ products="gecko",
+ animatable=True,
+ needs_context=False,
+ spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}
+
// Section 14 - Clipping, Masking and Compositing
${helpers.single_keyword("clip-rule", "nonzero evenodd",
products="gecko",
@@ -74,3 +116,153 @@ ${helpers.single_keyword("clip-rule", "nonzero evenodd",
gecko_inexhaustive=True,
animatable=False,
spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty")}
+
+${helpers.predefined_type("marker-start", "UrlOrNone", "Either::Second(None_)",
+ products="gecko",
+ animatable="False",
+ spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
+
+${helpers.predefined_type("marker-mid", "UrlOrNone", "Either::Second(None_)",
+ products="gecko",
+ animatable="False",
+ spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
+
+${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
+ products="gecko",
+ animatable="False",
+ spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
+
+<%helpers:longhand name="paint-order"
+ animatable="False"
+ products="gecko"
+ spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder">
+
+ use values::computed::ComputedValueAsSpecified;
+ use std::fmt;
+ use style_traits::ToCss;
+ use values::HasViewportPercentage;
+
+ pub const NORMAL: u8 = 0;
+ pub const FILL: u8 = 1;
+ pub const STROKE: u8 = 2;
+ pub const MARKERS: u8 = 3;
+
+ // number of bits for each component
+ pub const SHIFT: u8 = 2;
+ // mask with above bits set
+ pub const MASK: u8 = 0b11;
+ // number of non-normal keyword values
+ pub const COUNT: u8 = 3;
+ // all keywords
+ pub const ALL: [u8; 3] = [FILL, STROKE, MARKERS];
+
+ /// Represented as a six-bit field, of 3 two-bit pairs
+ ///
+ /// Each pair can be set to FILL, STROKE, or MARKERS
+ /// Lowest significant bit pairs are highest priority.
+ /// `normal` is the empty bitfield. The three pairs are
+ /// never zero in any case other than `normal`.
+ ///
+ /// Higher priority values, i.e. the values specified first,
+ /// will be painted first (and may be covered by paintings of lower priority)
+ #[derive(PartialEq, Clone, Copy, Debug)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ pub struct SpecifiedValue(pub u8);
+
+ pub mod computed_value {
+ pub use super::SpecifiedValue as T;
+ }
+
+ pub fn get_initial_value() -> SpecifiedValue {
+ SpecifiedValue(NORMAL)
+ }
+
+ impl SpecifiedValue {
+ pub fn bits_at(&self, pos: u8) -> u8 {
+ (self.0 >> pos * SHIFT) & MASK
+ }
+ }
+
+ pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
+ if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
+ Ok(SpecifiedValue(0))
+ } else {
+ let mut value = 0;
+ // bitfield representing what we've seen so far
+ // bit 1 is fill, bit 2 is stroke, bit 3 is markers
+ let mut seen = 0;
+ let mut pos = 0;
+
+ loop {
+
+ let result = input.try(|i| {
+ match_ignore_ascii_case! { i.expect_ident()?,
+ "fill" => Ok(FILL),
+ "stroke" => Ok(STROKE),
+ "markers" => Ok(MARKERS),
+ _ => Err(())
+ }
+ });
+
+ match result {
+ Ok(val) => {
+ if (seen & (1 << val)) != 0 {
+ // don't parse the same ident twice
+ return Err(())
+ } else {
+ value |= val << (pos * SHIFT);
+ seen |= 1 << val;
+ pos += 1;
+ }
+ }
+ Err(()) => break,
+ }
+ }
+
+ if value == 0 {
+ // couldn't find any keyword
+ Err(())
+ } else {
+ // fill in rest
+ for i in pos..COUNT {
+ for paint in &ALL {
+ // if not seen, set bit at position, mark as seen
+ if (seen & (1 << paint)) == 0 {
+ seen |= 1 << paint;
+ value |= paint << (i * SHIFT);
+ break;
+ }
+ }
+ }
+
+ Ok(SpecifiedValue(value))
+ }
+ }
+ }
+
+ impl ToCss for SpecifiedValue {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ if self.0 == 0 {
+ return dest.write_str("normal")
+ }
+
+ for pos in 0..COUNT {
+ if pos != 0 {
+ dest.write_str(" ")?
+ }
+ match self.bits_at(pos) {
+ FILL => dest.write_str("fill")?,
+ STROKE => dest.write_str("stroke")?,
+ MARKERS => dest.write_str("markers")?,
+ _ => unreachable!(),
+ }
+ }
+ Ok(())
+ }
+ }
+
+ no_viewport_percentage!(SpecifiedValue);
+
+ impl ComputedValueAsSpecified for SpecifiedValue { }
+</%helpers:longhand>
+
diff --git a/components/style/properties/shorthand/inherited_svg.mako.rs b/components/style/properties/shorthand/inherited_svg.mako.rs
new file mode 100644
index 00000000000..24d6e37890c
--- /dev/null
+++ b/components/style/properties/shorthand/inherited_svg.mako.rs
@@ -0,0 +1,36 @@
+/* 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/. */
+
+<%namespace name="helpers" file="/helpers.mako.rs" />
+
+<%helpers:shorthand name="marker" products="gecko"
+ sub_properties="marker-start marker-end marker-mid"
+ spec="https://www.w3.org/TR/SVG2/painting.html#MarkerShorthand">
+ use values::specified::UrlOrNone;
+
+ pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
+ let url = UrlOrNone::parse(context, input)?;
+
+ Ok(Longhands {
+ marker_start: url.clone(),
+ marker_mid: url.clone(),
+ marker_end: url,
+ })
+ }
+
+ impl<'a> LonghandsToSerialize<'a> {
+ fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ if let DeclaredValue::Value(ref start) = *self.marker_start {
+ if let DeclaredValue::Value(ref mid) = *self.marker_mid {
+ if let DeclaredValue::Value(ref end) = *self.marker_end {
+ if start == mid && mid == end {
+ start.to_css(dest)?;
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+ }
+</%helpers:shorthand>
diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs
index 74c9fd6287f..492bbfb4bc0 100644
--- a/components/style/values/computed/length.rs
+++ b/components/style/values/computed/length.rs
@@ -4,7 +4,7 @@
//! `<length>` computed values, and related ones.
-use app_units::Au;
+use app_units::{Au, AU_PER_PX};
use ordered_float::NotNaN;
use std::fmt;
use style_traits::ToCss;
@@ -195,6 +195,12 @@ impl LengthOrPercentage {
LengthOrPercentage::Length(Au(0))
}
+ #[inline]
+ /// 1px length value for SVG defaults
+ pub fn one() -> LengthOrPercentage {
+ LengthOrPercentage::Length(Au(AU_PER_PX))
+ }
+
/// Returns true if the computed value is absolute 0 or 0%.
///
/// (Returns false for calc() values, even if ones that may resolve to zero.)
diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs
index 3c22ab1a8bb..b505d2364c8 100644
--- a/components/style/values/computed/mod.rs
+++ b/components/style/values/computed/mod.rs
@@ -10,7 +10,7 @@ use font_metrics::FontMetricsProvider;
use properties::ComputedValues;
use std::fmt;
use style_traits::ToCss;
-use super::{CSSFloat, specified};
+use super::{CSSFloat, RGBA, specified};
pub use cssparser::Color as CSSColor;
pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image};
@@ -19,7 +19,7 @@ pub use super::{Auto, Either, None_};
#[cfg(feature = "gecko")]
pub use super::specified::{AlignJustifyContent, AlignJustifySelf};
pub use super::specified::{Angle, BorderStyle, GridLine, Time, UrlOrNone};
-pub use super::specified::url::UrlExtraData;
+pub use super::specified::url::{SpecifiedUrl, UrlExtraData};
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone};
pub use self::position::Position;
@@ -185,6 +185,83 @@ pub type Number = CSSFloat;
pub type Opacity = CSSFloat;
+/// An SVG paint value
+///
+/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct SVGPaint {
+ /// The paint source
+ pub kind: SVGPaintKind,
+ /// The fallback color
+ pub fallback: Option<CSSColor>,
+}
+
+impl Default for SVGPaint {
+ fn default() -> Self {
+ SVGPaint {
+ kind: SVGPaintKind::None,
+ fallback: None,
+ }
+ }
+}
+
+impl SVGPaint {
+ /// Opaque black color
+ pub fn black() -> Self {
+ let rgba = RGBA::from_floats(0., 0., 0., 1.);
+ SVGPaint {
+ kind: SVGPaintKind::Color(CSSColor::RGBA(rgba)),
+ fallback: None,
+ }
+ }
+}
+
+/// 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.
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum SVGPaintKind {
+ /// `none`
+ None,
+ /// `<color>`
+ Color(CSSColor),
+ /// `url(...)`
+ PaintServer(SpecifiedUrl),
+ /// `context-fill`
+ ContextFill,
+ /// `context-stroke`
+ ContextStroke,
+}
+
+impl ToCss for SVGPaintKind {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ SVGPaintKind::None => dest.write_str("none"),
+ SVGPaintKind::ContextStroke => dest.write_str("context-stroke"),
+ SVGPaintKind::ContextFill => dest.write_str("context-fill"),
+ SVGPaintKind::Color(ref color) => color.to_css(dest),
+ SVGPaintKind::PaintServer(ref server) => server.to_css(dest),
+ }
+ }
+}
+
+impl ToCss for SVGPaint {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ self.kind.to_css(dest)?;
+ if let Some(ref fallback) = self.fallback {
+ fallback.to_css(dest)?;
+ }
+ Ok(())
+ }
+}
+
+/// <length> | <percentage> | <number>
+pub type LoPOrNumber = Either<LengthOrPercentage, Number>;
+
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs
index fb4ac9c0b60..d2e64481a39 100644
--- a/components/style/values/specified/length.rs
+++ b/components/style/values/specified/length.rs
@@ -987,6 +987,34 @@ impl LengthOrPercentage {
LengthOrPercentage::parse_internal(input, AllowedNumericType::NonNegative)
}
+ /// Parse a length, treating dimensionless numbers as pixels
+ ///
+ /// https://www.w3.org/TR/SVG2/types.html#presentation-attribute-css-value
+ pub fn parse_numbers_are_pixels(input: &mut Parser) -> Result<LengthOrPercentage, ()> {
+ if let Ok(lop) = input.try(|i| Self::parse_internal(i, AllowedNumericType::All)) {
+ Ok(lop)
+ } else {
+ let num = input.expect_number()?;
+ Ok(LengthOrPercentage::Length(NoCalcLength::Absolute(Au((AU_PER_PX * num) as i32))))
+ }
+ }
+
+ /// Parse a non-negative length, treating dimensionless numbers as pixels
+ ///
+ /// This is nonstandard behavior used by Firefox for SVG
+ pub fn parse_numbers_are_pixels_non_negative(input: &mut Parser) -> Result<LengthOrPercentage, ()> {
+ if let Ok(lop) = input.try(|i| Self::parse_internal(i, AllowedNumericType::NonNegative)) {
+ Ok(lop)
+ } else {
+ let num = input.expect_number()?;
+ if num >= 0. {
+ Ok(LengthOrPercentage::Length(NoCalcLength::Absolute(Au((AU_PER_PX * num) as i32))))
+ } else {
+ Err(())
+ }
+ }
+ }
+
/// Extract value from ref without a clone, replacing it with a 0 Au
///
/// Use when you need to move out of a length array without cloning
diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs
index e79d68b7777..f959a63902a 100644
--- a/components/style/values/specified/mod.rs
+++ b/components/style/values/specified/mod.rs
@@ -670,6 +670,175 @@ impl Shadow {
}
}
+no_viewport_percentage!(SVGPaint);
+
+/// An SVG paint value
+///
+/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct SVGPaint {
+ /// The paint source
+ pub kind: SVGPaintKind,
+ /// The fallback color
+ pub fallback: Option<CSSColor>,
+}
+
+/// 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.
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum SVGPaintKind {
+ /// `none`
+ None,
+ /// `<color>`
+ Color(CSSColor),
+ /// `url(...)`
+ PaintServer(SpecifiedUrl),
+ /// `context-fill`
+ ContextFill,
+ /// `context-stroke`
+ ContextStroke,
+}
+
+impl SVGPaintKind {
+ fn parse_ident(input: &mut Parser) -> Result<Self, ()> {
+ Ok(match_ignore_ascii_case! { input.expect_ident()?,
+ "none" => SVGPaintKind::None,
+ "context-fill" => SVGPaintKind::ContextFill,
+ "context-stroke" => SVGPaintKind::ContextStroke,
+ _ => return Err(())
+ })
+ }
+}
+
+impl Parse for SVGPaint {
+ fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
+ let fallback = input.try(|i| CSSColor::parse(context, i));
+ Ok(SVGPaint {
+ kind: SVGPaintKind::PaintServer(url),
+ fallback: fallback.ok(),
+ })
+ } else if let Ok(kind) = input.try(SVGPaintKind::parse_ident) {
+ if kind == SVGPaintKind::None {
+ Ok(SVGPaint {
+ kind: kind,
+ fallback: None,
+ })
+ } else {
+ let fallback = input.try(|i| CSSColor::parse(context, i));
+ Ok(SVGPaint {
+ kind: kind,
+ fallback: fallback.ok(),
+ })
+ }
+ } else if let Ok(color) = input.try(|i| CSSColor::parse(context, i)) {
+ Ok(SVGPaint {
+ kind: SVGPaintKind::Color(color),
+ fallback: None,
+ })
+ } else {
+ Err(())
+ }
+ }
+}
+
+impl ToCss for SVGPaintKind {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ SVGPaintKind::None => dest.write_str("none"),
+ SVGPaintKind::ContextStroke => dest.write_str("context-stroke"),
+ SVGPaintKind::ContextFill => dest.write_str("context-fill"),
+ SVGPaintKind::Color(ref color) => color.to_css(dest),
+ SVGPaintKind::PaintServer(ref server) => server.to_css(dest),
+ }
+ }
+}
+
+impl ToCss for SVGPaint {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ self.kind.to_css(dest)?;
+ if let Some(ref fallback) = self.fallback {
+ fallback.to_css(dest)?;
+ }
+ Ok(())
+ }
+}
+
+
+impl ToComputedValue for SVGPaint {
+ type ComputedValue = super::computed::SVGPaint;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+ super::computed::SVGPaint {
+ kind: self.kind.to_computed_value(context),
+ fallback: self.fallback.as_ref().map(|f| f.to_computed_value(context))
+ }
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+ SVGPaint {
+ kind: ToComputedValue::from_computed_value(&computed.kind),
+ fallback: computed.fallback.as_ref().map(ToComputedValue::from_computed_value)
+ }
+ }
+}
+
+impl ToComputedValue for SVGPaintKind {
+ type ComputedValue = super::computed::SVGPaintKind;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+ match *self {
+ SVGPaintKind::None => super::computed::SVGPaintKind::None,
+ SVGPaintKind::ContextStroke => super::computed::SVGPaintKind::ContextStroke,
+ SVGPaintKind::ContextFill => super::computed::SVGPaintKind::ContextFill,
+ SVGPaintKind::Color(ref color) => {
+ super::computed::SVGPaintKind::Color(color.to_computed_value(context))
+ }
+ SVGPaintKind::PaintServer(ref server) => {
+ super::computed::SVGPaintKind::PaintServer(server.to_computed_value(context))
+ }
+ }
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+ match *computed {
+ super::computed::SVGPaintKind::None => SVGPaintKind::None,
+ super::computed::SVGPaintKind::ContextStroke => SVGPaintKind::ContextStroke,
+ super::computed::SVGPaintKind::ContextFill => SVGPaintKind::ContextFill,
+ super::computed::SVGPaintKind::Color(ref color) => {
+ SVGPaintKind::Color(ToComputedValue::from_computed_value(color))
+ }
+ super::computed::SVGPaintKind::PaintServer(ref server) => {
+ SVGPaintKind::PaintServer(ToComputedValue::from_computed_value(server))
+ }
+ }
+ }
+}
+
+/// <length> | <percentage> | <number>
+pub type LoPOrNumber = Either<LengthOrPercentage, Number>;
+
+impl LoPOrNumber {
+ /// parse a <length-percentage> | <number> enforcing that the contents aren't negative
+ pub fn parse_non_negative(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ if let Ok(lop) = input.try(LengthOrPercentage::parse_non_negative) {
+ Ok(Either::First(lop))
+ } else if let Ok(num) = input.try(Number::parse_non_negative) {
+ Ok(Either::Second(num))
+ } else {
+ Err(())
+ }
+ }
+}
impl HasViewportPercentage for ClipRect {
fn has_viewport_percentage(&self) -> bool {
diff --git a/components/style/values/specified/url.rs b/components/style/values/specified/url.rs
index 41af5a16dea..f6b8dd2de29 100644
--- a/components/style/values/specified/url.rs
+++ b/components/style/values/specified/url.rs
@@ -6,6 +6,8 @@
use cssparser::{CssStringWriter, Parser};
#[cfg(feature = "gecko")]
+use gecko_bindings::structs::ServoBundledURI;
+#[cfg(feature = "gecko")]
use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
use parser::{Parse, ParserContext};
#[cfg(feature = "gecko")]
@@ -167,6 +169,24 @@ impl SpecifiedUrl {
extra_data: UrlExtraData {}
}
}
+
+ /// Create a bundled URI suitable for sending to Gecko
+ /// to be constructed into a css::URLValue
+ #[cfg(feature = "gecko")]
+ pub fn for_ffi(&self) -> Option<ServoBundledURI> {
+ let extra_data = self.extra_data();
+ let (ptr, len) = match self.as_slice_components() {
+ Ok(value) => value,
+ Err(_) => return None,
+ };
+ Some(ServoBundledURI {
+ mURLString: ptr,
+ mURLStringLength: len as u32,
+ mBaseURI: extra_data.base.get(),
+ mReferrer: extra_data.referrer.get(),
+ mPrincipal: extra_data.principal.get(),
+ })
+ }
}
impl PartialEq for SpecifiedUrl {