style: Standardize different methods to inherit and reset properties. draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 27 Jul 2017 15:42:05 +0200
changeset 617520 0f2da78d5026d90a2524438c2c8c6c1023d4ef73
parent 617519 df2d0d347666af69d3894b74d6d3058c63314dd5
child 617521 383b3be90e08d3933e2bef44df8baf77b2de5d94
push id71069
push userbmo:emilio+bugs@crisal.io
push dateFri, 28 Jul 2017 15:20:24 +0000
milestone56.0a1
style: Standardize different methods to inherit and reset properties. This avoids special-casing justify-items. MozReview-Commit-ID: FoEs2IHC1t6
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/helpers.mako.rs
servo/components/style/properties/properties.mako.rs
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -381,23 +381,33 @@ impl ${style_struct.gecko_struct_name} {
 <%def name="impl_simple_copy(ident, gecko_ffi_name, on_set=None, *kwargs)">
     #[allow(non_snake_case)]
     pub fn copy_${ident}_from(&mut self, other: &Self) {
         self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name};
         % if on_set:
         self.${on_set}();
         % endif
     }
+
+    #[allow(non_snake_case)]
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
 </%def>
 
 <%def name="impl_coord_copy(ident, gecko_ffi_name)">
     #[allow(non_snake_case)]
     pub fn copy_${ident}_from(&mut self, other: &Self) {
         self.gecko.${gecko_ffi_name}.copy_from(&other.gecko.${gecko_ffi_name});
     }
+
+    #[allow(non_snake_case)]
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
 </%def>
 
 <%!
 def get_gecko_property(ffi_name, self_param = "self"):
     if "mBorderColor" in ffi_name:
         return ffi_name.replace("mBorderColor",
                                 "unsafe { *%s.gecko.__bindgen_anon_1.mBorderColor.as_ref() }"
                                 % self_param)
@@ -465,16 +475,21 @@ def set_gecko_property(ffi_name, expr):
 </%def>
 
 <%def name="impl_color_copy(ident, gecko_ffi_name)">
     #[allow(non_snake_case)]
     pub fn copy_${ident}_from(&mut self, other: &Self) {
         let color = ${get_gecko_property(gecko_ffi_name, self_param = "other")};
         ${set_gecko_property(gecko_ffi_name, "color")};
     }
+
+    #[allow(non_snake_case)]
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
 </%def>
 
 <%def name="impl_color_clone(ident, gecko_ffi_name)">
     #[allow(non_snake_case)]
     pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
         ${get_gecko_property(gecko_ffi_name)}.into()
     }
 </%def>
@@ -594,16 +609,21 @@ def set_gecko_property(ffi_name, expr):
             bindings::Gecko_nsStyleSVGPaint_CopyFrom(
                 &mut ${get_gecko_property(gecko_ffi_name)},
                 & ${get_gecko_property(gecko_ffi_name, "other")}
             );
         }
     }
 
     #[allow(non_snake_case)]
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
+
+    #[allow(non_snake_case)]
     pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
         use values::generics::{SVGPaint, SVGPaintKind};
         use values::specified::url::SpecifiedUrl;
         use self::structs::nsStyleSVGPaintType;
         use self::structs::nsStyleSVGFallbackType;
         let ref paint = ${get_gecko_property(gecko_ffi_name)};
         let fallback = if let nsStyleSVGFallbackType::eStyleSVGFallbackType_Color = paint.mFallbackType {
             Some(convert_nscolor_to_rgba(paint.mFallbackColor))
@@ -656,22 +676,30 @@ def set_gecko_property(ffi_name, expr):
     pub fn copy_${ident}_from(&mut self, other: &Self) {
         % if inherit_from:
         self.gecko.${inherit_from} = other.gecko.${inherit_from};
         // NOTE: This is needed to easily handle the `unset` and `initial`
         // keywords, which are implemented calling this function.
         //
         // In practice, this means that we may have an incorrect value here, but
         // we'll adjust that properly in the style fixup phase.
+        //
+        // FIXME(emilio): We could clean this up a bit special-casing the reset_
+        // function below.
         self.gecko.${gecko_ffi_name} = other.gecko.${inherit_from};
         % else:
         self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name};
         % endif
     }
 
+    #[allow(non_snake_case)]
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
+
 %if need_clone:
     #[allow(non_snake_case)]
     pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
         Au(self.gecko.${gecko_ffi_name})
     }
 % endif
 </%def>
 
@@ -679,16 +707,20 @@ def set_gecko_property(ffi_name, expr):
     #[allow(non_snake_case)]
     pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
         v.to_gecko_style_coord(&mut self.gecko.${gecko_ffi_name}.data_at_mut(${index}));
     }
     #[allow(non_snake_case)]
     pub fn copy_${ident}_from(&mut self, other: &Self) {
         self.gecko.${gecko_ffi_name}.data_at_mut(${index}).copy_from(&other.gecko.${gecko_ffi_name}.data_at(${index}));
     }
+    #[allow(non_snake_case)]
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
     % if need_clone:
         #[allow(non_snake_case)]
         pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
             use properties::longhands::${ident}::computed_value::T;
             T::from_gecko_style_coord(&self.gecko.${gecko_ffi_name}.data_at(${index}))
                 .expect("clone for ${ident} failed")
         }
     % endif
@@ -698,16 +730,20 @@ def set_gecko_property(ffi_name, expr):
     #[allow(non_snake_case)]
     pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
         v.to_gecko_style_coord(&mut self.gecko.${gecko_ffi_name});
     }
     #[allow(non_snake_case)]
     pub fn copy_${ident}_from(&mut self, other: &Self) {
         self.gecko.${gecko_ffi_name}.copy_from(&other.gecko.${gecko_ffi_name});
     }
+    #[allow(non_snake_case)]
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
     % if need_clone:
         #[allow(non_snake_case)]
         pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
             use properties::longhands::${ident}::computed_value::T;
             T::from_gecko_style_coord(&self.gecko.${gecko_ffi_name})
                 .expect("clone for ${ident} failed")
         }
     % endif
@@ -735,31 +771,40 @@ def set_gecko_property(ffi_name, expr):
     #[allow(non_snake_case)]
     pub fn copy_${ident}_from(&mut self, other: &Self) {
         % for side in SIDES:
             self.gecko.${gecko_ffi_name}.data_at_mut(${side.index})
                 .copy_from(&other.gecko.${gecko_ffi_name}.data_at(${side.index}));
         % endfor
         ${ caller.body() }
     }
+
+    #[allow(non_snake_case)]
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
 </%def>
 
 <%def name="impl_corner_style_coord(ident, gecko_ffi_name, x_index, y_index, need_clone)">
     #[allow(non_snake_case)]
     pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
         v.0.width.to_gecko_style_coord(&mut self.gecko.${gecko_ffi_name}.data_at_mut(${x_index}));
         v.0.height.to_gecko_style_coord(&mut self.gecko.${gecko_ffi_name}.data_at_mut(${y_index}));
     }
     #[allow(non_snake_case)]
     pub fn copy_${ident}_from(&mut self, other: &Self) {
         self.gecko.${gecko_ffi_name}.data_at_mut(${x_index})
                   .copy_from(&other.gecko.${gecko_ffi_name}.data_at(${x_index}));
         self.gecko.${gecko_ffi_name}.data_at_mut(${y_index})
                   .copy_from(&other.gecko.${gecko_ffi_name}.data_at(${y_index}));
     }
+    #[allow(non_snake_case)]
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
     % if need_clone:
         #[allow(non_snake_case)]
         pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
             use values::computed::border::BorderCornerRadius;
             let width = GeckoStyleCoordConvertible::from_gecko_style_coord(
                             &self.gecko.${gecko_ffi_name}.data_at(${x_index}))
                             .expect("Failed to clone ${ident}");
             let height = GeckoStyleCoordConvertible::from_gecko_style_coord(
@@ -794,16 +839,20 @@ def set_gecko_property(ffi_name, expr):
         }
     }
     #[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});
         }
     }
+    #[allow(non_snake_case)]
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
     % if need_clone:
         pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
             use values::specified::url::SpecifiedUrl;
             use values::None_;
 
             if self.gecko.${gecko_ffi_name}.mRawPtr.is_null() {
                 Either::Second(None_)
             } else {
@@ -972,16 +1021,20 @@ impl ${style_struct.gecko_struct_name} {
     #[allow(non_snake_case)]
     pub fn set_${longhand.ident}(&mut self, _: longhands::${longhand.ident}::computed_value::T) {
         warn!("stylo: Unimplemented property setter: ${longhand.name}");
     }
     #[allow(non_snake_case)]
     pub fn copy_${longhand.ident}_from(&mut self, _: &Self) {
         warn!("stylo: Unimplemented property setter: ${longhand.name}");
     }
+    #[allow(non_snake_case)]
+    pub fn reset_${longhand.ident}(&mut self, other: &Self) {
+        self.copy_${longhand.ident}_from(other)
+    }
     % if longhand.need_clone:
     #[allow(non_snake_case)]
     pub fn clone_${longhand.ident}(&self) -> longhands::${longhand.ident}::computed_value::T {
         unimplemented!()
     }
     % endif
     % if longhand.need_index:
     pub fn ${longhand.ident}_count(&self) -> usize { 0 }
@@ -1148,16 +1201,21 @@ fn static_assert() {
     pub fn copy__moz_border_${side.ident}_colors_from(&mut self, other: &Self) {
         unsafe {
             bindings::Gecko_CopyMozBorderColors(&mut self.gecko, &other.gecko,
                                                 structs::Side::eSide${to_camel_case(side.ident)});
         }
     }
 
     #[allow(non_snake_case)]
+    pub fn reset__moz_border_${side.ident}_colors(&mut self, other: &Self) {
+        self.copy__moz_border_${side.ident}_colors_from(other)
+    }
+
+    #[allow(non_snake_case)]
     pub fn clone__moz_border_${side.ident}_colors(&self)
                                                   -> longhands::_moz_border_${side.ident}_colors::computed_value::T {
         use self::longhands::_moz_border_${side.ident}_colors::computed_value::T;
 
         let mut gecko_colors =
             unsafe { bindings::Gecko_GetMozBorderColors(&self.gecko,
                                                         structs::Side::eSide${to_camel_case(side.ident)}) };
 
@@ -1198,16 +1256,20 @@ fn static_assert() {
 
     pub fn copy_border_image_source_from(&mut self, other: &Self) {
         unsafe {
             Gecko_CopyImageValueFrom(&mut self.gecko.mBorderImageSource,
                                      &other.gecko.mBorderImageSource);
         }
     }
 
+    pub fn reset_border_image_source(&mut self, other: &Self) {
+        self.copy_border_image_source_from(other)
+    }
+
     pub fn clone_border_image_source(&self) -> longhands::border_image_source::computed_value::T {
         use values::None_;
 
         match unsafe { self.gecko.mBorderImageSource.into_image() } {
             Some(image) => Either::Second(image),
             None => Either::First(None_),
         }
     }
@@ -1233,16 +1295,20 @@ fn static_assert() {
         % endfor
     }
 
     pub fn copy_border_image_repeat_from(&mut self, other: &Self) {
         self.gecko.mBorderImageRepeatH = other.gecko.mBorderImageRepeatH;
         self.gecko.mBorderImageRepeatV = other.gecko.mBorderImageRepeatV;
     }
 
+    pub fn reset_border_image_repeat(&mut self, other: &Self) {
+        self.copy_border_image_repeat_from(other)
+    }
+
     pub fn clone_border_image_repeat(&self) -> longhands::border_image_repeat::computed_value::T {
         use properties::longhands::border_image_repeat::computed_value::RepeatKeyword;
         use gecko_bindings::structs;
 
         % for side in ["H", "V"]:
         let servo_${side.lower()} = match self.gecko.mBorderImageRepeat${side} as u32 {
             % for keyword in border_image_repeat_keywords:
             structs::NS_STYLE_BORDER_IMAGE_REPEAT_${keyword.upper()} => RepeatKeyword::${keyword},
@@ -1335,16 +1401,20 @@ fn static_assert() {
         // 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.unit() != nsStyleUnit::eStyleUnit_Calc);
         unsafe {
             self.gecko.mZIndex.copy_from_unchecked(&other.gecko.mZIndex);
         }
     }
 
+    pub fn reset_z_index(&mut self, other: &Self) {
+        self.copy_z_index_from(other)
+    }
+
     pub fn clone_z_index(&self) -> longhands::z_index::computed_value::T {
         return match self.gecko.mZIndex.as_value() {
             CoordDataValue::Integer(n) => Either::First(n),
             CoordDataValue::Auto => Either::Second(Auto),
             _ => {
                 debug_assert!(false);
                 Either::First(0)
             }
@@ -1409,16 +1479,20 @@ fn static_assert() {
     }
 
     pub fn copy_${value.name}_from(&mut self, other: &Self) {
         self.gecko.${value.gecko}.mHasSpan = other.gecko.${value.gecko}.mHasSpan;
         self.gecko.${value.gecko}.mInteger = other.gecko.${value.gecko}.mInteger;
         self.gecko.${value.gecko}.mLineName.assign(&*other.gecko.${value.gecko}.mLineName);
     }
 
+    pub fn reset_${value.name}(&mut self, other: &Self) {
+        self.copy_${value.name}_from(other)
+    }
+
     pub fn clone_${value.name}(&self) -> longhands::${value.name}::computed_value::T {
         use gecko_bindings::structs::{nsStyleGridLine_kMinLine, nsStyleGridLine_kMaxLine};
         use string_cache::Atom;
         use values::specified::Integer;
 
         longhands::${value.name}::computed_value::T {
             is_span: self.gecko.${value.gecko}.mHasSpan,
             ident: {
@@ -1447,16 +1521,20 @@ fn static_assert() {
                                 &mut self.gecko.mGridAuto${kind.title()}Max)
     }
 
     pub fn copy_grid_auto_${kind}_from(&mut self, other: &Self) {
         self.gecko.mGridAuto${kind.title()}Min.copy_from(&other.gecko.mGridAuto${kind.title()}Min);
         self.gecko.mGridAuto${kind.title()}Max.copy_from(&other.gecko.mGridAuto${kind.title()}Max);
     }
 
+    pub fn reset_grid_auto_${kind}(&mut self, other: &Self) {
+        self.copy_grid_auto_${kind}_from(other)
+    }
+
     pub fn clone_grid_auto_${kind}(&self) -> longhands::grid_auto_${kind}::computed_value::T {
         ::values::generics::grid::TrackSize::from_gecko_style_coords(&self.gecko.mGridAuto${kind.title()}Min,
                                                                      &self.gecko.mGridAuto${kind.title()}Max)
     }
 
     pub fn set_grid_template_${kind}(&mut self, v: longhands::grid_template_${kind}::computed_value::T) {
         <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %>
         use gecko_bindings::structs::{nsTArray, nsStyleGridLine_kMaxLine};
@@ -1584,16 +1662,20 @@ fn static_assert() {
     }
 
     pub fn copy_grid_template_${kind}_from(&mut self, other: &Self) {
         unsafe {
             bindings::Gecko_CopyStyleGridTemplateValues(&mut ${self_grid},
                                                         &other.gecko.mGridTemplate${kind.title()});
         }
     }
+
+    pub fn reset_grid_template_${kind}(&mut self, other: &Self) {
+        self.copy_grid_template_${kind}_from(other)
+    }
     % endfor
 
     ${impl_simple_type_with_conversion("grid_auto_flow")}
 
     pub fn set_grid_template_areas(&mut self, v: longhands::grid_template_areas::computed_value::T) {
         use gecko_bindings::bindings::Gecko_NewGridTemplateAreasValue;
         use gecko_bindings::sugar::refptr::UniqueRefPtr;
 
@@ -1623,16 +1705,20 @@ fn static_assert() {
         }
 
         unsafe { self.gecko.mGridTemplateAreas.set_move(refptr.get()) }
     }
 
     pub fn copy_grid_template_areas_from(&mut self, other: &Self) {
         unsafe { self.gecko.mGridTemplateAreas.set(&other.gecko.mGridTemplateAreas) }
     }
+
+    pub fn reset_grid_template_areas(&mut self, other: &Self) {
+        self.copy_grid_template_areas_from(other)
+    }
 </%self:impl_trait>
 
 <% skip_outline_longhands = " ".join("outline-style outline-width".split() +
                                      ["-moz-outline-radius-{0}".format(x.ident.replace("_", ""))
                                       for x in CORNERS]) %>
 <%self:impl_trait style_struct_name="Outline"
                   skip_longhands="${skip_outline_longhands}"
                   skip_additionals="*">
@@ -1658,16 +1744,21 @@ fn static_assert() {
     }
 
     #[allow(non_snake_case)]
     pub fn copy_outline_style_from(&mut self, other: &Self) {
         self.gecko.mOutlineStyle = other.gecko.mOutlineStyle;
     }
 
     #[allow(non_snake_case)]
+    pub fn reset_outline_style(&mut self, other: &Self) {
+        self.copy_outline_style_from(other)
+    }
+
+    #[allow(non_snake_case)]
     pub fn clone_outline_style(&self) -> longhands::outline_style::computed_value::T {
         // FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts
         match ${get_gecko_property("mOutlineStyle")} ${border_style_keyword.maybe_cast("u32")} {
             % for value in border_style_keyword.values_for('gecko'):
             structs::${border_style_keyword.gecko_constant(value)} => Either::Second(border_style::T::${value}),
             % endfor
             structs::${border_style_keyword.gecko_constant('auto')} => Either::First(Auto),
             % if border_style_keyword.gecko_inexhaustive:
@@ -1720,30 +1811,34 @@ fn static_assert() {
                 for (current, feature) in current_settings.iter_mut().zip(feature_settings) {
                     current.mTag = feature.tag;
                     current.mValue = feature.value.0;
                 }
             }
         };
     }
 
-    pub fn copy_font_feature_settings_from(&mut self, other: &Self ) {
+    pub fn copy_font_feature_settings_from(&mut self, other: &Self) {
         let current_settings = &mut self.gecko.mFont.fontFeatureSettings;
         let feature_settings = &other.gecko.mFont.fontFeatureSettings;
         let settings_length = feature_settings.len() as u32;
 
         current_settings.clear_pod();
         unsafe { current_settings.set_len_pod(settings_length) };
 
         for (current, feature) in current_settings.iter_mut().zip(feature_settings.iter()) {
             current.mTag = feature.mTag;
             current.mValue = feature.mValue;
         }
     }
 
+    pub fn reset_font_feature_settings(&mut self, other: &Self) {
+        self.copy_font_feature_settings_from(other)
+    }
+
     pub fn clone_font_feature_settings(&self) -> longhands::font_feature_settings::computed_value::T {
         use values::generics::{FontSettings, FontSettingTag, FontSettingTagInt} ;
 
         if self.gecko.mFont.fontFeatureSettings.len() == 0 {
             FontSettings::Normal
         } else {
             FontSettings::Tag(
                 self.gecko.mFont.fontFeatureSettings.iter().map(|gecko_font_feature_setting| {
@@ -1785,16 +1880,20 @@ fn static_assert() {
         unsafe { current_settings.set_len_pod(settings_length) };
 
         for (current, feature) in current_settings.iter_mut().zip(feature_settings.iter()) {
             current.mTag = feature.mTag;
             current.mValue = feature.mValue;
         }
     }
 
+    pub fn reset_font_variation_settings(&mut self, other: &Self) {
+        self.copy_font_variation_settings_from(other)
+    }
+
     pub fn fixup_none_generic(&mut self, device: &Device) {
         unsafe {
             bindings::Gecko_nsStyleFont_FixupNoneGeneric(&mut self.gecko, device.pres_context())
         }
     }
 
     pub fn set_font_family(&mut self, v: longhands::font_family::computed_value::T) {
         use properties::longhands::font_family::computed_value::FontFamily;
@@ -1828,16 +1927,20 @@ fn static_assert() {
         unimplemented!()
     }
 
     pub fn copy_font_family_from(&mut self, other: &Self) {
         unsafe { Gecko_CopyFontFamilyFrom(&mut self.gecko.mFont, &other.gecko.mFont); }
         self.gecko.mGenericID = other.gecko.mGenericID;
     }
 
+    pub fn reset_font_family(&mut self, other: &Self) {
+        self.copy_font_family_from(other)
+    }
+
     pub fn clone_font_family(&self) -> longhands::font_family::computed_value::T {
         use properties::longhands::font_family::computed_value::{FontFamily, FamilyName};
         use gecko_bindings::structs::FontFamilyType;
         use gecko_string_cache::Atom;
 
         ::properties::longhands::font_family::computed_value::T(
             self.gecko.mFont.fontlist.mFontlist.iter().map(|gecko_font_family_name| {
                 match gecko_font_family_name.mType {
@@ -2065,16 +2168,20 @@ fn static_assert() {
             T::Number(n) => self.gecko.mFont.sizeAdjust = n,
         }
     }
 
     pub fn copy_font_size_adjust_from(&mut self, other: &Self) {
         self.gecko.mFont.sizeAdjust = other.gecko.mFont.sizeAdjust;
     }
 
+    pub fn reset_font_size_adjust(&mut self, other: &Self) {
+        self.copy_font_size_adjust_from(other)
+    }
+
     pub fn clone_font_size_adjust(&self) -> longhands::font_size_adjust::computed_value::T {
         use properties::longhands::font_size_adjust::computed_value::T;
         T::from_gecko_adjust(self.gecko.mFont.sizeAdjust)
     }
 
     #[allow(non_snake_case)]
     pub fn set__x_lang(&mut self, v: longhands::_x_lang::computed_value::T) {
         let ptr = v.0.as_ptr();
@@ -2086,16 +2193,21 @@ fn static_assert() {
 
     #[allow(non_snake_case)]
     pub fn copy__x_lang_from(&mut self, other: &Self) {
         unsafe {
             Gecko_nsStyleFont_CopyLangFrom(&mut self.gecko, &other.gecko);
         }
     }
 
+    #[allow(non_snake_case)]
+    pub fn reset__x_lang(&mut self, other: &Self) {
+        self.copy__x_lang_from(other)
+    }
+
     <% impl_simple_type_with_conversion("font_language_override", "mFont.languageOverride") %>
 
     pub fn set_font_variant_alternates(&mut self, v: longhands::font_variant_alternates::computed_value::T) {
         use gecko_bindings::bindings::{Gecko_ClearAlternateValues, Gecko_AppendAlternateValues};
         % for value in "normal swash stylistic ornaments annotation styleset character_variant historical".split():
             use gecko_bindings::structs::NS_FONT_VARIANT_ALTERNATES_${value.upper()};
         % endfor
         use self::longhands::font_variant_alternates::VariantAlternates;
@@ -2144,16 +2256,20 @@ fn static_assert() {
         use gecko_bindings::bindings::Gecko_CopyAlternateValuesFrom;
 
         self.gecko.mFont.variantAlternates = other.gecko.mFont.variantAlternates;
         unsafe {
             Gecko_CopyAlternateValuesFrom(&mut self.gecko.mFont, &other.gecko.mFont);
         }
     }
 
+    pub fn reset_font_variant_alternates(&mut self, other: &Self) {
+        self.copy_font_variant_alternates_from(other)
+    }
+
     pub fn clone_font_variant_alternates(&self) -> longhands::font_variant_alternates::computed_value::T {
         use Atom;
         % for value in "normal swash stylistic ornaments annotation styleset character_variant historical".split():
             use gecko_bindings::structs::NS_FONT_VARIANT_ALTERNATES_${value.upper()};
         % endfor
         use properties::longhands::font_variant_alternates::VariantAlternates;
         use properties::longhands::font_variant_alternates::VariantAlternatesList;
         use values::CustomIdent;
@@ -2231,16 +2347,21 @@ fn static_assert() {
         self.gecko.m${type.capitalize()}${gecko_ffi_name}Count = count;
 
         // The length of mTransitions or mAnimations is often greater than m{Transition|Animation}XXCount,
         // don't copy values over the count.
         for (index, gecko) in self.gecko.m${type.capitalize()}s.iter_mut().enumerate().take(count as usize) {
             gecko.m${gecko_ffi_name} = other.gecko.m${type.capitalize()}s[index].m${gecko_ffi_name};
         }
     }
+
+    #[allow(non_snake_case)]
+    pub fn reset_${type}_${ident}(&mut self, other: &Self) {
+        self.copy_${type}_${ident}_from(other)
+    }
 </%def>
 
 <%def name="impl_animation_or_transition_count(type, ident, gecko_ffi_name)">
     #[allow(non_snake_case)]
     pub fn ${type}_${ident}_count(&self) -> usize {
         self.gecko.m${type.capitalize()}${gecko_ffi_name}Count as usize
     }
 </%def>
@@ -2420,16 +2541,20 @@ fn static_assert() {
         self.gecko.mDisplay = result;
     }
 
     pub fn copy_display_from(&mut self, other: &Self) {
         self.gecko.mDisplay = other.gecko.mDisplay;
         self.gecko.mOriginalDisplay = other.gecko.mDisplay;
     }
 
+    pub fn reset_display(&mut self, other: &Self) {
+        self.copy_display_from(other)
+    }
+
     <%call expr="impl_keyword_clone('display', 'mDisplay', display_keyword)"></%call>
 
     <% overflow_x = data.longhands_by_name["overflow-x"] %>
     pub fn set_overflow_y(&mut self, v: longhands::overflow_y::computed_value::T) {
         use properties::longhands::overflow_x::computed_value::T as BaseType;
         // FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts
         self.gecko.mOverflowY = match v {
             % for value in overflow_x.keyword.values_for('gecko'):
@@ -2540,16 +2665,20 @@ fn static_assert() {
 
         for (this, that) in self.gecko.mScrollSnapCoordinate
                                .iter_mut()
                                .zip(other.gecko.mScrollSnapCoordinate.iter()) {
             *this = *that;
         }
     }
 
+    pub fn reset_scroll_snap_coordinate(&mut self, other: &Self) {
+        self.copy_scroll_snap_coordinate_from(other)
+    }
+
     pub fn clone_scroll_snap_coordinate(&self) -> longhands::scroll_snap_coordinate::computed_value::T {
         let vec = self.gecko.mScrollSnapCoordinate.iter().map(|f| f.into()).collect();
         longhands::scroll_snap_coordinate::computed_value::T(vec)
     }
 
     ${impl_css_url('_moz_binding', 'mBinding.mPtr')}
 
     <%def name="transform_function_arm(name, keyword, items)">
@@ -2663,16 +2792,20 @@ fn static_assert() {
         };
         Self::convert_transform(&vec, &mut self.gecko.mSpecifiedTransform);
     }
 
     pub fn copy_transform_from(&mut self, other: &Self) {
         unsafe { self.gecko.mSpecifiedTransform.set(&other.gecko.mSpecifiedTransform); }
     }
 
+    pub fn reset_transform(&mut self, other: &Self) {
+        self.copy_transform_from(other)
+    }
+
     <%def name="computed_operation_arm(name, keyword, items)">
         <%
             # %s is substituted with the call to GetArrayItem.
             css_value_getters = {
                 "length" : "Au(bindings::Gecko_CSSValue_GetAbsoluteLength(%s))",
                 "lop" : "%s.get_lop()",
                 "angle" : "%s.get_angle()",
                 "number" : "bindings::Gecko_CSSValue_GetNumber(%s)",
@@ -2852,16 +2985,21 @@ fn static_assert() {
             if transition.mProperty == eCSSProperty_UNKNOWN ||
                transition.mProperty == eCSSPropertyExtra_variable {
                 let atom = other.gecko.mTransitions[index].mUnknownProperty.raw::<nsIAtom>();
                 debug_assert!(!atom.is_null());
                 unsafe { Gecko_StyleTransition_SetUnsupportedProperty(transition, atom) };
             }
         }
     }
+
+    pub fn reset_transition_property(&mut self, other: &Self) {
+        self.copy_transition_property_from(other)
+    }
+
     ${impl_transition_count('property', 'Property')}
 
     pub fn animations_equals(&self, other: &Self) -> bool {
         unsafe { bindings::Gecko_StyleAnimationsEquals(&self.gecko.mAnimations, &other.gecko.mAnimations) }
     }
 
     pub fn set_animation_name<I>(&mut self, v: I)
         where I: IntoIterator<Item = longhands::animation_name::computed_value::single_value::T>,
@@ -2899,16 +3037,21 @@ fn static_assert() {
         self.gecko.mAnimationNameCount = count;
 
         // The length of mAnimations is often greater than mAnimationXXCount,
         // don't copy values over the count.
         for (index, animation) in self.gecko.mAnimations.iter_mut().enumerate().take(count as usize) {
             animation.mName.assign(&*other.gecko.mAnimations[index].mName);
         }
     }
+
+    pub fn reset_animation_name(&mut self, other: &Self) {
+        self.copy_animation_name_from(other)
+    }
+
     ${impl_animation_count('name', 'Name')}
 
     ${impl_animation_time_value('delay', 'Delay')}
     ${impl_animation_time_value('duration', 'Duration')}
 
     ${impl_animation_keyword('direction', 'Direction',
                              data.longhands_by_name["animation-direction"].keyword)}
     ${impl_animation_keyword('fill_mode', 'FillMode',
@@ -2962,16 +3105,20 @@ fn static_assert() {
         self.gecko.mPerspectiveOrigin[1].set(v.vertical);
     }
 
     pub fn copy_perspective_origin_from(&mut self, other: &Self) {
         self.gecko.mPerspectiveOrigin[0].copy_from(&other.gecko.mPerspectiveOrigin[0]);
         self.gecko.mPerspectiveOrigin[1].copy_from(&other.gecko.mPerspectiveOrigin[1]);
     }
 
+    pub fn reset_perspective_origin(&mut self, other: &Self) {
+        self.copy_perspective_origin_from(other)
+    }
+
     pub fn clone_perspective_origin(&self) -> longhands::perspective_origin::computed_value::T {
         use properties::longhands::perspective_origin::computed_value::T;
         use values::computed::LengthOrPercentage;
         T {
             horizontal: LengthOrPercentage::from_gecko_style_coord(&self.gecko.mPerspectiveOrigin[0])
                 .expect("Expected length or percentage for horizontal value of perspective-origin"),
             vertical: LengthOrPercentage::from_gecko_style_coord(&self.gecko.mPerspectiveOrigin[1])
                 .expect("Expected length or percentage for vertical value of perspective-origin"),
@@ -2985,16 +3132,20 @@ fn static_assert() {
     }
 
     pub fn copy_transform_origin_from(&mut self, other: &Self) {
         self.gecko.mTransformOrigin[0].copy_from(&other.gecko.mTransformOrigin[0]);
         self.gecko.mTransformOrigin[1].copy_from(&other.gecko.mTransformOrigin[1]);
         self.gecko.mTransformOrigin[2].copy_from(&other.gecko.mTransformOrigin[2]);
     }
 
+    pub fn reset_transform_origin(&mut self, other: &Self) {
+        self.copy_transform_origin_from(other)
+    }
+
     pub fn clone_transform_origin(&self) -> longhands::transform_origin::computed_value::T {
         use properties::longhands::transform_origin::computed_value::T;
         use values::computed::LengthOrPercentage;
         T {
             horizontal: LengthOrPercentage::from_gecko_style_coord(&self.gecko.mTransformOrigin[0])
                 .expect("clone for LengthOrPercentage failed"),
             vertical: LengthOrPercentage::from_gecko_style_coord(&self.gecko.mTransformOrigin[1])
                 .expect("clone for LengthOrPercentage failed"),
@@ -3084,16 +3235,20 @@ fn static_assert() {
         use gecko_bindings::bindings::Gecko_CopyWillChangeFrom;
 
         self.gecko.mWillChangeBitField = other.gecko.mWillChangeBitField;
         unsafe {
             Gecko_CopyWillChangeFrom(&mut self.gecko, &other.gecko as *const _ as *mut _);
         }
     }
 
+    pub fn reset_will_change(&mut self, other: &Self) {
+        self.copy_will_change_from(other)
+    }
+
     pub fn clone_will_change(&self) -> longhands::will_change::computed_value::T {
         use properties::longhands::will_change::computed_value::T;
         use gecko_bindings::structs::nsIAtom;
         use gecko_string_cache::Atom;
         use values::CustomIdent;
 
         if self.gecko.mWillChange.mBuffer.len() == 0 {
             T::Auto
@@ -3217,16 +3372,20 @@ fn static_assert() {
         }
         for (layer, other) in self.gecko.${layers_field_name}.mLayers.iter_mut()
                                   .zip(other.gecko.${layers_field_name}.mLayers.iter())
                                   .take(count as usize) {
             layer.${field_name} = other.${field_name};
         }
         self.gecko.${layers_field_name}.${field_name}Count = count;
     }
+
+    pub fn reset_${shorthand}_${name}(&mut self, other: &Self) {
+        self.copy_${shorthand}_${name}_from(other)
+    }
 </%def>
 
 <%def name="impl_simple_image_array_property(name, shorthand, layer_field_name, field_name, struct_name)">
     <%
         ident = "%s_%s" % (shorthand, name)
         style_struct = next(x for x in data.style_structs if x.name == struct_name)
         longhand = next(x for x in style_struct.longhands if x.ident == ident)
         keyword = longhand.keyword
@@ -3367,16 +3526,20 @@ fn static_assert() {
                                   .zip(other.gecko.${image_layers_field}.mLayers.iter())
                                   .take(count as usize) {
             layer.mPosition.m${orientation.upper()}Position
                 = other.mPosition.m${orientation.upper()}Position;
         }
         self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count = count;
     }
 
+    pub fn reset_${shorthand}_position_${orientation}(&mut self, other: &Self) {
+        self.copy_${shorthand}_position_${orientation}_from(other)
+    }
+
     pub fn clone_${shorthand}_position_${orientation}(&self)
         -> longhands::${shorthand}_position_${orientation}::computed_value::T {
         longhands::${shorthand}_position_${orientation}::computed_value::T(
             self.gecko.${image_layers_field}.mLayers.iter()
                 .take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize)
                 .map(|position| position.mPosition.m${orientation.upper()}Position.into())
                 .collect()
         )
@@ -3478,17 +3641,16 @@ fn static_assert() {
                 BackgroundSize::Explicit {
                     width: to_servo(layer.mSize.mWidth._base, layer.mSize.mWidthType),
                     height: to_servo(layer.mSize.mHeight._base, layer.mSize.mHeightType),
                 }
             }).collect()
         )
     }
 
-
     pub fn copy_${shorthand}_image_from(&mut self, other: &Self) {
         use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
         unsafe {
             let count = other.gecko.${image_layers_field}.mImageCount;
             unsafe {
                 Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field},
                                               count as usize,
                                               LayerType::${shorthand.capitalize()});
@@ -3498,16 +3660,20 @@ fn static_assert() {
                                       .zip(other.gecko.${image_layers_field}.mLayers.iter())
                                       .take(count as usize) {
                 Gecko_CopyImageValueFrom(&mut layer.mImage, &other.mImage);
             }
             self.gecko.${image_layers_field}.mImageCount = count;
         }
     }
 
+    pub fn reset_${shorthand}_image(&mut self, other: &Self) {
+        self.copy_${shorthand}_image_from(other)
+    }
+
     #[allow(unused_variables)]
     pub fn set_${shorthand}_image<I>(&mut self, images: I)
         where I: IntoIterator<Item = longhands::${shorthand}_image::computed_value::single_value::T>,
               I::IntoIter: ExactSizeIterator
     {
         use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
 
         let images = images.into_iter();
@@ -3613,16 +3779,20 @@ fn static_assert() {
             }
         }
     }
 
     pub fn copy_list_style_image_from(&mut self, other: &Self) {
         unsafe { Gecko_CopyListStyleImageFrom(&mut self.gecko, &other.gecko); }
     }
 
+    pub fn reset_list_style_image(&mut self, other: &Self) {
+        self.copy_list_style_image_from(other)
+    }
+
     pub fn clone_list_style_image(&self) -> longhands::list_style_image::computed_value::T {
         use values::specified::url::SpecifiedUrl;
         use values::{Either, None_};
 
         longhands::list_style_image::computed_value::T(
             match self.gecko.mListStyleImage.mRawPtr.is_null() {
                 true => Either::Second(None_),
                 false => {
@@ -3650,16 +3820,20 @@ fn static_assert() {
     }
 
     pub fn copy_list_style_type_from(&mut self, other: &Self) {
         unsafe {
             Gecko_CopyCounterStyle(&mut self.gecko.mCounterStyle, &other.gecko.mCounterStyle);
         }
     }
 
+    pub fn reset_list_style_type(&mut self, other: &Self) {
+        self.copy_list_style_type_from(other)
+    }
+
     pub fn set_quotes(&mut self, other: longhands::quotes::computed_value::T) {
         use gecko_bindings::bindings::Gecko_NewStyleQuoteValues;
         use gecko_bindings::sugar::refptr::UniqueRefPtr;
 
         let mut refptr = unsafe {
             UniqueRefPtr::from_addrefed(Gecko_NewStyleQuoteValues(other.0.len() as u32))
         };
 
@@ -3670,16 +3844,20 @@ fn static_assert() {
 
         unsafe { self.gecko.mQuotes.set_move(refptr.get()) }
     }
 
     pub fn copy_quotes_from(&mut self, other: &Self) {
         unsafe { self.gecko.mQuotes.set(&other.gecko.mQuotes); }
     }
 
+    pub fn reset_quotes(&mut self, other: &Self) {
+        self.copy_quotes_from(other)
+    }
+
     pub fn clone_quotes(&self) -> longhands::quotes::computed_value::T {
         unsafe {
             let ref gecko_quote_values = *self.gecko.mQuotes.mRawPtr;
             longhands::quotes::computed_value::T(
                 gecko_quote_values.mQuotePairs.iter().map(|gecko_pair| {
                     (gecko_pair.first.to_string(), gecko_pair.second.to_string())
                 }).collect()
             )
@@ -3769,16 +3947,20 @@ fn static_assert() {
             gecko_shadow.set_from_box_shadow(servo);
         }
     }
 
     pub fn copy_box_shadow_from(&mut self, other: &Self) {
         self.gecko.mBoxShadow.copy_from(&other.gecko.mBoxShadow);
     }
 
+    pub fn reset_box_shadow(&mut self, other: &Self) {
+        self.copy_box_shadow_from(other)
+    }
+
     pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T {
         let buf = self.gecko.mBoxShadow.iter().map(|v| v.to_box_shadow()).collect();
         longhands::box_shadow::computed_value::T(buf)
     }
 
     pub fn set_clip(&mut self, v: longhands::clip::computed_value::T) {
         use gecko_bindings::structs::NS_STYLE_CLIP_AUTO;
         use gecko_bindings::structs::NS_STYLE_CLIP_RECT;
@@ -3829,16 +4011,20 @@ fn static_assert() {
         }
     }
 
     pub fn copy_clip_from(&mut self, other: &Self) {
         self.gecko.mClip = other.gecko.mClip;
         self.gecko.mClipFlags = other.gecko.mClipFlags;
     }
 
+    pub fn reset_clip(&mut self, other: &Self) {
+        self.copy_clip_from(other)
+    }
+
     pub fn clone_clip(&self) -> longhands::clip::computed_value::T {
         use gecko_bindings::structs::NS_STYLE_CLIP_AUTO;
         use gecko_bindings::structs::NS_STYLE_CLIP_BOTTOM_AUTO;
         use gecko_bindings::structs::NS_STYLE_CLIP_LEFT_AUTO;
         use gecko_bindings::structs::NS_STYLE_CLIP_RIGHT_AUTO;
         use gecko_bindings::structs::NS_STYLE_CLIP_TOP_AUTO;
         use values::computed::{ClipRect, ClipRectOrAuto};
         use values::Either;
@@ -3958,16 +4144,20 @@ fn static_assert() {
     }
 
     pub fn copy_filter_from(&mut self, other: &Self) {
         unsafe {
             Gecko_CopyFiltersFrom(&other.gecko as *const _ as *mut _, &mut self.gecko);
         }
     }
 
+    pub fn reset_filter(&mut self, other: &Self) {
+        self.copy_filter_from(other)
+    }
+
     pub fn clone_filter(&self) -> longhands::filter::computed_value::T {
         use values::generics::effects::Filter;
         use values::specified::url::SpecifiedUrl;
         use gecko_bindings::structs::NS_STYLE_FILTER_BLUR;
         use gecko_bindings::structs::NS_STYLE_FILTER_BRIGHTNESS;
         use gecko_bindings::structs::NS_STYLE_FILTER_CONTRAST;
         use gecko_bindings::structs::NS_STYLE_FILTER_GRAYSCALE;
         use gecko_bindings::structs::NS_STYLE_FILTER_INVERT;
@@ -4041,31 +4231,39 @@ fn static_assert() {
         }
     }
 
     pub fn copy_image_orientation_from(&mut self, other: &Self) {
         unsafe {
             bindings::Gecko_CopyImageOrientationFrom(&mut self.gecko, &other.gecko);
         }
     }
+
+    pub fn reset_image_orientation(&mut self, other: &Self) {
+        self.copy_image_orientation_from(other)
+    }
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="InheritedTable"
                   skip_longhands="border-spacing">
 
     pub fn set_border_spacing(&mut self, v: longhands::border_spacing::computed_value::T) {
         self.gecko.mBorderSpacingCol = v.horizontal.0;
         self.gecko.mBorderSpacingRow = v.vertical.0;
     }
 
     pub fn copy_border_spacing_from(&mut self, other: &Self) {
         self.gecko.mBorderSpacingCol = other.gecko.mBorderSpacingCol;
         self.gecko.mBorderSpacingRow = other.gecko.mBorderSpacingRow;
     }
 
+    pub fn reset_border_spacing(&mut self, other: &Self) {
+        self.copy_border_spacing_from(other)
+    }
+
     pub fn clone_border_spacing(&self) -> longhands::border_spacing::computed_value::T {
         longhands::border_spacing::computed_value::T {
             horizontal: Au(self.gecko.mBorderSpacingCol),
             vertical: Au(self.gecko.mBorderSpacingRow)
         }
     }
 </%self:impl_trait>
 
@@ -4090,16 +4288,20 @@ fn static_assert() {
             gecko_shadow.set_from_simple_shadow(servo);
         }
     }
 
     pub fn copy_text_shadow_from(&mut self, other: &Self) {
         self.gecko.mTextShadow.copy_from(&other.gecko.mTextShadow);
     }
 
+    pub fn reset_text_shadow(&mut self, other: &Self) {
+        self.copy_text_shadow_from(other)
+    }
+
     pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T {
         let buf = self.gecko.mTextShadow.iter().map(|v| v.to_simple_shadow()).collect();
         longhands::text_shadow::computed_value::T(buf)
     }
 
     pub fn set_line_height(&mut self, v: longhands::line_height::computed_value::T) {
         use values::generics::text::LineHeight;
         // FIXME: Align binary representations and ditch |match| for cast + static_asserts
@@ -4216,16 +4418,20 @@ fn static_assert() {
         self.clear_text_emphasis_style_if_string();
         if other.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 {
             self.gecko.mTextEmphasisStyleString
                       .assign(&*other.gecko.mTextEmphasisStyleString)
         }
         self.gecko.mTextEmphasisStyle = other.gecko.mTextEmphasisStyle;
     }
 
+    pub fn reset_text_emphasis_style(&mut self, other: &Self) {
+        self.copy_text_emphasis_style_from(other)
+    }
+
     pub fn clone_text_emphasis_style(&self) -> longhands::text_emphasis_style::computed_value::T {
         use properties::longhands::text_emphasis_style::computed_value::{T, KeywordValue};
         use properties::longhands::text_emphasis_style::ShapeKeyword;
 
         if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_NONE as u8 {
             return T::None;
         } else if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 {
             return T::String(self.gecko.mTextEmphasisStyleString.to_string());
@@ -4291,16 +4497,17 @@ fn static_assert() {
             if side.mType == structs::NS_STYLE_TEXT_OVERFLOW_STRING as u8 {
                 side.mString.assign(&nsString::new());
                 side.mType = structs::NS_STYLE_TEXT_OVERFLOW_CLIP as u8;
             }
         }
         clear_if_string(&mut self.gecko.mTextOverflow.mLeft);
         clear_if_string(&mut self.gecko.mTextOverflow.mRight);
     }
+
     pub fn set_text_overflow(&mut self, v: longhands::text_overflow::computed_value::T) {
         use gecko_bindings::structs::nsStyleTextOverflowSide;
         use properties::longhands::text_overflow::Side;
 
         fn set(side: &mut nsStyleTextOverflowSide, value: &Side) {
             let ty = match *value {
                 Side::Clip => structs::NS_STYLE_TEXT_OVERFLOW_CLIP,
                 Side::Ellipsis => structs::NS_STYLE_TEXT_OVERFLOW_ELLIPSIS,
@@ -4328,16 +4535,20 @@ fn static_assert() {
             side.mType = other.mType
         }
         self.clear_overflow_sides_if_string();
         set(&mut self.gecko.mTextOverflow.mLeft, &other.gecko.mTextOverflow.mLeft);
         set(&mut self.gecko.mTextOverflow.mRight, &other.gecko.mTextOverflow.mRight);
         self.gecko.mTextOverflow.mLogicalDirections = other.gecko.mTextOverflow.mLogicalDirections;
     }
 
+    pub fn reset_text_overflow(&mut self, other: &Self) {
+        self.copy_text_overflow_from(other)
+    }
+
     pub fn clone_text_overflow(&self) -> longhands::text_overflow::computed_value::T {
         use gecko_bindings::structs::nsStyleTextOverflowSide;
         use properties::longhands::text_overflow::Side;
 
         fn to_servo(side: &nsStyleTextOverflowSide) -> Side {
             match side.mType as u32 {
                 structs::NS_STYLE_TEXT_OVERFLOW_CLIP => Side::Clip,
                 structs::NS_STYLE_TEXT_OVERFLOW_ELLIPSIS => Side::Ellipsis,
@@ -4371,16 +4582,20 @@ fn static_assert() {
         }
     }
 
     pub fn copy_initial_letter_from(&mut self, other: &Self) {
         self.gecko.mInitialLetterSize = other.gecko.mInitialLetterSize;
         self.gecko.mInitialLetterSink = other.gecko.mInitialLetterSink;
     }
 
+    pub fn reset_initial_letter(&mut self, other: &Self) {
+        self.copy_initial_letter_from(other)
+    }
+
     pub fn clone_initial_letter(&self) -> longhands::initial_letter::computed_value::T {
         use values::generics::text::InitialLetter;
 
         if self.gecko.mInitialLetterSize == 0. && self.gecko.mInitialLetterSink == 0 {
             InitialLetter::Normal
         } else if self.gecko.mInitialLetterSize.floor() as i32 == self.gecko.mInitialLetterSink {
             InitialLetter::Specified(self.gecko.mInitialLetterSize, None)
         } else {
@@ -4508,16 +4723,20 @@ fn static_assert() {
     }
 
     pub fn copy_${ident}_from(&mut self, other: &Self) {
         use gecko_bindings::bindings::Gecko_CopyShapeSourceFrom;
         unsafe {
             Gecko_CopyShapeSourceFrom(&mut self.gecko.${gecko_ffi_name}, &other.gecko.${gecko_ffi_name});
         }
     }
+
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
 </%def>
 
 <% skip_svg_longhands = """
 mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position-x mask-position-y mask-size mask-image
 clip-path
 """
 %>
 <%self:impl_trait style_struct_name="SVG"
@@ -4575,16 +4794,20 @@ clip-path
     }
 
     pub fn copy_stroke_dasharray_from(&mut self, other: &Self) {
         unsafe {
             bindings::Gecko_nsStyleSVG_CopyDashArray(&mut self.gecko, &other.gecko);
         }
     }
 
+    pub fn reset_stroke_dasharray(&mut self, other: &Self) {
+        self.copy_stroke_dasharray_from(other)
+    }
+
     pub fn clone_stroke_dasharray(&self) -> longhands::stroke_dasharray::computed_value::T {
         use values::computed::LengthOrPercentage;
 
         let mut vec = vec![];
         for gecko in self.gecko.mStrokeDasharray.iter() {
             match gecko.as_value() {
                 CoordDataValue::Factor(number) => vec.push(Either::First(number)),
                 CoordDataValue::Coord(coord) =>
@@ -4665,16 +4888,21 @@ clip-path
     }
 
     #[allow(non_snake_case)]
     pub fn copy__moz_context_properties_from(&mut self, other: &Self) {
         unsafe {
             bindings::Gecko_nsStyleSVG_CopyContextProperties(&mut self.gecko, &other.gecko);
         }
     }
+
+    #[allow(non_snake_case)]
+    pub fn reset__moz_context_properties(&mut self, other: &Self) {
+        self.copy__moz_context_properties_from(other)
+    }
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="Color"
                   skip_longhands="*">
     pub fn set_color(&mut self, v: longhands::color::computed_value::T) {
         let result = convert_rgba_to_nscolor(&v);
         ${set_gecko_property("mColor", "result")}
     }
@@ -4768,16 +4996,20 @@ clip-path
 
     pub fn copy_cursor_from(&mut self, other: &Self) {
         self.gecko.mCursor = other.gecko.mCursor;
         unsafe {
             Gecko_CopyCursorArrayFrom(&mut self.gecko, &other.gecko);
         }
     }
 
+    pub fn reset_cursor(&mut self, other: &Self) {
+        self.copy_cursor_from(other)
+    }
+
     pub fn clone_cursor(&self) -> longhands::cursor::computed_value::T {
         use properties::longhands::cursor::computed_value::{Keyword, Image};
         use style_traits::cursor::Cursor;
         use values::specified::url::SpecifiedUrl;
 
         let keyword = match self.gecko.mCursor as u32 {
             structs::NS_STYLE_CURSOR_AUTO => Keyword::Auto,
             structs::NS_STYLE_CURSOR_NONE => Keyword::Cursor(Cursor::None),
@@ -4995,16 +5227,20 @@ clip-path
 
     pub fn copy_content_from(&mut self, other: &Self) {
         use gecko_bindings::bindings::Gecko_CopyStyleContentsFrom;
         unsafe {
             Gecko_CopyStyleContentsFrom(&mut self.gecko, &other.gecko)
         }
     }
 
+    pub fn reset_content(&mut self, other: &Self) {
+        self.copy_content_from(other)
+    }
+
     % for counter_property in ["Increment", "Reset"]:
         pub fn set_counter_${counter_property.lower()}(&mut self, v: longhands::counter_increment::computed_value::T) {
             unsafe {
                 bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut self.gecko,
                                                                       v.0.len() as u32);
                 for (i, (name, value)) in v.0.into_iter().enumerate() {
                     self.gecko.m${counter_property}s[i].mCounter.assign(name.0.as_slice());
                     self.gecko.m${counter_property}s[i].mValue = value;
@@ -5013,16 +5249,20 @@ clip-path
         }
 
         pub fn copy_counter_${counter_property.lower()}_from(&mut self, other: &Self) {
             unsafe {
                 bindings::Gecko_CopyCounter${counter_property}sFrom(&mut self.gecko, &other.gecko)
             }
         }
 
+        pub fn reset_counter_${counter_property.lower()}(&mut self, other: &Self) {
+            self.copy_counter_${counter_property.lower()}_from(other)
+        }
+
         pub fn clone_counter_${counter_property.lower()}(&self) -> longhands::counter_increment::computed_value::T {
             use values::CustomIdent;
             use gecko_string_cache::Atom;
 
             longhands::counter_increment::computed_value::T(
                 self.gecko.m${counter_property}s.iter().map(|ref gecko_counter| {
                     (CustomIdent(Atom::from(gecko_counter.mCounter.to_string())), gecko_counter.mValue)
                 }).collect()
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -912,16 +912,25 @@
                                             other: &Self,
                                             wm: WritingMode) {
         <%self:logical_setter_helper name="${name}">
             <%def name="inner(physical_ident)">
                 self.copy_${physical_ident}_from(other)
             </%def>
         </%self:logical_setter_helper>
     }
+
+    /// Copy the appropriate physical property from another struct for ${name}
+    /// given a writing mode.
+    pub fn reset_${to_rust_ident(name)}(&mut self,
+                                        other: &Self,
+                                        wm: WritingMode) {
+        self.copy_${to_rust_ident(name)}_from(other, wm)
+    }
+
     % if need_clone:
         /// Get the computed value for the appropriate physical property for
         /// ${name} given a writing mode.
         pub fn clone_${to_rust_ident(name)}(&self, wm: WritingMode)
             -> longhands::${to_rust_ident(name)}::computed_value::T {
         <%self:logical_setter_helper name="${name}">
             <%def name="inner(physical_ident)">
                 self.clone_${physical_ident}()
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -1703,16 +1703,23 @@ pub mod style_structs {
                         }
                     % endif
                     /// Set ${longhand.name} from other struct.
                     #[allow(non_snake_case)]
                     #[inline]
                     pub fn copy_${longhand.ident}_from(&mut self, other: &Self) {
                         self.${longhand.ident} = other.${longhand.ident}.clone();
                     }
+
+                    /// Reset ${longhand.name} from the initial struct.
+                    #[allow(non_snake_case)]
+                    #[inline]
+                    pub fn reset_${longhand.ident}(&mut self, other: &Self) {
+                        self.copy_${longhand.ident}_from(other)
+                    }
                     % if longhand.need_clone:
                         /// Get the computed value for ${longhand.name}.
                         #[allow(non_snake_case)]
                         #[inline]
                         pub fn clone_${longhand.ident}(&self) -> longhands::${longhand.ident}::computed_value::T {
                             self.${longhand.ident}.clone()
                         }
                     % endif
@@ -2621,29 +2628,24 @@ impl<'a> StyleBuilder<'a> {
             );
     }
 
     /// Reset `${property.ident}` to the initial value.
     #[allow(non_snake_case)]
     pub fn reset_${property.ident}(&mut self) {
         let reset_struct =
             self.reset_style.get_${property.style_struct.name_lower}();
-        % if property.ident == "justify_items":
-            // TODO(emilio): Generalise this!
-            self.${property.style_struct.ident}.mutate()
-                .reset_${property.ident}(reset_struct)
-        % else:
-            self.${property.style_struct.ident}.mutate()
-                .copy_${property.ident}_from(
-                    reset_struct,
-                    % if property.logical:
-                    self.writing_mode,
-                    % endif
-                );
-        % endif
+
+        self.${property.style_struct.ident}.mutate()
+            .reset_${property.ident}(
+                reset_struct,
+                % if property.logical:
+                self.writing_mode,
+                % endif
+            );
     }
 
     % if not property.is_vector:
     /// Set the `${property.ident}` to the computed value `value`.
     #[allow(non_snake_case)]
     pub fn set_${property.ident}(
         &mut self,
         value: longhands::${property.ident}::computed_value::T