Support url() values in background-image and mask-image in stylo. r=manishearth draft
authorCameron McCormack <cam@mcc.id.au>
Mon, 10 Oct 2016 14:55:19 +0800
changeset 426810 ddec05aaaa00dc266f1b1b591cc6d5922ad155a7
parent 426809 8f608a643704c7ff3220221b4d276a20f2d5b8e6
child 534271 ff8d12d283ebf99fedbc3e9a523b95e5d3ce0b08
push id32806
push userbmo:cam@mcc.id.au
push dateWed, 19 Oct 2016 05:46:23 +0000
reviewersmanishearth
milestone52.0a1
Support url() values in background-image and mask-image in stylo. r=manishearth MozReview-Commit-ID: 7IUzzVV9rOi
servo/components/style/properties/data.py
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/helpers.mako.rs
servo/components/style/properties/longhand/background.mako.rs
servo/components/style/properties/longhand/svg.mako.rs
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -58,27 +58,28 @@ class Keyword(object):
     def maybe_cast(self, type_str):
         return "as " + type_str if self.needs_cast() else ""
 
 
 class Longhand(object):
     def __init__(self, style_struct, name, animatable=None, derived_from=None, keyword=None,
                  predefined_type=None, custom_cascade=False, experimental=False, internal=False,
                  need_clone=False, need_index=False, gecko_ffi_name=None, depend_on_viewport_size=False,
-                 allowed_in_keyframe_block=True):
+                 allowed_in_keyframe_block=True, has_uncacheable_values=False):
         self.name = name
         self.keyword = keyword
         self.predefined_type = predefined_type
         self.ident = to_rust_ident(name)
         self.camel_case = to_camel_case(self.ident)
         self.style_struct = style_struct
         self.experimental = ("layout.%s.enabled" % name) if experimental else None
         self.custom_cascade = custom_cascade
         self.internal = internal
         self.need_index = need_index
+        self.has_uncacheable_values = has_uncacheable_values
         self.gecko_ffi_name = gecko_ffi_name or "m" + self.camel_case
         self.depend_on_viewport_size = depend_on_viewport_size
         self.derived_from = (derived_from or "").split()
 
         # https://drafts.csswg.org/css-animations/#keyframes
         # > The <declaration-list> inside of <keyframe-block> accepts any CSS property
         # > except those defined in this specification,
         # > but does accept the `animation-play-state` property and interprets it specially.
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -25,16 +25,17 @@ use gecko_bindings::bindings::Gecko_Crea
 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_SetGradientImageValue;
 use gecko_bindings::bindings::Gecko_SetListStyleType;
 use gecko_bindings::bindings::Gecko_SetMozBinding;
 use gecko_bindings::bindings::Gecko_SetNullImageValue;
+use gecko_bindings::bindings::Gecko_SetUrlImageValue;
 use gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
 use gecko_bindings::structs;
 use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
 use gecko_bindings::sugar::ownership::HasArcFFI;
 use gecko::values::convert_nscolor_to_rgba;
 use gecko::values::convert_rgba_to_nscolor;
 use gecko::values::GeckoStyleCoordConvertible;
 use gecko::values::round_border_to_device_pixels;
@@ -1189,18 +1190,20 @@ fn static_assert() {
 
     pub fn copy_${shorthand}_image_from(&mut self, other: &Self) {
         unsafe {
             Gecko_CopyImageValueFrom(&mut self.gecko.${image_layers_field}.mLayers.mFirstElement.mImage,
                                      &other.gecko.${image_layers_field}.mLayers.mFirstElement.mImage);
         }
     }
 
+    #[allow(unused_variables)]
     pub fn set_${shorthand}_image(&mut self,
-                                  images: longhands::${shorthand}_image::computed_value::T) {
+                                  images: longhands::${shorthand}_image::computed_value::T,
+                                  cacheable: &mut bool) {
         use gecko_bindings::structs::nsStyleImage;
         use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SHAPE_CIRCULAR};
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL, NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER};
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER};
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE, NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE};
         use gecko_bindings::structs::nsStyleCoord;
         use values::computed::{Image, Gradient, GradientKind, GradientShape, LengthOrKeyword};
@@ -1378,23 +1381,30 @@ fn static_assert() {
         for (image, geckoimage) in images.0.into_iter().zip(self.gecko.${image_layers_field}
                                                                 .mLayers.iter_mut()) {
             % if shorthand == "background":
                 if let Some(image) = image.0 {
                     match image {
                         Image::Gradient(gradient) => {
                             set_gradient(gradient, &mut geckoimage.mImage)
                         },
-                        Image::Url(..) => {
-                            // let utf8_bytes = url.as_bytes();
-                            // Gecko_SetUrlImageValue(&mut self.gecko.mImage.mLayers.mFirstElement,
-                            //                        utf8_bytes.as_ptr() as *const _,
-                            //                        utf8_bytes.len());
-                            warn!("stylo: imgRequestProxies are not threadsafe in gecko, \
-                                   background-image: url() not yet implemented");
+                        Image::Url(ref url, ref extra_data) => {
+                            unsafe {
+                                Gecko_SetUrlImageValue(&mut geckoimage.mImage,
+                                                       url.as_str().as_ptr(),
+                                                       url.as_str().len() as u32,
+                                                       extra_data.base.get(),
+                                                       extra_data.referrer.get(),
+                                                       extra_data.principal.get());
+                            }
+                            // We unfortunately must make any url() value uncacheable, since
+                            // the applicable declarations cache is not per document, but
+                            // global, and the imgRequestProxy objects we store in the style
+                            // structs don't like to be tracked by more than one document.
+                            *cacheable = false;
                         }
                     }
                 }
             % else:
                 use properties::longhands::mask_image::single_value::computed_value::T;
                 match image {
                     T::Image(image) => match image {
                         Image::Gradient(gradient) => {
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -219,18 +219,23 @@
                     |value| {
                         if let Some(ref mut cascade_info) = *cascade_info {
                             cascade_info.on_cascade_property(&declaration,
                                                              &value);
                         }
                         match *value {
                             DeclaredValue::Value(ref specified_value) => {
                                 let computed = specified_value.to_computed_value(context);
+                                % if property.has_uncacheable_values:
+                                context.mutate_style().mutate_${data.current_style_struct.name_lower}()
+                                                      .set_${property.ident}(computed, cacheable);
+                                % else:
                                 context.mutate_style().mutate_${data.current_style_struct.name_lower}()
                                                       .set_${property.ident}(computed);
+                                % endif
                             }
                             DeclaredValue::WithVariables { .. } => unreachable!(),
                             DeclaredValue::Initial => {
                                 // We assume that it's faster to use copy_*_from rather than
                                 // set_*(get_initial_value());
                                 let initial_struct = ComputedValues::initial_values()
                                                       .get_${data.current_style_struct.name_lower}();
                                 context.mutate_style().mutate_${data.current_style_struct.name_lower}()
--- a/servo/components/style/properties/longhand/background.mako.rs
+++ b/servo/components/style/properties/longhand/background.mako.rs
@@ -5,17 +5,18 @@
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <% data.new_style_struct("Background", inherited=False) %>
 
 ${helpers.predefined_type("background-color", "CSSColor",
     "::cssparser::Color::RGBA(::cssparser::RGBA { red: 0., green: 0., blue: 0., alpha: 0. }) /* transparent */",
     animatable=True)}
 
-<%helpers:vector_longhand name="background-image" animatable="False">
+<%helpers:vector_longhand name="background-image" animatable="False"
+                          has_uncacheable_values="${product == 'gecko'}">
     use cssparser::ToCss;
     use std::fmt;
     use values::specified::Image;
     use values::LocalToCss;
     use values::NoViewportPercentage;
 
     pub mod computed_value {
         use values::computed;
--- a/servo/components/style/properties/longhand/svg.mako.rs
+++ b/servo/components/style/properties/longhand/svg.mako.rs
@@ -141,17 +141,18 @@
 </%helpers:longhand>
 
 ${helpers.single_keyword("mask-composite",
                          "add subtract intersect exclude",
                          vector=True,
                          products="gecko",
                          animatable=False)}
 
-<%helpers:vector_longhand name="mask-image" products="gecko" animatable="False">
+<%helpers:vector_longhand name="mask-image" products="gecko" animatable="False"
+                          has_uncacheable_values="${product == 'gecko'}">
     use cssparser::ToCss;
     use std::fmt;
     use url::Url;
     use values::specified::{Image, UrlExtraData};
     use values::LocalToCss;
     use values::NoViewportPercentage;
 
     pub mod computed_value {