servo: Merge #12465 - Add bindings for calc() (from Manishearth:stylo-calc); r=heycam
authorManish Goregaokar <manishsmail@gmail.com>
Tue, 19 Jul 2016 20:57:10 -0500
changeset 339325 02cdb0067389c06511d1cfd947aeab278089c28e
parent 339324 94ac355919ffc98cb52d6ae979dce8c1d739489e
child 339326 90c92334a916642e221b3ff3c4477f60bf226a90
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)
reviewersheycam
servo: Merge #12465 - Add bindings for calc() (from Manishearth:stylo-calc); r=heycam This adds bindings for dealing with refcounted calc() values. So far we can get/set them, but we don't yet have the ability to copy them around. I'll work on that next. Corresponding gecko bindings at https://github.com/servo/gecko-dev/compare/stylo...Manishearth:stylo-calc?expand=1 f? @emilio @heycam Source-Repo: https://github.com/servo/servo Source-Revision: 37604401d027b991d9daf0b1df24408da36d5230
servo/components/style/gecko_conversions.rs
servo/components/style/lib.rs
servo/ports/geckolib/gecko_bindings/bindings.rs
servo/ports/geckolib/gecko_bindings/structs_debug.rs
servo/ports/geckolib/gecko_bindings/structs_release.rs
servo/ports/geckolib/gecko_bindings/sugar/mod.rs
servo/ports/geckolib/gecko_bindings/sugar/ns_style_coord.rs
servo/ports/geckolib/gecko_bindings/tools/regen.py
servo/ports/geckolib/properties.mako.rs
servo/ports/geckolib/values.rs
new file mode 100644
--- /dev/null
+++ b/servo/components/style/gecko_conversions.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/. */
+
+//! This module contains conversion helpers between Servo and Gecko types
+//! Ideally, it would be in geckolib itself, but coherence
+//! forces us to keep the traits and implementations here
+
+use app_units::Au;
+use gecko_bindings::structs::nsStyleCoord_CalcValue;
+use values::computed::CalcLengthOrPercentage;
+
+impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
+    fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
+        let has_percentage = other.percentage.is_some();
+        nsStyleCoord_CalcValue {
+            mLength: other.length.map_or(0, |l| l.0),
+            mPercent: other.percentage.unwrap_or(0.0),
+            mHasPercent: has_percentage,
+        }
+    }
+}
+
+impl From<nsStyleCoord_CalcValue> for CalcLengthOrPercentage {
+    fn from(other: nsStyleCoord_CalcValue) -> CalcLengthOrPercentage {
+        let percentage = if other.mHasPercent {
+            Some(other.mPercent)
+        } else {
+            None
+        };
+        CalcLengthOrPercentage {
+            length: Some(Au(other.mLength)),
+            percentage: percentage,
+        }
+    }
+}
--- a/servo/components/style/lib.rs
+++ b/servo/components/style/lib.rs
@@ -76,16 +76,18 @@ pub mod bezier;
 pub mod cache;
 pub mod context;
 pub mod custom_properties;
 pub mod data;
 pub mod dom;
 pub mod element_state;
 pub mod error_reporting;
 pub mod font_face;
+#[cfg(feature = "gecko")]
+pub mod gecko_conversions;
 pub mod keyframes;
 pub mod logical_geometry;
 pub mod matching;
 pub mod media_queries;
 pub mod parallel;
 pub mod parser;
 pub mod refcell;
 pub mod restyle_hints;
--- a/servo/ports/geckolib/gecko_bindings/bindings.rs
+++ b/servo/ports/geckolib/gecko_bindings/bindings.rs
@@ -118,16 +118,26 @@ unsafe impl Send for nsStyleGradientStop
 unsafe impl Sync for nsStyleGradientStop {}
 impl HeapSizeOf for nsStyleGradientStop { fn heap_size_of_children(&self) -> usize { 0 } }
 use structs::nsStyleImageLayers;
 unsafe impl Send for nsStyleImageLayers {}
 unsafe impl Sync for nsStyleImageLayers {}
 impl HeapSizeOf for nsStyleImageLayers { fn heap_size_of_children(&self) -> usize { 0 } }
 use structs::nsStyleImageLayers_Layer as Layer;
 use structs::nsStyleImageLayers_LayerType as LayerType;
+use structs::nsStyleUnit;
+unsafe impl Send for nsStyleUnit {}
+unsafe impl Sync for nsStyleUnit {}
+impl HeapSizeOf for nsStyleUnit { fn heap_size_of_children(&self) -> usize { 0 } }
+use structs::nsStyleUnion;
+unsafe impl Send for nsStyleUnion {}
+unsafe impl Sync for nsStyleUnion {}
+impl HeapSizeOf for nsStyleUnion { fn heap_size_of_children(&self) -> usize { 0 } }
+use structs::nsStyleCoord_CalcValue as CalcValue;
+use structs::nsStyleCoord_Calc as Calc;
 use structs::SheetParsingMode;
 use structs::nsMainThreadPtrHandle;
 use structs::nsMainThreadPtrHolder;
 use structs::nscolor;
 use structs::nsFont;
 use structs::FontFamilyList;
 use structs::FontFamilyType;
 use structs::nsIAtom;
@@ -250,16 +260,23 @@ extern "C" {
     pub fn Gecko_SetNodeFlags(node: *mut RawGeckoNode, flags: u32);
     pub fn Gecko_UnsetNodeFlags(node: *mut RawGeckoNode, flags: u32);
     pub fn Gecko_EnsureTArrayCapacity(array: *mut ::std::os::raw::c_void,
                                       capacity: usize, elem_size: usize);
     pub fn Gecko_EnsureImageLayersLength(layers: *mut nsStyleImageLayers,
                                          len: usize);
     pub fn Gecko_InitializeImageLayer(layer: *mut Layer,
                                       layer_type: LayerType);
+    pub fn Gecko_ResetStyleCoord(unit: *mut nsStyleUnit,
+                                 value: *mut nsStyleUnion);
+    pub fn Gecko_SetStyleCoordCalcValue(unit: *mut nsStyleUnit,
+                                        value: *mut nsStyleUnion,
+                                        calc: CalcValue);
+    pub fn Gecko_AddRefCalcArbitraryThread(aPtr: *mut Calc);
+    pub fn Gecko_ReleaseCalcArbitraryThread(aPtr: *mut Calc);
     pub fn Servo_StylesheetFromUTF8Bytes(bytes: *const u8, length: u32,
                                          parsing_mode: SheetParsingMode,
                                          base: *mut ThreadSafeURIHolder,
                                          referrer: *mut ThreadSafeURIHolder,
                                          principal:
                                              *mut ThreadSafePrincipalHolder)
      -> *mut RawServoStyleSheet;
     pub fn Servo_AddRefStyleSheet(sheet: *mut RawServoStyleSheet);
--- a/servo/ports/geckolib/gecko_bindings/structs_debug.rs
+++ b/servo/ports/geckolib/gecko_bindings/structs_debug.rs
@@ -4880,22 +4880,21 @@ impl ::std::clone::Clone for nsStyleCoor
 fn bindgen_test_layout_nsStyleCoord_CalcValue() {
     assert_eq!(::std::mem::size_of::<nsStyleCoord_CalcValue>() , 12usize);
     assert_eq!(::std::mem::align_of::<nsStyleCoord_CalcValue>() , 4usize);
 }
 #[repr(C)]
 #[derive(Debug)]
 pub struct nsStyleCoord_Calc {
     pub _base: nsStyleCoord_CalcValue,
-    pub mRefCnt: nsAutoRefCnt,
-    pub _mOwningThread: nsAutoOwningThread,
+    pub mRefCnt: ThreadSafeAutoRefCnt,
 }
 #[test]
 fn bindgen_test_layout_nsStyleCoord_Calc() {
-    assert_eq!(::std::mem::size_of::<nsStyleCoord_Calc>() , 32usize);
+    assert_eq!(::std::mem::size_of::<nsStyleCoord_Calc>() , 24usize);
     assert_eq!(::std::mem::align_of::<nsStyleCoord_Calc>() , 8usize);
 }
 #[repr(u32)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub enum nsStyleCoord_CoordConstructorType { CoordConstructor = 0, }
 #[test]
 fn bindgen_test_layout_nsStyleCoord() {
     assert_eq!(::std::mem::size_of::<nsStyleCoord>() , 16usize);
--- a/servo/ports/geckolib/gecko_bindings/structs_release.rs
+++ b/servo/ports/geckolib/gecko_bindings/structs_release.rs
@@ -4859,22 +4859,21 @@ impl ::std::clone::Clone for nsStyleCoor
 fn bindgen_test_layout_nsStyleCoord_CalcValue() {
     assert_eq!(::std::mem::size_of::<nsStyleCoord_CalcValue>() , 12usize);
     assert_eq!(::std::mem::align_of::<nsStyleCoord_CalcValue>() , 4usize);
 }
 #[repr(C)]
 #[derive(Debug)]
 pub struct nsStyleCoord_Calc {
     pub _base: nsStyleCoord_CalcValue,
-    pub mRefCnt: nsAutoRefCnt,
-    pub _mOwningThread: nsAutoOwningThread,
+    pub mRefCnt: ThreadSafeAutoRefCnt,
 }
 #[test]
 fn bindgen_test_layout_nsStyleCoord_Calc() {
-    assert_eq!(::std::mem::size_of::<nsStyleCoord_Calc>() , 32usize);
+    assert_eq!(::std::mem::size_of::<nsStyleCoord_Calc>() , 24usize);
     assert_eq!(::std::mem::align_of::<nsStyleCoord_Calc>() , 8usize);
 }
 #[repr(u32)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub enum nsStyleCoord_CoordConstructorType { CoordConstructor = 0, }
 #[test]
 fn bindgen_test_layout_nsStyleCoord() {
     assert_eq!(::std::mem::size_of::<nsStyleCoord>() , 16usize);
--- a/servo/ports/geckolib/gecko_bindings/sugar/mod.rs
+++ b/servo/ports/geckolib/gecko_bindings/sugar/mod.rs
@@ -1,6 +1,7 @@
 /* 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/. */
 
 mod ns_style_auto_array;
+mod ns_style_coord;
 mod ns_t_array;
new file mode 100644
--- /dev/null
+++ b/servo/ports/geckolib/gecko_bindings/sugar/ns_style_coord.rs
@@ -0,0 +1,54 @@
+/* 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/. */
+
+use bindings::{Gecko_ResetStyleCoord, Gecko_SetStyleCoordCalcValue, Gecko_AddRefCalcArbitraryThread};
+use std::mem::transmute;
+use structs::{nsStyleCoord_CalcValue, nsStyleCoord_Calc, nsStyleUnit, nsStyleUnion, nsStyleCoord};
+
+// Functions here are unsafe because it is possible to use the wrong nsStyleUnit
+// FIXME we should be pairing up nsStyleUnion and nsStyleUnit somehow
+// nsStyleCoord is one way to do it, but there are other structs using pairs
+// of union and unit too
+
+impl nsStyleUnion {
+    /// Clean up any resources used by an nsStyleUnit
+    /// Currently, this only happens if the nsStyleUnit
+    /// is a Calc
+    pub unsafe fn reset(&mut self, unit: &mut nsStyleUnit) {
+        if *unit == nsStyleUnit::eStyleUnit_Calc {
+            Gecko_ResetStyleCoord(unit, self);
+        }
+    }
+
+    /// Set internal value to a calc() value
+    /// reset() the union before calling this
+    pub unsafe fn set_calc_value(&mut self, unit: &mut nsStyleUnit, v: nsStyleCoord_CalcValue) {
+        // Calc should have been cleaned up
+        debug_assert!(*unit != nsStyleUnit::eStyleUnit_Calc);
+        Gecko_SetStyleCoordCalcValue(unit, self, v);
+    }
+
+    pub unsafe fn get_calc(&self) -> nsStyleCoord_CalcValue {
+        (*self.as_calc())._base
+    }
+
+    pub unsafe fn addref_if_calc(&mut self, unit: &nsStyleUnit) {
+        if *unit == nsStyleUnit::eStyleUnit_Calc {
+            Gecko_AddRefCalcArbitraryThread(self.as_calc_mut());
+        }
+    }
+
+    unsafe fn as_calc_mut(&mut self) -> &mut nsStyleCoord_Calc {
+        transmute(*self.mPointer.as_mut() as *mut nsStyleCoord_Calc)
+    }
+    unsafe fn as_calc(&self) -> &nsStyleCoord_Calc {
+        transmute(*self.mPointer.as_ref() as *const nsStyleCoord_Calc)
+    }
+}
+
+impl nsStyleCoord {
+    pub unsafe fn addref_if_calc(&mut self) {
+        self.mValue.addref_if_calc(&self.mUnit);
+    }
+}
--- a/servo/ports/geckolib/gecko_bindings/tools/regen.py
+++ b/servo/ports/geckolib/gecko_bindings/tools/regen.py
@@ -116,16 +116,18 @@ COMPILATION_TARGETS = {
             "nsStyleSVG", "nsStyleVariables", "nsStyleBackground",
             "nsStylePosition", "nsStyleTextReset", "nsStyleDisplay",
             "nsStyleContent", "nsStyleUIReset", "nsStyleTable",
             "nsStyleMargin", "nsStylePadding", "nsStyleBorder",
             "nsStyleOutline", "nsStyleXUL", "nsStyleSVGReset", "nsStyleColumn",
             "nsStyleEffects", "nsStyleImage", "nsStyleGradient",
             "nsStyleCoord", "nsStyleGradientStop", "nsStyleImageLayers",
             "nsStyleImageLayers::Layer", "nsStyleImageLayers::LayerType",
+            "nsStyleUnit", "nsStyleUnion", "nsStyleCoord::CalcValue",
+            "nsStyleCoord::Calc",
 
             "SheetParsingMode", "nsMainThreadPtrHandle",
             "nsMainThreadPtrHolder", "nscolor", "nsFont", "FontFamilyList",
             "FontFamilyType", "nsIAtom",
         ],
         "void_types": [
             "nsINode", "nsIDocument", "nsIPrincipal", "nsIURI",
         ]
--- a/servo/ports/geckolib/properties.mako.rs
+++ b/servo/ports/geckolib/properties.mako.rs
@@ -30,17 +30,17 @@ use std::mem::{transmute, uninitialized,
 use std::sync::Arc;
 use std::cmp;
 use style::custom_properties::ComputedValuesMap;
 use style::logical_geometry::WritingMode;
 use style::properties::{CascadePropertyFn, ServoComputedValues, ComputedValues};
 use style::properties::longhands;
 use style::properties::style_struct_traits::*;
 use values::{StyleCoordHelpers, GeckoStyleCoordConvertible, convert_nscolor_to_rgba};
-use values::{convert_rgba_to_nscolor, debug_assert_unit_is_safe_to_copy};
+use values::convert_rgba_to_nscolor;
 use values::round_border_to_device_pixels;
 
 #[derive(Clone, Debug)]
 pub struct GeckoComputedValues {
     % for style_struct in data.style_structs:
     ${style_struct.ident}: Arc<${style_struct.gecko_struct_name}>,
     % endfor
 
@@ -312,19 +312,20 @@ def set_gecko_property(ffi_name, expr):
 </%def>
 
 <%def name="impl_split_style_coord(ident, unit_ffi_name, union_ffi_name, need_clone=False)">
     fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
         v.to_gecko_style_coord(&mut self.gecko.${unit_ffi_name},
                                &mut self.gecko.${union_ffi_name});
     }
     fn copy_${ident}_from(&mut self, other: &Self) {
-        debug_assert_unit_is_safe_to_copy(self.gecko.${unit_ffi_name});
+        unsafe { self.gecko.${union_ffi_name}.reset(&mut self.gecko.${unit_ffi_name}) };
         self.gecko.${unit_ffi_name} =  other.gecko.${unit_ffi_name};
         self.gecko.${union_ffi_name} = other.gecko.${union_ffi_name};
+        unsafe { self.gecko.${union_ffi_name}.addref_if_calc(&self.gecko.${unit_ffi_name}) };
     }
     % if need_clone:
         fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
             use style::properties::longhands::${ident}::computed_value::T;
             T::from_gecko_style_coord(&self.gecko.${unit_ffi_name},
                                       &self.gecko.${union_ffi_name})
                 .expect("clone for ${ident} failed")
         }
@@ -342,22 +343,24 @@ def set_gecko_property(ffi_name, expr):
                                     y_unit_ffi_name, y_union_ffi_name, need_clone=False)">
     fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
         v.0.width.to_gecko_style_coord(&mut self.gecko.${x_unit_ffi_name},
                                        &mut self.gecko.${x_union_ffi_name});
         v.0.height.to_gecko_style_coord(&mut self.gecko.${y_unit_ffi_name},
                                         &mut self.gecko.${y_union_ffi_name});
     }
     fn copy_${ident}_from(&mut self, other: &Self) {
-        debug_assert_unit_is_safe_to_copy(self.gecko.${x_unit_ffi_name});
-        debug_assert_unit_is_safe_to_copy(self.gecko.${y_unit_ffi_name});
+        unsafe { self.gecko.${x_union_ffi_name}.reset(&mut self.gecko.${x_unit_ffi_name}) };
+        unsafe { self.gecko.${y_union_ffi_name}.reset(&mut self.gecko.${y_unit_ffi_name}) };
         self.gecko.${x_unit_ffi_name} = other.gecko.${x_unit_ffi_name};
         self.gecko.${x_union_ffi_name} = other.gecko.${x_union_ffi_name};
         self.gecko.${y_unit_ffi_name} = other.gecko.${y_unit_ffi_name};
         self.gecko.${y_union_ffi_name} = other.gecko.${y_union_ffi_name};
+        unsafe { self.gecko.${x_union_ffi_name}.addref_if_calc(&self.gecko.${x_unit_ffi_name}) };
+        unsafe { self.gecko.${y_union_ffi_name}.addref_if_calc(&self.gecko.${y_unit_ffi_name}) };
     }
     % if need_clone:
         fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
             use style::properties::longhands::${ident}::computed_value::T;
             use euclid::Size2D;
             let width = GeckoStyleCoordConvertible::from_gecko_style_coord(&self.gecko.${x_unit_ffi_name},
                                                                            &self.gecko.${x_union_ffi_name})
                             .expect("Failed to clone ${ident}");
@@ -622,17 +625,20 @@ fn static_assert() {
         use style::properties::longhands::z_index::computed_value::T;
         match v {
             T::Auto => self.gecko.mZIndex.set_auto(),
             T::Number(n) => self.gecko.mZIndex.set_int(n),
         }
     }
 
     fn copy_z_index_from(&mut self, other: &Self) {
-        debug_assert_unit_is_safe_to_copy(self.gecko.mZIndex.mUnit);
+        use gecko_bindings::structs::nsStyleUnit;
+        // z-index is never a calc(). If it were, we'd be leaking here, so
+        // assert that it isn't.
+        debug_assert!(self.gecko.mZIndex.mUnit != nsStyleUnit::eStyleUnit_Calc);
         self.gecko.mZIndex.mUnit = other.gecko.mZIndex.mUnit;
         self.gecko.mZIndex.mValue = other.gecko.mZIndex.mValue;
     }
 
     fn clone_z_index(&self) -> longhands::z_index::computed_value::T {
         use style::properties::longhands::z_index::computed_value::T;
 
         if self.gecko.mZIndex.is_auto() {
--- a/servo/ports/geckolib/values.rs
+++ b/servo/ports/geckolib/values.rs
@@ -38,109 +38,116 @@ pub trait StyleCoordHelpers {
     fn set_factor(&mut self, val: f32);
     fn is_factor(&self) -> bool;
     fn get_factor(&self) -> f32;
 }
 
 impl StyleCoordHelpers for nsStyleCoord {
     #[inline]
     fn copy_from(&mut self, other: &Self) {
-        debug_assert_unit_is_safe_to_copy(self.mUnit);
-        debug_assert_unit_is_safe_to_copy(other.mUnit);
+        unsafe { self.mValue.reset(&mut self.mUnit) };
         self.mUnit = other.mUnit;
         self.mValue = other.mValue;
+        unsafe { self.addref_if_calc(); }
     }
 
     #[inline]
     fn set<T: GeckoStyleCoordConvertible>(&mut self, val: T) {
         val.to_gecko_style_coord(&mut self.mUnit, &mut self.mValue);
     }
 
     #[inline]
     fn set_auto(&mut self) {
+        unsafe { self.mValue.reset(&mut self.mUnit) };
         self.mUnit = nsStyleUnit::eStyleUnit_Auto;
         unsafe { *self.mValue.mInt.as_mut() = 0; }
     }
     #[inline]
     fn is_auto(&self) -> bool {
         self.mUnit == nsStyleUnit::eStyleUnit_Auto
     }
 
     #[inline]
     fn set_normal(&mut self) {
+        unsafe { self.mValue.reset(&mut self.mUnit) };
         self.mUnit = nsStyleUnit::eStyleUnit_Normal;
         unsafe { *self.mValue.mInt.as_mut() = 0; }
     }
     #[inline]
     fn is_normal(&self) -> bool {
         self.mUnit == nsStyleUnit::eStyleUnit_Normal
     }
 
     #[inline]
     fn set_coord(&mut self, val: Au) {
+        unsafe { self.mValue.reset(&mut self.mUnit) };
         self.mUnit = nsStyleUnit::eStyleUnit_Coord;
         unsafe { *self.mValue.mInt.as_mut() = val.0; }
     }
     #[inline]
     fn is_coord(&self) -> bool {
         self.mUnit == nsStyleUnit::eStyleUnit_Coord
     }
     #[inline]
     fn get_coord(&self) -> Au {
         debug_assert!(self.is_coord());
         Au(unsafe { *self.mValue.mInt.as_ref() })
     }
 
     #[inline]
     fn set_int(&mut self, val: i32) {
+        unsafe { self.mValue.reset(&mut self.mUnit) };
         self.mUnit = nsStyleUnit::eStyleUnit_Integer;
         unsafe { *self.mValue.mInt.as_mut() = val; }
     }
     #[inline]
     fn is_int(&self) -> bool {
         self.mUnit == nsStyleUnit::eStyleUnit_Integer
     }
     #[inline]
     fn get_int(&self) -> i32 {
         debug_assert!(self.is_int());
         unsafe { *self.mValue.mInt.as_ref() }
     }
 
     #[inline]
     fn set_enum(&mut self, val: i32) {
+        unsafe { self.mValue.reset(&mut self.mUnit) };
         self.mUnit = nsStyleUnit::eStyleUnit_Enumerated;
         unsafe { *self.mValue.mInt.as_mut() = val; }
     }
     #[inline]
     fn is_enum(&self) -> bool {
         self.mUnit == nsStyleUnit::eStyleUnit_Enumerated
     }
     #[inline]
     fn get_enum(&self) -> i32 {
         debug_assert!(self.is_enum());
         unsafe { *self.mValue.mInt.as_ref() }
     }
 
     #[inline]
     fn set_percent(&mut self, val: f32) {
+        unsafe { self.mValue.reset(&mut self.mUnit) };
         self.mUnit = nsStyleUnit::eStyleUnit_Percent;
         unsafe { *self.mValue.mFloat.as_mut() = val; }
     }
     #[inline]
     fn is_percent(&self) -> bool {
         self.mUnit == nsStyleUnit::eStyleUnit_Percent
     }
     #[inline]
     fn get_percent(&self) -> f32 {
         debug_assert!(self.is_percent());
         unsafe { *self.mValue.mFloat.as_ref() }
     }
 
     #[inline]
     fn set_factor(&mut self, val: f32) {
+        unsafe { self.mValue.reset(&mut self.mUnit) };
         self.mUnit = nsStyleUnit::eStyleUnit_Factor;
         unsafe { *self.mValue.mFloat.as_mut() = val; }
     }
     #[inline]
     fn is_factor(&self) -> bool {
         self.mUnit == nsStyleUnit::eStyleUnit_Factor
     }
     #[inline]
@@ -152,112 +159,116 @@ impl StyleCoordHelpers for nsStyleCoord 
 
 pub trait GeckoStyleCoordConvertible : Sized {
     fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion);
     fn from_gecko_style_coord(unit: &nsStyleUnit, union: &nsStyleUnion) -> Option<Self>;
 }
 
 impl GeckoStyleCoordConvertible for LengthOrPercentage {
     fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion) {
+        unsafe { union.reset(unit) };
         match *self {
             LengthOrPercentage::Length(au) => {
                 *unit = nsStyleUnit::eStyleUnit_Coord;
                 unsafe { *union.mInt.as_mut() = au.0; }
             },
             LengthOrPercentage::Percentage(p) => {
                 *unit = nsStyleUnit::eStyleUnit_Percent;
                 unsafe { *union.mFloat.as_mut() = p; }
             },
-            LengthOrPercentage::Calc(_) => unimplemented!(),
+            LengthOrPercentage::Calc(calc) => unsafe { union.set_calc_value(unit, calc.into()) },
         };
     }
 
     fn from_gecko_style_coord(unit: &nsStyleUnit, union: &nsStyleUnion) -> Option<Self> {
         match *unit {
             nsStyleUnit::eStyleUnit_Coord
                 => Some(LengthOrPercentage::Length(Au(unsafe { *union.mInt.as_ref() }))),
             nsStyleUnit::eStyleUnit_Percent
                 => Some(LengthOrPercentage::Percentage(unsafe { *union.mFloat.as_ref() })),
             nsStyleUnit::eStyleUnit_Calc
-                => unimplemented!(),
+                => Some(LengthOrPercentage::Calc(unsafe { union.get_calc().into() })),
             _ => None,
         }
     }
 }
 
 impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto {
     fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion) {
+        unsafe { union.reset(unit) };
         match *self {
             LengthOrPercentageOrAuto::Length(au) => {
                 *unit = nsStyleUnit::eStyleUnit_Coord;
                 unsafe { *union.mInt.as_mut() = au.0; }
             },
             LengthOrPercentageOrAuto::Percentage(p) => {
                 *unit = nsStyleUnit::eStyleUnit_Percent;
                 unsafe { *union.mFloat.as_mut() = p; }
             },
             LengthOrPercentageOrAuto::Auto => {
                 *unit = nsStyleUnit::eStyleUnit_Auto;
                 unsafe { *union.mInt.as_mut() = 0; }
             },
-            LengthOrPercentageOrAuto::Calc(_) => unimplemented!(),
+            LengthOrPercentageOrAuto::Calc(calc) => unsafe { union.set_calc_value(unit, calc.into()) },
         };
     }
 
     fn from_gecko_style_coord(unit: &nsStyleUnit, union: &nsStyleUnion) -> Option<Self> {
         match *unit {
             nsStyleUnit::eStyleUnit_Auto
                 => Some(LengthOrPercentageOrAuto::Auto),
             nsStyleUnit::eStyleUnit_Coord
                 => Some(LengthOrPercentageOrAuto::Length(Au(unsafe { *union.mInt.as_ref() }))),
             nsStyleUnit::eStyleUnit_Percent
                 => Some(LengthOrPercentageOrAuto::Percentage(unsafe { *union.mFloat.as_ref() })),
             nsStyleUnit::eStyleUnit_Calc
-                => unimplemented!(),
+                => Some(LengthOrPercentageOrAuto::Calc(unsafe { union.get_calc().into() })),
             _ => None,
         }
     }
 }
 
 impl GeckoStyleCoordConvertible for LengthOrPercentageOrNone {
     fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion) {
+        unsafe { union.reset(unit) };
         match *self {
             LengthOrPercentageOrNone::Length(au) => {
                 *unit = nsStyleUnit::eStyleUnit_Coord;
                 unsafe { *union.mInt.as_mut() = au.0; }
             },
             LengthOrPercentageOrNone::Percentage(p) => {
                 *unit = nsStyleUnit::eStyleUnit_Percent;
                 unsafe { *union.mFloat.as_mut() = p; }
             },
             LengthOrPercentageOrNone::None => {
                 *unit = nsStyleUnit::eStyleUnit_None;
                 unsafe { *union.mInt.as_mut() = 0; }
             },
-            LengthOrPercentageOrNone::Calc(_) => unimplemented!(),
+            LengthOrPercentageOrNone::Calc(calc) => unsafe { union.set_calc_value(unit, calc.into()) },
         };
     }
 
     fn from_gecko_style_coord(unit: &nsStyleUnit, union: &nsStyleUnion) -> Option<Self> {
         match *unit {
             nsStyleUnit::eStyleUnit_None
                 => Some(LengthOrPercentageOrNone::None),
             nsStyleUnit::eStyleUnit_Coord
                 => Some(LengthOrPercentageOrNone::Length(Au(unsafe { *union.mInt.as_ref() }))),
             nsStyleUnit::eStyleUnit_Percent
                 => Some(LengthOrPercentageOrNone::Percentage(unsafe { *union.mFloat.as_ref() })),
             nsStyleUnit::eStyleUnit_Calc
-                => unimplemented!(),
+                => Some(LengthOrPercentageOrNone::Calc(unsafe { union.get_calc().into() })),
             _ => None,
         }
     }
 }
 
 impl<T: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for Option<T> {
     fn to_gecko_style_coord(&self, unit: &mut nsStyleUnit, union: &mut nsStyleUnion) {
+        unsafe { union.reset(unit) };
         if let Some(ref me) = *self {
             me.to_gecko_style_coord(unit, union);
         } else {
             *unit = nsStyleUnit::eStyleUnit_None;
             unsafe { *union.mInt.as_mut() = 0; }
         }
     }
 
@@ -265,16 +276,17 @@ impl<T: GeckoStyleCoordConvertible> Geck
         Some(T::from_gecko_style_coord(unit, union))
     }
 }
 
 impl GeckoStyleCoordConvertible for Angle {
     fn to_gecko_style_coord(&self,
                             unit: &mut nsStyleUnit,
                             union: &mut nsStyleUnion) {
+        unsafe { union.reset(unit) };
         *unit = nsStyleUnit::eStyleUnit_Radian;
         unsafe { *union.mFloat.as_mut() = self.radians() };
     }
 
     fn from_gecko_style_coord(unit: &nsStyleUnit, union: &nsStyleUnion) -> Option<Self> {
         if *unit == nsStyleUnit::eStyleUnit_Radian {
             Some(Angle::from_radians(unsafe { *union.mFloat.as_ref() }))
         } else {
@@ -305,12 +317,8 @@ pub fn round_border_to_device_pixels(wid
     // would round down to zero is clamped to 1 device pixel.  Used for storing
     // computed values of border-*-width and outline-width.
     if width == Au(0) {
         Au(0)
     } else {
         max(au_per_device_px, Au(width.0 / au_per_device_px.0 * au_per_device_px.0))
     }
 }
-
-pub fn debug_assert_unit_is_safe_to_copy(unit: nsStyleUnit) {
-    debug_assert!(unit != nsStyleUnit::eStyleUnit_Calc, "stylo: Can't yet handle refcounted Calc");
-}