Bug 1338388 - Part 7: stylo: Add mako template for URLOrNone, use for marker-* properties; r?heycam draft
authorManish Goregaokar <manishearth@gmail.com>
Thu, 09 Feb 2017 17:43:52 -0800
changeset 486530 18821229c1eaedaa7039dc0e9c9b3954dfd15524
parent 486497 ec0fa995ffb16bdac183b285ffce29af41583df9
child 486531 62f8444622902894f534ac912af973ea79922c0e
push id46017
push userbmo:manishearth@gmail.com
push dateSat, 18 Feb 2017 08:18:38 +0000
reviewersheycam
bugs1338388
milestone54.0a1
Bug 1338388 - Part 7: stylo: Add mako template for URLOrNone, use for marker-* properties; r?heycam MozReview-Commit-ID: 4QKKzJ1DVYP
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
servo/components/style/build_gecko.rs
servo/components/style/gecko_bindings/bindings.rs
servo/components/style/gecko_bindings/sugar/refptr.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/box.mako.rs
servo/components/style/properties/longhand/inherited_svg.mako.rs
servo/components/style/values/specified/url.rs
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -763,30 +763,16 @@ ServoBundledURI::IntoCssUrl()
   RefPtr<css::URLValue> urlValue = new css::URLValue(urlBuffer,
                                                      do_AddRef(mBaseURI),
                                                      do_AddRef(mReferrer),
                                                      do_AddRef(mPrincipal));
   return urlValue.forget();
 }
 
 void
-Gecko_SetMozBinding(nsStyleDisplay* aDisplay, ServoBundledURI aBundledURI)
-{
-    MOZ_ASSERT(aDisplay);
-    aDisplay->mBinding = aBundledURI.IntoCssUrl();
-}
-
-void
-Gecko_CopyMozBindingFrom(nsStyleDisplay* aDest, const nsStyleDisplay* aSrc)
-{
-  aDest->mBinding = aSrc->mBinding;
-}
-
-
-void
 Gecko_SetNullImageValue(nsStyleImage* aImage)
 {
   MOZ_ASSERT(aImage);
   aImage->SetNull();
 }
 
 void
 Gecko_SetGradientImageValue(nsStyleImage* aImage, nsStyleGradient* aGradient)
@@ -1088,16 +1074,25 @@ Gecko_nsStyleSVGPaint_SetURLValue(nsStyl
   aPaint->SetPaintServer(url.get(), NS_RGB(0, 0, 0));
 }
 
 void Gecko_nsStyleSVGPaint_Reset(nsStyleSVGPaint* aPaint)
 {
   aPaint->SetNone();
 }
 
+css::URLValue*
+Gecko_NewURLValue(ServoBundledURI aURI)
+{
+  RefPtr<css::URLValue> url = aURI.IntoCssUrl();
+  return url.forget().take();
+}
+
+NS_IMPL_THREADSAFE_FFI_REFCOUNTING(css::URLValue, CSSURLValue);
+
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
 nsCSSShadowArray*
 Gecko_NewCSSShadowArray(uint32_t aLen)
 {
   RefPtr<nsCSSShadowArray> arr = new(aLen) nsCSSShadowArray(aLen);
   return arr.forget().take();
 }
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -228,20 +228,16 @@ void Gecko_SetCursorArrayLength(nsStyleU
 void Gecko_SetCursorImage(nsCursorImage* cursor,
                           const uint8_t* string_bytes, uint32_t string_length,
                           ThreadSafeURIHolder* base_uri,
                           ThreadSafeURIHolder* referrer,
                           ThreadSafePrincipalHolder* principal);
 void Gecko_CopyCursorArrayFrom(nsStyleUserInterface* dest,
                                const nsStyleUserInterface* src);
 
-// Display style.
-void Gecko_SetMozBinding(nsStyleDisplay* style_struct, ServoBundledURI bundled_uri);
-void Gecko_CopyMozBindingFrom(nsStyleDisplay* des, const nsStyleDisplay* src);
-
 // Dirtiness tracking.
 uint32_t Gecko_GetNodeFlags(RawGeckoNodeBorrowed node);
 void Gecko_SetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
 void Gecko_UnsetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
 void Gecko_SetOwnerDocumentNeedsStyleFlush(RawGeckoElementBorrowed element);
 
 // Incremental restyle.
 // Also, we might want a ComputedValues to ComputedValues API for animations?
@@ -297,16 +293,19 @@ void Gecko_StyleClipPath_SetURLValue(moz
 void Gecko_ResetFilters(nsStyleEffects* effects, size_t new_len);
 void Gecko_CopyFiltersFrom(nsStyleEffects* aSrc, nsStyleEffects* aDest);
 void Gecko_nsStyleFilter_SetURLValue(nsStyleFilter* effects, ServoBundledURI uri);
 
 void Gecko_nsStyleSVGPaint_CopyFrom(nsStyleSVGPaint* dest, const nsStyleSVGPaint* src);
 void Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* paint, ServoBundledURI uri);
 void Gecko_nsStyleSVGPaint_Reset(nsStyleSVGPaint* paint);
 
+mozilla::css::URLValue* Gecko_NewURLValue(ServoBundledURI uri);
+NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::URLValue, CSSURLValue);
+
 void Gecko_FillAllBackgroundLists(nsStyleImageLayers* layers, uint32_t max_len);
 void Gecko_FillAllMaskLists(nsStyleImageLayers* layers, uint32_t max_len);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
 nsCSSShadowArray* Gecko_NewCSSShadowArray(uint32_t len);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSShadowArray, CSSShadowArray);
 
 nsStyleQuoteValues* Gecko_NewStyleQuoteValues(uint32_t len);
--- a/servo/components/style/build_gecko.rs
+++ b/servo/components/style/build_gecko.rs
@@ -503,16 +503,17 @@ mod bindings {
             .hide_type("nsACString_internal")
             .hide_type("nsAString_internal")
             .raw_line("pub use nsstring::{nsACString, nsAString};")
             .raw_line("type nsACString_internal = nsACString;")
             .raw_line("type nsAString_internal = nsAString;")
             .whitelisted_function("Servo_.*")
             .whitelisted_function("Gecko_.*");
         let structs_types = [
+            "mozilla::css::URLValue",
             "RawGeckoDocument",
             "RawGeckoElement",
             "RawGeckoKeyframeList",
             "RawGeckoNode",
             "RawGeckoAnimationValueList",
             "RawServoAnimationValue",
             "RawServoDeclarationBlock",
             "RawGeckoPresContext",
--- a/servo/components/style/gecko_bindings/bindings.rs
+++ b/servo/components/style/gecko_bindings/bindings.rs
@@ -1,13 +1,14 @@
 /* automatically generated by rust-bindgen */
 
 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;
 use gecko_bindings::structs::RawGeckoNode;
 use gecko_bindings::structs::RawGeckoAnimationValueList;
 use gecko_bindings::structs::RawServoAnimationValue;
 use gecko_bindings::structs::RawServoDeclarationBlock;
 use gecko_bindings::structs::RawGeckoPresContext;
@@ -614,24 +615,16 @@ extern "C" {
                                 referrer: *mut ThreadSafeURIHolder,
                                 principal: *mut ThreadSafePrincipalHolder);
 }
 extern "C" {
     pub fn Gecko_CopyCursorArrayFrom(dest: *mut nsStyleUserInterface,
                                      src: *const nsStyleUserInterface);
 }
 extern "C" {
-    pub fn Gecko_SetMozBinding(style_struct: *mut nsStyleDisplay,
-                               bundled_uri: ServoBundledURI);
-}
-extern "C" {
-    pub fn Gecko_CopyMozBindingFrom(des: *mut nsStyleDisplay,
-                                    src: *const nsStyleDisplay);
-}
-extern "C" {
     pub fn Gecko_GetNodeFlags(node: RawGeckoNodeBorrowed) -> u32;
 }
 extern "C" {
     pub fn Gecko_SetNodeFlags(node: RawGeckoNodeBorrowed, flags: u32);
 }
 extern "C" {
     pub fn Gecko_UnsetNodeFlags(node: RawGeckoNodeBorrowed, flags: u32);
 }
@@ -725,16 +718,25 @@ extern "C" {
 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_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);
 }
 extern "C" {
     pub fn Gecko_FillAllMaskLists(layers: *mut nsStyleImageLayers,
                                   max_len: u32);
 }
 extern "C" {
--- a/servo/components/style/gecko_bindings/sugar/refptr.rs
+++ b/servo/components/style/gecko_bindings/sugar/refptr.rs
@@ -259,15 +259,18 @@ impl_threadsafe_refcount!(::gecko_bindin
                           Gecko_AddRefURIArbitraryThread,
                           Gecko_ReleaseURIArbitraryThread);
 impl_threadsafe_refcount!(::gecko_bindings::structs::nsStyleQuoteValues,
                           Gecko_AddRefQuoteValuesArbitraryThread,
                           Gecko_ReleaseQuoteValuesArbitraryThread);
 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>;
 
 /// A Gecko `ThreadSafeURIHolder` wrapped in a safe refcounted pointer, to use
 /// during stylesheet parsing and style computation.
 pub type GeckoArcURI = RefPtr<::gecko_bindings::structs::ThreadSafeURIHolder>;
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -21,28 +21,26 @@ use gecko_bindings::bindings::Gecko_Copy
 use gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name};
 % endfor
 use gecko_bindings::bindings::Gecko_Construct_nsStyleVariables;
 use gecko_bindings::bindings::Gecko_CopyCursorArrayFrom;
 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;
 use gecko_bindings::bindings::Gecko_FontFamilyList_Clear;
 use gecko_bindings::bindings::Gecko_SetCursorArrayLength;
 use gecko_bindings::bindings::Gecko_SetCursorImage;
 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};
 use gecko_bindings::bindings::RawGeckoPresContextBorrowed;
 use gecko_bindings::structs;
 use gecko_bindings::structs::nsStyleVariables;
 use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
 use gecko_bindings::sugar::ownership::HasArcFFI;
@@ -393,17 +391,21 @@ fn color_to_nscolor_zero_currentcolor(co
             SVGPaintKind::ContextFill => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextFill;
             }
             SVGPaintKind::ContextStroke => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextStroke;
             }
             SVGPaintKind::PaintServer(url) => {
                 unsafe {
-                    bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, url.for_ffi());
+                    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);
                 }
             }
@@ -506,16 +508,51 @@ fn color_to_nscolor_zero_currentcolor(co
             let height = GeckoStyleCoordConvertible::from_gecko_style_coord(
                             &self.gecko.${gecko_ffi_name}.data_at(${y_index}))
                             .expect("Failed to clone ${ident}");
             T(Size2D::new(width, height))
         }
     % 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>
 
 <%def name="impl_style_struct(style_struct)">
 impl ${style_struct.gecko_struct_name} {
     #[allow(dead_code, unused_variables)]
     pub fn default(pres_context: RawGeckoPresContextBorrowed) -> Arc<Self> {
@@ -595,16 +632,17 @@ impl Debug for ${style_struct.gecko_stru
         "LengthOrPercentage": impl_style_coord,
         "LengthOrPercentageOrAuto": impl_style_coord,
         "LengthOrPercentageOrNone": impl_style_coord,
         "LengthOrNone": impl_style_coord,
         "Number": impl_simple,
         "Opacity": impl_simple,
         "CSSColor": impl_color,
         "SVGPaint": impl_svg_paint,
+        "UrlOrNone": impl_css_url,
     }
 
     def longhand_method(longhand):
         args = dict(ident=longhand.ident, gecko_ffi_name=longhand.gecko_ffi_name,
                     need_clone=longhand.need_clone)
 
         # get the method and pass additional keyword or type-specific arguments
         if longhand.logical:
@@ -1273,17 +1311,17 @@ fn static_assert() {
     ${impl_animation_count(ident, gecko_ffi_name)}
     ${impl_copy_animation_value(ident, gecko_ffi_name)}
 </%def>
 
 <% skip_box_longhands= """display overflow-y vertical-align
                           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""" %>
 <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
 
     // We manually-implement the |display| property until we get general
     // infrastructure for preffing certain values.
     <% display_keyword = Keyword("display", "inline block inline-block table inline-table table-row-group " +
@@ -1368,34 +1406,16 @@ fn static_assert() {
                         .expect("Expected length or percentage for vertical-align");
                     T::LengthOrPercentage(v)
                 }
         }
     }
 
     <%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) => {
-
-                unsafe {
-                    Gecko_SetMozBinding(&mut self.gecko, url.for_ffi());
-                }
-            }
-        }
-    }
-    #[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'
     // as 'always'." - CSS2.1, section 13.3.1
     pub fn set_page_break_before(&mut self, v: longhands::page_break_before::computed_value::T) {
         use computed_values::page_break_before::T;
         let result = match v {
             T::auto   => false,
@@ -2110,18 +2130,22 @@ fn static_assert() {
         match image {
             Either::Second(_none) => {
                 unsafe {
                     Gecko_SetListStyleImageNone(&mut self.gecko);
                 }
             }
             Either::First(ref url) => {
                 unsafe {
-                    Gecko_SetListStyleImage(&mut self.gecko,
-                                            url.for_ffi());
+                    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
                 // are re-used from the applicable declaration cache, and the List struct
                 // is an inherited struct.
             }
         }
     }
@@ -2312,17 +2336,19 @@ fn static_assert() {
                         },
                         // TODO handle currentColor
                         // https://bugzilla.mozilla.org/show_bug.cgi?id=760345
                         Color::CurrentColor => 0,
                     };
                 }
                 Url(ref url) => {
                     unsafe {
-                        bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, url.for_ffi());
+                        if let Some(ffi) = url.for_ffi() {
+                            bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, ffi);
+                        }
                     }
                 }
             }
         }
     }
 
     pub fn copy_filter_from(&mut self, other: &Self) {
         unsafe {
@@ -2672,17 +2698,19 @@ clip-path
         // clean up existing struct
         unsafe { Gecko_DestroyClipPath(clip_path) };
 
         clip_path.mType = StyleShapeSourceType::None;
 
         match v {
             ShapeSource::Url(ref url) => {
                 unsafe {
-                    bindings::Gecko_StyleClipPath_SetURLValue(clip_path, url.for_ffi());
+                    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();
                 clip_path.mType = StyleShapeSourceType::Box;
             }
             ShapeSource::Shape(servo_shape, maybe_box) => {
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -1917,16 +1917,17 @@
                          gecko_constant_prefix="NS_THEME",
                          products="gecko",
                          spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)",
                          animatable=False)}
 
 ${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)}
 
 ${helpers.single_keyword("-moz-orient",
                           "inline block horizontal vertical",
                           products="gecko",
                           gecko_ffi_name="mOrient",
--- a/servo/components/style/properties/longhand/inherited_svg.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_svg.mako.rs
@@ -95,8 +95,27 @@
 
 // Section 14 - Clipping, Masking and Compositing
 ${helpers.single_keyword("clip-rule", "nonzero evenodd",
                          products="gecko",
                          gecko_enum_prefix="StyleFillRule",
                          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",
+                          boxed=True)}
+
+${helpers.predefined_type("marker-mid", "UrlOrNone", "Either::Second(None_)",
+                          products="gecko",
+                          animatable="False",
+                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
+                          boxed=True)}
+
+${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
+                          products="gecko",
+                          animatable="False",
+                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
+                          boxed=True)}
+
--- a/servo/components/style/values/specified/url.rs
+++ b/servo/components/style/values/specified/url.rs
@@ -167,30 +167,29 @@ impl SpecifiedUrl {
             original: Some(Arc::new(url.into())),
             resolved: ServoUrl::parse(url).ok(),
             extra_data: UrlExtraData {}
         }
     }
 
     /// Create a bundled URI suitable for sending to Gecko
     /// to be constructed into a css::URLValue
-    pub fn for_ffi(&self) -> ServoBundledURI {
-        use std::ptr;
+    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(_) => (ptr::null(), 0),
+            Err(_) => return None,
         };
-        ServoBundledURI {
+        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 {
     fn eq(&self, other: &Self) -> bool {
         // TODO(emilio): maybe we care about equality of the specified values if
         // present? Seems not.
         self.resolved == other.resolved &&