servo: Merge #13157 - stylo: support background-size and corner gradients (from Manishearth:background-size); r=emilio
authorManish Goregaokar <manishsmail@gmail.com>
Sun, 04 Sep 2016 03:45:05 -0500
changeset 339644 52a5c15677dae5b1abeb54b027b3f26d195cc180
parent 339643 8cf60a0a83a6e3b85651909b7136bde9cf48c00b
child 339645 d181fb336ca9c7e3c20dd0e4db1475946cfddfc6
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
servo: Merge #13157 - stylo: support background-size and corner gradients (from Manishearth:background-size); r=emilio Forgot to fix this in the midst of all other things fixed in #12945 <s>(not yet tested, need to figure out how to test bg-size with gradients)</s> r? @bholley Source-Repo: https://github.com/servo/servo Source-Revision: c46003eb05cca0ea779fee73d0f6325c85e19357
servo/components/style/gecko_conversions.rs
servo/components/style/properties/gecko.mako.rs
servo/ports/geckolib/gecko_bindings/sugar/ns_style_coord.rs
--- a/servo/components/style/gecko_conversions.rs
+++ b/servo/components/style/gecko_conversions.rs
@@ -9,17 +9,17 @@
 #![allow(unsafe_code)]
 
 use app_units::Au;
 use gecko_bindings::bindings::{RawServoStyleSheet, ServoComputedValues};
 use gecko_bindings::structs::nsStyleCoord_CalcValue;
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI};
 use properties::ComputedValues;
 use stylesheets::Stylesheet;
-use values::computed::{CalcLengthOrPercentage, LengthOrPercentage};
+use values::computed::{CalcLengthOrPercentage, LengthOrPercentage, LengthOrPercentageOrAuto};
 
 unsafe impl HasFFI for Stylesheet {
     type FFIType = RawServoStyleSheet;
 }
 unsafe impl HasArcFFI for Stylesheet {}
 unsafe impl HasFFI for ComputedValues {
     type FFIType = ServoComputedValues;
 }
@@ -67,16 +67,39 @@ impl From<LengthOrPercentage> for nsStyl
                     mHasPercent: true,
                 }
             },
             LengthOrPercentage::Calc(calc) => calc.into(),
         }
     }
 }
 
+impl LengthOrPercentageOrAuto {
+    pub fn to_calc_value(&self) -> Option<nsStyleCoord_CalcValue> {
+        match *self {
+            LengthOrPercentageOrAuto::Length(au) => {
+                Some(nsStyleCoord_CalcValue {
+                    mLength: au.0,
+                    mPercent: 0.0,
+                    mHasPercent: false,
+                })
+            },
+            LengthOrPercentageOrAuto::Percentage(pc) => {
+                Some(nsStyleCoord_CalcValue {
+                    mLength: 0,
+                    mPercent: pc,
+                    mHasPercent: true,
+                })
+            },
+            LengthOrPercentageOrAuto::Calc(calc) => Some(calc.into()),
+            LengthOrPercentageOrAuto::Auto => None,
+        }
+    }
+}
+
 impl From<nsStyleCoord_CalcValue> for LengthOrPercentage {
     fn from(other: nsStyleCoord_CalcValue) -> LengthOrPercentage {
         match (other.mHasPercent, other.mLength) {
             (false, _) => LengthOrPercentage::Length(Au(other.mLength)),
             (true, 0) => LengthOrPercentage::Percentage(other.mPercent),
             _ => LengthOrPercentage::Calc(other.into()),
         }
     }
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -994,17 +994,17 @@ fn static_assert() {
     }
 </%def>
 // TODO: Gecko accepts lists in most background-related properties. We just use
 // the first element (which is the common case), but at some point we want to
 // add support for parsing these lists in servo and pushing to nsTArray's.
 <% skip_background_longhands = """background-color background-repeat
                                   background-image background-clip
                                   background-origin background-attachment
-                                  background-position""" %>
+                                  background-size background-position""" %>
 <%self:impl_trait style_struct_name="Background"
                   skip_longhands="${skip_background_longhands}"
                   skip_additionals="*">
 
     <% impl_color("background_color", "mBackgroundColor", need_clone=True) %>
 
     <%self:simple_background_array_property name="repeat" field_name="mRepeat">
         use properties::longhands::background_repeat::single_value::computed_value::T;
@@ -1053,16 +1053,88 @@ fn static_assert() {
 
         match servo {
             T::scroll => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL as u8,
             T::fixed => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED as u8,
             T::local => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL as u8,
         }
     </%self:simple_background_array_property>
 
+    <%self:simple_background_array_property name="size" field_name="mSize">
+        use gecko_bindings::structs::nsStyleImageLayers_Size_Dimension;
+        use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType;
+        use gecko_bindings::structs::{nsStyleCoord_CalcValue, nsStyleImageLayers_Size};
+        use properties::longhands::background_size::single_value::computed_value::T;
+        use values::computed::LengthOrPercentageOrAuto;
+
+        let mut width = nsStyleCoord_CalcValue::new();
+        let mut height = nsStyleCoord_CalcValue::new();
+
+        let (w_type, h_type) = match servo {
+            T::Explicit(size) => {
+                let mut w_type = nsStyleImageLayers_Size_DimensionType::eAuto;
+                let mut h_type = nsStyleImageLayers_Size_DimensionType::eAuto;
+                if let Some(w) = size.width.to_calc_value() {
+                    width = w;
+                    w_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage;
+                }
+                if let Some(h) = size.height.to_calc_value() {
+                    height = h;
+                    h_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage;
+                }
+                (w_type, h_type)
+            }
+            T::Cover => (nsStyleImageLayers_Size_DimensionType::eCover,
+                         nsStyleImageLayers_Size_DimensionType::eCover),
+            T::Contain => (nsStyleImageLayers_Size_DimensionType::eContain,
+                         nsStyleImageLayers_Size_DimensionType::eContain),
+        };
+
+        nsStyleImageLayers_Size {
+            mWidth: nsStyleImageLayers_Size_Dimension { _base: width },
+            mHeight: nsStyleImageLayers_Size_Dimension { _base: height },
+            mWidthType: w_type as u8,
+            mHeightType: h_type as u8,
+        }
+    </%self:simple_background_array_property>
+
+    pub fn clone_background_size(&self) -> longhands::background_size::computed_value::T {
+        use gecko_bindings::structs::nsStyleCoord_CalcValue as CalcValue;
+        use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType as DimensionType;
+        use properties::longhands::background_size::single_value::computed_value::{ExplicitSize, T};
+        use values::computed::LengthOrPercentageOrAuto;
+
+        fn to_servo(value: CalcValue, ty: u8) -> LengthOrPercentageOrAuto {
+            if ty == DimensionType::eAuto as u8 {
+                LengthOrPercentageOrAuto::Auto
+            } else {
+                debug_assert!(ty == DimensionType::eLengthPercentage as u8);
+                LengthOrPercentageOrAuto::Calc(value.into())
+            }
+        }
+
+        longhands::background_size::computed_value::T(
+            self.gecko.mImage.mLayers.iter().map(|ref layer| {
+                if DimensionType::eCover as u8 == layer.mSize.mWidthType {
+                    debug_assert!(layer.mSize.mHeightType == DimensionType::eCover as u8);
+                    return T::Cover
+                }
+                if DimensionType::eContain as u8 == layer.mSize.mWidthType {
+                    debug_assert!(layer.mSize.mHeightType == DimensionType::eContain as u8);
+                    return T::Contain
+                }
+
+                T::Explicit(ExplicitSize {
+                    width: to_servo(layer.mSize.mWidth._base, layer.mSize.mWidthType),
+                    height: to_servo(layer.mSize.mHeight._base, layer.mSize.mHeightType),
+                })
+            }).collect()
+        )
+    }
+
     pub fn copy_background_position_from(&mut self, other: &Self) {
         self.gecko.mImage.mPositionXCount = cmp::min(1, other.gecko.mImage.mPositionXCount);
         self.gecko.mImage.mPositionYCount = cmp::min(1, other.gecko.mImage.mPositionYCount);
         self.gecko.mImage.mLayers.mFirstElement.mPosition =
             other.gecko.mImage.mLayers.mFirstElement.mPosition;
         unsafe {
             Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, other.gecko.mImage.mLayers.len());
         }
@@ -1115,16 +1187,17 @@ fn static_assert() {
     }
 
     pub fn set_background_image(&mut self, images: longhands::background_image::computed_value::T) {
         use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER};
         use gecko_bindings::structs::nsStyleCoord;
         use values::computed::Image;
         use values::specified::AngleOrCorner;
+        use values::specified::{HorizontalDirection, VerticalDirection};
         use cssparser::Color as CSSColor;
 
         unsafe {
             // Prevent leaking of the last element we did set
             for image in &mut self.gecko.mImage.mLayers {
                 Gecko_SetNullImageValue(&mut image.mImage)
             }
             Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, images.0.len());
@@ -1151,20 +1224,41 @@ fn static_assert() {
                         let gecko_gradient = unsafe {
                             Gecko_CreateGradient(NS_STYLE_GRADIENT_SHAPE_LINEAR as u8,
                                                  NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8,
                                                  /* repeating = */ false,
                                                  /* legacy_syntax = */ false,
                                                  stop_count as u32)
                         };
 
-                        // TODO: figure out what gecko does in the `corner` case.
-                        if let AngleOrCorner::Angle(angle) = gradient.angle_or_corner {
-                            unsafe {
-                                (*gecko_gradient).mAngle.set(angle);
+                        match gradient.angle_or_corner {
+                            AngleOrCorner::Angle(angle) => {
+                                unsafe {
+                                    (*gecko_gradient).mAngle.set(angle);
+                                    (*gecko_gradient).mBgPosX.set_value(CoordDataValue::None);
+                                    (*gecko_gradient).mBgPosY.set_value(CoordDataValue::None);
+                                }
+                            }
+                            AngleOrCorner::Corner(horiz, vert) => {
+                                let percent_x = match horiz {
+                                    HorizontalDirection::Left => 0.0,
+                                    HorizontalDirection::Right => 1.0,
+                                };
+                                let percent_y = match vert {
+                                    VerticalDirection::Top => 0.0,
+                                    VerticalDirection::Bottom => 1.0,
+                                };
+
+                                unsafe {
+                                    (*gecko_gradient).mAngle.set_value(CoordDataValue::None);
+                                    (*gecko_gradient).mBgPosX
+                                                     .set_value(CoordDataValue::Percent(percent_x));
+                                    (*gecko_gradient).mBgPosY
+                                                     .set_value(CoordDataValue::Percent(percent_y));
+                                }
                             }
                         }
 
                         let mut coord: nsStyleCoord = nsStyleCoord::null();
                         for (index, stop) in gradient.stops.iter().enumerate() {
                             // NB: stops are guaranteed to be none in the gecko side by
                             // default.
                             coord.set(stop.position);
--- a/servo/ports/geckolib/gecko_bindings/sugar/ns_style_coord.rs
+++ b/servo/ports/geckolib/gecko_bindings/sugar/ns_style_coord.rs
@@ -35,16 +35,26 @@ impl CoordData for nsStyleCoord {
 impl CoordDataMut for nsStyleCoord {
     unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) {
         let unit = self.get_mUnit_mut() as *mut _;
         let value = self.get_mValue_mut() as *mut _;
         (&mut *unit, &mut *value)
     }
 }
 
+impl nsStyleCoord_CalcValue {
+    pub fn new() -> Self {
+        nsStyleCoord_CalcValue {
+            mLength: 0,
+            mPercent: 0.0,
+            mHasPercent: false,
+        }
+    }
+}
+
 impl nsStyleSides {
     #[inline]
     pub fn data_at(&self, index: usize) -> SidesData {
         SidesData {
             sides: self,
             index: index,
         }
     }