servo: Merge #12645 - stylo: Allow computing change hints during the traversal (from emilio:stylo); r=bholley
authorEmilio Cobos Álvarez <ecoal95@gmail.com>
Wed, 03 Aug 2016 19:02:26 -0500
changeset 339428 1f1fe0aa5f631d3ebac44d43e635f82f1447cb32
parent 339427 51c17be9c6d5eeb0357ad91c7635ca0c08dfcb7d
child 339429 8c0b61a2f4a4a86af64e1a7acb888b9e18b4a4e0
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)
reviewersbholley
servo: Merge #12645 - stylo: Allow computing change hints during the traversal (from emilio:stylo); r=bholley <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors <!-- Either: --> - [x] These changes do not require tests because geckolib :-( <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> r? @bholley cc @heycam Source-Repo: https://github.com/servo/servo Source-Revision: cbf71a2cf39e792f75309e68f7cabe862d4a70eb
servo/.travis.yml
servo/components/layout/animation.rs
servo/components/script/layout_wrapper.rs
servo/components/script_layout_interface/restyle_damage.rs
servo/components/style/animation.rs
servo/components/style/dom.rs
servo/components/style/gecko_glue.rs
servo/components/style/matching.rs
servo/components/style/restyle_hints.rs
servo/components/style/sequential.rs
servo/components/style/traversal.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/tools/regen.py
servo/ports/geckolib/lib.rs
servo/ports/geckolib/sanity_checks.rs
servo/ports/geckolib/wrapper.rs
servo/python/servo/testing_commands.py
--- a/servo/.travis.yml
+++ b/servo/.travis.yml
@@ -8,16 +8,17 @@ matrix:
          - ./mach test-tidy --no-progress --all
          - ./mach test-tidy --no-progress --self-test
       cache: false
     - sudo: 9000
       dist: trusty
       script:
          - ./mach build -d --verbose
          - ./mach build-geckolib
+         - ./mach test-geckolib
          - ./mach test-unit
          - ./mach test-compiletest
          - bash etc/ci/check_no_unwrap.sh
          - bash etc/ci/lockfile_changed.sh
          - bash etc/ci/manifest_changed.sh
       cache:
         directories:
           - .cargo
--- a/servo/components/layout/animation.rs
+++ b/servo/components/layout/animation.rs
@@ -9,16 +9,17 @@ use flow::{self, Flow};
 use gfx::display_list::OpaqueNode;
 use ipc_channel::ipc::IpcSender;
 use msg::constellation_msg::PipelineId;
 use script_layout_interface::restyle_damage::RestyleDamage;
 use script_traits::{AnimationState, LayoutMsg as ConstellationMsg};
 use std::collections::HashMap;
 use std::sync::mpsc::Receiver;
 use style::animation::{Animation, update_style_for_animation};
+use style::dom::TRestyleDamage;
 use style::timer::Timer;
 
 /// Processes any new animations that were discovered after style recalculation.
 /// Also expire any old animations that have completed, inserting them into
 /// `expired_animations`.
 pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
                               running_animations: &mut HashMap<OpaqueNode, Vec<Animation>>,
                               expired_animations: &mut HashMap<OpaqueNode, Vec<Animation>>,
@@ -125,20 +126,21 @@ pub fn update_animation_state(constellat
 pub fn recalc_style_for_animations(context: &SharedLayoutContext,
                                    flow: &mut Flow,
                                    animations: &HashMap<OpaqueNode,
                                                         Vec<Animation>>) {
     let mut damage = RestyleDamage::empty();
     flow.mutate_fragments(&mut |fragment| {
         if let Some(ref animations) = animations.get(&fragment.node) {
             for animation in animations.iter() {
+                let old_style = fragment.style.clone();
                 update_style_for_animation(&context.style_context,
                                            animation,
-                                           &mut fragment.style,
-                                           Some(&mut damage));
+                                           &mut fragment.style);
+                damage |= RestyleDamage::compute(Some(&old_style), &fragment.style);
             }
         }
     });
 
     let base = flow::mut_base(flow);
     base.restyle_damage.insert(damage);
     for kid in base.children.iter_mut() {
         recalc_style_for_animations(context, kid, animations)
--- a/servo/components/script/layout_wrapper.rs
+++ b/servo/components/script/layout_wrapper.rs
@@ -46,24 +46,25 @@ use script_layout_interface::restyle_dam
 use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, LayoutNode, PseudoElementType};
 use script_layout_interface::wrapper_traits::{ThreadSafeLayoutNode, ThreadSafeLayoutElement};
 use script_layout_interface::{HTMLCanvasData, LayoutNodeType, TrustedNodeAddress};
 use script_layout_interface::{OpaqueStyleAndLayoutData, PartialStyleAndLayoutData};
 use selectors::matching::{DeclarationBlock, ElementFlags};
 use selectors::parser::{AttrSelector, NamespaceConstraint};
 use std::marker::PhantomData;
 use std::mem::{transmute, transmute_copy};
+use std::sync::Arc;
 use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace};
 use style::attr::AttrValue;
 use style::computed_values::display;
 use style::context::SharedStyleContext;
 use style::data::PrivateStyleData;
 use style::dom::{PresentationalHintsSynthetizer, OpaqueNode, TDocument, TElement, TNode, UnsafeNode};
 use style::element_state::*;
-use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
+use style::properties::{ComputedValues, PropertyDeclaration, PropertyDeclarationBlock};
 use style::refcell::{Ref, RefCell, RefMut};
 use style::selector_impl::{ElementSnapshot, NonTSPseudoClass, ServoSelectorImpl};
 use style::sink::Push;
 use style::str::is_whitespace;
 use url::Url;
 
 #[derive(Copy, Clone)]
 pub struct ServoLayoutNode<'a> {
@@ -257,16 +258,23 @@ impl<'ln> TNode for ServoLayoutNode<'ln>
         }
     }
 
     fn next_sibling(&self) -> Option<ServoLayoutNode<'ln>> {
         unsafe {
             self.node.next_sibling_ref().map(|node| self.new_with_this_lifetime(&node))
         }
     }
+
+    #[inline]
+    fn existing_style_for_restyle_damage<'a>(&'a self,
+                                             current_cv: Option<&'a Arc<ComputedValues>>)
+                                             -> Option<&'a Arc<ComputedValues>> {
+        current_cv
+    }
 }
 
 impl<'ln> LayoutNode for ServoLayoutNode<'ln> {
     type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>;
 
     fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode {
         ServoThreadSafeLayoutNode::new(self)
     }
--- a/servo/components/script_layout_interface/restyle_damage.rs
+++ b/servo/components/script_layout_interface/restyle_damage.rs
@@ -39,31 +39,38 @@ bitflags! {
         const RESOLVE_GENERATED_CONTENT = 0x20,
 
         #[doc = "The entire flow needs to be reconstructed."]
         const RECONSTRUCT_FLOW = 0x40
     }
 }
 
 impl TRestyleDamage for RestyleDamage {
-    fn compute(old: Option<&Arc<ServoComputedValues>>, new: &ServoComputedValues) ->
-        RestyleDamage { compute_damage(old, new) }
+    /// For Servo the style source is always the computed values.
+    type PreExistingComputedValues = Arc<ServoComputedValues>;
 
-    /// Returns a bitmask that represents a flow that needs to be rebuilt and reflowed.
+    fn compute(old: Option<&Arc<ServoComputedValues>>,
+               new: &Arc<ServoComputedValues>) -> RestyleDamage {
+        compute_damage(old, new)
+    }
+
+    /// Returns a bitmask that represents a flow that needs to be rebuilt and
+    /// reflowed.
     ///
-    /// Use this instead of `RestyleDamage::all()` because `RestyleDamage::all()` will result in
-    /// unnecessary sequential resolution of generated content.
+    /// Use this instead of `RestyleDamage::all()` because
+    /// `RestyleDamage::all()` will result in unnecessary sequential resolution
+    /// of generated content.
     fn rebuild_and_reflow() -> RestyleDamage {
         REPAINT | STORE_OVERFLOW | BUBBLE_ISIZES | REFLOW_OUT_OF_FLOW | REFLOW | RECONSTRUCT_FLOW
     }
 }
 
 impl RestyleDamage {
-    /// Supposing a flow has the given `position` property and this damage, returns the damage that
-    /// we should add to the *parent* of this flow.
+    /// Supposing a flow has the given `position` property and this damage,
+    /// returns the damage that we should add to the *parent* of this flow.
     pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -> RestyleDamage {
         if child_is_absolutely_positioned {
             self & (REPAINT | STORE_OVERFLOW | REFLOW_OUT_OF_FLOW | RESOLVE_GENERATED_CONTENT)
         } else {
             self & (REPAINT | STORE_OVERFLOW | REFLOW | REFLOW_OUT_OF_FLOW |
                     RESOLVE_GENERATED_CONTENT)
         }
     }
@@ -138,17 +145,18 @@ macro_rules! add_if_not_equal(
             $damage.insert($($effect)|*);
             true
         } else {
             false
         }
     })
 );
 
-fn compute_damage(old: Option<&Arc<ServoComputedValues>>, new: &ServoComputedValues) -> RestyleDamage {
+fn compute_damage(old: Option<&Arc<ServoComputedValues>>, new: &Arc<ServoComputedValues>) -> RestyleDamage {
+    let new = &**new;
     let old: &ServoComputedValues = match old {
         None => return RestyleDamage::rebuild_and_reflow(),
         Some(cv) => &**cv,
     };
 
     let mut damage = RestyleDamage::empty();
 
     // This should check every CSS property, as enumerated in the fields of
--- a/servo/components/style/animation.rs
+++ b/servo/components/style/animation.rs
@@ -1,17 +1,17 @@
 /* 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/. */
 
 //! CSS transitions and animations.
 
 use bezier::Bezier;
 use context::SharedStyleContext;
-use dom::{OpaqueNode, TRestyleDamage};
+use dom::OpaqueNode;
 use euclid::point::Point2D;
 use keyframes::{KeyframesStep, KeyframesStepValue};
 use properties::animated_properties::{AnimatedProperty, TransitionProperty};
 use properties::longhands::animation_direction::computed_value::AnimationDirection;
 use properties::longhands::animation_iteration_count::computed_value::AnimationIterationCount;
 use properties::longhands::animation_play_state::computed_value::AnimationPlayState;
 use properties::longhands::transition_timing_function::computed_value::StartEnd;
 use properties::longhands::transition_timing_function::computed_value::TransitionTimingFunction;
@@ -485,36 +485,31 @@ pub fn update_style_for_animation_frame(
     }
 
     frame.property_animation.update(Arc::make_mut(&mut new_style), progress);
 
     true
 }
 /// Updates a single animation and associated style based on the current time.
 /// If `damage` is provided, inserts the appropriate restyle damage.
-pub fn update_style_for_animation<Damage>(context: &SharedStyleContext,
-                                          animation: &Animation,
-                                          style: &mut Arc<ComputedValues>,
-                                          damage: Option<&mut Damage>)
-where Damage: TRestyleDamage {
+pub fn update_style_for_animation(context: &SharedStyleContext,
+                                  animation: &Animation,
+                                  style: &mut Arc<ComputedValues>) {
     debug!("update_style_for_animation: entering");
     debug_assert!(!animation.is_expired());
+
     match *animation {
         Animation::Transition(_, start_time, ref frame, _) => {
             debug!("update_style_for_animation: transition found");
             let now = context.timer.seconds();
             let mut new_style = (*style).clone();
             let updated_style = update_style_for_animation_frame(&mut new_style,
                                                                  now, start_time,
                                                                  frame);
             if updated_style {
-                if let Some(damage) = damage {
-                    *damage = *damage | Damage::compute(Some(style), &new_style);
-                }
-
                 *style = new_style
             }
         }
         Animation::Keyframes(_, ref name, ref state) => {
             debug!("update_style_for_animation: animation found: \"{}\", {:?}", name, state);
             let duration = state.duration;
             let started_at = state.started_at;
 
@@ -655,20 +650,16 @@ where Damage: TRestyleDamage {
                     None => {
                         debug!("update_style_for_animation: property animation {:?} not animating",
                                transition_property);
                     }
                 }
             }
 
             debug!("update_style_for_animation: got style change in animation \"{}\"", name);
-            if let Some(damage) = damage {
-                *damage = *damage | Damage::compute(Some(style), &new_style);
-            }
-
             *style = new_style;
         }
     }
 }
 
 /// Update the style in the node when it finishes.
 pub fn complete_expired_transitions(node: OpaqueNode, style: &mut Arc<ComputedValues>,
                                     context: &SharedStyleContext) -> bool {
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -41,17 +41,29 @@ impl OpaqueNode {
     /// Returns the address of this node, for debugging purposes.
     #[inline]
     pub fn id(&self) -> usize {
         self.0
     }
 }
 
 pub trait TRestyleDamage : BitOr<Output=Self> + Copy {
-    fn compute(old: Option<&Arc<ComputedValues>>, new: &ComputedValues) -> Self;
+    /// The source for our current computed values in the cascade. This is a
+    /// ComputedValues in Servo and a StyleContext in Gecko.
+    ///
+    /// This is needed because Gecko has a few optimisations for the calculation
+    /// of the difference depending on which values have been used during
+    /// layout.
+    ///
+    /// This should be obtained via TNode::existing_style_for_restyle_damage
+    type PreExistingComputedValues;
+
+    fn compute(old: Option<&Self::PreExistingComputedValues>,
+               new: &Arc<ComputedValues>) -> Self;
+
     fn rebuild_and_reflow() -> Self;
 }
 
 pub trait TNode : Sized + Copy + Clone {
     type ConcreteElement: TElement<ConcreteNode = Self, ConcreteDocument = Self::ConcreteDocument>;
     type ConcreteDocument: TDocument<ConcreteNode = Self, ConcreteElement = Self::ConcreteElement>;
     type ConcreteRestyleDamage: TRestyleDamage;
 
@@ -154,16 +166,23 @@ pub trait TNode : Sized + Copy + Clone {
         where <Self::ConcreteElement as Element>::Impl: SelectorImplExt {
         Ref::map(self.borrow_data().unwrap(), |data| data.style.as_ref().unwrap())
     }
 
     /// Removes the style from this node.
     fn unstyle(self) {
         self.mutate_data().unwrap().style = None;
     }
+
+    /// XXX: It's a bit unfortunate we need to pass the current computed values
+    /// as an argument here, but otherwise Servo would crash due to double
+    /// borrows to return it.
+    fn existing_style_for_restyle_damage<'a>(&'a self,
+                                             current_computed_values: Option<&'a Arc<ComputedValues>>)
+        -> Option<&'a <Self::ConcreteRestyleDamage as TRestyleDamage>::PreExistingComputedValues>;
 }
 
 pub trait TDocument : Sized + Copy + Clone {
     type ConcreteNode: TNode<ConcreteElement = Self::ConcreteElement, ConcreteDocument = Self>;
     type ConcreteElement: TElement<ConcreteNode = Self::ConcreteNode, ConcreteDocument = Self>;
 
     fn as_node(&self) -> Self::ConcreteNode;
 
--- a/servo/components/style/gecko_glue.rs
+++ b/servo/components/style/gecko_glue.rs
@@ -8,17 +8,16 @@ use std::marker::PhantomData;
 use std::mem::{forget, transmute};
 use std::sync::Arc;
 
 pub struct ArcHelpers<GeckoType, ServoType> {
     phantom1: PhantomData<GeckoType>,
     phantom2: PhantomData<ServoType>,
 }
 
-
 impl<GeckoType, ServoType> ArcHelpers<GeckoType, ServoType> {
     pub fn with<F, Output>(raw: *mut GeckoType, cb: F) -> Output
                            where F: FnOnce(&Arc<ServoType>) -> Output {
         debug_assert!(!raw.is_null());
 
         let owned = unsafe { Self::into(raw) };
         let result = cb(&owned);
         forget(owned);
@@ -42,16 +41,25 @@ impl<GeckoType, ServoType> ArcHelpers<Ge
     pub unsafe fn into(ptr: *mut GeckoType) -> Arc<ServoType> {
         transmute(ptr)
     }
 
     pub fn from(owned: Arc<ServoType>) -> *mut GeckoType {
         unsafe { transmute(owned) }
     }
 
+    pub fn borrow<F, Output>(borrowed: &Arc<ServoType>, cb: F) -> Output
+        where F: FnOnce(&mut GeckoType) -> Output
+    {
+        let borrowed_gecko_type: *const &mut GeckoType =
+            unsafe { transmute(borrowed) };
+
+        unsafe { cb(*borrowed_gecko_type) }
+    }
+
     pub unsafe fn addref(ptr: *mut GeckoType) {
         Self::with(ptr, |arc| forget(arc.clone()));
     }
 
     pub unsafe fn release(ptr: *mut GeckoType) {
         let _ = Self::into(ptr);
     }
 }
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -1,17 +1,17 @@
 /* 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/. */
 
 //! High-level interface to CSS selector matching.
 
 #![allow(unsafe_code)]
 
-use animation::{self, Animation};
+use animation;
 use arc_ptr_eq;
 use cache::{LRUCache, SimpleHashCache};
 use context::{StyleContext, SharedStyleContext};
 use data::PrivateStyleData;
 use dom::{TElement, TNode, TRestyleDamage};
 use properties::{ComputedValues, PropertyDeclaration, cascade};
 use selector_impl::{ElementExt, SelectorImplExt, TheSelectorImpl, PseudoElement};
 use selector_matching::{DeclarationBlock, Stylist};
@@ -437,18 +437,23 @@ trait PrivateMatchMethods: TNode
                         &**style,
                         &mut this_style,
                         &shared_context.timer);
             }
 
             cacheable = cacheable && !animations_started
         }
 
+
+        let existing_style =
+            self.existing_style_for_restyle_damage(style.map(|s| &*s));
+
         // Calculate style difference.
-        let damage = Self::ConcreteRestyleDamage::compute(style.map(|s| &*s), &*this_style);
+        let damage =
+            Self::ConcreteRestyleDamage::compute(existing_style, &this_style);
 
         // Cache the resolved style if it was cacheable.
         if cacheable {
             applicable_declarations_cache.insert(applicable_declarations.to_vec(),
                                                  this_style.clone());
         }
 
         // Return the final style and the damage done to our caller.
@@ -485,18 +490,19 @@ trait PrivateMatchMethods: TNode
                 //
                 // Thus, we can't assume all the animations have been already
                 // updated by layout, because other restyle due to script might
                 // be triggered by layout before the animation tick.
                 //
                 // See #12171 and the associated PR for an example where this
                 // happened while debugging other release panic.
                 if !running_animation.is_expired() {
-                    animation::update_style_for_animation::<Self::ConcreteRestyleDamage>(
-                        context, running_animation, style, None);
+                    animation::update_style_for_animation(context,
+                                                          running_animation,
+                                                          style);
                     running_animation.mark_as_expired();
                 }
             }
         }
 
         had_animations_to_expire || had_running_animations
     }
 }
@@ -580,19 +586,27 @@ pub trait ElementMatchMethods : TElement
         if self.has_attr(&ns!(), &atom!("id")) {
             return StyleSharingResult::CannotShare
         }
 
         for (i, &(ref candidate, ())) in style_sharing_candidate_cache.iter().enumerate() {
             if let Some(shared_style) = self.share_style_with_candidate_if_possible(parent.clone(), candidate) {
                 // Yay, cache hit. Share the style.
                 let node = self.as_node();
+
                 let style = &mut node.mutate_data().unwrap().style;
-                let damage = <<Self as TElement>::ConcreteNode as TNode>
-                                 ::ConcreteRestyleDamage::compute((*style).as_ref(), &*shared_style);
+
+                let damage = {
+                    let source =
+                        node.existing_style_for_restyle_damage((*style).as_ref());
+                    let damage = <<Self as TElement>::ConcreteNode as TNode>
+                                     ::ConcreteRestyleDamage::compute(source, &shared_style);
+                    damage
+                };
+
                 *style = Some(shared_style);
                 return StyleSharingResult::StyleWasShared(i, damage)
             }
         }
 
         StyleSharingResult::CannotShare
     }
 }
@@ -670,18 +684,24 @@ pub trait MatchMethods : TNode {
         let mut applicable_declarations_cache =
             context.local_context().applicable_declarations_cache.borrow_mut();
 
         let damage;
         if self.is_text_node() {
             let mut data_ref = self.mutate_data().unwrap();
             let mut data = &mut *data_ref;
             let cloned_parent_style = ComputedValues::style_for_child_text_node(parent_style.unwrap());
-            damage = Self::ConcreteRestyleDamage::compute(data.style.as_ref(),
-                                                          &*cloned_parent_style);
+
+            {
+                let existing_style =
+                    self.existing_style_for_restyle_damage(data.style.as_ref());
+                damage = Self::ConcreteRestyleDamage::compute(existing_style,
+                                                              &cloned_parent_style);
+            }
+
             data.style = Some(cloned_parent_style);
         } else {
             damage = {
                 let mut data_ref = self.mutate_data().unwrap();
                 let mut data = &mut *data_ref;
                 let (mut damage, final_style) = self.cascade_node_pseudo_element(
                     context,
                     parent_style,
@@ -692,17 +712,16 @@ pub trait MatchMethods : TNode {
                     true);
 
                 data.style = Some(final_style);
 
                 <Self::ConcreteElement as Element>::Impl::each_eagerly_cascaded_pseudo_element(|pseudo| {
                     let applicable_declarations_for_this_pseudo =
                         applicable_declarations.per_pseudo.get(&pseudo).unwrap();
 
-
                     if !applicable_declarations_for_this_pseudo.is_empty() {
                         // NB: Transitions and animations should only work for
                         // pseudo-elements ::before and ::after
                         let should_animate_properties =
                             <Self::ConcreteElement as Element>::Impl::pseudo_is_before_or_after(&pseudo);
                         let (new_damage, style) = self.cascade_node_pseudo_element(
                             context,
                             Some(data.style.as_ref().unwrap()),
--- a/servo/components/style/restyle_hints.rs
+++ b/servo/components/style/restyle_hints.rs
@@ -23,17 +23,17 @@ bitflags! {
     pub flags RestyleHint: u8 {
         #[doc = "Rerun selector matching on the element."]
         const RESTYLE_SELF = 0x01,
         #[doc = "Rerun selector matching on all of the element's descendants."]
         // NB: In Gecko, we have RESTYLE_SUBTREE which is inclusive of self, but heycam isn't aware
         // of a good reason for that.
         const RESTYLE_DESCENDANTS = 0x02,
         #[doc = "Rerun selector matching on all later siblings of the element and all of their descendants."]
-        const RESTYLE_LATER_SIBLINGS = 0x04,
+        const RESTYLE_LATER_SIBLINGS = 0x08,
     }
 }
 
 /// In order to compute restyle hints, we perform a selector match against a
 /// list of partial selectors whose rightmost simple selector may be sensitive
 /// to the thing being changed. We do this matching twice, once for the element
 /// as it exists now and once for the element as it existed at the time of the
 /// last restyle. If the results of the selector match differ, that means that
--- a/servo/components/style/sequential.rs
+++ b/servo/components/style/sequential.rs
@@ -16,17 +16,17 @@ pub fn traverse_dom<N, C>(root: N,
         where N: TNode,
               C: DomTraversalContext<N>
     {
         debug_assert!(context.should_process(node));
         context.process_preorder(node);
 
         for kid in node.children() {
             context.pre_process_child_hook(node, kid);
-            if context.should_process(node) {
+            if context.should_process(kid) {
                 doit::<N, C>(context, kid);
             }
         }
 
         context.process_postorder(node);
     }
 
     let context = C::new(shared, root.opaque());
--- a/servo/components/style/traversal.rs
+++ b/servo/components/style/traversal.rs
@@ -7,17 +7,16 @@
 use animation;
 use context::{SharedStyleContext, StyleContext};
 use dom::{OpaqueNode, TElement, TNode, TRestyleDamage, UnsafeNode};
 use matching::{ApplicableDeclarations, ElementMatchMethods, MatchMethods, StyleSharingResult};
 use selector_impl::SelectorImplExt;
 use selectors::Element;
 use selectors::bloom::BloomFilter;
 use std::cell::RefCell;
-use std::sync::Arc;
 use tid::tid;
 use util::opts;
 use values::HasViewportPercentage;
 
 /// Every time we do another layout, the old bloom filters are invalid. This is
 /// detected by ticking a generation number every layout.
 pub type Generation = u32;
 
--- a/servo/ports/geckolib/gecko_bindings/bindings.rs
+++ b/servo/ports/geckolib/gecko_bindings/bindings.rs
@@ -139,16 +139,20 @@ use structs::nsChangeHint;
 use structs::SheetParsingMode;
 use structs::nsMainThreadPtrHandle;
 use structs::nsMainThreadPtrHolder;
 use structs::nscolor;
 use structs::nsFont;
 use structs::FontFamilyList;
 use structs::FontFamilyType;
 use structs::nsIAtom;
+use structs::nsStyleContext;
+unsafe impl Send for nsStyleContext {}
+unsafe impl Sync for nsStyleContext {}
+impl HeapSizeOf for nsStyleContext { fn heap_size_of_children(&self) -> usize { 0 } }
 
 pub type RawGeckoNode = nsINode;
 pub enum Element { }
 pub type RawGeckoElement = Element;
 pub type RawGeckoDocument = nsIDocument;
 pub enum ServoNodeData { }
 pub enum ServoComputedValues { }
 pub enum RawServoStyleSheet { }
@@ -289,20 +293,23 @@ extern "C" {
                                base_uri: *mut ThreadSafeURIHolder,
                                referrer: *mut ThreadSafeURIHolder,
                                principal: *mut ThreadSafePrincipalHolder);
     pub fn Gecko_CopyMozBindingFrom(des: *mut nsStyleDisplay,
                                     src: *const nsStyleDisplay);
     pub fn Gecko_GetNodeFlags(node: *mut RawGeckoNode) -> u32;
     pub fn Gecko_SetNodeFlags(node: *mut RawGeckoNode, flags: u32);
     pub fn Gecko_UnsetNodeFlags(node: *mut RawGeckoNode, flags: u32);
-    pub fn Gecko_CalcAndStoreStyleDifference(element: *mut RawGeckoElement,
-                                             newstyle:
-                                                 *mut ServoComputedValues)
+    pub fn Gecko_GetStyleContext(node: *mut RawGeckoNode)
+     -> *mut nsStyleContext;
+    pub fn Gecko_CalcStyleDifference(oldstyle: *mut nsStyleContext,
+                                     newstyle: *mut ServoComputedValues)
      -> nsChangeHint;
+    pub fn Gecko_StoreStyleDifference(node: *mut RawGeckoNode,
+                                      change: nsChangeHint);
     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);
--- a/servo/ports/geckolib/gecko_bindings/structs_debug.rs
+++ b/servo/ports/geckolib/gecko_bindings/structs_debug.rs
@@ -183,16 +183,22 @@ pub const NS_ERROR_MODULE_DOM_ANIM: ::st
 pub const NS_ERROR_MODULE_DOM_PUSH: ::std::os::raw::c_uint = 40;
 pub const NS_ERROR_MODULE_GENERAL: ::std::os::raw::c_uint = 51;
 pub const NS_ERROR_SEVERITY_SUCCESS: ::std::os::raw::c_uint = 0;
 pub const NS_ERROR_SEVERITY_ERROR: ::std::os::raw::c_uint = 1;
 pub const NS_ERROR_MODULE_BASE_OFFSET: ::std::os::raw::c_uint = 69;
 pub const MOZ_STRING_WITH_OBSOLETE_API: ::std::os::raw::c_uint = 1;
 pub const NSID_LENGTH: ::std::os::raw::c_uint = 39;
 pub const NS_NUMBER_OF_FLAGS_IN_REFCNT: ::std::os::raw::c_uint = 2;
+pub const _STL_PAIR_H: ::std::os::raw::c_uint = 1;
+pub const _GLIBCXX_UTILITY: ::std::os::raw::c_uint = 1;
+pub const __cpp_lib_tuple_element_t: ::std::os::raw::c_uint = 201402;
+pub const __cpp_lib_tuples_by_type: ::std::os::raw::c_uint = 201304;
+pub const __cpp_lib_exchange_function: ::std::os::raw::c_uint = 201304;
+pub const __cpp_lib_integer_sequence: ::std::os::raw::c_uint = 201304;
 pub const NS_EVENT_STATE_HIGHEST_SERVO_BIT: ::std::os::raw::c_uint = 6;
 pub const DOM_USER_DATA: ::std::os::raw::c_uint = 1;
 pub const SMIL_MAPPED_ATTR_ANIMVAL: ::std::os::raw::c_uint = 2;
 pub const TWIPS_PER_POINT_INT: ::std::os::raw::c_uint = 20;
 pub const POINTS_PER_INCH_INT: ::std::os::raw::c_uint = 72;
 pub const NS_ATTRNAME_NODEINFO_BIT: ::std::os::raw::c_uint = 1;
 pub const NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM: ::std::os::raw::c_uint = 12;
 pub const NS_ATTRVALUE_INTEGERTYPE_BITS: ::std::os::raw::c_uint = 4;
@@ -1479,16 +1485,63 @@ pub enum nsresult {
     NS_ERROR_DOCUMENT_IS_PRINTMODE = -2139617327,
     NS_SUCCESS_DONT_FIXUP = 7864321,
     NS_SUCCESS_RESTART_APP_NOT_SAME_PROFILE = 7864323,
     NS_SUCCESS_UNORM_NOTFOUND = 7864337,
     NS_ERROR_NOT_IN_TREE = -2139619290,
     NS_OK_NO_NAME_CLAUSE_HANDLED = 7864354,
 }
 pub type nsrefcnt = MozRefCountType;
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct HasPointerTypeHelper;
+impl ::std::clone::Clone for HasPointerTypeHelper {
+    fn clone(&self) -> Self { *self }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct PointerType<T, D> {
+    pub _phantom0: ::std::marker::PhantomData<T>,
+    pub _phantom1: ::std::marker::PhantomData<D>,
+}
+/**
+ * <div rustbindgen="true" replaces="UniquePtr">
+ *
+ * TODO(Emilio): This is a workaround and we should be able to get rid of this
+ * one.
+ */
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct UniquePtr<T, Deleter> {
+    pub mPtr: *mut T,
+    pub _phantom0: ::std::marker::PhantomData<Deleter>,
+}
+/**
+ * A default deletion policy using plain old operator delete.
+ *
+ * Note that this type can be specialized, but authors should beware of the risk
+ * that the specialization may at some point cease to match (either because it
+ * gets moved to a different compilation unit or the signature changes). If the
+ * non-specialized (|delete|-based) version compiles for that type but does the
+ * wrong thing, bad things could happen.
+ *
+ * This is a non-issue for types which are always incomplete (i.e. opaque handle
+ * types), since |delete|-ing such a type will always trigger a compilation
+ * error.
+ */
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct DefaultDelete<T> {
+    pub _phantom0: ::std::marker::PhantomData<T>,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct UniqueSelector<T> {
+    pub _phantom0: ::std::marker::PhantomData<T>,
+}
 /**
  * typedefs for backwards compatibility
  */
 pub type nsSubstring = nsAString_internal;
 pub type nsCSubstring = nsACString_internal;
 pub type nsAFlatString = nsString;
 pub type nsASingleFragmentString = nsSubstring;
 pub type nsAFlatCString = nsCString;
@@ -2698,16 +2751,22 @@ pub struct nsIExpandedPrincipal {
 #[repr(C)]
 pub struct _vftable_nsIExpandedPrincipal {
     pub _base: _vftable_nsISupports,
 }
 impl ::std::clone::Clone for nsIExpandedPrincipal {
     fn clone(&self) -> Self { *self }
 }
 #[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct _Make_integer_sequence<_Tp, _ISeq> {
+    pub _phantom0: ::std::marker::PhantomData<_Tp>,
+    pub _phantom1: ::std::marker::PhantomData<_ISeq>,
+}
+#[repr(C)]
 #[derive(Debug, Copy)]
 pub struct nsIURI {
     pub _base: nsISupports,
 }
 #[repr(C)]
 pub struct _vftable_nsIURI {
     pub _base: _vftable_nsISupports,
 }
@@ -2749,17 +2808,17 @@ impl ::std::clone::Clone for nsIRequest 
  * instances. These states are calculated by IntrinsicState() and
  * ContentStatesChanged() has to be called when one of them changes thus
  * informing the layout/style engine of the change.
  * Event states are associated with pseudo-classes.
  */
 #[repr(C)]
 #[derive(Debug, Copy)]
 pub struct EventStates {
-    pub mStates: ::std::os::raw::c_ulonglong,
+    pub mStates: ::std::os::raw::c_ulong,
 }
 impl ::std::clone::Clone for EventStates {
     fn clone(&self) -> Self { *self }
 }
 #[test]
 fn bindgen_test_layout_EventStates() {
     assert_eq!(::std::mem::size_of::<EventStates>() , 8usize);
     assert_eq!(::std::mem::align_of::<EventStates>() , 8usize);
@@ -2813,21 +2872,16 @@ pub enum nsIDOMElement { }
 pub enum nsIDOMNodeList { }
 pub enum nsIEditor { }
 pub enum nsIFrame { }
 pub enum nsINodeList { }
 pub enum nsNodeSupportsWeakRefTearoff { }
 pub enum nsNodeWeakReference { }
 pub enum nsDOMMutationObserver { }
 pub enum ServoNodeData { }
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct DefaultDelete<> {
-    pub _phantom0: ::std::marker::PhantomData<ServoNodeData>,
-}
 pub enum EventListenerManager { }
 pub enum BoxQuadOptions { }
 pub enum ConvertCoordinateOptions { }
 pub enum DOMPoint { }
 pub enum DOMQuad { }
 pub enum DOMRectReadOnly { }
 pub enum Element { }
 pub enum Text { }
@@ -2884,17 +2938,17 @@ impl ::std::clone::Clone for nsMutationG
 #[test]
 fn bindgen_test_layout_nsMutationGuard() {
     assert_eq!(::std::mem::size_of::<nsMutationGuard>() , 8usize);
     assert_eq!(::std::mem::align_of::<nsMutationGuard>() , 8usize);
 }
 extern "C" {
     #[link_name = "_ZN15nsMutationGuard11sGenerationE"]
     pub static mut nsMutationGuard_consts_sGeneration:
-               ::std::os::raw::c_ulonglong;
+               ::std::os::raw::c_ulong;
 }
 pub type Float = f32;
 #[repr(i8)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub enum SurfaceType {
     DATA = 0,
     D2D1_BITMAP = 1,
     D2D1_DRAWTARGET = 2,
@@ -3275,17 +3329,17 @@ pub struct nsAttrName {
 fn bindgen_test_layout_nsAttrName() {
     assert_eq!(::std::mem::size_of::<nsAttrName>() , 8usize);
     assert_eq!(::std::mem::align_of::<nsAttrName>() , 8usize);
 }
 pub type nscolor = u32;
 #[repr(i8)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub enum nsHexColorType { NoAlpha = 0, AllowAlpha = 1, }
-pub enum nsStyledElementNotElementCSSInlineStyle { }
+pub enum nsStyledElement { }
 pub enum MiscContainer { }
 pub enum ServoDeclarationBlock { }
 pub enum Declaration { }
 /**
  * A class used to construct a nsString from a nsStringBuffer (we might
  * want to move this to nsString at some point).
  *
  * WARNING: Note that nsCheapString doesn't take an explicit length -- it
@@ -3486,38 +3540,34 @@ fn bindgen_test_layout_ServoAttrSnapshot
     assert_eq!(::std::mem::align_of::<ServoAttrSnapshot>() , 8usize);
 }
 /**
  * A bitflags enum class used to determine what data does a ServoElementSnapshot
  * contains.
  */
 #[repr(i8)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum ServoElementSnapshotFlags {
-    State = 1,
-    Attributes = 2,
-    HTMLElementInHTMLDocument = 4,
-    All = 7,
-}
+pub enum ServoElementSnapshotFlags { State = 1, Attributes = 2, All = 3, }
 /**
  * This class holds all non-tree-structural state of an element that might be
  * used for selector matching eventually.
  *
  * This means the attributes, and the element state, such as :hover, :active,
  * etc...
  */
 #[repr(C)]
 #[derive(Debug)]
 pub struct ServoElementSnapshot {
     pub mContains: ServoElementSnapshotFlags,
     pub mAttrs: nsTArray<ServoAttrSnapshot>,
     pub mState: ::std::os::raw::c_uchar,
     pub mExplicitRestyleHint: nsRestyleHint,
     pub mExplicitChangeHint: nsChangeHint,
     pub mIsHTMLElementInHTMLDocument: bool,
+    pub mIsInChromeDocument: bool,
 }
 #[test]
 fn bindgen_test_layout_ServoElementSnapshot() {
     assert_eq!(::std::mem::size_of::<ServoElementSnapshot>() , 32usize);
     assert_eq!(::std::mem::align_of::<ServoElementSnapshot>() , 8usize);
 }
 pub enum ErrorReporter { }
 #[repr(u32)]
@@ -5357,32 +5407,43 @@ fn bindgen_test_layout_nsStyleGradient()
 #[repr(u32)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub enum nsStyleImageType {
     eStyleImageType_Null = 0,
     eStyleImageType_Image = 1,
     eStyleImageType_Gradient = 2,
     eStyleImageType_Element = 3,
 }
+#[repr(C)]
+pub struct CachedBorderImageData {
+    pub mCachedSVGViewportSize: [u64; 2usize],
+    pub mSubImages: u64,
+}
+#[test]
+fn bindgen_test_layout_CachedBorderImageData() {
+    assert_eq!(::std::mem::size_of::<CachedBorderImageData>() , 24usize);
+    assert_eq!(::std::mem::align_of::<CachedBorderImageData>() , 8usize);
+}
 /**
  * Represents a paintable image of one of the following types.
  * (1) A real image loaded from an external source.
  * (2) A CSS linear or radial gradient.
  * (3) An element within a document, or an <img>, <video>, or <canvas> element
  *     not in a document.
  * (*) Optionally a crop rect can be set to paint a partial (rectangular)
  * region of an image. (Currently, this feature is only supported with an
  * image of type (1)).
  */
 #[repr(C)]
 pub struct nsStyleImage {
-    pub mSubImages: u64,
+    pub mCachedBIData: UniquePtr<CachedBorderImageData,
+                                 DefaultDelete<CachedBorderImageData>>,
     pub mType: nsStyleImageType,
     pub nsStyleImage_nsStyleStruct_h_unnamed_21: nsStyleImage_nsStyleStruct_h_unnamed_21,
-    pub mCropRect: nsAutoPtr<nsStyleSides>,
+    pub mCropRect: UniquePtr<nsStyleSides, DefaultDelete<nsStyleSides>>,
     pub mImageTracked: bool,
 }
 #[repr(C)]
 #[derive(Debug, Copy)]
 pub struct nsStyleImage_nsStyleStruct_h_unnamed_21 {
     pub mImage: __BindgenUnionField<*mut imgRequestProxy>,
     pub mGradient: __BindgenUnionField<*mut nsStyleGradient>,
     pub mElementId: __BindgenUnionField<*mut ::std::os::raw::c_ushort>,
@@ -6256,16 +6317,27 @@ pub struct nsStyleColumn {
 fn bindgen_test_layout_nsStyleColumn() {
     assert_eq!(::std::mem::size_of::<nsStyleColumn>() , 56usize);
     assert_eq!(::std::mem::align_of::<nsStyleColumn>() , 8usize);
 }
 extern "C" {
     #[link_name = "_ZN13nsStyleColumn15kMaxColumnCountE"]
     pub static nsStyleColumn_consts_kMaxColumnCount: ::std::os::raw::c_uint;
 }
+#[repr(C)]
+#[derive(Debug)]
+pub struct FragmentOrURL {
+    pub mURL: nsCOMPtr<nsIURI>,
+    pub mIsLocalRef: bool,
+}
+#[test]
+fn bindgen_test_layout_FragmentOrURL() {
+    assert_eq!(::std::mem::size_of::<FragmentOrURL>() , 16usize);
+    assert_eq!(::std::mem::align_of::<FragmentOrURL>() , 8usize);
+}
 #[repr(u32)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub enum nsStyleSVGPaintType {
     eStyleSVGPaintType_None = 1,
     eStyleSVGPaintType_Color = 2,
     eStyleSVGPaintType_Server = 3,
     eStyleSVGPaintType_ContextFill = 4,
     eStyleSVGPaintType_ContextStroke = 5,
@@ -6283,17 +6355,17 @@ pub struct nsStyleSVGPaint {
     pub mPaint: nsStyleSVGPaint_nsStyleStruct_h_unnamed_27,
     pub mType: nsStyleSVGPaintType,
     pub mFallbackColor: nscolor,
 }
 #[repr(C)]
 #[derive(Debug, Copy)]
 pub struct nsStyleSVGPaint_nsStyleStruct_h_unnamed_27 {
     pub mColor: __BindgenUnionField<nscolor>,
-    pub mPaintServer: __BindgenUnionField<*mut nsIURI>,
+    pub mPaintServer: __BindgenUnionField<*mut FragmentOrURL>,
     pub _bindgen_data_: u64,
 }
 impl nsStyleSVGPaint_nsStyleStruct_h_unnamed_27 { }
 impl ::std::clone::Clone for nsStyleSVGPaint_nsStyleStruct_h_unnamed_27 {
     fn clone(&self) -> Self { *self }
 }
 #[test]
 fn bindgen_test_layout_nsStyleSVGPaint_nsStyleStruct_h_unnamed_27() {
@@ -6307,19 +6379,19 @@ fn bindgen_test_layout_nsStyleSVGPaint()
     assert_eq!(::std::mem::size_of::<nsStyleSVGPaint>() , 16usize);
     assert_eq!(::std::mem::align_of::<nsStyleSVGPaint>() , 8usize);
 }
 #[repr(C)]
 #[derive(Debug)]
 pub struct nsStyleSVG {
     pub mFill: nsStyleSVGPaint,
     pub mStroke: nsStyleSVGPaint,
-    pub mMarkerEnd: nsCOMPtr<nsIURI>,
-    pub mMarkerMid: nsCOMPtr<nsIURI>,
-    pub mMarkerStart: nsCOMPtr<nsIURI>,
+    pub mMarkerEnd: FragmentOrURL,
+    pub mMarkerMid: FragmentOrURL,
+    pub mMarkerStart: FragmentOrURL,
     pub mStrokeDasharray: nsTArray<nsStyleCoord>,
     pub mStrokeDashoffset: nsStyleCoord,
     pub mStrokeWidth: nsStyleCoord,
     pub mFillOpacity: f32,
     pub mStrokeMiterlimit: f32,
     pub mStrokeOpacity: f32,
     pub mClipRule: u8,
     pub mColorInterpolation: u8,
@@ -6340,17 +6412,17 @@ pub enum nsStyleSVG_nsStyleStruct_h_unna
     STROKE_DASHARRAY_CONTEXT = 16,
     STROKE_DASHOFFSET_CONTEXT = 32,
     STROKE_WIDTH_CONTEXT = 64,
     FILL_OPACITY_SOURCE_SHIFT = 0,
     STROKE_OPACITY_SOURCE_SHIFT = 2,
 }
 #[test]
 fn bindgen_test_layout_nsStyleSVG() {
-    assert_eq!(::std::mem::size_of::<nsStyleSVG>() , 120usize);
+    assert_eq!(::std::mem::size_of::<nsStyleSVG>() , 144usize);
     assert_eq!(::std::mem::align_of::<nsStyleSVG>() , 8usize);
 }
 #[repr(C)]
 #[derive(Debug)]
 pub struct nsStyleBasicShape {
     pub mRefCnt: nsAutoRefCnt,
     pub _mOwningThread: nsAutoOwningThread,
     pub mType: nsStyleBasicShape_Type,
@@ -6378,17 +6450,17 @@ pub struct nsStyleClipPath {
     pub nsStyleClipPath_nsStyleStruct_h_unnamed_29: nsStyleClipPath_nsStyleStruct_h_unnamed_29,
     pub mType: StyleClipPathType,
     pub mSizingBox: StyleClipShapeSizing,
 }
 #[repr(C)]
 #[derive(Debug, Copy)]
 pub struct nsStyleClipPath_nsStyleStruct_h_unnamed_29 {
     pub mBasicShape: __BindgenUnionField<*mut nsStyleBasicShape>,
-    pub mURL: __BindgenUnionField<*mut nsIURI>,
+    pub mURL: __BindgenUnionField<*mut FragmentOrURL>,
     pub _bindgen_data_: u64,
 }
 impl nsStyleClipPath_nsStyleStruct_h_unnamed_29 { }
 impl ::std::clone::Clone for nsStyleClipPath_nsStyleStruct_h_unnamed_29 {
     fn clone(&self) -> Self { *self }
 }
 #[test]
 fn bindgen_test_layout_nsStyleClipPath_nsStyleStruct_h_unnamed_29() {
@@ -6407,17 +6479,17 @@ fn bindgen_test_layout_nsStyleClipPath()
 pub struct nsStyleFilter {
     pub mType: i32,
     pub mFilterParameter: nsStyleCoord,
     pub nsStyleFilter_nsStyleStruct_h_unnamed_30: nsStyleFilter_nsStyleStruct_h_unnamed_30,
 }
 #[repr(C)]
 #[derive(Debug, Copy)]
 pub struct nsStyleFilter_nsStyleStruct_h_unnamed_30 {
-    pub mURL: __BindgenUnionField<*mut nsIURI>,
+    pub mURL: __BindgenUnionField<*mut FragmentOrURL>,
     pub mDropShadow: __BindgenUnionField<*mut nsCSSShadowArray>,
     pub _bindgen_data_: u64,
 }
 impl nsStyleFilter_nsStyleStruct_h_unnamed_30 { }
 impl ::std::clone::Clone for nsStyleFilter_nsStyleStruct_h_unnamed_30 {
     fn clone(&self) -> Self { *self }
 }
 #[test]
@@ -6469,8 +6541,25 @@ pub struct nsStyleEffects {
     pub mClipFlags: u8,
     pub mMixBlendMode: u8,
 }
 #[test]
 fn bindgen_test_layout_nsStyleEffects() {
     assert_eq!(::std::mem::size_of::<nsStyleEffects>() , 40usize);
     assert_eq!(::std::mem::align_of::<nsStyleEffects>() , 8usize);
 }
+/**
+ * <div rustbindgen="true" replaces="nsSize">
+ */
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct nsSize {
+    pub width: nscoord,
+    pub height: nscoord,
+}
+impl ::std::clone::Clone for nsSize {
+    fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_nsSize() {
+    assert_eq!(::std::mem::size_of::<nsSize>() , 8usize);
+    assert_eq!(::std::mem::align_of::<nsSize>() , 4usize);
+}
--- a/servo/ports/geckolib/gecko_bindings/structs_release.rs
+++ b/servo/ports/geckolib/gecko_bindings/structs_release.rs
@@ -183,16 +183,22 @@ pub const NS_ERROR_MODULE_DOM_ANIM: ::st
 pub const NS_ERROR_MODULE_DOM_PUSH: ::std::os::raw::c_uint = 40;
 pub const NS_ERROR_MODULE_GENERAL: ::std::os::raw::c_uint = 51;
 pub const NS_ERROR_SEVERITY_SUCCESS: ::std::os::raw::c_uint = 0;
 pub const NS_ERROR_SEVERITY_ERROR: ::std::os::raw::c_uint = 1;
 pub const NS_ERROR_MODULE_BASE_OFFSET: ::std::os::raw::c_uint = 69;
 pub const MOZ_STRING_WITH_OBSOLETE_API: ::std::os::raw::c_uint = 1;
 pub const NSID_LENGTH: ::std::os::raw::c_uint = 39;
 pub const NS_NUMBER_OF_FLAGS_IN_REFCNT: ::std::os::raw::c_uint = 2;
+pub const _STL_PAIR_H: ::std::os::raw::c_uint = 1;
+pub const _GLIBCXX_UTILITY: ::std::os::raw::c_uint = 1;
+pub const __cpp_lib_tuple_element_t: ::std::os::raw::c_uint = 201402;
+pub const __cpp_lib_tuples_by_type: ::std::os::raw::c_uint = 201304;
+pub const __cpp_lib_exchange_function: ::std::os::raw::c_uint = 201304;
+pub const __cpp_lib_integer_sequence: ::std::os::raw::c_uint = 201304;
 pub const NS_EVENT_STATE_HIGHEST_SERVO_BIT: ::std::os::raw::c_uint = 6;
 pub const DOM_USER_DATA: ::std::os::raw::c_uint = 1;
 pub const SMIL_MAPPED_ATTR_ANIMVAL: ::std::os::raw::c_uint = 2;
 pub const TWIPS_PER_POINT_INT: ::std::os::raw::c_uint = 20;
 pub const POINTS_PER_INCH_INT: ::std::os::raw::c_uint = 72;
 pub const NS_ATTRNAME_NODEINFO_BIT: ::std::os::raw::c_uint = 1;
 pub const NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM: ::std::os::raw::c_uint = 12;
 pub const NS_ATTRVALUE_INTEGERTYPE_BITS: ::std::os::raw::c_uint = 4;
@@ -1479,16 +1485,63 @@ pub enum nsresult {
     NS_ERROR_DOCUMENT_IS_PRINTMODE = -2139617327,
     NS_SUCCESS_DONT_FIXUP = 7864321,
     NS_SUCCESS_RESTART_APP_NOT_SAME_PROFILE = 7864323,
     NS_SUCCESS_UNORM_NOTFOUND = 7864337,
     NS_ERROR_NOT_IN_TREE = -2139619290,
     NS_OK_NO_NAME_CLAUSE_HANDLED = 7864354,
 }
 pub type nsrefcnt = MozRefCountType;
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct HasPointerTypeHelper;
+impl ::std::clone::Clone for HasPointerTypeHelper {
+    fn clone(&self) -> Self { *self }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct PointerType<T, D> {
+    pub _phantom0: ::std::marker::PhantomData<T>,
+    pub _phantom1: ::std::marker::PhantomData<D>,
+}
+/**
+ * <div rustbindgen="true" replaces="UniquePtr">
+ *
+ * TODO(Emilio): This is a workaround and we should be able to get rid of this
+ * one.
+ */
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct UniquePtr<T, Deleter> {
+    pub mPtr: *mut T,
+    pub _phantom0: ::std::marker::PhantomData<Deleter>,
+}
+/**
+ * A default deletion policy using plain old operator delete.
+ *
+ * Note that this type can be specialized, but authors should beware of the risk
+ * that the specialization may at some point cease to match (either because it
+ * gets moved to a different compilation unit or the signature changes). If the
+ * non-specialized (|delete|-based) version compiles for that type but does the
+ * wrong thing, bad things could happen.
+ *
+ * This is a non-issue for types which are always incomplete (i.e. opaque handle
+ * types), since |delete|-ing such a type will always trigger a compilation
+ * error.
+ */
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct DefaultDelete<T> {
+    pub _phantom0: ::std::marker::PhantomData<T>,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct UniqueSelector<T> {
+    pub _phantom0: ::std::marker::PhantomData<T>,
+}
 /**
  * typedefs for backwards compatibility
  */
 pub type nsSubstring = nsAString_internal;
 pub type nsCSubstring = nsACString_internal;
 pub type nsAFlatString = nsString;
 pub type nsASingleFragmentString = nsSubstring;
 pub type nsAFlatCString = nsCString;
@@ -2677,16 +2730,22 @@ pub struct nsIExpandedPrincipal {
 #[repr(C)]
 pub struct _vftable_nsIExpandedPrincipal {
     pub _base: _vftable_nsISupports,
 }
 impl ::std::clone::Clone for nsIExpandedPrincipal {
     fn clone(&self) -> Self { *self }
 }
 #[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct _Make_integer_sequence<_Tp, _ISeq> {
+    pub _phantom0: ::std::marker::PhantomData<_Tp>,
+    pub _phantom1: ::std::marker::PhantomData<_ISeq>,
+}
+#[repr(C)]
 #[derive(Debug, Copy)]
 pub struct nsIURI {
     pub _base: nsISupports,
 }
 #[repr(C)]
 pub struct _vftable_nsIURI {
     pub _base: _vftable_nsISupports,
 }
@@ -2728,17 +2787,17 @@ impl ::std::clone::Clone for nsIRequest 
  * instances. These states are calculated by IntrinsicState() and
  * ContentStatesChanged() has to be called when one of them changes thus
  * informing the layout/style engine of the change.
  * Event states are associated with pseudo-classes.
  */
 #[repr(C)]
 #[derive(Debug, Copy)]
 pub struct EventStates {
-    pub mStates: ::std::os::raw::c_ulonglong,
+    pub mStates: ::std::os::raw::c_ulong,
 }
 impl ::std::clone::Clone for EventStates {
     fn clone(&self) -> Self { *self }
 }
 #[test]
 fn bindgen_test_layout_EventStates() {
     assert_eq!(::std::mem::size_of::<EventStates>() , 8usize);
     assert_eq!(::std::mem::align_of::<EventStates>() , 8usize);
@@ -2792,21 +2851,16 @@ pub enum nsIDOMElement { }
 pub enum nsIDOMNodeList { }
 pub enum nsIEditor { }
 pub enum nsIFrame { }
 pub enum nsINodeList { }
 pub enum nsNodeSupportsWeakRefTearoff { }
 pub enum nsNodeWeakReference { }
 pub enum nsDOMMutationObserver { }
 pub enum ServoNodeData { }
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct DefaultDelete<> {
-    pub _phantom0: ::std::marker::PhantomData<ServoNodeData>,
-}
 pub enum EventListenerManager { }
 pub enum BoxQuadOptions { }
 pub enum ConvertCoordinateOptions { }
 pub enum DOMPoint { }
 pub enum DOMQuad { }
 pub enum DOMRectReadOnly { }
 pub enum Element { }
 pub enum Text { }
@@ -2863,17 +2917,17 @@ impl ::std::clone::Clone for nsMutationG
 #[test]
 fn bindgen_test_layout_nsMutationGuard() {
     assert_eq!(::std::mem::size_of::<nsMutationGuard>() , 8usize);
     assert_eq!(::std::mem::align_of::<nsMutationGuard>() , 8usize);
 }
 extern "C" {
     #[link_name = "_ZN15nsMutationGuard11sGenerationE"]
     pub static mut nsMutationGuard_consts_sGeneration:
-               ::std::os::raw::c_ulonglong;
+               ::std::os::raw::c_ulong;
 }
 pub type Float = f32;
 #[repr(i8)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub enum SurfaceType {
     DATA = 0,
     D2D1_BITMAP = 1,
     D2D1_DRAWTARGET = 2,
@@ -3254,17 +3308,17 @@ pub struct nsAttrName {
 fn bindgen_test_layout_nsAttrName() {
     assert_eq!(::std::mem::size_of::<nsAttrName>() , 8usize);
     assert_eq!(::std::mem::align_of::<nsAttrName>() , 8usize);
 }
 pub type nscolor = u32;
 #[repr(i8)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub enum nsHexColorType { NoAlpha = 0, AllowAlpha = 1, }
-pub enum nsStyledElementNotElementCSSInlineStyle { }
+pub enum nsStyledElement { }
 pub enum MiscContainer { }
 pub enum ServoDeclarationBlock { }
 pub enum Declaration { }
 /**
  * A class used to construct a nsString from a nsStringBuffer (we might
  * want to move this to nsString at some point).
  *
  * WARNING: Note that nsCheapString doesn't take an explicit length -- it
@@ -3465,38 +3519,34 @@ fn bindgen_test_layout_ServoAttrSnapshot
     assert_eq!(::std::mem::align_of::<ServoAttrSnapshot>() , 8usize);
 }
 /**
  * A bitflags enum class used to determine what data does a ServoElementSnapshot
  * contains.
  */
 #[repr(i8)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum ServoElementSnapshotFlags {
-    State = 1,
-    Attributes = 2,
-    HTMLElementInHTMLDocument = 4,
-    All = 7,
-}
+pub enum ServoElementSnapshotFlags { State = 1, Attributes = 2, All = 3, }
 /**
  * This class holds all non-tree-structural state of an element that might be
  * used for selector matching eventually.
  *
  * This means the attributes, and the element state, such as :hover, :active,
  * etc...
  */
 #[repr(C)]
 #[derive(Debug)]
 pub struct ServoElementSnapshot {
     pub mContains: ServoElementSnapshotFlags,
     pub mAttrs: nsTArray<ServoAttrSnapshot>,
     pub mState: ::std::os::raw::c_uchar,
     pub mExplicitRestyleHint: nsRestyleHint,
     pub mExplicitChangeHint: nsChangeHint,
     pub mIsHTMLElementInHTMLDocument: bool,
+    pub mIsInChromeDocument: bool,
 }
 #[test]
 fn bindgen_test_layout_ServoElementSnapshot() {
     assert_eq!(::std::mem::size_of::<ServoElementSnapshot>() , 32usize);
     assert_eq!(::std::mem::align_of::<ServoElementSnapshot>() , 8usize);
 }
 pub enum ErrorReporter { }
 #[repr(u32)]
@@ -5336,32 +5386,43 @@ fn bindgen_test_layout_nsStyleGradient()
 #[repr(u32)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub enum nsStyleImageType {
     eStyleImageType_Null = 0,
     eStyleImageType_Image = 1,
     eStyleImageType_Gradient = 2,
     eStyleImageType_Element = 3,
 }
+#[repr(C)]
+pub struct CachedBorderImageData {
+    pub mCachedSVGViewportSize: [u64; 2usize],
+    pub mSubImages: u64,
+}
+#[test]
+fn bindgen_test_layout_CachedBorderImageData() {
+    assert_eq!(::std::mem::size_of::<CachedBorderImageData>() , 24usize);
+    assert_eq!(::std::mem::align_of::<CachedBorderImageData>() , 8usize);
+}
 /**
  * Represents a paintable image of one of the following types.
  * (1) A real image loaded from an external source.
  * (2) A CSS linear or radial gradient.
  * (3) An element within a document, or an <img>, <video>, or <canvas> element
  *     not in a document.
  * (*) Optionally a crop rect can be set to paint a partial (rectangular)
  * region of an image. (Currently, this feature is only supported with an
  * image of type (1)).
  */
 #[repr(C)]
 pub struct nsStyleImage {
-    pub mSubImages: u64,
+    pub mCachedBIData: UniquePtr<CachedBorderImageData,
+                                 DefaultDelete<CachedBorderImageData>>,
     pub mType: nsStyleImageType,
     pub nsStyleImage_nsStyleStruct_h_unnamed_21: nsStyleImage_nsStyleStruct_h_unnamed_21,
-    pub mCropRect: nsAutoPtr<nsStyleSides>,
+    pub mCropRect: UniquePtr<nsStyleSides, DefaultDelete<nsStyleSides>>,
 }
 #[repr(C)]
 #[derive(Debug, Copy)]
 pub struct nsStyleImage_nsStyleStruct_h_unnamed_21 {
     pub mImage: __BindgenUnionField<*mut imgRequestProxy>,
     pub mGradient: __BindgenUnionField<*mut nsStyleGradient>,
     pub mElementId: __BindgenUnionField<*mut ::std::os::raw::c_ushort>,
     pub _bindgen_data_: u64,
@@ -6233,16 +6294,27 @@ pub struct nsStyleColumn {
 fn bindgen_test_layout_nsStyleColumn() {
     assert_eq!(::std::mem::size_of::<nsStyleColumn>() , 56usize);
     assert_eq!(::std::mem::align_of::<nsStyleColumn>() , 8usize);
 }
 extern "C" {
     #[link_name = "_ZN13nsStyleColumn15kMaxColumnCountE"]
     pub static nsStyleColumn_consts_kMaxColumnCount: ::std::os::raw::c_uint;
 }
+#[repr(C)]
+#[derive(Debug)]
+pub struct FragmentOrURL {
+    pub mURL: nsCOMPtr<nsIURI>,
+    pub mIsLocalRef: bool,
+}
+#[test]
+fn bindgen_test_layout_FragmentOrURL() {
+    assert_eq!(::std::mem::size_of::<FragmentOrURL>() , 16usize);
+    assert_eq!(::std::mem::align_of::<FragmentOrURL>() , 8usize);
+}
 #[repr(u32)]
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
 pub enum nsStyleSVGPaintType {
     eStyleSVGPaintType_None = 1,
     eStyleSVGPaintType_Color = 2,
     eStyleSVGPaintType_Server = 3,
     eStyleSVGPaintType_ContextFill = 4,
     eStyleSVGPaintType_ContextStroke = 5,
@@ -6260,17 +6332,17 @@ pub struct nsStyleSVGPaint {
     pub mPaint: nsStyleSVGPaint_nsStyleStruct_h_unnamed_27,
     pub mType: nsStyleSVGPaintType,
     pub mFallbackColor: nscolor,
 }
 #[repr(C)]
 #[derive(Debug, Copy)]
 pub struct nsStyleSVGPaint_nsStyleStruct_h_unnamed_27 {
     pub mColor: __BindgenUnionField<nscolor>,
-    pub mPaintServer: __BindgenUnionField<*mut nsIURI>,
+    pub mPaintServer: __BindgenUnionField<*mut FragmentOrURL>,
     pub _bindgen_data_: u64,
 }
 impl nsStyleSVGPaint_nsStyleStruct_h_unnamed_27 { }
 impl ::std::clone::Clone for nsStyleSVGPaint_nsStyleStruct_h_unnamed_27 {
     fn clone(&self) -> Self { *self }
 }
 #[test]
 fn bindgen_test_layout_nsStyleSVGPaint_nsStyleStruct_h_unnamed_27() {
@@ -6284,19 +6356,19 @@ fn bindgen_test_layout_nsStyleSVGPaint()
     assert_eq!(::std::mem::size_of::<nsStyleSVGPaint>() , 16usize);
     assert_eq!(::std::mem::align_of::<nsStyleSVGPaint>() , 8usize);
 }
 #[repr(C)]
 #[derive(Debug)]
 pub struct nsStyleSVG {
     pub mFill: nsStyleSVGPaint,
     pub mStroke: nsStyleSVGPaint,
-    pub mMarkerEnd: nsCOMPtr<nsIURI>,
-    pub mMarkerMid: nsCOMPtr<nsIURI>,
-    pub mMarkerStart: nsCOMPtr<nsIURI>,
+    pub mMarkerEnd: FragmentOrURL,
+    pub mMarkerMid: FragmentOrURL,
+    pub mMarkerStart: FragmentOrURL,
     pub mStrokeDasharray: nsTArray<nsStyleCoord>,
     pub mStrokeDashoffset: nsStyleCoord,
     pub mStrokeWidth: nsStyleCoord,
     pub mFillOpacity: f32,
     pub mStrokeMiterlimit: f32,
     pub mStrokeOpacity: f32,
     pub mClipRule: u8,
     pub mColorInterpolation: u8,
@@ -6317,17 +6389,17 @@ pub enum nsStyleSVG_nsStyleStruct_h_unna
     STROKE_DASHARRAY_CONTEXT = 16,
     STROKE_DASHOFFSET_CONTEXT = 32,
     STROKE_WIDTH_CONTEXT = 64,
     FILL_OPACITY_SOURCE_SHIFT = 0,
     STROKE_OPACITY_SOURCE_SHIFT = 2,
 }
 #[test]
 fn bindgen_test_layout_nsStyleSVG() {
-    assert_eq!(::std::mem::size_of::<nsStyleSVG>() , 120usize);
+    assert_eq!(::std::mem::size_of::<nsStyleSVG>() , 144usize);
     assert_eq!(::std::mem::align_of::<nsStyleSVG>() , 8usize);
 }
 #[repr(C)]
 #[derive(Debug)]
 pub struct nsStyleBasicShape {
     pub mRefCnt: nsAutoRefCnt,
     pub _mOwningThread: nsAutoOwningThread,
     pub mType: nsStyleBasicShape_Type,
@@ -6355,17 +6427,17 @@ pub struct nsStyleClipPath {
     pub nsStyleClipPath_nsStyleStruct_h_unnamed_29: nsStyleClipPath_nsStyleStruct_h_unnamed_29,
     pub mType: StyleClipPathType,
     pub mSizingBox: StyleClipShapeSizing,
 }
 #[repr(C)]
 #[derive(Debug, Copy)]
 pub struct nsStyleClipPath_nsStyleStruct_h_unnamed_29 {
     pub mBasicShape: __BindgenUnionField<*mut nsStyleBasicShape>,
-    pub mURL: __BindgenUnionField<*mut nsIURI>,
+    pub mURL: __BindgenUnionField<*mut FragmentOrURL>,
     pub _bindgen_data_: u64,
 }
 impl nsStyleClipPath_nsStyleStruct_h_unnamed_29 { }
 impl ::std::clone::Clone for nsStyleClipPath_nsStyleStruct_h_unnamed_29 {
     fn clone(&self) -> Self { *self }
 }
 #[test]
 fn bindgen_test_layout_nsStyleClipPath_nsStyleStruct_h_unnamed_29() {
@@ -6384,17 +6456,17 @@ fn bindgen_test_layout_nsStyleClipPath()
 pub struct nsStyleFilter {
     pub mType: i32,
     pub mFilterParameter: nsStyleCoord,
     pub nsStyleFilter_nsStyleStruct_h_unnamed_30: nsStyleFilter_nsStyleStruct_h_unnamed_30,
 }
 #[repr(C)]
 #[derive(Debug, Copy)]
 pub struct nsStyleFilter_nsStyleStruct_h_unnamed_30 {
-    pub mURL: __BindgenUnionField<*mut nsIURI>,
+    pub mURL: __BindgenUnionField<*mut FragmentOrURL>,
     pub mDropShadow: __BindgenUnionField<*mut nsCSSShadowArray>,
     pub _bindgen_data_: u64,
 }
 impl nsStyleFilter_nsStyleStruct_h_unnamed_30 { }
 impl ::std::clone::Clone for nsStyleFilter_nsStyleStruct_h_unnamed_30 {
     fn clone(&self) -> Self { *self }
 }
 #[test]
@@ -6446,8 +6518,25 @@ pub struct nsStyleEffects {
     pub mClipFlags: u8,
     pub mMixBlendMode: u8,
 }
 #[test]
 fn bindgen_test_layout_nsStyleEffects() {
     assert_eq!(::std::mem::size_of::<nsStyleEffects>() , 40usize);
     assert_eq!(::std::mem::align_of::<nsStyleEffects>() , 8usize);
 }
+/**
+ * <div rustbindgen="true" replaces="nsSize">
+ */
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct nsSize {
+    pub width: nscoord,
+    pub height: nscoord,
+}
+impl ::std::clone::Clone for nsSize {
+    fn clone(&self) -> Self { *self }
+}
+#[test]
+fn bindgen_test_layout_nsSize() {
+    assert_eq!(::std::mem::size_of::<nsSize>() , 8usize);
+    assert_eq!(::std::mem::align_of::<nsSize>() , 4usize);
+}
--- a/servo/ports/geckolib/gecko_bindings/tools/regen.py
+++ b/servo/ports/geckolib/gecko_bindings/tools/regen.py
@@ -75,33 +75,38 @@ COMPILATION_TARGETS = {
             "nsDataHashtable.h", "nsCSSScanner.h", "nsTArray",
             "pair", "SheetParsingMode.h", "StaticPtr.h", "nsProxyRelease.h",
             "mozilla/dom/AnimationEffectReadOnlyBinding.h",
             "nsChangeHint.h", "ServoElementSnapshot.h",
             "EventStates.h", "nsAttrValue.h", "nsAttrName.h",
             "/Types.h",   # <- Disallow UnionTypes.h
             "/utility",   # <- Disallow xutility
             "nsINode.h",  # <- For `NodeFlags`.
+            "UniquePtr.h"
         ],
         "blacklist": [
             "IsDestructibleFallbackImpl", "IsDestructibleFallback",
             "ProxyReleaseEvent", "FallibleTArray", "nsTArray_Impl",
             "__is_tuple_like_impl", "tuple_size", "tuple",
             "__make_pair_return_impl", "__make_pair_return", "tuple_element",
             "_Itup_cat", "AnimationEffectTimingProperties",
             "FastAnimationEffectTimingProperties", "ComputedTimingProperties",
             "FastComputedTimingProperties",
             "nsINode",
+            "HasPointerType"
         ],
         "opaque_types": [
             "nsIntMargin", "nsIntPoint", "nsIntRect", "nsCOMArray",
             "nsDependentString", "EntryStore", "gfxFontFeatureValueSet",
             "imgRequestProxy", "imgRequestProxyStatic", "CounterStyleManager",
             "ImageValue", "URLValue", "URLValueData", "nsIPrincipal",
-            "nsDataHashtable", "imgIRequest"
+            "nsDataHashtable", "imgIRequest",
+            "Maybe",  # <- AlignedStorage, which means templated union, which
+                      # means impossible to represent in stable rust as of
+                      # right now.
         ],
     },
     # Generation of the ffi bindings.
     "bindings": {
         "raw_lines": [
             "use heapsize::HeapSizeOf;",
         ],
         "match_headers": [
@@ -123,17 +128,17 @@ COMPILATION_TARGETS = {
             "nsStyleOutline", "nsStyleXUL", "nsStyleSVGReset", "nsStyleColumn",
             "nsStyleEffects", "nsStyleImage", "nsStyleGradient",
             "nsStyleCoord", "nsStyleGradientStop", "nsStyleImageLayers",
             "nsStyleImageLayers::Layer", "nsStyleImageLayers::LayerType",
             "nsStyleUnit", "nsStyleUnion", "nsStyleCoord::CalcValue",
             "nsStyleCoord::Calc", "nsRestyleHint", "ServoElementSnapshot",
             "nsChangeHint", "SheetParsingMode", "nsMainThreadPtrHandle",
             "nsMainThreadPtrHolder", "nscolor", "nsFont", "FontFamilyList",
-            "FontFamilyType", "nsIAtom",
+            "FontFamilyType", "nsIAtom", "nsStyleContext"
         ],
         "void_types": [
             "nsINode", "nsIDocument", "nsIPrincipal", "nsIURI",
         ],
     }
 }
 
 
--- a/servo/ports/geckolib/lib.rs
+++ b/servo/ports/geckolib/lib.rs
@@ -21,14 +21,15 @@ extern crate url;
 extern crate util;
 
 mod context;
 mod data;
 mod snapshot;
 mod snapshot_helpers;
 #[allow(non_snake_case)]
 pub mod glue;
+mod sanity_checks;
 mod traversal;
 mod wrapper;
 
 // FIXME(bholley): This should probably go away once we harmonize the allocators.
 #[no_mangle]
 pub extern "C" fn je_malloc_usable_size(_: *const ::libc::c_void) -> ::libc::size_t { 0 }
new file mode 100644
--- /dev/null
+++ b/servo/ports/geckolib/sanity_checks.rs
@@ -0,0 +1,44 @@
+/* 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/. */
+
+//! Different static asserts that ensure the build does what it's expected to.
+//!
+//! TODO: maybe cfg(test) this?
+
+#![allow(unused_imports)]
+
+use std::mem;
+
+macro_rules! check_enum_value {
+    ($a:expr, $b:expr) => {
+        unsafe {
+            mem::transmute::<[u32; $a as usize],
+                             [u32; $b as usize]>([0; $a as usize]);
+        }
+    }
+}
+
+// NB: It's a shame we can't do this statically with bitflags, but no
+// const-fn and no other way to access the numerical value :-(
+macro_rules! check_enum_value_non_static {
+    ($a:expr, $b:expr) => {
+        assert_eq!($a as usize, $b as usize);
+    }
+}
+
+#[test]
+fn assert_restyle_hints_match() {
+    use style::restyle_hints::*; // For flags
+    use gecko_bindings::structs::nsRestyleHint;
+
+    check_enum_value_non_static!(nsRestyleHint::eRestyle_Self, RESTYLE_SELF.bits());
+    // XXX This for Servo actually means something like an hypothetical
+    // Restyle_AllDescendants (but without running selector matching on the
+    // element). ServoRestyleManager interprets it like that, but in practice we
+    // should align the behavior with Gecko adding a new restyle hint, maybe?
+    //
+    // See https://bugzilla.mozilla.org/show_bug.cgi?id=1291786
+    check_enum_value_non_static!(nsRestyleHint::eRestyle_SomeDescendants, RESTYLE_DESCENDANTS.bits());
+    check_enum_value_non_static!(nsRestyleHint::eRestyle_LaterSiblings, RESTYLE_LATER_SIBLINGS.bits());
+}
--- a/servo/ports/geckolib/wrapper.rs
+++ b/servo/ports/geckolib/wrapper.rs
@@ -3,31 +3,34 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #![allow(unsafe_code)]
 
 use gecko_bindings::bindings;
 use gecko_bindings::bindings::Gecko_ChildrenCount;
 use gecko_bindings::bindings::Gecko_ClassOrClassList;
 use gecko_bindings::bindings::Gecko_GetNodeData;
+use gecko_bindings::bindings::Gecko_GetStyleContext;
+use gecko_bindings::bindings::ServoComputedValues;
 use gecko_bindings::bindings::ServoNodeData;
+use gecko_bindings::bindings::{Gecko_CalcStyleDifference, Gecko_StoreStyleDifference};
 use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentElement};
 use gecko_bindings::bindings::{Gecko_GetFirstChild, Gecko_GetFirstChildElement};
 use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetLastChildElement};
 use gecko_bindings::bindings::{Gecko_GetNextSibling, Gecko_GetNextSiblingElement};
 use gecko_bindings::bindings::{Gecko_GetNodeFlags, Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
 use gecko_bindings::bindings::{Gecko_GetParentElement, Gecko_GetParentNode};
 use gecko_bindings::bindings::{Gecko_GetPrevSibling, Gecko_GetPrevSiblingElement};
 use gecko_bindings::bindings::{Gecko_GetServoDeclarationBlock, Gecko_IsHTMLElementInHTMLDocument};
 use gecko_bindings::bindings::{Gecko_IsLink, Gecko_IsRootElement, Gecko_IsTextNode};
 use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink};
 use gecko_bindings::bindings::{Gecko_LocalName, Gecko_Namespace, Gecko_NodeIsElement, Gecko_SetNodeData};
 use gecko_bindings::bindings::{RawGeckoDocument, RawGeckoElement, RawGeckoNode};
-use gecko_bindings::structs::nsIAtom;
 use gecko_bindings::structs::{NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO, NODE_IS_DIRTY_FOR_SERVO};
+use gecko_bindings::structs::{nsIAtom, nsChangeHint, nsStyleContext};
 use glue::GeckoDeclarationBlock;
 use libc::uintptr_t;
 use selectors::Element;
 use selectors::matching::DeclarationBlock;
 use selectors::parser::{AttrSelector, NamespaceConstraint};
 use snapshot::GeckoElementSnapshot;
 use snapshot_helpers;
 use std::marker::PhantomData;
@@ -35,16 +38,17 @@ use std::ops::BitOr;
 use std::ptr;
 use std::sync::Arc;
 use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace};
 use style::data::PrivateStyleData;
 use style::dom::{OpaqueNode, PresentationalHintsSynthetizer};
 use style::dom::{TDocument, TElement, TNode, TRestyleDamage, UnsafeNode};
 use style::element_state::ElementState;
 use style::error_reporting::StdoutErrorReporter;
+use style::gecko_glue::ArcHelpers;
 use style::gecko_selector_impl::{GeckoSelectorImpl, NonTSPseudoClass};
 use style::parser::ParserContextExtraData;
 use style::properties::{ComputedValues, parse_style_attribute};
 use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
 use style::refcell::{Ref, RefCell, RefMut};
 use style::selector_impl::ElementExt;
 use style::sink::Push;
 use url::Url;
@@ -86,32 +90,54 @@ impl<'ln> GeckoNode<'ln> {
                 let ptr: NonOpaqueStyleData = Box::into_raw(Box::new(RefCell::new(PrivateStyleData::new())));
                 Gecko_SetNodeData(self.node, ptr as *mut ServoNodeData);
             }
         }
     }
 }
 
 #[derive(Clone, Copy)]
-pub struct DummyRestyleDamage;
-impl TRestyleDamage for DummyRestyleDamage {
-    fn compute(_: Option<&Arc<ComputedValues>>, _: &ComputedValues) -> Self { DummyRestyleDamage }
-    fn rebuild_and_reflow() -> Self { DummyRestyleDamage }
+pub struct GeckoRestyleDamage(nsChangeHint);
+
+impl TRestyleDamage for GeckoRestyleDamage {
+    type PreExistingComputedValues = nsStyleContext;
+    fn compute(source: Option<&nsStyleContext>,
+               new_style: &Arc<ComputedValues>) -> Self {
+        type Helpers = ArcHelpers<ServoComputedValues, ComputedValues>;
+        let context = match source {
+            Some(ctx) => ctx as *const nsStyleContext as *mut nsStyleContext,
+            None => return Self::rebuild_and_reflow(),
+        };
+
+        Helpers::borrow(new_style, |new_style| {
+            let hint = unsafe { Gecko_CalcStyleDifference(context, new_style) };
+            GeckoRestyleDamage(hint)
+        })
+    }
+
+    fn rebuild_and_reflow() -> Self {
+        GeckoRestyleDamage(nsChangeHint::nsChangeHint_ReconstructFrame)
+    }
 }
-impl BitOr for DummyRestyleDamage {
+
+impl BitOr for GeckoRestyleDamage {
     type Output = Self;
-    fn bitor(self, _: Self) -> Self { DummyRestyleDamage }
+
+    fn bitor(self, other: Self) -> Self {
+        use std::mem;
+        GeckoRestyleDamage(unsafe { mem::transmute(self.0 as u32 | other.0 as u32) })
+    }
 }
 
 
 
 impl<'ln> TNode for GeckoNode<'ln> {
     type ConcreteDocument = GeckoDocument<'ln>;
     type ConcreteElement = GeckoElement<'ln>;
-    type ConcreteRestyleDamage = DummyRestyleDamage;
+    type ConcreteRestyleDamage = GeckoRestyleDamage;
 
     fn to_unsafe(&self) -> UnsafeNode {
         (self.node as usize, 0)
     }
 
     unsafe fn from_unsafe(n: &UnsafeNode) -> Self {
         GeckoNode::from_raw(n.0 as *mut RawGeckoNode)
     }
@@ -238,19 +264,24 @@ impl<'ln> TNode for GeckoNode<'ln> {
 
     #[inline(always)]
     fn mutate_data(&self) -> Option<RefMut<PrivateStyleData>> {
         unsafe {
             self.get_node_data().as_ref().map(|d| d.borrow_mut())
         }
     }
 
-    fn restyle_damage(self) -> Self::ConcreteRestyleDamage { DummyRestyleDamage }
+    fn restyle_damage(self) -> Self::ConcreteRestyleDamage {
+        // Not called from style, only for layout.
+        unimplemented!();
+    }
 
-    fn set_restyle_damage(self, _: Self::ConcreteRestyleDamage) {}
+    fn set_restyle_damage(self, damage: Self::ConcreteRestyleDamage) {
+        unsafe { Gecko_StoreStyleDifference(self.node, damage.0) }
+    }
 
     fn parent_node(&self) -> Option<GeckoNode<'ln>> {
         unsafe {
             Gecko_GetParentNode(self.node).as_ref().map(|n| GeckoNode::from_ref(n))
         }
     }
 
     fn first_child(&self) -> Option<GeckoNode<'ln>> {
@@ -272,16 +303,30 @@ impl<'ln> TNode for GeckoNode<'ln> {
     }
 
     fn next_sibling(&self) -> Option<GeckoNode<'ln>> {
         unsafe {
             Gecko_GetNextSibling(self.node).as_ref().map(|n| GeckoNode::from_ref(n))
         }
     }
 
+    fn existing_style_for_restyle_damage<'a>(&'a self,
+                                             current_cv: Option<&'a Arc<ComputedValues>>)
+                                             -> Option<&'a nsStyleContext> {
+        if current_cv.is_none() {
+            // Don't bother in doing an ffi call to get null back.
+            return None;
+        }
+
+        unsafe {
+            let context_ptr = Gecko_GetStyleContext(self.node);
+            context_ptr.as_ref()
+        }
+    }
+
     fn needs_dirty_on_viewport_size_changed(&self) -> bool {
         // Gecko's node doesn't have the DIRTY_ON_VIEWPORT_SIZE_CHANGE flag,
         // so we force them to be dirtied on viewport size change, regardless if
         // they use viewport percentage size or not.
         // TODO(shinglyu): implement this in Gecko: https://github.com/servo/servo/pull/11890
         true
     }
 
--- a/servo/python/servo/testing_commands.py
+++ b/servo/python/servo/testing_commands.py
@@ -153,16 +153,27 @@ class MachCommands(CommandBase):
     def suite_for_path(self, path_arg):
         if os.path.exists(path.abspath(path_arg)):
             abs_path = path.abspath(path_arg)
             for prefix, suite in TEST_SUITES_BY_PREFIX.iteritems():
                 if abs_path.startswith(prefix):
                     return suite
         return None
 
+    @Command('test-geckolib',
+             description='Test geckolib sanity checks',
+             category='testing')
+    def test_geckolib(self):
+        self.ensure_bootstrapped()
+
+        env = self.build_env()
+        env["RUST_BACKTRACE"] = "1"
+
+        return call(["cargo", "test"], env=env, cwd=path.join("ports", "geckolib"))
+
     @Command('test-unit',
              description='Run unit tests',
              category='testing')
     @CommandArgument('--package', '-p', default=None, help="Specific package to test")
     @CommandArgument('test_name', nargs=argparse.REMAINDER,
                      help="Only run tests that match this pattern or file path")
     def test_unit(self, test_name=None, package=None):
         if test_name is None: