Browse Source

series qrename script files

Frank-Rainer Grahl 3 years ago
parent
commit
bfd129e9c2
100 changed files with 35114 additions and 0 deletions
  1. 28 0
      frg/253-58/mozilla-release58_427917.patch
  2. 331 0
      frg/253-58/mozilla-release58_427920.patch
  3. 28 0
      frg/253-58/mozilla-release58_427921.patch
  4. 56 0
      frg/253-58/mozilla-release58_427929.patch
  5. 36 0
      frg/253-58/mozilla-release58_427930.patch
  6. 143 0
      frg/253-58/mozilla-release58_427931.patch
  7. 117 0
      frg/253-58/mozilla-release58_427932.patch
  8. 453 0
      frg/253-58/mozilla-release58_427934.patch
  9. 266 0
      frg/253-58/mozilla-release58_427937.patch
  10. 623 0
      frg/253-58/mozilla-release58_427938.patch
  11. 40 0
      frg/253-58/mozilla-release58_427939.patch
  12. 37 0
      frg/253-58/mozilla-release58_427940.patch
  13. 51 0
      frg/253-58/mozilla-release58_427959.patch
  14. 155 0
      frg/253-58/mozilla-release58_427968.patch
  15. 39 0
      frg/253-58/mozilla-release58_427975.patch
  16. 215 0
      frg/253-58/mozilla-release58_427981.patch
  17. 83 0
      frg/253-58/mozilla-release58_427985.patch
  18. 27 0
      frg/253-58/mozilla-release58_427986.patch
  19. 139 0
      frg/253-58/mozilla-release58_427993.patch
  20. 119 0
      frg/253-58/mozilla-release58_428001.patch
  21. 72 0
      frg/253-58/mozilla-release58_428008.patch
  22. 71 0
      frg/253-58/mozilla-release58_428011.patch
  23. 95 0
      frg/253-58/mozilla-release58_428023.patch
  24. 41 0
      frg/253-58/mozilla-release58_428026.patch
  25. 2024 0
      frg/253-58/mozilla-release58_428028.patch
  26. 478 0
      frg/253-58/mozilla-release58_428029.patch
  27. 415 0
      frg/253-58/mozilla-release58_428030.patch
  28. 50 0
      frg/253-58/mozilla-release58_428034.patch
  29. 42 0
      frg/253-58/mozilla-release58_428035.patch
  30. 258 0
      frg/253-58/mozilla-release58_428040.patch
  31. 219 0
      frg/253-58/mozilla-release58_428041.patch
  32. 84 0
      frg/253-58/mozilla-release58_428042.patch
  33. 109 0
      frg/253-58/mozilla-release58_428056.patch
  34. 337 0
      frg/253-58/mozilla-release58_428062.patch
  35. 44 0
      frg/253-58/mozilla-release58_428073.patch
  36. 207 0
      frg/253-58/mozilla-release58_428074.patch
  37. 4518 0
      frg/253-58/mozilla-release58_428077.patch
  38. 1145 0
      frg/253-58/mozilla-release58_428078.patch
  39. 694 0
      frg/253-58/mozilla-release58_428079.patch
  40. 226 0
      frg/253-58/mozilla-release58_428081.patch
  41. 150 0
      frg/253-58/mozilla-release58_428082.patch
  42. 62 0
      frg/253-58/mozilla-release58_428083.patch
  43. 66 0
      frg/253-58/mozilla-release58_428089.patch
  44. 86 0
      frg/253-58/mozilla-release58_428093.patch
  45. 79 0
      frg/253-58/mozilla-release58_428094.patch
  46. 1394 0
      frg/253-58/mozilla-release58_428103.patch
  47. 788 0
      frg/253-58/mozilla-release58_428111.patch
  48. 387 0
      frg/253-58/mozilla-release58_428113.patch
  49. 53 0
      frg/253-58/mozilla-release58_428122.patch
  50. 34 0
      frg/253-58/mozilla-release58_428135.patch
  51. 136 0
      frg/253-58/mozilla-release58_428136.patch
  52. 24 0
      frg/253-58/mozilla-release58_428145.patch
  53. 30 0
      frg/253-58/mozilla-release58_428146.patch
  54. 26 0
      frg/253-58/mozilla-release58_428147.patch
  55. 25 0
      frg/253-58/mozilla-release58_428148.patch
  56. 29 0
      frg/253-58/mozilla-release58_428149.patch
  57. 29 0
      frg/253-58/mozilla-release58_428150.patch
  58. 58 0
      frg/253-58/mozilla-release58_428154.patch
  59. 39 0
      frg/253-58/mozilla-release58_428155.patch
  60. 43 0
      frg/253-58/mozilla-release58_428156.patch
  61. 89 0
      frg/253-58/mozilla-release58_428157.patch
  62. 92 0
      frg/253-58/mozilla-release58_428159.patch
  63. 154 0
      frg/253-58/mozilla-release58_428160.patch
  64. 40 0
      frg/253-58/mozilla-release58_428161.patch
  65. 662 0
      frg/253-58/mozilla-release58_428162.patch
  66. 29 0
      frg/253-58/mozilla-release58_428163.patch
  67. 35 0
      frg/253-58/mozilla-release58_428164.patch
  68. 1477 0
      frg/253-58/mozilla-release58_428169.patch
  69. 60 0
      frg/253-58/mozilla-release58_428170.patch
  70. 52 0
      frg/253-58/mozilla-release58_428173.patch
  71. 1245 0
      frg/253-58/mozilla-release58_428174.patch
  72. 120 0
      frg/253-58/mozilla-release58_428175.patch
  73. 81 0
      frg/253-58/mozilla-release58_428177.patch
  74. 34 0
      frg/253-58/mozilla-release58_428178.patch
  75. 48 0
      frg/253-58/mozilla-release58_428179.patch
  76. 65 0
      frg/253-58/mozilla-release58_428180.patch
  77. 61 0
      frg/253-58/mozilla-release58_428181.patch
  78. 159 0
      frg/253-58/mozilla-release58_428182.patch
  79. 1802 0
      frg/253-58/mozilla-release58_428183.patch
  80. 197 0
      frg/253-58/mozilla-release58_428184.patch
  81. 34 0
      frg/253-58/mozilla-release58_428185.patch
  82. 112 0
      frg/253-58/mozilla-release58_428186.patch
  83. 726 0
      frg/253-58/mozilla-release58_428187.patch
  84. 37 0
      frg/253-58/mozilla-release58_428189.patch
  85. 103 0
      frg/253-58/mozilla-release58_428190.patch
  86. 161 0
      frg/253-58/mozilla-release58_428191.patch
  87. 3119 0
      frg/253-58/mozilla-release58_428195.patch
  88. 37 0
      frg/253-58/mozilla-release58_428197.patch
  89. 81 0
      frg/253-58/mozilla-release58_428202.patch
  90. 436 0
      frg/253-58/mozilla-release58_428203.patch
  91. 144 0
      frg/253-58/mozilla-release58_428204.patch
  92. 48 0
      frg/253-58/mozilla-release58_428207.patch
  93. 105 0
      frg/253-58/mozilla-release58_428212.patch
  94. 35 0
      frg/253-58/mozilla-release58_428214.patch
  95. 14 0
      frg/253-58/mozilla-release58_428215.patch
  96. 14 0
      frg/253-58/mozilla-release58_428216.patch
  97. 2432 0
      frg/253-58/mozilla-release58_428217.patch
  98. 1316 0
      frg/253-58/mozilla-release58_428218.patch
  99. 25 0
      frg/253-58/mozilla-release58_428220.patch
  100. 1980 0
      frg/253-58/mozilla-release58_428221.patch

+ 28 - 0
frg/253-58/mozilla-release58_427917.patch

@@ -0,0 +1,28 @@
+# HG changeset patch
+# User Emilio Cobos Alvarez <emilio@crisal.io>
+# Date 1503333097 -7200
+#      Mon Aug 21 18:31:37 2017 +0200
+# Node ID 39e9a20aacfcde749c386b048a48d86144a9f6fa
+# Parent  0a5026562d739585badc16bb91f3a426b75c88c0
+Bug 1341102: Update expectations after servo/servo#18139. r=me
+
+MozReview-Commit-ID: F8wa1hxNtCZ
+
+diff --git a/testing/web-platform/meta/css/CSS2/syntax/at-rule-008.xht.ini b/testing/web-platform/meta/css/CSS2/syntax/at-rule-008.xht.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/css/CSS2/syntax/at-rule-008.xht.ini
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[at-rule-008.xht]
+-  type: reftest
+-  expected:
+-    if stylo: FAIL
+diff --git a/testing/web-platform/meta/css/CSS2/syntax/at-rule-009.xht.ini b/testing/web-platform/meta/css/CSS2/syntax/at-rule-009.xht.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/css/CSS2/syntax/at-rule-009.xht.ini
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[at-rule-009.xht]
+-  type: reftest
+-  expected:
+-    if stylo: FAIL

+ 331 - 0
frg/253-58/mozilla-release58_427920.patch

@@ -0,0 +1,331 @@
+# HG changeset patch
+# User Emilio Cobos Alvarez <emilio@crisal.io>
+# Date 1503331150 18000
+#      Mon Aug 21 10:59:10 2017 -0500
+# Node ID ab0b55814e1b77f7402d088506e84dca1cb38860
+# Parent  4009e36438f1beb673101000287d81b1e71ea456
+servo: Merge #18143 - style: Remove Stylist::is_device_dirty (from emilio:stylist-stylesheets); r=<try>
+
+More progress on unifying how Gecko and Servo track stylist dirtiness.
+
+Source-Repo: https://github.com/servo/servo
+Source-Revision: e60266a72302a0ed332f1dd18d335b6092c47da4
+
+diff --git a/servo/components/style/animation.rs b/servo/components/style/animation.rs
+--- a/servo/components/style/animation.rs
++++ b/servo/components/style/animation.rs
+@@ -432,31 +432,33 @@ pub fn start_transitions_if_applicable(n
+                                        -> bool {
+     let mut had_animations = false;
+     for i in 0..new_style.get_box().transition_property_count() {
+         // Create any property animations, if applicable.
+         let property_animations = PropertyAnimation::from_transition(i,
+                                                                      old_style,
+                                                                      Arc::make_mut(new_style));
+         for property_animation in property_animations {
+-            // Per [1], don't trigger a new transition if the end state for that transition is
+-            // the same as that of a transition that's already running on the same node.
++            // Set the property to the initial value.
++            //
++            // NB: get_mut is guaranteed to succeed since we called make_mut()
++            // above.
++            property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0);
++
++            // Per [1], don't trigger a new transition if the end state for that
++            // transition is the same as that of a transition that's already
++            // running on the same node.
+             //
+             // [1]: https://drafts.csswg.org/css-transitions/#starting
+             if possibly_expired_animations.iter().any(|animation| {
+-                    animation.has_the_same_end_value_as(&property_animation)
+-                }) {
++                animation.has_the_same_end_value_as(&property_animation)
++            }) {
+                 continue
+             }
+ 
+-            // Set the property to the initial value.
+-            // NB: get_mut is guaranteed to succeed since we called make_mut()
+-            // above.
+-            property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0);
+-
+             // Kick off the animation.
+             let box_style = new_style.get_box();
+             let now = timer.seconds();
+             let start_time =
+                 now + (box_style.transition_delay_mod(i).seconds() as f64);
+             new_animations_sender
+                 .send(Animation::Transition(opaque_node, start_time, AnimationFrame {
+                     duration: box_style.transition_duration_mod(i).seconds() as f64,
+diff --git a/servo/components/style/stylist.rs b/servo/components/style/stylist.rs
+--- a/servo/components/style/stylist.rs
++++ b/servo/components/style/stylist.rs
+@@ -73,19 +73,16 @@ pub struct Stylist {
+ 
+     /// Viewport constraints based on the current device.
+     viewport_constraints: Option<ViewportConstraints>,
+ 
+     /// If true, the quirks-mode stylesheet is applied.
+     #[cfg_attr(feature = "servo", ignore_heap_size_of = "defined in selectors")]
+     quirks_mode: QuirksMode,
+ 
+-    /// If true, the device has changed, and the stylist needs to be updated.
+-    is_device_dirty: bool,
+-
+     /// Selector maps for all of the style sheets in the stylist, after
+     /// evalutaing media rules against the current device, split out per
+     /// cascade level.
+     cascade_data: PerOrigin<CascadeData>,
+ 
+     /// The rule tree, that stores the results of selector matching.
+     rule_tree: RuleTree,
+ 
+@@ -125,17 +122,16 @@ impl Stylist {
+     /// Construct a new `Stylist`, using given `Device` and `QuirksMode`.
+     /// If more members are added here, think about whether they should
+     /// be reset in clear().
+     #[inline]
+     pub fn new(device: Device, quirks_mode: QuirksMode) -> Self {
+         Stylist {
+             viewport_constraints: None,
+             device: device,
+-            is_device_dirty: true,
+             quirks_mode: quirks_mode,
+ 
+             cascade_data: Default::default(),
+             precomputed_pseudo_element_decls: PerPseudoElementMap::default(),
+             rule_tree: RuleTree::new(),
+             num_rebuilds: 0,
+         }
+ 
+@@ -179,40 +175,30 @@ impl Stylist {
+     {
+         for (data, _) in self.cascade_data.iter_origins() {
+             f(&data.invalidation_map)
+         }
+     }
+ 
+     /// Rebuild the stylist for the given document stylesheets, and optionally
+     /// with a set of user agent stylesheets.
+-    ///
+-    /// This method resets all the style data each time the stylesheets change
+-    /// (which is indicated by the `stylesheets_changed` parameter), or the
+-    /// device is dirty, which means we need to re-evaluate media queries.
+     pub fn rebuild<'a, I, S>(
+         &mut self,
+         doc_stylesheets: I,
+         guards: &StylesheetGuards,
+         ua_stylesheets: Option<&UserAgentStylesheets>,
+         author_style_disabled: bool,
+         extra_data: &mut PerOrigin<ExtraStyleData>,
+-        mut origins_to_rebuild: OriginSet,
+-    ) -> OriginSet
++        origins_to_rebuild: OriginSet,
++    )
+     where
+         I: Iterator<Item = &'a S> + Clone,
+         S: StylesheetInDocument + ToMediaListKey + 'static,
+     {
+-        if self.is_device_dirty {
+-            origins_to_rebuild = OriginSet::all();
+-        }
+-
+-        if origins_to_rebuild.is_empty() {
+-            return origins_to_rebuild;
+-        }
++        debug_assert!(!origins_to_rebuild.is_empty());
+ 
+         self.num_rebuilds += 1;
+ 
+         // Update viewport_constraints regardless of which origins'
+         // `CascadeData` we're updating.
+         self.viewport_constraints = None;
+         if viewport_rule::enabled() {
+             // TODO(emilio): This doesn't look so efficient.
+@@ -247,47 +233,65 @@ impl Stylist {
+         }
+ 
+         if origins_to_rebuild.contains(Origin::UserAgent.into()) {
+             self.precomputed_pseudo_element_decls.clear();
+         }
+ 
+         if let Some(ua_stylesheets) = ua_stylesheets {
+             for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets {
++                let sheet_origin =
++                    stylesheet.contents(guards.ua_or_user).origin;
++
+                 debug_assert!(matches!(
+-                    stylesheet.contents(guards.ua_or_user).origin,
+-                    Origin::UserAgent | Origin::User));
+-                self.add_stylesheet(stylesheet, guards.ua_or_user, extra_data);
++                    sheet_origin,
++                    Origin::UserAgent | Origin::User
++                ));
++
++                if origins_to_rebuild.contains(sheet_origin.into()) {
++                    self.add_stylesheet(
++                        stylesheet,
++                        guards.ua_or_user,
++                        extra_data
++                    );
++                }
+             }
+ 
+             if self.quirks_mode != QuirksMode::NoQuirks {
+                 let stylesheet = &ua_stylesheets.quirks_mode_stylesheet;
++                let sheet_origin =
++                    stylesheet.contents(guards.ua_or_user).origin;
++
+                 debug_assert!(matches!(
+-                    stylesheet.contents(guards.ua_or_user).origin,
+-                    Origin::UserAgent | Origin::User));
+-                self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet,
+-                                    guards.ua_or_user, extra_data);
++                    sheet_origin,
++                    Origin::UserAgent | Origin::User
++                ));
++
++                if origins_to_rebuild.contains(sheet_origin.into()) {
++                    self.add_stylesheet(
++                        &ua_stylesheets.quirks_mode_stylesheet,
++                        guards.ua_or_user,
++                        extra_data
++                    );
++                }
+             }
+         }
+ 
+         // Only add stylesheets for origins we are updating, and only add
+         // Author level sheets if author style is not disabled.
+         let sheets_to_add = doc_stylesheets.filter(|s| {
+             let sheet_origin = s.contents(guards.author).origin;
+ 
+             origins_to_rebuild.contains(sheet_origin.into()) &&
+                 (!matches!(sheet_origin, Origin::Author) || !author_style_disabled)
+         });
+ 
+         for stylesheet in sheets_to_add {
+             self.add_stylesheet(stylesheet, guards.author, extra_data);
+         }
+-
+-        self.is_device_dirty = false;
+-        origins_to_rebuild
+     }
+ 
+     fn add_stylesheet<S>(
+         &mut self,
+         stylesheet: &S,
+         guard: &SharedRwLockReadGuard,
+         _extra_data: &mut PerOrigin<ExtraStyleData>
+     )
+@@ -826,40 +830,36 @@ impl Stylist {
+         }
+ 
+         inputs
+     }
+ 
+     /// Set a given device, which may change the styles that apply to the
+     /// document.
+     ///
++    /// Returns the sheet origins that were actually affected.
++    ///
+     /// This means that we may need to rebuild style data even if the
+     /// stylesheets haven't changed.
+     ///
+     /// Also, the device that arrives here may need to take the viewport rules
+     /// into account.
+     ///
+-    /// TODO(emilio): Probably should be unified with `update`, right now I
+-    /// don't think we take into account dynamic updates to viewport rules.
+-    ///
+-    /// Probably worth to make the stylist own a single `Device`, and have a
+-    /// `update_device` function?
+-    ///
+     /// feature = "servo" because gecko only has one device, and manually tracks
+     /// when the device is dirty.
+     ///
+     /// FIXME(emilio): The semantics of the device for Servo and Gecko are
+     /// different enough we may want to unify them.
+     #[cfg(feature = "servo")]
+     pub fn set_device<'a, I, S>(
+         &mut self,
+         mut device: Device,
+         guard: &SharedRwLockReadGuard,
+         stylesheets: I,
+-    )
++    ) -> OriginSet
+     where
+         I: Iterator<Item = &'a S> + Clone,
+         S: StylesheetInDocument + ToMediaListKey + 'static,
+     {
+         let cascaded_rule = ViewportRule {
+             declarations: viewport_rule::Cascade::from_stylesheets(
+                 stylesheets.clone(),
+                 guard,
+@@ -870,21 +870,20 @@ impl Stylist {
+         self.viewport_constraints =
+             ViewportConstraints::maybe_new(&device, &cascaded_rule, self.quirks_mode);
+ 
+         if let Some(ref constraints) = self.viewport_constraints {
+             device.account_for_viewport_rule(constraints);
+         }
+ 
+         self.device = device;
+-        let features_changed = self.media_features_change_changed_style(
++        self.media_features_change_changed_style(
+             stylesheets,
+-            guard
+-        );
+-        self.is_device_dirty |= !features_changed.is_empty();
++            guard,
++        )
+     }
+ 
+     /// Returns whether, given a media feature change, any previously-applicable
+     /// style has become non-applicable, or vice-versa for each origin.
+     pub fn media_features_change_changed_style<'a, I, S>(
+         &self,
+         stylesheets: I,
+         guard: &SharedRwLockReadGuard,
+@@ -1062,17 +1061,16 @@ impl Stylist {
+                                         rule_inclusion: RuleInclusion,
+                                         applicable_declarations: &mut V,
+                                         context: &mut MatchingContext,
+                                         flags_setter: &mut F)
+         where E: TElement,
+               V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock> + Debug,
+               F: FnMut(&E, ElementSelectorFlags),
+     {
+-        debug_assert!(!self.is_device_dirty);
+         // Gecko definitely has pseudo-elements with style attributes, like
+         // ::-moz-color-swatch.
+         debug_assert!(cfg!(feature = "gecko") ||
+                       style_attribute.is_none() || pseudo_element.is_none(),
+                       "Style attributes do not apply to pseudo-elements");
+         debug_assert!(pseudo_element.map_or(true, |p| !p.is_precomputed()));
+ 
+         let rule_hash_target = element.rule_hash_target();
+@@ -1212,23 +1210,16 @@ impl Stylist {
+     /// of our rule maps.
+     #[inline]
+     pub fn may_have_rules_for_id(&self, id: &Atom) -> bool {
+         self.cascade_data
+             .iter_origins()
+             .any(|(d, _)| d.mapped_ids.might_contain_hash(id.get_hash()))
+     }
+ 
+-    /// Return whether the device is dirty, that is, whether the screen size or
+-    /// media type have changed (for now).
+-    #[inline]
+-    pub fn is_device_dirty(&self) -> bool {
+-        self.is_device_dirty
+-    }
+-
+     /// Returns the registered `@keyframes` animation for the specified name.
+     #[inline]
+     pub fn get_animation(&self, name: &Atom) -> Option<&KeyframesAnimation> {
+         self.cascade_data
+             .iter_origins()
+             .filter_map(|(d, _)| d.animations.get(name))
+             .next()
+     }

+ 28 - 0
frg/253-58/mozilla-release58_427921.patch

@@ -0,0 +1,28 @@
+# HG changeset patch
+# User Emilio Cobos Alvarez <emilio@crisal.io>
+# Date 1503336369 -7200
+#      Mon Aug 21 19:26:09 2017 +0200
+# Node ID 02095185a9479e03f31f8a38d05eb64cd9516bf2
+# Parent  65267d88dd9595638deb83d90940878bfb8296b9
+Bug 1341102: More expectation updates after servo/servo#18139. r=me
+
+MozReview-Commit-ID: 7q1ITUpRcS2
+
+diff --git a/testing/web-platform/meta/css/CSS2/cascade/at-import-009.xht.ini b/testing/web-platform/meta/css/CSS2/cascade/at-import-009.xht.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/css/CSS2/cascade/at-import-009.xht.ini
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[at-import-009.xht]
+-  type: reftest
+-  expected:
+-    if stylo: FAIL
+diff --git a/testing/web-platform/meta/css/CSS2/cascade/at-import-010.xht.ini b/testing/web-platform/meta/css/CSS2/cascade/at-import-010.xht.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/css/CSS2/cascade/at-import-010.xht.ini
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[at-import-010.xht]
+-  type: reftest
+-  expected:
+-    if stylo: FAIL

+ 56 - 0
frg/253-58/mozilla-release58_427929.patch

@@ -0,0 +1,56 @@
+# HG changeset patch
+# User Lars T Hansen <lhansen@mozilla.com>
+# Date 1503069705 -7200
+#      Fri Aug 18 17:21:45 2017 +0200
+# Node ID 9bf5648598b0c49cb6083edd2ca3eb259cc31de7
+# Parent  9b393a2ce559f32c0fb5be7edd9ab203bc0c9a86
+Bug 1391636 - gate the availability of wasm threads on 8-byte lock-free atomics. r=bbouvier
+
+diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
+--- a/js/src/builtin/TestingFunctions.cpp
++++ b/js/src/builtin/TestingFunctions.cpp
+@@ -28,16 +28,17 @@
+ #include "builtin/Promise.h"
+ #include "builtin/SelfHostingDefines.h"
+ #ifdef DEBUG
+ #include "frontend/TokenStream.h"
+ #include "irregexp/RegExpAST.h"
+ #include "irregexp/RegExpEngine.h"
+ #include "irregexp/RegExpParser.h"
+ #endif
++#include "jit/AtomicOperations.h"
+ #include "jit/InlinableNatives.h"
+ #include "js/Debug.h"
+ #include "js/HashTable.h"
+ #include "js/StructuredClone.h"
+ #include "js/UbiNode.h"
+ #include "js/UbiNodeBreadthFirst.h"
+ #include "js/UbiNodeShortestPaths.h"
+ #include "js/UniquePtr.h"
+@@ -544,16 +545,26 @@ static bool
+ WasmThreadsSupported(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);
+ #ifdef ENABLE_WASM_THREAD_OPS
+     bool isSupported = wasm::HasSupport(cx);
+ #else
+     bool isSupported = false;
+ #endif
++
++    // NOTE!  When we land thread support, the following test and its comment
++    // should be moved into wasm::HasSupport() or wasm::HasCompilerSupport().
++
++    // Wasm threads require 8-byte lock-free atomics.  This guard will
++    // effectively disable Wasm support for some older devices, such as early
++    // ARMv6 and older MIPS.
++
++    isSupported = isSupported && jit::AtomicOperations::isLockfree8();
++
+     args.rval().setBoolean(isSupported);
+     return true;
+ }
+ 
+ static bool
+ WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp)
+ {
+     CallArgs args = CallArgsFromVp(argc, vp);

+ 36 - 0
frg/253-58/mozilla-release58_427930.patch

@@ -0,0 +1,36 @@
+# HG changeset patch
+# User Lars T Hansen <lhansen@mozilla.com>
+# Date 1503298183 -7200
+#      Mon Aug 21 08:49:43 2017 +0200
+# Node ID e013d1324ea834f2d3c62edaeb644e41f5089459
+# Parent  fae358857f63020903ff105569ccf02fd9a15773
+Bug 1391636 - make some locals DEBUG-only.  r=me
+
+diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp
+--- a/js/src/jit/x86/CodeGenerator-x86.cpp
++++ b/js/src/jit/x86/CodeGenerator-x86.cpp
+@@ -1056,22 +1056,24 @@ CodeGeneratorX86::visitExtendInt32ToInt6
+         MOZ_ASSERT(output.high == edx);
+         masm.cdq();
+     }
+ }
+ 
+ void
+ CodeGeneratorX86::visitSignExtendInt64(LSignExtendInt64* lir)
+ {
++#ifdef DEBUG
+     Register64 input = ToRegister64(lir->getInt64Operand(0));
+     Register64 output = ToOutRegister64(lir);
+     MOZ_ASSERT(input.low == eax);
+     MOZ_ASSERT(output.low == eax);
+     MOZ_ASSERT(input.high == edx);
+     MOZ_ASSERT(output.high == edx);
++#endif
+     switch (lir->mode()) {
+       case MSignExtendInt64::Byte:
+         masm.move8SignExtend(eax, eax);
+         break;
+       case MSignExtendInt64::Half:
+         masm.move16SignExtend(eax, eax);
+         break;
+       case MSignExtendInt64::Word:

+ 143 - 0
frg/253-58/mozilla-release58_427931.patch

@@ -0,0 +1,143 @@
+# HG changeset patch
+# User Christoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
+# Date 1503298634 -7200
+#      Mon Aug 21 08:57:14 2017 +0200
+# Node ID 525e9e4dac88fe6640c7f6b3e46984855cff5930
+# Parent  d128550bda95a5e4372f0139abb51949a30fc732
+Bug 1391011: CSP: Fix upgrade-insecure-requests for toplevel navigations when base it https. r=smaug
+
+diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
+--- a/docshell/base/nsDocShell.cpp
++++ b/docshell/base/nsDocShell.cpp
+@@ -10880,16 +10880,72 @@ nsDocShell::GetInheritedPrincipal(bool a
+     }
+ 
+     return docPrincipal;
+   }
+ 
+   return nullptr;
+ }
+ 
++// CSPs upgrade-insecure-requests directive applies to same origin top level
++// navigations. Using the SOP would return false for the case when an https
++// page triggers and http page to load, even though that http page would be
++// upgraded to https later. Hence we have to use that custom function instead
++// of simply calling aTriggeringPrincipal->Equals(aResultPrincipal).
++static bool
++IsConsideredSameOriginForUIR(nsIPrincipal* aTriggeringPrincipal,
++                             nsIPrincipal* aResultPrincipal)
++{
++  MOZ_ASSERT(aTriggeringPrincipal);
++  MOZ_ASSERT(aResultPrincipal);
++
++  // we only have to make sure that the following truth table holds:
++  // aTriggeringPrincipal         | aResultPrincipal             | Result
++  // ----------------------------------------------------------------
++  // http://example.com/foo.html  | http://example.com/bar.html  | true
++  // https://example.com/foo.html | https://example.com/bar.html | true
++  // https://example.com/foo.html | http://example.com/bar.html  | true
++  if (aTriggeringPrincipal->Equals(aResultPrincipal)) {
++    return true;
++  }
++
++  if (!aResultPrincipal->GetIsCodebasePrincipal()) {
++    return false;
++  }
++
++  nsCOMPtr<nsIURI> resultURI;
++  nsresult rv = aResultPrincipal->GetURI(getter_AddRefs(resultURI));
++  NS_ENSURE_SUCCESS(rv, false);
++
++  nsAutoCString resultScheme;
++  rv = resultURI->GetScheme(resultScheme);
++  NS_ENSURE_SUCCESS(rv, false);
++  if (!resultScheme.EqualsLiteral("http")) {
++    return false;
++  }
++
++  nsAutoCString tmpResultSpec;
++  rv = resultURI->GetSpec(tmpResultSpec);
++  NS_ENSURE_SUCCESS(rv, false);
++  // replace http with https
++  tmpResultSpec.Replace(0, 4, "https");
++
++  nsCOMPtr<nsIURI> tmpResultURI;
++  rv = NS_NewURI(getter_AddRefs(tmpResultURI), tmpResultSpec);
++  NS_ENSURE_SUCCESS(rv, false);
++
++  mozilla::OriginAttributes tmpOA =
++    BasePrincipal::Cast(aResultPrincipal)->OriginAttributesRef();
++
++  nsCOMPtr<nsIPrincipal> tmpResultPrincipal =
++    BasePrincipal::CreateCodebasePrincipal(tmpResultURI, tmpOA);
++
++  return aTriggeringPrincipal->Equals(tmpResultPrincipal);
++}
++
+ nsresult
+ nsDocShell::DoURILoad(nsIURI* aURI,
+                       nsIURI* aOriginalURI,
+                       Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
+                       bool aKeepResultPrincipalURIIfSet,
+                       bool aLoadReplace,
+                       bool aLoadFromExternal,
+                       nsIURI* aReferrerURI,
+@@ -11198,17 +11254,17 @@ nsDocShell::DoURILoad(nsIURI* aURI,
+     csp->GetUpgradeInsecureRequests(&upgradeInsecureRequests);
+     if (upgradeInsecureRequests) {
+       // only upgrade if the navigation is same origin
+       nsCOMPtr<nsIPrincipal> resultPrincipal;
+       rv = nsContentUtils::GetSecurityManager()->
+              GetChannelResultPrincipal(channel,
+                                        getter_AddRefs(resultPrincipal));
+       NS_ENSURE_SUCCESS(rv, rv);
+-      if (resultPrincipal->Equals(aTriggeringPrincipal)) {
++      if (IsConsideredSameOriginForUIR(aTriggeringPrincipal, resultPrincipal)) {
+         static_cast<mozilla::LoadInfo*>(loadInfo.get())->SetUpgradeInsecureRequests();
+       }
+     }
+   }
+ 
+ 
+   nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
+     do_QueryInterface(channel);
+diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp
+--- a/netwerk/base/nsNetUtil.cpp
++++ b/netwerk/base/nsNetUtil.cpp
+@@ -2584,31 +2584,22 @@ NS_ShouldSecureUpgrade(nsIURI* aURI,
+   // data (it is read-only).
+   // if the connection is not using SSL and either the exact host matches or
+   // a superdomain wants to force HTTPS, do it.
+   bool isHttps = false;
+   nsresult rv = aURI->SchemeIs("https", &isHttps);
+   NS_ENSURE_SUCCESS(rv, rv);
+ 
+   if (!isHttps) {
+-    // If any of the documents up the chain to the root doucment makes use of
+-    // the CSP directive 'upgrade-insecure-requests', then it's time to fulfill
+-    // the promise to CSP and mixed content blocking to upgrade the channel
+-    // from http to https.
+     if (aLoadInfo) {
+-      // Please note that cross origin top level navigations are not subject
+-      // to upgrade-insecure-requests, see:
+-      // http://www.w3.org/TR/upgrade-insecure-requests/#examples
+-      // Compare the principal we are navigating to (aChannelResultPrincipal)
+-      // with the referring/triggering Principal.
+-      bool crossOriginNavigation =
+-        (aLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT) &&
+-        (!aChannelResultPrincipal->Equals(aLoadInfo->TriggeringPrincipal()));
+-
+-      if (aLoadInfo->GetUpgradeInsecureRequests() && !crossOriginNavigation) {
++      // If any of the documents up the chain to the root document makes use of
++      // the CSP directive 'upgrade-insecure-requests', then it's time to fulfill
++      // the promise to CSP and mixed content blocking to upgrade the channel
++      // from http to https.
++      if (aLoadInfo->GetUpgradeInsecureRequests()) {
+         // let's log a message to the console that we are upgrading a request
+         nsAutoCString scheme;
+         aURI->GetScheme(scheme);
+         // append the additional 's' for security to the scheme :-)
+         scheme.AppendASCII("s");
+         NS_ConvertUTF8toUTF16 reportSpec(aURI->GetSpecOrDefault());
+         NS_ConvertUTF8toUTF16 reportScheme(scheme);
+ 

+ 117 - 0
frg/253-58/mozilla-release58_427932.patch

@@ -0,0 +1,117 @@
+# HG changeset patch
+# User Christoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
+# Date 1503298681 -7200
+#      Mon Aug 21 08:58:01 2017 +0200
+# Node ID 729120b963788d9737b024759368356f8f0cd077
+# Parent  5ec4d2055433176f18dcdaa241369514741cd4cc
+Bug 1391011: CSP: Test upgrade-insecure-requests for toplevel navigations when base it https. r=smaug
+
+diff --git a/dom/security/test/csp/file_uir_top_nav.html b/dom/security/test/csp/file_uir_top_nav.html
+new file mode 100644
+--- /dev/null
++++ b/dom/security/test/csp/file_uir_top_nav.html
+@@ -0,0 +1,17 @@
++<!DOCTYPE HTML>
++<html>
++<head>
++  <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
++</head>
++<body>
++<script class="testbody" type="text/javascript">
++
++// 1) same origin navigation
++window.open("http://example.com/tests/dom/security/test/csp/file_uir_top_nav_dummy.html");
++
++// 2) same origin navigation
++window.open("http://test1.example.com/tests/dom/security/test/csp/file_uir_top_nav_dummy.html");
++
++</script>
++</body>
++</html>
+diff --git a/dom/security/test/csp/file_uir_top_nav_dummy.html b/dom/security/test/csp/file_uir_top_nav_dummy.html
+new file mode 100644
+--- /dev/null
++++ b/dom/security/test/csp/file_uir_top_nav_dummy.html
+@@ -0,0 +1,12 @@
++<!DOCTYPE HTML>
++<html>
++<body>
++just a dummy page to check uir applies to top level navigations
++<script class="testbody" type="text/javascript">
++window.onload = function() {
++  window.opener.parent.postMessage({result: window.location.href}, "*");
++  window.close();
++}
++</script>
++</body>
++</html>
+diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini
+--- a/dom/security/test/csp/mochitest.ini
++++ b/dom/security/test/csp/mochitest.ini
+@@ -319,12 +319,16 @@ tags = mcb
+ [test_iframe_srcdoc.html]
+ [test_image_nonce.html]
+ [test_websocket_self.html]
+ skip-if = toolkit == 'android'
+ [test_ignore_xfo.html]
+ [test_data_csp_merge.html]
+ [test_data_csp_inheritance.html]
+ [test_report_font_cache.html]
++[test_uir_top_nav.html]
++support-files =
++  file_uir_top_nav.html
++  file_uir_top_nav_dummy.html
+ [test_sandbox_allow_scripts.html]
+ support-files =
+   file_sandbox_allow_scripts.html
+   file_sandbox_allow_scripts.html^headers^
+diff --git a/dom/security/test/csp/test_uir_top_nav.html b/dom/security/test/csp/test_uir_top_nav.html
+new file mode 100644
+--- /dev/null
++++ b/dom/security/test/csp/test_uir_top_nav.html
+@@ -0,0 +1,45 @@
++<!DOCTYPE HTML>
++<html>
++<head>
++  <title>Bug 1391011: Test uir for toplevel navigations</title>
++  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
++  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
++</head>
++<body>
++<iframe style="width:100%;" id="testframe"></iframe>
++
++<script class="testbody" type="text/javascript">
++
++SimpleTest.waitForExplicitFinish();
++
++/* Description of the test:
++ * We load an https page which defines upgrade-insecure-requests into an iframe
++ * and perform a same origin and a cross origin toplevel load and make sure that
++ * upgrade-insecure-requests applies to the same origin load.
++ */
++
++let totalTests = 2;
++let testCounter = 0;
++
++function checkResults(aResult) {
++  ok(aResult == "https://example.com/tests/dom/security/test/csp/file_uir_top_nav_dummy.html" ||
++     aResult == "http://test1.example.com/tests/dom/security/test/csp/file_uir_top_nav_dummy.html",
++     "same origin should be upgraded to https, cross origin should remain http");
++  if (++testCounter < totalTests) {
++    return;
++  }
++  window.removeEventListener("message", receiveMessage);
++  SimpleTest.finish();
++}
++
++window.addEventListener("message", receiveMessage);
++function receiveMessage(event) {
++  checkResults(event.data.result);
++}
++
++document.getElementById("testframe").src =
++  "https://example.com/tests/dom/security/test/csp/file_uir_top_nav.html";
++
++</script>
++</body>
++</html>

+ 453 - 0
frg/253-58/mozilla-release58_427934.patch

@@ -0,0 +1,453 @@
+# HG changeset patch
+# User Cervantes Yu <cyu@mozilla.com>
+# Date 1503303869 -28800
+#      Mon Aug 21 16:24:29 2017 +0800
+# Node ID a8bf3954befdd08ed7e60cd863d755b244f19333
+# Parent  5694daa9561e8625796400ed829c87a97b319089
+Bug 1320134 - Part 4: Remove the debug patches for running out of TLS slots on Windows. r=froydnj
+
+Revert revision f760842b14a2, 051b765ca8f2 and 01125b5142e5 since the original
+bug that we run out of TLS slots on Windows is no longer showing up after
+firefox55. It should have been fixed elsewhere, very likely in the rust part.
+
+MozReview-Commit-ID: 9j5hFSGT3OE
+
+diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp
+--- a/toolkit/crashreporter/nsExceptionHandler.cpp
++++ b/toolkit/crashreporter/nsExceptionHandler.cpp
+@@ -20,20 +20,16 @@
+ #include "mozilla/TimeStamp.h"
+ #include "mozilla/ipc/CrashReporterClient.h"
+ 
+ #include "nsThreadUtils.h"
+ #include "nsXULAppAPI.h"
+ #include "jsfriendapi.h"
+ #include "ThreadAnnotation.h"
+ 
+-#ifdef XP_WIN
+-#include "mozilla/TlsAllocationTracker.h"
+-#endif
+-
+ #if defined(XP_WIN32)
+ #ifdef WIN32_LEAN_AND_MEAN
+ #undef WIN32_LEAN_AND_MEAN
+ #endif
+ 
+ #include "nsXULAppAPI.h"
+ #include "nsIXULAppInfo.h"
+ #include "nsIWindowsRegKey.h"
+@@ -1423,23 +1419,16 @@ PrepareChildExceptionTimeAnnotations()
+     if (gTopPendingIPCName) {
+       WriteAnnotation(apiData, "TopPendingIPCName", gTopPendingIPCName);
+     }
+     if (topPendingIPCTypeBuffer[2]) {
+       WriteAnnotation(apiData, "TopPendingIPCType", topPendingIPCTypeBuffer);
+     }
+   }
+ 
+-#ifdef XP_WIN
+-  const char* tlsAllocations = mozilla::GetTlsAllocationStacks();
+-  if (tlsAllocations) {
+-    WriteAnnotation(apiData, "TlsAllocations", tlsAllocations);
+-  }
+-#endif
+-
+   std::function<void(const char*)> getThreadAnnotationCB =
+     [&] (const char * aAnnotation) -> void {
+     if (aAnnotation) {
+       WriteLiteral(apiData, "ThreadIdNameMapping=");
+       WriteString(apiData, aAnnotation);
+       WriteLiteral(apiData, "\n");
+     }
+   };
+diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp
+--- a/toolkit/xre/nsEmbedFunctions.cpp
++++ b/toolkit/xre/nsEmbedFunctions.cpp
+@@ -21,17 +21,16 @@
+ #include "nsIFile.h"
+ #include "nsIToolkitChromeRegistry.h"
+ #include "nsIToolkitProfile.h"
+ 
+ #ifdef XP_WIN
+ #include <process.h>
+ #include <shobjidl.h>
+ #include "mozilla/ipc/WindowsMessageLoop.h"
+-#include "mozilla/TlsAllocationTracker.h"
+ #endif
+ 
+ #include "nsAppDirectoryServiceDefs.h"
+ #include "nsAppRunner.h"
+ #include "nsAutoRef.h"
+ #include "nsDirectoryServiceDefs.h"
+ #include "nsExceptionHandler.h"
+ #include "nsString.h"
+@@ -361,24 +360,16 @@ XRE_InitChildProcess(int aArgc,
+ #endif
+ 
+ #ifdef MOZ_JPROF
+   // Call the code to install our handler
+   setupProfilingStuff();
+ #endif
+ 
+ #if defined(XP_WIN)
+-#ifndef DEBUG
+-  // XXX Bug 1320134: added for diagnosing the crashes because we're running out
+-  // of TLS indices on Windows. Remove after the root cause is found.
+-  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+-    mozilla::InitTlsAllocationTracker();
+-  }
+-#endif
+-
+   // From the --attach-console support in nsNativeAppSupportWin.cpp, but
+   // here we are a content child process, so we always attempt to attach
+   // to the parent's (ie, the browser's) console.
+   // Try to attach console to the parent process.
+   // It will succeed when the parent process is a command line,
+   // so that stdio will be displayed in it.
+   if (AttachConsole(ATTACH_PARENT_PROCESS)) {
+     // Change std handles to refer to new console handles.
+@@ -705,24 +696,16 @@ XRE_InitChildProcess(int aArgc,
+ 
+ #if defined(XP_MACOSX)
+       // Everybody should be done using shared memory by now.
+       mozilla::ipc::SharedMemoryBasic::Shutdown();
+ #endif
+     }
+   }
+ 
+-#if defined(XP_WIN) && !defined(DEBUG)
+-  // XXX Bug 1320134: added for diagnosing the crashes because we're running out
+-  // of TLS indices on Windows. Remove after the root cause is found.
+-  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+-    mozilla::ShutdownTlsAllocationTracker();
+-  }
+-#endif
+-
+   return XRE_DeinitCommandLine();
+ }
+ 
+ MessageLoop*
+ XRE_GetIOMessageLoop()
+ {
+   if (sChildProcessType == GeckoProcessType_Default) {
+     return BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO);
+diff --git a/xpcom/build/TlsAllocationTracker.cpp b/xpcom/build/TlsAllocationTracker.cpp
+deleted file mode 100644
+--- a/xpcom/build/TlsAllocationTracker.cpp
++++ /dev/null
+@@ -1,250 +0,0 @@
+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+-/* 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/. */
+-
+-#include "TlsAllocationTracker.h"
+-
+-#include <stdint.h>
+-
+-#include <windows.h>
+-
+-#include "mozilla/Atomics.h"
+-#include "mozilla/JSONWriter.h"
+-#include "mozilla/Move.h"
+-#include "mozilla/StackWalk.h"
+-#include "mozilla/StaticMutex.h"
+-#include "mozilla/StaticPtr.h"
+-
+-#include "nsDebug.h"
+-#include "nsHashKeys.h"
+-#include "nsString.h"
+-#include "nsTArray.h"
+-#include "nsTHashtable.h"
+-#include "nsWindowsDllInterceptor.h"
+-
+-namespace mozilla {
+-namespace {
+-
+-static StaticAutoPtr<nsCString> sTlsAllocationStacks;
+-
+-struct nsCStringWriter : public JSONWriteFunc {
+-  explicit nsCStringWriter(nsCString* aData)
+-    : mData(aData)
+-  {
+-    MOZ_ASSERT(mData);
+-  }
+-
+-  void Write(const char* aStr)
+-  {
+-    mData->AppendASCII(aStr);
+-  }
+-
+-  nsCString* mData;
+-};
+-
+-// Start recording TlsAlloc() call stacks when we observed kStartTrackingTlsAt
+-// allocations. We choose this value close to the maximum number of TLS indexes
+-// in a Windows process, which is 1088, in the hope of catching TLS leaks
+-// without impacting normal users.
+-const uint32_t kStartTrackingTlsAt = 950;
+-
+-using stack_t = nsTArray<uintptr_t>;
+-
+-struct StackEntry : public nsUint32HashKey {
+-  explicit StackEntry(KeyTypePointer aKey)
+-    : nsUint32HashKey(aKey)
+-  { }
+-
+-  stack_t mStack;
+-};
+-
+-using stacks_t = nsTHashtable<StackEntry>;
+-
+-static StaticAutoPtr<stacks_t> sRecentTlsAllocationStacks;
+-
+-static Atomic<bool> sInitialized;
+-static StaticMutex sMutex;
+-static Atomic<uint32_t> sCurrentTlsSlots{0};
+-
+-using TlsAllocFn = DWORD (WINAPI *)();
+-using TlsFreeFn = BOOL (WINAPI *)(DWORD);
+-
+-TlsAllocFn gOriginalTlsAlloc;
+-TlsFreeFn gOriginalTlsFree;
+-
+-static void
+-MaybeRecordCurrentStack(DWORD aTlsIndex)
+-{
+-  if (sCurrentTlsSlots < kStartTrackingTlsAt) {
+-    return;
+-  }
+-
+-  stack_t rawStack;
+-  auto callback = [](uint32_t, void* aPC, void*, void* aClosure) {
+-    auto stack = static_cast<stack_t*>(aClosure);
+-    stack->AppendElement(reinterpret_cast<uintptr_t>(aPC));
+-  };
+-  MozStackWalk(callback, /* skip 2 frames */ 2, /* maxFrames */ 0, &rawStack);
+-
+-  StaticMutexAutoLock lock(sMutex);
+-  if (!sRecentTlsAllocationStacks) {
+-    return;
+-  }
+-
+-  StackEntry* stack = sRecentTlsAllocationStacks->PutEntry(aTlsIndex);
+-
+-  MOZ_ASSERT(!stack->mStack.IsEmpty());
+-  stack->mStack = Move(rawStack);
+-}
+-
+-static void
+-MaybeDeleteRecordedStack(DWORD aTlsIndex)
+-{
+-  StaticMutexAutoLock lock(sMutex);
+-  if (!sRecentTlsAllocationStacks) {
+-    return;
+-  }
+-
+-  auto entry = sRecentTlsAllocationStacks->GetEntry(aTlsIndex);
+-  if (entry) {
+-    sRecentTlsAllocationStacks->RemoveEntry(aTlsIndex);
+-  }
+-}
+-
+-
+-static void
+-AnnotateRecentTlsStacks()
+-{
+-  StaticMutexAutoLock lock(sMutex);
+-  if (!sRecentTlsAllocationStacks) {
+-    // Maybe another thread steals the stack vector content and is dumping the
+-    // stacks
+-    return;
+-  }
+-
+-  // Move the content to prevent further requests to this function.
+-  UniquePtr<stacks_t> stacks = MakeUnique<stacks_t>();
+-  sRecentTlsAllocationStacks->SwapElements(*stacks.get());
+-  sRecentTlsAllocationStacks = nullptr;
+-
+-  sTlsAllocationStacks = new nsCString();
+-  JSONWriter output(
+-    MakeUnique<nsCStringWriter, nsCString*>(sTlsAllocationStacks.get()));
+-
+-  output.Start(JSONWriter::SingleLineStyle);
+-  for (auto iter = stacks->Iter(); !iter.Done(); iter.Next()) {
+-    const stack_t& stack = iter.Get()->mStack;
+-
+-    output.StartArrayElement();
+-    for (auto pc : stack) {
+-      output.IntElement(pc);
+-    }
+-    output.EndArray();
+-  }
+-  output.End();
+-}
+-
+-DWORD WINAPI
+-InterposedTlsAlloc()
+-{
+-  if (!sInitialized) {
+-    // Don't interpose if we didn't fully initialize both hooks or after we
+-    // already shutdown the tracker.
+-    return gOriginalTlsAlloc();
+-  }
+-
+-  sCurrentTlsSlots += 1;
+-
+-  DWORD tlsAllocRv = gOriginalTlsAlloc();
+-
+-  MaybeRecordCurrentStack(tlsAllocRv);
+-
+-  if (tlsAllocRv == TLS_OUT_OF_INDEXES) {
+-    AnnotateRecentTlsStacks();
+-  }
+-
+-  return tlsAllocRv;
+-}
+-
+-BOOL WINAPI
+-InterposedTlsFree(DWORD aTlsIndex)
+-{
+-  if (!sInitialized) {
+-    // Don't interpose if we didn't fully initialize both hooks or after we
+-    // already shutdown the tracker.
+-    return gOriginalTlsFree(aTlsIndex);
+-  }
+-
+-  sCurrentTlsSlots -= 1;
+-
+-  MaybeDeleteRecordedStack(aTlsIndex);
+-
+-  return gOriginalTlsFree(aTlsIndex);
+-}
+-
+-}  // Anonymous namespace.
+-
+-void
+-InitTlsAllocationTracker()
+-{
+-  if (sInitialized) {
+-    return;
+-  }
+-
+-  sRecentTlsAllocationStacks = new stacks_t();
+-
+-  // Windows DLL interceptor
+-  static WindowsDllInterceptor sKernel32DllInterceptor{};
+-
+-  // Initialize dll interceptor and add hook.
+-  sKernel32DllInterceptor.Init("kernel32.dll");
+-  bool succeeded = sKernel32DllInterceptor.AddHook(
+-    "TlsAlloc",
+-    reinterpret_cast<intptr_t>(InterposedTlsAlloc),
+-    reinterpret_cast<void**>(&gOriginalTlsAlloc));
+-
+-  if (!succeeded) {
+-    return;
+-  }
+-
+-  succeeded = sKernel32DllInterceptor.AddHook(
+-    "TlsFree",
+-    reinterpret_cast<intptr_t>(InterposedTlsFree),
+-    reinterpret_cast<void**>(&gOriginalTlsFree));
+-
+-  if (!succeeded) {
+-    return;
+-  }
+-
+-  sInitialized = true;
+-}
+-
+-const char*
+-GetTlsAllocationStacks()
+-{
+-  StaticMutexAutoLock lock(sMutex);
+-
+-  if (!sTlsAllocationStacks) {
+-    return nullptr;
+-  }
+-
+-  return sTlsAllocationStacks->BeginReading();
+-}
+-
+-void
+-ShutdownTlsAllocationTracker()
+-{
+-  if (!sInitialized) {
+-    return;
+-  }
+-  sInitialized = false;
+-
+-  StaticMutexAutoLock lock(sMutex);
+-
+-  sRecentTlsAllocationStacks = nullptr;
+-  sTlsAllocationStacks = nullptr;
+-}
+-
+-}  // namespace mozilla
+diff --git a/xpcom/build/TlsAllocationTracker.h b/xpcom/build/TlsAllocationTracker.h
+deleted file mode 100644
+--- a/xpcom/build/TlsAllocationTracker.h
++++ /dev/null
+@@ -1,27 +0,0 @@
+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+-/* 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/. */
+-
+-#ifndef mozilla_TlsAllocationTracker_h
+-#define mozilla_TlsAllocationTracker_h
+-
+-#include <string>
+-
+-#include "mozilla/Types.h"
+-
+-namespace mozilla {
+-
+-void
+-InitTlsAllocationTracker();
+-
+-const char*
+-GetTlsAllocationStacks();
+-
+-void
+-ShutdownTlsAllocationTracker();
+-
+-}
+-
+-#endif
+diff --git a/xpcom/build/moz.build b/xpcom/build/moz.build
+--- a/xpcom/build/moz.build
++++ b/xpcom/build/moz.build
+@@ -17,29 +17,27 @@ EXPORTS += [
+ EXPORTS.mozilla += [
+     'FileLocation.h',
+     'IOInterposer.h',
+     'LateWriteChecks.h',
+     'Omnijar.h',
+     'PoisonIOInterposer.h',
+     'ServiceList.h',
+     'Services.h',
+-    'TlsAllocationTracker.h',
+     'XPCOM.h',
+     'XREAppData.h',
+ ]
+ 
+ if CONFIG['OS_ARCH'] == 'WINNT':
+     EXPORTS += ['nsWindowsDllInterceptor.h']
+     EXPORTS.mozilla += ['perfprobe.h']
+     SOURCES += [
+         'perfprobe.cpp',
+         'PoisonIOInterposerBase.cpp',
+         'PoisonIOInterposerWin.cpp',
+-        'TlsAllocationTracker.cpp',
+     ]
+ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+     UNIFIED_SOURCES += [
+         'PoisonIOInterposerBase.cpp',
+         'PoisonIOInterposerMac.cpp',
+     ]
+     SOURCES += ['mach_override.c']
+     SOURCES['mach_override.c'].flags += ['-Wno-unused-function']

+ 266 - 0
frg/253-58/mozilla-release58_427937.patch

@@ -0,0 +1,266 @@
+# HG changeset patch
+# User Stone Shih <sshih@mozilla.com>
+# Date 1502604528 -28800
+#      Sun Aug 13 14:08:48 2017 +0800
+# Node ID 1edccf6d5a8a2eb9a71be9365ce405b6065be587
+# Parent  11fee246739a657020aa2b6b85ebbacecf11fd74
+Bug 1361067 Part1: Refactor coalescing mouse wheel events. r=smaug.
+
+MozReview-Commit-ID: 3NJJ77zAxNJ
+
+diff --git a/dom/ipc/CoalescedInputData.h b/dom/ipc/CoalescedInputData.h
+new file mode 100644
+--- /dev/null
++++ b/dom/ipc/CoalescedInputData.h
+@@ -0,0 +1,65 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* 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/. */
++
++#ifndef mozilla_dom_CoalescedInputData_h
++#define mozilla_dom_CoalescedInputData_h
++
++#include "mozilla/UniquePtr.h"
++#include "FrameMetrics.h"
++
++namespace mozilla {
++namespace dom {
++
++template<class InputEventType>
++class CoalescedInputData
++{
++protected:
++  typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
++
++  UniquePtr<InputEventType> mCoalescedInputEvent;
++  ScrollableLayerGuid mGuid;
++  uint64_t mInputBlockId;
++
++public:
++  CoalescedInputData()
++    : mInputBlockId(0)
++  {
++  }
++
++  void Reset()
++  {
++    mCoalescedInputEvent = nullptr;
++  }
++
++  bool IsEmpty()
++  {
++    return !mCoalescedInputEvent;
++  }
++
++  bool CanCoalesce(const InputEventType& aEvent,
++                   const ScrollableLayerGuid& aGuid,
++                   const uint64_t& aInputBlockId);
++
++  const InputEventType* GetCoalescedEvent()
++  {
++    return mCoalescedInputEvent.get();
++  }
++
++  ScrollableLayerGuid GetScrollableLayerGuid()
++  {
++    return mGuid;
++  }
++
++  uint64_t GetInputBlockId()
++  {
++    return mInputBlockId;
++  }
++};
++
++} // namespace dom
++} // namespace mozilla
++
++#endif // mozilla_dom_CoalescedInputData_h
+diff --git a/dom/ipc/CoalescedWheelData.cpp b/dom/ipc/CoalescedWheelData.cpp
+--- a/dom/ipc/CoalescedWheelData.cpp
++++ b/dom/ipc/CoalescedWheelData.cpp
+@@ -1,52 +1,51 @@
+ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim: set ts=8 sts=2 et sw=2 tw=80: */
+ /* 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/. */
+ #include "base/basictypes.h"
+ 
+ #include "CoalescedWheelData.h"
+-#include "FrameMetrics.h"
+ 
+ using namespace mozilla;
+ using namespace mozilla::dom;
+ 
+ void
+ CoalescedWheelData::Coalesce(const WidgetWheelEvent& aEvent,
+                              const ScrollableLayerGuid& aGuid,
+                              const uint64_t& aInputBlockId)
+ {
+   if (IsEmpty()) {
+-    mCoalescedWheelEvent = MakeUnique<WidgetWheelEvent>(aEvent);
++    mCoalescedInputEvent = MakeUnique<WidgetWheelEvent>(aEvent);
+     mGuid = aGuid;
+     mInputBlockId = aInputBlockId;
+   } else {
+     MOZ_ASSERT(mGuid == aGuid);
+     MOZ_ASSERT(mInputBlockId == aInputBlockId);
+-    MOZ_ASSERT(mCoalescedWheelEvent->mModifiers == aEvent.mModifiers);
+-    MOZ_ASSERT(mCoalescedWheelEvent->mDeltaMode == aEvent.mDeltaMode);
+-    MOZ_ASSERT(mCoalescedWheelEvent->mCanTriggerSwipe ==
++    MOZ_ASSERT(mCoalescedInputEvent->mModifiers == aEvent.mModifiers);
++    MOZ_ASSERT(mCoalescedInputEvent->mDeltaMode == aEvent.mDeltaMode);
++    MOZ_ASSERT(mCoalescedInputEvent->mCanTriggerSwipe ==
+                aEvent.mCanTriggerSwipe);
+-    mCoalescedWheelEvent->mDeltaX += aEvent.mDeltaX;
+-    mCoalescedWheelEvent->mDeltaY += aEvent.mDeltaY;
+-    mCoalescedWheelEvent->mDeltaZ += aEvent.mDeltaZ;
+-    mCoalescedWheelEvent->mLineOrPageDeltaX += aEvent.mLineOrPageDeltaX;
+-    mCoalescedWheelEvent->mLineOrPageDeltaY += aEvent.mLineOrPageDeltaY;
+-    mCoalescedWheelEvent->mTimeStamp = aEvent.mTimeStamp;
++    mCoalescedInputEvent->mDeltaX += aEvent.mDeltaX;
++    mCoalescedInputEvent->mDeltaY += aEvent.mDeltaY;
++    mCoalescedInputEvent->mDeltaZ += aEvent.mDeltaZ;
++    mCoalescedInputEvent->mLineOrPageDeltaX += aEvent.mLineOrPageDeltaX;
++    mCoalescedInputEvent->mLineOrPageDeltaY += aEvent.mLineOrPageDeltaY;
++    mCoalescedInputEvent->mTimeStamp = aEvent.mTimeStamp;
+   }
+ }
+ 
+ bool
+ CoalescedWheelData::CanCoalesce(const WidgetWheelEvent& aEvent,
+                                 const ScrollableLayerGuid& aGuid,
+                                 const uint64_t& aInputBlockId)
+ {
+   MOZ_ASSERT(!IsEmpty());
+-  return !mCoalescedWheelEvent ||
+-         (mCoalescedWheelEvent->mRefPoint == aEvent.mRefPoint &&
+-          mCoalescedWheelEvent->mModifiers == aEvent.mModifiers &&
+-          mCoalescedWheelEvent->mDeltaMode == aEvent.mDeltaMode &&
+-          mCoalescedWheelEvent->mCanTriggerSwipe == aEvent.mCanTriggerSwipe &&
++  return !mCoalescedInputEvent ||
++         (mCoalescedInputEvent->mRefPoint == aEvent.mRefPoint &&
++          mCoalescedInputEvent->mModifiers == aEvent.mModifiers &&
++          mCoalescedInputEvent->mDeltaMode == aEvent.mDeltaMode &&
++          mCoalescedInputEvent->mCanTriggerSwipe == aEvent.mCanTriggerSwipe &&
+           mGuid == aGuid &&
+           mInputBlockId == aInputBlockId);
+ }
+diff --git a/dom/ipc/CoalescedWheelData.h b/dom/ipc/CoalescedWheelData.h
+--- a/dom/ipc/CoalescedWheelData.h
++++ b/dom/ipc/CoalescedWheelData.h
+@@ -2,66 +2,30 @@
+ /* vim: set ts=8 sts=2 et sw=2 tw=80: */
+ /* 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/. */
+ 
+ #ifndef mozilla_dom_CoalescedWheelData_h
+ #define mozilla_dom_CoalescedWheelData_h
+ 
++#include "CoalescedInputData.h"
+ #include "mozilla/MouseEvents.h"
+-#include "mozilla/UniquePtr.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+-class CoalescedWheelData final
++class CoalescedWheelData final : public CoalescedInputData<WidgetWheelEvent>
+ {
+-protected:
+-  typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
+-
+ public:
+-  UniquePtr<WidgetWheelEvent> mCoalescedWheelEvent;
+-  ScrollableLayerGuid mGuid;
+-  uint64_t mInputBlockId;
+-
+-  CoalescedWheelData()
+-    : mInputBlockId(0)
+-  {
+-  }
+-
+   void Coalesce(const WidgetWheelEvent& aEvent,
+                 const ScrollableLayerGuid& aGuid,
+                 const uint64_t& aInputBlockId);
+-  void Reset()
+-  {
+-    mCoalescedWheelEvent = nullptr;
+-  }
+-
+-  bool IsEmpty()
+-  {
+-    return !mCoalescedWheelEvent;
+-  }
+ 
+   bool CanCoalesce(const WidgetWheelEvent& aEvent,
+                    const ScrollableLayerGuid& aGuid,
+                    const uint64_t& aInputBlockId);
+-
+-  const WidgetWheelEvent* GetCoalescedWheelEvent()
+-  {
+-    return mCoalescedWheelEvent.get();
+-  }
+-
+-  ScrollableLayerGuid GetScrollableLayerGuid()
+-  {
+-    return mGuid;
+-  }
+-
+-  uint64_t GetInputBlockId()
+-  {
+-    return mInputBlockId;
+-  }
+ };
+ 
+ } // namespace dom
+ } // namespace mozilla
+ 
+ #endif // mozilla_dom_CoalescedWheelData_h
+diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp
+--- a/dom/ipc/TabChild.cpp
++++ b/dom/ipc/TabChild.cpp
+@@ -1690,17 +1690,17 @@ TabChild::DispatchWidgetEventViaAPZ(Widg
+ 
+ void
+ TabChild::MaybeDispatchCoalescedWheelEvent()
+ {
+   if (mCoalescedWheelData.IsEmpty()) {
+     return;
+   }
+   const WidgetWheelEvent* wheelEvent =
+-    mCoalescedWheelData.GetCoalescedWheelEvent();
++    mCoalescedWheelData.GetCoalescedEvent();
+   MOZ_ASSERT(wheelEvent);
+   DispatchWheelEvent(*wheelEvent,
+                      mCoalescedWheelData.GetScrollableLayerGuid(),
+                      mCoalescedWheelData.GetInputBlockId());
+   mCoalescedWheelData.Reset();
+ }
+ 
+ void
+diff --git a/dom/ipc/moz.build b/dom/ipc/moz.build
+--- a/dom/ipc/moz.build
++++ b/dom/ipc/moz.build
+@@ -14,16 +14,17 @@ XPIDL_SOURCES += [
+ XPIDL_MODULE = 'dom'
+ 
+ EXPORTS.mozilla.dom.ipc += [
+     'IdType.h',
+     'StructuredCloneData.h',
+ ]
+ 
+ EXPORTS.mozilla.dom += [
++    'CoalescedInputData.h',
+     'CoalescedWheelData.h',
+     'ContentBridgeChild.h',
+     'ContentBridgeParent.h',
+     'ContentChild.h',
+     'ContentParent.h',
+     'ContentPrefs.h',
+     'ContentProcess.h',
+     'ContentProcessManager.h',

+ 623 - 0
frg/253-58/mozilla-release58_427938.patch

@@ -0,0 +1,623 @@
+# HG changeset patch
+# User Stone Shih <sshih@mozilla.com>
+# Date 1502434688 -28800
+#      Fri Aug 11 14:58:08 2017 +0800
+# Node ID 64edaaccec973cd3b0d2aeea1f565d65e8614ea3
+# Parent  8b2a6f9dae4c3173e7d7598b5cb53258c243f338
+Bug 1361067 Part2: Coalesce mouse move events to be once per refresh cycle. r=smaug.
+
+MozReview-Commit-ID: 6jwQxxNIC2n
+
+diff --git a/dom/base/FlushType.h b/dom/base/FlushType.h
+--- a/dom/base/FlushType.h
++++ b/dom/base/FlushType.h
+@@ -16,30 +16,30 @@ namespace mozilla {
+  * This is the enum used by nsIDocument::FlushPendingNotifications to
+  * decide what to flush.
+  *
+  * Please note that if you change these values, you should sync it with the
+  * flushTypeNames array inside PresShell::FlushPendingNotifications.
+  */
+ enum class FlushType : uint8_t {
+   None             = 0, /* Actually don't flush anything */
+-  Content          = 1, /* flush the content model construction */
+-  ContentAndNotify = 2, /* As above, plus flush the frame model
++  Event            = 1, /* Flush pending events before notify other observers */
++  Content          = 2, /* flush the content model construction */
++  ContentAndNotify = 3, /* As above, plus flush the frame model
+                            construction and other nsIMutationObserver
+                            notifications. */
+-  Style            = 3, /* As above, plus flush style reresolution */
++  Style            = 4, /* As above, plus flush style reresolution */
+   Frames           = Style,
+-  EnsurePresShellInitAndFrames = 4, /* As above, plus ensure the pres shell is alive */
+-  InterruptibleLayout = 5, /* As above, plus flush reflow,
++  EnsurePresShellInitAndFrames = 5, /* As above, plus ensure the pres shell is alive */
++  InterruptibleLayout = 6, /* As above, plus flush reflow,
+                               but allow it to be interrupted (so
+                               an incomplete layout may result) */
+-  Layout           = 6, /* As above, but layout must run to
++  Layout           = 7, /* As above, but layout must run to
+                            completion */
+-  Display          = 7, /* As above, plus flush painting */
+-
++  Display          = 8, /* As above, plus flush painting */
+   Count
+ };
+ 
+ struct ChangesToFlush {
+   ChangesToFlush(FlushType aFlushType, bool aFlushAnimations)
+     : mFlushType(aFlushType)
+     , mFlushAnimations(aFlushAnimations)
+   {}
+diff --git a/dom/ipc/CoalescedMouseData.cpp b/dom/ipc/CoalescedMouseData.cpp
+new file mode 100644
+--- /dev/null
++++ b/dom/ipc/CoalescedMouseData.cpp
+@@ -0,0 +1,98 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* 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/. */
++#include "base/basictypes.h"
++
++#include "CoalescedMouseData.h"
++#include "TabChild.h"
++
++using namespace mozilla;
++using namespace mozilla::dom;
++
++void
++CoalescedMouseData::Coalesce(const WidgetMouseEvent& aEvent,
++                             const ScrollableLayerGuid& aGuid,
++                             const uint64_t& aInputBlockId)
++{
++  if (IsEmpty()) {
++    mCoalescedInputEvent = MakeUnique<WidgetMouseEvent>(aEvent);
++    mGuid = aGuid;
++    mInputBlockId = aInputBlockId;
++  } else {
++    MOZ_ASSERT(mGuid == aGuid);
++    MOZ_ASSERT(mInputBlockId == aInputBlockId);
++    MOZ_ASSERT(mCoalescedInputEvent->mModifiers == aEvent.mModifiers);
++    MOZ_ASSERT(mCoalescedInputEvent->mReason == aEvent.mReason);
++    MOZ_ASSERT(mCoalescedInputEvent->inputSource == aEvent.inputSource);
++
++    // Assuming button changes should trigger other mouse events and dispatch
++    // the coalesced mouse move events.
++    MOZ_ASSERT(mCoalescedInputEvent->button == aEvent.button);
++    MOZ_ASSERT(mCoalescedInputEvent->buttons == aEvent.buttons);
++    mCoalescedInputEvent->mTimeStamp = aEvent.mTimeStamp;
++    mCoalescedInputEvent->mRefPoint = aEvent.mRefPoint;
++    mCoalescedInputEvent->pressure = aEvent.pressure;
++    mCoalescedInputEvent->AssignPointerHelperData(aEvent);
++  }
++}
++
++bool
++CoalescedMouseData::CanCoalesce(const WidgetMouseEvent& aEvent,
++                             const ScrollableLayerGuid& aGuid,
++                             const uint64_t& aInputBlockId)
++{
++  return !mCoalescedInputEvent ||
++         (mCoalescedInputEvent->mModifiers == aEvent.mModifiers &&
++          mCoalescedInputEvent->inputSource == aEvent.inputSource &&
++          mCoalescedInputEvent->pointerId == aEvent.pointerId &&
++          mGuid == aGuid &&
++          mInputBlockId == aInputBlockId);
++}
++
++
++void
++CoalescedMouseMoveFlusher::WillRefresh(mozilla::TimeStamp aTime)
++{
++  MOZ_ASSERT(mRefreshDriver);
++  mTabChild->MaybeDispatchCoalescedMouseMoveEvents();
++  RemoveObserver();
++}
++
++void
++CoalescedMouseMoveFlusher::StartObserver()
++{
++  nsRefreshDriver* refreshDriver = GetRefreshDriver();
++  if (mRefreshDriver && mRefreshDriver == refreshDriver) {
++    // Nothing to do if we already added an observer and it's same refresh driver.
++    return;
++  }
++  RemoveObserver();
++  if (refreshDriver) {
++    mRefreshDriver = refreshDriver;
++    DebugOnly<bool> success =
++      mRefreshDriver->AddRefreshObserver(this, FlushType::Event);
++    MOZ_ASSERT(success);
++  }
++}
++
++void
++CoalescedMouseMoveFlusher::RemoveObserver()
++{
++  if (mRefreshDriver) {
++    mRefreshDriver->RemoveRefreshObserver(this, FlushType::Event);
++    mRefreshDriver = nullptr;
++  }
++}
++
++nsRefreshDriver*
++CoalescedMouseMoveFlusher::GetRefreshDriver()
++{
++  nsCOMPtr<nsIPresShell> presShell = mTabChild->GetPresShell();
++  if (!presShell || !presShell->GetPresContext() ||
++      !presShell->GetPresContext()->RefreshDriver()) {
++    return nullptr;
++  }
++  return presShell->GetPresContext()->RefreshDriver();
++}
+diff --git a/dom/ipc/CoalescedMouseData.h b/dom/ipc/CoalescedMouseData.h
+new file mode 100644
+--- /dev/null
++++ b/dom/ipc/CoalescedMouseData.h
+@@ -0,0 +1,58 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* 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/. */
++
++#ifndef mozilla_dom_CoalescedMouseData_h
++#define mozilla_dom_CoalescedMouseData_h
++
++#include "CoalescedInputData.h"
++#include "mozilla/MouseEvents.h"
++#include "nsRefreshDriver.h"
++
++namespace mozilla {
++namespace dom {
++
++class CoalescedMouseData final : public CoalescedInputData<WidgetMouseEvent>
++{
++public:
++  void Coalesce(const WidgetMouseEvent& aEvent,
++                const ScrollableLayerGuid& aGuid,
++                const uint64_t& aInputBlockId);
++
++  bool CanCoalesce(const WidgetMouseEvent& aEvent,
++                   const ScrollableLayerGuid& aGuid,
++                   const uint64_t& aInputBlockId);
++};
++
++class CoalescedMouseMoveFlusher final : public nsARefreshObserver {
++public:
++  explicit CoalescedMouseMoveFlusher(TabChild* aTabChild)
++    : mTabChild(aTabChild)
++  {
++    MOZ_ASSERT(mTabChild);
++  }
++
++  virtual void WillRefresh(mozilla::TimeStamp aTime) override;
++
++  NS_INLINE_DECL_REFCOUNTING(CoalescedMouseMoveFlusher, override)
++
++  void StartObserver();
++  void RemoveObserver();
++
++private:
++  ~CoalescedMouseMoveFlusher() {
++    RemoveObserver();
++  }
++
++  nsRefreshDriver* GetRefreshDriver();
++
++  TabChild* mTabChild;
++  RefPtr<nsRefreshDriver> mRefreshDriver;
++};
++
++} // namespace dom
++} // namespace mozilla
++
++#endif // mozilla_dom_CoalescedMouseData_h
+diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp
+--- a/dom/ipc/TabChild.cpp
++++ b/dom/ipc/TabChild.cpp
+@@ -448,16 +448,21 @@ TabChild::TabChild(nsIContentChild* aMan
+     }
+   };
+ 
+   // preloaded TabChild should not be added to child map
+   if (mUniqueId) {
+     MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end());
+     NestedTabChildMap()[mUniqueId] = this;
+   }
++  mCoalesceMouseMoveEvents =
++    Preferences::GetBool("dom.event.coalesce_mouse_move");
++  if (mCoalesceMouseMoveEvents) {
++    mCoalescedMouseEventFlusher = new CoalescedMouseMoveFlusher(this);
++  }
+ }
+ 
+ bool
+ TabChild::AsyncPanZoomEnabled() const
+ {
+   // This might get called by the TouchEvent::PrefEnabled code before we have
+   // mCompositorOptions populated (bug 1370089). In that case we just assume
+   // APZ is enabled because we're in a content process (because TabChild) and
+@@ -1055,16 +1060,20 @@ TabChild::ProvideWindow(mozIDOMWindowPro
+                                    aLoadInfo,
+                                    aWindowIsNew,
+                                    aReturn);
+ }
+ 
+ void
+ TabChild::DestroyWindow()
+ {
++    if (mCoalescedMouseEventFlusher) {
++      mCoalescedMouseEventFlusher->RemoveObserver();
++      mCoalescedMouseEventFlusher = nullptr;
++    }
+     nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
+     if (baseWindow)
+         baseWindow->Destroy();
+ 
+     // NB: the order of mPuppetWidget->Destroy() and mRemoteFrame->Destroy()
+     // is important: we want to kill off remote layers before their
+     // frames
+     if (mPuppetWidget) {
+@@ -1575,22 +1584,52 @@ TabChild::RecvMouseEvent(const nsString&
+   APZCCallbackHelper::DispatchMouseEvent(GetPresShell(), aType,
+                                          CSSPoint(aX, aY), aButton, aClickCount,
+                                          aModifiers, aIgnoreRootScrollFrame,
+                                          nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN,
+                                          0 /* Use the default value here. */);
+   return IPC_OK();
+ }
+ 
++void
++TabChild::MaybeDispatchCoalescedMouseMoveEvents()
++{
++  if (!mCoalesceMouseMoveEvents || mCoalescedMouseData.IsEmpty()) {
++    return;
++  }
++  const WidgetMouseEvent* event = mCoalescedMouseData.GetCoalescedEvent();
++  MOZ_ASSERT(event);
++  // Dispatch the coalesced mousemove event. Using RecvRealMouseButtonEvent to
++  // bypass the coalesce handling in RecvRealMouseMoveEvent.
++  RecvRealMouseButtonEvent(*event,
++                           mCoalescedWheelData.GetScrollableLayerGuid(),
++                           mCoalescedWheelData.GetInputBlockId());
++  MOZ_ASSERT(mCoalescedMouseEventFlusher);
++  mCoalescedMouseData.Reset();
++  mCoalescedMouseEventFlusher->RemoveObserver();
++}
++
+ mozilla::ipc::IPCResult
+ TabChild::RecvRealMouseMoveEvent(const WidgetMouseEvent& aEvent,
+                                  const ScrollableLayerGuid& aGuid,
+                                  const uint64_t& aInputBlockId)
+ {
+-  if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) {
++  if (mCoalesceMouseMoveEvents) {
++    MOZ_ASSERT(mCoalescedMouseEventFlusher);
++    if (mCoalescedMouseData.CanCoalesce(aEvent, aGuid, aInputBlockId)) {
++      mCoalescedMouseData.Coalesce(aEvent, aGuid, aInputBlockId);
++      mCoalescedMouseEventFlusher->StartObserver();
++      return IPC_OK();
++    }
++    // Can't coalesce current mousemove event. Dispatch the coalesced mousemove
++    // event and coalesce the current one.
++    MaybeDispatchCoalescedMouseMoveEvents();
++    mCoalescedMouseData.Coalesce(aEvent, aGuid, aInputBlockId);
++    mCoalescedMouseEventFlusher->StartObserver();
++  } else if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) {
+     return IPC_FAIL_NO_REASON(this);
+   }
+   return IPC_OK();
+ }
+ 
+ mozilla::ipc::IPCResult
+ TabChild::RecvSynthMouseMoveEvent(const WidgetMouseEvent& aEvent,
+                                   const ScrollableLayerGuid& aGuid,
+@@ -1602,16 +1641,21 @@ TabChild::RecvSynthMouseMoveEvent(const 
+   return IPC_OK();
+ }
+ 
+ mozilla::ipc::IPCResult
+ TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
+                                    const ScrollableLayerGuid& aGuid,
+                                    const uint64_t& aInputBlockId)
+ {
++  if (aEvent.mMessage != eMouseMove) {
++    // Flush the coalesced mousemove event before dispatching other mouse
++    // events.
++    MaybeDispatchCoalescedMouseMoveEvents();
++  }
+   // Mouse events like eMouseEnterIntoWidget, that are created in the parent
+   // process EventStateManager code, have an input block id which they get from
+   // the InputAPZContext in the parent process stack. However, they did not
+   // actually go through the APZ code and so their mHandledByAPZ flag is false.
+   // Since thos events didn't go through APZ, we don't need to send
+   // notifications for them.
+   bool pendingLayerization = false;
+   if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
+diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h
+--- a/dom/ipc/TabChild.h
++++ b/dom/ipc/TabChild.h
+@@ -23,16 +23,17 @@
+ #include "nsFrameMessageManager.h"
+ #include "nsIPresShell.h"
+ #include "nsIScriptObjectPrincipal.h"
+ #include "nsWeakReference.h"
+ #include "nsITabChild.h"
+ #include "nsITooltipListener.h"
+ #include "mozilla/Attributes.h"
+ #include "mozilla/dom/TabContext.h"
++#include "mozilla/dom/CoalescedMouseData.h"
+ #include "mozilla/dom/CoalescedWheelData.h"
+ #include "mozilla/DOMEventTargetHelper.h"
+ #include "mozilla/EventDispatcher.h"
+ #include "mozilla/EventForwards.h"
+ #include "mozilla/layers/CompositorTypes.h"
+ #include "mozilla/layers/APZCCallbackHelper.h"
+ #include "mozilla/layers/CompositorOptions.h"
+ #include "nsIWebBrowserChrome3.h"
+@@ -65,16 +66,17 @@ namespace widget {
+ struct AutoCacheNativeKeyCommands;
+ } // namespace widget
+ 
+ namespace dom {
+ 
+ class TabChild;
+ class TabGroup;
+ class ClonedMessageData;
++class CoalescedMouseData;
+ class CoalescedWheelData;
+ 
+ class TabChildGlobal : public DOMEventTargetHelper,
+                        public nsIContentFrameMessageManager,
+                        public nsIScriptObjectPrincipal,
+                        public nsIGlobalObject,
+                        public nsSupportsWeakReference
+ {
+@@ -264,16 +266,17 @@ class TabChild final : public TabChildBa
+                        public nsSupportsWeakReference,
+                        public nsITabChild,
+                        public nsIObserver,
+                        public TabContext,
+                        public nsITooltipListener,
+                        public mozilla::ipc::IShmemAllocator
+ {
+   typedef mozilla::dom::ClonedMessageData ClonedMessageData;
++  typedef mozilla::dom::CoalescedMouseData CoalescedMouseData;
+   typedef mozilla::dom::CoalescedWheelData CoalescedWheelData;
+   typedef mozilla::layout::RenderFrameChild RenderFrameChild;
+   typedef mozilla::layers::APZEventState APZEventState;
+   typedef mozilla::layers::SetAllowedTouchBehaviorCallback SetAllowedTouchBehaviorCallback;
+ 
+ public:
+   /**
+    * Find TabChild of aTabId in the same content process of the
+@@ -680,16 +683,18 @@ public:
+   void RemovePendingDocShellBlocker();
+ 
+   // The HANDLE object for the widget this TabChild in.
+   WindowsHandle WidgetNativeData()
+   {
+     return mWidgetNativeData;
+   }
+ 
++  void MaybeDispatchCoalescedMouseMoveEvents();
++
+ protected:
+   virtual ~TabChild();
+ 
+   virtual PRenderFrameChild* AllocPRenderFrameChild() override;
+ 
+   virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) override;
+ 
+   virtual mozilla::ipc::IPCResult RecvDestroy() override;
+@@ -847,31 +852,34 @@ private:
+   // be skipped to not flood child process.
+   mozilla::TimeStamp mRepeatedKeyEventTime;
+ 
+   // Similar to mRepeatedKeyEventTime, store the end time (from parent process)
+   // of handling the last repeated wheel event so that in case event handling
+   // takes time, some repeated events can be skipped to not flood child process.
+   mozilla::TimeStamp mLastWheelProcessedTimeFromParent;
+   mozilla::TimeDuration mLastWheelProcessingDuration;
++  CoalescedMouseData mCoalescedMouseData;
+   CoalescedWheelData mCoalescedWheelData;
++  RefPtr<CoalescedMouseMoveFlusher> mCoalescedMouseEventFlusher;
+ 
+   RefPtr<layers::IAPZCTreeManager> mApzcTreeManager;
+ 
+   // The most recently seen layer observer epoch in RecvSetDocShellIsActive.
+   uint64_t mLayerObserverEpoch;
+ 
+ #if defined(XP_WIN) && defined(ACCESSIBILITY)
+   // The handle associated with the native window that contains this tab
+   uintptr_t mNativeWindowHandle;
+ #endif // defined(XP_WIN)
+ 
+ #if defined(ACCESSIBILITY)
+   PDocAccessibleChild* mTopLevelDocAccessibleChild;
+ #endif
++  bool mCoalesceMouseMoveEvents;
+ 
+   bool mPendingDocShellIsActive;
+   bool mPendingDocShellPreserveLayers;
+   bool mPendingDocShellReceivedMessage;
+   uint32_t mPendingDocShellBlockers;
+ 
+   WindowsHandle mWidgetNativeData;
+ 
+diff --git a/dom/ipc/moz.build b/dom/ipc/moz.build
+--- a/dom/ipc/moz.build
++++ b/dom/ipc/moz.build
+@@ -15,16 +15,17 @@ XPIDL_MODULE = 'dom'
+ 
+ EXPORTS.mozilla.dom.ipc += [
+     'IdType.h',
+     'StructuredCloneData.h',
+ ]
+ 
+ EXPORTS.mozilla.dom += [
+     'CoalescedInputData.h',
++    'CoalescedMouseData.h',
+     'CoalescedWheelData.h',
+     'ContentBridgeChild.h',
+     'ContentBridgeParent.h',
+     'ContentChild.h',
+     'ContentParent.h',
+     'ContentPrefs.h',
+     'ContentProcess.h',
+     'ContentProcessManager.h',
+@@ -45,16 +46,17 @@ EXPORTS.mozilla.dom += [
+ EXPORTS.mozilla += [
+     'PreallocatedProcessManager.h',
+     'ProcessHangMonitor.h',
+     'ProcessHangMonitorIPC.h',
+     'ProcessPriorityManager.h',
+ ]
+ 
+ UNIFIED_SOURCES += [
++    'CoalescedMouseData.cpp',
+     'CoalescedWheelData.cpp',
+     'ColorPickerParent.cpp',
+     'ContentBridgeChild.cpp',
+     'ContentBridgeParent.cpp',
+     'ContentParent.cpp',
+     'ContentPrefs.cpp',
+     'ContentProcess.cpp',
+     'ContentProcessManager.cpp',
+diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp
+--- a/layout/base/PresShell.cpp
++++ b/layout/base/PresShell.cpp
+@@ -4050,16 +4050,17 @@ PresShell::DoFlushPendingNotifications(m
+   FlushType flushType = aFlush.mFlushType;
+ 
+   MOZ_ASSERT(NeedFlush(flushType), "Why did we get called?");
+ 
+   static const EnumeratedArray<FlushType,
+                                FlushType::Count,
+                                const char*> flushTypeNames = {
+     "",
++    "Event",
+     "Content",
+     "ContentAndNotify",
+     // As far as the profiler is concerned, EnsurePresShellInitAndFrames and
+     // Frames are the same
+     "Style",
+     "Style",
+     "InterruptibleLayout",
+     "Layout",
+diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp
+--- a/layout/base/nsRefreshDriver.cpp
++++ b/layout/base/nsRefreshDriver.cpp
+@@ -1398,22 +1398,24 @@ nsRefreshDriver::ImageRequestCount() con
+   }
+   return count + mRequests.Count();
+ }
+ 
+ nsRefreshDriver::ObserverArray&
+ nsRefreshDriver::ArrayFor(FlushType aFlushType)
+ {
+   switch (aFlushType) {
++    case FlushType::Event:
++      return mObservers[0];
+     case FlushType::Style:
+-      return mObservers[0];
++      return mObservers[1];
+     case FlushType::Layout:
+-      return mObservers[1];
++      return mObservers[2];
+     case FlushType::Display:
+-      return mObservers[2];
++      return mObservers[3];
+     default:
+       MOZ_CRASH("We don't track refresh observers for this flush type");
+   }
+ }
+ 
+ /*
+  * nsITimerCallback implementation
+  */
+@@ -1812,17 +1814,17 @@ nsRefreshDriver::Tick(TimeStamp aNowTime
+       obs->WillRefresh(aNowTime);
+ 
+       if (!mPresContext || !mPresContext->GetPresShell()) {
+         StopTimer();
+         return;
+       }
+     }
+ 
+-    if (i == 0) {
++    if (i == 1) {
+       // This is the FlushType::Style case.
+ 
+       DispatchScrollEvents();
+       DispatchAnimationEvents();
+       DispatchPendingEvents();
+       RunFrameRequestCallbacks(aNowTime);
+ 
+       if (mPresContext && mPresContext->GetPresShell()) {
+@@ -1850,17 +1852,17 @@ nsRefreshDriver::Tick(TimeStamp aNowTime
+           // a layout flush).
+           nsPresContext* presContext = shell->GetPresContext();
+           if (presContext) {
+             presContext->NotifyFontFaceSetOnRefresh();
+           }
+           mNeedToRecomputeVisibility = true;
+         }
+       }
+-    } else if  (i == 1) {
++    } else if  (i == 2) {
+       // This is the FlushType::Layout case.
+       Maybe<AutoProfilerTracing> tracingLayoutFlush;
+       AutoTArray<nsIPresShell*, 16> observers;
+       observers.AppendElements(mLayoutFlushObservers);
+       for (uint32_t j = observers.Length();
+            j && mPresContext && mPresContext->GetPresShell(); --j) {
+         // Make sure to not process observers which might have been removed
+         // during previous iterations.
+diff --git a/layout/base/nsRefreshDriver.h b/layout/base/nsRefreshDriver.h
+--- a/layout/base/nsRefreshDriver.h
++++ b/layout/base/nsRefreshDriver.h
+@@ -453,17 +453,17 @@ private:
+   // The number is doubled every time the threshold is hit.
+   uint64_t mWarningThreshold;
+   mozilla::TimeStamp mMostRecentRefresh;
+   mozilla::TimeStamp mTickStart;
+   mozilla::TimeStamp mNextThrottledFrameRequestTick;
+   mozilla::TimeStamp mNextRecomputeVisibilityTick;
+ 
+   // separate arrays for each flush type we support
+-  ObserverArray mObservers[3];
++  ObserverArray mObservers[4];
+   RequestTable mRequests;
+   ImageStartTable mStartTable;
+   AutoTArray<nsCOMPtr<nsIRunnable>, 16> mEarlyRunners;
+   ScrollEventArray mScrollEvents;
+ 
+   struct PendingEvent {
+     nsCOMPtr<nsINode> mTarget;
+     nsCOMPtr<nsIDOMEvent> mEvent;
+diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
+--- a/modules/libpref/init/all.js
++++ b/modules/libpref/init/all.js
+@@ -1425,16 +1425,17 @@ pref("privacy.resistFingerprinting", fal
+ pref("privacy.trackingprotection.lower_network_priority", true);
+ #else
+ pref("privacy.trackingprotection.lower_network_priority", false);
+ #endif
+ 
+ pref("dom.event.contextmenu.enabled",       true);
+ pref("dom.event.clipboardevents.enabled",   true);
+ pref("dom.event.highrestimestamp.enabled",  true);
++pref("dom.event.coalesce_mouse_move",       false);
+ 
+ pref("dom.webcomponents.enabled",           false);
+ pref("dom.webcomponents.customelements.enabled", false);
+ 
+ pref("javascript.enabled",                  true);
+ pref("javascript.options.strict",           false);
+ #ifdef DEBUG
+ pref("javascript.options.strict.debug",     false);

+ 40 - 0
frg/253-58/mozilla-release58_427939.patch

@@ -0,0 +1,40 @@
+# HG changeset patch
+# User Stone Shih <sshih@mozilla.com>
+# Date 1503012772 -28800
+#      Fri Aug 18 07:32:52 2017 +0800
+# Node ID 2186f168ab69f70ca131e0699b0251e5cd0a4950
+# Parent  a13af006d99e8ad68db2b1c324be19bf6721e6c5
+Bug 1361067 Part3: Tweak test_touch_listeners_impacting_wheel.html to synthesize mousemove before taking control of refresh driver. r=kats.
+
+MozReview-Commit-ID: HLPcPFXxvAz
+
+diff --git a/gfx/layers/apz/test/mochitest/test_touch_listeners_impacting_wheel.html b/gfx/layers/apz/test/mochitest/test_touch_listeners_impacting_wheel.html
+--- a/gfx/layers/apz/test/mochitest/test_touch_listeners_impacting_wheel.html
++++ b/gfx/layers/apz/test/mochitest/test_touch_listeners_impacting_wheel.html
+@@ -74,24 +74,25 @@ function* test(testDriver) {
+   });
+   box.addEventListener('wheel', takeSnapshots, { capture: false, passive: true });
+ 
+   // Let the event regions and layerization propagate to the APZ
+   yield waitForAllPaints(function() {
+     flushApzRepaints(testDriver);
+   });
+ 
++  yield synthesizeNativeMouseMoveAndWaitForMoveEvent(box, 10, 10, testDriver);
++
+   // Take over control of the refresh driver and compositor
+   var utils = SpecialPowers.DOMWindowUtils;
+   utils.advanceTimeAndRefresh(0);
+ 
+   // Trigger an APZ scroll using a wheel event. If APZ is waiting for a
+   // content response, it will wait for takeSnapshots to finish running before
+   // it starts scrolling, which will cause the checks in takeSnapshots to fail.
+-  yield synthesizeNativeMouseMoveAndWaitForMoveEvent(box, 10, 10, testDriver);
+   yield synthesizeNativeWheelAndWaitForScrollEvent(box, 10, 10, 0, -50, testDriver);
+ }
+ 
+ if (isApzEnabled()) {
+   SimpleTest.waitForExplicitFinish();
+   // Disable touch events, so that APZ knows not to wait for touch listeners.
+   // Also explicitly set the content response timeout, so we know how long it
+   // is (see comment in takeSnapshots).

+ 37 - 0
frg/253-58/mozilla-release58_427940.patch

@@ -0,0 +1,37 @@
+# HG changeset patch
+# User Paolo Amadini <paolo.mozmail@amadzone.org>
+# Date 1503051154 -3600
+#      Fri Aug 18 11:12:34 2017 +0100
+# Node ID c5f62e5b5655d3a94c55556cbfe55a902ff92b01
+# Parent  b9c9b6de4760a1a0486783839586235b1c1175d1
+Bug 1391576 - Stop doing main-thread I/O in FileUtils.getFile for the most common case. r=kmag
+
+MozReview-Commit-ID: HybmKdeReeX
+
+diff --git a/toolkit/modules/FileUtils.jsm b/toolkit/modules/FileUtils.jsm
+--- a/toolkit/modules/FileUtils.jsm
++++ b/toolkit/modules/FileUtils.jsm
+@@ -27,20 +27,21 @@ this.FileUtils = {
+    * @param   key
+    *          The Directory Service Key to start from
+    * @param   pathArray
+    *          An array of path components to locate beneath the directory
+    *          specified by |key|. The last item in this array must be the
+    *          leaf name of a file.
+    * @return  nsIFile object for the file specified. The file is NOT created
+    *          if it does not exist, however all required directories along
+-   *          the way are.
++   *          the way are if pathArray has more than one item.
+    */
+   getFile: function FileUtils_getFile(key, pathArray, followLinks) {
+-    var file = this.getDir(key, pathArray.slice(0, -1), true, followLinks);
++    var file = this.getDir(key, pathArray.slice(0, -1), pathArray.length > 1,
++                           followLinks);
+     file.append(pathArray[pathArray.length - 1]);
+     return file;
+   },
+ 
+   /**
+    * Gets a directory at the specified hierarchy under a nsIDirectoryService
+    * key.
+    * @param   key

+ 51 - 0
frg/253-58/mozilla-release58_427959.patch

@@ -0,0 +1,51 @@
+# HG changeset patch
+# User Christoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
+# Date 1503323286 -7200
+#      Mon Aug 21 15:48:06 2017 +0200
+# Node ID fd7a7759990a88239d16b4f7073679db606ceeb0
+# Parent  bb72d5d623141a49c6de010964e56b7bde040322
+Bug 1392095 - Update browser/components/sessionstore/test/browser_739531.js to comply with new data: URI inheritance model. r=smaug
+
+diff --git a/browser/components/sessionstore/test/browser.ini b/browser/components/sessionstore/test/browser.ini
+--- a/browser/components/sessionstore/test/browser.ini
++++ b/browser/components/sessionstore/test/browser.ini
+@@ -42,16 +42,17 @@ support-files =
+   browser_456342_sample.xhtml
+   browser_463205_sample.html
+   browser_463206_sample.html
+   browser_466937_sample.html
+   browser_485482_sample.html
+   browser_637020_slow.sjs
+   browser_662743_sample.html
+   browser_739531_sample.html
++  browser_739531_frame.html
+   browser_911547_sample.html
+   browser_911547_sample.html^headers^
+   restore_redirect_http.html
+   restore_redirect_http.html^headers^
+   restore_redirect_js.html
+   restore_redirect_target.html
+   browser_1234021_page.html
+ 
+diff --git a/browser/components/sessionstore/test/browser_739531_frame.html b/browser/components/sessionstore/test/browser_739531_frame.html
+new file mode 100644
+--- /dev/null
++++ b/browser/components/sessionstore/test/browser_739531_frame.html
+@@ -0,0 +1,1 @@
++<body><html>1</html></body>
+diff --git a/browser/components/sessionstore/test/browser_739531_sample.html b/browser/components/sessionstore/test/browser_739531_sample.html
+--- a/browser/components/sessionstore/test/browser_739531_sample.html
++++ b/browser/components/sessionstore/test/browser_739531_sample.html
+@@ -13,11 +13,11 @@ function boom() {
+   var r = d.documentElement;
+   d.removeChild(r);
+   document.adoptNode(r);
+ }
+ 
+ </script>
+ </head>
+ <body onload="boom();">
+-<iframe src="data:text/html;charset=utf-8,1" id="f"></iframe>
++<iframe src="browser_739531_frame.html" id="f"></iframe>
+ </body>
+ </html>

+ 155 - 0
frg/253-58/mozilla-release58_427968.patch

@@ -0,0 +1,155 @@
+# HG changeset patch
+# User Dragan Mladjenovic <dragan.mladjenovic@rt-rk.com>
+# Date 1502949240 14400
+#      Thu Aug 17 01:54:00 2017 -0400
+# Node ID 8ccc616a23b3b1422e9e3b59e64d90544b7b23bc
+# Parent  26d9718019725c9766efcc11690f83802b681a08
+Bug 1391185 - Add missing implementation for MacroAssembler::moveValue to mips32. r=bbouvier
+
+diff --git a/js/src/jit/mips32/Assembler-mips32.h b/js/src/jit/mips32/Assembler-mips32.h
+--- a/js/src/jit/mips32/Assembler-mips32.h
++++ b/js/src/jit/mips32/Assembler-mips32.h
+@@ -68,16 +68,23 @@ static constexpr Register JSReturnReg_Da
+ static constexpr Register64 ReturnReg64(InvalidReg, InvalidReg);
+ static constexpr FloatRegister ReturnFloat32Reg = { FloatRegisters::f0, FloatRegister::Single };
+ static constexpr FloatRegister ReturnDoubleReg = { FloatRegisters::f0, FloatRegister::Double };
+ static constexpr FloatRegister ScratchFloat32Reg = { FloatRegisters::f18, FloatRegister::Single };
+ static constexpr FloatRegister ScratchDoubleReg = { FloatRegisters::f18, FloatRegister::Double };
+ static constexpr FloatRegister SecondScratchFloat32Reg = { FloatRegisters::f16, FloatRegister::Single };
+ static constexpr FloatRegister SecondScratchDoubleReg = { FloatRegisters::f16, FloatRegister::Double };
+ 
++struct ScratchDoubleScope : public AutoFloatRegisterScope
++{
++    explicit ScratchDoubleScope(MacroAssembler& masm)
++      : AutoFloatRegisterScope(masm, ScratchDoubleReg)
++    { }
++};
++
+ // Registers used in the GenerateFFIIonExit Disable Activation block.
+ // None of these may be the second scratch register (t8).
+ static constexpr Register WasmIonExitRegReturnData = JSReturnReg_Data;
+ static constexpr Register WasmIonExitRegReturnType = JSReturnReg_Type;
+ static constexpr Register WasmIonExitTlsReg = s5;
+ 
+ static constexpr FloatRegister f0  = { FloatRegisters::f0, FloatRegister::Double };
+ static constexpr FloatRegister f2  = { FloatRegisters::f2, FloatRegister::Double };
+diff --git a/js/src/jit/mips32/CodeGenerator-mips32.cpp b/js/src/jit/mips32/CodeGenerator-mips32.cpp
+--- a/js/src/jit/mips32/CodeGenerator-mips32.cpp
++++ b/js/src/jit/mips32/CodeGenerator-mips32.cpp
+@@ -172,26 +172,20 @@ CodeGeneratorMIPS::visitBox(LBox* box)
+     // virtual register. All that needs to be written is the type tag for
+     // the type definition.
+     masm.move32(Imm32(MIRTypeToTag(box->type())), ToRegister(type));
+ }
+ 
+ void
+ CodeGeneratorMIPS::visitBoxFloatingPoint(LBoxFloatingPoint* box)
+ {
+-    const LDefinition* payload = box->getDef(PAYLOAD_INDEX);
+-    const LDefinition* type = box->getDef(TYPE_INDEX);
+-    const LAllocation* in = box->getOperand(0);
++    const AnyRegister in = ToAnyRegister(box->getOperand(0));
++    const ValueOperand out = ToOutValue(box);
+ 
+-    FloatRegister reg = ToFloatRegister(in);
+-    if (box->type() == MIRType::Float32) {
+-        masm.convertFloat32ToDouble(reg, ScratchDoubleReg);
+-        reg = ScratchDoubleReg;
+-    }
+-    masm.ma_mv(reg, ValueOperand(ToRegister(type), ToRegister(payload)));
++    masm.moveValue(TypedOrValueRegister(box->type(), in), out);
+ }
+ 
+ void
+ CodeGeneratorMIPS::visitUnbox(LUnbox* unbox)
+ {
+     // Note that for unbox, the type and payload indexes are switched on the
+     // inputs.
+     MUnbox* mir = unbox->mir();
+diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp
+--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
++++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
+@@ -2255,29 +2255,80 @@ MacroAssembler::callWithABINoProfiler(co
+     callWithABIPost(stackAdjust, result);
+ }
+ // ===============================================================
+ // Move instructions
+ 
+ void
+ MacroAssembler::moveValue(const TypedOrValueRegister& src, const ValueOperand& dest)
+ {
+-    MOZ_CRASH("NIY");
++    if (src.hasValue()) {
++        moveValue(src.valueReg(), dest);
++        return;
++    }
++
++    MIRType type = src.type();
++    AnyRegister reg = src.typedReg();
++
++    if (!IsFloatingPointType(type)) {
++        mov(ImmWord(MIRTypeToTag(type)), dest.typeReg());
++        if (reg.gpr() != dest.payloadReg())
++            move32(reg.gpr(), dest.payloadReg());
++        return;
++    }
++
++    ScratchDoubleScope scratch(*this);
++    FloatRegister freg = reg.fpu();
++    if (type == MIRType::Float32) {
++        convertFloat32ToDouble(freg, scratch);
++        freg = scratch;
++    }
++    boxDouble(freg, dest, scratch);
+ }
+ 
+ void
+ MacroAssembler::moveValue(const ValueOperand& src, const ValueOperand& dest)
+ {
+-    MOZ_CRASH("NIY");
++    Register s0 = src.typeReg();
++    Register s1 = src.payloadReg();
++    Register d0 = dest.typeReg();
++    Register d1 = dest.payloadReg();
++
++    // Either one or both of the source registers could be the same as a
++    // destination register.
++    if (s1 == d0) {
++        if (s0 == d1) {
++            // If both are, this is just a swap of two registers.
++            ScratchRegisterScope scratch(*this);
++            MOZ_ASSERT(d1 != scratch);
++            MOZ_ASSERT(d0 != scratch);
++            move32(d1, scratch);
++            move32(d0, d1);
++            move32(scratch, d0);
++            return;
++        }
++        // If only one is, copy that source first.
++        mozilla::Swap(s0, s1);
++        mozilla::Swap(d0, d1);
++    }
++
++    if (s0 != d0)
++        move32(s0, d0);
++    if (s1 != d1)
++        move32(s1, d1);
+ }
+ 
+ void
+ MacroAssembler::moveValue(const Value& src, const ValueOperand& dest)
+ {
+-    MOZ_CRASH("NIY");
++    move32(Imm32(src.toNunboxTag()), dest.typeReg());
++    if (src.isGCThing())
++        movePtr(ImmGCPtr(src.toGCThing()), dest.payloadReg());
++    else
++        move32(Imm32(src.toNunboxPayload()), dest.payloadReg());
+ }
+ 
+ // ===============================================================
+ // Branch functions
+ 
+ void
+ MacroAssembler::branchValueIsNurseryObject(Condition cond, const Address& address,
+                                            Register temp, Label* label)

+ 39 - 0
frg/253-58/mozilla-release58_427975.patch

@@ -0,0 +1,39 @@
+# HG changeset patch
+# User Paolo Amadini <paolo.mozmail@amadzone.org>
+# Date 1503323553 -3600
+#      Mon Aug 21 14:52:33 2017 +0100
+# Node ID 75eda325afa7b5ae071aec000ead833d3b585bd1
+# Parent  5513073876375231d78ce358c3dea56d6d80d61e
+Bug 1296554 - Show a static progress bar for downloads of unknown size. r=jaws
+
+MozReview-Commit-ID: HgRl7vlTp3Z
+
+diff --git a/browser/components/downloads/DownloadsCommon.jsm b/browser/components/downloads/DownloadsCommon.jsm
+--- a/browser/components/downloads/DownloadsCommon.jsm
++++ b/browser/components/downloads/DownloadsCommon.jsm
+@@ -1213,17 +1213,24 @@ DownloadsIndicatorDataCtor.prototype = {
+    */
+   _refreshProperties() {
+     let summary =
+       DownloadsCommon.summarizeDownloads(this._activeDownloads());
+ 
+     // Determine if the indicator should be shown or get attention.
+     this._hasDownloads = (this._itemCount > 0);
+ 
+-    this._percentComplete = summary.percentComplete;
++    // Always show a progress bar if there are downloads in progress.
++    if (summary.percentComplete >= 0) {
++      this._percentComplete = summary.percentComplete;
++    } else if (summary.numDownloading > 0) {
++      this._percentComplete = 0;
++    } else {
++      this._percentComplete = -1;
++    }
+   }
+ };
+ 
+ XPCOMUtils.defineLazyGetter(this, "PrivateDownloadsIndicatorData", function() {
+   return new DownloadsIndicatorDataCtor(true);
+ });
+ 
+ XPCOMUtils.defineLazyGetter(this, "DownloadsIndicatorData", function() {

+ 215 - 0
frg/253-58/mozilla-release58_427981.patch

@@ -0,0 +1,215 @@
+# HG changeset patch
+# User Andrew McCreight <continuation@gmail.com>
+# Date 1503071968 25200
+#      Fri Aug 18 08:59:28 2017 -0700
+# Node ID 1bb5bcc356b417bb745a956ecbaef724c88c82cd
+# Parent  d2b353a471228249858af65361e91be26cb0e754
+Bug 1368219 - Remove the unused OSFile.getAvailableFreeSpace. r=Yoric
+
+The test is failing frequently on Linux 32 debug, and the method is unused.
+
+MozReview-Commit-ID: 5ngM1pfDV7g
+
+diff --git a/toolkit/components/osfile/modules/osfile_async_front.jsm b/toolkit/components/osfile/modules/osfile_async_front.jsm
+--- a/toolkit/components/osfile/modules/osfile_async_front.jsm
++++ b/toolkit/components/osfile/modules/osfile_async_front.jsm
+@@ -996,31 +996,16 @@ File.move = function move(sourcePath, de
+ if (!SharedAll.Constants.Win) {
+   File.unixSymLink = function unixSymLink(sourcePath, destPath) {
+     return Scheduler.post("unixSymLink", [Type.path.toMsg(sourcePath),
+       Type.path.toMsg(destPath)], [sourcePath, destPath]);
+   };
+ }
+ 
+ /**
+- * Gets the number of bytes available on disk to the current user.
+- *
+- * @param {string} Platform-specific path to a directory on the disk to
+- * query for free available bytes.
+- *
+- * @return {number} The number of bytes available for the current user.
+- * @throws {OS.File.Error} In case of any error.
+- */
+-File.getAvailableFreeSpace = function getAvailableFreeSpace(sourcePath) {
+-  return Scheduler.post("getAvailableFreeSpace",
+-    [Type.path.toMsg(sourcePath)], sourcePath
+-  ).then(Type.uint64_t.fromMsg);
+-};
+-
+-/**
+  * Remove an empty directory.
+  *
+  * @param {string} path The name of the directory to remove.
+  * @param {*=} options Additional options.
+  *   - {bool} ignoreAbsent If |true|, do not fail if the
+  *     directory does not exist yet.
+  */
+ File.removeEmptyDir = function removeEmptyDir(path, options) {
+diff --git a/toolkit/components/osfile/modules/osfile_async_worker.js b/toolkit/components/osfile/modules/osfile_async_worker.js
+--- a/toolkit/components/osfile/modules/osfile_async_worker.js
++++ b/toolkit/components/osfile/modules/osfile_async_worker.js
+@@ -203,20 +203,16 @@ if (this.Components) {
+    copy: function copy(sourcePath, destPath, options) {
+      return File.copy(Type.path.fromMsg(sourcePath),
+        Type.path.fromMsg(destPath), options);
+    },
+    move: function move(sourcePath, destPath, options) {
+      return File.move(Type.path.fromMsg(sourcePath),
+        Type.path.fromMsg(destPath), options);
+    },
+-   getAvailableFreeSpace: function getAvailableFreeSpace(sourcePath) {
+-     return Type.uint64_t.toMsg(
+-       File.getAvailableFreeSpace(Type.path.fromMsg(sourcePath)));
+-   },
+    makeDir: function makeDir(path, options) {
+      return File.makeDir(Type.path.fromMsg(path), options);
+    },
+    removeEmptyDir: function removeEmptyDir(path, options) {
+      return File.removeEmptyDir(Type.path.fromMsg(path), options);
+    },
+    remove: function remove(path, options) {
+      return File.remove(Type.path.fromMsg(path), options);
+diff --git a/toolkit/components/osfile/modules/osfile_unix_front.jsm b/toolkit/components/osfile/modules/osfile_unix_front.jsm
+--- a/toolkit/components/osfile/modules/osfile_unix_front.jsm
++++ b/toolkit/components/osfile/modules/osfile_unix_front.jsm
+@@ -383,37 +383,16 @@
+              ctypes.errno == Const.ENOENT) {
+            return;
+          }
+          throw new File.Error("removeEmptyDir", ctypes.errno, path);
+        }
+      };
+ 
+      /**
+-      * Gets the number of bytes available on disk to the current user.
+-      *
+-      * @param {string} sourcePath Platform-specific path to a directory on
+-      * the disk to query for free available bytes.
+-      *
+-      * @return {number} The number of bytes available for the current user.
+-      * @throws {OS.File.Error} In case of any error.
+-      */
+-     File.getAvailableFreeSpace = function Unix_getAvailableFreeSpace(sourcePath) {
+-       let fileSystemInfo = new Type.statvfs.implementation();
+-       let fileSystemInfoPtr = fileSystemInfo.address();
+-
+-       throw_on_negative("statvfs", (UnixFile.statvfs || UnixFile.statfs)(sourcePath, fileSystemInfoPtr));
+-
+-       let bytes = new Type.uint64_t.implementation(
+-                        fileSystemInfo.f_frsize * fileSystemInfo.f_bavail);
+-
+-       return bytes.value;
+-     };
+-
+-     /**
+       * Default mode for opening directories.
+       */
+      const DEFAULT_UNIX_MODE_DIR = Const.S_IRWXU;
+ 
+      /**
+       * Create a directory.
+       *
+       * @param {string} path The name of the directory.
+diff --git a/toolkit/components/osfile/modules/osfile_win_front.jsm b/toolkit/components/osfile/modules/osfile_win_front.jsm
+--- a/toolkit/components/osfile/modules/osfile_win_front.jsm
++++ b/toolkit/components/osfile/modules/osfile_win_front.jsm
+@@ -652,36 +652,16 @@
+        }
+        // sd will be set only if the function succeeds.
+        if (!sd.isNull()) {
+            WinFile.LocalFree(Type.HLOCAL.cast(sd));
+        }
+      };
+ 
+      /**
+-      * Gets the number of bytes available on disk to the current user.
+-      *
+-      * @param {string} sourcePath Platform-specific path to a directory on
+-      * the disk to query for free available bytes.
+-      *
+-      * @return {number} The number of bytes available for the current user.
+-      * @throws {OS.File.Error} In case of any error.
+-      */
+-     File.getAvailableFreeSpace = function Win_getAvailableFreeSpace(sourcePath) {
+-       let freeBytesAvailableToUser = new Type.uint64_t.implementation(0);
+-       let freeBytesAvailableToUserPtr = freeBytesAvailableToUser.address();
+-
+-       throw_on_zero("getAvailableFreeSpace",
+-         WinFile.GetDiskFreeSpaceEx(sourcePath, freeBytesAvailableToUserPtr, null, null)
+-       );
+-
+-       return freeBytesAvailableToUser.value;
+-     };
+-
+-     /**
+       * A global value used to receive data during time conversions.
+       */
+      let gSystemTime = new Type.SystemTime.implementation();
+      let gSystemTimePtr = gSystemTime.address();
+ 
+      /**
+       * Utility function: convert a FILETIME to a JavaScript Date.
+       */
+diff --git a/toolkit/components/osfile/tests/xpcshell/test_available_free_space.js b/toolkit/components/osfile/tests/xpcshell/test_available_free_space.js
+deleted file mode 100644
+--- a/toolkit/components/osfile/tests/xpcshell/test_available_free_space.js
++++ /dev/null
+@@ -1,38 +0,0 @@
+-/* This Source Code Form is subject to the terms of the Mozilla Public
+- * License, v. 2.0. If a copy of the MPL was not distributed with this
+- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+-
+-"use strict";
+-
+-ChromeUtils.import("resource://gre/modules/osfile.jsm");
+-ChromeUtils.import("resource://gre/modules/Services.jsm");
+-
+-registerCleanupFunction(function() {
+-  Services.prefs.setBoolPref("toolkit.osfile.log", false);
+-});
+-
+-function run_test() {
+-  Services.prefs.setBoolPref("toolkit.osfile.log", true);
+-
+-  run_next_test();
+-}
+-
+-/**
+- * Test OS.File.getAvailableFreeSpace
+- */
+-add_task(async function() {
+-  // Set up profile. We will use profile path to query for available free
+-  // space.
+-  do_get_profile();
+-
+-  let dir = OS.Constants.Path.profileDir;
+-
+-  // Sanity checking for the test
+-  Assert.ok((await OS.File.exists(dir)));
+-
+-  // Query for available bytes for user
+-  let availableBytes = await OS.File.getAvailableFreeSpace(dir);
+-
+-  Assert.ok(!!availableBytes);
+-  Assert.ok(availableBytes > 0);
+-});
+diff --git a/toolkit/components/osfile/tests/xpcshell/xpcshell.ini b/toolkit/components/osfile/tests/xpcshell/xpcshell.ini
+--- a/toolkit/components/osfile/tests/xpcshell/xpcshell.ini
++++ b/toolkit/components/osfile/tests/xpcshell/xpcshell.ini
+@@ -1,16 +1,14 @@
+ [DEFAULT]
+ head = head.js
+ 
+ support-files =
+   test_loader/module_test_loader.js
+ 
+-[test_available_free_space.js]
+-skip-if = os == 'linux' # Bug 1368219
+ [test_compression.js]
+ [test_constants.js]
+ [test_creationDate.js]
+ [test_duration.js]
+ [test_exception.js]
+ [test_file_URL_conversion.js]
+ [test_loader.js]
+ [test_logging.js]

+ 83 - 0
frg/253-58/mozilla-release58_427985.patch

@@ -0,0 +1,83 @@
+# HG changeset patch
+# User Emilio Cobos Alvarez <emilio@crisal.io>
+# Date 1503339680 18000
+#      Mon Aug 21 13:21:20 2017 -0500
+# Node ID fbe168f2ade31233918dac15d3ef6677651190d2
+# Parent  9fe5ae9bc220583547d289d69c6360b3a2ac1b8e
+servo: Merge #18173 - style: Keep dirty bit invariants during invalidation (from emilio:invalidation-dirty-thingie); r=bholley
+
+There's the question of whether should we be recursing into the invalidation
+code for elements without data... Probably not, but that's a somewhat more
+risky change.
+
+Bug: 1391444
+Source-Repo: https://github.com/servo/servo
+Source-Revision: 05f2001914720590c87ccf564389a6fb2e2e1465
+
+diff --git a/servo/components/style/invalidation/element/invalidator.rs b/servo/components/style/invalidation/element/invalidator.rs
+--- a/servo/components/style/invalidation/element/invalidator.rs
++++ b/servo/components/style/invalidation/element/invalidator.rs
+@@ -24,16 +24,25 @@ use smallvec::SmallVec;
+ use std::fmt;
+ 
+ /// The struct that takes care of encapsulating all the logic on where and how
+ /// element styles need to be invalidated.
+ pub struct TreeStyleInvalidator<'a, 'b: 'a, E>
+     where E: TElement,
+ {
+     element: E,
++    // TODO(emilio): It's tempting enough to just avoid running invalidation for
++    // elements without data.
++    //
++    // But that's be wrong for sibling invalidations when a new element has been
++    // inserted in the tree and still has no data (though I _think_ the slow
++    // selector bits save us, it'd be nice not to depend on them).
++    //
++    // Seems like we could at least avoid running invalidation for the
++    // descendants if an element has no data, though.
+     data: Option<&'a mut ElementData>,
+     shared_context: &'a SharedStyleContext<'b>,
+ }
+ 
+ type InvalidationVector = SmallVec<[Invalidation; 10]>;
+ 
+ /// The kind of invalidation we're processing.
+ ///
+@@ -348,17 +357,17 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator
+                 sibling_invalidations,
+             );
+ 
+         // The child may not be a flattened tree child of the current element,
+         // but may be arbitrarily deep.
+         //
+         // Since we keep the traversal flags in terms of the flattened tree,
+         // we need to propagate it as appropriate.
+-        if invalidated_child {
++        if invalidated_child && child.get_data().is_some() {
+             let mut current = child.traversal_parent();
+             while let Some(parent) = current.take() {
+                 if parent == self.element {
+                     break;
+                 }
+ 
+                 unsafe { parent.set_dirty_descendants() };
+                 current = parent.traversal_parent();
+@@ -465,17 +474,17 @@ impl<'a, 'b: 'a, E> TreeStyleInvalidator
+ 
+         if let Some(after) = self.element.after_pseudo_element() {
+             any_descendant |=
+                 self.invalidate_pseudo_element_or_nac(after, invalidations);
+         }
+ 
+         any_descendant |= self.invalidate_nac(invalidations);
+ 
+-        if any_descendant {
++        if any_descendant && self.data.as_ref().map_or(false, |d| !d.styles.is_display_none()) {
+             unsafe { self.element.set_dirty_descendants() };
+         }
+ 
+         any_descendant
+     }
+ 
+     /// Process the given sibling invalidations coming from our previous
+     /// sibling.

+ 27 - 0
frg/253-58/mozilla-release58_427986.patch

@@ -0,0 +1,27 @@
+# HG changeset patch
+# User ruby <akriti.v10@gmail.com>
+# Date 1503327973 -19800
+#      Mon Aug 21 20:36:13 2017 +0530
+# Node ID 25731ae36331f06a612c9484f4c62d4cedff0cf1
+# Parent  5a72835f43c7a7a5f87946b970e6f5c09ed7e33f
+Bug 1391578 - title capitalization done for the menu item r=dao
+MozReview-Commit-ID: G0SW8LYTEdm
+
+diff --git a/browser/locales/en-US/chrome/browser/safebrowsing/report-phishing.dtd b/browser/locales/en-US/chrome/browser/safebrowsing/report-phishing.dtd
+--- a/browser/locales/en-US/chrome/browser/safebrowsing/report-phishing.dtd
++++ b/browser/locales/en-US/chrome/browser/safebrowsing/report-phishing.dtd
+@@ -1,13 +1,13 @@
+ <!-- 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/. -->
+ 
+ <!-- Localization note (reportDeceptiveSiteMenu.title) - Label of the Help menu
+   item. Either this or safeb.palm.notdeceptive.label from
+   phishing-afterload-warning-message.dtd is shown. -->
+-<!ENTITY reportDeceptiveSiteMenu.title      "Report deceptive site…">
++<!ENTITY reportDeceptiveSiteMenu.title      "Report Deceptive Site…">
+ <!-- Localization note (reportDeceptiveSiteMenu.accesskey) - Because
+   safeb.palm.notdeceptive.label from phishing-afterload-warning-message.dtd and
+   reportDeceptiveSiteMenu.title are never shown at the same time, the same
+   accesskey can be used for them. -->
+ <!ENTITY reportDeceptiveSiteMenu.accesskey  "D">

+ 139 - 0
frg/253-58/mozilla-release58_427993.patch

@@ -0,0 +1,139 @@
+# HG changeset patch
+# User Mantaroh Yoshinaga <mantaroh@gmail.com>
+# Date 1503344109 18000
+#      Mon Aug 21 14:35:09 2017 -0500
+# Node ID 94c5f2703f194004a5db405007c0c7e186612047
+# Parent  d4706adfb4929627c83d6e342a0d2e2270f51a2c
+servo: Merge #18168 - Add ComputeSquaredDistance trait for SvgLengthOrPercentageOrNumber (from mantaroh:stroke-distance); r=nox
+
+<!-- Please describe your changes on the following line: -->
+This is a PR for https://bugzilla.mozilla.org/show_bug.cgi?id=1387986
+
+This patch will add ComputeSquaredDistance trait for SvgLengthOrPercentageOrNumber in order to calculating distance between LengthOrPercentage and Number.
+
+---
+<!-- 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: -->
+There are already these tests in dom/smil/tests of gecko, this PR will enable these tests.
+For detail, see https://bugzilla.mozilla.org/show_bug.cgi?id=1387986.
+
+<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
+
+<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
+
+Source-Repo: https://github.com/servo/servo
+Source-Revision: 181f41ed378bba8be0028c571e5efa4fe6b02956
+
+diff --git a/servo/components/style/values/computed/mod.rs b/servo/components/style/values/computed/mod.rs
+--- a/servo/components/style/values/computed/mod.rs
++++ b/servo/components/style/values/computed/mod.rs
+@@ -364,17 +364,17 @@ impl From<GreaterThanOrEqualToOneNumber>
+     #[inline]
+     fn from(number: GreaterThanOrEqualToOneNumber) -> CSSFloat {
+         number.0
+     }
+ }
+ 
+ #[allow(missing_docs)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, Copy, Debug, PartialEq, ToCss)]
++#[derive(Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)]
+ pub enum NumberOrPercentage {
+     Percentage(Percentage),
+     Number(Number),
+ }
+ 
+ impl ToComputedValue for specified::NumberOrPercentage {
+     type ComputedValue = NumberOrPercentage;
+ 
+diff --git a/servo/components/style/values/generics/svg.rs b/servo/components/style/values/generics/svg.rs
+--- a/servo/components/style/values/generics/svg.rs
++++ b/servo/components/style/values/generics/svg.rs
+@@ -3,18 +3,19 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ //! Generic types for CSS values in SVG
+ 
+ use cssparser::Parser;
+ use parser::{Parse, ParserContext};
+ use std::fmt;
+ use style_traits::{ParseError, StyleParseError, ToCss};
++use values::computed::NumberOrPercentage;
+ use values::computed::length::LengthOrPercentage;
+-
++use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ 
+ /// An SVG paint value
+ ///
+ /// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ #[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
+ pub struct SVGPaint<ColorType, UrlPaintServer> {
+     /// The paint source
+@@ -95,25 +96,61 @@ impl<ColorType: Parse, UrlPaintServer: P
+             Err(StyleParseError::UnspecifiedError.into())
+         }
+     }
+ }
+ 
+ /// A value of <length> | <percentage> | <number> for svg which allow unitless length.
+ /// https://www.w3.org/TR/SVG11/painting.html#StrokeProperties
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, Copy, Debug, PartialEq, ToCss, HasViewportPercentage)]
+-#[derive(ToComputedValue, ToAnimatedValue, ComputeSquaredDistance)]
++#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)]
++#[derive(ToCss, ToComputedValue)]
+ pub enum SvgLengthOrPercentageOrNumber<LengthOrPercentageType, NumberType> {
+     /// <length> | <percentage>
+     LengthOrPercentage(LengthOrPercentageType),
+     /// <number>
+     Number(NumberType),
+ }
+ 
++impl<L, N> ComputeSquaredDistance for SvgLengthOrPercentageOrNumber<L, N>
++    where
++        L: ComputeSquaredDistance + Copy + Into<NumberOrPercentage>,
++        N: ComputeSquaredDistance + Copy + Into<NumberOrPercentage>
++{
++    #[inline]
++    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
++        match (self, other) {
++            (
++                &SvgLengthOrPercentageOrNumber::LengthOrPercentage(ref from),
++                &SvgLengthOrPercentageOrNumber::LengthOrPercentage(ref to)
++            ) => {
++                from.compute_squared_distance(to)
++            },
++            (
++                &SvgLengthOrPercentageOrNumber::Number(ref from),
++                &SvgLengthOrPercentageOrNumber::Number(ref to)
++            ) => {
++                from.compute_squared_distance(to)
++            },
++            (
++                &SvgLengthOrPercentageOrNumber::LengthOrPercentage(from),
++                &SvgLengthOrPercentageOrNumber::Number(to)
++            ) => {
++                from.into().compute_squared_distance(&to.into())
++            },
++            (
++                &SvgLengthOrPercentageOrNumber::Number(from),
++                &SvgLengthOrPercentageOrNumber::LengthOrPercentage(to)
++            ) => {
++                from.into().compute_squared_distance(&to.into())
++            },
++        }
++    }
++}
++
+ impl<LengthOrPercentageType, NumberType> SvgLengthOrPercentageOrNumber<LengthOrPercentageType, NumberType>
+     where LengthOrPercentage: From<LengthOrPercentageType>,
+           LengthOrPercentageType: Copy
+ {
+     /// return true if this struct has calc value.
+     pub fn has_calc(&self) -> bool {
+         match self {
+             &SvgLengthOrPercentageOrNumber::LengthOrPercentage(lop) => {

+ 119 - 0
frg/253-58/mozilla-release58_428001.patch

@@ -0,0 +1,119 @@
+# HG changeset patch
+# User Mark Hammond <mhammond@skippinet.com.au>
+# Date 1502157748 -36000
+#      Tue Aug 08 12:02:28 2017 +1000
+# Node ID 71b5aad2f01ddd1b4a5aefaa8249c97ce02462c1
+# Parent  f384b669fc38a6d2c52f5fffacbedd9a764287ce
+Bug 1355766 - don't treat a 412 response as a sync error. r=kitcambridge
+
+MozReview-Commit-ID: 4IL6RJcP9PC
+
+diff --git a/services/sync/modules/engines.js b/services/sync/modules/engines.js
+--- a/services/sync/modules/engines.js
++++ b/services/sync/modules/engines.js
+@@ -1767,18 +1767,28 @@ SyncEngine.prototype = {
+   },
+ 
+   async _sync() {
+     try {
+       await this._syncStartup();
+       Observers.notify("weave:engine:sync:status", "process-incoming");
+       await this._processIncoming();
+       Observers.notify("weave:engine:sync:status", "upload-outgoing");
+-      await this._uploadOutgoing();
+-      await this._syncFinish();
++      try {
++        await this._uploadOutgoing();
++        await this._syncFinish();
++      } catch (ex) {
++        if (!ex.status || ex.status != 412) {
++          throw ex;
++        }
++        // a 412 posting just means another client raced - but we don't want
++        // to treat that as a sync error - the next sync is almost certain
++        // to work.
++        this._log.warn("412 error during sync - will retry.")
++      }
+     } finally {
+       await this._syncCleanup();
+     }
+   },
+ 
+   async canDecrypt() {
+     // Report failure even if there's nothing to decrypt
+     let canDecrypt = false;
+diff --git a/services/sync/tests/unit/test_412.js b/services/sync/tests/unit/test_412.js
+new file mode 100644
+--- /dev/null
++++ b/services/sync/tests/unit/test_412.js
+@@ -0,0 +1,57 @@
++/* Any copyright is dedicated to the Public Domain.
++ * http://creativecommons.org/publicdomain/zero/1.0/ */
++
++Cu.import("resource://services-sync/service.js");
++Cu.import("resource://testing-common/services/sync/rotaryengine.js");
++Cu.import("resource://testing-common/services/sync/utils.js");
++
++initTestLogging("Trace");
++
++Services.prefs.setCharPref("services.sync.log.logger.service.main", "Trace");
++
++add_task(async function test_412_not_treated_as_failure() {
++  await Service.engineManager.register(RotaryEngine);
++  let engine = Service.engineManager.get("rotary");
++
++  let server = serverForFoo(engine);
++
++  await SyncTestingInfrastructure(server);
++  generateNewKeys(Service.collectionKeys);
++
++  // add an item to the server to the first sync advances lastModified.
++  let collection = server.getCollection("foo", "rotary");
++  let payload = encryptPayload({id: "existing", something: "existing record"});
++  collection.insert("existing", payload);
++
++  let promiseObserved = promiseOneObserver("weave:engine:sync:finish");
++  try {
++    // Do sync.
++    _("initial sync to initialize the world");
++    await Service.sync();
++
++    // create a new record that should be uploaded and arrange for our lastSync
++    // timestamp to be wrong so we get a 412.
++    engine._store.items = {new: "new record"};
++    engine._tracker.addChangedID("new", 0);
++
++    let saw412 = false;
++    let _uploadOutgoing = engine._uploadOutgoing;
++    engine._uploadOutgoing = async () => {
++      engine.lastSync -= 2;
++      try {
++        await _uploadOutgoing.call(engine);
++      } catch (ex) {
++        saw412 = ex.status == 412;
++        throw ex;
++      }
++    }
++    _("Second sync - expecting a 412");
++    await Service.sync();
++    await promiseObserved;
++    ok(saw412, "did see a 412 error");
++    // But service status should be OK as the 412 shouldn't be treated as an error.
++    equal(Service.status.service, STATUS_OK);
++  } finally {
++    await promiseStopServer(server);
++  }
++});
+diff --git a/services/sync/tests/unit/xpcshell.ini b/services/sync/tests/unit/xpcshell.ini
+--- a/services/sync/tests/unit/xpcshell.ini
++++ b/services/sync/tests/unit/xpcshell.ini
+@@ -181,8 +181,9 @@ support-files = prefs_test_prefs_store.j
+ 
+ # Synced tabs.
+ [test_syncedtabs.js]
+ 
+ [test_telemetry.js]
+ requesttimeoutfactor = 4
+ 
+ [test_uistate.js]
++[test_412.js]

+ 72 - 0
frg/253-58/mozilla-release58_428008.patch

@@ -0,0 +1,72 @@
+# HG changeset patch
+# User Xidorn Quan <me@upsuper.org>
+# Date 1502927359 -36000
+#      Thu Aug 17 09:49:19 2017 +1000
+# Node ID 06d2f579a7f39ee0b2f20f43ec7e570fded37872
+# Parent  bb5a1ae3bbd80daecef3c8f2841e25389d44c569
+Bug 1391103 - Align Maybe::mStorage like when the type is in a struct. r=froydnj
+
+MozReview-Commit-ID: 6ArNhZA4Wdf
+
+diff --git a/mfbt/Alignment.h b/mfbt/Alignment.h
+--- a/mfbt/Alignment.h
++++ b/mfbt/Alignment.h
+@@ -29,16 +29,36 @@ class AlignmentFinder
+   };
+ 
+ public:
+   static const size_t alignment = sizeof(Aligner) - sizeof(T);
+ };
+ 
+ #define MOZ_ALIGNOF(T) mozilla::AlignmentFinder<T>::alignment
+ 
++namespace detail {
++template<typename T>
++struct AlignasHelper
++{
++  T mT;
++};
++} // namespace detail
++
++/*
++ * Use this instead of alignof to align struct field as if it is inside
++ * a struct. On some platforms, there exist types which have different
++ * alignment between when it is used on its own and when it is used on
++ * a struct field.
++ *
++ * Known examples are 64bit types (uint64_t, double) on 32bit Linux,
++ * where they have 8byte alignment on their own, and 4byte alignment
++ * when in struct.
++ */
++#define MOZ_ALIGNAS_IN_STRUCT(T) alignas(mozilla::detail::AlignasHelper<T>)
++
+ /*
+  * Declare the MOZ_ALIGNED_DECL macro for declaring aligned types.
+  *
+  * For instance,
+  *
+  *   MOZ_ALIGNED_DECL(char arr[2], 8);
+  *
+  * will declare a two-character array |arr| aligned to 8 bytes.
+diff --git a/mfbt/Maybe.h b/mfbt/Maybe.h
+--- a/mfbt/Maybe.h
++++ b/mfbt/Maybe.h
+@@ -80,17 +80,17 @@ struct Nothing { };
+  *
+  * N.B. GCC has missed optimizations with Maybe in the past and may generate
+  * extra branches/loads/stores. Use with caution on hot paths; it's not known
+  * whether or not this is still a problem.
+  */
+ template<class T>
+ class MOZ_NON_PARAM MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
+ {
+-  alignas(T) unsigned char mStorage[sizeof(T)];
++  MOZ_ALIGNAS_IN_STRUCT(T) unsigned char mStorage[sizeof(T)];
+   char mIsSome; // not bool -- guarantees minimal space consumption
+ 
+   // GCC fails due to -Werror=strict-aliasing if |mStorage| is directly cast to
+   // T*.  Indirecting through these functions addresses the problem.
+   void* data() { return mStorage; }
+   const void* data() const { return mStorage; }
+ 
+ public:

+ 71 - 0
frg/253-58/mozilla-release58_428011.patch

@@ -0,0 +1,71 @@
+# HG changeset patch
+# User Tom Ritter <tom@mozilla.com>
+# Date 1499115222 18000
+#      Mon Jul 03 15:53:42 2017 -0500
+# Node ID dd9b0b8c781ced3eb27b6324b00538bfde3bf577
+# Parent  380381c55e3a79f591644838bbf4481e842bd309
+Bug 1377948 Silence two warnings that occur as errors on the MinGW build r=arai
+
+MozReview-Commit-ID: LQBAoLVpVab
+
+diff --git a/js/src/vm/Time.cpp b/js/src/vm/Time.cpp
+--- a/js/src/vm/Time.cpp
++++ b/js/src/vm/Time.cpp
+@@ -264,18 +264,20 @@ size_t
+ PRMJ_FormatTime(char* buf, size_t buflen, const char* fmt, const PRMJTime* prtm,
+                 int timeZoneYear, int offsetInSeconds)
+ {
+     size_t result = 0;
+ #if defined(XP_UNIX) || defined(XP_WIN)
+     struct tm a;
+ #ifdef XP_WIN
+     _invalid_parameter_handler oldHandler;
+++#ifndef __MINGW32__
+     int oldReportMode;
+-#endif
++#endif // __MINGW32__
++#endif //XP_WIN
+ 
+     memset(&a, 0, sizeof(struct tm));
+ 
+     a.tm_sec = prtm->tm_sec;
+     a.tm_min = prtm->tm_min;
+     a.tm_hour = prtm->tm_hour;
+     a.tm_mday = prtm->tm_mday;
+     a.tm_mon = prtm->tm_mon;
+@@ -347,25 +349,33 @@ PRMJ_FormatTime(char* buf, size_t buflen
+      * Even with the above, SunOS 4 seems to detonate if tm_zone and tm_gmtoff
+      * are null.  This doesn't quite work, though - the timezone is off by
+      * tzoff + dst.  (And mktime seems to return -1 for the exact dst
+      * changeover time.)
+      */
+ 
+ #ifdef XP_WIN
+     oldHandler = _set_invalid_parameter_handler(PRMJ_InvalidParameterHandler);
++#ifndef __MINGW32__
++    /*
++     * MinGW doesn't have _CrtSetReportMode and defines it to be a no-op.
++     * We ifdef it off to avoid warnings about unused variables
++     */
+     oldReportMode = _CrtSetReportMode(_CRT_ASSERT, 0);
+-#endif
++#endif // __MINGW32__
++#endif // XP_WIN
+ 
+     result = strftime(buf, buflen, fmt, &a);
+ 
+ #ifdef XP_WIN
+     _set_invalid_parameter_handler(oldHandler);
++#ifndef __MINGW32__
+     _CrtSetReportMode(_CRT_ASSERT, oldReportMode);
+-#endif
++#endif // __MINGW32__
++#endif // XP_WIN
+ 
+     if (fake_tm_year && result) {
+         char real_year[16];
+         char fake_year[16];
+         size_t real_year_len;
+         size_t fake_year_len;
+         char* p;
+ 

+ 95 - 0
frg/253-58/mozilla-release58_428023.patch

@@ -0,0 +1,95 @@
+# HG changeset patch
+# User Francesco Lodolo (:flod) <flod@lodolo.net>
+# Date 1503219152 -7200
+#      Sun Aug 20 10:52:32 2017 +0200
+# Node ID 2486c6e1f89d4f5f8af5f37f08180b617816e283
+# Parent  33d2ab9254c81f8ff13e1dfb8b1aea2fcb5a503f
+Bug 1391933 - Fix localization issues in Kill Add-on dialogs, r=kmag
+
+Changes originally landed in bug 1356334:
+* Removed SUMO link as a localizable string.
+* Updated SUMO link: removed "en-US" from link and "cache" parameter.
+* Use ordered placeholder instead of %S.
+* Fix typo ("responsing").
+* Use "extension" instead of "add-on" in DOM strings for consistency.
+* Removed period from KillAddonScriptGlobalMessage, since it's a checkbox.
+
+MozReview-Commit-ID: 5IFH2ruISZb
+
+diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties
+--- a/browser/locales/en-US/chrome/browser/browser.properties
++++ b/browser/locales/en-US/chrome/browser/browser.properties
+@@ -582,21 +582,20 @@ browser.menu.showCharacterEncoding=false
+ 
+ # Mozilla data reporting notification (Telemetry, Firefox Health Report, etc)
+ dataReportingNotification.message       = %1$S automatically sends some data to %2$S so that we can improve your experience.
+ dataReportingNotification.button.label  = Choose What I Share
+ dataReportingNotification.button.accessKey  = C
+ 
+ # Process hang reporter
+ processHang.label = A web page is slowing down your browser. What would you like to do?
+-# LOCALIZATION NOTE (processHang.add-on.label): The first %S is the name of
+-# an extension. The second %S is the name of the product (e.g., Firefox)
+-processHang.add-on.label = A script in the extension “%S” is causing %S to slow down.
++# LOCALIZATION NOTE (processHang.add-on.label): %1$S is the name of the
++# extension. %2$S is the name of the product (e.g., Firefox)
++processHang.add-on.label = A script in the extension “%1$S” is causing %2$S to slow down.
+ processHang.add-on.learn-more.text = Learn more
+-processHang.add-on.learn-more.url = https://support.mozilla.org/en-US/kb/warning-unresponsive-script?cache=no#w_other-causes
+ processHang.button_stop.label = Stop It
+ processHang.button_stop.accessKey = S
+ processHang.button_stop_sandbox.label = Temporarily Disable Extension on Page
+ processHang.button_stop_sandbox.accessKey = A
+ processHang.button_wait.label = Wait
+ processHang.button_wait.accessKey = W
+ processHang.button_debug.label = Debug Script
+ processHang.button_debug.accessKey = D
+diff --git a/browser/modules/ProcessHangMonitor.jsm b/browser/modules/ProcessHangMonitor.jsm
+--- a/browser/modules/ProcessHangMonitor.jsm
++++ b/browser/modules/ProcessHangMonitor.jsm
+@@ -333,17 +333,17 @@ var ProcessHangMonitor = {
+       let brandBundle = doc.getElementById("bundle_brand");
+ 
+       let addonName = aps.getExtensionName(report.addonId);
+ 
+       let label = bundle.getFormattedString("processHang.add-on.label",
+                                             [addonName, brandBundle.getString("brandShortName")]);
+ 
+       let linkText = bundle.getString("processHang.add-on.learn-more.text");
+-      let linkURL = bundle.getString("processHang.add-on.learn-more.url");
++      let linkURL = "https://support.mozilla.org/kb/warning-unresponsive-script#w_other-causes";
+ 
+       let link = doc.createElement("label");
+       link.setAttribute("class", "text-link");
+       link.setAttribute("role", "link");
+       link.setAttribute("onclick", `openUILinkIn(${JSON.stringify(linkURL)}, "tab")`);
+       link.setAttribute("value", linkText);
+ 
+       message = doc.createDocumentFragment();
+diff --git a/dom/locales/en-US/chrome/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties
+--- a/dom/locales/en-US/chrome/dom/dom.properties
++++ b/dom/locales/en-US/chrome/dom/dom.properties
+@@ -3,19 +3,20 @@
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ KillScriptTitle=Warning: Unresponsive script
+ KillScriptMessage=A script on this page may be busy, or it may have stopped responding. You can stop the script now, or you can continue to see if the script will complete.
+ KillScriptWithDebugMessage=A script on this page may be busy, or it may have stopped responding. You can stop the script now, open the script in the debugger, or let the script continue.
+ KillScriptLocation=Script: %S
+ 
+ KillAddonScriptTitle=Warning: Unresponsive add-on script
+-# LOCALIZATION NOTE (KillAddonScriptMessage): The first %S is the name of an add-on. The second %S is the name of the application (e.g., Firefox).
+-KillAddonScriptMessage=A script from the add-on “%S” is running on this page, and making %S unresponsive.\n\nIt may be busy, or it may have stopped responsing permanently. You can stop the script now, or you can continue to see if it will complete.
+-KillAddonScriptGlobalMessage=Prevent the add-on script from running on this page until it next reloads.
++# LOCALIZATION NOTE (KillAddonScriptMessage): %1$S is the name of an extension.
++# %2$S is the name of the application (e.g., Firefox).
++KillAddonScriptMessage=A script from the extension “%1$S” is running on this page, and making %2$S unresponsive.\n\nIt may be busy, or it may have stopped responding permanently. You can stop the script now, or you can continue to see if it will complete.
++KillAddonScriptGlobalMessage=Prevent the extension script from running on this page until it next reloads
+ 
+ StopScriptButton=Stop script
+ DebugScriptButton=Debug script
+ WaitForScriptButton=Continue
+ DontAskAgain=&Don’t ask me again
+ JSURLLoadBlockedWarning=Attempt to load a javascript: URL from one host\nin a window displaying content from another host\nwas blocked by the security manager.
+ WindowCloseBlockedWarning=Scripts may not close windows that were not opened by script.
+ OnBeforeUnloadTitle=Are you sure?

+ 41 - 0
frg/253-58/mozilla-release58_428026.patch

@@ -0,0 +1,41 @@
+# HG changeset patch
+# User Simon Sapin <simon.sapin@exyr.org>
+# Date 1503333294 -7200
+#      Mon Aug 21 18:34:54 2017 +0200
+# Node ID db2a49c83d536d38fad916149e43a8fb35121f82
+# Parent  cd7b29a1f661f60177507a4e807320cab56397f9
+Bug 1392329 - Add a command-line front-end script for gtest microbenchmarks. r=froydnj
+
+Example usage:
+
+$ ./testing/gtest/bench.py Stylo*
+
+  29.779 ±  0.254 ms    Stylo.Servo_StyleSheet_FromUTF8Bytes_Bench
+  28.841 ±  0.031 ms    Stylo.Gecko_nsCSSParser_ParseSheet_Bench
+ 296.240 ±  4.744 ms    Stylo.Servo_DeclarationBlock_SetPropertyById_Bench
+ 293.855 ±  4.304 ms    Stylo.Servo_DeclarationBlock_SetPropertyById_WithInitialSpace_Bench
+
+MozReview-Commit-ID: L6vx8A8Iz9q
+
+diff --git a/testing/gtest/bench.py b/testing/gtest/bench.py
+new file mode 100644
+--- /dev/null
++++ b/testing/gtest/bench.py
+@@ -0,0 +1,17 @@
++#!/usr/bin/python3
++
++import sys, subprocess, json, statistics
++
++proc = subprocess.Popen(["./mach", "gtest", sys.argv[1]], stdout=subprocess.PIPE)
++for line in proc.stdout:
++    if line.startswith(b"PERFHERDER_DATA:"):
++        data = json.loads(line[len("PERFHERDER_DATA:"):].decode("utf8"))
++        for suite in data["suites"]:
++            for subtest in suite["subtests"]:
++                print("%4d.%03d ± %6s ms    %s.%s" % (
++                    subtest["value"] / 1000.,
++                    subtest["value"] % 1000,
++                    "%.3f" % (statistics.stdev(subtest["replicates"]) / 1000),
++                    suite["name"],
++                    subtest["name"],
++                ))

+ 2024 - 0
frg/253-58/mozilla-release58_428028.patch

@@ -0,0 +1,2024 @@
+# HG changeset patch
+# User Jonathan Kew <jkew@mozilla.com>
+# Date 1503346292 -3600
+#      Mon Aug 21 21:11:32 2017 +0100
+# Node ID ed3226f7ff560e2ff36c7a57562b918dc9bf7c28
+# Parent  94efdad0f42bf690ca69e790bb4c1c8aec27c451
+Bug 1391717 - Update imported CSS tests in layout/reftests/w3c-css/received. r=dholbert
+
+diff --git a/layout/reftests/w3c-css/README b/layout/reftests/w3c-css/README
+--- a/layout/reftests/w3c-css/README
++++ b/layout/reftests/w3c-css/README
+@@ -1,28 +1,30 @@
+ W3C CSS Test Suite Directory
+ ----------------------------
+ 
+ This directory is for tests that are sync'ed with the official
+-W3C CSS test suites at http://test.csswg.org/.
++W3C CSS test suites at https://github.com/w3c/web-platform-tests/.
+  
+ submitted/ is for tests that are to be submitted to W3C.
+ This directory is sync'ed automatically with the
+ contributors/mozilla/submitted/mozilla-central-reftests/
+ directory in the CSSWG repository. The master copy is Mozilla's.
+ 
+ received/ is for tests that are received from W3C.
+ This directory is sync'ed semi-automatically with the approved/
+ directory in the CSSWG repository. The master copy is CSSWG's.
+ Don't make changes here; they'll be overwritten by the next sync.
+ 
+-import-tests.py automatically imports tests from a cloned hg repository
+-of csswg tests, located at hg.csswg.org/test. Note that this will
+-remove everything in the received/ directory when run, so don't
+-store anything in there.
++import-tests.py automatically imports a selection of CSSWG tests
++from a clone of the https://github.com/w3c/web-platform-tests Git
++repository.
++
++Note that this will remove everything in the received/ directory when run,
++so don't store anything in there.
+ 
+ failures.list is a list of reftests that fail in mozilla's
+ implementation of a given css module. Since the tests in are
+ checked-in to the mozilla tree after import, they are run in
+ the same manner as all other reftests in the tree. Thus, these
+ tests are marked as fails() when included in the reftest.list
+ file, so that new imports will not reawaken old oranges.
+ 
+diff --git a/layout/reftests/w3c-css/failures.list b/layout/reftests/w3c-css/failures.list
+--- a/layout/reftests/w3c-css/failures.list
++++ b/layout/reftests/w3c-css/failures.list
+@@ -61,20 +61,20 @@ fails-if(!styloVsGecko) css-writing-mode
+ fails-if(!styloVsGecko) css-writing-modes-3/float-rgt-orthog-vrl-in-htb-003.xht
+ fails-if(!styloVsGecko) css-writing-modes-3/sizing-orthog-htb-in-vrl-001.xht
+ fails-if(!styloVsGecko) css-writing-modes-3/sizing-orthog-htb-in-vrl-004.xht
+ fails-if(!styloVsGecko) css-writing-modes-3/sizing-orthog-htb-in-vrl-013.xht
+ fails-if((OSX||winWidget||Android)&&!styloVsGecko) css-writing-modes-3/sizing-orthog-htb-in-vlr-008.xht
+ fails-if((OSX||winWidget||Android)&&!styloVsGecko) css-writing-modes-3/sizing-orthog-htb-in-vlr-020.xht
+ fails-if((OSX||winWidget||Android)&&!styloVsGecko) css-writing-modes-3/sizing-orthog-htb-in-vrl-008.xht
+ fails-if((OSX||winWidget||Android)&&!styloVsGecko) css-writing-modes-3/sizing-orthog-htb-in-vrl-020.xht
+-fails-if((OSX||winWidget||Android)&&!styloVsGecko) css-writing-modes-3/sizing-orthog-vlr-in-htb-008.xht
+-fails-if((OSX||winWidget||Android)&&!styloVsGecko) css-writing-modes-3/sizing-orthog-vlr-in-htb-020.xht
+-fails-if((OSX||winWidget||Android)&&!styloVsGecko) css-writing-modes-3/sizing-orthog-vrl-in-htb-008.xht
+-fails-if((OSX||winWidget||Android)&&!styloVsGecko) css-writing-modes-3/sizing-orthog-vrl-in-htb-020.xht
++css-writing-modes-3/sizing-orthog-vlr-in-htb-008.xht
++css-writing-modes-3/sizing-orthog-vlr-in-htb-020.xht
++css-writing-modes-3/sizing-orthog-vrl-in-htb-008.xht
++css-writing-modes-3/sizing-orthog-vrl-in-htb-020.xht
+ fails-if(Android) css-writing-modes-3/sizing-orthog-htb-in-vlr-003.xht
+ fails-if(Android) css-writing-modes-3/sizing-orthog-htb-in-vlr-009.xht
+ fails-if(Android) css-writing-modes-3/sizing-orthog-htb-in-vlr-015.xht
+ fails-if(Android) css-writing-modes-3/sizing-orthog-htb-in-vlr-021.xht
+ fails-if(Android) css-writing-modes-3/sizing-orthog-htb-in-vrl-003.xht
+ fails-if(Android) css-writing-modes-3/sizing-orthog-htb-in-vrl-009.xht
+ fails-if(Android) css-writing-modes-3/sizing-orthog-htb-in-vrl-015.xht
+ fails-if(Android) css-writing-modes-3/sizing-orthog-htb-in-vrl-021.xht
+@@ -106,23 +106,23 @@ fuzzy-if(OSX||winWidget,135,1080) css-wr
+ fuzzy-if(OSX||winWidget,111,960)  css-writing-modes-3/inline-block-alignment-srl-008.xht
+ fuzzy-if(OSX||winWidget,213,1540) css-writing-modes-3/line-box-direction-???-0??.xht
+ fuzzy-if(OSX||winWidget,110,1200) css-writing-modes-3/row-progression-???-0??.xht
+ fuzzy-if(OSX||winWidget,110,1200) css-writing-modes-3/table-column-order-00?.xht
+ fuzzy-if(winWidget,110,1200) css-writing-modes-3/table-column-order-slr-007.xht
+ fuzzy-if(OSX||winWidget,110,1200) css-writing-modes-3/table-column-order-srl-006.xht
+ fuzzy-if(OSX||winWidget,75,404)   css-writing-modes-3/text-align-v??-0??.xht
+ fuzzy-if(OSX||winWidget,215,780)  css-writing-modes-3/text-baseline-???-00?.xht
+-skip-if(stylo) fuzzy-if(OSX,15,16)    css-writing-modes-3/text-combine-upright-decorations-001.html
++fuzzy-if(OSX,15,16)    css-writing-modes-3/text-combine-upright-decorations-001.html
+ fuzzy-if(OSX||winWidget,255,480)  css-writing-modes-3/text-indent-v??-0??.xht
+ fuzzy-if(OSX||winWidget,226,960)  css-writing-modes-3/text-orientation-016.xht
+ fuzzy-if(OSX||winWidget,223,720)  css-writing-modes-3/vertical-alignment-*.xht
+ fuzzy-if(OSX||winWidget,153,612)  css-writing-modes-3/writing-mode-vertical-??-00?.*
+ fuzzy(255,960) css-writing-modes-3/text-combine-upright-value-all-00?.html
+-fuzzy(255,960) fails-if(stylo) css-writing-modes-3/text-combine-upright-value-all-001.html
++fuzzy(255,960) css-writing-modes-3/text-combine-upright-value-all-001.html
+ 
+ # Bug 1167911
+ skip css-writing-modes-3/abs-pos-non-replaced-icb-vlr-021.xht
+ skip css-writing-modes-3/abs-pos-non-replaced-icb-vrl-020.xht
+ 
+ # Bug 1244601
+ fails-if(!styloVsGecko) css-writing-modes-3/block-flow-direction-slr-058.xht
+ fails-if(!styloVsGecko) css-writing-modes-3/block-flow-direction-srl-057.xht
+@@ -181,18 +181,18 @@ fails-if(!styloVsGecko) css-writing-mode
+ fails-if(!styloVsGecko) css-writing-modes-3/wm-propagation-body-*.xht
+ 
+ css-writing-modes-3/text-combine-upright-layout-rules-001.html
+ 
+ #### CSS Multi-column 1 ##############################################
+ 
+ # Fuzzy annotations for multicol tests are due to AA differences.
+ # fails-if(!stylo) annotations need to be triaged later. (Bug 1299006)
+-fails-if(!styloVsGecko) css-multicol-1/multicol-block-clip-001.xht
+-fails-if(!styloVsGecko) css-multicol-1/multicol-block-clip-002.xht
++fails-if((winWidget||OSX)&&!styloVsGecko) css-multicol-1/multicol-block-no-clip-001.xht
++fails-if((winWidget||OSX)&&!styloVsGecko) css-multicol-1/multicol-block-no-clip-002.xht
+ fails-if(!styloVsGecko) css-multicol-1/multicol-br-inside-avoidcolumn-001.xht
+ fails-if(!styloVsGecko) css-multicol-1/multicol-break-000.xht
+ fails-if(!styloVsGecko) css-multicol-1/multicol-break-001.xht
+ fuzzy(135,1008) css-multicol-1/multicol-clip-001.xht
+ fuzzy(135,770) css-multicol-1/multicol-clip-002.xht
+ fuzzy(135,467) css-multicol-1/multicol-collapsing-001.xht
+ fuzzy(87,180) css-multicol-1/multicol-columns-001.xht
+ fuzzy(87,180) css-multicol-1/multicol-columns-002.xht
+@@ -205,19 +205,19 @@ fuzzy(204,930) fuzzy-if(skiaContent,208,
+ fails-if((OSX||winWidget)&&!styloVsGecko) css-multicol-1/multicol-columns-invalid-002.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) css-multicol-1/multicol-columns-toolong-001.xht
+ fuzzy(135,530) css-multicol-1/multicol-containing-001.xht
+ fuzzy(215,241) css-multicol-1/multicol-containing-002.xht
+ fuzzy(87,180) css-multicol-1/multicol-count-001.xht
+ fails-if(!styloVsGecko) css-multicol-1/multicol-count-002.xht
+ fails-if(!styloVsGecko) css-multicol-1/multicol-count-computed-001.xht
+ fails-if(!styloVsGecko) css-multicol-1/multicol-count-computed-002.xht
+-fails-if(!styloVsGecko) css-multicol-1/multicol-count-computed-003.xht
++fails-if((winWidget||OSX||Android)&&!styloVsGecko) css-multicol-1/multicol-count-computed-003.xht
+ fuzzy-if(winWidget||OSX||gtkWidget,112,861) fails-if(Android) css-multicol-1/multicol-count-computed-004.xht
+-fails-if(!styloVsGecko) css-multicol-1/multicol-count-computed-005.xht
++fails-if((winWidget||OSX||Android)&&!styloVsGecko) css-multicol-1/multicol-count-computed-005.xht
+ fails-if(!styloVsGecko) css-multicol-1/multicol-count-large-001.xht
+ fuzzy(255,132) css-multicol-1/multicol-count-large-002.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) css-multicol-1/multicol-count-negative-001.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) css-multicol-1/multicol-count-negative-002.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) css-multicol-1/multicol-count-non-integer-001.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) css-multicol-1/multicol-count-non-integer-002.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) css-multicol-1/multicol-count-non-integer-003.xht
+ fuzzy(135,80) css-multicol-1/multicol-fill-auto-002.xht
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/OWNERS b/layout/reftests/w3c-css/received/css-multicol-1/OWNERS
+--- a/layout/reftests/w3c-css/received/css-multicol-1/OWNERS
++++ b/layout/reftests/w3c-css/received/css-multicol-1/OWNERS
+@@ -1,1 +1,2 @@
+ @frivoal
++@rachelandrew
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-001-ref.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-001-ref.xht
+deleted file mode 100644
+--- a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-001-ref.xht
++++ /dev/null
+@@ -1,33 +0,0 @@
+-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+-<html xmlns="http://www.w3.org/1999/xhtml">
+- <head>
+-  <title>CSS Reftest Reference</title>
+-  <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
+-  <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-24 -->
+-  <meta name="flags" content="image" />
+-  <style type="text/css"><![CDATA[
+-  table
+-  {
+-  border-spacing: 0px;
+-  border: gray solid 1em;
+-  font: 1.25em/1 serif;
+-  }
+-
+-  td
+-  {
+-  padding: 0;
+-  width: 3em;
+-  }
+-
+-  td + td {width: 8em;}
+-
+-  img, td {vertical-align: top;}
+-  ]]></style>
+- </head>
+- <body>
+-  <table>
+-    <tr>
+-      <td><img src="support/swatch-blue.png" width="40" height="80" alt="Image download support must be enabled" /><img src="support/black20x20.png" width="50" height="20" alt="Image download support must be enabled" /></td><td><img src="support/swatch-orange.png" width="40" height="80" alt="Image download support must be enabled" /></td>
+-    </tr></table>
+- </body>
+-</html>
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-001.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-001.xht
+deleted file mode 100644
+--- a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-001.xht
++++ /dev/null
+@@ -1,55 +0,0 @@
+-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+-<html xmlns="http://www.w3.org/1999/xhtml">
+- <head>
+-  <title>CSS Multi-column Layout Test: Overflowed content inside multicol element</title>
+-  <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
+-  <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-24 -->
+-  <link rel="help" href="http://www.w3.org/TR/css3-multicol/#overflow-inside-multicol-elements" title="8.1. Overflow inside multicol elements" />
+-  <link rel="match" href="multicol-block-clip-001-ref.xht"/>
+-  <meta name="flags" content="ahem" />
+-  <meta name="assert" content="This test checks that content in the normal flow that extends into column gaps is clipped in the middle of the column gap." />
+-<style type="text/css"><![CDATA[
+-@font-face {
+-  font-family: Ahem;
+-  src: url("../../../fonts/Ahem.ttf");
+-}
+-]]></style>
+-  <style type="text/css"><![CDATA[
+-  div
+-  {
+-  border: gray solid 1em;
+-  font: 1.25em/1 Ahem;
+-  orphans: 1;
+-  widows: 1;
+-  width: 11em;
+-
+-  -moz-column-count: 4;
+-  -moz-column-gap: 1em;
+-  }
+-
+-  h4
+-  {
+-  background: black;
+-  color: black;
+-  font: inherit;
+-  margin: 0;
+-  width: 11em;
+-  }
+-
+-  #first-column {color: blue;}
+-
+-  #second-column {color: orange;}
+-
+-  #third-column, #fourth-column {color: white;}
+-  ]]></style>
+- </head>
+- <body>
+-  <div>
+-    <span id="first-column"> ab cd ef gh </span>
+-    <h4> 1234567890123 </h4>
+-    <span id="second-column"> ij kl mn oq </span>
+-    <span id="third-column"> ab cd ef gh </span>
+-    <span id="fourth-column"> rs tu vw xy </span>
+-  </div>
+- </body>
+-</html>
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-002-ref.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-002-ref.xht
+deleted file mode 100644
+--- a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-002-ref.xht
++++ /dev/null
+@@ -1,54 +0,0 @@
+-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+-<html xmlns="http://www.w3.org/1999/xhtml">
+- <head>
+-  <title>CSS Reftest Reference</title>
+-  <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
+-  <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-24 -->
+-  <meta name="flags" content="image" />
+-  <style type="text/css"><![CDATA[
+-  div
+-  {
+-  font: 1.25em/1 serif;
+-  border: 1em solid gray;
+-  width: 11em;
+-  height: 6em;
+-  position: relative;
+-  }
+-
+-  img {position: absolute;}
+-
+-  img#black {top: 4em;}
+-
+-  img#first-orange {top: 5em;}
+-
+-  img#second-orange {left: 4em;}
+-
+-  img#first-pink
+-  {
+-  left: 4em;
+-  top: 3em;
+-  }
+-
+-  img#second-pink {left: 8em;}
+-
+-  img#yellow
+-  {
+-  left: 8em;
+-  top: 1em;
+-  }
+-  ]]></style>
+- </head>
+- <body>
+-
+-  <div>
+-	<img id="blue" src="support/swatch-blue.png" width="40" height="80" alt="Image download support must be enabled" />
+-	<img id="black" src="support/black20x20.png" width="70" height="20" alt="Image download support must be enabled" />
+-	<img id="first-orange" src="support/swatch-orange.png" width="40" height="20" alt="Image download support must be enabled" />
+-	<img id="second-orange" src="support/swatch-orange.png" width="40" height="60" alt="Image download support must be enabled" />
+-	<img id="first-pink" src="support/swatch-pink.png" width="40" height="60" alt="Image download support must be enabled" />
+-	<img id="second-pink" src="support/swatch-pink.png" width="40" height="20" alt="Image download support must be enabled" />
+-	<img id="yellow" src="support/swatch-yellow.png" width="40" height="80" alt="Image download support must be enabled" />
+-  </div>
+-
+- </body>
+-</html>
+\ No newline at end of file
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-002.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-002.xht
+deleted file mode 100644
+--- a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-clip-002.xht
++++ /dev/null
+@@ -1,57 +0,0 @@
+-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+-<html xmlns="http://www.w3.org/1999/xhtml">
+- <head>
+-  <title>CSS Multi-column Layout Test: Overflowed content inside and outside multicol element</title>
+-  <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
+-  <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-24 -->
+-  <link rel="help" href="http://www.w3.org/TR/css3-multicol/#overflow-inside-multicol-elements" title="8.1. Overflow inside multicol elements" />
+-  <link rel="match" href="multicol-block-clip-002-ref.xht"/>
+-  <meta name="flags" content="ahem" />
+-  <meta name="assert" content="This test checks that content in the normal flow that extends into column gaps is clipped in the middle of the column gap." />
+-<style type="text/css"><![CDATA[
+-@font-face {
+-  font-family: Ahem;
+-  src: url("../../../fonts/Ahem.ttf");
+-}
+-]]></style>
+-  <style type="text/css"><![CDATA[
+-  div
+-  {
+-  border: gray solid 1em;
+-  font: 1.25em/1 Ahem;
+-  orphans: 1;
+-  widows: 1;
+-  width: 11em;
+-
+-  -moz-column-count: 3;
+-  -moz-column-gap: 1em;
+-  }
+-
+-  h4
+-  {
+-  background: black;
+-  color: black;
+-  font: inherit;
+-  margin: 0;
+-  width: 11em;
+-  }
+-
+-  #first-column {color: blue;}
+-
+-  #second-column {color: orange;}
+-
+-  #third-column {color: pink;}
+-
+-  #fourth-column {color: yellow;}
+-  ]]></style>
+- </head>
+- <body>
+-  <div>
+-    <span id="first-column"> ab cd ef gh </span>
+-    <h4> 1234567890123 </h4>
+-    <span id="second-column"> ij kl mn oq </span>
+-    <span id="third-column"> ab cd ef gh </span>
+-    <span id="fourth-column"> rs tu vw xy </span>
+-  </div>
+- </body>
+-</html>
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-001-ref.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-001-ref.xht
+new file mode 100644
+--- /dev/null
++++ b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-001-ref.xht
+@@ -0,0 +1,33 @@
++<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
++<html xmlns="http://www.w3.org/1999/xhtml">
++ <head>
++  <title>CSS Reftest Reference</title>
++  <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
++  <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-24 -->
++  <meta name="flags" content="image" />
++  <style type="text/css"><![CDATA[
++  table
++  {
++  border-spacing: 0px;
++  border: gray solid 1em;
++  font: 1.25em/1 serif;
++  }
++
++  td
++  {
++  padding: 0;
++  width: 3em;
++  }
++
++  td + td {width: 8em;}
++
++  img, td {vertical-align: top;}
++  ]]></style>
++ </head>
++ <body>
++  <table>
++    <tr>
++      <td><img src="support/swatch-blue.png" width="40" height="80" alt="Image download support must be enabled" /><img src="support/black20x20.png" width="60" height="20" alt="Image download support must be enabled" /></td><td><img src="support/swatch-orange.png" width="40" height="80" alt="Image download support must be enabled" /></td>
++    </tr></table>
++ </body>
++</html>
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-001.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-001.xht
+new file mode 100644
+--- /dev/null
++++ b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-001.xht
+@@ -0,0 +1,54 @@
++<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
++<html xmlns="http://www.w3.org/1999/xhtml">
++ <head>
++  <title>CSS Multi-column Layout Test: Overflowed content inside multicol element</title>
++  <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
++  <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-24 -->
++  <link rel="help" href="http://www.w3.org/TR/css3-multicol/#overflow-inside-multicol-elements" title="8.1. Overflow inside multicol elements" />
++  <link rel="match" href="multicol-block-no-clip-001-ref.xht"/>
++  <meta name="flags" content="ahem" />
++  <meta name="assert" content="This test checks that content in the normal flow that extends into column gaps is not clipped in the middle of the column gap." />
++<style type="text/css"><![CDATA[
++@font-face {
++  font-family: Ahem;
++  src: url("../../../fonts/Ahem.ttf");
++}
++]]></style>
++  <style type="text/css"><![CDATA[
++  div
++  {
++  border: gray solid 1em;
++  font: 1.25em/1 Ahem;
++  orphans: 1;
++  widows: 1;
++  width: 11em;
++
++  -moz-column-count: 4;
++  -moz-column-gap: 1em;
++  }
++
++  h4
++  {
++  background: black;
++  color: black;
++  font: inherit;
++  margin: 0;
++  }
++
++  #first-column {color: blue;}
++
++  #second-column {color: orange;}
++
++  #third-column, #fourth-column {color: white;}
++  ]]></style>
++ </head>
++ <body>
++  <div>
++    <span id="first-column"> ab cd ef gh </span>
++    <h4>123</h4>
++    <span id="second-column"> ij kl mn oq </span>
++    <span id="third-column"> ab cd ef gh </span>
++    <span id="fourth-column"> rs tu vw xy </span>
++  </div>
++ </body>
++</html>
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-002-ref.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-002-ref.xht
+new file mode 100644
+--- /dev/null
++++ b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-002-ref.xht
+@@ -0,0 +1,54 @@
++<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
++<html xmlns="http://www.w3.org/1999/xhtml">
++ <head>
++  <title>CSS Reftest Reference</title>
++  <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
++  <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-24 -->
++  <meta name="flags" content="image" />
++  <style type="text/css"><![CDATA[
++  div
++  {
++  font: 1.25em/1 serif;
++  border: 1em solid gray;
++  width: 11em;
++  height: 6em;
++  position: relative;
++  }
++
++  img {position: absolute;}
++
++  img#black {top: 4em;}
++
++  img#first-orange {top: 5em;}
++
++  img#second-orange {left: 4em;}
++
++  img#first-pink
++  {
++  left: 4em;
++  top: 3em;
++  }
++
++  img#second-pink {left: 8em;}
++
++  img#yellow
++  {
++  left: 8em;
++  top: 1em;
++  }
++  ]]></style>
++ </head>
++ <body>
++
++  <div>
++	<img id="blue" src="support/swatch-blue.png" width="40" height="80" alt="Image download support must be enabled" />
++	<img id="black" src="support/black20x20.png" width="80" height="20" alt="Image download support must be enabled" />
++	<img id="first-orange" src="support/swatch-orange.png" width="40" height="20" alt="Image download support must be enabled" />
++	<img id="second-orange" src="support/swatch-orange.png" width="40" height="60" alt="Image download support must be enabled" />
++	<img id="first-pink" src="support/swatch-pink.png" width="40" height="60" alt="Image download support must be enabled" />
++	<img id="second-pink" src="support/swatch-pink.png" width="40" height="20" alt="Image download support must be enabled" />
++	<img id="yellow" src="support/swatch-yellow.png" width="40" height="80" alt="Image download support must be enabled" />
++  </div>
++
++ </body>
++</html>
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-002.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-002.xht
+new file mode 100644
+--- /dev/null
++++ b/layout/reftests/w3c-css/received/css-multicol-1/multicol-block-no-clip-002.xht
+@@ -0,0 +1,56 @@
++<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
++<html xmlns="http://www.w3.org/1999/xhtml">
++ <head>
++  <title>CSS Multi-column Layout Test: Overflowed content inside and outside multicol element</title>
++  <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
++  <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-24 -->
++  <link rel="help" href="http://www.w3.org/TR/css3-multicol/#overflow-inside-multicol-elements" title="8.1. Overflow inside multicol elements" />
++  <link rel="match" href="multicol-block-no-clip-002-ref.xht"/>
++  <meta name="flags" content="ahem" />
++  <meta name="assert" content="This test checks that content in the normal flow that extends into column gaps is not clipped in the middle of the column gap." />
++<style type="text/css"><![CDATA[
++@font-face {
++  font-family: Ahem;
++  src: url("../../../fonts/Ahem.ttf");
++}
++]]></style>
++  <style type="text/css"><![CDATA[
++  div
++  {
++  border: gray solid 1em;
++  font: 1.25em/1 Ahem;
++  orphans: 1;
++  widows: 1;
++  width: 11em;
++
++  -moz-column-count: 3;
++  -moz-column-gap: 1em;
++  }
++
++  h4
++  {
++  background: black;
++  color: black;
++  font: inherit;
++  margin: 0;
++  }
++
++  #first-column {color: blue;}
++
++  #second-column {color: orange;}
++
++  #third-column {color: pink;}
++
++  #fourth-column {color: yellow;}
++  ]]></style>
++ </head>
++ <body>
++  <div>
++    <span id="first-column"> ab cd ef gh </span>
++    <h4>1234</h4>
++    <span id="second-column"> ij kl mn oq </span>
++    <span id="third-column"> ab cd ef gh </span>
++    <span id="fourth-column"> rs tu vw xy </span>
++  </div>
++ </body>
++</html>
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-clip-001.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-clip-001.xht
+--- a/layout/reftests/w3c-css/received/css-multicol-1/multicol-clip-001.xht
++++ b/layout/reftests/w3c-css/received/css-multicol-1/multicol-clip-001.xht
+@@ -2,17 +2,17 @@
+ <html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+   <title>CSS Multi-column Layout Test: overflowed content inside and outside multicol element</title>
+   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
+   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-24 -->
+   <link rel="help" href="http://www.w3.org/TR/css3-multicol/#overflow-inside-multicol-elements" title="8.1. Overflow inside multicol elements" />
+   <link rel="match" href="multicol-clip-001-ref.xht" />
+   <meta name="flags" content="ahem" />
+-  <meta name="assert" content="This test checks that content in the normal flow can extend into column gap before it reaches its middle. In this test, the 'l' and 'c' glyphs are painted into the left half of the column gap; the 'l' and 'e' glyphs extend outside the last column box at the edge of the multi-column and are therefore rendered thanks to the default 'overflow: visible' declaration." />
++  <meta name="assert" content="This test checks that content in the normal flow can extend into column gap. In this test, the 'l' and 'c' glyphs are painted into the left half of the column gap; the 'l' and 'e' glyphs extend outside the last column box at the edge of the multi-column and are therefore rendered thanks to the default 'overflow: visible' declaration." />
+ <style type="text/css"><![CDATA[
+ @font-face {
+   font-family: Ahem;
+   src: url("../../../fonts/Ahem.ttf");
+ }
+ ]]></style>
+   <style type="text/css"><![CDATA[
+   div
+@@ -42,9 +42,9 @@
+ 
+     <span>
+     bl ac
+     </span>
+     bl ue
+   </div>
+ 
+  </body>
+-</html>
+\ No newline at end of file
++</html>
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-003-ref.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-003-ref.xht
+--- a/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-003-ref.xht
++++ b/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-003-ref.xht
+@@ -10,16 +10,16 @@
+   img {vertical-align: top;}
+   ]]></style>
+  </head>
+ 
+  <body>
+ 
+   <div><img src="support/swatch-gray.png" width="300" height="20" alt="Image download support must be enabled" /></div>
+ 
+-  <div><img src="support/swatch-gray.png" width="20" height="20" alt="Image download support must be enabled" /><img src="support/swatch-pink.png" width="70" height="20" alt="Image download support must be enabled" /><img src="support/swatch-blue.png" width="15" height="20" alt="Image download support must be enabled" /><img src="support/swatch-yellow.png" width="35" height="20" alt="Image download support must be enabled" /><img src="support/swatch-purple.png" width="80" height="20" alt="Image download support must be enabled" /><img src="support/swatch-yellow.png" width="60" height="20" alt="Image download support must be enabled" /><img src="support/swatch-gray.png" width="20" height="20" alt="Image download support must be enabled" /></div>
++  <div><img src="support/swatch-gray.png" width="20" height="20" alt="Image download support must be enabled" /><img src="support/swatch-pink.png" width="80" height="20" alt="Image download support must be enabled" /><img src="support/swatch-blue.png" width="5" height="20" alt="Image download support must be enabled" /><img src="support/swatch-yellow.png" width="35" height="20" alt="Image download support must be enabled" /><img src="support/swatch-purple.png" width="80" height="20" alt="Image download support must be enabled" /><img src="support/swatch-yellow.png" width="60" height="20" alt="Image download support must be enabled" /><img src="support/swatch-gray.png" width="20" height="20" alt="Image download support must be enabled" /></div>
+ 
+-  <div><img src="support/swatch-gray.png" width="20" height="20" alt="Image download support must be enabled" /><img src="support/swatch-orange.png" width="70" height="20" alt="Image download support must be enabled" /><img src="support/swatch-blue.png" width="15" height="20" alt="Image download support must be enabled" /><img src="support/swatch-yellow.png" width="35" height="20" alt="Image download support must be enabled" /><img src="support/swatch-gray.png" width="80" height="20" alt="Image download support must be enabled" /><img src="support/swatch-yellow.png" width="60" height="20" alt="Image download support must be enabled" /><img src="support/swatch-gray.png" width="20" height="20" alt="Image download support must be enabled" /></div>
++  <div><img src="support/swatch-gray.png" width="20" height="20" alt="Image download support must be enabled" /><img src="support/swatch-orange.png" width="80" height="20" alt="Image download support must be enabled" /><img src="support/swatch-blue.png" width="5" height="20" alt="Image download support must be enabled" /><img src="support/swatch-yellow.png" width="35" height="20" alt="Image download support must be enabled" /><img src="support/swatch-gray.png" width="80" height="20" alt="Image download support must be enabled" /><img src="support/swatch-yellow.png" width="60" height="20" alt="Image download support must be enabled" /><img src="support/swatch-gray.png" width="20" height="20" alt="Image download support must be enabled" /></div>
+ 
+   <div><img src="support/swatch-gray.png" width="300" height="20" alt="Image download support must be enabled" /></div>
+ 
+  </body>
+-</html>
+\ No newline at end of file
++</html>
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-003.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-003.xht
+--- a/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-003.xht
++++ b/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-003.xht
+@@ -2,17 +2,17 @@
+ <html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+   <title>CSS Multi-column Layout Test: -moz-column-rule and overflow inside (complex test)</title>
+   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
+   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-07-29 -->
+   <link rel="help" href="http://www.w3.org/TR/css3-multicol/#the-number-and-width-of-columns" title="3. The number and width of -moz-columns" />
+   <link rel="match" href="multicol-count-computed-003-ref.xht" />
+   <meta name="flags" content="ahem" />
+-  <meta name="assert" content="This test checks that if one of 2 adjacent column boxes (2nd and 3rd colum box in this test) does not have any content, then the column rule separating those should not be drawn. In this test, the 3rd colum box should have no inline content. This test also checks that inline content in the normal flow that extends into a column gap should be clipped in the middle of the column gap. So, in this test, inline content in 1st column box should be partially clipped and overlapped partially by 1st -moz-column-rule." />
++  <meta name="assert" content="This test checks that if one of 2 adjacent column boxes (2nd and 3rd colum box in this test) does not have any content, then the column rule separating those should not be drawn. In this test, the 3rd colum box should have no inline content. This test also checks that inline content in the normal flow that extends into a column gap should not be clipped in the middle of the column gap. So, in this test, inline content in 1st column box should not be clipped and should overlappe partially the 1st -moz-column-rule." />
+ <style type="text/css"><![CDATA[
+ @font-face {
+   font-family: Ahem;
+   src: url("../../../fonts/Ahem.ttf");
+ }
+ ]]></style>
+   <style type="text/css"><![CDATA[
+   div
+@@ -54,23 +54,21 @@
+   #pink {color: pink;}
+   #orange {color: orange;}
+   #purple {color: purple;}
+   #gray {color: gray;}
+ 
+   /*
+   Since
+   "
+-  Content in the normal flow that extends into
+-  column gaps (e.g., long words or images) is
+-  clipped in the middle of the column gap.
++  content that extends outside column boxes visibly overflows and is not clipped to the column box.
+   "
+-  http://www.w3.org/TR/css3-multicol/#overflow-inside-multicol-elements
++  https://drafts.csswg.org/css-multicol-1/#overflow-inside-multicol-elements
+   this causes the right-half (0.5em) of the 'K' glyph to
+-  be overlapped by the right-half (0.75em) of the 1st blue -moz-column-rule.
++  overlap the right-half (0.75em) of the 1st blue -moz-column-rule.
+   Same thing should happen to the 'N' glyph of 'ORAN'.
+ 
+   Because no inline content should be rendered into the
+   3rd column box, this causes the 2nd column rule not
+   been rendered because
+   "
+   Column rules are only drawn between two -moz-columns that
+   both have content.
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-005.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-005.xht
+--- a/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-005.xht
++++ b/layout/reftests/w3c-css/received/css-multicol-1/multicol-count-computed-005.xht
+@@ -2,17 +2,17 @@
+ <html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+   <title>CSS Multi-column Layout Test: -moz-column-rule and overflow inside (complex test)</title>
+   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
+   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-08-03 -->
+   <link rel="help" href="http://www.w3.org/TR/css3-multicol/#the-number-and-width-of-columns" title="3. The number and width of -moz-columns" />
+   <link rel="match" href="multicol-count-computed-003-ref.xht" />
+   <meta name="flags" content="ahem" />
+-  <meta name="assert" content="This test checks that if one of 2 adjacent column boxes (2nd and 3rd colum box in this test) does not have any content, then the column rule separating those should not be drawn. In this test, the 3rd colum box should have no inline content. This test also checks that inline content in the normal flow that extends into a column gap should be clipped in the middle of the column gap. So, in this test, inline content in 1st column box should be partially clipped and overlapped partially by 1st -moz-column-rule." />
++  <meta name="assert" content="This test checks that if one of 2 adjacent column boxes (2nd and 3rd colum box in this test) does not have any content, then the column rule separating those should not be drawn. In this test, the 3rd colum box should have no inline content. This test also checks that inline content in the normal flow that extends into a column gap should not be clipped in the middle of the column gap. So, in this test, inline content in 1st column box should not be partially clipped and should overlap partially with the 1st -moz-column-rule." />
+ <style type="text/css"><![CDATA[
+ @font-face {
+   font-family: Ahem;
+   src: url("../../../fonts/Ahem.ttf");
+ }
+ ]]></style>
+   <style type="text/css"><![CDATA[
+   div
+@@ -58,23 +58,21 @@
+   #pink {color: pink;}
+   #orange {color: orange;}
+   #purple {color: purple;}
+   #gray {color: gray;}
+ 
+   /*
+   Since
+   "
+-  Content in the normal flow that extends into
+-  column gaps (e.g., long words or images) is
+-  clipped in the middle of the column gap.
++  content that extends outside column boxes visibly overflows and is not clipped to the column box
+   "
+   http://www.w3.org/TR/css3-multicol/#overflow-inside-multicol-elements
+   this causes the right-half (0.5em) of the 'K' glyph to
+-  be overlapped by the right-half (0.75em) of the 1st blue -moz-column-rule.
++  overlap with the right-half (0.75em) of the 1st blue -moz-column-rule.
+   Same thing should happen to the 'N' glyph of 'ORAN'.
+ 
+   Because no inline content should be rendered into the
+   3rd column box, this causes the 2nd column rule not
+   been rendered because
+   "
+   Column rules are only drawn between two -moz-columns that
+   both have content.
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-gap-large-001.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-gap-large-001.xht
+--- a/layout/reftests/w3c-css/received/css-multicol-1/multicol-gap-large-001.xht
++++ b/layout/reftests/w3c-css/received/css-multicol-1/multicol-gap-large-001.xht
+@@ -2,17 +2,17 @@
+ <html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+   <title>CSS Multi-column Layout Test: '-moz-column-gap' with large value</title>
+   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
+   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-08-06 -->
+   <link rel="help" href="http://www.w3.org/TR/css3-multicol/#column-gap" title="4.1 '-moz-column-gap" />
+   <link rel="match" href="multicol-gap-large-001-ref.xht" />
+   <meta name="flags" content="ahem" />
+-  <meta name="assert" content="This test checks that when '-moz-column-gap' is large and when used '-moz-column-width' is narrow, then content extends into -moz-column-gap until its middle and content can extend, overflow outside the edges of the multi-colum element if 'overflow' is set to 'visible'." />
++  <meta name="assert" content="This test checks that when '-moz-column-gap' is large and when used '-moz-column-width' is narrow, then content extends into -moz-column-gap and content can extend, overflow outside the edges of the multi-colum element if 'overflow' is set to 'visible'." />
+ <style type="text/css"><![CDATA[
+ @font-face {
+   font-family: Ahem;
+   src: url("../../../fonts/Ahem.ttf");
+ }
+ ]]></style>
+   <style type="text/css"><![CDATA[
+   div
+diff --git a/layout/reftests/w3c-css/received/css-multicol-1/multicol-width-small-001.xht b/layout/reftests/w3c-css/received/css-multicol-1/multicol-width-small-001.xht
+--- a/layout/reftests/w3c-css/received/css-multicol-1/multicol-width-small-001.xht
++++ b/layout/reftests/w3c-css/received/css-multicol-1/multicol-width-small-001.xht
+@@ -3,17 +3,17 @@
+  <head>
+   <title>CSS Multi-column Layout Test: narrow -moz-column-width</title>
+   <link rel="author" title="Opera Software ASA" href="http://www.opera.com/" />
+   <link rel="reviewer" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" /> <!-- 2013-08-24 -->
+   <link rel="help" href="http://www.w3.org/TR/css3-multicol/#overflow-inside-multicol-elements" title="8.1. Overflow inside multicol elements" />
+   <link rel="help" href="http://www.w3.org/TR/css3-multicol/#cw" title="3.1. '-moz-column-width'" />
+   <link rel="match" href="multicol-width-small-001-ref.xht" />
+   <meta name="flags" content="ahem" />
+-  <meta name="assert" content="This test checks that a set '-moz-column-width' which is small with regards to width of multi-column element. In this test, in-flow content that extends into column gaps is clipped in the middle of the column gap. " />
++  <meta name="assert" content="This test checks that a set '-moz-column-width' which is small with regards to width of multi-column element." />
+ <style type="text/css"><![CDATA[
+ @font-face {
+   font-family: Ahem;
+   src: url("../../../fonts/Ahem.ttf");
+ }
+ ]]></style>
+   <style type="text/css"><![CDATA[
+   div
+@@ -48,14 +48,12 @@
+   <!--
+ 
+   Expected results
+ 
+   *************************
+   *B|a|b|u|b|u|B|a| | | | *
+   *************************
+ 
+-  Every "l", "c" and "e" glyphs are clipped.
+-
+   -->
+ 
+  </body>
+ </html>
+diff --git a/layout/reftests/w3c-css/received/css-values-3/attr-invalid-type-003.html b/layout/reftests/w3c-css/received/css-values-3/attr-invalid-type-003.html
+deleted file mode 100644
+--- a/layout/reftests/w3c-css/received/css-values-3/attr-invalid-type-003.html
++++ /dev/null
+@@ -1,46 +0,0 @@
+-<!DOCTYPE html>
+-<html>
+-<head>
+-	<meta charset="utf-8">
+-	<title>
+-		CSS Values and Units Test:
+-		Attribute references (types)
+-	</title>
+-	<meta name="assert" content="
+-		When the type of an att() function is known and unexpected, the declaration is ignored
+-	" />
+-
+-	<link
+-		rel="author"
+-		title="François REMY"
+-		href="mailto:fremycompany.developer@yahoo.fr"
+-	/ >
+-
+-	<link rel="help" href="http://www.w3.org/TR/css3-values/#attr-notation"/>
+-
+-	<link
+-		rel="match"
+-		href="reference/200-200-green.html"
+-	/>
+-
+-	<style type="text/css">
+-
+-			html, body { margin: 0px; padding: 0px; }
+-
+-			html { background: white; overflow: hidden; }
+-			#outer { position: relative; background: green; }
+-
+-			#outer { width: 200px; width: attr(data-test number); height: 200px; }
+-			/* NOTE: while '0' is a valid length AND a valid number, the number type isn't a valid representation of a length. */
+-			/* The reason for this is that most numbers aren't valid length */
+-			/* ! Spec need some updates to make those assumptions clearly valid (see Tab Atkins for details) */
+-
+-	</style>
+-
+-</head>
+-<body>
+-
+-	<div id="outer" data-test="0"></div>
+-
+-</body>
+-</html>
+diff --git a/layout/reftests/w3c-css/received/css-values-3/support/vh_not_refreshing_on_chrome_iframe.html b/layout/reftests/w3c-css/received/css-values-3/support/vh_not_refreshing_on_chrome_iframe.html
+new file mode 100644
+--- /dev/null
++++ b/layout/reftests/w3c-css/received/css-values-3/support/vh_not_refreshing_on_chrome_iframe.html
+@@ -0,0 +1,81 @@
++<!DOCTYPE html>
++<html>
++<!-- Submitted from TestTWF Paris -->
++<head>
++
++	<title>CSS Values and Units Test: vh-based dimension doesn't change when the element other dimension doesn't change.</title>
++
++	<style type="text/css">
++
++		* { margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; font-size: 13px; }
++
++			/* the first test box has its vertical dimension is set to some vh units */
++		#testBoxWithVhOnly { background: #F00; width: 60px; height: 20vh; float: left; }
++
++			/* the second test box, with fixed height */
++		#testBoxNotGrownHorizontallyByJS { background: #F0F; width: 20vh; height: 60px; float: left; }
++
++			/* third box, changed by using CSS transition */
++		#testBoxWithTransition { background: #FF0; width: 20vh; height: 40px; float: left;
++			transition-property:       width, height;
++			transition-duration:       1.5s;
++			transition-delay:          0;
++		}
++
++			/* the reference box, growing in both directions (height by js, width by vh unit */
++		#referenceBoxGrownHorizontallyByJS { background: #0F0; width: 20vh; height: 40px; float: left; }
++
++		p { clear: both; margin: 10px 0; }
++
++	</style>
++
++</head>
++<body>
++
++<p>
++	All boxes should end up the same size. The green box is the reference one.
++</p>
++
++<div id="testBoxWithVhOnly"></div>
++<div id="testBoxNotGrownHorizontallyByJS"></div>
++<div id="testBoxWithTransition"></div>
++<div id="referenceBoxGrownHorizontallyByJS"></div>
++
++<script type="text/javascript">
++
++	// In case this file was opened by mistake, redirects to proper test
++	if (window.top.location.href  === document.location.href) {
++
++		window.top.location.href = "vh_not_refreshing_on_chrome.html";
++
++	}
++
++	function setDimension(id, dimension, value) {
++
++		var element = document.getElementById(id);
++
++		element.style[dimension] = value + "px";
++
++	}
++
++	function animate() {
++
++		var viewportHeight = document.documentElement.clientHeight;
++
++		var sizeH = 20;
++
++		var referenceDimension = Math.round(sizeH * viewportHeight / 100);
++
++		setDimension('referenceBoxGrownHorizontallyByJS', 'height', referenceDimension);
++
++		setTimeout(animate, 20);
++	}
++
++	setTimeout(animate, 20);
++
++	var transitionedTestBoxStyle = document.getElementById('testBoxWithTransition').style;
++	transitionedTestBoxStyle.height = "60px";
++</script>
++
++</body>
++</html>
+diff --git a/layout/reftests/w3c-css/received/css-values-3/vh_not_refreshing_on_chrome.html b/layout/reftests/w3c-css/received/css-values-3/vh_not_refreshing_on_chrome.html
+--- a/layout/reftests/w3c-css/received/css-values-3/vh_not_refreshing_on_chrome.html
++++ b/layout/reftests/w3c-css/received/css-values-3/vh_not_refreshing_on_chrome.html
+@@ -42,12 +42,12 @@
+ 		}
+ 
+ 		setTimeout(resizeReference, 10);
+ 	</script>
+ 
+ </head>
+ <body>
+ 
+-<iframe id="frameTest" src="vh_not_refreshing_on_chrome_iframe.html" frameborder="0"></iframe>
++<iframe id="frameTest" src="support/vh_not_refreshing_on_chrome_iframe.html" frameborder="0"></iframe>
+ 
+ </body>
+ </html>
+diff --git a/layout/reftests/w3c-css/received/css-values-3/vh_not_refreshing_on_chrome_iframe.html b/layout/reftests/w3c-css/received/css-values-3/vh_not_refreshing_on_chrome_iframe.html
+deleted file mode 100644
+--- a/layout/reftests/w3c-css/received/css-values-3/vh_not_refreshing_on_chrome_iframe.html
++++ /dev/null
+@@ -1,85 +0,0 @@
+-<!DOCTYPE html>
+-<html>
+-<!-- Submitted from TestTWF Paris -->
+-<head>
+-
+-	<title>CSS Values and Units Test: vh-based dimension doesn't change when the element other dimension doesn't change.</title>
+-	<meta name="assert" content="vh-based dimension doesn't change when the element other dimension doesn't change. Bug for Chrome 19.0.1084.56 / Mac OS X 10.6.8">
+-	<link rel="author" title="Marc Bourlon" href="mailto:marc@bourlon.com">
+-	<link rel="help" href="http://www.w3.org/TR/css3-values/#viewport-relative-lengths" title="5.1.2. Viewport-percentage lengths: the 'vw', 'vh', 'vmin', 'vmax' units">
+-	<link rel="match" href="reference/vh_not_refreshing_on_chrome-ref.html">
+-
+-	<style type="text/css">
+-
+-		* { margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; font-size: 13px; }
+-
+-			/* the first test box has its vertical dimension is set to some vh units */
+-		#testBoxWithVhOnly { background: #F00; width: 60px; height: 20vh; float: left; }
+-
+-			/* the second test box, with fixed height */
+-		#testBoxNotGrownHorizontallyByJS { background: #F0F; width: 20vh; height: 60px; float: left; }
+-
+-			/* third box, changed by using CSS transition */
+-		#testBoxWithTransition { background: #FF0; width: 20vh; height: 40px; float: left;
+-			transition-property:       width, height;
+-			transition-duration:       1.5s;
+-			transition-delay:          0;
+-		}
+-
+-			/* the reference box, growing in both directions (height by js, width by vh unit */
+-		#referenceBoxGrownHorizontallyByJS { background: #0F0; width: 20vh; height: 40px; float: left; }
+-
+-		p { clear: both; margin: 10px 0; }
+-
+-	</style>
+-
+-</head>
+-<body>
+-
+-<p>
+-	All boxes should end up the same size. The green box is the reference one.
+-</p>
+-
+-<div id="testBoxWithVhOnly"></div>
+-<div id="testBoxNotGrownHorizontallyByJS"></div>
+-<div id="testBoxWithTransition"></div>
+-<div id="referenceBoxGrownHorizontallyByJS"></div>
+-
+-<script type="text/javascript">
+-
+-	// In case this file was opened by mistake, redirects to proper test
+-	if (window.top.location.href  === document.location.href) {
+-
+-		window.top.location.href = "vh_not_refreshing_on_chrome.html";
+-
+-	}
+-
+-	function setDimension(id, dimension, value) {
+-
+-		var element = document.getElementById(id);
+-
+-		element.style[dimension] = value + "px";
+-
+-	}
+-
+-	function animate() {
+-
+-		var viewportHeight = document.documentElement.clientHeight;
+-
+-		var sizeH = 20;
+-
+-		var referenceDimension = Math.round(sizeH * viewportHeight / 100);
+-
+-		setDimension('referenceBoxGrownHorizontallyByJS', 'height', referenceDimension);
+-
+-		setTimeout(animate, 20);
+-	}
+-
+-	setTimeout(animate, 20);
+-
+-	var transitionedTestBoxStyle = document.getElementById('testBoxWithTransition').style;
+-	transitionedTestBoxStyle.height = "60px";
+-</script>
+-
+-</body>
+-</html>
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vlr-007.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vlr-007.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vlr-007.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vlr-007.xht
+@@ -11,17 +11,17 @@
+ 
+   <title>CSS Writing Modes Test: vertical-lr - contiguous floated tables and horizontal margins</title>
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
+ 
+   <meta content="image" name="flags" />
+-  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-lr' are not substracted by the amount of their borders. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
++  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-lr' are not subtracted by the amount of their borders. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   table
+     {
+       border-collapse: separate;
+       border-spacing: 0px;
+       float: left;
+       height: 100px;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vlr-009.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vlr-009.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vlr-009.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vlr-009.xht
+@@ -11,17 +11,17 @@
+ 
+   <title>CSS Writing Modes Test: vertical-lr - contiguous floated tables and horizontal margins</title>
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
+ 
+   <meta content="image" name="flags" />
+-  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-lr' are not substracted by the amount of their horizontal padding. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
++  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-lr' are not subtracted by the amount of their horizontal padding. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   table
+     {
+       background-color: green;
+       border-collapse: separate;
+       border-spacing: 0px;
+       float: left;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vrl-006.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vrl-006.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vrl-006.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vrl-006.xht
+@@ -11,17 +11,17 @@
+ 
+   <title>CSS Writing Modes Test: vertical-rl - contiguous floated tables and horizontal margins</title>
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
+ 
+   <meta content="image" name="flags" />
+-  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-rl' are not substracted by the amount of their borders. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
++  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-rl' are not subtracted by the amount of their borders. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   table
+     {
+       border-collapse: separate;
+       border-spacing: 0px;
+       float: left;
+       height: 100px;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vrl-008.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vrl-008.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vrl-008.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/contiguous-floated-table-vrl-008.xht
+@@ -11,17 +11,17 @@
+ 
+   <title>CSS Writing Modes Test: vertical-rl - contiguous floated tables and horizontal margins</title>
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
+ 
+   <meta content="image" name="flags" />
+-  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-rl' are not substracted by the amount of their horizontal padding. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
++  <meta content="This test checks that horizontal margins existing between contiguous floated tables with writing-mode set to 'vertical-rl' are not subtracted by the amount of their horizontal padding. In this test, there should be an horizontal gap of 50px separating both tables. Margins between 2 floated boxes do not collapse." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   table
+     {
+       background-color: green;
+       border-collapse: separate;
+       border-spacing: 0px;
+       float: left;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-003.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-003.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-003.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-003.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vlr-003-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-005.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-005.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-005.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-005.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vlr-003-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-007.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-007.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-007.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-007.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vlr-007-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-009.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-009.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-009.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-009.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vlr-007-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-011.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-011.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-011.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-011.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vlr-011-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-013.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-013.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-013.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-013.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vlr-011-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-021.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-021.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-021.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-021.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vlr-021-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+   <meta name="DC.date.created" content="2015-07-22T09:54:03+11:00" scheme=
+   "W3CDTF" />
+   <meta name="DC.date.modified" content="2016-07-22T09:54:03+11:00" scheme=
+   "W3CDTF" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-023.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-023.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-023.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vlr-023.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vlr-023-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+   <meta name="DC.date.created" content="2015-07-22T09:54:03+11:00" scheme="W3CDTF" />
+   <meta name="DC.date.modified" content="2016-07-22T09:54:03+11:00" scheme="W3CDTF" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-002.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-002.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-002.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-002.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vrl-002-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-004.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-004.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-004.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-004.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vrl-002-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-006.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-006.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-006.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-006.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vrl-006-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-008.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-008.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-008.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-008.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vrl-006-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-010.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-010.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-010.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-010.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vrl-010-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a border. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'border-left' of inline box and transparent 'border-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-012.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-012.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-012.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/line-box-height-vrl-012.xht
+@@ -12,17 +12,17 @@
+   -->
+ 
+   <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
+   <link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes" />
+   <link rel="help" href="http://www.w3.org/TR/CSS21/visudet.html#line-height" title="10.8.1 Leading and half-leading" />
+   <link rel="match" href="line-box-height-vrl-010-ref.xht" />
+ 
+   <meta content="" name="flags" />
+-  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accomodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
++  <meta content="This test checks that a line box height does not increase because an inline non-replaced box has a padding. In this test, the '34' inline box and the '56' inline box should be lined up with its inline '12' sibling. The line box height, enclosed by the blue border should not grow to accommodate transparent 'padding-left' of inline box and transparent 'padding-right' of inline box." name="assert" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       margin-left: 32px;
+     }
+ 
+   div
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-008-ref.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-008-ref.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-008-ref.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-008-ref.xht
+@@ -12,16 +12,17 @@
+   <meta name="DC.date.modified" content="2017-01-03T09:54:03+11:00" scheme="W3CDTF" />
+ 
+   <meta content="" name="flags" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin: 8px 0px;
+     }
+ 
+   table
+     {
+       border-spacing: 0px;
+       left: 0px;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-008.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-008.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-008.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-008.xht
+@@ -63,16 +63,17 @@
+   html
+     {
+       writing-mode: vertical-lr;
+     }
+ 
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin-left: 100px;
+       margin-right: 100px;
+     }
+ 
+   div#sized-400px-vlr-containing-block
+     {
+       width: 400px;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-020-ref.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-020-ref.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-020-ref.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-020-ref.xht
+@@ -12,16 +12,17 @@
+   <meta name="DC.date.modified" content="2016-12-30T09:54:03+11:00" scheme="W3CDTF" />
+ 
+   <meta content="" name="flags" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin: 8px 0px;
+     }
+ 
+   table
+     {
+       border-spacing: 0px;
+       position: absolute;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-020.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-020.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-020.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vlr-020.xht
+@@ -63,16 +63,17 @@
+   html
+     {
+       writing-mode: vertical-lr;
+     }
+ 
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin-left: 0px;
+       margin-right: 0px;
+     }
+ 
+   div#sized-400px-vlr-containing-block
+     {
+       width: 400px;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-008-ref.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-008-ref.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-008-ref.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-008-ref.xht
+@@ -12,16 +12,17 @@
+   <meta name="DC.date.modified" content="2017-01-03T09:54:03+11:00" scheme="W3CDTF" />
+ 
+   <meta content="" name="flags" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin: 8px 0px;
+     }
+ 
+   table
+     {
+       border-spacing: 0px;
+       left: calc(100% - 136px - 3px - 50ch - 3px - 136px);
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-008.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-008.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-008.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-008.xht
+@@ -63,16 +63,17 @@
+   html
+     {
+       writing-mode: vertical-rl;
+     }
+ 
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin-left: 100px;
+       margin-right: 100px;
+     }
+ 
+   div#sized-400px-vrl-containing-block
+     {
+       width: 400px;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-020-ref.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-020-ref.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-020-ref.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-020-ref.xht
+@@ -12,16 +12,17 @@
+   <meta name="DC.date.modified" content="2017-01-03T09:54:03+11:00" scheme="W3CDTF" />
+ 
+   <meta content="" name="flags" />
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin: 8px 0px;
+     }
+ 
+   table
+     {
+       border-spacing: 0px;
+       left: calc(100% - 52px - 3px - 50ch - 3px - 52px);
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-020.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-020.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-020.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-htb-in-vrl-020.xht
+@@ -63,16 +63,17 @@
+   html
+     {
+       writing-mode: vertical-rl;
+     }
+ 
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin-left: 0px;
+       margin-right: 0px;
+     }
+ 
+   div#sized-400px-vrl-containing-block
+     {
+       width: 400px;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-008-ref.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-008-ref.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-008-ref.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-008-ref.xht
+@@ -18,16 +18,17 @@
+     {
+       padding: 100px 0px;
+       writing-mode: vertical-lr;
+     }
+ 
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+     }
+ 
+   p
+     {
+       left: 8px;
+       position: absolute;
+       writing-mode: horizontal-tb;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-008.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-008.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-008.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-008.xht
+@@ -58,16 +58,17 @@
+   is smaller than containing-block's height (short sentence)
+ 
+   -->
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin-bottom: 100px;
+       margin-top: 100px;
+       /* Nota bene: margin-top of p#sentence-before will collapse with body's margin-top */
+     }
+ 
+   div#sized-400px-htb-containing-block
+     {
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-020-ref.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-020-ref.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-020-ref.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-020-ref.xht
+@@ -17,16 +17,17 @@
+   html
+     {
+       writing-mode: vertical-lr;
+     }
+ 
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+     }
+ 
+   p
+     {
+       left: 8px;
+       position: absolute;
+       writing-mode: horizontal-tb;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-020.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-020.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-020.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vlr-in-htb-020.xht
+@@ -58,16 +58,17 @@
+   is smaller than containing-block's height (short sentence)
+ 
+   -->
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin-bottom: 0px;
+       margin-top: 0px;
+     }
+ 
+   div#sized-400px-htb-containing-block
+     {
+       height: 400px;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-008-ref.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-008-ref.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-008-ref.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-008-ref.xht
+@@ -18,16 +18,17 @@
+     {
+       padding: 100px 0px;
+       writing-mode: vertical-rl;
+     }
+ 
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+     }
+ 
+   p
+     {
+       left: 8px;
+       position: absolute;
+       writing-mode: horizontal-tb;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-008.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-008.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-008.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-008.xht
+@@ -58,16 +58,17 @@
+   is smaller than containing-block's height (short sentence)
+ 
+   -->
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin-bottom: 100px;
+       margin-top: 100px;
+       /* Nota bene: margin-top of p#sentence-before will collapse with body's margin-top */
+     }
+ 
+   div#sized-400px-htb-containing-block
+     {
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-020-ref.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-020-ref.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-020-ref.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-020-ref.xht
+@@ -17,16 +17,17 @@
+   html
+     {
+       writing-mode: vertical-rl;
+     }
+ 
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+     }
+ 
+   p
+     {
+       left: 8px;
+       position: absolute;
+       writing-mode: horizontal-tb;
+diff --git a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-020.xht b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-020.xht
+--- a/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-020.xht
++++ b/layout/reftests/w3c-css/received/css-writing-modes-3/sizing-orthog-vrl-in-htb-020.xht
+@@ -58,16 +58,17 @@
+   is smaller than containing-block's height (short sentence)
+ 
+   -->
+ 
+   <style type="text/css"><![CDATA[
+   body
+     {
+       font-size: 16px;
++      font-family: monospace;
+       line-height: 1.25; /* therefore, each line box is 20px tall */
+       margin-bottom: 0px;
+       margin-top: 0px;
+     }
+ 
+   div#sized-400px-htb-containing-block
+     {
+       height: 400px;
+diff --git a/layout/reftests/w3c-css/received/import.log b/layout/reftests/w3c-css/received/import.log
+--- a/layout/reftests/w3c-css/received/import.log
++++ b/layout/reftests/w3c-css/received/import.log
+@@ -1,9 +1,9 @@
+-Importing revision: b369eca1d18725d94f7ce99862de113de393b69f
++Importing revision: a574530634a7e3f1c4e4f0385ec8e32620468def
+ from repository: https://github.com/w3c/web-platform-tests.git
+ Importing css-conditional-3/OWNERS to css-conditional-3/OWNERS
+ Importing css-conditional-3/at-media-whitespace-optional-001.html to css-conditional-3/at-media-whitespace-optional-001.html
+ Importing css-conditional-3/reference/background-lime.html to css-conditional-3/reference/background-lime.html
+ Importing css-conditional-3/at-media-whitespace-optional-002.html to css-conditional-3/at-media-whitespace-optional-002.html
+ Importing css-conditional-3/at-supports-001.html to css-conditional-3/at-supports-001.html
+ Importing css-conditional-3/at-supports-001-ref.html to css-conditional-3/at-supports-001-ref.html
+ Importing css-conditional-3/at-supports-002.html to css-conditional-3/at-supports-002.html
+@@ -91,20 +91,20 @@ Importing css-multicol-1/reference/multi
+ Importing css-multicol-1/multicol-basic-002.html to css-multicol-1/multicol-basic-002.html
+ Importing css-multicol-1/multicol-basic-003.html to css-multicol-1/multicol-basic-003.html
+ Importing css-multicol-1/multicol-basic-004.html to css-multicol-1/multicol-basic-004.html
+ Importing css-multicol-1/multicol-basic-005.xht to css-multicol-1/multicol-basic-005.xht
+ Importing css-multicol-1/reference/multicol-basic-005-ref.xht to css-multicol-1/reference/multicol-basic-005-ref.xht
+ Importing css-multicol-1/multicol-basic-006.xht to css-multicol-1/multicol-basic-006.xht
+ Importing css-multicol-1/multicol-basic-007.xht to css-multicol-1/multicol-basic-007.xht
+ Importing css-multicol-1/multicol-basic-008.xht to css-multicol-1/multicol-basic-008.xht
+-Importing css-multicol-1/multicol-block-clip-001.xht to css-multicol-1/multicol-block-clip-001.xht
+-Importing css-multicol-1/multicol-block-clip-001-ref.xht to css-multicol-1/multicol-block-clip-001-ref.xht
+-Importing css-multicol-1/multicol-block-clip-002.xht to css-multicol-1/multicol-block-clip-002.xht
+-Importing css-multicol-1/multicol-block-clip-002-ref.xht to css-multicol-1/multicol-block-clip-002-ref.xht
++Importing css-multicol-1/multicol-block-no-clip-001.xht to css-multicol-1/multicol-block-no-clip-001.xht
++Importing css-multicol-1/multicol-block-no-clip-001-ref.xht to css-multicol-1/multicol-block-no-clip-001-ref.xht
++Importing css-multicol-1/multicol-block-no-clip-002.xht to css-multicol-1/multicol-block-no-clip-002.xht
++Importing css-multicol-1/multicol-block-no-clip-002-ref.xht to css-multicol-1/multicol-block-no-clip-002-ref.xht
+ Importing css-multicol-1/multicol-br-inside-avoidcolumn-001.xht to css-multicol-1/multicol-br-inside-avoidcolumn-001.xht
+ Importing css-multicol-1/multicol-br-inside-avoidcolumn-ref.xht to css-multicol-1/multicol-br-inside-avoidcolumn-ref.xht
+ Importing css-multicol-1/multicol-break-000.xht to css-multicol-1/multicol-break-000.xht
+ Importing css-multicol-1/multicol-break-000-ref.xht to css-multicol-1/multicol-break-000-ref.xht
+ Importing css-multicol-1/multicol-break-001.xht to css-multicol-1/multicol-break-001.xht
+ Importing css-multicol-1/multicol-break-001-ref.xht to css-multicol-1/multicol-break-001-ref.xht
+ Importing css-multicol-1/multicol-clip-001.xht to css-multicol-1/multicol-clip-001.xht
+ Importing css-multicol-1/multicol-clip-001-ref.xht to css-multicol-1/multicol-clip-001-ref.xht
+@@ -260,17 +260,17 @@ Importing css-multicol-1/multicol-rule-l
+ Importing css-multicol-1/multicol-rule-none-000.xht to css-multicol-1/multicol-rule-none-000.xht
+ Importing css-multicol-1/multicol-rule-outset-000.xht to css-multicol-1/multicol-rule-outset-000.xht
+ Importing css-multicol-1/multicol-rule-percent-001.xht to css-multicol-1/multicol-rule-percent-001.xht
+ Importing css-multicol-1/multicol-rule-px-001.xht to css-multicol-1/multicol-rule-px-001.xht
+ Importing css-multicol-1/multicol-rule-ridge-000.xht to css-multicol-1/multicol-rule-ridge-000.xht
+ Importing css-multicol-1/multicol-rule-samelength-001.xht to css-multicol-1/multicol-rule-samelength-001.xht
+ Importing css-multicol-1/multicol-rule-samelength-001-ref.xht to css-multicol-1/multicol-rule-samelength-001-ref.xht
+ Importing css-multicol-1/multicol-rule-shorthand-001.xht to css-multicol-1/multicol-rule-shorthand-001.xht
+-Warning: href attribute found empty in /Users/mozilla/web-platform-tests/css/css-multicol-1/multicol-rule-shorthand-2.xht
++Warning: href attribute found empty in ../../../../web-platform-tests/css/css-multicol-1/multicol-rule-shorthand-2.xht
+ Importing css-multicol-1/multicol-rule-solid-000.xht to css-multicol-1/multicol-rule-solid-000.xht
+ Importing css-multicol-1/multicol-rule-solid-000-ref.xht to css-multicol-1/multicol-rule-solid-000-ref.xht
+ Importing css-multicol-1/multicol-rule-stacking-001.xht to css-multicol-1/multicol-rule-stacking-001.xht
+ Importing css-multicol-1/multicol-rule-stacking-ref.xht to css-multicol-1/multicol-rule-stacking-ref.xht
+ Importing css-multicol-1/multicol-rule-style-groove-001.xht to css-multicol-1/multicol-rule-style-groove-001.xht
+ Importing css-multicol-1/multicol-rule-style-groove-001-ref.xht to css-multicol-1/multicol-rule-style-groove-001-ref.xht
+ Importing css-multicol-1/multicol-rule-style-inset-001.xht to css-multicol-1/multicol-rule-style-inset-001.xht
+ Importing css-multicol-1/multicol-rule-style-ridge-001-ref.xht to css-multicol-1/multicol-rule-style-ridge-001-ref.xht
+@@ -405,26 +405,26 @@ Importing css-values-3/support/swatch-te
+ Importing css-values-3/support/swatch-white.png to css-values-3/support/swatch-white.png
+ Importing css-values-3/support/swatch-yellow.png to css-values-3/support/swatch-yellow.png
+ Importing css-values-3/support/test-bl.png to css-values-3/support/test-bl.png
+ Importing css-values-3/support/test-br.png to css-values-3/support/test-br.png
+ Importing css-values-3/support/test-inner-half-size.png to css-values-3/support/test-inner-half-size.png
+ Importing css-values-3/support/test-outer.png to css-values-3/support/test-outer.png
+ Importing css-values-3/support/test-tl.png to css-values-3/support/test-tl.png
+ Importing css-values-3/support/test-tr.png to css-values-3/support/test-tr.png
++Importing css-values-3/support/vh_not_refreshing_on_chrome_iframe.html to css-values-3/support/vh_not_refreshing_on_chrome_iframe.html
+ Importing css-values-3/support/support/README to css-values-3/support/support/README
+ Importing css-values-3/support/support/swatch-green.png to css-values-3/support/support/swatch-green.png
+ Importing css-values-3/support/support/swatch-red.png to css-values-3/support/support/swatch-red.png
+ Importing css-values-3/attr-color-invalid-cast.html to css-values-3/attr-color-invalid-cast.html
+ Importing css-values-3/reference/200-200-green.html to css-values-3/reference/200-200-green.html
+ Importing css-values-3/attr-color-invalid-fallback.html to css-values-3/attr-color-invalid-fallback.html
+ Importing css-values-3/attr-color-valid.html to css-values-3/attr-color-valid.html
+ Importing css-values-3/attr-invalid-type-001.html to css-values-3/attr-invalid-type-001.html
+ Importing css-values-3/attr-invalid-type-002.html to css-values-3/attr-invalid-type-002.html
+-Importing css-values-3/attr-invalid-type-003.html to css-values-3/attr-invalid-type-003.html
+ Importing css-values-3/attr-length-invalid-cast.html to css-values-3/attr-length-invalid-cast.html
+ Importing css-values-3/attr-length-invalid-fallback.html to css-values-3/attr-length-invalid-fallback.html
+ Importing css-values-3/attr-length-valid-zero-nofallback.html to css-values-3/attr-length-valid-zero-nofallback.html
+ Importing css-values-3/attr-length-valid-zero.html to css-values-3/attr-length-valid-zero.html
+ Importing css-values-3/attr-length-valid.html to css-values-3/attr-length-valid.html
+ Importing css-values-3/attr-px-invalid-cast.html to css-values-3/attr-px-invalid-cast.html
+ Importing css-values-3/attr-px-invalid-fallback.html to css-values-3/attr-px-invalid-fallback.html
+ Importing css-values-3/attr-px-valid.html to css-values-3/attr-px-valid.html
+@@ -451,17 +451,16 @@ Importing css-values-3/vh-interpolate-vh
+ Importing css-values-3/vh-support-atviewport.html to css-values-3/vh-support-atviewport.html
+ Importing css-values-3/vh-support-margin.html to css-values-3/vh-support-margin.html
+ Importing css-values-3/vh-support-transform-origin.html to css-values-3/vh-support-transform-origin.html
+ Importing css-values-3/vh-support-transform-translate.html to css-values-3/vh-support-transform-translate.html
+ Importing css-values-3/vh-support.html to css-values-3/vh-support.html
+ Importing css-values-3/vh-zero-support.html to css-values-3/vh-zero-support.html
+ Importing css-values-3/vh_not_refreshing_on_chrome.html to css-values-3/vh_not_refreshing_on_chrome.html
+ Importing css-values-3/reference/vh_not_refreshing_on_chrome-ref.html to css-values-3/reference/vh_not_refreshing_on_chrome-ref.html
+-Importing css-values-3/vh_not_refreshing_on_chrome_iframe.html to css-values-3/vh_not_refreshing_on_chrome_iframe.html
+ Importing css-writing-modes-3/OWNERS to css-writing-modes-3/OWNERS
+ Importing css-writing-modes-3/support/100x100-lime.png to css-writing-modes-3/support/100x100-lime.png
+ Importing css-writing-modes-3/support/100x100-red.png to css-writing-modes-3/support/100x100-red.png
+ Importing css-writing-modes-3/support/bg-red-1col-2row-320x320.png to css-writing-modes-3/support/bg-red-1col-2row-320x320.png
+ Importing css-writing-modes-3/support/bg-red-1col-3row-320x320.png to css-writing-modes-3/support/bg-red-1col-3row-320x320.png
+ Importing css-writing-modes-3/support/bg-red-2col-2row-320x320.png to css-writing-modes-3/support/bg-red-2col-2row-320x320.png
+ Importing css-writing-modes-3/support/bg-red-2col-3row-320x320.png to css-writing-modes-3/support/bg-red-2col-3row-320x320.png
+ Importing css-writing-modes-3/support/bg-red-3col-2row-320x320.png to css-writing-modes-3/support/bg-red-3col-2row-320x320.png
+diff --git a/layout/reftests/w3c-css/received/reftest.list b/layout/reftests/w3c-css/received/reftest.list
+--- a/layout/reftests/w3c-css/received/reftest.list
++++ b/layout/reftests/w3c-css/received/reftest.list
+@@ -44,18 +44,18 @@
+ == css-multicol-1/multicol-basic-001.html css-multicol-1/reference/multicol-basic-ref.html
+ == css-multicol-1/multicol-basic-002.html css-multicol-1/reference/multicol-basic-ref.html
+ == css-multicol-1/multicol-basic-003.html css-multicol-1/reference/multicol-basic-ref.html
+ == css-multicol-1/multicol-basic-004.html css-multicol-1/reference/multicol-basic-ref.html
+ == css-multicol-1/multicol-basic-005.xht css-multicol-1/reference/multicol-basic-005-ref.xht
+ == css-multicol-1/multicol-basic-006.xht css-multicol-1/reference/multicol-basic-005-ref.xht
+ == css-multicol-1/multicol-basic-007.xht css-multicol-1/reference/multicol-basic-005-ref.xht
+ == css-multicol-1/multicol-basic-008.xht css-multicol-1/reference/multicol-basic-005-ref.xht
+-fails-if(!styloVsGecko) == css-multicol-1/multicol-block-clip-001.xht css-multicol-1/multicol-block-clip-001-ref.xht
+-fails-if(!styloVsGecko) == css-multicol-1/multicol-block-clip-002.xht css-multicol-1/multicol-block-clip-002-ref.xht
++fails-if((winWidget||OSX)&&!styloVsGecko) == css-multicol-1/multicol-block-no-clip-001.xht css-multicol-1/multicol-block-no-clip-001-ref.xht
++fails-if((winWidget||OSX)&&!styloVsGecko) == css-multicol-1/multicol-block-no-clip-002.xht css-multicol-1/multicol-block-no-clip-002-ref.xht
+ fails-if(!styloVsGecko) == css-multicol-1/multicol-br-inside-avoidcolumn-001.xht css-multicol-1/multicol-br-inside-avoidcolumn-ref.xht
+ fails-if(!styloVsGecko) == css-multicol-1/multicol-break-000.xht css-multicol-1/multicol-break-000-ref.xht
+ fails-if(!styloVsGecko) == css-multicol-1/multicol-break-001.xht css-multicol-1/multicol-break-001-ref.xht
+ fuzzy(135,1008) == css-multicol-1/multicol-clip-001.xht css-multicol-1/multicol-clip-001-ref.xht
+ fuzzy(135,770) == css-multicol-1/multicol-clip-002.xht css-multicol-1/multicol-clip-002-ref.xht
+ fuzzy(135,467) == css-multicol-1/multicol-collapsing-001.xht css-multicol-1/multicol-collapsing-001-ref.xht
+ fuzzy(87,180) == css-multicol-1/multicol-columns-001.xht css-multicol-1/multicol-columns-001-ref.xht
+ fuzzy(87,180) == css-multicol-1/multicol-columns-002.xht css-multicol-1/multicol-columns-001-ref.xht
+@@ -68,19 +68,19 @@ fuzzy(204,930) fuzzy-if(skiaContent,208,
+ fails-if((OSX||winWidget)&&!styloVsGecko) == css-multicol-1/multicol-columns-invalid-002.xht css-multicol-1/multicol-columns-invalid-001-ref.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) == css-multicol-1/multicol-columns-toolong-001.xht css-multicol-1/multicol-columns-invalid-001-ref.xht
+ fuzzy(135,530) == css-multicol-1/multicol-containing-001.xht css-multicol-1/multicol-containing-001-ref.xht
+ fuzzy(215,241) == css-multicol-1/multicol-containing-002.xht css-multicol-1/multicol-containing-002-ref.xht
+ fuzzy(87,180) == css-multicol-1/multicol-count-001.xht css-multicol-1/multicol-columns-001-ref.xht
+ fails-if(!styloVsGecko) == css-multicol-1/multicol-count-002.xht css-multicol-1/multicol-count-002-ref.xht
+ fails-if(!styloVsGecko) == css-multicol-1/multicol-count-computed-001.xht css-multicol-1/multicol-count-computed-ref.xht
+ fails-if(!styloVsGecko) == css-multicol-1/multicol-count-computed-002.xht css-multicol-1/multicol-count-computed-2-ref.xht
+-fails-if(!styloVsGecko) == css-multicol-1/multicol-count-computed-003.xht css-multicol-1/multicol-count-computed-003-ref.xht
++fails-if((winWidget||OSX||Android)&&!styloVsGecko) == css-multicol-1/multicol-count-computed-003.xht css-multicol-1/multicol-count-computed-003-ref.xht
+ fuzzy-if(winWidget||OSX||gtkWidget,112,861) fails-if(Android) == css-multicol-1/multicol-count-computed-004.xht css-multicol-1/multicol-count-computed-004-ref.xht
+-fails-if(!styloVsGecko) == css-multicol-1/multicol-count-computed-005.xht css-multicol-1/multicol-count-computed-003-ref.xht
++fails-if((winWidget||OSX||Android)&&!styloVsGecko) == css-multicol-1/multicol-count-computed-005.xht css-multicol-1/multicol-count-computed-003-ref.xht
+ fails-if(!styloVsGecko) == css-multicol-1/multicol-count-large-001.xht css-multicol-1/multicol-count-large-ref.xht
+ fuzzy(255,132) == css-multicol-1/multicol-count-large-002.xht css-multicol-1/multicol-count-large-2-ref.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) == css-multicol-1/multicol-count-negative-001.xht css-multicol-1/multicol-columns-invalid-001-ref.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) == css-multicol-1/multicol-count-negative-002.xht css-multicol-1/multicol-columns-invalid-001-ref.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) == css-multicol-1/multicol-count-non-integer-001.xht css-multicol-1/multicol-columns-invalid-001-ref.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) == css-multicol-1/multicol-count-non-integer-002.xht css-multicol-1/multicol-columns-invalid-001-ref.xht
+ fuzzy(204,930) fuzzy-if(skiaContent,208,930) == css-multicol-1/multicol-count-non-integer-003.xht css-multicol-1/multicol-columns-invalid-001-ref.xht
+ == css-multicol-1/multicol-fill-000.xht css-multicol-1/multicol-fill-000-ref.xht
+@@ -200,25 +200,24 @@ fails-if(!styloVsGecko) == css-multicol-
+ == css-namespaces-3/syntax-005.xml css-namespaces-3/reftest/ref-lime-5.xml
+ == css-namespaces-3/syntax-006.xml css-namespaces-3/reftest/ref-lime-1.xml
+ == css-namespaces-3/syntax-007.xml css-namespaces-3/reftest/ref-lime-1.xml
+ == css-namespaces-3/syntax-008.xml css-namespaces-3/reftest/ref-lime-2.xml
+ == css-namespaces-3/syntax-009.xml css-namespaces-3/reftest/ref-lime-1.xml
+ == css-namespaces-3/syntax-010.xml css-namespaces-3/reftest/ref-lime-3.xml
+ == css-namespaces-3/syntax-011.xml css-namespaces-3/reftest/ref-lime-6.xml
+ == css-namespaces-3/syntax-012.xml css-namespaces-3/reftest/ref-lime-3.xml
+-fails-if(stylo||styloVsGecko) == css-namespaces-3/syntax-013.xml css-namespaces-3/reftest/ref-lime-5.xml # bug 1388911
++fails-if(stylo||styloVsGecko) == css-namespaces-3/syntax-013.xml css-namespaces-3/reftest/ref-lime-5.xml
+ == css-namespaces-3/syntax-014.xml css-namespaces-3/reftest/ref-lime-3.xml
+ == css-namespaces-3/syntax-015.xml css-namespaces-3/reftest/ref-lime-1.xml
+ fails-if(!styloVsGecko) == css-values-3/attr-color-invalid-cast.html css-values-3/reference/200-200-green.html
+ == css-values-3/attr-color-invalid-fallback.html css-values-3/reference/200-200-green.html
+ fails-if(!styloVsGecko) == css-values-3/attr-color-valid.html css-values-3/reference/200-200-green.html
+ == css-values-3/attr-invalid-type-001.html css-values-3/reference/200-200-green.html
+ == css-values-3/attr-invalid-type-002.html css-values-3/reference/200-200-green.html
+-== css-values-3/attr-invalid-type-003.html css-values-3/reference/200-200-green.html
+ fails-if(!styloVsGecko) == css-values-3/attr-length-invalid-cast.html css-values-3/reference/200-200-green.html
+ == css-values-3/attr-length-invalid-fallback.html css-values-3/reference/200-200-green.html
+ fails-if(!styloVsGecko) == css-values-3/attr-length-valid-zero-nofallback.html css-values-3/reference/200-200-green.html
+ fails-if(!styloVsGecko) == css-values-3/attr-length-valid-zero.html css-values-3/reference/200-200-green.html
+ fails-if(!styloVsGecko) == css-values-3/attr-length-valid.html css-values-3/reference/200-200-green.html
+ fails-if(!styloVsGecko) == css-values-3/attr-px-invalid-cast.html css-values-3/reference/200-200-green.html
+ == css-values-3/attr-px-invalid-fallback.html css-values-3/reference/200-200-green.html
+ fails-if(!styloVsGecko) == css-values-3/attr-px-valid.html css-values-3/reference/200-200-green.html
+@@ -241,17 +240,16 @@ fuzzy(78,197) == css-values-3/ch-unit-00
+ == css-values-3/vh-interpolate-vh.html css-values-3/reference/all-green.html
+ == css-values-3/vh-support-atviewport.html css-values-3/reference/all-green.html
+ == css-values-3/vh-support-margin.html css-values-3/reference/all-green.html
+ skip == css-values-3/vh-support-transform-origin.html css-values-3/reference/all-green.html
+ skip == css-values-3/vh-support-transform-translate.html css-values-3/reference/all-green.html
+ == css-values-3/vh-support.html css-values-3/reference/all-green.html
+ == css-values-3/vh-zero-support.html css-values-3/reference/all-green.html
+ skip == css-values-3/vh_not_refreshing_on_chrome.html css-values-3/reference/vh_not_refreshing_on_chrome-ref.html
+-skip == css-values-3/vh_not_refreshing_on_chrome_iframe.html css-values-3/reference/vh_not_refreshing_on_chrome-ref.html
+ == css-writing-modes-3/abs-pos-non-replaced-icb-vlr-003.xht reference/ref-filled-green-100px-square.xht
+ == css-writing-modes-3/abs-pos-non-replaced-icb-vlr-005.xht css-writing-modes-3/abs-pos-non-replaced-icb-vrl-004-ref.xht
+ == css-writing-modes-3/abs-pos-non-replaced-icb-vlr-007.xht reference/ref-filled-green-100px-square.xht
+ == css-writing-modes-3/abs-pos-non-replaced-icb-vlr-009.xht css-writing-modes-3/abs-pos-non-replaced-icb-vrl-008-ref.xht
+ == css-writing-modes-3/abs-pos-non-replaced-icb-vlr-011.xht reference/ref-filled-green-100px-square.xht
+ == css-writing-modes-3/abs-pos-non-replaced-icb-vlr-013.xht css-writing-modes-3/abs-pos-non-replaced-icb-vrl-004-ref.xht
+ == css-writing-modes-3/abs-pos-non-replaced-icb-vlr-015.xht css-writing-modes-3/abs-pos-non-replaced-icb-vrl-008-ref.xht
+ == css-writing-modes-3/abs-pos-non-replaced-icb-vlr-017.xht css-writing-modes-3/abs-pos-non-replaced-icb-vrl-008-ref.xht
+@@ -991,47 +989,47 @@ fails-if(Android) == css-writing-modes-3
+ == css-writing-modes-3/sizing-orthog-prct-vrl-in-htb-006.xht css-writing-modes-3/sizing-orthog-prct-vrl-in-htb-006-ref.xht
+ == css-writing-modes-3/sizing-orthog-prct-vrl-in-htb-007.xht css-writing-modes-3/sizing-orthog-prct-vrl-in-htb-007-ref.xht
+ == css-writing-modes-3/sizing-orthog-prct-vrl-in-htb-008.xht css-writing-modes-3/sizing-orthog-prct-vrl-in-htb-008-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-001.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-001-ref.xht
+ fails-if(Android) == css-writing-modes-3/sizing-orthog-vlr-in-htb-003.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-003-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-004.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-004-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-006.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-006-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-007.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-007-ref.xht
+-fails-if((OSX||winWidget||Android)&&!styloVsGecko) == css-writing-modes-3/sizing-orthog-vlr-in-htb-008.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-008-ref.xht
++== css-writing-modes-3/sizing-orthog-vlr-in-htb-008.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-008-ref.xht
+ fails-if(Android) == css-writing-modes-3/sizing-orthog-vlr-in-htb-009.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-009-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-010.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-010-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-011.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-011-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-012.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-012-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-013.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-013-ref.xht
+ fails-if(Android) == css-writing-modes-3/sizing-orthog-vlr-in-htb-015.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-015-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-016.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-016-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-018.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-018-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-019.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-019-ref.xht
+-fails-if((OSX||winWidget||Android)&&!styloVsGecko) == css-writing-modes-3/sizing-orthog-vlr-in-htb-020.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-020-ref.xht
++== css-writing-modes-3/sizing-orthog-vlr-in-htb-020.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-020-ref.xht
+ fails-if(Android) == css-writing-modes-3/sizing-orthog-vlr-in-htb-021.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-015-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-022.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-022-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-023.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-023-ref.xht
+ == css-writing-modes-3/sizing-orthog-vlr-in-htb-024.xht css-writing-modes-3/sizing-orthog-vlr-in-htb-018-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-001.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-001-ref.xht
+ fails-if(Android) == css-writing-modes-3/sizing-orthog-vrl-in-htb-003.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-003-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-004.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-004-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-006.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-006-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-007.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-007-ref.xht
+-fails-if((OSX||winWidget||Android)&&!styloVsGecko) == css-writing-modes-3/sizing-orthog-vrl-in-htb-008.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-008-ref.xht
++== css-writing-modes-3/sizing-orthog-vrl-in-htb-008.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-008-ref.xht
+ fails-if(Android) == css-writing-modes-3/sizing-orthog-vrl-in-htb-009.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-009-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-010.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-010-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-011.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-011-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-012.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-012-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-013.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-013-ref.xht
+ fails-if(Android) == css-writing-modes-3/sizing-orthog-vrl-in-htb-015.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-015-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-016.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-016-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-018.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-018-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-019.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-019-ref.xht
+-fails-if((OSX||winWidget||Android)&&!styloVsGecko) == css-writing-modes-3/sizing-orthog-vrl-in-htb-020.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-020-ref.xht
++== css-writing-modes-3/sizing-orthog-vrl-in-htb-020.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-020-ref.xht
+ fails-if(Android) == css-writing-modes-3/sizing-orthog-vrl-in-htb-021.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-015-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-022.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-022-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-023.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-023-ref.xht
+ == css-writing-modes-3/sizing-orthog-vrl-in-htb-024.xht css-writing-modes-3/sizing-orthog-vrl-in-htb-018-ref.xht
+ fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes-3/table-column-order-002.xht css-writing-modes-3/block-flow-direction-001-ref.xht
+ fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes-3/table-column-order-003.xht css-writing-modes-3/block-flow-direction-001-ref.xht
+ fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes-3/table-column-order-004.xht css-writing-modes-3/block-flow-direction-001-ref.xht
+ fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes-3/table-column-order-005.xht css-writing-modes-3/block-flow-direction-001-ref.xht

+ 478 - 0
frg/253-58/mozilla-release58_428029.patch

@@ -0,0 +1,478 @@
+# HG changeset patch
+# User Eitan Isaacson <eitan@monotonous.org>
+# Date 1501866434 25200
+#      Fri Aug 04 10:07:14 2017 -0700
+# Node ID 8827ea5e0a505b61b08cf6950b81a4985e9821b9
+# Parent  c6914fd7ac60b0e42bc10916d0fb83c79c1d72f1
+Bug 1388062 - Refactor browser aria-owns tests. r=surkov r=yzen
+
+diff --git a/accessible/tests/browser/e10s/browser_events_show.js b/accessible/tests/browser/e10s/browser_events_show.js
+--- a/accessible/tests/browser/e10s/browser_events_show.js
++++ b/accessible/tests/browser/e10s/browser_events_show.js
+@@ -6,10 +6,12 @@
+ 
+ /**
+  * Test show event
+  */
+ addAccessibleTask('<div id="div" style="visibility: hidden;"></div>',
+   async function(browser) {
+     let onShow = waitForEvent(EVENT_SHOW, "div");
+     await invokeSetStyle(browser, "div", "visibility", "visible");
+-    await onShow;
++    let showEvent = await onShow;
++    ok(showEvent.accessibleDocument instanceof nsIAccessibleDocument,
++      "Accessible document not present.");
+   });
+diff --git a/accessible/tests/browser/e10s/browser_events_textchange.js b/accessible/tests/browser/e10s/browser_events_textchange.js
+--- a/accessible/tests/browser/e10s/browser_events_textchange.js
++++ b/accessible/tests/browser/e10s/browser_events_textchange.js
+@@ -8,16 +8,18 @@ function checkTextChangeEvent(event, id,
+   let tcEvent = event.QueryInterface(nsIAccessibleTextChangeEvent);
+   is(tcEvent.start, start, `Correct start offset for ${prettyName(id)}`);
+   is(tcEvent.length, end - start, `Correct length for ${prettyName(id)}`);
+   is(tcEvent.isInserted, isInserted,
+     `Correct isInserted flag for ${prettyName(id)}`);
+   is(tcEvent.modifiedText, text, `Correct text for ${prettyName(id)}`);
+   is(tcEvent.isFromUserInput, isFromUserInput,
+     `Correct value of isFromUserInput for ${prettyName(id)}`);
++  ok(tcEvent.accessibleDocument instanceof nsIAccessibleDocument,
++    "Accessible document not present.");
+ }
+ 
+ async function changeText(browser, id, value, events) {
+   let onEvents = waitForOrderedEvents(events.map(({ isInserted }) => {
+     let eventType = isInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED;
+     return [ eventType, id ];
+   }));
+   // Change text in the subtree.
+diff --git a/accessible/tests/browser/events.js b/accessible/tests/browser/events.js
+--- a/accessible/tests/browser/events.js
++++ b/accessible/tests/browser/events.js
+@@ -8,17 +8,17 @@
+ // globals from there.
+ /* import-globals-from shared-head.js */
+ /* import-globals-from ../mochitest/common.js */
+ 
+ /* exported EVENT_REORDER, EVENT_SHOW, EVENT_TEXT_INSERTED, EVENT_TEXT_REMOVED,
+             EVENT_DOCUMENT_LOAD_COMPLETE, EVENT_HIDE, EVENT_TEXT_CARET_MOVED,
+             EVENT_DESCRIPTION_CHANGE, EVENT_NAME_CHANGE, EVENT_STATE_CHANGE,
+             EVENT_VALUE_CHANGE, EVENT_TEXT_VALUE_CHANGE, EVENT_FOCUS,
+-            EVENT_DOCUMENT_RELOAD,
++            EVENT_DOCUMENT_RELOAD, UnexpectedEvents,
+             waitForEvent, waitForEvents, waitForOrderedEvents */
+ 
+ const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
+ const EVENT_HIDE = nsIAccessibleEvent.EVENT_HIDE;
+ const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
+ const EVENT_SHOW = nsIAccessibleEvent.EVENT_SHOW;
+ const EVENT_STATE_CHANGE = nsIAccessibleEvent.EVENT_STATE_CHANGE;
+ const EVENT_TEXT_CARET_MOVED = nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED;
+@@ -107,19 +107,16 @@ function waitForEvent(eventType, matchCr
+ 
+         // If event type does not match expected type, skip the event.
+         if (event.eventType !== eventType) {
+           return;
+         }
+ 
+         if (matchEvent(event, matchCriteria)) {
+           Logger.log(`Correct event type: ${eventTypeToString(eventType)}`);
+-          ok(event.accessibleDocument instanceof nsIAccessibleDocument,
+-            "Accessible document present.");
+-
+           Services.obs.removeObserver(this, "accessible-event");
+           resolve(event);
+         }
+       }
+     };
+     Services.obs.addObserver(eventObserver, "accessible-event");
+   });
+ }
+diff --git a/accessible/tests/browser/tree/browser.ini b/accessible/tests/browser/tree/browser.ini
+--- a/accessible/tests/browser/tree/browser.ini
++++ b/accessible/tests/browser/tree/browser.ini
+@@ -1,10 +1,9 @@
+ [DEFAULT]
+ skip-if = e10s && os == 'win' && release_or_beta
+ support-files =
+   head.js
+   !/accessible/tests/browser/events.js
+   !/accessible/tests/browser/shared-head.js
+   !/accessible/tests/mochitest/*.js
+ 
+-[browser_test_aria_owns.js]
+-[browser_test_aria_owns_select.js]
++[browser_aria_owns.js]
+diff --git a/accessible/tests/browser/tree/browser_aria_owns.js b/accessible/tests/browser/tree/browser_aria_owns.js
+new file mode 100644
+--- /dev/null
++++ b/accessible/tests/browser/tree/browser_aria_owns.js
+@@ -0,0 +1,149 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++"use strict";
++
++let NO_MOVE = { unexpected: [[EVENT_REORDER, "container"]] };
++let MOVE = { expected: [[EVENT_REORDER, "container"]] };
++
++// Set last ordinal child as aria-owned, should produce no reorder.
++addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
++  async function(browser, accDoc) {
++    let containerAcc = findAccessibleChildByID(accDoc, "container");
++
++    testChildrenIds(containerAcc, ["a"]);
++
++    await contentSpawnMutation(browser, NO_MOVE, function() {
++      // aria-own ordinal child in place, should be a no-op.
++      document.getElementById("container").setAttribute("aria-owns", "a");
++    });
++
++    testChildrenIds(containerAcc, ["a"]);
++  }
++);
++
++// Add a new ordinal child to a container with an aria-owned child.
++// Order should respect aria-owns.
++addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
++  async function(browser, accDoc) {
++    let containerAcc = findAccessibleChildByID(accDoc, "container");
++
++    testChildrenIds(containerAcc, ["a"]);
++
++    await contentSpawnMutation(browser, MOVE, function() {
++      let container = document.getElementById("container");
++      container.setAttribute("aria-owns", "a");
++
++      let aa = document.createElement("li");
++      aa.id = "aa";
++      container.appendChild(aa);
++    });
++
++    testChildrenIds(containerAcc, ["aa", "a"]);
++
++    await contentSpawnMutation(browser, MOVE, function() {
++      document.getElementById("container").removeAttribute("aria-owns");
++    });
++
++    testChildrenIds(containerAcc, ["a", "aa"]);
++  }
++);
++
++// Remove a no-move aria-owns attribute, should result in a no-move.
++addAccessibleTask(`<ul id="container" aria-owns="a"><li id="a">Test</li></ul>`,
++  async function(browser, accDoc) {
++    let containerAcc = findAccessibleChildByID(accDoc, "container");
++
++    testChildrenIds(containerAcc, ["a"]);
++
++    await contentSpawnMutation(browser, NO_MOVE, function() {
++      // remove aria-owned child that is already ordinal, should be no-op.
++      document.getElementById("container").removeAttribute("aria-owns");
++    });
++
++    testChildrenIds(containerAcc, ["a"]);
++  }
++);
++
++// Attempt to steal an aria-owned child. The attempt should fail.
++addAccessibleTask(`
++  <ul>
++    <li id="a">Test</li>
++  </ul>
++  <ul aria-owns="a"></ul>
++  <ul id="container"></ul>`,
++  async function(browser, accDoc) {
++    let containerAcc = findAccessibleChildByID(accDoc, "container");
++
++    testChildrenIds(containerAcc, []);
++
++    await contentSpawnMutation(browser, NO_MOVE, function() {
++      document.getElementById("container").setAttribute("aria-owns", "a");
++    });
++
++    testChildrenIds(containerAcc, []);
++  }
++);
++
++// Correctly aria-own children of <select>
++addAccessibleTask(`
++  <div id="container" role="group" aria-owns="b"></div>
++  <select id="select">
++    <option id="a"></option>
++    <option id="b"></option>
++  </select>`,
++  async function(browser, accDoc) {
++    let containerAcc = findAccessibleChildByID(accDoc, "container");
++    let selectAcc = findAccessibleChildByID(accDoc, "select");
++
++    testChildrenIds(containerAcc, ["b"]);
++    testChildrenIds(selectAcc.firstChild, ["a"]);
++
++    let waitfor = { expected: [
++      [EVENT_REORDER, "container"],
++      [EVENT_REORDER,
++        evt => getAccessibleDOMNodeID(evt.accessible.parent) == "select"]] };
++
++    await contentSpawnMutation(browser, waitfor, function() {
++      document.getElementById("container").removeAttribute("aria-owns");
++    });
++
++    testChildrenIds(containerAcc, []);
++    testChildrenIds(selectAcc.firstChild, ["a", "b"]);
++  }
++);
++
++addAccessibleTask(`
++  <ul id="one">
++    <li id="a">Test</li>
++    <li id="b">Test 2</li>
++    <li id="c">Test 3</li>
++  </ul>
++  <ul id="two"></ul>`,
++  async function(browser, accDoc) {
++    let one = findAccessibleChildByID(accDoc, "one");
++    let two = findAccessibleChildByID(accDoc, "two");
++
++    let waitfor = { expected: [
++      [EVENT_REORDER, "one"],
++      [EVENT_REORDER, "two"]] };
++
++    await contentSpawnMutation(browser, waitfor, function() {
++      // Put same id twice in aria-owns
++      document.getElementById("two").setAttribute("aria-owns", "a a");
++    });
++
++    testChildrenIds(one, ["b", "c"]);
++    testChildrenIds(two, ["a"]);
++
++    await contentSpawnMutation(browser, waitfor, function() {
++      // If the previous double-id aria-owns worked correctly, we should
++      // be in a good state and all is fine..
++      document.getElementById("two").setAttribute("aria-owns", "a b");
++    });
++
++    testChildrenIds(one, ["c"]);
++    testChildrenIds(two, ["a", "b"]);
++  }
++);
+diff --git a/accessible/tests/browser/tree/browser_test_aria_owns.js b/accessible/tests/browser/tree/browser_test_aria_owns.js
+deleted file mode 100644
+--- a/accessible/tests/browser/tree/browser_test_aria_owns.js
++++ /dev/null
+@@ -1,96 +0,0 @@
+-/* This Source Code Form is subject to the terms of the Mozilla Public
+- * License, v. 2.0. If a copy of the MPL was not distributed with this
+- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+-
+-"use strict";
+-
+-function testChildrenIds(acc, expectedIds) {
+-  let ids = arrayFromChildren(acc).map(child => getAccessibleDOMNodeID(child));
+-  Assert.deepEqual(ids, expectedIds,
+-    `Children for ${getAccessibleDOMNodeID(acc)} are wrong.`);
+-}
+-
+-async function runTests(browser, accDoc) {
+-  let one = findAccessibleChildByID(accDoc, "one");
+-  let two = findAccessibleChildByID(accDoc, "two");
+-  let three = findAccessibleChildByID(accDoc, "three");
+-  let four = findAccessibleChildByID(accDoc, "four");
+-
+-  testChildrenIds(one, ["a"]);
+-  testChildrenIds(two, ["b", "c", "d"]);
+-  testChildrenIds(three, []);
+-
+-  let onReorders = waitForEvents({
+-    expected: [
+-      [EVENT_REORDER, "two"]], // children will be reordered via aria-owns
+-    unexpected: [
+-      [EVENT_REORDER, "one"],  // child will remain in place
+-      [EVENT_REORDER, "three"], // none of its children will be reclaimed
+-      [EVENT_REORDER, "four"]] // child will remain in place
+-  });
+-
+-  await ContentTask.spawn(browser, null, async function() {
+-    // aria-own ordinal child in place, should be a no-op.
+-    document.getElementById("one").setAttribute("aria-owns", "a");
+-    // remove aria-owned child that is already ordinal, should be no-op.
+-    document.getElementById("four").removeAttribute("aria-owns");
+-    // shuffle aria-owns with markup child.
+-    document.getElementById("two").setAttribute("aria-owns", "d c");
+-  });
+-
+-  await onReorders;
+-
+-  testChildrenIds(one, ["a"]);
+-  testChildrenIds(two, ["b", "d", "c"]);
+-  testChildrenIds(three, []);
+-  testChildrenIds(four, ["e"]);
+-
+-  onReorders = waitForEvent(EVENT_REORDER, "one");
+-
+-  await ContentTask.spawn(browser, null, async function() {
+-    let aa = document.createElement("li");
+-    aa.id = "aa";
+-    document.getElementById("one").appendChild(aa);
+-  });
+-
+-  await onReorders;
+-
+-  testChildrenIds(one, ["aa", "a"]);
+-
+-  onReorders = waitForEvents([
+-      [EVENT_REORDER, "two"],    // "b" will go to "three"
+-      [EVENT_REORDER, "three"], // some children will be reclaimed and acquired
+-      [EVENT_REORDER, "one"]]); // removing aria-owns will reorder native children
+-
+-  await ContentTask.spawn(browser, null, async function() {
+-    // removing aria-owns should reorder the children
+-    document.getElementById("one").removeAttribute("aria-owns");
+-    // child order will be overridden by aria-owns
+-    document.getElementById("three").setAttribute("aria-owns", "b d");
+-  });
+-
+-  await onReorders;
+-
+-  testChildrenIds(one, ["a", "aa"]);
+-  testChildrenIds(two, ["c"]);
+-  testChildrenIds(three, ["b", "d"]);
+-}
+-
+-/**
+- * Test caching of accessible object states
+- */
+-addAccessibleTask(`
+-    <ul id="one">
+-      <li id="a">Test</li>
+-    </ul>
+-    <ul id="two" aria-owns="d">
+-      <li id="b">Test 2</li>
+-      <li id="c">Test 3</li>
+-    </ul>
+-    <ul id="three">
+-      <li id="d">Test 4</li>
+-    </ul>
+-    <ul id="four" aria-owns="e">
+-      <li id="e">Test 5</li>
+-    </ul>
+-    `, runTests);
+diff --git a/accessible/tests/browser/tree/browser_test_aria_owns_select.js b/accessible/tests/browser/tree/browser_test_aria_owns_select.js
+deleted file mode 100644
+--- a/accessible/tests/browser/tree/browser_test_aria_owns_select.js
++++ /dev/null
+@@ -1,45 +0,0 @@
+-/* This Source Code Form is subject to the terms of the Mozilla Public
+- * License, v. 2.0. If a copy of the MPL was not distributed with this
+- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+-
+-"use strict";
+-
+-function testChildrenIds(acc, expectedIds) {
+-  let ids = arrayFromChildren(acc).map(child => getAccessibleDOMNodeID(child));
+-  Assert.deepEqual(ids, expectedIds,
+-    `Children for ${getAccessibleDOMNodeID(acc)} are wrong.`);
+-}
+-
+-async function runTests(browser, accDoc) {
+-  let div = findAccessibleChildByID(accDoc, "div");
+-  let select = findAccessibleChildByID(accDoc, "select");
+-
+-  testChildrenIds(div, ["b"]);
+-  testChildrenIds(select.firstChild, ["a"]);
+-
+-  let onReorders = waitForEvents([
+-    [EVENT_REORDER, "div"],
+-    [EVENT_REORDER,
+-      evt => getAccessibleDOMNodeID(evt.accessible.parent) == "select"]
+-  ]);
+-
+-  await ContentTask.spawn(browser, null, async function() {
+-    document.getElementById("div").removeAttribute("aria-owns");
+-  });
+-
+-  await onReorders;
+-
+-  testChildrenIds(div, []);
+-  testChildrenIds(select.firstChild, ["a", "b"]);
+-}
+-
+-/**
+- * Test caching of accessible object states
+- */
+-addAccessibleTask(`
+-  <div id="div" role="group" aria-owns="b"></div>
+-  <select id="select">
+-    <option id="a"></option>
+-    <option id="b"></option>
+-  </select>
+-    `, runTests);
+diff --git a/accessible/tests/browser/tree/head.js b/accessible/tests/browser/tree/head.js
+--- a/accessible/tests/browser/tree/head.js
++++ b/accessible/tests/browser/tree/head.js
+@@ -1,15 +1,65 @@
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ "use strict";
+ 
++/* exported contentSpawnMutation, testChildrenIds */
++
+ // Load the shared-head file first.
+ /* import-globals-from ../shared-head.js */
+ Services.scriptloader.loadSubScript(
+   "chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
+   this);
+ 
+ // Loading and common.js from accessible/tests/mochitest/ for all tests, as
+ // well as events.js.
+ loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "events.js", "layout.js");
++
++/*
++ * A test function for comparing the IDs of an accessible's children
++ * with an expected array of IDs.
++ */
++function testChildrenIds(acc, expectedIds) {
++  let ids = arrayFromChildren(acc).map(child => getAccessibleDOMNodeID(child));
++  Assert.deepEqual(ids, expectedIds,
++    `Children for ${getAccessibleDOMNodeID(acc)} are wrong.`);
++}
++
++/*
++ * This function spawns a content task and awaits expected mutation events from
++ * aria-owns changes. It's good at catching events we did *not* expect. We do
++ * this advancing the layout refresh to flush the relocations/insertions queue.
++ */
++async function contentSpawnMutation(browser, waitFor, func) {
++  let onReorders = waitForEvents({ expected: waitFor.expected || [] });
++  let unexpectedListener = new UnexpectedEvents(waitFor.unexpected || []);
++
++  function tick() {
++    // 100ms is an arbitrary positive number to advance the clock.
++    // We don't need to advance the clock for a11y mutations, but other
++    // tick listeners may depend on an advancing clock with each refresh.
++    content.QueryInterface(Ci.nsIInterfaceRequestor)
++      .getInterface(Ci.nsIDOMWindowUtils).advanceTimeAndRefresh(100);
++  }
++
++  // This stops the refreh driver from doing its regular ticks, and leaves
++  // us in control.
++  await ContentTask.spawn(browser, null, tick);
++
++  // Perform the tree mutation.
++  await ContentTask.spawn(browser, null, func);
++
++  // Do one tick to flush our queue (insertions, relocations, etc.)
++  await ContentTask.spawn(browser, null, tick);
++
++  await onReorders;
++
++  unexpectedListener.stop();
++
++  // Go back to normal refresh driver ticks.
++  await ContentTask.spawn(browser, null, function() {
++    content.QueryInterface(Ci.nsIInterfaceRequestor)
++      .getInterface(Ci.nsIDOMWindowUtils).restoreNormalRefresh();
++  });
++}

+ 415 - 0
frg/253-58/mozilla-release58_428030.patch

@@ -0,0 +1,415 @@
+# HG changeset patch
+# User Olli Pettay <Olli.Pettay@helsinki.fi>
+# Date 1503349307 -10800
+#      Tue Aug 22 00:01:47 2017 +0300
+# Node ID f63a7cba6c08cc4fe68678ed264818f2130ea39d
+# Parent  27c6cd728a5b2278753610fbe9636d8c34ba5db7
+Bug 1391423, add a nursery for purple buffer to allow faster addref/release on the main thread, r=mccr8
+
+diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
+--- a/dom/base/FragmentOrElement.cpp
++++ b/dom/base/FragmentOrElement.cpp
+@@ -2122,19 +2122,19 @@ NS_INTERFACE_MAP_BEGIN(FragmentOrElement
+   NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
+   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
+                                  new nsNodeSupportsWeakRefTearoff(this))
+   // DOM bindings depend on the identity pointer being the
+   // same as nsINode (which nsIContent inherits).
+   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
+ NS_INTERFACE_MAP_END
+ 
+-NS_IMPL_CYCLE_COLLECTING_ADDREF(FragmentOrElement)
+-NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(FragmentOrElement,
+-                                                   nsNodeUtils::LastRelease(this))
++NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(FragmentOrElement)
++NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(FragmentOrElement,
++                                                                    nsNodeUtils::LastRelease(this))
+ 
+ //----------------------------------------------------------------------
+ 
+ nsresult
+ FragmentOrElement::CopyInnerTo(FragmentOrElement* aDst,
+                                bool aPreallocateChildren)
+ {
+   nsresult rv = aDst->mAttrsAndChildren.EnsureCapacityToClone(mAttrsAndChildren,
+diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp
+--- a/xpcom/base/nsCycleCollector.cpp
++++ b/xpcom/base/nsCycleCollector.cpp
+@@ -192,16 +192,45 @@
+ #include "mozilla/ThreadLocal.h"
+ 
+ #ifdef MOZ_CRASHREPORTER
+ #include "nsExceptionHandler.h"
+ #endif
+ 
+ using namespace mozilla;
+ 
++struct NurseryPurpleBufferEntry
++{
++  void* mPtr;
++  nsCycleCollectionParticipant* mParticipant;
++  nsCycleCollectingAutoRefCnt* mRefCnt;
++};
++
++#define NURSERY_PURPLE_BUFFER_SIZE 2048
++bool gNurseryPurpleBufferEnabled = true;
++NurseryPurpleBufferEntry gNurseryPurpleBufferEntry[NURSERY_PURPLE_BUFFER_SIZE];
++uint32_t gNurseryPurpleBufferEntryCount = 0;
++
++void ClearNurseryPurpleBuffer();
++
++void SuspectUsingNurseryPurpleBuffer(void* aPtr,
++                                     nsCycleCollectionParticipant* aCp,
++                                     nsCycleCollectingAutoRefCnt* aRefCnt)
++{
++  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
++  MOZ_ASSERT(gNurseryPurpleBufferEnabled);
++  if (gNurseryPurpleBufferEntryCount == NURSERY_PURPLE_BUFFER_SIZE) {
++    ClearNurseryPurpleBuffer();
++  }
++
++  gNurseryPurpleBufferEntry[gNurseryPurpleBufferEntryCount] =
++    { aPtr, aCp, aRefCnt };
++  ++gNurseryPurpleBufferEntryCount;
++}
++
+ //#define COLLECT_TIME_DEBUG
+ 
+ // Enable assertions that are useful for diagnosing errors in graph construction.
+ //#define DEBUG_CC_GRAPH
+ 
+ #define DEFAULT_SHUTDOWN_COLLECTIONS 5
+ 
+ // One to do the freeing, then another to detect there is no more work to do.
+@@ -1034,16 +1063,23 @@ public:
+   ~nsPurpleBuffer()
+   {
+   }
+ 
+   // This method compacts mEntries.
+   template<class PurpleVisitor>
+   void VisitEntries(PurpleVisitor& aVisitor)
+   {
++    Maybe<AutoRestore<bool>> ar;
++    if (NS_IsMainThread()) {
++      ar.emplace(gNurseryPurpleBufferEnabled);
++      gNurseryPurpleBufferEnabled = false;
++      ClearNurseryPurpleBuffer();
++    }
++
+     if (mEntries.IsEmpty()) {
+       return;
+     }
+ 
+     uint32_t oldLength = mEntries.Length();
+     uint32_t keptLength = 0;
+     auto revIter = mEntries.IterFromLast();
+     auto iter = mEntries.Iter();
+@@ -1283,16 +1319,17 @@ public:
+   void SetForgetSkippableCallback(CC_ForgetSkippableCallback aForgetSkippableCB)
+   {
+     CheckThreadSafety();
+     mForgetSkippableCB = aForgetSkippableCB;
+   }
+ 
+   void Suspect(void* aPtr, nsCycleCollectionParticipant* aCp,
+                nsCycleCollectingAutoRefCnt* aRefCnt);
++  void SuspectNurseryEntries();
+   uint32_t SuspectedCount();
+   void ForgetSkippable(js::SliceBudget& aBudget, bool aRemoveChildlessNodes,
+                        bool aAsyncSnowWhiteFreeing);
+   bool FreeSnowWhite(bool aUntilNoSWInPurpleBuffer);
+ 
+   // This method assumes its argument is already canonicalized.
+   void RemoveObjectFromGraph(void* aPtr);
+ 
+@@ -3490,16 +3527,27 @@ nsCycleCollector::Suspect(void* aPtr, ns
+ 
+   MOZ_ASSERT(aParti || CanonicalizeXPCOMParticipant(static_cast<nsISupports*>(aPtr)) == aPtr,
+              "Suspect nsISupports pointer must be canonical");
+ 
+   mPurpleBuf.Put(aPtr, aParti, aRefCnt);
+ }
+ 
+ void
++nsCycleCollector::SuspectNurseryEntries()
++{
++  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
++  while (gNurseryPurpleBufferEntryCount) {
++    NurseryPurpleBufferEntry& entry =
++      gNurseryPurpleBufferEntry[--gNurseryPurpleBufferEntryCount];
++    mPurpleBuf.Put(entry.mPtr, entry.mParticipant, entry.mRefCnt);
++  }
++}
++
++void
+ nsCycleCollector::CheckThreadSafety()
+ {
+ #ifdef DEBUG
+   MOZ_ASSERT(mEventTarget->IsOnCurrentThread());
+ #endif
+ }
+ 
+ // The cycle collector uses the mark bitmap to discover what JS objects
+@@ -3891,24 +3939,32 @@ nsCycleCollector::BeginCollection(ccType
+   mBuilder->DoneAddingRoots();
+   mIncrementalPhase = GraphBuildingPhase;
+ }
+ 
+ uint32_t
+ nsCycleCollector::SuspectedCount()
+ {
+   CheckThreadSafety();
++  if (NS_IsMainThread()) {
++    return gNurseryPurpleBufferEntryCount + mPurpleBuf.Count();
++  }
++
+   return mPurpleBuf.Count();
+ }
+ 
+ void
+ nsCycleCollector::Shutdown(bool aDoCollect)
+ {
+   CheckThreadSafety();
+ 
++  if (NS_IsMainThread()) {
++    gNurseryPurpleBufferEnabled = false;
++  }
++
+   // Always delete snow white objects.
+   FreeSnowWhite(true);
+ 
+   if (aDoCollect) {
+     ShutdownCollect();
+   }
+ }
+ 
+@@ -4036,16 +4092,40 @@ NS_CycleCollectorSuspect3(void* aPtr, ns
+ 
+   if (MOZ_LIKELY(data->mCollector)) {
+     data->mCollector->Suspect(aPtr, aCp, aRefCnt);
+     return;
+   }
+   SuspectAfterShutdown(aPtr, aCp, aRefCnt, aShouldDelete);
+ }
+ 
++void ClearNurseryPurpleBuffer()
++{
++  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
++  CollectorData* data = sCollectorData.get();
++  MOZ_ASSERT(data);
++  MOZ_ASSERT(data->mCollector);
++  data->mCollector->SuspectNurseryEntries();
++}
++
++void
++NS_CycleCollectorSuspectUsingNursery(void* aPtr,
++                                     nsCycleCollectionParticipant* aCp,
++                                     nsCycleCollectingAutoRefCnt* aRefCnt,
++                                     bool* aShouldDelete)
++{
++  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
++  if (!gNurseryPurpleBufferEnabled) {
++    NS_CycleCollectorSuspect3(aPtr, aCp, aRefCnt, aShouldDelete);
++    return;
++  }
++
++  SuspectUsingNurseryPurpleBuffer(aPtr, aCp, aRefCnt);
++}
++
+ uint32_t
+ nsCycleCollector_suspectedCount()
+ {
+   CollectorData* data = sCollectorData.get();
+ 
+   // We should have started the cycle collector by now.
+   MOZ_ASSERT(data);
+ 
+diff --git a/xpcom/base/nsISupportsImpl.h b/xpcom/base/nsISupportsImpl.h
+--- a/xpcom/base/nsISupportsImpl.h
++++ b/xpcom/base/nsISupportsImpl.h
+@@ -185,71 +185,81 @@ do {                                    
+ #define NS_IN_PURPLE_BUFFER (1 << 0)
+ #define NS_IS_PURPLE (1 << 1)
+ #define NS_REFCOUNT_CHANGE (1 << NS_NUMBER_OF_FLAGS_IN_REFCNT)
+ #define NS_REFCOUNT_VALUE(_val) (_val >> NS_NUMBER_OF_FLAGS_IN_REFCNT)
+ 
+ class nsCycleCollectingAutoRefCnt
+ {
+ public:
++
++  typedef void (*Suspect)(void* aPtr,
++                          nsCycleCollectionParticipant* aCp,
++                          nsCycleCollectingAutoRefCnt* aRefCnt,
++                          bool* aShouldDelete);
++
+   nsCycleCollectingAutoRefCnt() : mRefCntAndFlags(0) {}
+ 
+   explicit nsCycleCollectingAutoRefCnt(uintptr_t aValue)
+     : mRefCntAndFlags(aValue << NS_NUMBER_OF_FLAGS_IN_REFCNT)
+   {
+   }
+ 
+   nsCycleCollectingAutoRefCnt(const nsCycleCollectingAutoRefCnt&) = delete;
+   void operator=(const nsCycleCollectingAutoRefCnt&) = delete;
+ 
++  template<Suspect suspect = NS_CycleCollectorSuspect3>
+   MOZ_ALWAYS_INLINE uintptr_t incr(nsISupports* aOwner)
+   {
+-    return incr(aOwner, nullptr);
++    return incr<suspect>(aOwner, nullptr);
+   }
+ 
++  template<Suspect suspect = NS_CycleCollectorSuspect3>
+   MOZ_ALWAYS_INLINE uintptr_t incr(void* aOwner,
+                                    nsCycleCollectionParticipant* aCp)
+   {
+     mRefCntAndFlags += NS_REFCOUNT_CHANGE;
+     mRefCntAndFlags &= ~NS_IS_PURPLE;
+     // For incremental cycle collection, use the purple buffer to track objects
+     // that have been AddRef'd.
+     if (!IsInPurpleBuffer()) {
+       mRefCntAndFlags |= NS_IN_PURPLE_BUFFER;
+       // Refcount isn't zero, so Suspect won't delete anything.
+       MOZ_ASSERT(get() > 0);
+-      NS_CycleCollectorSuspect3(aOwner, aCp, this, nullptr);
++      suspect(aOwner, aCp, this, nullptr);
+     }
+     return NS_REFCOUNT_VALUE(mRefCntAndFlags);
+   }
+ 
+   MOZ_ALWAYS_INLINE void stabilizeForDeletion()
+   {
+     // Set refcnt to 1 and mark us to be in the purple buffer.
+     // This way decr won't call suspect again.
+     mRefCntAndFlags = NS_REFCOUNT_CHANGE | NS_IN_PURPLE_BUFFER;
+   }
+ 
++  template<Suspect suspect = NS_CycleCollectorSuspect3>
+   MOZ_ALWAYS_INLINE uintptr_t decr(nsISupports* aOwner,
+                                    bool* aShouldDelete = nullptr)
+   {
+-    return decr(aOwner, nullptr, aShouldDelete);
++    return decr<suspect>(aOwner, nullptr, aShouldDelete);
+   }
+ 
++  template<Suspect suspect = NS_CycleCollectorSuspect3>
+   MOZ_ALWAYS_INLINE uintptr_t decr(void* aOwner,
+                                    nsCycleCollectionParticipant* aCp,
+                                    bool* aShouldDelete = nullptr)
+   {
+     MOZ_ASSERT(get() > 0);
+     if (!IsInPurpleBuffer()) {
+       mRefCntAndFlags -= NS_REFCOUNT_CHANGE;
+       mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE);
+       uintptr_t retval = NS_REFCOUNT_VALUE(mRefCntAndFlags);
+       // Suspect may delete 'aOwner' and 'this'!
+-      NS_CycleCollectorSuspect3(aOwner, aCp, this, aShouldDelete);
++      suspect(aOwner, aCp, this, aShouldDelete);
+       return retval;
+     }
+     mRefCntAndFlags -= NS_REFCOUNT_CHANGE;
+     mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE);
+     return NS_REFCOUNT_VALUE(mRefCntAndFlags);
+   }
+ 
+   MOZ_ALWAYS_INLINE void RemovePurple()
+@@ -705,16 +715,28 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
+   MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                        \
+   NS_ASSERT_OWNINGTHREAD(_class);                                             \
+   nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this);    \
+   nsrefcnt count = mRefCnt.incr(base);                                        \
+   NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                         \
+   return count;                                                               \
+ }
+ 
++#define NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(_class)              \
++NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void)                  \
++{                                                                             \
++  MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class)                                  \
++  MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                        \
++  NS_ASSERT_OWNINGTHREAD(_class);                                             \
++  nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this);    \
++  nsrefcnt count = mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>(base);  \
++  NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                         \
++  return count;                                                               \
++}
++
+ #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy)       \
+ NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void)                 \
+ {                                                                             \
+   MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");                            \
+   NS_ASSERT_OWNINGTHREAD(_class);                                             \
+   nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this);    \
+   nsrefcnt count = mRefCnt.decr(base);                                        \
+   NS_LOG_RELEASE(this, count, #_class);                                       \
+@@ -750,16 +772,43 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
+   }                                                                           \
+   return count;                                                               \
+ }                                                                             \
+ NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void)                     \
+ {                                                                             \
+   delete this;                                                                \
+ }
+ 
++// _LAST_RELEASE can be useful when certain resources should be released
++// as soon as we know the object will be deleted.
++#define NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(_class, _last)  \
++NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void)                               \
++{                                                                                           \
++  MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");                                          \
++  NS_ASSERT_OWNINGTHREAD(_class);                                                           \
++  bool shouldDelete = false;                                                                \
++  nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this);                  \
++  nsrefcnt count = mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>(base, &shouldDelete); \
++  NS_LOG_RELEASE(this, count, #_class);                                                     \
++  if (count == 0) {                                                                         \
++      mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>(base);                             \
++      _last;                                                                                \
++      mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>(base);                             \
++      if (shouldDelete) {                                                                   \
++          mRefCnt.stabilizeForDeletion();                                                   \
++          DeleteCycleCollectable();                                                         \
++      }                                                                                     \
++  }                                                                                         \
++  return count;                                                                             \
++}                                                                                           \
++NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void)                                   \
++{                                                                                           \
++  delete this;                                                                              \
++}
++
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ /**
+  * There are two ways of implementing QueryInterface, and we use both:
+  *
+  * Table-driven QueryInterface uses a static table of IID->offset mappings
+  * and a shared helper function. Using it tends to reduce codesize and improve
+  * runtime performance (due to processor cache hits).
+diff --git a/xpcom/build/nsXPCOM.h b/xpcom/build/nsXPCOM.h
+--- a/xpcom/build/nsXPCOM.h
++++ b/xpcom/build/nsXPCOM.h
+@@ -304,16 +304,22 @@ XPCOM_API(void) NS_LogCOMPtrRelease(void
+ class nsCycleCollectionParticipant;
+ class nsCycleCollectingAutoRefCnt;
+ 
+ XPCOM_API(void) NS_CycleCollectorSuspect3(void* aPtr,
+                                           nsCycleCollectionParticipant* aCp,
+                                           nsCycleCollectingAutoRefCnt* aRefCnt,
+                                           bool* aShouldDelete);
+ 
++XPCOM_API(void)
++NS_CycleCollectorSuspectUsingNursery(void* aPtr,
++                                     nsCycleCollectionParticipant* aCp,
++                                     nsCycleCollectingAutoRefCnt* aRefCnt,
++                                     bool* aShouldDelete);
++
+ #endif
+ 
+ /**
+  * Categories (in the category manager service) used by XPCOM:
+  */
+ 
+ /**
+  * A category which is read after component registration but before

+ 50 - 0
frg/253-58/mozilla-release58_428034.patch

@@ -0,0 +1,50 @@
+# HG changeset patch
+# User Gabriel Luong <gabriel.luong@gmail.com>
+# Date 1503352677 25200
+#      Mon Aug 21 14:57:57 2017 -0700
+# Node ID e547c933f9e8d76b53dcb4a3251a30889fc8ae05
+# Parent  2ff492715d4be4503a8e1987f32ce80e7885f0e5
+Bug 1391866 - Remove border-bottom from the last child of accordions. r=bgrins
+
+diff --git a/devtools/client/inspector/layout/components/Accordion.css b/devtools/client/inspector/layout/components/Accordion.css
+--- a/devtools/client/inspector/layout/components/Accordion.css
++++ b/devtools/client/inspector/layout/components/Accordion.css
+@@ -34,12 +34,16 @@
+   fill: var(--theme-comment-alt);
+ }
+ 
+ .accordion ._content {
+   border-bottom: 1px solid var(--theme-splitter-color);
+   font-size: 11px;
+ }
+ 
++.accordion div:last-child ._content {
++  border-bottom: none;
++}
++
+ .arrow {
+   vertical-align: middle;
+   display: inline-block;
+ }
+diff --git a/devtools/client/themes/computed.css b/devtools/client/themes/computed.css
+--- a/devtools/client/themes/computed.css
++++ b/devtools/client/themes/computed.css
+@@ -45,16 +45,18 @@
+   margin-inline-end: 5px;
+ }
+ 
+ #computed-property-container {
+   -moz-user-select: text;
+   overflow-y: auto;
+   overflow-x: hidden;
+   flex: auto;
++  border-top: 1px solid var(--theme-splitter-color);
++  margin-top: -1px;
+ }
+ 
+ .row-striped {
+   background: var(--theme-body-background);
+ }
+ 
+ .computed-property-hidden {
+   display: none;

+ 42 - 0
frg/253-58/mozilla-release58_428035.patch

@@ -0,0 +1,42 @@
+# HG changeset patch
+# User Gabriel Luong <gabriel.luong@gmail.com>
+# Date 1503353248 25200
+#      Mon Aug 21 15:07:28 2017 -0700
+# Node ID 5caa229b025e4605909de5e28037a3e3796c77be
+# Parent  44743e7c0aff3c095980440f85fb5196ec06947b
+Bug 1389732 - Add photon colors to variables.css. r=bgrins
+
+diff --git a/devtools/client/themes/variables.css b/devtools/client/themes/variables.css
+--- a/devtools/client/themes/variables.css
++++ b/devtools/client/themes/variables.css
+@@ -237,9 +237,30 @@
+ 
+   --toolbarbutton-background: rgba(110,120,130,0.1);
+   --toolbarbutton-border-color: transparent;
+   --toolbarbutton-hover-background: rgba(110,120,130,0.2);
+   --toolbarbutton-hover-border-color: var(--toolbarbutton-border-color);
+   --toolbarbutton-checked-background: var(--theme-selection-background);
+   --toolbarbutton-checked-color: var(--theme-selection-color);
+   --toolbarbutton-checked-border-color: var(--toolbarbutton-border-color);
++
++  /* Firefox Colors CSS Variables v1.0.3
++   * Colors are taken from: https://github.com/FirefoxUX/design-tokens */
++  --magenta-65: #dd00a9;
++
++  --blue-50: #0a84ff;
++  --blue-55: #0074e8;
++  --blue-60: #0060df;
++  --blue-70: #003eaa;
++
++  --green-70: #058b00;
++
++  --grey-10: #f9f9fa;
++  --grey-20: #ededf0;
++  --grey-30: #d7d7db;
++  --grey-40: #b1b1b3;
++  --grey-50: #737373;
++  --grey-60: #4a4a4f;
++  --grey-70: #38383d;
++  --grey-80: #2a2a2e;
++  --grey-90: #0c0c0d;
+ }

+ 258 - 0
frg/253-58/mozilla-release58_428040.patch

@@ -0,0 +1,258 @@
+# HG changeset patch
+# User sotaro <sotaro.ikeda.g@gmail.com>
+# Date 1503364611 -32400
+#      Tue Aug 22 10:16:51 2017 +0900
+# Node ID 6aa04814065027c6bc342ab5f03afdeb8a205390
+# Parent  88c422218869e7407995487868273ba5857cce67
+Bug 1391557 - Remove LayerTransactionParent::layer_manager() r=nical
+
+diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp
+--- a/gfx/layers/ipc/LayerTransactionParent.cpp
++++ b/gfx/layers/ipc/LayerTransactionParent.cpp
+@@ -173,121 +173,121 @@ LayerTransactionParent::RecvUpdate(const
+ 
+   TimeStamp updateStart = TimeStamp::Now();
+ 
+   MOZ_LAYERS_LOG(("[ParentSide] received txn with %zu edits", aInfo.cset().Length()));
+ 
+   UpdateFwdTransactionId(aInfo.fwdTransactionId());
+   AutoClearReadLocks clearLocks(mReadLocks);
+ 
+-  if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
++  if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+     for (const auto& op : aInfo.toDestroy()) {
+       DestroyActor(op);
+     }
+     return IPC_OK();
+   }
+ 
+   // This ensures that destroy operations are always processed. It is not safe
+   // to early-return from RecvUpdate without doing so.
+   AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this, &aInfo.toDestroy());
+ 
+   {
+     AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
+-    layer_manager()->BeginTransaction();
++    mLayerManager->BeginTransaction();
+   }
+ 
+   // Not all edits require an update to the hit testing tree.
+   mUpdateHitTestingTree = false;
+ 
+   for (EditArray::index_type i = 0; i < aInfo.cset().Length(); ++i) {
+     const Edit& edit = const_cast<Edit&>(aInfo.cset()[i]);
+ 
+     switch (edit.type()) {
+     // Create* ops
+     case Edit::TOpCreatePaintedLayer: {
+       MOZ_LAYERS_LOG(("[ParentSide] CreatePaintedLayer"));
+ 
+-      RefPtr<PaintedLayer> layer = layer_manager()->CreatePaintedLayer();
++      RefPtr<PaintedLayer> layer = mLayerManager->CreatePaintedLayer();
+       if (!BindLayer(layer, edit.get_OpCreatePaintedLayer())) {
+         return IPC_FAIL_NO_REASON(this);
+       }
+ 
+       UpdateHitTestingTree(layer, "CreatePaintedLayer");
+       break;
+     }
+     case Edit::TOpCreateContainerLayer: {
+       MOZ_LAYERS_LOG(("[ParentSide] CreateContainerLayer"));
+ 
+-      RefPtr<ContainerLayer> layer = layer_manager()->CreateContainerLayer();
++      RefPtr<ContainerLayer> layer = mLayerManager->CreateContainerLayer();
+       if (!BindLayer(layer, edit.get_OpCreateContainerLayer())) {
+         return IPC_FAIL_NO_REASON(this);
+       }
+ 
+       UpdateHitTestingTree(layer, "CreateContainerLayer");
+       break;
+     }
+     case Edit::TOpCreateImageLayer: {
+       MOZ_LAYERS_LOG(("[ParentSide] CreateImageLayer"));
+ 
+-      RefPtr<ImageLayer> layer = layer_manager()->CreateImageLayer();
++      RefPtr<ImageLayer> layer = mLayerManager->CreateImageLayer();
+       if (!BindLayer(layer, edit.get_OpCreateImageLayer())) {
+         return IPC_FAIL_NO_REASON(this);
+       }
+ 
+       UpdateHitTestingTree(layer, "CreateImageLayer");
+       break;
+     }
+     case Edit::TOpCreateColorLayer: {
+       MOZ_LAYERS_LOG(("[ParentSide] CreateColorLayer"));
+ 
+-      RefPtr<ColorLayer> layer = layer_manager()->CreateColorLayer();
++      RefPtr<ColorLayer> layer = mLayerManager->CreateColorLayer();
+       if (!BindLayer(layer, edit.get_OpCreateColorLayer())) {
+         return IPC_FAIL_NO_REASON(this);
+       }
+ 
+       UpdateHitTestingTree(layer, "CreateColorLayer");
+       break;
+     }
+     case Edit::TOpCreateTextLayer: {
+       MOZ_LAYERS_LOG(("[ParentSide] CreateTextLayer"));
+ 
+-      RefPtr<TextLayer> layer = layer_manager()->CreateTextLayer();
++      RefPtr<TextLayer> layer = mLayerManager->CreateTextLayer();
+       if (!BindLayer(layer, edit.get_OpCreateTextLayer())) {
+         return IPC_FAIL_NO_REASON(this);
+       }
+ 
+       UpdateHitTestingTree(layer, "CreateTextLayer");
+       break;
+     }
+     case Edit::TOpCreateBorderLayer: {
+       MOZ_LAYERS_LOG(("[ParentSide] CreateBorderLayer"));
+ 
+-      RefPtr<BorderLayer> layer = layer_manager()->CreateBorderLayer();
++      RefPtr<BorderLayer> layer = mLayerManager->CreateBorderLayer();
+       if (!BindLayer(layer, edit.get_OpCreateBorderLayer())) {
+         return IPC_FAIL_NO_REASON(this);
+       }
+ 
+       UpdateHitTestingTree(layer, "CreateBorderLayer");
+       break;
+     }
+     case Edit::TOpCreateCanvasLayer: {
+       MOZ_LAYERS_LOG(("[ParentSide] CreateCanvasLayer"));
+ 
+-      RefPtr<CanvasLayer> layer = layer_manager()->CreateCanvasLayer();
++      RefPtr<CanvasLayer> layer = mLayerManager->CreateCanvasLayer();
+       if (!BindLayer(layer, edit.get_OpCreateCanvasLayer())) {
+         return IPC_FAIL_NO_REASON(this);
+       }
+ 
+       UpdateHitTestingTree(layer, "CreateCanvasLayer");
+       break;
+     }
+     case Edit::TOpCreateRefLayer: {
+       MOZ_LAYERS_LOG(("[ParentSide] CreateRefLayer"));
+ 
+-      RefPtr<RefLayer> layer = layer_manager()->CreateRefLayer();
++      RefPtr<RefLayer> layer = mLayerManager->CreateRefLayer();
+       if (!BindLayer(layer, edit.get_OpCreateRefLayer())) {
+         return IPC_FAIL_NO_REASON(this);
+       }
+ 
+       UpdateHitTestingTree(layer, "CreateRefLayer");
+       break;
+     }
+     case Edit::TOpSetDiagnosticTypes: {
+@@ -475,17 +475,17 @@ LayerTransactionParent::RecvUpdate(const
+       return IPC_FAIL_NO_REASON(this);
+     }
+   }
+ 
+   mCompositorBridge->ShadowLayersUpdated(this, aInfo, mUpdateHitTestingTree);
+ 
+   {
+     AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
+-    layer_manager()->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW);
++    mLayerManager->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW);
+   }
+ 
+   if (!IsSameProcess()) {
+     // Ensure that any pending operations involving back and front
+     // buffers have completed, so that neither process stomps on the
+     // other's buffer contents.
+     LayerManagerComposite::PlatformSyncBeforeReplyUpdate();
+   }
+@@ -729,17 +729,17 @@ LayerTransactionParent::RecvLeaveTestMod
+ }
+ 
+ mozilla::ipc::IPCResult
+ LayerTransactionParent::RecvGetAnimationOpacity(const uint64_t& aCompositorAnimationsId,
+                                                 float* aOpacity,
+                                                 bool* aHasAnimationOpacity)
+ {
+   *aHasAnimationOpacity = false;
+-  if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
++  if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+     return IPC_FAIL_NO_REASON(this);
+   }
+ 
+   mCompositorBridge->ApplyAsyncProperties(this);
+ 
+   if (!mAnimStorage) {
+     return IPC_FAIL_NO_REASON(this);
+   }
+@@ -751,17 +751,17 @@ LayerTransactionParent::RecvGetAnimation
+   }
+   return IPC_OK();
+ }
+ 
+ mozilla::ipc::IPCResult
+ LayerTransactionParent::RecvGetAnimationTransform(const uint64_t& aCompositorAnimationsId,
+                                                   MaybeTransform* aTransform)
+ {
+-  if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
++  if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+     return IPC_FAIL_NO_REASON(this);
+   }
+ 
+   // Make sure we apply the latest animation style or else we can end up with
+   // a race between when we temporarily clear the animation transform (in
+   // CompositorBridgeParent::SetShadowProperties) and when animation recalculates
+   // the value.
+   mCompositorBridge->ApplyAsyncProperties(this);
+@@ -797,33 +797,33 @@ GetAPZCForViewID(Layer* aLayer, FrameMet
+       });
+   return resultApzc;
+ }
+ 
+ mozilla::ipc::IPCResult
+ LayerTransactionParent::RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aScrollID,
+                                                  const float& aX, const float& aY)
+ {
+-  if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
++  if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+     return IPC_FAIL_NO_REASON(this);
+   }
+ 
+   AsyncPanZoomController* controller = GetAPZCForViewID(mRoot, aScrollID);
+   if (!controller) {
+     return IPC_FAIL_NO_REASON(this);
+   }
+   controller->SetTestAsyncScrollOffset(CSSPoint(aX, aY));
+   return IPC_OK();
+ }
+ 
+ mozilla::ipc::IPCResult
+ LayerTransactionParent::RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollID,
+                                          const float& aValue)
+ {
+-  if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
++  if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+     return IPC_FAIL_NO_REASON(this);
+   }
+ 
+   AsyncPanZoomController* controller = GetAPZCForViewID(mRoot, aScrollID);
+   if (!controller) {
+     return IPC_FAIL_NO_REASON(this);
+   }
+   controller->SetTestAsyncZoom(LayerToParentLayerScale(aValue));
+diff --git a/gfx/layers/ipc/LayerTransactionParent.h b/gfx/layers/ipc/LayerTransactionParent.h
+--- a/gfx/layers/ipc/LayerTransactionParent.h
++++ b/gfx/layers/ipc/LayerTransactionParent.h
+@@ -52,18 +52,16 @@ public:
+                          uint64_t aId);
+ 
+ protected:
+   ~LayerTransactionParent();
+ 
+ public:
+   void Destroy();
+ 
+-  HostLayerManager* layer_manager() const { return mLayerManager; }
+-
+   void SetLayerManager(HostLayerManager* aLayerManager, CompositorAnimationStorage* aAnimStorage);
+ 
+   uint64_t GetId() const { return mId; }
+   Layer* GetRoot() const { return mRoot; }
+ 
+   uint64_t GetChildEpoch() const { return mChildEpoch; }
+   bool ShouldParentObserveEpoch();
+ 

+ 219 - 0
frg/253-58/mozilla-release58_428041.patch

@@ -0,0 +1,219 @@
+# HG changeset patch
+# User Nicholas Nethercote <nnethercote@mozilla.com>
+# Date 1503295636 -36000
+#      Mon Aug 21 16:07:16 2017 +1000
+# Node ID 50fd4bb9897fb179ceeca364b04469c19900cc60
+# Parent  5aa2f55a54dde5e1a9dd8e160517441f72a5895c
+Bug 1390760 - Measure ServoComputedData::visited_style. r=bholley.
+
+For the Obama wikipedia page, this covers about 85% of the unmeasured
+ComputedValues structs. The about:memory output looks like this:
+
+> +---2,443,648 B (02.41%) -- computed-values
+> |   +--1,088,272 B (01.07%) -- dom
+> |   +----945,744 B (00.93%) -- non-dom
+> |   +----409,632 B (00.40%) -- visited
+
+I'm not sure why some CVs are still being missed.
+
+MozReview-Commit-ID: 1bYWwSi4ihn
+
+diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp
+--- a/dom/base/Element.cpp
++++ b/dom/base/Element.cpp
+@@ -4279,24 +4279,25 @@ Element::AddSizeOfExcludingThis(SizeOfSt
+                                               &aState.mSeenPtrs, this);
+ 
+     // Now measure just the ComputedValues (and style structs) under
+     // mServoData. This counts towards the relevant fields in |aSizes|.
+     RefPtr<ServoStyleContext> sc;
+     if (Servo_Element_HasPrimaryComputedValues(this)) {
+       sc = Servo_Element_GetPrimaryComputedValues(this).Consume();
+       if (!aState.HaveSeenPtr(sc.get())) {
+-        sc->AddSizeOfIncludingThis(aState, aSizes, /* isDOM = */ true);
++        sc->AddSizeOfIncludingThis(aState, aSizes, &aSizes.mComputedValuesDom);
+       }
+ 
+       for (size_t i = 0; i < nsCSSPseudoElements::kEagerPseudoCount; i++) {
+         if (Servo_Element_HasPseudoComputedValues(this, i)) {
+           sc = Servo_Element_GetPseudoComputedValues(this, i).Consume();
+           if (!aState.HaveSeenPtr(sc.get())) {
+-            sc->AddSizeOfIncludingThis(aState, aSizes, /* isDOM = */ true);
++            sc->AddSizeOfIncludingThis(aState, aSizes,
++                                       &aSizes.mComputedValuesDom);
+           }
+         }
+       }
+     }
+   }
+ }
+ 
+ struct DirtyDescendantsBit {
+diff --git a/dom/base/nsWindowMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp
+--- a/dom/base/nsWindowMemoryReporter.cpp
++++ b/dom/base/nsWindowMemoryReporter.cpp
+@@ -491,16 +491,22 @@ CollectWindowReports(nsGlobalWindow *aWi
+ 
+   REPORT_SIZE("/layout/computed-values/non-dom",
+               windowSizes.mStyleSizes.mComputedValuesNonDom,
+               "Memory used by ComputedValues objects not accessible from DOM "
+               "elements.");
+   aWindowTotalSizes->mStyleSizes.mComputedValuesNonDom +=
+     windowSizes.mStyleSizes.mComputedValuesNonDom;
+ 
++  REPORT_SIZE("/layout/computed-values/visited",
++              windowSizes.mStyleSizes.mComputedValuesVisited,
++              "Memory used by ComputedValues objects used for visited styles.");
++  aWindowTotalSizes->mStyleSizes.mComputedValuesVisited +=
++    windowSizes.mStyleSizes.mComputedValuesVisited;
++
+ #undef REPORT_SIZE
+ #undef REPORT_COUNT
+ }
+ 
+ typedef nsTArray< RefPtr<nsGlobalWindow> > WindowArray;
+ 
+ NS_IMETHODIMP
+ nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
+@@ -665,17 +671,18 @@ nsWindowMemoryReporter::CollectReports(n
+ #undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
+ 
+   REPORT("window-objects/layout/servo-style-structs", styleTotal,
+          "Memory used for style structs within windows. This is the sum of "
+          "all windows' 'layout/servo-style-structs/' numbers.");
+ 
+   REPORT("window-objects/layout/computed-values",
+          windowTotalSizes.mStyleSizes.mComputedValuesDom +
+-         windowTotalSizes.mStyleSizes.mComputedValuesNonDom,
++         windowTotalSizes.mStyleSizes.mComputedValuesNonDom +
++         windowTotalSizes.mStyleSizes.mComputedValuesVisited,
+          "This is the sum of all windows' 'layout/computed-values/' "
+          "numbers.");
+ 
+ #undef REPORT
+ 
+   return NS_OK;
+ }
+ 
+diff --git a/dom/base/nsWindowSizes.h b/dom/base/nsWindowSizes.h
+--- a/dom/base/nsWindowSizes.h
++++ b/dom/base/nsWindowSizes.h
+@@ -108,17 +108,18 @@ struct nsArenaSizes {
+ };
+ 
+ #define NS_STYLE_SIZES_FIELD(name_) mStyle##name_
+ 
+ struct nsStyleSizes
+ {
+ #define FOR_EACH_SIZE(macro) \
+   macro(Style, mComputedValuesDom) \
+-  macro(Style, mComputedValuesNonDom)
++  macro(Style, mComputedValuesNonDom) \
++  macro(Style, mComputedValuesVisited)
+ 
+   nsStyleSizes()
+     :
+       FOR_EACH_SIZE(ZERO_SIZE)
+ 
+       #define STYLE_STRUCT(name_, cb_) \
+         NS_STYLE_SIZES_FIELD(name_)(0),
+       #define STYLE_STRUCT_LIST_IGNORE_VARIABLES
+diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
+--- a/layout/generic/nsFrame.cpp
++++ b/layout/generic/nsFrame.cpp
+@@ -10670,17 +10670,17 @@ nsIFrame::AddSizeOfExcludingThisForTree(
+     mProperties.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
+ 
+   // We don't do this for Gecko because this stuff is stored in the nsPresArena
+   // and so measured elsewhere.
+   if (mStyleContext->IsServo()) {
+     ServoStyleContext* sc = mStyleContext->AsServo();
+     if (!aSizes.mState.HaveSeenPtr(sc)) {
+       sc->AddSizeOfIncludingThis(aSizes.mState, aSizes.mStyleSizes,
+-                                 /* isDOM = */ false);
++                                 &aSizes.mStyleSizes.mComputedValuesNonDom);
+     }
+   }
+ 
+   FrameChildListIterator iter(this);
+   while (!iter.IsDone()) {
+     for (const nsIFrame* f : iter.CurrentList()) {
+       f->AddSizeOfExcludingThisForTree(aSizes);
+     }
+diff --git a/layout/style/ServoBindings.cpp b/layout/style/ServoBindings.cpp
+--- a/layout/style/ServoBindings.cpp
++++ b/layout/style/ServoBindings.cpp
+@@ -259,16 +259,28 @@ ServoComputedData::AddSizeOfExcludingThi
+   if (!aState.HaveSeenPtr(p##name_)) { \
+     aSizes.NS_STYLE_SIZES_FIELD(name_) += \
+       ServoStyleStructsMallocSizeOf(p##name_); \
+   }
+   #define STYLE_STRUCT_LIST_IGNORE_VARIABLES
+ #include "nsStyleStructList.h"
+ #undef STYLE_STRUCT
+ #undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
++
++  if (visited_style.mPtr && !aState.HaveSeenPtr(visited_style.mPtr)) {
++    visited_style.mPtr->AddSizeOfIncludingThis(
++      aState, aSizes, &aSizes.mComputedValuesVisited);
++  }
++
++  // Measurement of the following members may be added later if DMD finds it is
++  // worthwhile:
++  // - custom_properties
++  // - writing_mode
++  // - rules
++  // - font_computation_data
+ }
+ 
+ void
+ Gecko_ServoStyleContext_Destroy(ServoStyleContext* aContext)
+ {
+   aContext->~ServoStyleContext();
+ }
+ 
+diff --git a/layout/style/ServoStyleContext.h b/layout/style/ServoStyleContext.h
+--- a/layout/style/ServoStyleContext.h
++++ b/layout/style/ServoStyleContext.h
+@@ -95,36 +95,35 @@ public:
+   }
+ 
+   /**
+    * Makes this context match |aOther| in terms of which style structs have
+    * been resolved.
+    */
+   inline void ResolveSameStructsAs(const ServoStyleContext* aOther);
+ 
++  // The |aCVsSize| outparam on this function is where the actual CVs size
++  // value is added. It's done that way because the callers know which value
++  // the size should be added to.
+   void AddSizeOfIncludingThis(SizeOfState& aState, nsStyleSizes& aSizes,
+-                              bool aIsDOM) const
++                              size_t* aCVsSize) const
+   {
+     // XXX WARNING: similar to ServoComputedData::AddSizeOfExcludingThis(),
+     // but here we need to step back 4 or 8 bytes to get past the servo_arc::Arc
+     // refcount to the base pointer.
+     static_assert(alignof(ServoStyleContext) == 4 ||
+                   alignof(ServoStyleContext) == 8,
+                   "alignment will break AddSizeOfExcludingThis()");
+     const char* p = reinterpret_cast<const char*>(this);
+     p -= std::max(sizeof(size_t), alignof(ServoStyleContext));
+ 
+     // We use ServoComputedValuesMallocSizeOf rather than
+     // |aState.mMallocSizeOf| to better distinguish in DMD's output the memory
+     // measured here.
+-    if (aIsDOM) {
+-      aSizes.mComputedValuesDom += ServoComputedValuesMallocSizeOf(p);
+-    } else {
+-      aSizes.mComputedValuesNonDom += ServoComputedValuesMallocSizeOf(p);
+-    }
++    *aCVsSize += ServoComputedValuesMallocSizeOf(p);
+     mSource.AddSizeOfExcludingThis(aState, aSizes);
+   }
+ 
+ private:
+   nsPresContext* mPresContext;
+   ServoComputedData mSource;
+ 
+   // A linked-list cache of inheriting anon boxes inheriting from this style _if

+ 84 - 0
frg/253-58/mozilla-release58_428042.patch

@@ -0,0 +1,84 @@
+# HG changeset patch
+# User Bevis Tseng <btseng@mozilla.com>
+# Date 1503307822 -28800
+#      Mon Aug 21 17:30:22 2017 +0800
+# Node ID fe7d953913e0b272eb9b1193c2095f0e4574519e
+# Parent  50fd4bb9897fb179ceeca364b04469c19900cc60
+Bug 1392201 - Label nsThreadShutdownAckEvent. r=froydnj
+
+diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp
+--- a/xpcom/threads/nsThread.cpp
++++ b/xpcom/threads/nsThread.cpp
+@@ -25,16 +25,17 @@
+ #include "mozilla/Logging.h"
+ #include "nsIObserverService.h"
+ #include "mozilla/HangMonitor.h"
+ #include "mozilla/IOInterposer.h"
+ #include "mozilla/ipc/MessageChannel.h"
+ #include "mozilla/ipc/BackgroundChild.h"
+ #include "mozilla/SchedulerGroup.h"
+ #include "mozilla/Services.h"
++#include "mozilla/SystemGroup.h"
+ #include "nsXPCOMPrivate.h"
+ #include "mozilla/ChaosMode.h"
+ #include "mozilla/Telemetry.h"
+ #include "mozilla/TimeStamp.h"
+ #include "mozilla/Unused.h"
+ #include "mozilla/dom/ScriptSettings.h"
+ #include "nsThreadSyncDispatch.h"
+ #include "GeckoProfiler.h"
+@@ -236,29 +237,31 @@ private:
+ struct nsThreadShutdownContext
+ {
+   nsThreadShutdownContext(NotNull<nsThread*> aTerminatingThread,
+                           NotNull<nsThread*> aJoiningThread,
+                           bool      aAwaitingShutdownAck)
+     : mTerminatingThread(aTerminatingThread)
+     , mJoiningThread(aJoiningThread)
+     , mAwaitingShutdownAck(aAwaitingShutdownAck)
++    , mIsMainThreadJoining(NS_IsMainThread())
+   {
+     MOZ_COUNT_CTOR(nsThreadShutdownContext);
+   }
+   ~nsThreadShutdownContext()
+   {
+     MOZ_COUNT_DTOR(nsThreadShutdownContext);
+   }
+ 
+   // NB: This will be the last reference.
+   NotNull<RefPtr<nsThread>> mTerminatingThread;
+   NotNull<nsThread*> MOZ_UNSAFE_REF("Thread manager is holding reference to joining thread")
+     mJoiningThread;
+   bool mAwaitingShutdownAck;
++  bool mIsMainThreadJoining;
+ };
+ 
+ // This event is responsible for notifying nsThread::Shutdown that it is time
+ // to call PR_JoinThread. It implements nsICancelableRunnable so that it can
+ // run on a DOM Worker thread (where all events must implement
+ // nsICancelableRunnable.)
+ class nsThreadShutdownAckEvent : public CancelableRunnable
+ {
+@@ -451,17 +454,21 @@ nsThread::ThreadFunc(void* aArg)
+ 
+   profiler_unregister_thread();
+ 
+   // Dispatch shutdown ACK
+   NotNull<nsThreadShutdownContext*> context =
+     WrapNotNull(self->mShutdownContext);
+   MOZ_ASSERT(context->mTerminatingThread == self);
+   event = do_QueryObject(new nsThreadShutdownAckEvent(context));
+-  context->mJoiningThread->Dispatch(event, NS_DISPATCH_NORMAL);
++  if (context->mIsMainThreadJoining) {
++    SystemGroup::Dispatch(TaskCategory::Other, event.forget());
++  } else {
++    context->mJoiningThread->Dispatch(event, NS_DISPATCH_NORMAL);
++  }
+ 
+   // Release any observer of the thread here.
+   self->SetObserver(nullptr);
+ 
+ #ifdef MOZ_TASK_TRACER
+   FreeTraceInfo();
+ #endif
+ 

+ 109 - 0
frg/253-58/mozilla-release58_428056.patch

@@ -0,0 +1,109 @@
+# HG changeset patch
+# User Ting-Yu Lin <tlin@mozilla.com>
+# Date 1503384385 -28800
+#      Tue Aug 22 14:46:25 2017 +0800
+# Node ID 9a93541800d3cf2e3c59362ae3d77c449db6f9d1
+# Parent  210ddb51ef86e1e8329affce6f050b1cd5cb8cf7
+Bug 1388165 - Clear mPresContext after creating XBL styleset. r=xidorn
+
+MozReview-Commit-ID: VBmKMTt8lc
+
+diff --git a/devtools/client/inspector/markup/test/browser.ini b/devtools/client/inspector/markup/test/browser.ini
+--- a/devtools/client/inspector/markup/test/browser.ini
++++ b/devtools/client/inspector/markup/test/browser.ini
+@@ -78,17 +78,16 @@ skip-if = os == "mac" # Full keyboard na
+ skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
+ [browser_markup_accessibility_semantics.js]
+ [browser_markup_anonymous_01.js]
+ [browser_markup_anonymous_02.js]
+ skip-if = e10s # scratchpad.xul is not loading in e10s window
+ [browser_markup_anonymous_03.js]
+ skip-if = stylo # Stylo doesn't support shadow DOM yet, bug 1293844
+ [browser_markup_anonymous_04.js]
+-skip-if = stylo && debug # Bug 1386865 - Triggers assertion
+ [browser_markup_copy_image_data.js]
+ subsuite = clipboard
+ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
+ [browser_markup_css_completion_style_attribute_01.js]
+ [browser_markup_css_completion_style_attribute_02.js]
+ [browser_markup_css_completion_style_attribute_03.js]
+ [browser_markup_dragdrop_autoscroll_01.js]
+ [browser_markup_dragdrop_autoscroll_02.js]
+diff --git a/dom/xbl/nsXBLPrototypeResources.cpp b/dom/xbl/nsXBLPrototypeResources.cpp
+--- a/dom/xbl/nsXBLPrototypeResources.cpp
++++ b/dom/xbl/nsXBLPrototypeResources.cpp
+@@ -174,16 +174,21 @@ nsXBLPrototypeResources::ComputeServoSty
+                "This should only be called with Servo-flavored style backend!");
+     // The XBL style sheets aren't document level sheets, but we need to
+     // decide a particular SheetType to add them to style set. This type
+     // doesn't affect the place where we pull those rules from
+     // stylist::push_applicable_declarations_as_xbl_only_stylist().
+     mServoStyleSet->AppendStyleSheet(SheetType::Doc, sheet->AsServo());
+   }
+   mServoStyleSet->UpdateStylistIfNeeded();
++
++  // The PresContext of the bound document could be destroyed anytime later,
++  // which shouldn't be used for XBL styleset, so we clear it here to avoid
++  // dangling pointer.
++  mServoStyleSet->ClearPresContext();
+ }
+ 
+ void
+ nsXBLPrototypeResources::AppendStyleSheet(StyleSheet* aSheet)
+ {
+   mStyleSheetList.AppendElement(aSheet);
+ }
+ 
+diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp
+--- a/layout/style/ServoStyleSet.cpp
++++ b/layout/style/ServoStyleSet.cpp
+@@ -1465,19 +1465,21 @@ ServoStyleSet::RunPostTraversalTasks()
+   }
+ }
+ 
+ ServoStyleRuleMap*
+ ServoStyleSet::StyleRuleMap()
+ {
+   if (!mStyleRuleMap) {
+     mStyleRuleMap = new ServoStyleRuleMap(this);
+-    nsIDocument* doc = mPresContext->Document();
+-    doc->AddObserver(mStyleRuleMap);
+-    doc->CSSLoader()->AddObserver(mStyleRuleMap);
++    if (mPresContext) {
++      nsIDocument* doc = mPresContext->Document();
++      doc->AddObserver(mStyleRuleMap);
++      doc->CSSLoader()->AddObserver(mStyleRuleMap);
++    }
+   }
+   return mStyleRuleMap;
+ }
+ 
+ bool
+ ServoStyleSet::MightHaveAttributeDependency(const Element& aElement,
+                                             nsIAtom* aAttribute) const
+ {
+diff --git a/layout/style/ServoStyleSet.h b/layout/style/ServoStyleSet.h
+--- a/layout/style/ServoStyleSet.h
++++ b/layout/style/ServoStyleSet.h
+@@ -419,16 +419,21 @@ public:
+   // its inner.
+   void SetNeedsRestyleAfterEnsureUniqueInner() {
+     mNeedsRestyleAfterEnsureUniqueInner = true;
+   }
+ 
+   // Returns the style rule map.
+   ServoStyleRuleMap* StyleRuleMap();
+ 
++  // Clear mPresContext. This is needed after XBL ServoStyleSet is created.
++  void ClearPresContext() {
++    mPresContext = nullptr;
++  }
++
+   /**
+    * Returns true if a modification to an an attribute with the specified
+    * local name might require us to restyle the element.
+    *
+    * This function allows us to skip taking a an attribute snapshot when
+    * the modified attribute doesn't appear in an attribute selector in
+    * a style sheet.
+    */

+ 337 - 0
frg/253-58/mozilla-release58_428062.patch

@@ -0,0 +1,337 @@
+# HG changeset patch
+# User Emilio Cobos Alvarez <emilio@crisal.io>
+# Date 1503398917 18000
+#      Tue Aug 22 05:48:37 2017 -0500
+# Node ID c400a6bfd3c03fb7f54add85cf1814d4f6ee0403
+# Parent  27ae7f3c6bf6a01f4e189c3af229eb99de9b6368
+servo: Merge #18184 - style: Inline a bunch of trivial stuff we're paying function calls for in Geckolib (from emilio:inline); r=upsuper
+
+Reviewed by Xidorn in https://bugzilla.mozilla.org/show_bug.cgi?id=1392170.
+
+Source-Repo: https://github.com/servo/servo
+Source-Revision: 1059ef4fdeb5c76102c3da22293d836942740033
+
+diff --git a/servo/components/style/data.rs b/servo/components/style/data.rs
+--- a/servo/components/style/data.rs
++++ b/servo/components/style/data.rs
+@@ -67,27 +67,29 @@ impl RestyleData {
+             damage: RestyleDamage::empty(),
+         }
+     }
+ 
+     /// Clear all the restyle state associated with this element.
+     ///
+     /// FIXME(bholley): The only caller of this should probably just assert that
+     /// the hint is empty and call clear_flags_and_damage().
++    #[inline]
+     fn clear_restyle_state(&mut self) {
+         self.clear_restyle_flags_and_damage();
+         self.hint = RestyleHint::empty();
+     }
+ 
+     /// Clear restyle flags and damage.
+     ///
+     /// Note that we don't touch the TRAVERSED_WITHOUT_STYLING bit, which gets
+     /// set to the correct value on each traversal. There's no reason anyone
+     /// needs to clear it, and clearing it accidentally mid-traversal could
+     /// cause incorrect style sharing behavior.
++    #[inline]
+     fn clear_restyle_flags_and_damage(&mut self) {
+         self.damage = RestyleDamage::empty();
+         self.flags = self.flags & TRAVERSED_WITHOUT_STYLING;
+     }
+ 
+     /// Returns whether this element or any ancestor is going to be
+     /// reconstructed.
+     pub fn reconstructed_self_or_ancestor(&self) -> bool {
+@@ -119,32 +121,34 @@ impl RestyleData {
+     /// Mark this element as restyled, which is useful to know whether we need
+     /// to do a post-traversal.
+     pub fn set_restyled(&mut self) {
+         self.flags.insert(WAS_RESTYLED);
+         self.flags.remove(TRAVERSED_WITHOUT_STYLING);
+     }
+ 
+     /// Returns true if this element was restyled.
++    #[inline]
+     pub fn is_restyle(&self) -> bool {
+         self.flags.contains(WAS_RESTYLED)
+     }
+ 
+     /// Mark that we traversed this element without computing any style for it.
+     pub fn set_traversed_without_styling(&mut self) {
+         self.flags.insert(TRAVERSED_WITHOUT_STYLING);
+     }
+ 
+     /// Returns whether the element was traversed without computing any style for
+     /// it.
+     pub fn traversed_without_styling(&self) -> bool {
+         self.flags.contains(TRAVERSED_WITHOUT_STYLING)
+     }
+ 
+     /// Returns whether this element has been part of a restyle.
++    #[inline]
+     pub fn contains_restyle_data(&self) -> bool {
+         self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
+     }
+ }
+ 
+ /// A lazily-allocated list of styles for eagerly-cascaded pseudo-elements.
+ ///
+ /// We use an Arc so that sharing these styles via the style sharing cache does
+@@ -348,16 +352,17 @@ impl ElementData {
+             );
+             invalidator.invalidate();
+             unsafe { element.set_handled_snapshot() }
+             debug_assert!(element.handled_snapshot());
+         }
+     }
+ 
+     /// Returns true if this element has styles.
++    #[inline]
+     pub fn has_styles(&self) -> bool {
+         self.styles.primary.is_some()
+     }
+ 
+     /// Returns the kind of restyling that we're going to need to do on this
+     /// element, based of the stored restyle hint.
+     pub fn restyle_kind(
+         &self,
+@@ -424,21 +429,23 @@ impl ElementData {
+         debug_assert!(self.has_styles());
+         let (important_rules, _custom) =
+             self.styles.primary().rules().get_properties_overriding_animations(&guards);
+         let (other_important_rules, _custom) = rules.get_properties_overriding_animations(&guards);
+         important_rules != other_important_rules
+     }
+ 
+     /// Drops any restyle state from the element.
++    #[inline]
+     pub fn clear_restyle_state(&mut self) {
+         self.restyle.clear_restyle_state();
+     }
+ 
+     /// Drops restyle flags and damage from the element.
++    #[inline]
+     pub fn clear_restyle_flags_and_damage(&mut self) {
+         self.restyle.clear_restyle_flags_and_damage();
+     }
+ 
+     /// Measures memory usage.
+     #[cfg(feature = "gecko")]
+     pub fn malloc_size_of_children_excluding_cvs(&self, state: &mut SizeOfState) -> usize {
+         let n = self.styles.malloc_size_of_children_excluding_cvs(state);
+diff --git a/servo/components/style/gecko/restyle_damage.rs b/servo/components/style/gecko/restyle_damage.rs
+--- a/servo/components/style/gecko/restyle_damage.rs
++++ b/servo/components/style/gecko/restyle_damage.rs
+@@ -13,31 +13,35 @@ use std::ops::{BitAnd, BitOr, BitOrAssig
+ 
+ /// The representation of Gecko's restyle damage is just a wrapper over
+ /// `nsChangeHint`.
+ #[derive(Clone, Copy, Debug, PartialEq)]
+ pub struct GeckoRestyleDamage(nsChangeHint);
+ 
+ impl GeckoRestyleDamage {
+     /// Trivially construct a new `GeckoRestyleDamage`.
++    #[inline]
+     pub fn new(raw: nsChangeHint) -> Self {
+         GeckoRestyleDamage(raw)
+     }
+ 
+     /// Get the inner change hint for this damage.
++    #[inline]
+     pub fn as_change_hint(&self) -> nsChangeHint {
+         self.0
+     }
+ 
+     /// Get an empty change hint, that is (`nsChangeHint(0)`).
++    #[inline]
+     pub fn empty() -> Self {
+         GeckoRestyleDamage(nsChangeHint(0))
+     }
+ 
+     /// Returns whether this restyle damage represents the empty damage.
++    #[inline]
+     pub fn is_empty(&self) -> bool {
+         self.0 == nsChangeHint(0)
+     }
+ 
+     /// Computes the `StyleDifference` (including the appropriate change hint)
+     /// given an old style (in the form of a `nsStyleContext`, and a new style
+     /// (in the form of `ComputedValues`).
+     ///
+diff --git a/servo/components/style/gecko/wrapper.rs b/servo/components/style/gecko/wrapper.rs
+--- a/servo/components/style/gecko/wrapper.rs
++++ b/servo/components/style/gecko/wrapper.rs
+@@ -289,16 +289,17 @@ impl<'ln> TNode for GeckoNode<'ln> {
+         let ptr: usize = self.0 as *const _ as usize;
+         OpaqueNode(ptr)
+     }
+ 
+     fn debug_id(self) -> usize {
+         unimplemented!()
+     }
+ 
++    #[inline]
+     fn as_element(&self) -> Option<GeckoElement<'ln>> {
+         if self.is_element() {
+             unsafe { Some(GeckoElement(&*(self.0 as *const _ as *const RawGeckoElement))) }
+         } else {
+             None
+         }
+     }
+ 
+@@ -1014,43 +1015,47 @@ impl<'le> TElement for GeckoElement<'le>
+     fn each_class<F>(&self, callback: F)
+         where F: FnMut(&Atom)
+     {
+         snapshot_helpers::each_class(self.0,
+                                      callback,
+                                      Gecko_ClassOrClassList)
+     }
+ 
++    #[inline]
+     fn has_snapshot(&self) -> bool {
+         self.flags() & (ELEMENT_HAS_SNAPSHOT as u32) != 0
+     }
+ 
++    #[inline]
+     fn handled_snapshot(&self) -> bool {
+         self.flags() & (ELEMENT_HANDLED_SNAPSHOT as u32) != 0
+     }
+ 
+     unsafe fn set_handled_snapshot(&self) {
+         debug_assert!(self.get_data().is_some());
+         self.set_flags(ELEMENT_HANDLED_SNAPSHOT as u32)
+     }
+ 
++    #[inline]
+     fn has_dirty_descendants(&self) -> bool {
+         self.flags() & (ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
+     }
+ 
+     unsafe fn set_dirty_descendants(&self) {
+         debug_assert!(self.get_data().is_some());
+         debug!("Setting dirty descendants: {:?}", self);
+         self.set_flags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
+     }
+ 
+     unsafe fn unset_dirty_descendants(&self) {
+         self.unset_flags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
+     }
+ 
++    #[inline]
+     fn has_animation_only_dirty_descendants(&self) -> bool {
+         self.flags() & (ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
+     }
+ 
+     unsafe fn set_animation_only_dirty_descendants(&self) {
+         self.set_flags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32)
+     }
+ 
+@@ -1059,21 +1064,23 @@ impl<'le> TElement for GeckoElement<'le>
+     }
+ 
+     unsafe fn clear_descendants_bits(&self) {
+         self.unset_flags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
+                          ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
+                          NODE_DESCENDANTS_NEED_FRAMES as u32)
+     }
+ 
++    #[inline]
+     fn is_visited_link(&self) -> bool {
+         use element_state::IN_VISITED_STATE;
+         self.get_state().intersects(IN_VISITED_STATE)
+     }
+ 
++    #[inline]
+     fn is_native_anonymous(&self) -> bool {
+         use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS;
+         self.flags() & (NODE_IS_NATIVE_ANONYMOUS as u32) != 0
+     }
+ 
+     fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
+         if !self.is_native_anonymous() {
+             return None;
+@@ -1091,16 +1098,17 @@ impl<'le> TElement for GeckoElement<'le>
+     fn store_children_to_process(&self, _: isize) {
+         // This is only used for bottom-up traversal, and is thus a no-op for Gecko.
+     }
+ 
+     fn did_process_child(&self) -> isize {
+         panic!("Atomic child count not implemented in Gecko");
+     }
+ 
++    #[inline(always)]
+     fn get_data(&self) -> Option<&AtomicRefCell<ElementData>> {
+         unsafe { self.0.mServoData.get().as_ref() }
+     }
+ 
+     unsafe fn ensure_data(&self) -> AtomicRefMut<ElementData> {
+         if self.get_data().is_none() {
+             debug!("Creating ElementData for {:?}", self);
+             let ptr = Box::into_raw(Box::new(AtomicRefCell::new(ElementData::default())));
+@@ -1122,16 +1130,17 @@ impl<'le> TElement for GeckoElement<'le>
+ 
+             // Perform a mutable borrow of the data in debug builds. This
+             // serves as an assertion that there are no outstanding borrows
+             // when we destroy the data.
+             debug_assert!({ let _ = data.borrow_mut(); true });
+         }
+     }
+ 
++    #[inline]
+     fn skip_root_and_item_based_display_fixup(&self) -> bool {
+         // We don't want to fix up display values of native anonymous content.
+         // Additionally, we want to skip root-based display fixup for document
+         // level native anonymous content subtree roots, since they're not
+         // really roots from the style fixup perspective.  Checking that we
+         // are NAC handles both cases.
+         self.is_native_anonymous()
+     }
+diff --git a/servo/components/style/traversal.rs b/servo/components/style/traversal.rs
+--- a/servo/components/style/traversal.rs
++++ b/servo/components/style/traversal.rs
+@@ -52,23 +52,25 @@ impl TraversalDriver {
+     /// Returns whether this represents a parallel traversal or not.
+     #[inline]
+     pub fn is_parallel(&self) -> bool {
+         matches!(*self, TraversalDriver::Parallel)
+     }
+ }
+ 
+ #[cfg(feature = "servo")]
++#[inline]
+ fn is_servo_nonincremental_layout() -> bool {
+     use servo_config::opts;
+ 
+     opts::get().nonincremental_layout
+ }
+ 
+ #[cfg(not(feature = "servo"))]
++#[inline]
+ fn is_servo_nonincremental_layout() -> bool {
+     false
+ }
+ 
+ /// A DOM Traversal trait, that is used to generically implement styling for
+ /// Gecko and Servo.
+ pub trait DomTraversal<E: TElement> : Sync {
+     /// Process `node` on the way down, before its children have been processed.
+diff --git a/servo/components/style/traversal_flags.rs b/servo/components/style/traversal_flags.rs
+--- a/servo/components/style/traversal_flags.rs
++++ b/servo/components/style/traversal_flags.rs
+@@ -72,12 +72,13 @@ pub fn assert_traversal_flags_match() {
+             ClearAnimationOnlyDirtyDescendants,
+         ServoTraversalFlags_ParallelTraversal => ParallelTraversal,
+         ServoTraversalFlags_FlushThrottledAnimations => FlushThrottledAnimations,
+     }
+ }
+ 
+ impl TraversalFlags {
+     /// Returns true if the traversal is for animation-only restyles.
++    #[inline]
+     pub fn for_animation_only(&self) -> bool {
+         self.contains(AnimationOnly)
+     }
+ }

+ 44 - 0
frg/253-58/mozilla-release58_428073.patch

@@ -0,0 +1,44 @@
+# HG changeset patch
+# User Masayuki Nakano <masayuki@d-toybox.com>
+# Date 1503295701 -32400
+#      Mon Aug 21 15:08:21 2017 +0900
+# Node ID 7f1d159041a2736260fcb1c8fdd026e5506244b9
+# Parent  905621f874da98928685e73a0bfb4e29ede0dc3a
+Bug 1354004 - Make new Japanese default font settings ride the train r=emk,m_kato
+
+Although, we still have an issue that is leading of text in <input type="text">
+element causes overflow and scrollable (bug 1378065), we have no other
+compatibility issue reports and the issue is not so important nor easy to fix.
+So, now, let's make the new Japanese default font settings ride the train.
+
+MozReview-Commit-ID: J3SN9FtHoZg
+
+diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
+--- a/modules/libpref/init/all.js
++++ b/modules/libpref/init/all.js
+@@ -3730,25 +3730,19 @@ pref("font.name-list.sans-serif.el", "Ar
+ pref("font.name-list.monospace.el", "Courier New");
+ pref("font.name-list.cursive.el", "Comic Sans MS");
+ 
+ pref("font.name-list.serif.he", "Narkisim, David");
+ pref("font.name-list.sans-serif.he", "Arial");
+ pref("font.name-list.monospace.he", "Fixed Miriam Transparent, Miriam Fixed, Rod, Courier New");
+ pref("font.name-list.cursive.he", "Guttman Yad, Ktav, Arial");
+ 
+-#ifdef EARLY_BETA_OR_EARLIER
+ pref("font.name-list.serif.ja", "Yu Mincho, MS PMincho, MS Mincho, Meiryo, Yu Gothic, MS PGothic, MS Gothic");
+ pref("font.name-list.sans-serif.ja", "Meiryo, Yu Gothic, MS PGothic, MS Gothic, Yu Mincho, MS PMincho, MS Mincho");
+ pref("font.name-list.monospace.ja", "MS Gothic, MS Mincho, Meiryo, Yu Gothic, Yu Mincho, MS PGothic, MS PMincho");
+-#else
+-pref("font.name-list.serif.ja", "MS PMincho, MS Mincho, MS PGothic, MS Gothic,Meiryo");
+-pref("font.name-list.sans-serif.ja", "MS PGothic, MS Gothic, MS PMincho, MS Mincho,Meiryo");
+-pref("font.name-list.monospace.ja", "MS Gothic, MS Mincho, MS PGothic, MS PMincho,Meiryo");
+-#endif
+ 
+ pref("font.name-list.serif.ko", "Batang, Gulim");
+ pref("font.name-list.sans-serif.ko", "Gulim");
+ pref("font.name-list.monospace.ko", "GulimChe");
+ pref("font.name-list.cursive.ko", "Gungsuh");
+ 
+ pref("font.name-list.serif.th", "Tahoma");
+ pref("font.name-list.sans-serif.th", "Tahoma");

+ 207 - 0
frg/253-58/mozilla-release58_428074.patch

@@ -0,0 +1,207 @@
+# HG changeset patch
+# User Masatoshi Kimura <VYV03354@nifty.ne.jp>
+# Date 1503148244 -32400
+#      Sat Aug 19 22:10:44 2017 +0900
+# Node ID b9ae810f6a04a621e35cc06bd6b357560bf2f42f
+# Parent  c219abe28508fda631242ab76727620020296988
+Bug 1392070 - Stop using the StopIteration object in Sqlite.jsm. r=mak
+
+MozReview-Commit-ID: BP3RuM5EweE
+
+diff --git a/toolkit/components/places/PlacesDBUtils.jsm b/toolkit/components/places/PlacesDBUtils.jsm
+--- a/toolkit/components/places/PlacesDBUtils.jsm
++++ b/toolkit/components/places/PlacesDBUtils.jsm
+@@ -160,19 +160,19 @@ this.PlacesDBUtils = {
+ 
+     try {
+       // Run a integrity check, but stop at the first error.
+       await PlacesUtils.withConnectionWrapper("PlacesDBUtils: check the integrity", async (db) => {
+         let row;
+         await db.execute(
+           "PRAGMA integrity_check",
+           null,
+-          r => {
++          (r, cancel) => {
+             row = r;
+-            throw StopIteration;
++            cancel();
+           });
+         if (row.getResultByIndex(0) === "ok") {
+           logs.push("The database is sane");
+         } else {
+           // We stopped due to an integrity corruption, try to fix if possible.
+           logs.push("The database is corrupt");
+           if (skipReindex) {
+             Services.prefs.setBoolPref("places.database.replaceOnStartup", true);
+diff --git a/toolkit/components/places/UnifiedComplete.js b/toolkit/components/places/UnifiedComplete.js
+--- a/toolkit/components/places/UnifiedComplete.js
++++ b/toolkit/components/places/UnifiedComplete.js
+@@ -1685,17 +1685,17 @@ Search.prototype = {
+         (this._trimmedOriginalSearchString.endsWith("/") || uri.path.length > 1)) {
+       match.icon = `page-icon:${uri.prePath}/`;
+     }
+ 
+     this._addMatch(match);
+     return true;
+   },
+ 
+-  _onResultRow(row) {
++  _onResultRow(row, cancel) {
+     let queryType = row.getResultByIndex(QUERYINDEX_QUERYTYPE);
+     let match;
+     switch (queryType) {
+       case QUERYTYPE_AUTOFILL_HOST:
+         this._result.setDefaultIndex(0);
+         match = this._processHostRow(row);
+         break;
+       case QUERYTYPE_AUTOFILL_URL:
+@@ -1705,17 +1705,17 @@ Search.prototype = {
+       case QUERYTYPE_FILTERED:
+         match = this._processRow(row);
+         break;
+     }
+     this._addMatch(match);
+     // If the search has been canceled by the user or by _addMatch, or we
+     // fetched enough results, we can stop the underlying Sqlite query.
+     if (!this.pending || this._counts[MATCHTYPE.GENERAL] == Prefs.get("maxRichResults"))
+-      throw StopIteration;
++      cancel();
+   },
+ 
+   _maybeRestyleSearchMatch(match) {
+     // Return if the URL does not represent a search result.
+     let parseResult =
+       PlacesSearchAutocompleteProvider.parseSubmissionURL(match.value);
+     if (!parseResult) {
+       return;
+diff --git a/toolkit/modules/NewTabUtils.jsm b/toolkit/modules/NewTabUtils.jsm
+--- a/toolkit/modules/NewTabUtils.jsm
++++ b/toolkit/modules/NewTabUtils.jsm
+@@ -1073,17 +1073,17 @@ var ActivityStreamProvider = {
+    *
+    * @returns {Promise} Returns a promise with the array of retrieved items
+    */
+   async executePlacesQuery(aQuery, aOptions = {}) {
+     let {columns, params} = aOptions;
+     let items = [];
+     let queryError = null;
+     let conn = await PlacesUtils.promiseDBConnection();
+-    await conn.executeCached(aQuery, params, aRow => {
++    await conn.executeCached(aQuery, params, (aRow, aCancel) => {
+       try {
+         let item = null;
+         // if columns array is given construct an object
+         if (columns && Array.isArray(columns)) {
+           item = {};
+           columns.forEach(column => {
+             item[column] = aRow.getResultByName(column);
+           });
+@@ -1092,17 +1092,17 @@ var ActivityStreamProvider = {
+           item = [];
+           for (let i = 0; i < aRow.numEntries; i++) {
+             item.push(aRow.getResultByIndex(i));
+           }
+         }
+         items.push(item);
+       } catch (e) {
+         queryError = e;
+-        throw StopIteration;
++        aCancel();
+       }
+     });
+     if (queryError) {
+       throw new Error(queryError);
+     }
+     return items;
+   }
+ };
+diff --git a/toolkit/modules/Sqlite.jsm b/toolkit/modules/Sqlite.jsm
+--- a/toolkit/modules/Sqlite.jsm
++++ b/toolkit/modules/Sqlite.jsm
+@@ -764,24 +764,21 @@ ConnectionData.prototype = Object.freeze
+           if (!onRow) {
+             rows.push(row);
+             continue;
+           }
+ 
+           handledRow = true;
+ 
+           try {
+-            onRow(row);
+-          } catch (e) {
+-            if (e instanceof StopIteration) {
++            onRow(row, () => {
+               userCancelled = true;
+               pending.cancel();
+-              break;
+-            }
+-
++            });
++          } catch (e) {
+             self._log.warn("Exception when calling onRow callback", e);
+           }
+         }
+       },
+ 
+       handleError(error) {
+         self._log.info("Error when executing SQL (" +
+                        error.result + "): " + error.message);
+@@ -1276,24 +1273,24 @@ OpenedConnection.prototype = Object.free
+    * no effect because no rows are returned from these. However, it has
+    * implications for SELECT statements.
+    *
+    * If your SELECT statement could return many rows or rows with large amounts
+    * of data, for performance reasons it is recommended to pass an `onRow`
+    * handler. Otherwise, the buffering may consume unacceptable amounts of
+    * resources.
+    *
+-   * If a `StopIteration` is thrown during execution of an `onRow` handler,
+-   * the execution of the statement is immediately cancelled. Subsequent
+-   * rows will not be processed and no more `onRow` invocations will be made.
+-   * The promise is resolved immediately.
++   * If the second parameter of an `onRow` handler is called during execution
++   * of the `onRow` handler, the execution of the statement is immediately
++   * cancelled. Subsequent rows will not be processed and no more `onRow`
++   * invocations will be made. The promise is resolved immediately.
+    *
+-   * If a non-`StopIteration` exception is thrown by the `onRow` handler, the
+-   * exception is logged and processing of subsequent rows occurs as if nothing
+-   * happened. The promise is still resolved (not rejected).
++   * If an exception is thrown by the `onRow` handler, the exception is logged
++   * and processing of subsequent rows occurs as if nothing happened. The
++   * promise is still resolved (not rejected).
+    *
+    * The return value is a promise that will be resolved when the statement
+    * has completed fully.
+    *
+    * The promise will be rejected with an `Error` instance if the statement
+    * did not finish execution fully. The `Error` may have an `errors` property.
+    * If defined, it will be an Array of objects describing individual errors.
+    * Each object has the properties `result` and `message`. `result` is a
+diff --git a/toolkit/modules/tests/xpcshell/test_sqlite.js b/toolkit/modules/tests/xpcshell/test_sqlite.js
+--- a/toolkit/modules/tests/xpcshell/test_sqlite.js
++++ b/toolkit/modules/tests/xpcshell/test_sqlite.js
+@@ -304,21 +304,21 @@ add_task(async function test_on_row_stop
+   let c = await getDummyDatabase("on_row_stop_iteration");
+ 
+   let sql = "INSERT INTO dirs (path) VALUES (?)";
+   for (let i = 0; i < 10; i++) {
+     await c.executeCached(sql, ["dir" + i]);
+   }
+ 
+   let i = 0;
+-  let hasResult = await c.execute("SELECT * FROM dirs", null, function onRow(row) {
++  let hasResult = await c.execute("SELECT * FROM dirs", null, function onRow(row, cancel) {
+     i++;
+ 
+     if (i == 5) {
+-      throw StopIteration;
++      cancel();
+     }
+   });
+ 
+   Assert.equal(hasResult, true);
+   Assert.equal(i, 5);
+ 
+   await c.close();
+ });

+ 4518 - 0
frg/253-58/mozilla-release58_428077.patch

@@ -0,0 +1,4518 @@
+# HG changeset patch
+# User Anthony Ramine <n.oxyde@gmail.com>
+# Date 1503404530 18000
+#      Tue Aug 22 07:22:10 2017 -0500
+# Node ID 5a75f509b7ca188588479d8942e1e351bec713c8
+# Parent  be8c5948d916693bd83f7b2d877c01084ff00ad5
+servo: Merge #18134 - Introduce values::animated::Animate (from servo:we-are-leaving-babylon); r=emilio
+
+Source-Repo: https://github.com/servo/servo
+Source-Revision: 8ca9542de6838fc485e9e41013d84b396ff216a9
+
+diff --git a/servo/components/style/gecko/wrapper.rs b/servo/components/style/gecko/wrapper.rs
+--- a/servo/components/style/gecko/wrapper.rs
++++ b/servo/components/style/gecko/wrapper.rs
+@@ -1405,25 +1405,25 @@ impl<'le> TElement for GeckoElement<'le>
+ 
+         // Check if we have to cancel the running transition because this is not a matching
+         // transition-property value.
+         transitions_to_keep.map_or(false, |set| {
+             existing_transitions.keys().any(|property| !set.contains(property))
+         })
+     }
+ 
+-    fn needs_transitions_update_per_property(&self,
+-                                             property: &TransitionProperty,
+-                                             combined_duration: f32,
+-                                             before_change_style: &ComputedValues,
+-                                             after_change_style: &ComputedValues,
+-                                             existing_transitions: &HashMap<TransitionProperty,
+-                                                                            Arc<AnimationValue>>)
+-                                             -> bool {
+-        use properties::animated_properties::Animatable;
++    fn needs_transitions_update_per_property(
++        &self,
++        property: &TransitionProperty,
++        combined_duration: f32,
++        before_change_style: &ComputedValues,
++        after_change_style: &ComputedValues,
++        existing_transitions: &HashMap<TransitionProperty, Arc<AnimationValue>>,
++    ) -> bool {
++        use values::animated::{Animate, Procedure};
+ 
+         // |property| should be an animatable longhand
+         let animatable_longhand = AnimatableLonghand::from_transition_property(property).unwrap();
+ 
+         if existing_transitions.contains_key(property) {
+             // If there is an existing transition, update only if the end value differs.
+             // If the end value has not changed, we should leave the currently running
+             // transition as-is since we don't want to interrupt its timing function.
+@@ -1435,17 +1435,17 @@ impl<'le> TElement for GeckoElement<'le>
+ 
+         let from = AnimationValue::from_computed_values(&animatable_longhand,
+                                                         before_change_style);
+         let to = AnimationValue::from_computed_values(&animatable_longhand,
+                                                       after_change_style);
+ 
+         combined_duration > 0.0f32 &&
+         from != to &&
+-        from.interpolate(&to, 0.5).is_ok()
++        from.animate(&to, Procedure::Interpolate { progress: 0.5 }).is_ok()
+     }
+ 
+     #[inline]
+     fn lang_attr(&self) -> Option<AttrValue> {
+         let ptr = unsafe { bindings::Gecko_LangValue(self.0) };
+         if ptr.is_null() {
+             None
+         } else {
+diff --git a/servo/components/style/macros.rs b/servo/components/style/macros.rs
+--- a/servo/components/style/macros.rs
++++ b/servo/components/style/macros.rs
+@@ -82,20 +82,23 @@ macro_rules! add_impls_for_keyword_enum 
+ 
+ macro_rules! define_keyword_type {
+     ($name: ident, $css: expr) => {
+         #[allow(missing_docs)]
+         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+         #[derive(Clone, ComputeSquaredDistance, Copy, PartialEq, ToCss)]
+         pub struct $name;
+ 
+-        impl $crate::properties::animated_properties::Animatable for $name {
++        impl $crate::values::animated::Animate for $name {
+             #[inline]
+-            fn add_weighted(&self, _other: &Self, _self_progress: f64, _other_progress: f64)
+-                -> Result<Self, ()> {
++            fn animate(
++                &self,
++                _other: &Self,
++                _procedure: $crate::values::animated::Procedure,
++            ) -> Result<Self, ()> {
+                 Ok($name)
+             }
+         }
+ 
+         impl fmt::Debug for $name {
+             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                 write!(f, $css)
+             }
+diff --git a/servo/components/style/properties/data.py b/servo/components/style/properties/data.py
+--- a/servo/components/style/properties/data.py
++++ b/servo/components/style/properties/data.py
+@@ -206,17 +206,17 @@ class Longhand(object):
+         self.is_animatable_with_computed_value = animation_value_type == "ComputedValue" \
+             or animation_value_type == "discrete"
+         if self.logical:
+             # Logical properties will be animatable (i.e. the animation type is
+             # discrete). For now, it is still non-animatable.
+             self.animatable = False
+             self.transitionable = False
+             self.animation_type = None
+-        # NB: Animatable implies clone because a property animation requires a
++        # NB: Animate implies clone because a property animation requires a
+         # copy of the computed value.
+         #
+         # See components/style/helpers/animated_properties.mako.rs.
+         self.need_clone = need_clone or self.animatable
+ 
+ 
+ class Shorthand(object):
+     def __init__(self, name, sub_properties, spec=None, experimental=False, internal=False,
+diff --git a/servo/components/style/properties/helpers.mako.rs b/servo/components/style/properties/helpers.mako.rs
+--- a/servo/components/style/properties/helpers.mako.rs
++++ b/servo/components/style/properties/helpers.mako.rs
+@@ -128,27 +128,22 @@
+                 % if allow_empty and allow_empty != "NotInitial":
+                 pub Vec<single_value::T>,
+                 % else:
+                 pub SmallVec<[single_value::T; 1]>,
+                 % endif
+             );
+ 
+             % if need_animatable or animation_value_type == "ComputedValue":
+-                use properties::animated_properties::Animatable;
+-                use values::animated::ToAnimatedZero;
++                use values::animated::{Animate, Procedure, ToAnimatedZero};
+ 
+-                impl Animatable for T {
+-                    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
+-                        -> Result<Self, ()> {
+-                        self.0.add_weighted(&other.0, self_portion, other_portion).map(T)
+-                    }
+-
+-                    fn add(&self, other: &Self) -> Result<Self, ()> {
+-                        self.0.add(&other.0).map(T)
++                impl Animate for T {
++                    #[inline]
++                    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++                        Ok(T(self.0.animate(&other.0, procedure)?))
+                     }
+                 }
+ 
+                 impl ToAnimatedZero for T {
+                     #[inline]
+                     fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+                 }
+             % endif
+diff --git a/servo/components/style/properties/helpers/animated_properties.mako.rs b/servo/components/style/properties/helpers/animated_properties.mako.rs
+--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
++++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
+@@ -3,46 +3,48 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ <%namespace name="helpers" file="/helpers.mako.rs" />
+ 
+ <% from data import to_idl_name, SYSTEM_FONT_LONGHANDS %>
+ 
+ use app_units::Au;
+ use cssparser::Parser;
+-use euclid::{Point2D, Point3D, Size2D};
++use euclid::Point3D;
+ #[cfg(feature = "gecko")] use gecko_bindings::bindings::RawServoAnimationValueMap;
+ #[cfg(feature = "gecko")] use gecko_bindings::structs::RawGeckoGfxMatrix4x4;
+ #[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID;
+ #[cfg(feature = "gecko")] use gecko_bindings::sugar::ownership::{HasFFI, HasSimpleFFI};
+ #[cfg(feature = "gecko")] use gecko_string_cache::Atom;
++use itertools::{EitherOrBoth, Itertools};
+ use properties::{CSSWideKeyword, PropertyDeclaration};
+ use properties::longhands;
+ use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
+ use properties::longhands::border_spacing::computed_value::T as BorderSpacing;
+ use properties::longhands::font_weight::computed_value::T as FontWeight;
+ use properties::longhands::font_stretch::computed_value::T as FontStretch;
+ use properties::longhands::line_height::computed_value::T as LineHeight;
+ use properties::longhands::transform::computed_value::ComputedMatrix;
+ use properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
+ use properties::longhands::transform::computed_value::T as TransformList;
+ use properties::longhands::vertical_align::computed_value::T as VerticalAlign;
+ use properties::longhands::visibility::computed_value::T as Visibility;
+ #[cfg(feature = "gecko")] use properties::{PropertyId, PropertyDeclarationId, LonghandId};
+ #[cfg(feature = "gecko")] use properties::{ShorthandId};
+ use selectors::parser::SelectorParseError;
+ use smallvec::SmallVec;
++use std::borrow::Cow;
+ use std::cmp;
+ #[cfg(feature = "gecko")] use fnv::FnvHashMap;
+ use style_traits::ParseError;
+ use super::ComputedValues;
+ #[cfg(feature = "gecko")]
+ use values::Auto;
+ use values::{CSSFloat, CustomIdent, Either};
+-use values::animated::{ToAnimatedValue, ToAnimatedZero};
++use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
+ use values::animated::color::{Color as AnimatedColor, RGBA as AnimatedRGBA};
+ use values::animated::effects::BoxShadowList as AnimatedBoxShadowList;
+ use values::animated::effects::Filter as AnimatedFilter;
+ use values::animated::effects::FilterList as AnimatedFilterList;
+ use values::animated::effects::TextShadowList as AnimatedTextShadowList;
+ use values::computed::{Angle, BorderCornerRadius, CalcLengthOrPercentage};
+ use values::computed::{ClipRect, Context, ComputedUrl, ComputedValueAsSpecified};
+ use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
+@@ -53,49 +55,18 @@ use values::computed::length::{NonNegati
+ use values::computed::length::NonNegativeLengthOrPercentage;
+ use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ use values::generics::{GreaterThanOrEqualToOne, NonNegative};
+ use values::generics::effects::Filter;
+ use values::generics::position as generic_position;
+ use values::generics::svg::{SVGLength,  SvgLengthOrPercentageOrNumber, SVGPaint};
+ use values::generics::svg::{SVGPaintKind, SVGStrokeDashArray, SVGOpacity};
+ 
+-/// A trait used to implement various procedures used during animation.
+-pub trait Animatable: Sized {
+-    /// Performs a weighted sum of this value and |other|. This is used for
+-    /// interpolation and addition of animation values.
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
+-        -> Result<Self, ()>;
+-
+-    /// [Interpolates][interpolation] a value with another for a given property.
+-    ///
+-    /// [interpolation]: https://w3c.github.io/web-animations/#animation-interpolation
+-    fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
+-        self.add_weighted(other, 1.0 - progress, progress)
+-    }
+-
+-    /// Returns the [sum][animation-addition] of this value and |other|.
+-    ///
+-    /// [animation-addition]: https://w3c.github.io/web-animations/#animation-addition
+-    fn add(&self, other: &Self) -> Result<Self, ()> {
+-        self.add_weighted(other, 1.0, 1.0)
+-    }
+-
+-    /// [Accumulates][animation-accumulation] this value onto itself (|count| - 1) times then
+-    /// accumulates |other| onto the result.
+-    /// If |count| is zero, the result will be |other|.
+-    ///
+-    /// [animation-accumulation]: https://w3c.github.io/web-animations/#animation-accumulation
+-    fn accumulate(&self, other: &Self, count: u64) -> Result<Self, ()> {
+-        self.add_weighted(other, count as f64, 1.0)
+-    }
+-}
+-
+ /// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list
+-pub trait RepeatableListAnimatable: Animatable {}
++pub trait RepeatableListAnimatable: Animate {}
+ 
+ /// A longhand property whose animation type is not "none".
+ ///
+ /// NOTE: This includes the 'display' property since it is animatable from SMIL even though it is
+ /// not animatable from CSS animations or Web Animations. CSS transitions also does not allow
+ /// animating 'display', but for CSS transitions we have the separate TransitionProperty type.
+ #[derive(Clone, Debug, PartialEq, Eq, Hash)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+@@ -444,17 +415,17 @@ impl AnimatedProperty {
+         match *self {
+             % for prop in data.longhands:
+                 % if prop.animatable:
+                     AnimatedProperty::${prop.camel_case}(ref from, ref to) => {
+                         // https://w3c.github.io/web-animations/#discrete-animation-type
+                         % if prop.animation_value_type == "discrete":
+                             let value = if progress < 0.5 { from.clone() } else { to.clone() };
+                         % else:
+-                            let value = match from.interpolate(to, progress) {
++                            let value = match from.animate(to, Procedure::Interpolate { progress }) {
+                                 Ok(value) => value,
+                                 Err(()) => return,
+                             };
+                         % endif
+                         % if not prop.is_animatable_with_computed_value:
+                             let value: longhands::${prop.ident}::computed_value::T =
+                                 ToAnimatedValue::from_animated_value(value);
+                         % endif
+@@ -655,88 +626,48 @@ impl AnimationValue {
+                         )
+                     }
+                 % endif
+             % endfor
+         }
+     }
+ }
+ 
+-impl Animatable for AnimationValue {
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
+-        -> Result<Self, ()> {
+-        match (self, other) {
+-            % for prop in data.longhands:
+-                % if prop.animatable:
+-                    (&AnimationValue::${prop.camel_case}(ref from),
+-                     &AnimationValue::${prop.camel_case}(ref to)) => {
+-                        % if prop.animation_value_type == "discrete":
+-                            if self_portion > other_portion {
+-                                Ok(AnimationValue::${prop.camel_case}(from.clone()))
+-                            } else {
+-                                Ok(AnimationValue::${prop.camel_case}(to.clone()))
+-                            }
+-                        % else:
+-                            from.add_weighted(to, self_portion, other_portion)
+-                                .map(AnimationValue::${prop.camel_case})
+-                        % endif
+-                    }
+-                % endif
+-            % endfor
+-            _ => {
+-                panic!("Expected weighted addition of computed values of the same \
+-                        property, got: {:?}, {:?}", self, other);
+-            }
+-        }
+-    }
+-
+-    fn add(&self, other: &Self) -> Result<Self, ()> {
++impl Animate for AnimationValue {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             % for prop in data.longhands:
+-                % if prop.animatable:
+-                    % if prop.animation_value_type == "discrete":
+-                        (&AnimationValue::${prop.camel_case}(_),
+-                         &AnimationValue::${prop.camel_case}(_)) => {
+-                            Err(())
+-                        }
+-                    % else:
+-                        (&AnimationValue::${prop.camel_case}(ref from),
+-                         &AnimationValue::${prop.camel_case}(ref to)) => {
+-                            from.add(to).map(AnimationValue::${prop.camel_case})
+-                        }
+-                    % endif
+-                % endif
++            % if prop.animatable:
++            % if prop.animation_value_type != "discrete":
++            (
++                &AnimationValue::${prop.camel_case}(ref this),
++                &AnimationValue::${prop.camel_case}(ref other),
++            ) => {
++                Ok(AnimationValue::${prop.camel_case}(
++                    this.animate(other, procedure)?,
++                ))
++            },
++            % else:
++            (
++                &AnimationValue::${prop.camel_case}(ref this),
++                &AnimationValue::${prop.camel_case}(ref other),
++            ) => {
++                if let Procedure::Interpolate { progress } = procedure {
++                    Ok(AnimationValue::${prop.camel_case}(
++                        if progress < 0.5 { this.clone() } else { other.clone() },
++                    ))
++                } else {
++                    Err(())
++                }
++            },
++            % endif
++            % endif
+             % endfor
+             _ => {
+-                panic!("Expected addition of computed values of the same \
+-                        property, got: {:?}, {:?}", self, other);
+-            }
+-        }
+-    }
+-
+-    fn accumulate(&self, other: &Self, count: u64) -> Result<Self, ()> {
+-        match (self, other) {
+-            % for prop in data.longhands:
+-                % if prop.animatable:
+-                    % if prop.animation_value_type == "discrete":
+-                        (&AnimationValue::${prop.camel_case}(_),
+-                         &AnimationValue::${prop.camel_case}(_)) => {
+-                            Err(())
+-                        }
+-                    % else:
+-                        (&AnimationValue::${prop.camel_case}(ref from),
+-                         &AnimationValue::${prop.camel_case}(ref to)) => {
+-                            from.accumulate(to, count).map(AnimationValue::${prop.camel_case})
+-                        }
+-                    % endif
+-                % endif
+-            % endfor
+-            _ => {
+-                panic!("Expected accumulation of computed values of the same \
+-                        property, got: {:?}, {:?}", self, other);
++                panic!("Unexpected AnimationValue::animate call, got: {:?}, {:?}", self, other);
+             }
+         }
+     }
+ }
+ 
+ impl ComputeSquaredDistance for AnimationValue {
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+         match (self, other) {
+@@ -782,27 +713,29 @@ impl ToAnimatedZero for AnimationValue {
+ 
+ impl RepeatableListAnimatable for LengthOrPercentage {}
+ impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {}
+ impl RepeatableListAnimatable for Either<NonNegativeNumber, NonNegativeLengthOrPercentage> {}
+ impl RepeatableListAnimatable for SvgLengthOrPercentageOrNumber<NonNegativeLengthOrPercentage, NonNegativeNumber> {}
+ 
+ macro_rules! repeated_vec_impl {
+     ($($ty:ty),*) => {
+-        $(impl<T: RepeatableListAnimatable> Animatable for $ty {
+-            fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
+-                -> Result<Self, ()> {
++        $(impl<T> Animate for $ty
++        where
++            T: RepeatableListAnimatable,
++        {
++            fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+                 // If the length of either list is zero, the least common multiple is undefined.
+                 if self.is_empty() || other.is_empty() {
+                     return Err(());
+                 }
+                 use num_integer::lcm;
+                 let len = lcm(self.len(), other.len());
+-                self.iter().cycle().zip(other.iter().cycle()).take(len).map(|(me, you)| {
+-                    me.add_weighted(you, self_portion, other_portion)
++                self.iter().cycle().zip(other.iter().cycle()).take(len).map(|(this, other)| {
++                    this.animate(other, procedure)
+                 }).collect()
+             }
+         }
+ 
+         impl<T> ComputeSquaredDistance for $ty
+         where
+             T: ComputeSquaredDistance + RepeatableListAnimatable,
+         {
+@@ -818,73 +751,27 @@ macro_rules! repeated_vec_impl {
+                 }).sum()
+             }
+         })*
+     };
+ }
+ 
+ repeated_vec_impl!(SmallVec<[T; 1]>, Vec<T>);
+ 
+-/// https://drafts.csswg.org/css-transitions/#animtype-number
+-impl Animatable for Au {
+-    #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        Ok(Au((self.0 as f64 * self_portion + other.0 as f64 * other_portion).round() as i32))
+-    }
+-}
+-
+-impl <T> Animatable for Option<T>
+-    where T: Animatable,
+-{
+-    #[inline]
+-    fn add_weighted(&self, other: &Option<T>, self_portion: f64, other_portion: f64) -> Result<Option<T>, ()> {
+-        match (self, other) {
+-            (&Some(ref this), &Some(ref other)) => {
+-                Ok(this.add_weighted(other, self_portion, other_portion).ok())
+-            }
+-            (&None, &None) => Ok(None),
+-            _ => Err(()),
+-        }
+-    }
+-}
+-
+-/// https://drafts.csswg.org/css-transitions/#animtype-number
+-impl Animatable for f32 {
++/// https://drafts.csswg.org/css-transitions/#animtype-visibility
++impl Animate for Visibility {
+     #[inline]
+-    fn add_weighted(&self, other: &f32, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        Ok((*self as f64 * self_portion + *other as f64 * other_portion) as f32)
+-    }
+-}
+-
+-/// https://drafts.csswg.org/css-transitions/#animtype-number
+-impl Animatable for f64 {
+-    #[inline]
+-    fn add_weighted(&self, other: &f64, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        Ok(*self * self_portion + *other * other_portion)
+-    }
+-}
+-
+-/// https://drafts.csswg.org/css-transitions/#animtype-integer
+-impl Animatable for i32 {
+-    #[inline]
+-    fn add_weighted(&self, other: &i32, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        Ok((*self as f64 * self_portion + *other as f64 * other_portion + 0.5).floor() as i32)
+-    }
+-}
+-
+-/// https://drafts.csswg.org/css-transitions/#animtype-visibility
+-impl Animatable for Visibility {
+-    #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        let (this_weight, other_weight) = procedure.weights();
+         match (*self, *other) {
+             (Visibility::visible, _) => {
+-                Ok(if self_portion > 0.0 { *self } else { *other })
++                Ok(if this_weight > 0.0 { *self } else { *other })
+             },
+             (_, Visibility::visible) => {
+-                Ok(if other_portion > 0.0 { *other } else { *self })
++                Ok(if other_weight > 0.0 { *other } else { *self })
+             },
+             _ => Err(()),
+         }
+     }
+ }
+ 
+ impl ComputeSquaredDistance for Visibility {
+     #[inline]
+@@ -895,47 +782,29 @@ impl ComputeSquaredDistance for Visibili
+ 
+ impl ToAnimatedZero for Visibility {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         Err(())
+     }
+ }
+ 
+-impl<T: Animatable + Copy> Animatable for Size2D<T> {
+-    #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        let width = self.width.add_weighted(&other.width, self_portion, other_portion)?;
+-        let height = self.height.add_weighted(&other.height, self_portion, other_portion)?;
+-
+-        Ok(Size2D::new(width, height))
+-    }
+-}
+-
+-impl<T: Animatable + Copy> Animatable for Point2D<T> {
++/// https://drafts.csswg.org/css-transitions/#animtype-length
++impl Animate for VerticalAlign {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        let x = self.x.add_weighted(&other.x, self_portion, other_portion)?;
+-        let y = self.y.add_weighted(&other.y, self_portion, other_portion)?;
+-
+-        Ok(Point2D::new(x, y))
+-    }
+-}
+-
+-/// https://drafts.csswg.org/css-transitions/#animtype-length
+-impl Animatable for VerticalAlign {
+-    #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        match (*self, *other) {
+-            (VerticalAlign::LengthOrPercentage(ref this),
+-             VerticalAlign::LengthOrPercentage(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion).map(|value| {
+-                    VerticalAlign::LengthOrPercentage(value)
+-                })
+-            }
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        match (self, other) {
++            (
++                &VerticalAlign::LengthOrPercentage(ref this),
++                &VerticalAlign::LengthOrPercentage(ref other),
++            ) => {
++                Ok(VerticalAlign::LengthOrPercentage(
++                    this.animate(other, procedure)?
++                ))
++            },
+             _ => Err(()),
+         }
+     }
+ }
+ 
+ impl ComputeSquaredDistance for VerticalAlign {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+@@ -953,112 +822,114 @@ impl ComputeSquaredDistance for Vertical
+ }
+ 
+ impl ToAnimatedZero for VerticalAlign {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+ }
+ 
+ /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+-impl Animatable for CalcLengthOrPercentage {
++impl Animate for CalcLengthOrPercentage {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        fn add_weighted_half<T>(this: Option<T>,
+-                                other: Option<T>,
+-                                self_portion: f64,
+-                                other_portion: f64)
+-                                -> Result<Option<T>, ()>
+-            where T: Default + Animatable,
+-        {
+-            match (this, other) {
+-                (None, None) => Ok(None),
+-                (this, other) => {
+-                    let this = this.unwrap_or(T::default());
+-                    let other = other.unwrap_or(T::default());
+-                    this.add_weighted(&other, self_portion, other_portion).map(Some)
+-                }
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        let animate_percentage_half = |this: Option<Percentage>, other: Option<Percentage>| {
++            if this.is_none() && other.is_none() {
++                return Ok(None);
+             }
+-        }
++            let this = this.unwrap_or_default();
++            let other = other.unwrap_or_default();
++            Ok(Some(this.animate(&other, procedure)?))
++        };
+ 
+-        let length = self.unclamped_length().add_weighted(&other.unclamped_length(), self_portion, other_portion)?;
+-        let percentage = add_weighted_half(self.percentage, other.percentage, self_portion, other_portion)?;
++        let length = self.unclamped_length().animate(&other.unclamped_length(), procedure)?;
++        let percentage = animate_percentage_half(self.percentage, other.percentage)?;
+         Ok(CalcLengthOrPercentage::with_clamping_mode(length, percentage, self.clamping_mode))
+     }
+ }
+ 
+ /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+-impl Animatable for LengthOrPercentage {
++impl Animate for LengthOrPercentage {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        match (*self, *other) {
+-            (LengthOrPercentage::Length(ref this),
+-             LengthOrPercentage::Length(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion)
+-                    .map(LengthOrPercentage::Length)
+-            }
+-            (LengthOrPercentage::Percentage(ref this),
+-             LengthOrPercentage::Percentage(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion)
+-                    .map(LengthOrPercentage::Percentage)
+-            }
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        match (self, other) {
++            (
++                &LengthOrPercentage::Length(ref this),
++                &LengthOrPercentage::Length(ref other),
++            ) => {
++                Ok(LengthOrPercentage::Length(this.animate(other, procedure)?))
++            },
++            (
++                &LengthOrPercentage::Percentage(ref this),
++                &LengthOrPercentage::Percentage(ref other),
++            ) => {
++                Ok(LengthOrPercentage::Percentage(this.animate(other, procedure)?))
++            },
+             (this, other) => {
+                 // Special handling for zero values since these should not require calc().
+                 if this.is_definitely_zero() {
+-                    return other.add_weighted(&other, 0., other_portion)
+-                } else if other.is_definitely_zero() {
+-                    return this.add_weighted(self, self_portion, 0.)
++                    return other.to_animated_zero()?.animate(other, procedure);
++                }
++                if other.is_definitely_zero() {
++                    return this.animate(&this.to_animated_zero()?, procedure);
+                 }
+ 
+-                let this: CalcLengthOrPercentage = From::from(this);
+-                let other: CalcLengthOrPercentage = From::from(other);
+-                this.add_weighted(&other, self_portion, other_portion)
+-                    .map(LengthOrPercentage::Calc)
++                let this = CalcLengthOrPercentage::from(*this);
++                let other = CalcLengthOrPercentage::from(*other);
++                Ok(LengthOrPercentage::Calc(this.animate(&other, procedure)?))
+             }
+         }
+     }
+ }
+ 
+ impl ToAnimatedZero for LengthOrPercentage {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+-        match self {
+-            &LengthOrPercentage::Length(_) | &LengthOrPercentage::Calc(_) =>
+-                Ok(LengthOrPercentage::zero()),
+-            &LengthOrPercentage::Percentage(_) =>
+-                Ok(LengthOrPercentage::Percentage(Percentage::zero())),
+-        }
++         match *self {
++             LengthOrPercentage::Length(ref length) => {
++                 Ok(LengthOrPercentage::Length(length.to_animated_zero()?))
++             },
++             LengthOrPercentage::Percentage(ref percentage) => {
++                 Ok(LengthOrPercentage::Percentage(percentage.to_animated_zero()?))
++             },
++             LengthOrPercentage::Calc(ref calc) => {
++                 Ok(LengthOrPercentage::Calc(calc.to_animated_zero()?))
++             },
++         }
+     }
+ }
+ 
+ /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+-impl Animatable for LengthOrPercentageOrAuto {
++impl Animate for LengthOrPercentageOrAuto {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        match (*self, *other) {
+-            (LengthOrPercentageOrAuto::Length(ref this),
+-             LengthOrPercentageOrAuto::Length(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion)
+-                    .map(LengthOrPercentageOrAuto::Length)
+-            }
+-            (LengthOrPercentageOrAuto::Percentage(ref this),
+-             LengthOrPercentageOrAuto::Percentage(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion)
+-                    .map(LengthOrPercentageOrAuto::Percentage)
+-            }
+-            (LengthOrPercentageOrAuto::Auto, LengthOrPercentageOrAuto::Auto) => {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        match (self, other) {
++            (
++                &LengthOrPercentageOrAuto::Length(ref this),
++                &LengthOrPercentageOrAuto::Length(ref other),
++            ) => {
++                Ok(LengthOrPercentageOrAuto::Length(this.animate(other, procedure)?))
++            },
++            (
++                &LengthOrPercentageOrAuto::Percentage(ref this),
++                &LengthOrPercentageOrAuto::Percentage(ref other),
++            ) => {
++                Ok(LengthOrPercentageOrAuto::Percentage(
++                    this.animate(other, procedure)?,
++                ))
++            },
++            (&LengthOrPercentageOrAuto::Auto, &LengthOrPercentageOrAuto::Auto) => {
+                 Ok(LengthOrPercentageOrAuto::Auto)
+-            }
++            },
+             (this, other) => {
+-                let this: Option<CalcLengthOrPercentage> = From::from(this);
+-                let other: Option<CalcLengthOrPercentage> = From::from(other);
+-                match this.add_weighted(&other, self_portion, other_portion) {
+-                    Ok(Some(result)) => Ok(LengthOrPercentageOrAuto::Calc(result)),
+-                    _ => Err(()),
+-                }
+-            }
++                let this: Option<CalcLengthOrPercentage> = From::from(*this);
++                let other: Option<CalcLengthOrPercentage> = From::from(*other);
++                Ok(LengthOrPercentageOrAuto::Calc(
++                    this.animate(&other, procedure)?.ok_or(())?,
++                ))
++            },
+         }
+     }
+ }
+ 
+ impl ToAnimatedZero for LengthOrPercentageOrAuto {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         match *self {
+@@ -1068,40 +939,43 @@ impl ToAnimatedZero for LengthOrPercenta
+                 Ok(LengthOrPercentageOrAuto::Length(Au(0)))
+             },
+             LengthOrPercentageOrAuto::Auto => Err(()),
+         }
+     }
+ }
+ 
+ /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+-impl Animatable for LengthOrPercentageOrNone {
++impl Animate for LengthOrPercentageOrNone {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        match (*self, *other) {
+-            (LengthOrPercentageOrNone::Length(ref this),
+-             LengthOrPercentageOrNone::Length(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion)
+-                    .map(LengthOrPercentageOrNone::Length)
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        match (self, other) {
++            (
++                &LengthOrPercentageOrNone::Length(ref this),
++                &LengthOrPercentageOrNone::Length(ref other),
++            ) => {
++                Ok(LengthOrPercentageOrNone::Length(this.animate(other, procedure)?))
++            },
++            (
++                &LengthOrPercentageOrNone::Percentage(ref this),
++                &LengthOrPercentageOrNone::Percentage(ref other),
++            ) => {
++                Ok(LengthOrPercentageOrNone::Percentage(
++                    this.animate(other, procedure)?,
++                ))
+             }
+-            (LengthOrPercentageOrNone::Percentage(ref this),
+-             LengthOrPercentageOrNone::Percentage(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion)
+-                    .map(LengthOrPercentageOrNone::Percentage)
+-            }
+-            (LengthOrPercentageOrNone::None, LengthOrPercentageOrNone::None) => {
++            (&LengthOrPercentageOrNone::None, &LengthOrPercentageOrNone::None) => {
+                 Ok(LengthOrPercentageOrNone::None)
+-            }
++            },
+             (this, other) => {
+-                let this = <Option<CalcLengthOrPercentage>>::from(this);
+-                let other = <Option<CalcLengthOrPercentage>>::from(other);
+-                match this.add_weighted(&other, self_portion, other_portion) {
+-                    Ok(Some(result)) => Ok(LengthOrPercentageOrNone::Calc(result)),
+-                    _ => Err(()),
+-                }
++                let this = <Option<CalcLengthOrPercentage>>::from(*this);
++                let other = <Option<CalcLengthOrPercentage>>::from(*other);
++                Ok(LengthOrPercentageOrNone::Calc(
++                    this.animate(&other, procedure)?.ok_or(())?,
++                ))
+             },
+         }
+     }
+ }
+ 
+ impl ToAnimatedZero for LengthOrPercentageOrNone {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+@@ -1112,24 +986,27 @@ impl ToAnimatedZero for LengthOrPercenta
+                 Ok(LengthOrPercentageOrNone::Length(Au(0)))
+             },
+             LengthOrPercentageOrNone::None => Err(()),
+         }
+     }
+ }
+ 
+ /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+-impl Animatable for MozLength {
++impl Animate for MozLength {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        match (*self, *other) {
+-            (MozLength::LengthOrPercentageOrAuto(ref this),
+-             MozLength::LengthOrPercentageOrAuto(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion)
+-                    .map(MozLength::LengthOrPercentageOrAuto)
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        match (self, other) {
++            (
++                &MozLength::LengthOrPercentageOrAuto(ref this),
++                &MozLength::LengthOrPercentageOrAuto(ref other),
++            ) => {
++                Ok(MozLength::LengthOrPercentageOrAuto(
++                    this.animate(other, procedure)?,
++                ))
+             }
+             _ => Err(()),
+         }
+     }
+ }
+ 
+ impl ToAnimatedZero for MozLength {
+     #[inline]
+@@ -1139,67 +1016,69 @@ impl ToAnimatedZero for MozLength {
+                 Ok(MozLength::LengthOrPercentageOrAuto(length.to_animated_zero()?))
+             },
+             _ => Err(())
+         }
+     }
+ }
+ 
+ /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+-impl Animatable for MaxLength {
++impl Animate for MaxLength {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        match (*self, *other) {
+-            (MaxLength::LengthOrPercentageOrNone(ref this),
+-             MaxLength::LengthOrPercentageOrNone(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion)
+-                    .map(MaxLength::LengthOrPercentageOrNone)
+-            }
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        match (self, other) {
++            (
++                &MaxLength::LengthOrPercentageOrNone(ref this),
++                &MaxLength::LengthOrPercentageOrNone(ref other),
++            ) => {
++                Ok(MaxLength::LengthOrPercentageOrNone(
++                    this.animate(other, procedure)?,
++                ))
++            },
+             _ => Err(()),
+         }
+     }
+ }
+ 
+ impl ToAnimatedZero for MaxLength {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+ }
+ 
+ /// http://dev.w3.org/csswg/css-transitions/#animtype-font-weight
+-impl Animatable for FontWeight {
++impl Animate for FontWeight {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         let a = self.0 as f64;
+         let b = other.0 as f64;
+         const NORMAL: f64 = 400.;
+-        let weight = (a - NORMAL) * self_portion + (b - NORMAL) * other_portion + NORMAL;
++        let (this_weight, other_weight) = procedure.weights();
++        let weight = (a - NORMAL) * this_weight + (b - NORMAL) * other_weight + NORMAL;
+         let weight = (weight.max(100.).min(900.) / 100.).round() * 100.;
+         Ok(FontWeight(weight as u16))
+     }
+ }
+ 
+ impl ToAnimatedZero for FontWeight {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         Ok(FontWeight::normal())
+     }
+ }
+ 
+ /// https://drafts.csswg.org/css-fonts/#font-stretch-prop
+-impl Animatable for FontStretch {
++impl Animate for FontStretch {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
+-        -> Result<Self, ()>
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>
+     {
+         let from = f64::from(*self);
+         let to = f64::from(*other);
+-        // FIXME: When `const fn` is available in release rust, make |normal|, below, const.
+         let normal = f64::from(FontStretch::normal);
+-        let result = (from - normal) * self_portion + (to - normal) * other_portion + normal;
+-
++        let (this_weight, other_weight) = procedure.weights();
++        let result = (from - normal) * this_weight + (to - normal) * other_weight + normal;
+         Ok(result.into())
+     }
+ }
+ 
+ impl ComputeSquaredDistance for FontStretch {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+         f64::from(*self).compute_squared_distance(&(*other).into())
+@@ -1236,23 +1115,26 @@ impl Into<FontStretch> for f64 {
+         let index = (self + 0.5).floor().min(9.0).max(1.0);
+         static FONT_STRETCH_ENUM_MAP: [FontStretch; 9] =
+             [ ultra_condensed, extra_condensed, condensed, semi_condensed, normal,
+               semi_expanded, expanded, extra_expanded, ultra_expanded ];
+         FONT_STRETCH_ENUM_MAP[(index - 1.0) as usize]
+     }
+ }
+ 
+-/// https://drafts.csswg.org/css-transitions/#animtype-simple-list
+-impl<H: Animatable, V: Animatable> Animatable for generic_position::Position<H, V> {
++impl<H, V> Animate for generic_position::Position<H, V>
++where
++    H: Animate,
++    V: Animate,
++{
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(generic_position::Position {
+-            horizontal: self.horizontal.add_weighted(&other.horizontal, self_portion, other_portion)?,
+-            vertical: self.vertical.add_weighted(&other.vertical, self_portion, other_portion)?,
++            horizontal: self.horizontal.animate(&other.horizontal, procedure)?,
++            vertical: self.vertical.animate(&other.vertical, procedure)?,
+         })
+     }
+ }
+ 
+ impl<H, V> ToAnimatedZero for generic_position::Position<H, V>
+ where
+     H: ToAnimatedZero,
+     V: ToAnimatedZero,
+@@ -1265,218 +1147,172 @@ where
+         })
+     }
+ }
+ 
+ impl<H, V> RepeatableListAnimatable for generic_position::Position<H, V>
+     where H: RepeatableListAnimatable, V: RepeatableListAnimatable {}
+ 
+ /// https://drafts.csswg.org/css-transitions/#animtype-rect
+-impl Animatable for ClipRect {
++impl Animate for ClipRect {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
+-        -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(ClipRect {
+-            top: self.top.add_weighted(&other.top, self_portion, other_portion)?,
+-            right: self.right.add_weighted(&other.right, self_portion, other_portion)?,
+-            bottom: self.bottom.add_weighted(&other.bottom, self_portion, other_portion)?,
+-            left: self.left.add_weighted(&other.left, self_portion, other_portion)?,
++            top: self.top.animate(&other.top, procedure)?,
++            right: self.right.animate(&other.right, procedure)?,
++            bottom: self.bottom.animate(&other.bottom, procedure)?,
++            left: self.left.animate(&other.left, procedure)?,
+         })
+     }
+ }
+ 
+ impl ToAnimatedZero for ClipRect {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+ }
+ 
+-/// Check if it's possible to do a direct numerical interpolation
+-/// between these two transform lists.
+-/// http://dev.w3.org/csswg/css-transforms/#transform-transform-animation
+-fn can_interpolate_list(from_list: &[TransformOperation],
+-                        to_list: &[TransformOperation]) -> bool {
+-    // Lists must be equal length
+-    if from_list.len() != to_list.len() {
+-        return false;
+-    }
+-
+-    // Each transform operation must match primitive type in other list
+-    for (from, to) in from_list.iter().zip(to_list) {
+-        match (from, to) {
+-            (&TransformOperation::Matrix(..), &TransformOperation::Matrix(..)) |
+-            (&TransformOperation::Skew(..), &TransformOperation::Skew(..)) |
+-            (&TransformOperation::Translate(..), &TransformOperation::Translate(..)) |
+-            (&TransformOperation::Scale(..), &TransformOperation::Scale(..)) |
+-            (&TransformOperation::Rotate(..), &TransformOperation::Rotate(..)) |
+-            (&TransformOperation::Perspective(..), &TransformOperation::Perspective(..)) => {}
+-            _ => {
+-                return false;
+-            }
+-        }
+-    }
+-
+-    true
+-}
+-
+ /// Build an equivalent 'identity transform function list' based
+ /// on an existing transform list.
+ /// http://dev.w3.org/csswg/css-transforms/#none-transform-animation
+-fn build_identity_transform_list(list: &[TransformOperation]) -> Vec<TransformOperation> {
+-    let mut result = vec!();
+-
+-    for operation in list {
+-        match *operation {
++impl ToAnimatedZero for TransformOperation {
++    fn to_animated_zero(&self) -> Result<Self, ()> {
++        match *self {
+             TransformOperation::Matrix(..) => {
+-                let identity = ComputedMatrix::identity();
+-                result.push(TransformOperation::Matrix(identity));
+-            }
+-            TransformOperation::MatrixWithPercents(..) => {}
+-            TransformOperation::Skew(..) => {
+-                result.push(TransformOperation::Skew(Angle::zero(), Angle::zero()))
+-            }
+-            TransformOperation::Translate(..) => {
+-                result.push(TransformOperation::Translate(LengthOrPercentage::zero(),
+-                                                          LengthOrPercentage::zero(),
+-                                                          Au(0)));
+-            }
++                Ok(TransformOperation::Matrix(ComputedMatrix::identity()))
++            },
++            TransformOperation::MatrixWithPercents(..) => {
++                // FIXME(nox): Should be MatrixWithPercents value.
++                Ok(TransformOperation::Matrix(ComputedMatrix::identity()))
++            },
++            TransformOperation::Skew(sx, sy) => {
++                Ok(TransformOperation::Skew(
++                    sx.to_animated_zero()?,
++                    sy.to_animated_zero()?,
++                ))
++            },
++            TransformOperation::Translate(ref tx, ref ty, ref tz) => {
++                Ok(TransformOperation::Translate(
++                    tx.to_animated_zero()?,
++                    ty.to_animated_zero()?,
++                    tz.to_animated_zero()?,
++                ))
++            },
+             TransformOperation::Scale(..) => {
+-                result.push(TransformOperation::Scale(1.0, 1.0, 1.0));
+-            }
++                Ok(TransformOperation::Scale(1.0, 1.0, 1.0))
++            },
+             TransformOperation::Rotate(x, y, z, a) => {
+                 let (x, y, z, _) = get_normalized_vector_and_angle(x, y, z, a);
+-                result.push(TransformOperation::Rotate(x, y, z, Angle::zero()));
+-            }
++                Ok(TransformOperation::Rotate(x, y, z, Angle::zero()))
++            },
+             TransformOperation::Perspective(..) |
+             TransformOperation::AccumulateMatrix { .. } |
+             TransformOperation::InterpolateMatrix { .. } => {
+                 // Perspective: We convert a perspective function into an equivalent
+                 //     ComputedMatrix, and then decompose/interpolate/recompose these matrices.
+                 // AccumulateMatrix/InterpolateMatrix: We do interpolation on
+                 //     AccumulateMatrix/InterpolateMatrix by reading it as a ComputedMatrix
+                 //     (with layout information), and then do matrix interpolation.
+                 //
+                 // Therefore, we use an identity matrix to represent the identity transform list.
+                 // http://dev.w3.org/csswg/css-transforms/#identity-transform-function
+-                let identity = ComputedMatrix::identity();
+-                result.push(TransformOperation::Matrix(identity));
+-            }
++                //
++                // FIXME(nox): This does not actually work, given the impl of
++                // Animate for TransformOperation bails out if the two given
++                // values are dissimilar.
++                Ok(TransformOperation::Matrix(ComputedMatrix::identity()))
++            },
+         }
+     }
+-
+-    result
+ }
+ 
+-/// A wrapper for calling add_weighted that interpolates the distance of the two values from
+-/// an initial_value and uses that to produce an interpolated value.
+-/// This is used for values such as 'scale' where the initial value is 1 and where if we interpolate
+-/// the absolute values, we will produce odd results for accumulation.
+-fn add_weighted_with_initial_val<T: Animatable>(a: &T,
+-                                                b: &T,
+-                                                a_portion: f64,
+-                                                b_portion: f64,
+-                                                initial_val: &T) -> Result<T, ()> {
+-    let a = a.add_weighted(&initial_val, 1.0, -1.0)?;
+-    let b = b.add_weighted(&initial_val, 1.0, -1.0)?;
+-    let result = a.add_weighted(&b, a_portion, b_portion)?;
+-    result.add_weighted(&initial_val, 1.0, 1.0)
++fn animate_multiplicative_factor(
++    this: CSSFloat,
++    other: CSSFloat,
++    procedure: Procedure,
++) -> Result<CSSFloat, ()> {
++    Ok((this - 1.).animate(&(other - 1.), procedure)? + 1.)
+ }
+ 
+-/// Add two transform lists.
+ /// http://dev.w3.org/csswg/css-transforms/#interpolation-of-transforms
+-fn add_weighted_transform_lists(from_list: &[TransformOperation],
+-                                to_list: &[TransformOperation],
+-                                self_portion: f64,
+-                                other_portion: f64) -> TransformList {
+-    let mut result = vec![];
+-
+-    if can_interpolate_list(from_list, to_list) {
+-        for (from, to) in from_list.iter().zip(to_list) {
+-            match (from, to) {
+-                (&TransformOperation::Matrix(from),
+-                 &TransformOperation::Matrix(_to)) => {
+-                    let sum = from.add_weighted(&_to, self_portion, other_portion).unwrap();
+-                    result.push(TransformOperation::Matrix(sum));
+-                }
+-                (&TransformOperation::MatrixWithPercents(_),
+-                 &TransformOperation::MatrixWithPercents(_)) => {
+-                    // We don't add_weighted `-moz-transform` matrices yet.
+-                    // They contain percentage values.
+-                    {}
+-                }
+-                (&TransformOperation::Skew(fx, fy),
+-                 &TransformOperation::Skew(tx, ty)) => {
+-                    let ix = fx.add_weighted(&tx, self_portion, other_portion).unwrap();
+-                    let iy = fy.add_weighted(&ty, self_portion, other_portion).unwrap();
+-                    result.push(TransformOperation::Skew(ix, iy));
+-                }
+-                (&TransformOperation::Translate(fx, fy, fz),
+-                 &TransformOperation::Translate(tx, ty, tz)) => {
+-                    let ix = fx.add_weighted(&tx, self_portion, other_portion).unwrap();
+-                    let iy = fy.add_weighted(&ty, self_portion, other_portion).unwrap();
+-                    let iz = fz.add_weighted(&tz, self_portion, other_portion).unwrap();
+-                    result.push(TransformOperation::Translate(ix, iy, iz));
+-                }
+-                (&TransformOperation::Scale(fx, fy, fz),
+-                 &TransformOperation::Scale(tx, ty, tz)) => {
+-                    let ix = add_weighted_with_initial_val(&fx, &tx, self_portion,
+-                                                           other_portion, &1.0).unwrap();
+-                    let iy = add_weighted_with_initial_val(&fy, &ty, self_portion,
+-                                                           other_portion, &1.0).unwrap();
+-                    let iz = add_weighted_with_initial_val(&fz, &tz, self_portion,
+-                                                           other_portion, &1.0).unwrap();
+-                    result.push(TransformOperation::Scale(ix, iy, iz));
++impl Animate for TransformOperation {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        match (self, other) {
++            (
++                &TransformOperation::Matrix(ref this),
++                &TransformOperation::Matrix(ref other),
++            ) => {
++                Ok(TransformOperation::Matrix(
++                    this.animate(other, procedure)?,
++                ))
++            },
++            (
++                &TransformOperation::Skew(ref fx, ref fy),
++                &TransformOperation::Skew(ref tx, ref ty),
++            ) => {
++                Ok(TransformOperation::Skew(
++                    fx.animate(tx, procedure)?,
++                    fy.animate(ty, procedure)?,
++                ))
++            },
++            (
++                &TransformOperation::Translate(ref fx, ref fy, ref fz),
++                &TransformOperation::Translate(ref tx, ref ty, ref tz),
++            ) => {
++                Ok(TransformOperation::Translate(
++                    fx.animate(tx, procedure)?,
++                    fy.animate(ty, procedure)?,
++                    fz.animate(tz, procedure)?,
++                ))
++            },
++            (
++                &TransformOperation::Scale(ref fx, ref fy, ref fz),
++                &TransformOperation::Scale(ref tx, ref ty, ref tz),
++            ) => {
++                Ok(TransformOperation::Scale(
++                    animate_multiplicative_factor(*fx, *tx, procedure)?,
++                    animate_multiplicative_factor(*fy, *ty, procedure)?,
++                    animate_multiplicative_factor(*fz, *tz, procedure)?,
++                ))
++            },
++            (
++                &TransformOperation::Rotate(fx, fy, fz, fa),
++                &TransformOperation::Rotate(tx, ty, tz, ta),
++            ) => {
++                let (fx, fy, fz, fa) = get_normalized_vector_and_angle(fx, fy, fz, fa);
++                let (tx, ty, tz, ta) = get_normalized_vector_and_angle(tx, ty, tz, ta);
++                if (fx, fy, fz) == (tx, ty, tz) {
++                    let ia = fa.animate(&ta, procedure)?;
++                    Ok(TransformOperation::Rotate(fx, fy, fz, ia))
++                } else {
++                    let matrix_f = rotate_to_matrix(fx, fy, fz, fa);
++                    let matrix_t = rotate_to_matrix(tx, ty, tz, ta);
++                    Ok(TransformOperation::Matrix(
++                        matrix_f.animate(&matrix_t, procedure)?,
++                    ))
+                 }
+-                (&TransformOperation::Rotate(fx, fy, fz, fa),
+-                 &TransformOperation::Rotate(tx, ty, tz, ta)) => {
+-                    let (fx, fy, fz, fa) = get_normalized_vector_and_angle(fx, fy, fz, fa);
+-                    let (tx, ty, tz, ta) = get_normalized_vector_and_angle(tx, ty, tz, ta);
+-                    if (fx, fy, fz) == (tx, ty, tz) {
+-                        let ia = fa.add_weighted(&ta, self_portion, other_portion).unwrap();
+-                        result.push(TransformOperation::Rotate(fx, fy, fz, ia));
+-                    } else {
+-                        let matrix_f = rotate_to_matrix(fx, fy, fz, fa);
+-                        let matrix_t = rotate_to_matrix(tx, ty, tz, ta);
+-                        let sum = matrix_f.add_weighted(&matrix_t, self_portion, other_portion)
+-                                          .unwrap();
+-
+-                        result.push(TransformOperation::Matrix(sum));
+-                    }
++            },
++            (
++                &TransformOperation::Perspective(ref fd),
++                &TransformOperation::Perspective(ref td),
++            ) => {
++                let mut fd_matrix = ComputedMatrix::identity();
++                let mut td_matrix = ComputedMatrix::identity();
++                if fd.0 > 0 {
++                    fd_matrix.m34 = -1. / fd.to_f32_px();
+                 }
+-                (&TransformOperation::Perspective(fd),
+-                 &TransformOperation::Perspective(td)) => {
+-                    let mut fd_matrix = ComputedMatrix::identity();
+-                    let mut td_matrix = ComputedMatrix::identity();
+-                    if fd.0 > 0 {
+-                        fd_matrix.m34 = -1. / fd.to_f32_px();
+-                    }
+-
+-                    if td.0 > 0 {
+-                        td_matrix.m34 = -1. / td.to_f32_px();
+-                    }
+-
+-                    let sum = fd_matrix.add_weighted(&td_matrix, self_portion, other_portion)
+-                                       .unwrap();
+-                    result.push(TransformOperation::Matrix(sum));
++                if td.0 > 0 {
++                    td_matrix.m34 = -1. / td.to_f32_px();
+                 }
+-                _ => {
+-                    // This should be unreachable due to the can_interpolate_list() call.
+-                    unreachable!();
+-                }
+-            }
++                Ok(TransformOperation::Matrix(
++                    fd_matrix.animate(&td_matrix, procedure)?,
++                ))
++            },
++            _ => Err(()),
+         }
+-    } else {
+-        let from_transform_list = TransformList(Some(from_list.to_vec()));
+-        let to_transform_list = TransformList(Some(to_list.to_vec()));
+-        result.push(
+-            TransformOperation::InterpolateMatrix { from_list: from_transform_list,
+-                                                    to_list: to_transform_list,
+-                                                    progress: Percentage(other_portion as f32) });
+     }
+-
+-    TransformList(Some(result))
+ }
+ 
+ /// https://www.w3.org/TR/css-transforms-1/#Rotate3dDefined
+ fn rotate_to_matrix(x: f32, y: f32, z: f32, a: Angle) -> ComputedMatrix {
+     let half_rad = a.radians() / 2.0;
+     let sc = (half_rad).sin() * (half_rad).cos();
+     let sq = (half_rad).sin().powi(2);
+ 
+@@ -1535,50 +1371,48 @@ pub struct MatrixDecomposed2D {
+     /// The scale function.
+     pub scale: Scale2D,
+     /// The rotation angle.
+     pub angle: f32,
+     /// The inner matrix.
+     pub matrix: InnerMatrix2D,
+ }
+ 
+-impl Animatable for InnerMatrix2D {
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++impl Animate for InnerMatrix2D {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(InnerMatrix2D {
+-            m11: add_weighted_with_initial_val(&self.m11, &other.m11,
+-                                               self_portion, other_portion, &1.0)?,
+-            m12: self.m12.add_weighted(&other.m12, self_portion, other_portion)?,
+-            m21: self.m21.add_weighted(&other.m21, self_portion, other_portion)?,
+-            m22: add_weighted_with_initial_val(&self.m22, &other.m22,
+-                                               self_portion, other_portion, &1.0)?,
++            m11: animate_multiplicative_factor(self.m11, other.m11, procedure)?,
++            m12: self.m12.animate(&other.m12, procedure)?,
++            m21: self.m21.animate(&other.m21, procedure)?,
++            m22: animate_multiplicative_factor(self.m22, other.m22, procedure)?,
+         })
+     }
+ }
+ 
+-impl Animatable for Translate2D {
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++impl Animate for Translate2D {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(Translate2D(
+-            self.0.add_weighted(&other.0, self_portion, other_portion)?,
+-            self.1.add_weighted(&other.1, self_portion, other_portion)?,
++            self.0.animate(&other.0, procedure)?,
++            self.1.animate(&other.1, procedure)?,
+         ))
+     }
+ }
+ 
+-impl Animatable for Scale2D {
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++impl Animate for Scale2D {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(Scale2D(
+-            add_weighted_with_initial_val(&self.0, &other.0, self_portion, other_portion, &1.0)?,
+-            add_weighted_with_initial_val(&self.1, &other.1, self_portion, other_portion, &1.0)?,
++            animate_multiplicative_factor(self.0, other.0, procedure)?,
++            animate_multiplicative_factor(self.1, other.1, procedure)?,
+         ))
+     }
+ }
+ 
+-impl Animatable for MatrixDecomposed2D {
++impl Animate for MatrixDecomposed2D {
+     /// https://drafts.csswg.org/css-transforms/#interpolation-of-decomposed-2d-matrix-values
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         // If x-axis of one is flipped, and y-axis of the other,
+         // convert to an unflipped rotation.
+         let mut scale = self.scale;
+         let mut angle = self.angle;
+         let mut other_angle = other.angle;
+         if (scale.0 < 0.0 && other.scale.1 < 0.0) || (scale.1 < 0.0 && other.scale.0 < 0.0) {
+             scale.0 = -scale.0;
+             scale.1 = -scale.1;
+@@ -1598,20 +1432,20 @@ impl Animatable for MatrixDecomposed2D {
+                 angle -= 360.
+             }
+             else{
+                 other_angle -= 360.
+             }
+         }
+ 
+         // Interpolate all values.
+-        let translate = self.translate.add_weighted(&other.translate, self_portion, other_portion)?;
+-        let scale = scale.add_weighted(&other.scale, self_portion, other_portion)?;
+-        let angle = angle.add_weighted(&other_angle, self_portion, other_portion)?;
+-        let matrix = self.matrix.add_weighted(&other.matrix, self_portion, other_portion)?;
++        let translate = self.translate.animate(&other.translate, procedure)?;
++        let scale = scale.animate(&other.scale, procedure)?;
++        let angle = angle.animate(&other_angle, procedure)?;
++        let matrix = self.matrix.animate(&other.matrix, procedure)?;
+ 
+         Ok(MatrixDecomposed2D {
+             translate: translate,
+             scale: scale,
+             angle: angle,
+             matrix: matrix,
+         })
+     }
+@@ -1626,36 +1460,35 @@ impl ComputeSquaredDistance for MatrixDe
+         let angle2 = other.angle as f64 * RAD_PER_DEG;
+         Ok(self.translate.compute_squared_distance(&other.translate)? +
+            self.scale.compute_squared_distance(&other.scale)? +
+            angle1.compute_squared_distance(&angle2)? +
+            self.matrix.compute_squared_distance(&other.matrix)?)
+     }
+ }
+ 
+-impl Animatable for ComputedMatrix {
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++impl Animate for ComputedMatrix {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         if self.is_3d() || other.is_3d() {
+             let decomposed_from = decompose_3d_matrix(*self);
+             let decomposed_to = decompose_3d_matrix(*other);
+             match (decomposed_from, decomposed_to) {
+-                (Ok(from), Ok(to)) => {
+-                    let sum = from.add_weighted(&to, self_portion, other_portion)?;
+-                    Ok(ComputedMatrix::from(sum))
++                (Ok(this), Ok(other)) => {
++                    Ok(ComputedMatrix::from(this.animate(&other, procedure)?))
+                 },
+                 _ => {
+-                    let result = if self_portion > other_portion {*self} else {*other};
++                    let (this_weight, other_weight) = procedure.weights();
++                    let result = if this_weight > other_weight { *self } else { *other };
+                     Ok(result)
+-                }
++                },
+             }
+         } else {
+-            let decomposed_from = MatrixDecomposed2D::from(*self);
+-            let decomposed_to = MatrixDecomposed2D::from(*other);
+-            let sum = decomposed_from.add_weighted(&decomposed_to, self_portion, other_portion)?;
+-            Ok(ComputedMatrix::from(sum))
++            let this = MatrixDecomposed2D::from(*self);
++            let other = MatrixDecomposed2D::from(*other);
++            Ok(ComputedMatrix::from(this.animate(&other, procedure)?))
+         }
+     }
+ }
+ 
+ impl ComputeSquaredDistance for ComputedMatrix {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+         if self.is_3d() || other.is_3d() {
+@@ -2082,103 +1915,104 @@ fn dot(a: [f32; 3], b: [f32; 3]) -> f32 
+ fn cross(row1: [f32; 3], row2: [f32; 3]) -> [f32; 3] {
+     [
+         row1[1] * row2[2] - row1[2] * row2[1],
+         row1[2] * row2[0] - row1[0] * row2[2],
+         row1[0] * row2[1] - row1[1] * row2[0]
+     ]
+ }
+ 
+-impl Animatable for Translate3D {
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++impl Animate for Translate3D {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(Translate3D(
+-            self.0.add_weighted(&other.0, self_portion, other_portion)?,
+-            self.1.add_weighted(&other.1, self_portion, other_portion)?,
+-            self.2.add_weighted(&other.2, self_portion, other_portion)?,
++            self.0.animate(&other.0, procedure)?,
++            self.1.animate(&other.1, procedure)?,
++            self.2.animate(&other.2, procedure)?,
+         ))
+     }
+ }
+ 
+-impl Animatable for Scale3D {
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++impl Animate for Scale3D {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(Scale3D(
+-            add_weighted_with_initial_val(&self.0, &other.0, self_portion, other_portion, &1.0)?,
+-            add_weighted_with_initial_val(&self.1, &other.1, self_portion, other_portion, &1.0)?,
+-            add_weighted_with_initial_val(&self.2, &other.2, self_portion, other_portion, &1.0)?,
++            animate_multiplicative_factor(self.0, other.0, procedure)?,
++            animate_multiplicative_factor(self.1, other.1, procedure)?,
++            animate_multiplicative_factor(self.2, other.2, procedure)?,
+         ))
+     }
+ }
+ 
+-impl Animatable for Skew {
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++impl Animate for Skew {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(Skew(
+-            self.0.add_weighted(&other.0, self_portion, other_portion)?,
+-            self.1.add_weighted(&other.1, self_portion, other_portion)?,
+-            self.2.add_weighted(&other.2, self_portion, other_portion)?,
++            self.0.animate(&other.0, procedure)?,
++            self.1.animate(&other.1, procedure)?,
++            self.2.animate(&other.2, procedure)?,
+         ))
+     }
+ }
+ 
+ impl ComputeSquaredDistance for Skew {
+     // We have to use atan() to convert the skew factors into skew angles, so implement
+     // ComputeSquaredDistance manually.
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+         Ok(self.0.atan().compute_squared_distance(&other.0.atan())? +
+            self.1.atan().compute_squared_distance(&other.1.atan())? +
+            self.2.atan().compute_squared_distance(&other.2.atan())?)
+     }
+ }
+ 
+-impl Animatable for Perspective {
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++impl Animate for Perspective {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(Perspective(
+-            self.0.add_weighted(&other.0, self_portion, other_portion)?,
+-            self.1.add_weighted(&other.1, self_portion, other_portion)?,
+-            self.2.add_weighted(&other.2, self_portion, other_portion)?,
+-            add_weighted_with_initial_val(&self.3, &other.3, self_portion, other_portion, &1.0)?,
++            self.0.animate(&other.0, procedure)?,
++            self.1.animate(&other.1, procedure)?,
++            self.2.animate(&other.2, procedure)?,
++            animate_multiplicative_factor(self.3, other.3, procedure)?,
+         ))
+     }
+ }
+ 
+-impl Animatable for MatrixDecomposed3D {
++impl Animate for MatrixDecomposed3D {
+     /// https://drafts.csswg.org/css-transforms/#interpolation-of-decomposed-3d-matrix-values
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
+-        -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         use std::f64;
+ 
+-        debug_assert!((self_portion + other_portion - 1.0f64).abs() <= f64::EPSILON ||
+-                      other_portion == 1.0f64 || other_portion == 0.0f64,
+-                      "add_weighted should only be used for interpolating or accumulating transforms");
++        let (this_weight, other_weight) = procedure.weights();
++
++        debug_assert!((this_weight + other_weight - 1.0f64).abs() <= f64::EPSILON ||
++                      other_weight == 1.0f64 || other_weight == 0.0f64,
++                      "animate should only be used for interpolating or accumulating transforms");
+ 
+         let mut sum = *self;
+ 
+         // Add translate, scale, skew and perspective components.
+-        sum.translate = self.translate.add_weighted(&other.translate, self_portion, other_portion)?;
+-        sum.scale = self.scale.add_weighted(&other.scale, self_portion, other_portion)?;
+-        sum.skew = self.skew.add_weighted(&other.skew, self_portion, other_portion)?;
+-        sum.perspective = self.perspective.add_weighted(&other.perspective, self_portion, other_portion)?;
++        sum.translate = self.translate.animate(&other.translate, procedure)?;
++        sum.scale = self.scale.animate(&other.scale, procedure)?;
++        sum.skew = self.skew.animate(&other.skew, procedure)?;
++        sum.perspective = self.perspective.animate(&other.perspective, procedure)?;
+ 
+         // Add quaternions using spherical linear interpolation (Slerp).
+         //
+-        // We take a specialized code path for accumulation (where other_portion is 1)
+-        if other_portion == 1.0 {
+-            if self_portion == 0.0 {
++        // We take a specialized code path for accumulation (where other_weight is 1)
++        if other_weight == 1.0 {
++            if this_weight == 0.0 {
+                 return Ok(*other)
+             }
+ 
+             let clamped_w = self.quaternion.3.min(1.0).max(-1.0);
+ 
+             // Determine the scale factor.
+             let mut theta = clamped_w.acos();
+             let mut scale = if theta == 0.0 { 0.0 } else { 1.0 / theta.sin() };
+-            theta *= self_portion;
++            theta *= this_weight;
+             scale *= theta.sin();
+ 
+-            // Scale the self matrix by self_portion.
++            // Scale the self matrix by this_weight.
+             let mut scaled_self = *self;
+             % for i in range(3):
+                 scaled_self.quaternion.${i} *= scale;
+             % endfor
+             scaled_self.quaternion.3 = theta.cos();
+ 
+             // Multiply scaled-self by other.
+             let a = &scaled_self.quaternion;
+@@ -2199,22 +2033,22 @@ impl Animatable for MatrixDecomposed3D {
+             product = product.min(1.0);
+             product = product.max(-1.0);
+ 
+             if product == 1.0 {
+                 return Ok(sum);
+             }
+ 
+             let theta = product.acos();
+-            let w = (other_portion * theta).sin() * 1.0 / (1.0 - product * product).sqrt();
++            let w = (other_weight * theta).sin() * 1.0 / (1.0 - product * product).sqrt();
+ 
+             let mut a = *self;
+             let mut b = *other;
+             % for i in range(4):
+-                a.quaternion.${i} *= (other_portion * theta).cos() - product * w;
++                a.quaternion.${i} *= (other_weight * theta).cos() - product * w;
+                 b.quaternion.${i} *= w;
+                 sum.quaternion.${i} = a.quaternion.${i} + b.quaternion.${i};
+             % endfor
+         }
+ 
+         Ok(sum)
+     }
+ }
+@@ -2412,233 +2246,242 @@ impl ComputedMatrix {
+              self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33),
+         };
+ 
+         Some(x)
+     }
+ }
+ 
+ /// https://drafts.csswg.org/css-transforms/#interpolation-of-transforms
+-impl Animatable for TransformList {
++impl Animate for TransformList {
+     #[inline]
+-    fn add_weighted(&self, other: &TransformList, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        // http://dev.w3.org/csswg/css-transforms/#interpolation-of-transforms
+-        let result = match (&self.0, &other.0) {
+-            (&Some(ref from_list), &Some(ref to_list)) => {
+-                // Two lists of transforms
+-                add_weighted_transform_lists(from_list, &to_list, self_portion, other_portion)
+-            }
+-            (&Some(ref from_list), &None) => {
+-                // http://dev.w3.org/csswg/css-transforms/#none-transform-animation
+-                let to_list = build_identity_transform_list(from_list);
+-                add_weighted_transform_lists(from_list, &to_list, self_portion, other_portion)
+-            }
+-            (&None, &Some(ref to_list)) => {
+-                // http://dev.w3.org/csswg/css-transforms/#none-transform-animation
+-                let from_list = build_identity_transform_list(to_list);
+-                add_weighted_transform_lists(&from_list, to_list, self_portion, other_portion)
+-            }
+-            _ => {
+-                // http://dev.w3.org/csswg/css-transforms/#none-none-animation
+-                TransformList(None)
+-            }
++    fn animate(
++        &self,
++        other: &Self,
++        procedure: Procedure,
++    ) -> Result<Self, ()> {
++        if self.0.is_none() && other.0.is_none() {
++            return Ok(TransformList(None));
++        }
++
++        if procedure == Procedure::Add {
++            let this = self.0.as_ref().map_or(&[][..], |l| l);
++            let other = other.0.as_ref().map_or(&[][..], |l| l);
++            let result = this.iter().chain(other).cloned().collect::<Vec<_>>();
++            return Ok(TransformList(if result.is_empty() {
++                None
++            } else {
++                Some(result)
++            }));
++        }
++
++        let this = if self.0.is_some() {
++            Cow::Borrowed(self)
++        } else {
++            Cow::Owned(other.to_animated_zero()?)
++        };
++        let other = if other.0.is_some() {
++            Cow::Borrowed(other)
++        } else {
++            Cow::Owned(self.to_animated_zero()?)
+         };
+ 
+-        Ok(result)
+-    }
+-
+-    fn add(&self, other: &Self) -> Result<Self, ()> {
+-        match (&self.0, &other.0) {
+-            (&Some(ref from_list), &Some(ref to_list)) => {
+-                Ok(TransformList(Some([&from_list[..], &to_list[..]].concat())))
+-            }
+-            (&Some(_), &None) => {
+-                Ok(self.clone())
+-            }
+-            (&None, &Some(_)) => {
+-                Ok(other.clone())
+-            }
+-            _ => {
+-                Ok(TransformList(None))
++        {
++            let this = (*this).0.as_ref().map_or(&[][..], |l| l);
++            let other = (*other).0.as_ref().map_or(&[][..], |l| l);
++            if this.len() == other.len() {
++                let result = this.iter().zip(other).map(|(this, other)| {
++                    this.animate(other, procedure)
++                }).collect::<Result<Vec<_>, _>>();
++                if let Ok(list) = result {
++                    return Ok(TransformList(if list.is_empty() {
++                        None
++                    } else {
++                        Some(list)
++                    }));
++                }
+             }
+         }
+-    }
+ 
+-    #[inline]
+-    fn accumulate(&self, other: &Self, count: u64) -> Result<Self, ()> {
+-        match (&self.0, &other.0) {
+-            (&Some(ref from_list), &Some(ref to_list)) => {
+-                if can_interpolate_list(from_list, to_list) {
+-                    Ok(add_weighted_transform_lists(from_list, &to_list, count as f64, 1.0))
+-                } else {
+-                    use std::i32;
+-                    let result = vec![TransformOperation::AccumulateMatrix {
+-                        from_list: self.clone(),
+-                        to_list: other.clone(),
+-                        count: cmp::min(count, i32::MAX as u64) as i32
+-                    }];
+-                    Ok(TransformList(Some(result)))
+-                }
+-            }
+-            (&Some(ref from_list), &None) => {
+-                Ok(add_weighted_transform_lists(from_list, from_list, count as f64, 0.0))
+-            }
+-            (&None, &Some(_)) => {
+-                // If |self| is 'none' then we are calculating:
+-                //
+-                //    none * |count| + |other|
+-                //    = none + |other|
+-                //    = |other|
+-                //
+-                // Hence the result is just |other|.
+-                Ok(other.clone())
+-            }
+-            _ => {
+-                Ok(TransformList(None))
+-            }
++        match procedure {
++            Procedure::Add => Err(()),
++            Procedure::Interpolate { progress } => {
++                Ok(TransformList(Some(vec![TransformOperation::InterpolateMatrix {
++                    from_list: this.into_owned(),
++                    to_list: other.into_owned(),
++                    progress: Percentage(progress as f32),
++                }])))
++            },
++            Procedure::Accumulate { count } => {
++                Ok(TransformList(Some(vec![TransformOperation::AccumulateMatrix {
++                    from_list: this.into_owned(),
++                    to_list: other.into_owned(),
++                    count: cmp::min(count, i32::max_value() as u64) as i32,
++                }])))
++            },
+         }
+     }
+ }
+ 
+-/// A helper function to retrieve the pixel length and percentage value.
+-fn extract_pixel_calc_value(lop: &LengthOrPercentage) -> (f64, CSSFloat) {
+-    match lop {
+-        &LengthOrPercentage::Length(au) => (au.to_f64_px(), 0.),
+-        &LengthOrPercentage::Percentage(percent) => (0., percent.0),
+-        &LengthOrPercentage::Calc(calc) => (calc.length().to_f64_px(), calc.percentage())
+-    }
+-}
+-
+-/// Compute the squared distance of two transform lists.
+ // This might not be the most useful definition of distance. It might be better, for example,
+ // to trace the distance travelled by a point as its transform is interpolated between the two
+ // lists. That, however, proves to be quite complicated so we take a simple approach for now.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=1318591#c0.
+-fn compute_transform_lists_squared_distance(from_list: &[TransformOperation],
+-                                            to_list: &[TransformOperation])
+-                                            -> Result<SquaredDistance, ()> {
+-    let zero_distance = SquaredDistance::Value(0.);
+-    let squared_distance = from_list.iter().zip(to_list.iter()).map(|(from, to)| {
+-        match (from, to) {
+-            (&TransformOperation::Matrix(from),
+-             &TransformOperation::Matrix(to)) => {
+-                from.compute_squared_distance(&to).unwrap_or(zero_distance)
+-            }
+-            (&TransformOperation::Skew(fx, fy),
+-             &TransformOperation::Skew(tx, ty)) => {
+-                fx.compute_squared_distance(&tx).unwrap_or(zero_distance) +
+-                    fy.compute_squared_distance(&ty).unwrap_or(zero_distance)
+-            }
+-            (&TransformOperation::Translate(fx, fy, fz),
+-             &TransformOperation::Translate(tx, ty, tz)) => {
++impl ComputeSquaredDistance for TransformOperation {
++    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
++        match (self, other) {
++            (
++                &TransformOperation::Matrix(ref this),
++                &TransformOperation::Matrix(ref other),
++            ) => {
++                this.compute_squared_distance(other)
++            },
++            (
++                &TransformOperation::Skew(ref fx, ref fy),
++                &TransformOperation::Skew(ref tx, ref ty),
++            ) => {
++                Ok(
++                    fx.compute_squared_distance(&tx)? +
++                    fy.compute_squared_distance(&ty)?,
++                )
++            },
++            (
++                &TransformOperation::Translate(ref fx, ref fy, ref fz),
++                &TransformOperation::Translate(ref tx, ref ty, ref tz),
++            ) => {
+                 // We don't want to require doing layout in order to calculate the result, so
+                 // drop the percentage part. However, dropping percentage makes us impossible to
+                 // compute the distance for the percentage-percentage case, but Gecko uses the
+                 // same formula, so it's fine for now.
+                 // Note: We use pixel value to compute the distance for translate, so we have to
+                 // convert Au into px.
+-                let diff_x = fx.add_weighted(&tx, 1., -1.).unwrap_or(LengthOrPercentage::zero());
+-                let diff_y = fy.add_weighted(&ty, 1., -1.).unwrap_or(LengthOrPercentage::zero());
+-                let (diff_x_length, _) = extract_pixel_calc_value(&diff_x);
+-                let (diff_y_length, _) = extract_pixel_calc_value(&diff_y);
+-                SquaredDistance::Value(diff_x_length * diff_x_length) +
+-                    SquaredDistance::Value(diff_y_length * diff_y_length) +
+-                    fz.to_f64_px().compute_squared_distance(&tz.to_f64_px()).unwrap_or(zero_distance)
+-            }
+-            (&TransformOperation::Scale(fx, fy, fz),
+-             &TransformOperation::Scale(tx, ty, tz)) => {
+-                fx.compute_squared_distance(&tx).unwrap_or(zero_distance) +
+-                    fy.compute_squared_distance(&ty).unwrap_or(zero_distance) +
+-                    fz.compute_squared_distance(&tz).unwrap_or(zero_distance)
+-            }
+-            (&TransformOperation::Rotate(fx, fy, fz, fa),
+-             &TransformOperation::Rotate(tx, ty, tz, ta)) => {
++                let extract_pixel_length = |lop: &LengthOrPercentage| {
++                    match *lop {
++                        LengthOrPercentage::Length(au) => au.to_f64_px(),
++                        LengthOrPercentage::Percentage(_) => 0.,
++                        LengthOrPercentage::Calc(calc) => calc.length().to_f64_px(),
++                    }
++                };
++
++                let fx = extract_pixel_length(&fx);
++                let fy = extract_pixel_length(&fy);
++                let tx = extract_pixel_length(&tx);
++                let ty = extract_pixel_length(&ty);
++
++                Ok(
++                    fx.compute_squared_distance(&tx)? +
++                    fy.compute_squared_distance(&ty)? +
++                    fz.to_f64_px().compute_squared_distance(&tz.to_f64_px())?,
++                )
++            },
++            (
++                &TransformOperation::Scale(ref fx, ref fy, ref fz),
++                &TransformOperation::Scale(ref tx, ref ty, ref tz),
++            ) => {
++                Ok(
++                    fx.compute_squared_distance(&tx)? +
++                    fy.compute_squared_distance(&ty)? +
++                    fz.compute_squared_distance(&tz)?,
++                )
++            },
++            (
++                &TransformOperation::Rotate(fx, fy, fz, fa),
++                &TransformOperation::Rotate(tx, ty, tz, ta),
++            ) => {
+                 let (fx, fy, fz, angle1) = get_normalized_vector_and_angle(fx, fy, fz, fa);
+                 let (tx, ty, tz, angle2) = get_normalized_vector_and_angle(tx, ty, tz, ta);
+                 if (fx, fy, fz) == (tx, ty, tz) {
+-                    angle1.compute_squared_distance(&angle2).unwrap_or(zero_distance)
++                    angle1.compute_squared_distance(&angle2)
+                 } else {
+                     let v1 = DirectionVector::new(fx, fy, fz);
+                     let v2 = DirectionVector::new(tx, ty, tz);
+                     let q1 = Quaternion::from_direction_and_angle(&v1, angle1.radians64());
+                     let q2 = Quaternion::from_direction_and_angle(&v2, angle2.radians64());
+-                    q1.compute_squared_distance(&q2).unwrap_or(zero_distance)
++                    q1.compute_squared_distance(&q2)
+                 }
+             }
+-            (&TransformOperation::Perspective(fd),
+-             &TransformOperation::Perspective(td)) => {
++            (
++                &TransformOperation::Perspective(ref fd),
++                &TransformOperation::Perspective(ref td),
++            ) => {
+                 let mut fd_matrix = ComputedMatrix::identity();
+                 let mut td_matrix = ComputedMatrix::identity();
+                 if fd.0 > 0 {
+                     fd_matrix.m34 = -1. / fd.to_f32_px();
+                 }
+ 
+                 if td.0 > 0 {
+                     td_matrix.m34 = -1. / td.to_f32_px();
+                 }
+-                fd_matrix.compute_squared_distance(&td_matrix).unwrap_or(zero_distance)
++                fd_matrix.compute_squared_distance(&td_matrix)
+             }
+-            (&TransformOperation::Perspective(p), &TransformOperation::Matrix(m)) |
+-            (&TransformOperation::Matrix(m), &TransformOperation::Perspective(p)) => {
++            (
++                &TransformOperation::Perspective(ref p),
++                &TransformOperation::Matrix(ref m),
++            ) | (
++                &TransformOperation::Matrix(ref m),
++                &TransformOperation::Perspective(ref p),
++            ) => {
+                 let mut p_matrix = ComputedMatrix::identity();
+                 if p.0 > 0 {
+                     p_matrix.m34 = -1. / p.to_f32_px();
+                 }
+-                p_matrix.compute_squared_distance(&m).unwrap_or(zero_distance)
++                p_matrix.compute_squared_distance(&m)
+             }
+-            _ => {
+-                // We don't support computation of distance for InterpolateMatrix and
+-                // AccumulateMatrix.
+-                zero_distance
+-            }
++            _ => Err(()),
+         }
+-    }).sum();
+-
+-    Ok(squared_distance)
++    }
+ }
+ 
+ impl ComputeSquaredDistance for TransformList {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+-        match (self.0.as_ref(), other.0.as_ref()) {
+-            (Some(from_list), Some(to_list)) => {
+-                if can_interpolate_list(from_list, to_list) {
+-                    compute_transform_lists_squared_distance(from_list, to_list)
+-                } else {
+-                    // Bug 1390039: we don't handle mismatch transform lists for now.
+-                    Err(())
+-                }
+-            },
+-            (Some(list), None) | (None, Some(list)) => {
+-                let none = build_identity_transform_list(list);
+-                compute_transform_lists_squared_distance(list, &none)
++        let this = self.0.as_ref().map_or(&[][..], |l| l);
++        let other = other.0.as_ref().map_or(&[][..], |l| l);
++
++        this.iter().zip_longest(other).map(|it| {
++            match it {
++                EitherOrBoth::Both(this, other) => {
++                    this.compute_squared_distance(other)
++                },
++                EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => {
++                    list.to_animated_zero()?.compute_squared_distance(list)
++                },
+             }
+-            _ => Ok(SquaredDistance::Value(0.))
+-        }
++        }).sum()
+     }
+ }
+ 
+ impl ToAnimatedZero for TransformList {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+-        Ok(TransformList(None))
++        match self.0 {
++            None => Ok(TransformList(None)),
++            Some(ref list) => {
++                Ok(TransformList(Some(
++                    list.iter().map(|op| op.to_animated_zero()).collect::<Result<Vec<_>, _>>()?
++                )))
++            },
++        }
+     }
+ }
+ 
+-impl<T, U> Animatable for Either<T, U>
+-        where T: Animatable + Copy, U: Animatable + Copy,
++impl<T, U> Animate for Either<T, U>
++where
++    T: Animate,
++    U: Animate,
+ {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        match (*self, *other) {
+-            (Either::First(ref this), Either::First(ref other)) => {
+-                this.add_weighted(&other, self_portion, other_portion).map(Either::First)
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        match (self, other) {
++            (&Either::First(ref this), &Either::First(ref other)) => {
++                Ok(Either::First(this.animate(other, procedure)?))
+             },
+-            (Either::Second(ref this), Either::Second(ref other)) => {
+-                this.add_weighted(&other, self_portion, other_portion).map(Either::Second)
++            (&Either::Second(ref this), &Either::Second(ref other)) => {
++                Ok(Either::Second(this.animate(other, procedure)?))
+             },
+             _ => Err(()),
+         }
+     }
+ }
+ 
+ impl<A, B> ToAnimatedZero for Either<A, B>
+ where
+@@ -2653,35 +2496,36 @@ where
+             },
+             Either::Second(ref second) => {
+                 Ok(Either::Second(second.to_animated_zero()?))
+             },
+         }
+     }
+ }
+ 
+-/// Animatable SVGPaint
++/// Animated SVGPaint
+ pub type IntermediateSVGPaint = SVGPaint<AnimatedRGBA, ComputedUrl>;
+ 
+-/// Animatable SVGPaintKind
++/// Animated SVGPaintKind
+ pub type IntermediateSVGPaintKind = SVGPaintKind<AnimatedRGBA, ComputedUrl>;
+ 
+-impl Animatable for IntermediateSVGPaint {
++impl Animate for IntermediateSVGPaint {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(IntermediateSVGPaint {
+-            kind: self.kind.add_weighted(&other.kind, self_portion, other_portion)?,
+-            fallback: self.fallback.add_weighted(&other.fallback, self_portion, other_portion)?,
++            kind: self.kind.animate(&other.kind, procedure)?,
++            fallback: self.fallback.animate(&other.fallback, procedure)?,
+         })
+     }
+ }
+ 
+ impl ComputeSquaredDistance for IntermediateSVGPaint {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
++        // FIXME(nox): This should be derived.
+         Ok(
+             self.kind.compute_squared_distance(&other.kind)? +
+             self.fallback.compute_squared_distance(&other.fallback)?,
+         )
+     }
+ }
+ 
+ impl ToAnimatedZero for IntermediateSVGPaint {
+@@ -2689,28 +2533,30 @@ impl ToAnimatedZero for IntermediateSVGP
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         Ok(IntermediateSVGPaint {
+             kind: self.kind.to_animated_zero()?,
+             fallback: self.fallback.and_then(|v| v.to_animated_zero().ok()),
+         })
+     }
+ }
+ 
+-impl Animatable for IntermediateSVGPaintKind {
++impl Animate for IntermediateSVGPaintKind {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+-            (&SVGPaintKind::Color(ref self_color), &SVGPaintKind::Color(ref other_color)) => {
+-                Ok(SVGPaintKind::Color(self_color.add_weighted(other_color, self_portion, other_portion)?))
+-            }
+-            // FIXME context values should be interpolable with colors
+-            // Gecko doesn't implement this behavior either.
++            (&SVGPaintKind::Color(ref this), &SVGPaintKind::Color(ref other)) => {
++                Ok(SVGPaintKind::Color(this.animate(other, procedure)?))
++            },
+             (&SVGPaintKind::ContextFill, &SVGPaintKind::ContextFill) => Ok(SVGPaintKind::ContextFill),
+             (&SVGPaintKind::ContextStroke, &SVGPaintKind::ContextStroke) => Ok(SVGPaintKind::ContextStroke),
+-            _ => Err(())
++            _ => {
++                // FIXME: Context values should be interpolable with colors,
++                // Gecko doesn't implement this behavior either.
++                Err(())
++            }
+         }
+     }
+ }
+ 
+ impl ComputeSquaredDistance for IntermediateSVGPaintKind {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+         match (self, other) {
+@@ -2798,152 +2644,171 @@ fn convert_from_number_or_percentage<Len
+         NumberOrPercentage::Number(num) =>
+             SvgLengthOrPercentageOrNumber::Number(num.into()),
+         NumberOrPercentage::Percentage(p) =>
+             SvgLengthOrPercentageOrNumber::LengthOrPercentage(
+                 (LengthOrPercentage::Percentage(p)).into())
+     }
+ }
+ 
+-impl <LengthOrPercentageType, NumberType> Animatable for
+-    SvgLengthOrPercentageOrNumber<LengthOrPercentageType, NumberType>
+-    where LengthOrPercentageType: Animatable + Into<NumberOrPercentage> + From<LengthOrPercentage> + Copy,
+-          NumberType: Animatable + Into<NumberOrPercentage> + From<Number>,
+-          SvgLengthOrPercentageOrNumber<LengthOrPercentageType, NumberType>: Copy,
+-          LengthOrPercentage: From<LengthOrPercentageType>
++impl <L, N> Animate for SvgLengthOrPercentageOrNumber<L, N>
++where
++    L: Animate + From<LengthOrPercentage> + Into<NumberOrPercentage> + Copy,
++    N: Animate + From<Number> + Into<NumberOrPercentage>,
++    LengthOrPercentage: From<L>,
++    Self: Copy,
+ {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         if self.has_calc() || other.has_calc() {
+             // TODO: We need to treat calc value.
+             // https://bugzilla.mozilla.org/show_bug.cgi?id=1386967
+             return Err(());
+         }
+ 
+-        let from_value = convert_to_number_or_percentage(*self);
+-        let to_value = convert_to_number_or_percentage(*other);
++        let this = convert_to_number_or_percentage(*self);
++        let other = convert_to_number_or_percentage(*other);
+ 
+-        match (from_value, to_value) {
+-            (NumberOrPercentage::Number(from),
+-             NumberOrPercentage::Number(to)) => {
+-                from.add_weighted(&to, self_portion, other_portion)
+-                    .map(|num| NumberOrPercentage::Number(num))
+-                    .map(|nop| convert_from_number_or_percentage(nop))
++        match (this, other) {
++            (
++                NumberOrPercentage::Number(ref this),
++                NumberOrPercentage::Number(ref other),
++            ) => {
++                Ok(convert_from_number_or_percentage(
++                    NumberOrPercentage::Number(this.animate(other, procedure)?)
++                ))
+             },
+-            (NumberOrPercentage::Percentage(from),
+-             NumberOrPercentage::Percentage(to)) => {
+-                from.add_weighted(&to, self_portion, other_portion)
+-                    .map(|p| NumberOrPercentage::Percentage(p))
+-                    .map(|nop| convert_from_number_or_percentage(nop))
++            (
++                NumberOrPercentage::Percentage(ref this),
++                NumberOrPercentage::Percentage(ref other),
++            ) => {
++                Ok(convert_from_number_or_percentage(
++                    NumberOrPercentage::Percentage(this.animate(other, procedure)?)
++                ))
+             },
+             _ => Err(()),
+         }
+     }
+ }
+ 
+-impl <LengthOrPercentageType, NumberType> ToAnimatedZero for
+-    SvgLengthOrPercentageOrNumber<LengthOrPercentageType, NumberType>
+-    where LengthOrPercentageType: ToAnimatedZero, NumberType: ToAnimatedZero
++impl<L, N> ToAnimatedZero for SvgLengthOrPercentageOrNumber<L, N>
++where
++    L: ToAnimatedZero,
++    N: ToAnimatedZero,
+ {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+-        match self {
+-            &SvgLengthOrPercentageOrNumber::LengthOrPercentage(ref lop) =>
+-                lop.to_animated_zero()
+-                    .map(SvgLengthOrPercentageOrNumber::LengthOrPercentage),
+-            &SvgLengthOrPercentageOrNumber::Number(ref num) =>
+-                num.to_animated_zero()
+-                    .map(SvgLengthOrPercentageOrNumber::Number),
++        match *self {
++            SvgLengthOrPercentageOrNumber::LengthOrPercentage(ref lop) => {
++                Ok(SvgLengthOrPercentageOrNumber::LengthOrPercentage(
++                    lop.to_animated_zero()?,
++                ))
++            },
++            SvgLengthOrPercentageOrNumber::Number(ref num) => {
++                Ok(SvgLengthOrPercentageOrNumber::Number(
++                    num.to_animated_zero()?,
++                ))
++            },
+         }
+     }
+ }
+ 
+-impl<LengthType> Animatable for SVGLength<LengthType>
+-        where LengthType: Animatable + Clone
++impl<L> Animate for SVGLength<L>
++where
++    L: Animate + Clone,
+ {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             (&SVGLength::Length(ref this), &SVGLength::Length(ref other)) => {
+-                this.add_weighted(&other, self_portion, other_portion).map(SVGLength::Length)
+-            }
++                Ok(SVGLength::Length(this.animate(other, procedure)?))
++            },
+             _ => {
+-                Ok(if self_portion > other_portion { self.clone() } else { other.clone() })
+-            }
++                // FIXME(nox): Is this correct for addition and accumulation?
++                // I think an error should be returned if it's not
++                // an interpolation.
++                let (this_weight, other_weight) = procedure.weights();
++                Ok(if this_weight > other_weight { self.clone() } else { other.clone() })
++            },
+         }
+     }
+ }
+ 
+-impl<LengthType> ToAnimatedZero for SVGLength<LengthType> where LengthType : ToAnimatedZero {
++impl<L> ToAnimatedZero for SVGLength<L>
++where
++    L: ToAnimatedZero,
++{
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+-        match self {
+-            &SVGLength::Length(ref length) => length.to_animated_zero().map(SVGLength::Length),
+-            &SVGLength::ContextValue => Ok(SVGLength::ContextValue),
++        match *self {
++            SVGLength::Length(ref length) => {
++                Ok(SVGLength::Length(length.to_animated_zero()?))
++            },
++            SVGLength::ContextValue => Ok(SVGLength::ContextValue),
+         }
+     }
+ }
+ 
+ /// https://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty
+-impl<LengthType> Animatable for SVGStrokeDashArray<LengthType>
+-    where LengthType : RepeatableListAnimatable + Clone
++impl<L> Animate for SVGStrokeDashArray<L>
++where
++    L: Clone + RepeatableListAnimatable,
+ {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        match (self, other) {
+-            (&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other))=> {
+-                this.add_weighted(other, self_portion, other_portion)
+-                    .map(SVGStrokeDashArray::Values)
+-            }
+-            _ => {
+-                Ok(if self_portion > other_portion { self.clone() } else { other.clone() })
+-            }
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        if matches!(procedure, Procedure::Add | Procedure::Accumulate { .. }) {
++            // Non-additive.
++            return Err(());
+         }
+-    }
+-
+-    /// stroke-dasharray is non-additive
+-    #[inline]
+-    fn add(&self, _other: &Self) -> Result<Self, ()> {
+-        Err(())
+-    }
+-
+-    /// stroke-dasharray is non-additive
+-    #[inline]
+-    fn accumulate(&self, _other: &Self, _count: u64) -> Result<Self, ()> {
+-        Err(())
+-    }
+-}
+-
+-impl<LengthType> ToAnimatedZero for SVGStrokeDashArray<LengthType>
+-    where LengthType : ToAnimatedZero + Clone
+-{
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-        match self {
+-            &SVGStrokeDashArray::Values(ref values) => {
+-                values.iter().map(ToAnimatedZero::to_animated_zero)
+-                      .collect::<Result<Vec<_>, ()>>().map(SVGStrokeDashArray::Values)
+-            }
+-            &SVGStrokeDashArray::ContextValue => Ok(SVGStrokeDashArray::ContextValue),
++        match (self, other) {
++            (&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other)) => {
++                Ok(SVGStrokeDashArray::Values(this.animate(other, procedure)?))
++            },
++            _ => {
++                let (this_weight, other_weight) = procedure.weights();
++                Ok(if this_weight > other_weight { self.clone() } else { other.clone() })
++            },
+         }
+     }
+ }
+ 
+-impl<OpacityType> Animatable for SVGOpacity<OpacityType>
+-    where OpacityType: Animatable + Clone
++impl<L> ToAnimatedZero for SVGStrokeDashArray<L>
++where
++    L: Clone + ToAnimatedZero
+ {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn to_animated_zero(&self) -> Result<Self, ()> {
++        match *self {
++            SVGStrokeDashArray::Values(ref values) => {
++                Ok(SVGStrokeDashArray::Values(
++                    values.iter().map(ToAnimatedZero::to_animated_zero).collect::<Result<Vec<_>, _>>()?,
++                ))
++            }
++            SVGStrokeDashArray::ContextValue => Ok(SVGStrokeDashArray::ContextValue),
++        }
++    }
++}
++
++impl<O> Animate for SVGOpacity<O>
++where
++    O: Animate + Clone,
++{
++    #[inline]
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             (&SVGOpacity::Opacity(ref this), &SVGOpacity::Opacity(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion).map(SVGOpacity::Opacity)
+-            }
++                Ok(SVGOpacity::Opacity(this.animate(other, procedure)?))
++            },
+             _ => {
+-                Ok(if self_portion > other_portion { self.clone() } else { other.clone() })
+-            }
++                // FIXME(nox): Is this correct for addition and accumulation?
++                // I think an error should be returned if it's not
++                // an interpolation.
++                let (this_weight, other_weight) = procedure.weights();
++                Ok(if this_weight > other_weight { self.clone() } else { other.clone() })
++            },
+         }
+     }
+ }
+ 
+ impl<OpacityType> ToAnimatedZero for SVGOpacity<OpacityType>
+     where OpacityType: ToAnimatedZero + Clone
+ {
+     #[inline]
+@@ -2958,155 +2823,123 @@ impl<OpacityType> ToAnimatedZero for SVG
+ 
+ <%
+     FILTER_FUNCTIONS = [ 'Blur', 'Brightness', 'Contrast', 'Grayscale',
+                          'HueRotate', 'Invert', 'Opacity', 'Saturate',
+                          'Sepia' ]
+ %>
+ 
+ /// https://drafts.fxtf.org/filters/#animation-of-filters
+-fn add_weighted_filter_function_impl(from: &AnimatedFilter,
+-                                     to: &AnimatedFilter,
+-                                     self_portion: f64,
+-                                     other_portion: f64)
+-                                     -> Result<AnimatedFilter, ()> {
+-    match (from, to) {
+-        % for func in [ 'Blur', 'HueRotate' ]:
+-            (&Filter::${func}(from_value), &Filter::${func}(to_value)) => {
+-                Ok(Filter::${func}(from_value.add_weighted(
+-                    &to_value,
+-                    self_portion,
+-                    other_portion,
+-                )?))
+-           },
+-        % endfor
+-        % for func in [ 'Grayscale', 'Invert', 'Sepia' ]:
+-            (&Filter::${func}(from_value), &Filter::${func}(to_value)) => {
+-                Ok(Filter::${func}(add_weighted_with_initial_val(
+-                    &from_value,
+-                    &to_value,
+-                    self_portion,
+-                    other_portion,
+-                    &NonNegative::<CSSFloat>(0.0),
+-                )?))
++impl Animate for AnimatedFilter {
++    fn animate(
++        &self,
++        other: &Self,
++        procedure: Procedure,
++    ) -> Result<Self, ()> {
++        match (self, other) {
++            % for func in ['Blur', 'Grayscale', 'HueRotate', 'Invert', 'Sepia']:
++            (&Filter::${func}(ref this), &Filter::${func}(ref other)) => {
++                Ok(Filter::${func}(this.animate(other, procedure)?))
+             },
+-        % endfor
+-        % for func in [ 'Brightness', 'Contrast', 'Opacity', 'Saturate' ]:
+-            (&Filter::${func}(from_value), &Filter::${func}(to_value)) => {
+-                Ok(Filter::${func}(add_weighted_with_initial_val(
+-                    &from_value,
+-                    &to_value,
+-                    self_portion,
+-                    other_portion,
+-                    &NonNegative::<CSSFloat>(1.0),
+-                )?))
+-                },
+-        % endfor
+-        % if product == "gecko":
+-        (&Filter::DropShadow(ref from_value), &Filter::DropShadow(ref to_value)) => {
+-            Ok(Filter::DropShadow(from_value.add_weighted(
+-                &to_value,
+-                self_portion,
+-                other_portion,
+-            )?))
+-        },
+-        (&Filter::Url(_), &Filter::Url(_)) => {
+-            Err(())
+-        },
+-        % endif
+-        _ => {
+-            // If specified the different filter functions,
+-            // we will need to interpolate as discreate.
+-            Err(())
+-        },
+-    }
+-}
+-
+-/// https://drafts.fxtf.org/filters/#animation-of-filters
+-fn add_weighted_filter_function(from: Option<<&AnimatedFilter>,
+-                                to: Option<<&AnimatedFilter>,
+-                                self_portion: f64,
+-                                other_portion: f64) -> Result<AnimatedFilter, ()> {
+-    match (from, to) {
+-        (Some(f), Some(t)) => {
+-            add_weighted_filter_function_impl(f, t, self_portion, other_portion)
+-        },
+-        (Some(f), None) => {
+-            add_weighted_filter_function_impl(f, f, self_portion, 0.0)
+-        },
+-        (None, Some(t)) => {
+-            add_weighted_filter_function_impl(t, t, other_portion, 0.0)
+-        },
+-        _ => { Err(()) }
+-    }
+-}
+-
+-fn compute_filter_square_distance(from: &AnimatedFilter, to: &AnimatedFilter) -> Result<SquaredDistance, ()> {
+-    match (from, to) {
+-        % for func in FILTER_FUNCTIONS :
+-            (&Filter::${func}(f),
+-             &Filter::${func}(t)) => {
+-                Ok(try!(f.compute_squared_distance(&t)))
++            % endfor
++            % for func in ['Brightness', 'Contrast', 'Opacity', 'Saturate']:
++            (&Filter::${func}(ref this), &Filter::${func}(ref other)) => {
++                Ok(Filter::${func}(NonNegative(animate_multiplicative_factor(
++                    this.0,
++                    other.0,
++                    procedure,
++                )?)))
+             },
+-        % endfor
+-        % if product == "gecko":
+-            (&Filter::DropShadow(ref f), &Filter::DropShadow(ref t)) => {
+-                Ok(try!(f.compute_squared_distance(&t)))
++            % endfor
++            % if product == "gecko":
++            (&Filter::DropShadow(ref this), &Filter::DropShadow(ref other)) => {
++                Ok(Filter::DropShadow(this.animate(other, procedure)?))
+             },
+-        % endif
+-        _ => {
+-            Err(())
++            % endif
++            _ => Err(()),
+         }
+     }
+ }
+ 
+-impl Animatable for AnimatedFilterList {
+-    #[inline]
+-    fn add_weighted(&self, other: &Self,
+-                    self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        let mut filters = vec![];
+-        let mut from_iter = self.0.iter();
+-        let mut to_iter = other.0.iter();
++/// http://dev.w3.org/csswg/css-transforms/#none-transform-animation
++impl ToAnimatedZero for AnimatedFilter {
++    fn to_animated_zero(&self) -> Result<Self, ()> {
++        match *self {
++            % for func in ['Blur', 'Grayscale', 'HueRotate', 'Invert', 'Sepia']:
++            Filter::${func}(ref this) => Ok(Filter::${func}(this.to_animated_zero()?)),
++            % endfor
++            % for func in ['Brightness', 'Contrast', 'Opacity', 'Saturate']:
++            Filter::${func}(_) => Ok(Filter::${func}(NonNegative(1.))),
++            % endfor
++            % if product == "gecko":
++            Filter::DropShadow(ref this) => Ok(Filter::DropShadow(this.to_animated_zero()?)),
++            % endif
++            _ => Err(()),
++        }
++    }
++}
++
+ 
+-        let mut from = from_iter.next();
+-        let mut to = to_iter.next();
+-        while from.is_some() || to.is_some() {
+-            filters.push(try!(add_weighted_filter_function(from,
+-                                                           to,
+-                                                           self_portion,
+-                                                           other_portion)));
+-            if from.is_some() {
+-                from = from_iter.next();
++// FIXME(nox): This should be derived.
++impl ComputeSquaredDistance for AnimatedFilter {
++    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
++        match (self, other) {
++            % for func in FILTER_FUNCTIONS:
++            (&Filter::${func}(ref this), &Filter::${func}(ref other)) => {
++                this.compute_squared_distance(other)
++            },
++            % endfor
++            % if product == "gecko":
++            (&Filter::DropShadow(ref this), &Filter::DropShadow(ref other)) => {
++                this.compute_squared_distance(other)
++            },
++            % endif
++            _ => Err(()),
++        }
++    }
++}
++
++impl Animate for AnimatedFilterList {
++    #[inline]
++    fn animate(
++        &self,
++        other: &Self,
++        procedure: Procedure,
++    ) -> Result<Self, ()> {
++        if procedure == Procedure::Add {
++            return Ok(AnimatedFilterList(
++                self.0.iter().chain(other.0.iter()).cloned().collect(),
++            ));
++        }
++        Ok(AnimatedFilterList(self.0.iter().zip_longest(other.0.iter()).map(|it| {
++            match it {
++                EitherOrBoth::Both(this, other) => {
++                    this.animate(other, procedure)
++                },
++                EitherOrBoth::Left(this) => {
++                    this.animate(&this.to_animated_zero()?, procedure)
++                },
++                EitherOrBoth::Right(other) => {
++                    other.to_animated_zero()?.animate(other, procedure)
++                },
+             }
+-            if to.is_some() {
+-                to = to_iter.next();
+-            }
+-        }
+-
+-        Ok(AnimatedFilterList(filters))
+-    }
+-
+-    fn add(&self, other: &Self) -> Result<Self, ()> {
+-        Ok(AnimatedFilterList(self.0.iter().chain(other.0.iter()).cloned().collect()))
++        }).collect::<Result<Vec<_>, _>>()?))
+     }
+ }
+ 
+ impl ComputeSquaredDistance for AnimatedFilterList {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+-        use itertools::{EitherOrBoth, Itertools};
+-
+         self.0.iter().zip_longest(other.0.iter()).map(|it| {
+             match it {
+-                EitherOrBoth::Both(from, to) => {
+-                    compute_filter_square_distance(&from, &to)
++                EitherOrBoth::Both(this, other) => {
++                    this.compute_squared_distance(other)
+                 },
+-                EitherOrBoth::Left(list) | EitherOrBoth::Right(list)=> {
+-                    let none = add_weighted_filter_function(Some(list), Some(list), 0.0, 0.0)?;
+-                    compute_filter_square_distance(&none, &list)
++                EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => {
++                    list.to_animated_zero()?.compute_squared_distance(list)
+                 },
+             }
+         }).sum()
+     }
+ }
+ 
+ /// A comparator to sort PropertyIds such that longhands are sorted before shorthands,
+ /// shorthands with fewer components are sorted before shorthands with more components,
+@@ -3156,40 +2989,42 @@ sorted_shorthands = [(p, position) for p
+ %>
+     match *shorthand {
+         % for property, position in sorted_shorthands:
+             ShorthandId::${property.camel_case} => ${position},
+         % endfor
+     }
+ }
+ 
+-impl<T> Animatable for NonNegative<T>
+-    where T: Animatable + Clone
++impl<T> Animate for NonNegative<T>
++where
++    T: Animate,
+ {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        self.0.add_weighted(&other.0, self_portion, other_portion).map(NonNegative::<T>)
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(NonNegative(self.0.animate(&other.0, procedure)?))
+     }
+ }
+ 
+ impl<T> ToAnimatedZero for NonNegative<T>
+     where T: ToAnimatedZero
+ {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         self.0.to_animated_zero().map(NonNegative::<T>)
+     }
+ }
+ 
+-impl<T> Animatable for GreaterThanOrEqualToOne<T>
+-    where T: Animatable + Clone
++impl<T> Animate for GreaterThanOrEqualToOne<T>
++where
++    T: Animate,
+ {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        self.0.add_weighted(&other.0, self_portion, other_portion).map(GreaterThanOrEqualToOne::<T>)
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(GreaterThanOrEqualToOne(self.0.animate(&other.0, procedure)?))
+     }
+ }
+ 
+ impl<T> ToAnimatedZero for GreaterThanOrEqualToOne<T>
+     where T: ToAnimatedZero
+ {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+diff --git a/servo/components/style/properties/longhand/font.mako.rs b/servo/components/style/properties/longhand/font.mako.rs
+--- a/servo/components/style/properties/longhand/font.mako.rs
++++ b/servo/components/style/properties/longhand/font.mako.rs
+@@ -1110,19 +1110,18 @@ macro_rules! impl_gecko_keyword_conversi
+                 Some(s)
+             } else {
+                 None
+             }
+         }
+     }
+ 
+     pub mod computed_value {
+-        use properties::animated_properties::Animatable;
+         use values::CSSFloat;
+-        use values::animated::{ToAnimatedValue, ToAnimatedZero};
++        use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
+         use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ 
+         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+         #[derive(Copy, Clone, Debug, PartialEq, ToCss)]
+         pub enum T {
+             None,
+             Number(CSSFloat),
+         }
+@@ -1132,22 +1131,22 @@ macro_rules! impl_gecko_keyword_conversi
+                 if gecko == -1.0 {
+                     T::None
+                 } else {
+                     T::Number(gecko)
+                 }
+             }
+         }
+ 
+-        impl Animatable for T {
+-            fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
+-                -> Result<Self, ()> {
+-                match (*self, *other) {
+-                    (T::Number(ref number), T::Number(ref other)) =>
+-                        Ok(T::Number(number.add_weighted(other, self_portion, other_portion)?)),
++        impl Animate for T {
++            fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++                match (self, other) {
++                    (&T::Number(ref number), &T::Number(ref other)) => {
++                        Ok(T::Number(number.animate(other, procedure)?))
++                    },
+                     _ => Err(()),
+                 }
+             }
+         }
+ 
+         impl ComputeSquaredDistance for T {
+             #[inline]
+             fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+diff --git a/servo/components/style/properties/longhand/inherited_table.mako.rs b/servo/components/style/properties/longhand/inherited_table.mako.rs
+--- a/servo/components/style/properties/longhand/inherited_table.mako.rs
++++ b/servo/components/style/properties/longhand/inherited_table.mako.rs
+@@ -21,37 +21,33 @@
+                          spec="https://drafts.csswg.org/css-tables/#propdef-caption-side")}
+ 
+ <%helpers:longhand name="border-spacing" animation_value_type="BorderSpacing" boxed="True"
+                    spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing">
+     use values::specified::{AllowQuirks, Length};
+     use values::specified::length::NonNegativeLength;
+ 
+     pub mod computed_value {
+-        use properties::animated_properties::Animatable;
+-        use values::animated::{ToAnimatedValue, ToAnimatedZero};
++        use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
+         use values::computed::NonNegativeAu;
+ 
+         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+         #[derive(Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)]
+         pub struct T {
+             pub horizontal: NonNegativeAu,
+             pub vertical: NonNegativeAu,
+         }
+ 
+         /// https://drafts.csswg.org/css-transitions/#animtype-simple-list
+-        impl Animatable for T {
++        impl Animate for T {
+             #[inline]
+-            fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
+-                -> Result<Self, ()> {
++            fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+                 Ok(T {
+-                    horizontal: self.horizontal.add_weighted(&other.horizontal,
+-                                                             self_portion, other_portion)?,
+-                    vertical: self.vertical.add_weighted(&other.vertical,
+-                                                         self_portion, other_portion)?,
++                    horizontal: self.horizontal.animate(&other.horizontal, procedure)?,
++                    vertical: self.vertical.animate(&other.vertical, procedure)?,
+                 })
+             }
+         }
+ 
+         impl ToAnimatedZero for T {
+             #[inline]
+             fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+         }
+diff --git a/servo/components/style/values/animated/color.rs b/servo/components/style/values/animated/color.rs
+--- a/servo/components/style/values/animated/color.rs
++++ b/servo/components/style/values/animated/color.rs
+@@ -1,16 +1,15 @@
+ /* 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/. */
+ 
+ //! Animated types for CSS colors.
+ 
+-use properties::animated_properties::Animatable;
+-use values::animated::ToAnimatedZero;
++use values::animated::{Animate, Procedure, ToAnimatedZero};
+ use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ 
+ /// An animated RGBA color.
+ ///
+ /// Unlike in computed values, each component value may exceed the
+ /// range `[0.0, 1.0]`.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ #[derive(Clone, Copy, Debug, PartialEq)]
+@@ -34,39 +33,33 @@ impl RGBA {
+ 
+     /// Returns a new color.
+     #[inline]
+     pub fn new(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
+         RGBA { red: red, green: green, blue: blue, alpha: alpha }
+     }
+ }
+ 
+-/// Unlike Animatable for computed colors, we don't clamp any component values.
++/// Unlike Animate for computed colors, we don't clamp any component values.
+ ///
+-/// FIXME(nox): Why do computed colors even implement Animatable?
+-impl Animatable for RGBA {
++/// FIXME(nox): Why do computed colors even implement Animate?
++impl Animate for RGBA {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        let mut alpha = self.alpha.add_weighted(&other.alpha, self_portion, other_portion)?;
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        let mut alpha = self.alpha.animate(&other.alpha, procedure)?;
+         if alpha <= 0. {
+             // Ideally we should return color value that only alpha component is
+             // 0, but this is what current gecko does.
+             return Ok(RGBA::transparent());
+         }
+ 
+         alpha = alpha.min(1.);
+-        let red = (self.red * self.alpha).add_weighted(
+-            &(other.red * other.alpha), self_portion, other_portion
+-        )? * 1. / alpha;
+-        let green = (self.green * self.alpha).add_weighted(
+-            &(other.green * other.alpha), self_portion, other_portion
+-        )? * 1. / alpha;
+-        let blue = (self.blue * self.alpha).add_weighted(
+-            &(other.blue * other.alpha), self_portion, other_portion
+-        )? * 1. / alpha;
++        let red = (self.red * self.alpha).animate(&(other.red * other.alpha), procedure)? * 1. / alpha;
++        let green = (self.green * self.alpha).animate(&(other.green * other.alpha), procedure)? * 1. / alpha;
++        let blue = (self.blue * self.alpha).animate(&(other.blue * other.alpha), procedure)? * 1. / alpha;
+ 
+         Ok(RGBA::new(red, green, blue, alpha))
+     }
+ }
+ 
+ impl ComputeSquaredDistance for RGBA {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+@@ -118,71 +111,71 @@ impl Color {
+     fn effective_intermediate_rgba(&self) -> RGBA {
+         RGBA {
+             alpha: self.color.alpha * (1. - self.foreground_ratio),
+             .. self.color
+         }
+     }
+ }
+ 
+-impl Animatable for Color {
++impl Animate for Color {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         // Common cases are interpolating between two numeric colors,
+         // two currentcolors, and a numeric color and a currentcolor.
+         //
+         // Note: this algorithm assumes self_portion + other_portion
+         // equals to one, so it may be broken for additive operation.
+         // To properly support additive color interpolation, we would
+         // need two ratio fields in computed color types.
++        let (this_weight, other_weight) = procedure.weights();
+         if self.foreground_ratio == other.foreground_ratio {
+             if self.is_currentcolor() {
+                 Ok(Color::currentcolor())
+             } else {
+                 Ok(Color {
+-                    color: self.color.add_weighted(&other.color, self_portion, other_portion)?,
++                    color: self.color.animate(&other.color, procedure)?,
+                     foreground_ratio: self.foreground_ratio,
+                 })
+             }
+         } else if self.is_currentcolor() && other.is_numeric() {
+             Ok(Color {
+                 color: other.color,
+-                foreground_ratio: self_portion as f32,
++                foreground_ratio: this_weight as f32,
+             })
+         } else if self.is_numeric() && other.is_currentcolor() {
+             Ok(Color {
+                 color: self.color,
+-                foreground_ratio: other_portion as f32,
++                foreground_ratio: other_weight as f32,
+             })
+         } else {
+             // For interpolating between two complex colors, we need to
+             // generate colors with effective alpha value.
+             let self_color = self.effective_intermediate_rgba();
+             let other_color = other.effective_intermediate_rgba();
+-            let color = self_color.add_weighted(&other_color, self_portion, other_portion)?;
++            let color = self_color.animate(&other_color, procedure)?;
+             // Then we compute the final foreground ratio, and derive
+             // the final alpha value from the effective alpha value.
+-            let foreground_ratio = self.foreground_ratio
+-                .add_weighted(&other.foreground_ratio, self_portion, other_portion)?;
++            let foreground_ratio = self.foreground_ratio.animate(&other.foreground_ratio, procedure)?;
+             let alpha = color.alpha / (1. - foreground_ratio);
+             Ok(Color {
+                 color: RGBA {
+                     alpha: alpha,
+                     .. color
+                 },
+                 foreground_ratio: foreground_ratio,
+             })
+         }
+     }
+ }
+ 
+ impl ComputeSquaredDistance for Color {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+-        // All comments in add_weighted also applies here.
++        // All comments from the Animate impl also applies here.
+         if self.foreground_ratio == other.foreground_ratio {
+             if self.is_currentcolor() {
+                 Ok(SquaredDistance::Value(0.))
+             } else {
+                 self.color.compute_squared_distance(&other.color)
+             }
+         } else if self.is_currentcolor() && other.is_numeric() {
+             Ok(
+diff --git a/servo/components/style/values/animated/effects.rs b/servo/components/style/values/animated/effects.rs
+--- a/servo/components/style/values/animated/effects.rs
++++ b/servo/components/style/values/animated/effects.rs
+@@ -1,22 +1,21 @@
+ /* 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/. */
+ 
+ //! Animated types for CSS values related to effects.
+ 
+-use properties::animated_properties::Animatable;
+ use properties::longhands::box_shadow::computed_value::T as ComputedBoxShadowList;
+ use properties::longhands::filter::computed_value::T as ComputedFilterList;
+ use properties::longhands::text_shadow::computed_value::T as ComputedTextShadowList;
+ use std::cmp;
+ #[cfg(not(feature = "gecko"))]
+ use values::Impossible;
+-use values::animated::{ToAnimatedValue, ToAnimatedZero};
++use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
+ use values::animated::color::RGBA;
+ use values::computed::{Angle, NonNegativeNumber};
+ use values::computed::length::{Length, NonNegativeLength};
+ use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ use values::generics::effects::BoxShadow as GenericBoxShadow;
+ use values::generics::effects::Filter as GenericFilter;
+ use values::generics::effects::SimpleShadow as GenericSimpleShadow;
+ 
+@@ -61,52 +60,46 @@ impl ToAnimatedValue for ComputedBoxShad
+     }
+ 
+     #[inline]
+     fn from_animated_value(animated: Self::AnimatedValue) -> Self {
+         ComputedBoxShadowList(ToAnimatedValue::from_animated_value(animated.0))
+     }
+ }
+ 
+-impl<S> Animatable for ShadowList<S>
++impl<S> Animate for ShadowList<S>
+ where
+-    S: Animatable + Clone + ToAnimatedZero,
++    S: Animate + Clone + ToAnimatedZero,
+ {
+     #[inline]
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        if procedure == Procedure::Add {
++            return Ok(ShadowList(
++                self.0.iter().chain(&other.0).cloned().collect(),
++            ));
++        }
++        // FIXME(nox): Use itertools here, to avoid the need for `unreachable!`.
+         let max_len = cmp::max(self.0.len(), other.0.len());
+         let mut shadows = Vec::with_capacity(max_len);
+         for i in 0..max_len {
+             shadows.push(match (self.0.get(i), other.0.get(i)) {
+                 (Some(shadow), Some(other)) => {
+-                    shadow.add_weighted(other, self_portion, other_portion)?
++                    shadow.animate(other, procedure)?
+                 },
+                 (Some(shadow), None) => {
+-                    shadow.add_weighted(&shadow.to_animated_zero()?, self_portion, other_portion)?
++                    shadow.animate(&shadow.to_animated_zero()?, procedure)?
+                 },
+                 (None, Some(shadow)) => {
+-                    shadow.to_animated_zero()?.add_weighted(&shadow, self_portion, other_portion)?
++                    shadow.to_animated_zero()?.animate(shadow, procedure)?
+                 },
+                 (None, None) => unreachable!(),
+             });
+         }
+         Ok(ShadowList(shadows))
+     }
+-
+-    #[inline]
+-    fn add(&self, other: &Self) -> Result<Self, ()> {
+-        Ok(ShadowList(
+-            self.0.iter().cloned().chain(other.0.iter().cloned()).collect(),
+-        ))
+-    }
+ }
+ 
+ impl<S> ComputeSquaredDistance for ShadowList<S>
+ where
+     S: ComputeSquaredDistance + ToAnimatedZero,
+ {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+@@ -141,30 +134,25 @@ impl ToAnimatedValue for ComputedTextSha
+     }
+ 
+     #[inline]
+     fn from_animated_value(animated: Self::AnimatedValue) -> Self {
+         ComputedTextShadowList(ToAnimatedValue::from_animated_value(animated.0))
+     }
+ }
+ 
+-impl Animatable for BoxShadow {
++impl Animate for BoxShadow {
+     #[inline]
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         if self.inset != other.inset {
+             return Err(());
+         }
+         Ok(BoxShadow {
+-            base: self.base.add_weighted(&other.base, self_portion, other_portion)?,
+-            spread: self.spread.add_weighted(&other.spread, self_portion, other_portion)?,
++            base: self.base.animate(&other.base, procedure)?,
++            spread: self.spread.animate(&other.spread, procedure)?,
+             inset: self.inset,
+         })
+     }
+ }
+ 
+ impl ComputeSquaredDistance for BoxShadow {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+@@ -219,36 +207,31 @@ impl ToAnimatedValue for ComputedFilterL
+ 
+ impl ToAnimatedZero for FilterList {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         Ok(FilterList(vec![]))
+     }
+ }
+ 
+-impl Animatable for SimpleShadow {
++impl Animate for SimpleShadow {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        let color = self.color.add_weighted(&other.color, self_portion, other_portion)?;
+-        let horizontal = self.horizontal.add_weighted(&other.horizontal, self_portion, other_portion)?;
+-        let vertical = self.vertical.add_weighted(&other.vertical, self_portion, other_portion)?;
+-        let blur = self.blur.add_weighted(&other.blur, self_portion, other_portion)?;
+-
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(SimpleShadow {
+-            color: color,
+-            horizontal: horizontal,
+-            vertical: vertical,
+-            blur: blur,
++            color: self.color.animate(&other.color, procedure)?,
++            horizontal: self.horizontal.animate(&other.horizontal, procedure)?,
++            vertical: self.vertical.animate(&other.vertical, procedure)?,
++            blur: self.blur.animate(&other.blur, procedure)?,
+         })
+     }
+ }
+ 
+ impl ToAnimatedZero for SimpleShadow {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         Ok(SimpleShadow {
+-            color: Some(RGBA::transparent()),
++            color: self.color.to_animated_zero()?,
+             horizontal: self.horizontal.to_animated_zero()?,
+             vertical: self.vertical.to_animated_zero()?,
+             blur: self.blur.to_animated_zero()?,
+         })
+     }
+ }
+diff --git a/servo/components/style/values/animated/mod.rs b/servo/components/style/values/animated/mod.rs
+--- a/servo/components/style/values/animated/mod.rs
++++ b/servo/components/style/values/animated/mod.rs
+@@ -4,16 +4,17 @@
+ 
+ //! Animated values.
+ //!
+ //! Some values, notably colors, cannot be interpolated directly with their
+ //! computed values and need yet another intermediate representation. This
+ //! module's raison d'être is to ultimately contain all these types.
+ 
+ use app_units::Au;
++use euclid::{Point2D, Size2D};
+ use smallvec::SmallVec;
+ use std::cmp::max;
+ use values::computed::Angle as ComputedAngle;
+ use values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
+ #[cfg(feature = "servo")]
+ use values::computed::ComputedUrl;
+ use values::computed::GreaterThanOrEqualToOneNumber as ComputedGreaterThanOrEqualToOneNumber;
+ use values::computed::MaxLength as ComputedMaxLength;
+@@ -22,30 +23,152 @@ use values::computed::NonNegativeAu;
+ use values::computed::NonNegativeLengthOrPercentage as ComputedNonNegativeLengthOrPercentage;
+ use values::computed::NonNegativeNumber as ComputedNonNegativeNumber;
+ use values::computed::PositiveInteger as ComputedPositiveInteger;
+ use values::specified::url::SpecifiedUrl;
+ 
+ pub mod color;
+ pub mod effects;
+ 
++/// Animating from one value to another.
++pub trait Animate: Sized {
++    /// Animate a value towards another one, given an animation procedure.
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>;
++}
++
++/// An animation procedure.
++///
++/// https://w3c.github.io/web-animations/#procedures-for-animating-properties
++#[allow(missing_docs)]
++#[derive(Clone, Copy, Debug, PartialEq)]
++pub enum Procedure {
++    /// https://w3c.github.io/web-animations/#animation-interpolation
++    Interpolate { progress: f64 },
++    /// https://w3c.github.io/web-animations/#animation-addition
++    Add,
++    /// https://w3c.github.io/web-animations/#animation-accumulation
++    Accumulate { count: u64 },
++}
++
+ /// Conversion between computed values and intermediate values for animations.
+ ///
+ /// Notably, colors are represented as four floats during animations.
+ pub trait ToAnimatedValue {
+     /// The type of the animated value.
+     type AnimatedValue;
+ 
+     /// Converts this value to an animated value.
+     fn to_animated_value(self) -> Self::AnimatedValue;
+ 
+     /// Converts back an animated value into a computed value.
+     fn from_animated_value(animated: Self::AnimatedValue) -> Self;
+ }
+ 
++/// Marker trait for computed values with the same representation during animations.
++pub trait AnimatedValueAsComputed {}
++
++/// Returns a value similar to `self` that represents zero.
++pub trait ToAnimatedZero: Sized {
++    /// Returns a value that, when added with an underlying value, will produce the underlying
++    /// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from
++    /// the zero value to the 'by' value, and then adds the result to the underlying value.
++    ///
++    /// This is not the necessarily the same as the initial value of a property. For example, the
++    /// initial value of 'stroke-width' is 1, but the zero value is 0, since adding 1 to the
++    /// underlying value will not produce the underlying value.
++    fn to_animated_zero(&self) -> Result<Self, ()>;
++}
++
++impl Procedure {
++    /// Returns this procedure as a pair of weights.
++    ///
++    /// This is useful for animations that don't animate differently
++    /// depending on the used procedure.
++    #[inline]
++    pub fn weights(self) -> (f64, f64) {
++        match self {
++            Procedure::Interpolate { progress } => (1. - progress, progress),
++            Procedure::Add => (1., 1.),
++            Procedure::Accumulate { count } => (count as f64, 1.),
++        }
++    }
++}
++
++/// https://drafts.csswg.org/css-transitions/#animtype-number
++impl Animate for i32 {
++    #[inline]
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(((*self as f64).animate(&(*other as f64), procedure)? + 0.5).floor() as i32)
++    }
++}
++
++/// https://drafts.csswg.org/css-transitions/#animtype-number
++impl Animate for f32 {
++    #[inline]
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok((*self as f64).animate(&(*other as f64), procedure)? as f32)
++    }
++}
++
++/// https://drafts.csswg.org/css-transitions/#animtype-number
++impl Animate for f64 {
++    #[inline]
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        let (self_weight, other_weight) = procedure.weights();
++        Ok(*self * self_weight + *other * other_weight)
++    }
++}
++
++impl<T> Animate for Option<T>
++where
++    T: Animate,
++{
++    #[inline]
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        match (self.as_ref(), other.as_ref()) {
++            (Some(ref this), Some(ref other)) => Ok(Some(this.animate(other, procedure)?)),
++            (None, None) => Ok(None),
++            _ => Err(()),
++        }
++    }
++}
++
++impl Animate for Au {
++    #[inline]
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(Au(self.0.animate(&other.0, procedure)?))
++    }
++}
++
++impl<T> Animate for Size2D<T>
++where
++    T: Animate + Copy,
++{
++    #[inline]
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(Size2D::new(
++            self.width.animate(&other.width, procedure)?,
++            self.height.animate(&other.height, procedure)?,
++        ))
++    }
++}
++
++impl<T> Animate for Point2D<T>
++where
++    T: Animate + Copy,
++{
++    #[inline]
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(Point2D::new(
++            self.x.animate(&other.x, procedure)?,
++            self.y.animate(&other.y, procedure)?,
++        ))
++    }
++}
++
+ impl<T> ToAnimatedValue for Option<T>
+ where
+     T: ToAnimatedValue,
+ {
+     type AnimatedValue = Option<<T as ToAnimatedValue>::AnimatedValue>;
+ 
+     #[inline]
+     fn to_animated_value(self) -> Self::AnimatedValue {
+@@ -87,19 +210,16 @@ where
+     }
+ 
+     #[inline]
+     fn from_animated_value(animated: Self::AnimatedValue) -> Self {
+         animated.into_iter().map(T::from_animated_value).collect()
+     }
+ }
+ 
+-/// Marker trait for computed values with the same representation during animations.
+-pub trait AnimatedValueAsComputed {}
+-
+ impl AnimatedValueAsComputed for Au {}
+ impl AnimatedValueAsComputed for ComputedAngle {}
+ impl AnimatedValueAsComputed for SpecifiedUrl {}
+ #[cfg(feature = "servo")]
+ impl AnimatedValueAsComputed for ComputedUrl {}
+ impl AnimatedValueAsComputed for bool {}
+ impl AnimatedValueAsComputed for f32 {}
+ 
+@@ -258,28 +378,16 @@ impl ToAnimatedValue for ComputedMozLeng
+                 };
+                 ComputedMozLength::LengthOrPercentageOrAuto(result)
+             },
+             _ => animated
+         }
+     }
+ }
+ 
+-/// Returns a value similar to `self` that represents zero.
+-pub trait ToAnimatedZero: Sized {
+-    /// Returns a value that, when added with an underlying value, will produce the underlying
+-    /// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from
+-    /// the zero value to the 'by' value, and then adds the result to the underlying value.
+-    ///
+-    /// This is not the necessarily the same as the initial value of a property. For example, the
+-    /// initial value of 'stroke-width' is 1, but the zero value is 0, since adding 1 to the
+-    /// underlying value will not produce the underlying value.
+-    fn to_animated_zero(&self) -> Result<Self, ()>;
+-}
+-
+ impl ToAnimatedZero for Au {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> { Ok(Au(0)) }
+ }
+ 
+ impl ToAnimatedZero for f32 {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> { Ok(0.) }
+@@ -289,8 +397,21 @@ impl ToAnimatedZero for f64 {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> { Ok(0.) }
+ }
+ 
+ impl ToAnimatedZero for i32 {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> { Ok(0) }
+ }
++
++impl<T> ToAnimatedZero for Option<T>
++where
++    T: ToAnimatedZero,
++{
++    #[inline]
++    fn to_animated_zero(&self) -> Result<Self, ()> {
++        match *self {
++            Some(ref value) => Ok(Some(value.to_animated_zero()?)),
++            None => Ok(None),
++        }
++    }
++}
+diff --git a/servo/components/style/values/computed/angle.rs b/servo/components/style/values/computed/angle.rs
+--- a/servo/components/style/values/computed/angle.rs
++++ b/servo/components/style/values/computed/angle.rs
+@@ -1,19 +1,19 @@
+ /* 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/. */
+ 
+ //! Computed angles.
+ 
+-use properties::animated_properties::Animatable;
+ use std::{f32, f64, fmt};
+ use std::f64::consts::PI;
+ use style_traits::ToCss;
+ use values::CSSFloat;
++use values::animated::{Animate, Procedure, ToAnimatedZero};
+ use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ 
+ /// A computed angle.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
+ #[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, PartialOrd)]
+ pub enum Angle {
+     /// An angle with degree unit.
+     Degree(CSSFloat),
+@@ -60,34 +60,44 @@ impl Angle {
+ 
+     /// Returns an angle that represents a rotation of zero radians.
+     pub fn zero() -> Self {
+         Angle::Radian(0.0)
+     }
+ }
+ 
+ /// https://drafts.csswg.org/css-transitions/#animtype-number
+-impl Animatable for Angle {
++impl Animate for Angle {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             (&Angle::Degree(ref this), &Angle::Degree(ref other)) => {
+-                Ok(Angle::Degree(this.add_weighted(other, self_portion, other_portion)?))
++                Ok(Angle::Degree(this.animate(other, procedure)?))
+             },
+             (&Angle::Gradian(ref this), &Angle::Gradian(ref other)) => {
+-                Ok(Angle::Gradian(this.add_weighted(other, self_portion, other_portion)?))
++                Ok(Angle::Gradian(this.animate(other, procedure)?))
+             },
+             (&Angle::Turn(ref this), &Angle::Turn(ref other)) => {
+-                Ok(Angle::Turn(this.add_weighted(other, self_portion, other_portion)?))
++                Ok(Angle::Turn(this.animate(other, procedure)?))
+             },
+             _ => {
+-                self.radians()
+-                    .add_weighted(&other.radians(), self_portion, other_portion)
+-                    .map(Angle::from_radians)
+-            }
++                Ok(Angle::from_radians(self.radians().animate(&other.radians(), procedure)?))
++            },
++        }
++    }
++}
++
++impl ToAnimatedZero for Angle {
++    #[inline]
++    fn to_animated_zero(&self) -> Result<Angle, ()> {
++        match *self {
++            Angle::Degree(ref this) => Ok(Angle::Degree(this.to_animated_zero()?)),
++            Angle::Gradian(ref this) => Ok(Angle::Gradian(this.to_animated_zero()?)),
++            Angle::Radian(ref this) => Ok(Angle::Radian(this.to_animated_zero()?)),
++            Angle::Turn(ref this) => Ok(Angle::Turn(this.to_animated_zero()?)),
+         }
+     }
+ }
+ 
+ impl ComputeSquaredDistance for Angle {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+         // Use the formula for calculating the distance between angles defined in SVG:
+diff --git a/servo/components/style/values/computed/background.rs b/servo/components/style/values/computed/background.rs
+--- a/servo/components/style/values/computed/background.rs
++++ b/servo/components/style/values/computed/background.rs
+@@ -1,35 +1,35 @@
+ /* 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/. */
+ 
+ //! Computed types for CSS values related to backgrounds.
+ 
+-use properties::animated_properties::{Animatable, RepeatableListAnimatable};
++use properties::animated_properties::RepeatableListAnimatable;
+ use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
+-use values::animated::{ToAnimatedValue, ToAnimatedZero};
++use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
+ use values::computed::length::LengthOrPercentageOrAuto;
+ use values::generics::background::BackgroundSize as GenericBackgroundSize;
+ 
+ /// A computed value for the `background-size` property.
+ pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>;
+ 
+ impl RepeatableListAnimatable for BackgroundSize {}
+ 
+-impl Animatable for BackgroundSize {
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++impl Animate for BackgroundSize {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             (
+                 &GenericBackgroundSize::Explicit { width: self_width, height: self_height },
+                 &GenericBackgroundSize::Explicit { width: other_width, height: other_height },
+             ) => {
+                 Ok(GenericBackgroundSize::Explicit {
+-                    width: self_width.add_weighted(&other_width, self_portion, other_portion)?,
+-                    height: self_height.add_weighted(&other_height, self_portion, other_portion)?,
++                    width: self_width.animate(&other_width, procedure)?,
++                    height: self_height.animate(&other_height, procedure)?,
+                 })
+             }
+             _ => Err(()),
+         }
+     }
+ }
+ 
+ impl ToAnimatedZero for BackgroundSize {
+diff --git a/servo/components/style/values/computed/length.rs b/servo/components/style/values/computed/length.rs
+--- a/servo/components/style/values/computed/length.rs
++++ b/servo/components/style/values/computed/length.rs
+@@ -6,16 +6,17 @@
+ 
+ use app_units::{Au, AU_PER_PX};
+ use ordered_float::NotNaN;
+ use std::fmt;
+ use style_traits::ToCss;
+ use style_traits::values::specified::AllowedLengthType;
+ use super::{Number, ToComputedValue, Context, Percentage};
+ use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
++use values::animated::ToAnimatedZero;
+ use values::computed::{NonNegativeAu, NonNegativeNumber};
+ use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ use values::generics::NonNegative;
+ use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength};
+ use values::specified::length::ViewportPercentageLength;
+ 
+ pub use super::image::Image;
+ pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
+@@ -67,16 +68,27 @@ impl ToComputedValue for specified::Leng
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ #[allow(missing_docs)]
+ pub struct CalcLengthOrPercentage {
+     pub clamping_mode: AllowedLengthType,
+     length: Au,
+     pub percentage: Option<Percentage>,
+ }
+ 
++impl ToAnimatedZero for CalcLengthOrPercentage {
++    #[inline]
++    fn to_animated_zero(&self) -> Result<Self, ()> {
++        Ok(CalcLengthOrPercentage {
++            clamping_mode: self.clamping_mode,
++            length: self.length.to_animated_zero()?,
++            percentage: self.percentage.to_animated_zero()?,
++        })
++    }
++}
++
+ impl ComputeSquaredDistance for CalcLengthOrPercentage {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+         // FIXME(nox): This looks incorrect to me, to add a distance between lengths
+         // with a distance between percentages.
+         Ok(
+             self.unclamped_length().to_f64_px().compute_squared_distance(
+                 &other.unclamped_length().to_f64_px())? +
+diff --git a/servo/components/style/values/computed/percentage.rs b/servo/components/style/values/computed/percentage.rs
+--- a/servo/components/style/values/computed/percentage.rs
++++ b/servo/components/style/values/computed/percentage.rs
+@@ -1,19 +1,18 @@
+ /* 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/. */
+ 
+ //! Computed percentages.
+ 
+-use properties::animated_properties::Animatable;
+ use std::fmt;
+ use style_traits::ToCss;
+ use values::{CSSFloat, serialize_percentage};
+-use values::animated::ToAnimatedZero;
++use values::animated::{Animate, Procedure, ToAnimatedZero};
+ 
+ /// A computed percentage.
+ #[derive(Clone, ComputeSquaredDistance, Copy, Debug, Default, HasViewportPercentage, PartialEq, PartialOrd)]
+ #[cfg_attr(feature = "servo", derive(Deserialize, HeapSizeOf, Serialize))]
+ pub struct Percentage(pub CSSFloat);
+ 
+ impl Percentage {
+     /// 0%
+@@ -31,20 +30,20 @@ impl Percentage {
+     /// Returns the absolute value for this percentage.
+     #[inline]
+     pub fn abs(&self) -> Self {
+         Percentage(self.0.abs())
+     }
+ }
+ 
+ /// https://drafts.csswg.org/css-transitions/#animtype-percentage
+-impl Animatable for Percentage {
++impl Animate for Percentage {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        Ok(Percentage((self.0 as f64 * self_portion + other.0 as f64 * other_portion) as f32))
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(Percentage(self.0.animate(&other.0, procedure)?))
+     }
+ }
+ 
+ impl ToAnimatedZero for Percentage {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         Ok(Percentage(0.))
+     }
+diff --git a/servo/components/style/values/computed/text.rs b/servo/components/style/values/computed/text.rs
+--- a/servo/components/style/values/computed/text.rs
++++ b/servo/components/style/values/computed/text.rs
+@@ -1,17 +1,16 @@
+ /* 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/. */
+ 
+ //! Computed types for text properties.
+ 
+-use properties::animated_properties::Animatable;
+ use values::{CSSInteger, CSSFloat};
+-use values::animated::ToAnimatedZero;
++use values::animated::{Animate, Procedure, ToAnimatedZero};
+ use values::computed::{NonNegativeAu, NonNegativeNumber};
+ use values::computed::length::{Length, LengthOrPercentage};
+ use values::generics::text::InitialLetter as GenericInitialLetter;
+ use values::generics::text::LineHeight as GenericLineHeight;
+ use values::generics::text::Spacing;
+ 
+ /// A computed value for the `initial-letter` property.
+ pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
+@@ -20,31 +19,31 @@ pub type InitialLetter = GenericInitialL
+ pub type LetterSpacing = Spacing<Length>;
+ 
+ /// A computed value for the `word-spacing` property.
+ pub type WordSpacing = Spacing<LengthOrPercentage>;
+ 
+ /// A computed value for the `line-height` property.
+ pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeAu>;
+ 
+-impl Animatable for LineHeight {
++impl Animate for LineHeight {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+-        match (*self, *other) {
+-            (GenericLineHeight::Length(ref this), GenericLineHeight::Length(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion).map(GenericLineHeight::Length)
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        match (self, other) {
++            (&GenericLineHeight::Length(ref this), &GenericLineHeight::Length(ref other)) => {
++                Ok(GenericLineHeight::Length(this.animate(other, procedure)?))
+             },
+-            (GenericLineHeight::Number(ref this), GenericLineHeight::Number(ref other)) => {
+-                this.add_weighted(other, self_portion, other_portion).map(GenericLineHeight::Number)
++            (&GenericLineHeight::Number(ref this), &GenericLineHeight::Number(ref other)) => {
++                Ok(GenericLineHeight::Number(this.animate(other, procedure)?))
+             },
+-            (GenericLineHeight::Normal, GenericLineHeight::Normal) => {
++            (&GenericLineHeight::Normal, &GenericLineHeight::Normal) => {
+                 Ok(GenericLineHeight::Normal)
+             },
+             #[cfg(feature = "gecko")]
+-            (GenericLineHeight::MozBlockHeight, GenericLineHeight::MozBlockHeight) => {
++            (&GenericLineHeight::MozBlockHeight, &GenericLineHeight::MozBlockHeight) => {
+                 Ok(GenericLineHeight::MozBlockHeight)
+             },
+             _ => Err(()),
+         }
+     }
+ }
+ 
+ impl ToAnimatedZero for LineHeight {
+diff --git a/servo/components/style/values/computed/transform.rs b/servo/components/style/values/computed/transform.rs
+--- a/servo/components/style/values/computed/transform.rs
++++ b/servo/components/style/values/computed/transform.rs
+@@ -1,16 +1,15 @@
+ /* 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/. */
+ 
+ //! Computed types for CSS values that are related to transformations.
+ 
+-use properties::animated_properties::Animatable;
+-use values::animated::ToAnimatedZero;
++use values::animated::{Animate, Procedure, ToAnimatedZero};
+ use values::computed::{Length, LengthOrPercentage, Number, Percentage};
+ use values::generics::transform::TimingFunction as GenericTimingFunction;
+ use values::generics::transform::TransformOrigin as GenericTransformOrigin;
+ 
+ /// The computed value of a CSS `<transform-origin>`
+ pub type TransformOrigin = GenericTransformOrigin<LengthOrPercentage, LengthOrPercentage, Length>;
+ 
+ /// A computed timing function.
+@@ -23,23 +22,23 @@ impl TransformOrigin {
+         Self::new(
+             LengthOrPercentage::Percentage(Percentage(0.5)),
+             LengthOrPercentage::Percentage(Percentage(0.5)),
+             Length::from_px(0),
+         )
+     }
+ }
+ 
+-impl Animatable for TransformOrigin {
++impl Animate for TransformOrigin {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(Self::new(
+-            self.horizontal.add_weighted(&other.horizontal, self_portion, other_portion)?,
+-            self.vertical.add_weighted(&other.vertical, self_portion, other_portion)?,
+-            self.depth.add_weighted(&other.depth, self_portion, other_portion)?,
++            self.horizontal.animate(&other.horizontal, procedure)?,
++            self.vertical.animate(&other.vertical, procedure)?,
++            self.depth.animate(&other.depth, procedure)?,
+         ))
+     }
+ }
+ 
+ impl ToAnimatedZero for TransformOrigin {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         Ok(Self::new(
+diff --git a/servo/components/style/values/generics/basic_shape.rs b/servo/components/style/values/generics/basic_shape.rs
+--- a/servo/components/style/values/generics/basic_shape.rs
++++ b/servo/components/style/values/generics/basic_shape.rs
+@@ -1,19 +1,18 @@
+ /* 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 handling for the [`basic-shape`](https://drafts.csswg.org/css-shapes/#typedef-basic-shape)
+ //! types that are generic over their `ToCss` implementations.
+ 
+-use properties::animated_properties::Animatable;
+ use std::fmt;
+ use style_traits::{HasViewportPercentage, ToCss};
+-use values::animated::ToAnimatedZero;
++use values::animated::{Animate, Procedure, ToAnimatedZero};
+ use values::computed::ComputedValueAsSpecified;
+ use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ use values::generics::border::BorderRadius;
+ use values::generics::position::Position;
+ use values::generics::rect::Rect;
+ 
+ /// A clipping shape, for `clip-path`.
+ pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, Url>;
+@@ -118,34 +117,31 @@ pub struct Polygon<LengthOrPercentage> {
+ // https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
+ // says that it can also be `inherit`
+ define_css_keyword_enum!(FillRule:
+     "nonzero" => NonZero,
+     "evenodd" => EvenOdd
+ );
+ add_impls_for_keyword_enum!(FillRule);
+ 
+-impl<B, T, U> Animatable for ShapeSource<B, T, U>
++impl<B, T, U> Animate for ShapeSource<B, T, U>
+ where
+-    B: Animatable,
++    B: Animate,
+     T: Clone + PartialEq,
+ {
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             (
+                 &ShapeSource::Shape(ref this, ref this_box),
+                 &ShapeSource::Shape(ref other, ref other_box),
+             ) if this_box == other_box => {
+-                let shape = this.add_weighted(other, self_portion, other_portion)?;
+-                Ok(ShapeSource::Shape(shape, this_box.clone()))
++                Ok(ShapeSource::Shape(
++                    this.animate(other, procedure)?,
++                    this_box.clone(),
++                ))
+             },
+             _ => Err(()),
+         }
+     }
+ }
+ 
+ // FIXME(nox): Implement ComputeSquaredDistance for T types and stop
+ // using PartialEq here, this will let us derive this impl.
+@@ -173,59 +169,50 @@ impl<B, T, U> ToAnimatedZero for ShapeSo
+     }
+ }
+ 
+ impl<B, T, U> HasViewportPercentage for ShapeSource<B, T, U> {
+     #[inline]
+     fn has_viewport_percentage(&self) -> bool { false }
+ }
+ 
+-impl<H, V, L> Animatable for BasicShape<H, V, L>
++impl<H, V, L> Animate for BasicShape<H, V, L>
+ where
+-    H: Animatable,
+-    V: Animatable,
+-    L: Animatable + Copy,
++    H: Animate,
++    V: Animate,
++    L: Animate + Copy,
+ {
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             (&BasicShape::Circle(ref this), &BasicShape::Circle(ref other)) => {
+-                Ok(BasicShape::Circle(this.add_weighted(other, self_portion, other_portion)?))
++                Ok(BasicShape::Circle(this.animate(other, procedure)?))
+             },
+             (&BasicShape::Ellipse(ref this), &BasicShape::Ellipse(ref other)) => {
+-                Ok(BasicShape::Ellipse(this.add_weighted(other, self_portion, other_portion)?))
++                Ok(BasicShape::Ellipse(this.animate(other, procedure)?))
+             },
+             (&BasicShape::Inset(ref this), &BasicShape::Inset(ref other)) => {
+-                Ok(BasicShape::Inset(this.add_weighted(other, self_portion, other_portion)?))
++                Ok(BasicShape::Inset(this.animate(other, procedure)?))
+             },
+             (&BasicShape::Polygon(ref this), &BasicShape::Polygon(ref other)) => {
+-                Ok(BasicShape::Polygon(this.add_weighted(other, self_portion, other_portion)?))
++                Ok(BasicShape::Polygon(this.animate(other, procedure)?))
+             },
+             _ => Err(()),
+         }
+     }
+ }
+ 
+-impl<L> Animatable for InsetRect<L>
++impl<L> Animate for InsetRect<L>
+ where
+-    L: Animatable + Copy,
++    L: Animate + Copy,
+ {
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
+-        let rect = self.rect.add_weighted(&other.rect, self_portion, other_portion)?;
+-        let round = self.round.add_weighted(&other.round, self_portion, other_portion)?;
+-        Ok(InsetRect { rect, round })
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(InsetRect {
++            rect: self.rect.animate(&other.rect, procedure)?,
++            round: self.round.animate(&other.round, procedure)?,
++        })
+     }
+ }
+ 
+ impl<L> ToCss for InsetRect<L>
+     where L: ToCss + PartialEq
+ {
+     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+         dest.write_str("inset(")?;
+@@ -233,97 +220,80 @@ impl<L> ToCss for InsetRect<L>
+         if let Some(ref radius) = self.round {
+             dest.write_str(" round ")?;
+             radius.to_css(dest)?;
+         }
+         dest.write_str(")")
+     }
+ }
+ 
+-impl<H, V, L> Animatable for Circle<H, V, L>
++impl<H, V, L> Animate for Circle<H, V, L>
+ where
+-    H: Animatable,
+-    V: Animatable,
+-    L: Animatable,
++    H: Animate,
++    V: Animate,
++    L: Animate,
+ {
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
+-        let position = self.position.add_weighted(&other.position, self_portion, other_portion)?;
+-        let radius = self.radius.add_weighted(&other.radius, self_portion, other_portion)?;
+-        Ok(Circle { position, radius })
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(Circle {
++            position: self.position.animate(&other.position, procedure)?,
++            radius: self.radius.animate(&other.radius, procedure)?,
++        })
+     }
+ }
+ 
+-impl<H, V, L> Animatable for Ellipse<H, V, L>
++impl<H, V, L> Animate for Ellipse<H, V, L>
+ where
+-    H: Animatable,
+-    V: Animatable,
+-    L: Animatable,
++    H: Animate,
++    V: Animate,
++    L: Animate,
+ {
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
+-        let position = self.position.add_weighted(&other.position, self_portion, other_portion)?;
+-        let semiaxis_x = self.semiaxis_x.add_weighted(&other.semiaxis_x, self_portion, other_portion)?;
+-        let semiaxis_y = self.semiaxis_y.add_weighted(&other.semiaxis_y, self_portion, other_portion)?;
+-        Ok(Ellipse { position, semiaxis_x, semiaxis_y })
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(Ellipse {
++            position: self.position.animate(&other.position, procedure)?,
++            semiaxis_x: self.semiaxis_x.animate(&other.semiaxis_x, procedure)?,
++            semiaxis_y: self.semiaxis_y.animate(&other.semiaxis_y, procedure)?,
++        })
+     }
+ }
+ 
+-impl<L> Animatable for ShapeRadius<L>
++impl<L> Animate for ShapeRadius<L>
+ where
+-    L: Animatable,
++    L: Animate,
+ {
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             (&ShapeRadius::Length(ref this), &ShapeRadius::Length(ref other)) => {
+-                Ok(ShapeRadius::Length(this.add_weighted(other, self_portion, other_portion)?))
++                Ok(ShapeRadius::Length(this.animate(other, procedure)?))
+             },
+             _ => Err(()),
+         }
+     }
+ }
+ 
+ impl<L> Default for ShapeRadius<L> {
+     #[inline]
+     fn default() -> Self { ShapeRadius::ClosestSide }
+ }
+ 
+-impl<L> Animatable for Polygon<L>
++impl<L> Animate for Polygon<L>
+ where
+-    L: Animatable,
++    L: Animate,
+ {
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         if self.fill != other.fill {
+             return Err(());
+         }
+         if self.coordinates.len() != other.coordinates.len() {
+             return Err(());
+         }
+         let coordinates = self.coordinates.iter().zip(other.coordinates.iter()).map(|(this, other)| {
+-            let x = this.0.add_weighted(&other.0, self_portion, other_portion)?;
+-            let y = this.1.add_weighted(&other.1, self_portion, other_portion)?;
+-            Ok((x, y))
++            Ok((
++                this.0.animate(&other.0, procedure)?,
++                this.1.animate(&other.1, procedure)?,
++            ))
+         }).collect::<Result<Vec<_>, _>>()?;
+         Ok(Polygon { fill: self.fill, coordinates })
+     }
+ }
+ 
+ impl<L> ComputeSquaredDistance for Polygon<L>
+ where
+     L: ComputeSquaredDistance,
+diff --git a/servo/components/style/values/generics/border.rs b/servo/components/style/values/generics/border.rs
+--- a/servo/components/style/values/generics/border.rs
++++ b/servo/components/style/values/generics/border.rs
+@@ -1,18 +1,18 @@
+ /* 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/. */
+ 
+ //! Generic types for CSS values related to borders.
+ 
+ use euclid::Size2D;
+-use properties::animated_properties::Animatable;
+ use std::fmt;
+ use style_traits::ToCss;
++use values::animated::{Animate, Procedure};
+ use values::generics::rect::Rect;
+ 
+ /// A generic value for a single side of a `border-image-width` property.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ #[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
+ pub enum BorderImageSideWidth<LengthOrPercentage, Number> {
+     /// `<length-or-percentage>`
+     Length(LengthOrPercentage),
+@@ -108,31 +108,27 @@ impl<L> BorderRadius<L>
+         if widths.0 != heights.0 || widths.1 != heights.1 || widths.2 != heights.2 || widths.3 != heights.3 {
+             dest.write_str(" / ")?;
+             heights.to_css(dest)?;
+         }
+         Ok(())
+     }
+ }
+ 
+-impl<L> Animatable for BorderRadius<L>
++impl<L> Animate for BorderRadius<L>
+ where
+-    L: Animatable + Copy,
++    L: Animate + Copy,
+ {
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
+-        let tl = self.top_left.add_weighted(&other.top_left, self_portion, other_portion)?;
+-        let tr = self.top_right.add_weighted(&other.top_right, self_portion, other_portion)?;
+-        let br = self.bottom_right.add_weighted(&other.bottom_right, self_portion, other_portion)?;
+-        let bl = self.bottom_left.add_weighted(&other.bottom_left, self_portion, other_portion)?;
+-        Ok(BorderRadius::new(tl, tr, br, bl))
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(BorderRadius::new(
++            self.top_left.animate(&other.top_left, procedure)?,
++            self.top_right.animate(&other.top_right, procedure)?,
++            self.bottom_right.animate(&other.bottom_right, procedure)?,
++            self.bottom_left.animate(&other.bottom_left, procedure)?,
++        ))
+     }
+ }
+ 
+ impl<L> ToCss for BorderRadius<L>
+     where L: PartialEq + ToCss
+ {
+     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+         let BorderRadius {
+@@ -158,28 +154,23 @@ impl<L> BorderCornerRadius<L> {
+ }
+ 
+ impl<L: Clone> From<L> for BorderCornerRadius<L> {
+     fn from(radius: L) -> Self {
+         Self::new(radius.clone(), radius)
+     }
+ }
+ 
+-impl<L> Animatable for BorderCornerRadius<L>
++impl<L> Animate for BorderCornerRadius<L>
+ where
+-    L: Animatable + Copy,
++    L: Animate + Copy,
+ {
+     #[inline]
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
+-        Ok(BorderCornerRadius(self.0.add_weighted(&other.0, self_portion, other_portion)?))
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(BorderCornerRadius(self.0.animate(&other.0, procedure)?))
+     }
+ }
+ 
+ impl<L> ToCss for BorderCornerRadius<L>
+     where L: ToCss,
+ {
+     fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+         where W: fmt::Write
+diff --git a/servo/components/style/values/generics/rect.rs b/servo/components/style/values/generics/rect.rs
+--- a/servo/components/style/values/generics/rect.rs
++++ b/servo/components/style/values/generics/rect.rs
+@@ -1,19 +1,19 @@
+ /* 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/. */
+ 
+ //! Generic types for CSS values that are composed of four sides.
+ 
+ use cssparser::Parser;
+ use parser::{Parse, ParserContext};
+-use properties::animated_properties::Animatable;
+ use std::fmt;
+ use style_traits::{ToCss, ParseError};
++use values::animated::{Animate, Procedure};
+ 
+ /// A CSS value made of four components, where its `ToCss` impl will try to
+ /// serialize as few components as possible, like for example in `border-width`.
+ #[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ pub struct Rect<T>(pub T, pub T, pub T, pub T);
+ 
+ impl<T> Rect<T> {
+@@ -47,31 +47,27 @@ impl<T> Rect<T>
+             // <first> <second> <third>
+             return Ok(Self::new(first, second.clone(), third, second));
+         };
+         // <first> <second> <third> <fourth>
+         Ok(Self::new(first, second, third, fourth))
+     }
+ }
+ 
+-impl<L> Animatable for Rect<L>
++impl<L> Animate for Rect<L>
+ where
+-    L: Animatable,
++    L: Animate,
+ {
+-    fn add_weighted(
+-        &self,
+-        other: &Self,
+-        self_portion: f64,
+-        other_portion: f64,
+-    ) -> Result<Self, ()> {
+-        let first = self.0.add_weighted(&other.0, self_portion, other_portion)?;
+-        let second = self.1.add_weighted(&other.1, self_portion, other_portion)?;
+-        let third = self.2.add_weighted(&other.2, self_portion, other_portion)?;
+-        let fourth = self.3.add_weighted(&other.3, self_portion, other_portion)?;
+-        Ok(Rect(first, second, third, fourth))
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
++        Ok(Rect(
++            self.0.animate(&other.0, procedure)?,
++            self.1.animate(&other.1, procedure)?,
++            self.2.animate(&other.2, procedure)?,
++            self.3.animate(&other.3, procedure)?,
++        ))
+     }
+ }
+ 
+ impl<T> From<T> for Rect<T>
+     where T: Clone
+ {
+     #[inline]
+     fn from(value: T) -> Self {
+diff --git a/servo/components/style/values/generics/text.rs b/servo/components/style/values/generics/text.rs
+--- a/servo/components/style/values/generics/text.rs
++++ b/servo/components/style/values/generics/text.rs
+@@ -2,19 +2,18 @@
+  * 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/. */
+ 
+ //! Generic types for text properties.
+ 
+ use app_units::Au;
+ use cssparser::Parser;
+ use parser::ParserContext;
+-use properties::animated_properties::Animatable;
+ use style_traits::ParseError;
+-use values::animated::ToAnimatedZero;
++use values::animated::{Animate, Procedure, ToAnimatedZero};
+ use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ 
+ /// A generic value for the `initial-letter` property.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ #[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
+ pub enum InitialLetter<Number, Integer> {
+     /// `normal`
+     Normal,
+@@ -67,28 +66,29 @@ impl<Value> Spacing<Value> {
+     pub fn value(&self) -> Option<&Value> {
+         match *self {
+             Spacing::Normal => None,
+             Spacing::Value(ref value) => Some(value),
+         }
+     }
+ }
+ 
+-impl<Value> Animatable for Spacing<Value>
+-    where Value: Animatable + From<Au>,
++impl<Value> Animate for Spacing<Value>
++where
++    Value: Animate + From<Au>,
+ {
+     #[inline]
+-    fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
++    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         if let (&Spacing::Normal, &Spacing::Normal) = (self, other) {
+             return Ok(Spacing::Normal);
+         }
+         let zero = Value::from(Au(0));
+         let this = self.value().unwrap_or(&zero);
+         let other = other.value().unwrap_or(&zero);
+-        this.add_weighted(other, self_portion, other_portion).map(Spacing::Value)
++        Ok(Spacing::Value(this.animate(other, procedure)?))
+     }
+ }
+ 
+ impl<V> ComputeSquaredDistance for Spacing<V>
+ where
+     V: ComputeSquaredDistance + From<Au>,
+ {
+     #[inline]
+diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs
+--- a/servo/ports/geckolib/glue.rs
++++ b/servo/ports/geckolib/glue.rs
+@@ -100,17 +100,17 @@ use style::invalidation::element::restyl
+ use style::media_queries::{MediaList, parse_media_query_list};
+ use style::parallel;
+ use style::parser::{ParserContext, self};
+ use style::properties::{CascadeFlags, ComputedValues, Importance};
+ use style::properties::{IS_FIELDSET_CONTENT, IS_LINK, IS_VISITED_LINK, LonghandIdSet};
+ use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyId, ShorthandId};
+ use style::properties::{SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, SourcePropertyDeclaration, StyleBuilder};
+ use style::properties::PROHIBIT_DISPLAY_CONTENTS;
+-use style::properties::animated_properties::{Animatable, AnimatableLonghand, AnimationValue};
++use style::properties::animated_properties::{AnimatableLonghand, AnimationValue};
+ use style::properties::animated_properties::compare_property_priority;
+ use style::properties::parse_one_declaration_into;
+ use style::rule_tree::StyleSource;
+ use style::selector_parser::PseudoElementCascadeType;
+ use style::sequential;
+ use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
+ use style::string_cache::Atom;
+ use style::style_adjuster::StyleAdjuster;
+@@ -123,17 +123,17 @@ use style::stylesheets::keyframes_rule::
+ use style::stylesheets::supports_rule::parse_condition_or_declaration;
+ use style::stylist::RuleInclusion;
+ use style::thread_state;
+ use style::timer::Timer;
+ use style::traversal::{DomTraversal, TraversalDriver};
+ use style::traversal::resolve_style;
+ use style::traversal_flags::{TraversalFlags, self};
+ use style::values::{CustomIdent, KeyframesName};
+-use style::values::animated::ToAnimatedZero;
++use style::values::animated::{Animate, Procedure, ToAnimatedZero};
+ use style::values::computed::Context;
+ use style::values::distance::ComputeSquaredDistance;
+ use style_traits::{PARSING_MODE_DEFAULT, ToCss};
+ use super::error_reporter::ErrorReporter;
+ use super::stylesheet_loader::StylesheetLoader;
+ 
+ /*
+  * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
+@@ -314,55 +314,55 @@ pub extern "C" fn Servo_MaybeGCRuleTree(
+ #[no_mangle]
+ pub extern "C" fn Servo_AnimationValues_Interpolate(from: RawServoAnimationValueBorrowed,
+                                                     to: RawServoAnimationValueBorrowed,
+                                                     progress: f64)
+      -> RawServoAnimationValueStrong
+ {
+     let from_value = AnimationValue::as_arc(&from);
+     let to_value = AnimationValue::as_arc(&to);
+-    if let Ok(value) = from_value.interpolate(to_value, progress) {
++    if let Ok(value) = from_value.animate(to_value, Procedure::Interpolate { progress }) {
+         Arc::new(value).into_strong()
+     } else {
+         RawServoAnimationValueStrong::null()
+     }
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_AnimationValues_IsInterpolable(from: RawServoAnimationValueBorrowed,
+                                                        to: RawServoAnimationValueBorrowed)
+                                                        -> bool {
+     let from_value = AnimationValue::as_arc(&from);
+     let to_value = AnimationValue::as_arc(&to);
+-    from_value.interpolate(to_value, 0.5).is_ok()
++    from_value.animate(to_value, Procedure::Interpolate { progress: 0.5 }).is_ok()
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_AnimationValues_Add(a: RawServoAnimationValueBorrowed,
+                                             b: RawServoAnimationValueBorrowed)
+      -> RawServoAnimationValueStrong
+ {
+     let a_value = AnimationValue::as_arc(&a);
+     let b_value = AnimationValue::as_arc(&b);
+-    if let Ok(value) = a_value.add(b_value) {
++    if let Ok(value) = a_value.animate(b_value, Procedure::Add) {
+         Arc::new(value).into_strong()
+     } else {
+         RawServoAnimationValueStrong::null()
+     }
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_AnimationValues_Accumulate(a: RawServoAnimationValueBorrowed,
+                                                    b: RawServoAnimationValueBorrowed,
+                                                    count: u64)
+      -> RawServoAnimationValueStrong
+ {
+     let a_value = AnimationValue::as_arc(&a);
+     let b_value = AnimationValue::as_arc(&b);
+-    if let Ok(value) = a_value.accumulate(b_value, count) {
++    if let Ok(value) = a_value.animate(b_value, Procedure::Accumulate { count }) {
+         Arc::new(value).into_strong()
+     } else {
+         RawServoAnimationValueStrong::null()
+     }
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_AnimationValues_GetZeroValue(
+@@ -458,22 +458,26 @@ pub extern "C" fn Servo_AnimationCompose
+     let composite_endpoint = |keyframe_value: Option<&RawOffsetArc<AnimationValue>>,
+                               composite_op: CompositeOperation| -> Option<AnimationValue> {
+         match keyframe_value {
+             Some(keyframe_value) => {
+                 match composite_op {
+                     CompositeOperation::Add => {
+                         debug_assert!(need_underlying_value,
+                                       "Should have detected we need an underlying value");
+-                        underlying_value.as_ref().unwrap().add(keyframe_value).ok()
++                        underlying_value.as_ref().unwrap().animate(keyframe_value, Procedure::Add).ok()
+                     },
+                     CompositeOperation::Accumulate => {
+                         debug_assert!(need_underlying_value,
+                                       "Should have detected we need an underlying value");
+-                        underlying_value.as_ref().unwrap().accumulate(keyframe_value, 1).ok()
++                        underlying_value
++                            .as_ref()
++                            .unwrap()
++                            .animate(keyframe_value, Procedure::Accumulate { count: 1 })
++                            .ok()
+                     },
+                     _ => None,
+                 }
+             },
+             None => {
+                 debug_assert!(need_underlying_value,
+                               "Should have detected we need an underlying value");
+                 underlying_value.clone()
+@@ -502,21 +506,27 @@ pub extern "C" fn Servo_AnimationCompose
+         };
+ 
+         // As with composite_endpoint, a return value of None means, "Use keyframe_value as-is."
+         let apply_iteration_composite = |keyframe_value: Option<&RawOffsetArc<AnimationValue>>,
+                                          composited_value: Option<AnimationValue>|
+                                         -> Option<AnimationValue> {
+             let count = computed_timing.mCurrentIteration;
+             match composited_value {
+-                Some(endpoint) => last_value.accumulate(&endpoint, count)
+-                                            .ok()
+-                                            .or(Some(endpoint)),
+-                None => last_value.accumulate(keyframe_value.unwrap(), count)
+-                                  .ok(),
++                Some(endpoint) => {
++                    last_value
++                        .animate(&endpoint, Procedure::Accumulate { count })
++                        .ok()
++                        .or(Some(endpoint))
++                },
++                None => {
++                    last_value
++                        .animate(keyframe_value.unwrap(), Procedure::Accumulate { count })
++                        .ok()
++                },
+             }
+         };
+ 
+         composited_from_value = apply_iteration_composite(keyframe_from_value,
+                                                           composited_from_value);
+         composited_to_value = apply_iteration_composite(keyframe_to_value,
+                                                         composited_to_value);
+     }
+@@ -530,22 +540,22 @@ pub extern "C" fn Servo_AnimationCompose
+         if progress < 0. {
+             value_map.insert(property, from_value.clone());
+         } else {
+             value_map.insert(property, to_value.clone());
+         }
+         return;
+     }
+ 
+-    let position = unsafe {
++    let pos = unsafe {
+         Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag)
+     };
+-    if let Ok(value) = from_value.interpolate(to_value, position) {
++    if let Ok(value) = from_value.animate(to_value, Procedure::Interpolate { progress: pos }) {
+         value_map.insert(property, value);
+-    } else if position < 0.5 {
++    } else if pos < 0.5 {
+         value_map.insert(property, from_value.clone());
+     } else {
+         value_map.insert(property, to_value.clone());
+     }
+ }
+ 
+ macro_rules! get_property_id_from_nscsspropertyid {
+     ($property_id: ident, $ret: expr) => {{
+@@ -2075,18 +2085,18 @@ pub extern "C" fn Servo_MatrixTransform_
+                                                 progress: f64,
+                                                 output: *mut RawGeckoGfxMatrix4x4) {
+     use self::MatrixTransformOperator::{Accumulate, Interpolate};
+     use style::properties::longhands::transform::computed_value::ComputedMatrix;
+ 
+     let from = ComputedMatrix::from(unsafe { from.as_ref() }.expect("not a valid 'from' matrix"));
+     let to = ComputedMatrix::from(unsafe { to.as_ref() }.expect("not a valid 'to' matrix"));
+     let result = match matrix_operator {
+-        Interpolate => from.interpolate(&to, progress),
+-        Accumulate => from.accumulate(&to, progress as u64),
++        Interpolate => from.animate(&to, Procedure::Interpolate { progress }),
++        Accumulate => from.animate(&to, Procedure::Accumulate { count: progress as u64 }),
+     };
+ 
+     let output = unsafe { output.as_mut() }.expect("not a valid 'output' matrix");
+     if let Ok(result) =  result {
+         *output = result.into();
+     };
+ }
+ 
+diff --git a/servo/tests/unit/style/animated_properties.rs b/servo/tests/unit/style/animated_properties.rs
+--- a/servo/tests/unit/style/animated_properties.rs
++++ b/servo/tests/unit/style/animated_properties.rs
+@@ -1,24 +1,25 @@
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ use app_units::Au;
+ use cssparser::RGBA;
+-use style::properties::animated_properties::Animatable;
+ use style::properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
+ use style::properties::longhands::transform::computed_value::T as TransformList;
+-use style::values::animated::ToAnimatedValue;
++use style::values::animated::{Animate, Procedure, ToAnimatedValue};
+ use style::values::computed::Percentage;
+ 
+ fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA {
+     let from = from.to_animated_value();
+     let to = to.to_animated_value();
+-    RGBA::from_animated_value(from.interpolate(&to, progress).unwrap())
++    RGBA::from_animated_value(
++        from.animate(&to, Procedure::Interpolate { progress }).unwrap(),
++    )
+ }
+ 
+ // Color
+ #[test]
+ fn test_rgba_color_interepolation_preserves_transparent() {
+     assert_eq!(interpolate_rgba(RGBA::transparent(),
+                                 RGBA::transparent(), 0.5),
+                RGBA::transparent());
+@@ -69,88 +70,100 @@ fn test_transform_interpolation_on_trans
+     let from = TransformList(Some(vec![
+         TransformOperation::Translate(LengthOrPercentage::Length(Au(0)),
+                                       LengthOrPercentage::Length(Au(100)),
+                                       Au(25))]));
+     let to = TransformList(Some(vec![
+         TransformOperation::Translate(LengthOrPercentage::Length(Au(100)),
+                                       LengthOrPercentage::Length(Au(0)),
+                                       Au(75))]));
+-    assert_eq!(from.interpolate(&to, 0.5).unwrap(),
+-               TransformList(Some(vec![
+-                   TransformOperation::Translate(LengthOrPercentage::Length(Au(50)),
+-                                                 LengthOrPercentage::Length(Au(50)),
+-                                                 Au(50))])));
++    assert_eq!(
++        from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
++        TransformList(Some(vec![TransformOperation::Translate(
++            LengthOrPercentage::Length(Au(50)),
++            LengthOrPercentage::Length(Au(50)),
++            Au(50),
++        )]))
++    );
+ 
+     let from = TransformList(Some(vec![TransformOperation::Translate(
+         LengthOrPercentage::Percentage(Percentage(0.5)),
+         LengthOrPercentage::Percentage(Percentage(1.0)),
+         Au(25),
+     )]));
+     let to = TransformList(Some(vec![
+         TransformOperation::Translate(LengthOrPercentage::Length(Au(100)),
+                                       LengthOrPercentage::Length(Au(50)),
+                                       Au(75))]));
+     assert_eq!(
+-        from.interpolate(&to, 0.5).unwrap(),
++        from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
+         TransformList(Some(vec![TransformOperation::Translate(
+             // calc(50px + 25%)
+             LengthOrPercentage::Calc(CalcLengthOrPercentage::new(Au(50), Some(Percentage(0.25)))),
+             // calc(25px + 50%)
+             LengthOrPercentage::Calc(CalcLengthOrPercentage::new(Au(25), Some(Percentage(0.5)))),
+             Au(50),
+         )]))
+     );
+ }
+ 
+ #[test]
+ fn test_transform_interpolation_on_scale() {
+     let from = TransformList(Some(vec![TransformOperation::Scale(1.0, 2.0, 1.0)]));
+     let to = TransformList(Some(vec![TransformOperation::Scale(2.0, 4.0, 2.0)]));
+-    assert_eq!(from.interpolate(&to, 0.5).unwrap(),
+-               TransformList(Some(vec![TransformOperation::Scale(1.5, 3.0, 1.5)])));
++    assert_eq!(
++        from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
++        TransformList(Some(vec![TransformOperation::Scale(1.5, 3.0, 1.5)]))
++    );
+ }
+ 
+ #[test]
+ fn test_transform_interpolation_on_rotate() {
+     use style::values::computed::Angle;
+ 
+     let from = TransformList(Some(vec![TransformOperation::Rotate(0.0, 0.0, 1.0,
+                                                                   Angle::from_radians(0.0))]));
+     let to = TransformList(Some(vec![TransformOperation::Rotate(0.0, 0.0, 1.0,
+                                                                 Angle::from_radians(100.0))]));
+-    assert_eq!(from.interpolate(&to, 0.5).unwrap(),
+-               TransformList(Some(vec![TransformOperation::Rotate(0.0, 0.0, 1.0,
+-                                                                  Angle::from_radians(50.0))])));
++    assert_eq!(
++        from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
++        TransformList(Some(vec![
++            TransformOperation::Rotate(0.0, 0.0, 1.0, Angle::from_radians(50.0)),
++        ]))
++    );
+ }
+ 
+ #[test]
+ fn test_transform_interpolation_on_skew() {
+     use style::values::computed::Angle;
+ 
+     let from = TransformList(Some(vec![TransformOperation::Skew(Angle::from_radians(0.0),
+                                                                 Angle::from_radians(100.0))]));
+     let to = TransformList(Some(vec![TransformOperation::Skew(Angle::from_radians(100.0),
+                                                               Angle::from_radians(0.0))]));
+-    assert_eq!(from.interpolate(&to, 0.5).unwrap(),
+-               TransformList(Some(vec![TransformOperation::Skew(Angle::from_radians(50.0),
+-                                                                Angle::from_radians(50.0))])));
++    assert_eq!(
++        from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
++        TransformList(Some(vec![TransformOperation::Skew(
++            Angle::from_radians(50.0),
++            Angle::from_radians(50.0),
++        )]))
++    );
+ }
+ 
+ #[test]
+ fn test_transform_interpolation_on_mismatched_lists() {
+     use style::values::computed::{Angle, LengthOrPercentage, Percentage};
+ 
+     let from = TransformList(Some(vec![TransformOperation::Rotate(0.0, 0.0, 1.0,
+                                                                   Angle::from_radians(100.0))]));
+     let to = TransformList(Some(vec![
+         TransformOperation::Translate(LengthOrPercentage::Length(Au(100)),
+                                       LengthOrPercentage::Length(Au(0)),
+                                       Au(0))]));
+     assert_eq!(
+-        from.interpolate(&to, 0.5).unwrap(),
++        from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
+         TransformList(Some(vec![TransformOperation::InterpolateMatrix {
+             from_list: from.clone(),
+             to_list: to.clone(),
+             progress: Percentage(0.5),
+         }]))
+     );
+ }
+diff --git a/servo/tests/unit/style/stylist.rs b/servo/tests/unit/style/stylist.rs
+--- a/servo/tests/unit/style/stylist.rs
++++ b/servo/tests/unit/style/stylist.rs
+@@ -1,25 +1,23 @@
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ use cssparser::SourceLocation;
+ use euclid::ScaleFactor;
+ use euclid::TypedSize2D;
+-use html5ever::LocalName;
+ use selectors::parser::{AncestorHashes, Selector};
+-use selectors::parser::LocalName as LocalNameSelector;
+ use servo_arc::Arc;
+ use servo_atoms::Atom;
+ use style::context::QuirksMode;
+ use style::media_queries::{Device, MediaType};
+ use style::properties::{PropertyDeclarationBlock, PropertyDeclaration};
+ use style::properties::{longhands, Importance};
+-use style::selector_map::{self, SelectorMap};
++use style::selector_map::SelectorMap;
+ use style::selector_parser::{SelectorImpl, SelectorParser};
+ use style::shared_lock::SharedRwLock;
+ use style::stylesheets::StyleRule;
+ use style::stylist::{Stylist, Rule};
+ use style::stylist::needs_revalidation_for_testing;
+ use style::thread_state;
+ 
+ /// Helper method to get some Rules from selector strings.

+ 1145 - 0
frg/253-58/mozilla-release58_428078.patch

@@ -0,0 +1,1145 @@
+# HG changeset patch
+# User Nicolas Chevobbe <nchevobbe@mozilla.com>
+# Date 1503057698 -7200
+#      Fri Aug 18 14:01:38 2017 +0200
+# Node ID c72fb15e6f6e6c7c3f67690f509bbadd8f709de9
+# Parent  8c425afa1607037b5331ba54904e3354ecbf7fc6
+Bug 1307880 - Show the number of filtered messages. r=bgrins
+
+This adds a "filteredMessagesCount" property to the messages store,
+which is updated at the same time as we update the "visibleMessages"
+property.
+The global number of hidden messages is then shown next to the text search
+input, and a button can be clicked to Reset the filters to their original
+values.
+This only takes into account messages that are filtered-out because
+the default filters changes. Which means that non-default filters, like
+CSS, Network and XHR don't impact filteredMessagesCount.
+
+We take this as an opportunity to rename the match*Filter functions to
+pass*Filter, since it better represents what the function does (a network
+message is not impacted by a level filter, but it can be misleading to say
+that it matches level filters).
+
+MozReview-Commit-ID: BLPmCFNtzEl
+
+diff --git a/devtools/client/locales/en-US/webconsole.properties b/devtools/client/locales/en-US/webconsole.properties
+--- a/devtools/client/locales/en-US/webconsole.properties
++++ b/devtools/client/locales/en-US/webconsole.properties
+@@ -292,8 +292,20 @@ webconsole.cssFilterButton.label=CSS
+ # a fetch call.
+ webconsole.xhrFilterButton.label=XHR
+ 
+ # LOCALIZATION NOTE (webconsole.requestsFilterButton.label)
+ # Label used as the text of the "Requests" button in the additional filter toolbar.
+ # It shows or hides messages displayed when the page makes a network call, for example
+ # when an image or a scripts is requested.
+ webconsole.requestsFilterButton.label=Requests
++
++# LOCALIZATION NOTE (webconsole.filteredMessages.label)
++# Text of the "filtered messages" bar, shown when console messages are hidden
++# because the user has set non-default filters in the filter bar.
++# This is a semi-colon list of plural forms.
++# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
++# example: 345 items hidden by filters.
++webconsole.filteredMessages.label=#1 item hidden by filters;#1 items hidden by filters
++
++# Label used as the text of the "Reset filters" button in the "filtered messages" bar.
++# It resets the default filters of the console to their original values.
++webconsole.resetFiltersButton.label=Reset filters
+diff --git a/devtools/client/themes/webconsole.css b/devtools/client/themes/webconsole.css
+--- a/devtools/client/themes/webconsole.css
++++ b/devtools/client/themes/webconsole.css
+@@ -728,37 +728,86 @@ a.learn-more-link.webconsole-learn-more-
+ 
+ .webconsole-output-wrapper {
+   display: flex;
+   flex-direction: column;
+   height: 100%;
+   -moz-user-focus: normal;
+ }
+ 
+-.webconsole-filterbar-wrapper {
+-  flex-grow: 0;
++/*
++  This element contains the different toolbars in the console
++    - primary, containing the clear messages button and the text search input.
++      It can expand as much as it need.
++    - filtered messages, containing the "X items hidden by filters" and the reset filters button.
++      It should be on the same row than the primary bar if it fits there, or on its own 100% row if it is wrapped.
++    - secondary, containing the filter buttons (Error, Warning, …).
++      It should be on its own 100% row.
++
++  Basically here's what we can have :
++
++  -----------------------------------------------------------------------------------------------------------
++  | Clear button - Open filter bar button - Filter Input | X items hidden by filters - Reset Filters button |
++  -----------------------------------------------------------------------------------------------------------
++  | Error - Warning - Log - Info - Debug - CSS - Network - XHR                                              |
++  -----------------------------------------------------------------------------------------------------------
++
++  or
++
++  ------------------------------------------------------------------------------------
++  | Clear button - Open filter bar button - Filter Input                             |
++  ------------------------------------------------------------------------------------
++  |                                X items hidden by filters  - Reset Filters button |
++  ------------------------------------------------------------------------------------
++  | Error - Warning - Log - Info - Debug - CSS - Network - XHR                       |
++  ------------------------------------------------------------------------------------
++*/
++.webconsole-filteringbar-wrapper {
++  display: flex;
++  /* Wrap so the "Hidden messages" bar can go to its own row if needed */
++  flex-wrap: wrap;
++}
++
++.webconsole-filterbar-primary {
++  display: flex;
++  /* We want the toolbar (which contain the text search input) to be at least 200px
++  so we don't allow to shrink it */
++  flex: 1 0 200px;
++}
++
++.devtools-toolbar.webconsole-filterbar-secondary {
++  height: initial;
++  /* This toolbar should always take the whole horizontal space */
++  width: 100%;
++}
++
++.webconsole-filterbar-primary .devtools-plaininput {
++  flex: 1 1 100%;
++}
++
++.webconsole-filterbar-filtered-messages {
++  /* Needed so the bar takes the whole horizontal space when it is wrapped */
++  flex-grow: 1;
++  color: var(--theme-comment);
++  text-align: end;
++}
++
++.webconsole-filterbar-filtered-messages .filter-message-text {
++  font-style: italic;
++}
++
++.webconsole-filterbar-filtered-messages .reset-filters-button {
++  margin-inline-start: 0.5em;
+ }
+ 
+ .webconsole-output {
+   flex: 1;
+   overflow: auto;
+ }
+ 
+-.webconsole-filterbar-primary {
+-  display: flex;
+-}
+-
+-.devtools-toolbar.webconsole-filterbar-secondary {
+-  height: initial;
+-}
+-
+-.webconsole-filterbar-primary .devtools-plaininput {
+-  flex: 1 1 100%;
+-}
+-
+ .webconsole-output-wrapper .message {
+   --border-size: 3px;
+   border-inline-start: var(--border-size) solid transparent;
+ }
+ 
+ .webconsole-output-wrapper .message:hover {
+   border-inline-start-color: #0a84ff; /* Photon Design System Blue 50 */
+ }
+diff --git a/devtools/client/webconsole/new-console-output/actions/filters.js b/devtools/client/webconsole/new-console-output/actions/filters.js
+--- a/devtools/client/webconsole/new-console-output/actions/filters.js
++++ b/devtools/client/webconsole/new-console-output/actions/filters.js
+@@ -8,17 +8,20 @@
+ 
+ const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
+ const Services = require("Services");
+ 
+ const {
+   FILTER_TEXT_SET,
+   FILTER_TOGGLE,
+   FILTERS_CLEAR,
++  DEFAULT_FILTERS_RESET,
+   PREFS,
++  FILTERS,
++  DEFAULT_FILTERS,
+ } = require("devtools/client/webconsole/new-console-output/constants");
+ 
+ function filterTextSet(text) {
+   return {
+     type: FILTER_TEXT_SET,
+     text
+   };
+ }
+@@ -38,18 +41,42 @@ function filterToggle(filter) {
+ function filtersClear() {
+   return (dispatch, getState) => {
+     dispatch({
+       type: FILTERS_CLEAR,
+     });
+ 
+     const filterState = getAllFilters(getState());
+     for (let filter in filterState) {
+-      Services.prefs.clearUserPref(PREFS.FILTER[filter.toUpperCase()]);
++      if (filter !== FILTERS.TEXT) {
++        Services.prefs.clearUserPref(PREFS.FILTER[filter.toUpperCase()]);
++      }
+     }
+   };
+ }
+ 
++/**
++ * Set the default filters to their original values.
++ * This is different than filtersClear where we reset
++ * all the filters to their original values. Here we want
++ * to keep non-default filters the user might have set.
++ */
++function defaultFiltersReset() {
++  return (dispatch, getState) => {
++    dispatch({
++      type: DEFAULT_FILTERS_RESET,
++    });
++
++    const filterState = getAllFilters(getState());
++    DEFAULT_FILTERS.forEach(filter => {
++      if (filterState[filter] === false) {
++        Services.prefs.clearUserPref(PREFS.FILTER[filter.toUpperCase()]);
++      }
++    });
++  };
++}
++
+ module.exports = {
+   filterTextSet,
+   filterToggle,
+-  filtersClear
++  filtersClear,
++  defaultFiltersReset,
+ };
+diff --git a/devtools/client/webconsole/new-console-output/components/filter-bar.js b/devtools/client/webconsole/new-console-output/components/filter-bar.js
+--- a/devtools/client/webconsole/new-console-output/components/filter-bar.js
++++ b/devtools/client/webconsole/new-console-output/components/filter-bar.js
+@@ -5,139 +5,243 @@
+ 
+ const {
+   createClass,
+   DOM: dom,
+   PropTypes
+ } = require("devtools/client/shared/vendor/react");
+ const { connect } = require("devtools/client/shared/vendor/react-redux");
+ const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
++const { getFilteredMessagesCount } = require("devtools/client/webconsole/new-console-output/selectors/messages");
+ const { getAllUi } = require("devtools/client/webconsole/new-console-output/selectors/ui");
+ const {
++  filterBarToggle,
++  defaultFiltersReset,
+   filterTextSet,
+-  filterBarToggle,
+-  messagesClear
++  messagesClear,
+ } = require("devtools/client/webconsole/new-console-output/actions/index");
+ const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
++const { PluralForm } = require("devtools/shared/plural-form");
+ const {
+-  MESSAGE_LEVEL
++  DEFAULT_FILTERS,
++  FILTERS,
+ } = require("../constants");
++
+ const FilterButton = require("devtools/client/webconsole/new-console-output/components/filter-button");
+ 
+ const FilterBar = createClass({
+ 
+   displayName: "FilterBar",
+ 
+   propTypes: {
+     dispatch: PropTypes.func.isRequired,
+     filter: PropTypes.object.isRequired,
+     serviceContainer: PropTypes.shape({
+       attachRefToHud: PropTypes.func.isRequired,
+     }).isRequired,
+     filterBarVisible: PropTypes.bool.isRequired,
++    filteredMessagesCount: PropTypes.object.isRequired,
++  },
++
++  shouldComponentUpdate(nextProps, nextState) {
++    if (nextProps.filter !== this.props.filter) {
++      return true;
++    }
++
++    if (nextProps.filterBarVisible !== this.props.filterBarVisible) {
++      return true;
++    }
++
++    if (
++      JSON.stringify(nextProps.filteredMessagesCount)
++      !== JSON.stringify(this.props.filteredMessagesCount)
++    ) {
++      return true;
++    }
++
++    return false;
+   },
+ 
+   componentDidMount() {
+     this.props.serviceContainer.attachRefToHud("filterBox",
+       this.wrapperNode.querySelector(".text-filter"));
+   },
+ 
+   onClickMessagesClear: function () {
+     this.props.dispatch(messagesClear());
+   },
+ 
+   onClickFilterBarToggle: function () {
+     this.props.dispatch(filterBarToggle());
+   },
+ 
++  onClickRemoveAllFilters: function () {
++    this.props.dispatch(defaultFiltersReset());
++  },
++
++  onClickRemoveTextFilter: function () {
++    this.props.dispatch(filterTextSet(""));
++  },
++
+   onSearchInput: function (e) {
+     this.props.dispatch(filterTextSet(e.target.value));
+   },
+ 
+-  render() {
+-    const {dispatch, filter, filterBarVisible} = this.props;
+-    let children = [];
++  renderFiltersConfigBar() {
++    const {
++      dispatch,
++      filter,
++      filteredMessagesCount,
++    } = this.props;
++
++    const getLabel = (baseLabel, filterKey) => {
++      const count = filteredMessagesCount[filterKey];
++      if (filter[filterKey] || count === 0) {
++        return baseLabel;
++      }
++      return `${baseLabel} (${count})`;
++    };
+ 
+-    children.push(dom.div({className: "devtools-toolbar webconsole-filterbar-primary"},
+-      dom.button({
+-        className: "devtools-button devtools-clear-icon",
+-        title: l10n.getStr("webconsole.clearButton.tooltip"),
+-        onClick: this.onClickMessagesClear
++    return dom.div({
++      className: "devtools-toolbar webconsole-filterbar-secondary",
++      key: "config-bar",
++    },
++      FilterButton({
++        active: filter[FILTERS.ERROR],
++        label: getLabel(
++          l10n.getStr("webconsole.errorsFilterButton.label"),
++          FILTERS.ERROR
++        ),
++        filterKey: FILTERS.ERROR,
++        dispatch
++      }),
++      FilterButton({
++        active: filter[FILTERS.WARN],
++        label: getLabel(
++          l10n.getStr("webconsole.warningsFilterButton.label"),
++          FILTERS.WARN
++        ),
++        filterKey: FILTERS.WARN,
++        dispatch
++      }),
++      FilterButton({
++        active: filter[FILTERS.LOG],
++        label: getLabel(l10n.getStr("webconsole.logsFilterButton.label"), FILTERS.LOG),
++        filterKey: FILTERS.LOG,
++        dispatch
++      }),
++      FilterButton({
++        active: filter[FILTERS.INFO],
++        label: getLabel(l10n.getStr("webconsole.infoFilterButton.label"), FILTERS.INFO),
++        filterKey: FILTERS.INFO,
++        dispatch
++      }),
++      FilterButton({
++        active: filter[FILTERS.DEBUG],
++        label: getLabel(l10n.getStr("webconsole.debugFilterButton.label"), FILTERS.DEBUG),
++        filterKey: FILTERS.DEBUG,
++        dispatch
++      }),
++      dom.span({
++        className: "devtools-separator",
+       }),
++      FilterButton({
++        active: filter[FILTERS.CSS],
++        label: l10n.getStr("webconsole.cssFilterButton.label"),
++        filterKey: FILTERS.CSS,
++        dispatch
++      }),
++      FilterButton({
++        active: filter[FILTERS.NETXHR],
++        label: l10n.getStr("webconsole.xhrFilterButton.label"),
++        filterKey: FILTERS.NETXHR,
++        dispatch
++      }),
++      FilterButton({
++        active: filter[FILTERS.NET],
++        label: l10n.getStr("webconsole.requestsFilterButton.label"),
++        filterKey: FILTERS.NET,
++        dispatch
++      })
++    );
++  },
++
++  renderFilteredMessagesBar() {
++    const {
++      filteredMessagesCount
++    } = this.props;
++    const {
++      global,
++    } = filteredMessagesCount;
++
++    let label = l10n.getStr("webconsole.filteredMessages.label");
++    label = PluralForm.get(global, label).replace("#1", global);
++
++    // Include all default filters that are hiding messages.
++    let title = DEFAULT_FILTERS.reduce((res, filter) => {
++      if (filteredMessagesCount[filter] > 0) {
++        return res.concat(`${filter}: ${filteredMessagesCount[filter]}`);
++      }
++      return res;
++    }, []).join(", ");
++
++    return dom.div({
++      className: "devtools-toolbar webconsole-filterbar-filtered-messages",
++      key: "filtered-messages-bar",
++    },
++      dom.span({
++        className: "filter-message-text",
++        title,
++      }, label),
+       dom.button({
+-        className: "devtools-button devtools-filter-icon" + (
+-          filterBarVisible ? " checked" : ""),
+-        title: l10n.getStr("webconsole.toggleFilterButton.tooltip"),
+-        onClick: this.onClickFilterBarToggle
+-      }),
+-      dom.input({
+-        className: "devtools-plaininput text-filter",
+-        type: "search",
+-        value: filter.text,
+-        placeholder: l10n.getStr("webconsole.filterInput.placeholder"),
+-        onInput: this.onSearchInput
+-      })
+-    ));
++        className: "devtools-button reset-filters-button",
++        onClick: this.onClickRemoveAllFilters
++      }, l10n.getStr("webconsole.resetFiltersButton.label"))
++    );
++  },
++
++  render() {
++    const {
++      filter,
++      filterBarVisible,
++      filteredMessagesCount,
++    } = this.props;
++
++    let children = [
++      dom.div({
++        className: "devtools-toolbar webconsole-filterbar-primary",
++        key: "primary-bar",
++      },
++        dom.button({
++          className: "devtools-button devtools-clear-icon",
++          title: l10n.getStr("webconsole.clearButton.tooltip"),
++          onClick: this.onClickMessagesClear
++        }),
++        dom.button({
++          className: "devtools-button devtools-filter-icon" + (
++            filterBarVisible ? " checked" : ""),
++          title: l10n.getStr("webconsole.toggleFilterButton.tooltip"),
++          onClick: this.onClickFilterBarToggle
++        }),
++        dom.input({
++          className: "devtools-plaininput text-filter",
++          type: "search",
++          value: filter.text,
++          placeholder: l10n.getStr("webconsole.filterInput.placeholder"),
++          onInput: this.onSearchInput
++        })
++      )
++    ];
++
++    if (filteredMessagesCount.global > 0) {
++      children.push(this.renderFilteredMessagesBar());
++    }
+ 
+     if (filterBarVisible) {
+-      children.push(
+-        dom.div({className: "devtools-toolbar webconsole-filterbar-secondary"},
+-          FilterButton({
+-            active: filter.error,
+-            label: l10n.getStr("webconsole.errorsFilterButton.label"),
+-            filterKey: MESSAGE_LEVEL.ERROR,
+-            dispatch
+-          }),
+-          FilterButton({
+-            active: filter.warn,
+-            label: l10n.getStr("webconsole.warningsFilterButton.label"),
+-            filterKey: MESSAGE_LEVEL.WARN,
+-            dispatch
+-          }),
+-          FilterButton({
+-            active: filter.log,
+-            label: l10n.getStr("webconsole.logsFilterButton.label"),
+-            filterKey: MESSAGE_LEVEL.LOG,
+-            dispatch
+-          }),
+-          FilterButton({
+-            active: filter.info,
+-            label: l10n.getStr("webconsole.infoFilterButton.label"),
+-            filterKey: MESSAGE_LEVEL.INFO,
+-            dispatch
+-          }),
+-          FilterButton({
+-            active: filter.debug,
+-            label: l10n.getStr("webconsole.debugFilterButton.label"),
+-            filterKey: MESSAGE_LEVEL.DEBUG,
+-            dispatch
+-          }),
+-          dom.span({
+-            className: "devtools-separator",
+-          }),
+-          FilterButton({
+-            active: filter.css,
+-            label: l10n.getStr("webconsole.cssFilterButton.label"),
+-            filterKey: "css",
+-            dispatch
+-          }),
+-          FilterButton({
+-            active: filter.netxhr,
+-            label: l10n.getStr("webconsole.xhrFilterButton.label"),
+-            filterKey: "netxhr",
+-            dispatch
+-          }),
+-          FilterButton({
+-            active: filter.net,
+-            label: l10n.getStr("webconsole.requestsFilterButton.label"),
+-            filterKey: "net",
+-            dispatch
+-          })
+-        )
+-      );
++      children.push(this.renderFiltersConfigBar());
+     }
+ 
+     return (
+       dom.div({
+         className: "webconsole-filteringbar-wrapper",
+         ref: node => {
+           this.wrapperNode = node;
+         }
+@@ -146,12 +250,13 @@ const FilterBar = createClass({
+     );
+   }
+ });
+ 
+ function mapStateToProps(state) {
+   return {
+     filter: getAllFilters(state),
+     filterBarVisible: getAllUi(state).filterBarVisible,
++    filteredMessagesCount: getFilteredMessagesCount(state),
+   };
+ }
+ 
+ module.exports = connect(mapStateToProps)(FilterBar);
+diff --git a/devtools/client/webconsole/new-console-output/constants.js b/devtools/client/webconsole/new-console-output/constants.js
+--- a/devtools/client/webconsole/new-console-output/constants.js
++++ b/devtools/client/webconsole/new-console-output/constants.js
+@@ -15,16 +15,17 @@ const actionTypes = {
+   MESSAGE_TABLE_RECEIVE: "MESSAGE_TABLE_RECEIVE",
+   MESSAGE_OBJECT_PROPERTIES_RECEIVE: "MESSAGE_OBJECT_PROPERTIES_RECEIVE",
+   MESSAGE_OBJECT_ENTRIES_RECEIVE: "MESSAGE_OBJECT_ENTRIES_RECEIVE",
+   REMOVED_ACTORS_CLEAR: "REMOVED_ACTORS_CLEAR",
+   TIMESTAMPS_TOGGLE: "TIMESTAMPS_TOGGLE",
+   FILTER_TOGGLE: "FILTER_TOGGLE",
+   FILTER_TEXT_SET: "FILTER_TEXT_SET",
+   FILTERS_CLEAR: "FILTERS_CLEAR",
++  DEFAULT_FILTERS_RESET: "DEFAULT_FILTERS_RESET",
+   FILTER_BAR_TOGGLE: "FILTER_BAR_TOGGLE",
+ };
+ 
+ const prefs = {
+   PREFS: {
+     FILTER: {
+       ERROR: "devtools.webconsole.filter.error",
+       WARN: "devtools.webconsole.filter.warn",
+@@ -36,16 +37,43 @@ const prefs = {
+       NETXHR: "devtools.webconsole.filter.netxhr",
+     },
+     UI: {
+       FILTER_BAR: "devtools.webconsole.ui.filterbar"
+     }
+   }
+ };
+ 
++const FILTERS = {
++  CSS: "css",
++  DEBUG: "debug",
++  ERROR: "error",
++  INFO: "info",
++  LOG: "log",
++  NET: "net",
++  NETXHR: "netxhr",
++  TEXT: "text",
++  WARN: "warn",
++};
++
++const DEFAULT_FILTERS_VALUES = {
++  [FILTERS.TEXT]: "",
++  [FILTERS.ERROR]: true,
++  [FILTERS.WARN]: true,
++  [FILTERS.LOG]: true,
++  [FILTERS.INFO]: true,
++  [FILTERS.DEBUG]: true,
++  [FILTERS.CSS]: false,
++  [FILTERS.NET]: false,
++  [FILTERS.NETXHR]: false,
++};
++
++const DEFAULT_FILTERS = Object.keys(DEFAULT_FILTERS_VALUES)
++  .filter(filter => DEFAULT_FILTERS_VALUES[filter] !== false);
++
+ const chromeRDPEnums = {
+   MESSAGE_SOURCE: {
+     XML: "xml",
+     CSS: "css",
+     JAVASCRIPT: "javascript",
+     NETWORK: "network",
+     CONSOLE_API: "console-api",
+     STORAGE: "storage",
+@@ -87,14 +115,18 @@ const chromeRDPEnums = {
+ 
+ const jstermCommands = {
+   JSTERM_COMMANDS: {
+     INSPECT: "inspectObject"
+   }
+ };
+ 
+ // Combine into a single constants object
+-module.exports = Object.assign({},
++module.exports = Object.assign({
++  FILTERS,
++  DEFAULT_FILTERS,
++  DEFAULT_FILTERS_VALUES,
++},
+   actionTypes,
+   chromeRDPEnums,
+   jstermCommands,
+   prefs,
+ );
+diff --git a/devtools/client/webconsole/new-console-output/reducers/filters.js b/devtools/client/webconsole/new-console-output/reducers/filters.js
+--- a/devtools/client/webconsole/new-console-output/reducers/filters.js
++++ b/devtools/client/webconsole/new-console-output/reducers/filters.js
+@@ -3,38 +3,34 @@
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ "use strict";
+ 
+ const Immutable = require("devtools/client/shared/vendor/immutable");
+ const constants = require("devtools/client/webconsole/new-console-output/constants");
+ 
+-const FilterState = Immutable.Record({
+-  css: false,
+-  debug: true,
+-  error: true,
+-  info: true,
+-  log: true,
+-  net: false,
+-  netxhr: false,
+-  text: "",
+-  warn: true,
+-});
++const FilterState = Immutable.Record(constants.DEFAULT_FILTERS_VALUES);
+ 
+ function filters(state = new FilterState(), action) {
+   switch (action.type) {
+     case constants.FILTER_TOGGLE:
+       const {filter} = action;
+       const active = !state.get(filter);
+       return state.set(filter, active);
+     case constants.FILTERS_CLEAR:
+       return new FilterState();
++    case constants.DEFAULT_FILTERS_RESET:
++      return state.withMutations(record => {
++        constants.DEFAULT_FILTERS.forEach(filterName => {
++          record.set(filterName, constants.DEFAULT_FILTERS_VALUES[filterName]);
++        });
++      });
+     case constants.FILTER_TEXT_SET:
+       let {text} = action;
+-      return state.set("text", text);
++      return state.set(constants.FILTERS.TEXT, text);
+   }
+ 
+   return state;
+ }
+ 
+ exports.FilterState = FilterState;
+ exports.filters = filters;
+diff --git a/devtools/client/webconsole/new-console-output/reducers/messages.js b/devtools/client/webconsole/new-console-output/reducers/messages.js
+--- a/devtools/client/webconsole/new-console-output/reducers/messages.js
++++ b/devtools/client/webconsole/new-console-output/reducers/messages.js
+@@ -1,32 +1,39 @@
+ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+ /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ "use strict";
+ 
+ const Immutable = require("devtools/client/shared/vendor/immutable");
+-const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
++
++const {
++  isGroupType,
++  l10n,
++} = require("devtools/client/webconsole/new-console-output/utils/messages");
+ 
+ const constants = require("devtools/client/webconsole/new-console-output/constants");
+-const {isGroupType} = require("devtools/client/webconsole/new-console-output/utils/messages");
+ const {
++  DEFAULT_FILTERS,
++  FILTERS,
+   MESSAGE_TYPE,
+-  MESSAGE_SOURCE
+-} = require("devtools/client/webconsole/new-console-output/constants");
++  MESSAGE_SOURCE,
++} = constants;
+ const { getGripPreviewItems } = require("devtools/client/shared/components/reps/reps");
+ const { getSourceNames } = require("devtools/client/shared/source-utils");
+ 
+ const MessageState = Immutable.Record({
+   // List of all the messages added to the console.
+   messagesById: Immutable.OrderedMap(),
+   // Array of the visible messages.
+   visibleMessages: [],
++  // Object for the filtered messages.
++  filteredMessagesCount: getDefaultFiltersCounter(),
+   // List of the message ids which are opened.
+   messagesUiById: Immutable.List(),
+   // Map of the form {messageId : tableData}, which represent the data passed
+   // as an argument in console.table calls.
+   messagesTableDataById: Immutable.Map(),
+   // Map of the form {messageId : {[actor]: properties}}, where `properties` is
+   // a RDP packet containing the properties of the ${actor} grip.
+   // This map is consumed by the ObjectInspector so we only load properties once,
+@@ -60,16 +67,17 @@ function messages(state = new MessageSta
+     messagesTableDataById,
+     messagesObjectPropertiesById,
+     messagesObjectEntriesById,
+     networkMessagesUpdateById,
+     groupsById,
+     currentGroup,
+     repeatById,
+     visibleMessages,
++    filteredMessagesCount,
+   } = state;
+ 
+   const {logLimit} = prefsState;
+ 
+   switch (action.type) {
+     case constants.MESSAGE_ADD:
+       let newMessage = action.message;
+ 
+@@ -118,18 +126,28 @@ function messages(state = new MessageSta
+           record.set("groupsById", groupsById.set(newMessage.id, parentGroups));
+ 
+           if (newMessage.type === constants.MESSAGE_TYPE.START_GROUP) {
+             // We want the group to be open by default.
+             record.set("messagesUiById", messagesUiById.push(newMessage.id));
+           }
+         }
+ 
+-        if (shouldMessageBeVisible(addedMessage, record, filtersState)) {
++        const {
++          visible,
++          cause
++        } = getMessageVisibility(addedMessage, record, filtersState);
++
++        if (visible) {
+           record.set("visibleMessages", [...visibleMessages, newMessage.id]);
++        } else if (DEFAULT_FILTERS.includes(cause)) {
++          record.set("filteredMessagesCount", Object.assign({}, filteredMessagesCount, {
++            global: filteredMessagesCount.global + 1,
++            [cause]: filteredMessagesCount[cause] + 1
++          }));
+         }
+ 
+         // Remove top level message if the total count of top level messages
+         // exceeds the current limit.
+         if (record.messagesById.size > logLimit) {
+           limitTopLevelMessageCount(state, record, logLimit);
+         }
+       });
+@@ -150,24 +168,24 @@ function messages(state = new MessageSta
+ 
+         // If the message is a group
+         if (isGroupType(messagesById.get(action.id).type)) {
+           // We want to make its children visible
+           const messagesToShow = [...messagesById].reduce((res, [id, message]) => {
+             if (
+               !visibleMessages.includes(message.id)
+               && getParentGroups(message.groupId, groupsById).includes(action.id)
+-              && shouldMessageBeVisible(
++              && getMessageVisibility(
+                 message,
+                 record,
+                 filtersState,
+                 // We want to check if the message is in an open group
+                 // only if it is not a direct child of the group we're opening.
+                 message.groupId !== action.id
+-              )
++              ).visible
+             ) {
+               res.push(id);
+             }
+             return res;
+           }, []);
+ 
+           // We can then insert the messages ids right after the one of the group.
+           const insertIndex = visibleMessages.indexOf(action.id) + 1;
+@@ -232,25 +250,37 @@ function messages(state = new MessageSta
+         })
+       );
+ 
+     case constants.REMOVED_ACTORS_CLEAR:
+       return state.set("removedActors", []);
+ 
+     case constants.FILTER_TOGGLE:
+     case constants.FILTER_TEXT_SET:
+-      return state.set(
+-        "visibleMessages",
+-        [...messagesById].reduce((res, [messageId, message]) => {
+-          if (shouldMessageBeVisible(message, state, filtersState)) {
+-            res.push(messageId);
++    case constants.FILTERS_CLEAR:
++    case constants.DEFAULT_FILTERS_RESET:
++      return state.withMutations(function (record) {
++        const messagesToShow = [];
++        const filtered = getDefaultFiltersCounter();
++        messagesById.forEach((message, messageId) => {
++          const {
++            visible,
++            cause
++          } = getMessageVisibility(message, state, filtersState);
++          if (visible) {
++            messagesToShow.push(messageId);
++          } else if (DEFAULT_FILTERS.includes(cause)) {
++            filtered.global = filtered.global + 1;
++            filtered[cause] = filtered[cause] + 1;
+           }
+-          return res;
+-        }, [])
+-      );
++        });
++
++        record.set("visibleMessages", messagesToShow);
++        record.set("filteredMessagesCount", filtered);
++      });
+   }
+ 
+   return state;
+ }
+ 
+ function getNewCurrentGroup(currentGoup, groupsById) {
+   let newCurrentGroup = null;
+   if (currentGoup) {
+@@ -427,66 +457,83 @@ function getAllActorsInMessage(message, 
+  * Returns total count of top level messages (those which are not
+  * within a group).
+  */
+ function getToplevelMessageCount(record) {
+   return record.messagesById.count(message => !message.groupId);
+ }
+ 
+ /**
+- * Returns true if given message should be visible, false otherwise.
++ * Check if a message should be visible in the console output, and if not, what
++ * causes it to be hidden.
++ *
++ * @return {Object} An object of the following form:
++ *         - visible {Boolean}: true if the message should be visible
++ *         - cause {String}: if visible is false, what causes the message to be hidden.
+  */
+-function shouldMessageBeVisible(message, messagesState, filtersState, checkGroup = true) {
++function getMessageVisibility(message, messagesState, filtersState, checkGroup = true) {
+   // Do not display the message if it's in closed group.
+   if (
+     checkGroup
+     && !isInOpenedGroup(message, messagesState.groupsById, messagesState.messagesUiById)
+   ) {
+-    return false;
++    return {
++      visible: false,
++      cause: "closedGroup"
++    };
+   }
+ 
+   // Some messages can't be filtered out (e.g. groups).
+-  // So, always return true for those.
++  // So, always return visible: true for those.
+   if (isUnfilterable(message)) {
+-    return true;
++    return {
++      visible: true
++    };
+   }
+ 
+-  // Let's check all filters and hide the message if they say so.
+-  if (!matchFilters(message, filtersState)) {
+-    return false;
++  if (!passSearchFilters(message, filtersState)) {
++    return {
++      visible: false,
++      cause: FILTERS.TEXT
++    };
+   }
+ 
+-  // If there is a free text available for filtering use it to decide
+-  // whether the message is displayed or not.
+-  let text = (filtersState.text || "").trim();
+-  if (text) {
+-    return matchSearchFilters(message, text);
++  // Let's check all level filters (error, warn, log, …) and return visible: false
++  // and the message level as a cause if the function returns false.
++  if (!passLevelFilters(message, filtersState)) {
++    return {
++      visible: false,
++      cause: message.level
++    };
+   }
+ 
+-  return true;
+-}
+-
+-function matchFilters(message, filtersState) {
+-  if (matchLevelFilters(message, filtersState)) {
+-    return true;
++  if (!passCssFilters(message, filtersState)) {
++    return {
++      visible: false,
++      cause: FILTERS.CSS
++    };
+   }
+ 
+-  // Return true if the message source is 'css'
+-  // and CSS filter is enabled.
+-  if (matchCssFilters(message, filtersState)) {
+-    return true;
++  if (!passNetworkFilter(message, filtersState)) {
++    return {
++      visible: false,
++      cause: FILTERS.NET
++    };
+   }
+ 
+-  // Return true if the message is network event
+-  // and Network and/or XHR filter is enabled.
+-  if (matchNetworkFilters(message, filtersState)) {
+-    return true;
++  if (!passXhrFilter(message, filtersState)) {
++    return {
++      visible: false,
++      cause: FILTERS.NETXHR
++    };
+   }
+ 
+-  return false;
++  return {
++    visible: true
++  };
+ }
+ 
+ function isUnfilterable(message) {
+   return [
+     MESSAGE_TYPE.COMMAND,
+     MESSAGE_TYPE.RESULT,
+     MESSAGE_TYPE.START_GROUP,
+     MESSAGE_TYPE.START_GROUP_COLLAPSED,
+@@ -504,40 +551,100 @@ function isInOpenedGroup(message, groups
+ function hasClosedParentGroup(group, messagesUI) {
+   return group.some(groupId => isGroupClosed(groupId, messagesUI));
+ }
+ 
+ function isGroupClosed(groupId, messagesUI) {
+   return messagesUI.includes(groupId) === false;
+ }
+ 
+-function matchNetworkFilters(message, filters) {
++/**
++ * Returns true if the message shouldn't be hidden because of the network filter state.
++ *
++ * @param {Object} message - The message to check the filter against.
++ * @param {FilterState} filters - redux "filters" state.
++ * @returns {Boolean}
++ */
++function passNetworkFilter(message, filters) {
++  // The message passes the filter if it is not a network message,
++  // or if it is an xhr one,
++  // or if the network filter is on.
+   return (
+-    message.source === MESSAGE_SOURCE.NETWORK &&
+-    (filters.get("net") === true && message.isXHR === false) ||
+-    (filters.get("netxhr") === true && message.isXHR === true)
++    message.source !== MESSAGE_SOURCE.NETWORK ||
++    message.isXHR === true ||
++    filters.get(FILTERS.NET) === true
+   );
+ }
+ 
+-function matchLevelFilters(message, filters) {
++/**
++ * Returns true if the message shouldn't be hidden because of the xhr filter state.
++ *
++ * @param {Object} message - The message to check the filter against.
++ * @param {FilterState} filters - redux "filters" state.
++ * @returns {Boolean}
++ */
++function passXhrFilter(message, filters) {
++  // The message passes the filter if it is not a network message,
++  // or if it is a non-xhr one,
++  // or if the xhr filter is on.
+   return (
+-    (message.source === MESSAGE_SOURCE.CONSOLE_API ||
+-    message.source === MESSAGE_SOURCE.JAVASCRIPT) &&
++    message.source !== MESSAGE_SOURCE.NETWORK ||
++    message.isXHR === false ||
++    filters.get(FILTERS.NETXHR) === true
++  );
++}
++
++/**
++ * Returns true if the message shouldn't be hidden because of levels filter state.
++ *
++ * @param {Object} message - The message to check the filter against.
++ * @param {FilterState} filters - redux "filters" state.
++ * @returns {Boolean}
++ */
++function passLevelFilters(message, filters) {
++  // The message passes the filter if it is not a console call,
++  // or if its level matches the state of the corresponding filter.
++  return (
++    (message.source !== MESSAGE_SOURCE.CONSOLE_API &&
++    message.source !== MESSAGE_SOURCE.JAVASCRIPT) ||
+     filters.get(message.level) === true
+   );
+ }
+ 
+-function matchCssFilters(message, filters) {
++/**
++ * Returns true if the message shouldn't be hidden because of the CSS filter state.
++ *
++ * @param {Object} message - The message to check the filter against.
++ * @param {FilterState} filters - redux "filters" state.
++ * @returns {Boolean}
++ */
++function passCssFilters(message, filters) {
++  // The message passes the filter if it is not a CSS message,
++  // or if the CSS filter is on.
+   return (
+-    message.source === MESSAGE_SOURCE.CSS &&
++    message.source !== MESSAGE_SOURCE.CSS ||
+     filters.get("css") === true
+   );
+ }
+ 
+-function matchSearchFilters(message, text) {
++/**
++ * Returns true if the message shouldn't be hidden because of search filter state.
++ *
++ * @param {Object} message - The message to check the filter against.
++ * @param {FilterState} filters - redux "filters" state.
++ * @returns {Boolean}
++ */
++function passSearchFilters(message, filters) {
++  let text = (filters.get("text") || "").trim();
++
++  // If there is no search, the message passes the filter.
++  if (!text) {
++    return true;
++  }
++
+   return (
+     // Look for a match in parameters.
+     isTextInParameters(text, message.parameters)
+     // Look for a match in location.
+     || isTextInFrame(text, message.frame)
+     // Look for a match in net events.
+     || isTextInNetEvent(text, message.request)
+     // Look for a match in stack-trace.
+@@ -665,9 +772,18 @@ function getAllProps(grips) {
+   result = result.filter(grip =>
+     typeof grip != "object" &&
+     typeof grip != "undefined"
+   );
+ 
+   return [...new Set(result)];
+ }
+ 
++function getDefaultFiltersCounter() {
++  const count = DEFAULT_FILTERS.reduce((res, filter) => {
++    res[filter] = 0;
++    return res;
++  }, {});
++  count.global = 0;
++  return count;
++}
++
+ exports.messages = messages;
+diff --git a/devtools/client/webconsole/new-console-output/selectors/messages.js b/devtools/client/webconsole/new-console-output/selectors/messages.js
+--- a/devtools/client/webconsole/new-console-output/selectors/messages.js
++++ b/devtools/client/webconsole/new-console-output/selectors/messages.js
+@@ -36,29 +36,34 @@ function getAllGroupsById(state) {
+ function getCurrentGroup(state) {
+   return state.messages.currentGroup;
+ }
+ 
+ function getVisibleMessages(state) {
+   return state.messages.visibleMessages;
+ }
+ 
++function getFilteredMessagesCount(state) {
++  return state.messages.filteredMessagesCount;
++}
++
+ function getAllRepeatById(state) {
+   return state.messages.repeatById;
+ }
+ 
+ function getAllNetworkMessagesUpdateById(state) {
+   return state.messages.networkMessagesUpdateById;
+ }
+ 
+ module.exports = {
+   getMessage,
+   getAllMessagesById,
+   getAllMessagesUiById,
+   getAllMessagesTableDataById,
+   getAllGroupsById,
+   getCurrentGroup,
+   getVisibleMessages,
++  getFilteredMessagesCount,
+   getAllRepeatById,
+   getAllNetworkMessagesUpdateById,
+   getAllMessagesObjectPropertiesById,
+   getAllMessagesObjectEntriesById,
+ };

+ 694 - 0
frg/253-58/mozilla-release58_428079.patch

@@ -0,0 +1,694 @@
+# HG changeset patch
+# User Nicolas Chevobbe <nchevobbe@mozilla.com>
+# Date 1502198823 -7200
+#      Tue Aug 08 15:27:03 2017 +0200
+# Node ID c43b0aed18a5f3643e92b62f5fc1e53a7f2f24b2
+# Parent  c72fb15e6f6e6c7c3f67690f509bbadd8f709de9
+Bug 1307880 - Add tests for the "Hidden messages" toolbar. r=bgrins
+
+This adds some tests to ensure the hidden messages toolbar works
+as expected. There are some for testing the component itself, as
+well as some to test the store.
+Some fixtures were modified as well to better represent the state
+of the application.
+
+
+MozReview-Commit-ID: 3Swqff1mbck
+
+diff --git a/devtools/client/webconsole/new-console-output/test/components/filter-bar.test.js b/devtools/client/webconsole/new-console-output/test/components/filter-bar.test.js
+--- a/devtools/client/webconsole/new-console-output/test/components/filter-bar.test.js
++++ b/devtools/client/webconsole/new-console-output/test/components/filter-bar.test.js
+@@ -4,22 +4,24 @@
+ 
+ const expect = require("expect");
+ const sinon = require("sinon");
+ const { render, mount, shallow } = require("enzyme");
+ 
+ const { createFactory, DOM } = require("devtools/client/shared/vendor/react");
+ const Provider = createFactory(require("react-redux").Provider);
+ 
++const actions = require("devtools/client/webconsole/new-console-output/actions/index");
+ const FilterButton = require("devtools/client/webconsole/new-console-output/components/filter-button");
+ const FilterBar = createFactory(require("devtools/client/webconsole/new-console-output/components/filter-bar"));
+ const { getAllUi } = require("devtools/client/webconsole/new-console-output/selectors/ui");
++const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
+ const {
+   MESSAGES_CLEAR,
+-  MESSAGE_LEVEL
++  FILTERS,
+ } = require("devtools/client/webconsole/new-console-output/constants");
+ 
+ const { setupStore } = require("devtools/client/webconsole/new-console-output/test/helpers");
+ const serviceContainer = require("devtools/client/webconsole/new-console-output/test/fixtures/serviceContainer");
+ 
+ describe("FilterBar component:", () => {
+   it("initial render", () => {
+     const store = setupStore([]);
+@@ -42,16 +44,150 @@ describe("FilterBar component:", () => {
+     // Text filter
+     expect(toolbar.children().eq(2).attr("class"))
+       .toBe("devtools-plaininput text-filter");
+     expect(toolbar.children().eq(2).attr("placeholder")).toBe("Filter output");
+     expect(toolbar.children().eq(2).attr("type")).toBe("search");
+     expect(toolbar.children().eq(2).attr("value")).toBe("");
+   });
+ 
++  it("displays the number of hidden messages when there are one hidden message", () => {
++    const store = setupStore([
++      "console.log('foobar', 'test')"
++    ]);
++    // Filter-out LOG messages
++    store.dispatch(actions.filterToggle(FILTERS.LOG));
++
++    const wrapper = mount(Provider({store}, FilterBar({ serviceContainer })));
++    const toolbar = wrapper.find(".webconsole-filterbar-filtered-messages");
++    expect(toolbar.exists()).toBeTruthy();
++
++    const message = toolbar.find(".filter-message-text");
++    expect(message.text()).toBe("1 item hidden by filters");
++    expect(message.prop("title")).toBe("log: 1");
++  });
++
++  it("Reset filters when the Reset filters button is clicked.", () => {
++    const store = setupStore([
++      "console.log('foobar', 'test')"
++    ]);
++    // Filter-out LOG messages
++    store.dispatch(actions.filterToggle(FILTERS.LOG));
++    const wrapper = mount(Provider({store}, FilterBar({serviceContainer})));
++
++    const resetFiltersButton = wrapper.find(
++      ".webconsole-filterbar-filtered-messages .devtools-button");
++    resetFiltersButton.simulate("click");
++
++    // Toolbar is now hidden
++    const toolbar = wrapper.find(".webconsole-filterbar-filtered-messages");
++    expect(toolbar.exists()).toBeFalsy();
++    expect(getAllFilters(store.getState()).get(FILTERS.LOG)).toBeTruthy();
++  });
++
++  it("displays the number of hidden messages when a search hide messages", () => {
++    const store = setupStore([
++      "console.log('foobar', 'test')",
++      "console.info('info message');",
++      "console.warn('danger, will robinson!')",
++      "console.debug('debug message');",
++      "console.error('error message');",
++    ]);
++    store.dispatch(actions.filterTextSet("qwerty"));
++
++    const wrapper = mount(Provider({store}, FilterBar({ serviceContainer })));
++    const toolbar = wrapper.find(".webconsole-filterbar-filtered-messages");
++    expect(toolbar.exists()).toBeTruthy();
++
++    const message = toolbar.find(".filter-message-text");
++    expect(message.text()).toBe("5 items hidden by filters");
++    expect(message.prop("title")).toBe("text: 5");
++  });
++
++  it("displays the number of hidden messages when there are multiple ones", () => {
++    const store = setupStore([
++      "console.log('foobar', 'test')",
++      "console.info('info message');",
++      "console.warn('danger, will robinson!')",
++      "console.debug('debug message');",
++      "console.error('error message');",
++      "console.log('foobar', 'test')",
++      "console.info('info message');",
++      "console.warn('danger, will robinson!')",
++      "console.debug('debug message');",
++      "console.error('error message');",
++    ]);
++
++    store.dispatch(actions.filterToggle(FILTERS.ERROR));
++    store.dispatch(actions.filterToggle(FILTERS.WARN));
++    store.dispatch(actions.filterToggle(FILTERS.LOG));
++    store.dispatch(actions.filterToggle(FILTERS.INFO));
++    store.dispatch(actions.filterToggle(FILTERS.DEBUG));
++    store.dispatch(actions.filterTextSet("qwerty"));
++
++    const wrapper = mount(Provider({store}, FilterBar({ serviceContainer })));
++    const message = wrapper.find(".filter-message-text");
++
++    expect(message.prop("title")).toBe("text: 10");
++  });
++
++  it("displays expected tooltip when there is text & level hidden-messages", () => {
++    const store = setupStore([
++      "console.log('foobar', 'test')",
++      "console.info('info message');",
++      "console.warn('danger, will robinson!')",
++      "console.debug('debug message');",
++      "console.error('error message');",
++      "console.log('foobar', 'test')",
++      "console.info('info message');",
++      "console.warn('danger, will robinson!')",
++      "console.debug('debug message');",
++      "console.error('error message');",
++    ]);
++
++    store.dispatch(actions.filterToggle(FILTERS.ERROR));
++    store.dispatch(actions.filterToggle(FILTERS.WARN));
++    store.dispatch(actions.filterToggle(FILTERS.LOG));
++    store.dispatch(actions.filterToggle(FILTERS.INFO));
++    store.dispatch(actions.filterToggle(FILTERS.DEBUG));
++
++    const wrapper = mount(Provider({store}, FilterBar({ serviceContainer })));
++    const toolbar = wrapper.find(".webconsole-filterbar-filtered-messages");
++    expect(toolbar.exists()).toBeTruthy();
++
++    const message = toolbar.find(".filter-message-text");
++    expect(message.text()).toBe("10 items hidden by filters");
++    expect(message.prop("title")).toBe("error: 2, warn: 2, log: 2, info: 2, debug: 2");
++  });
++
++  it("does not display the number of hidden messages when there are no messages", () => {
++    const store = setupStore([]);
++    const wrapper = mount(Provider({store}, FilterBar({ serviceContainer })));
++    const toolbar = wrapper.find(".webconsole-filterbar-filtered-messages");
++    expect(toolbar.exists()).toBeFalsy();
++  });
++
++  it("does not display the number of hidden non-default filters (CSS, Network,…)", () => {
++    const store = setupStore([
++      "Unknown property ‘such-unknown-property’.  Declaration dropped.",
++      "GET request",
++      "XHR GET request"
++    ]);
++    const wrapper = mount(Provider({store}, FilterBar({ serviceContainer })));
++
++    // Let's make sure those non-default filters are off.
++    const filters = getAllFilters(store.getState());
++    expect(filters.get(FILTERS.CSS)).toBe(false);
++    expect(filters.get(FILTERS.NET)).toBe(false);
++    expect(filters.get(FILTERS.NETXHR)).toBe(false);
++
++    const toolbar = wrapper.find(".webconsole-filterbar-filtered-messages");
++    expect(toolbar.exists()).toBeFalsy();
++  });
++
+   it("displays filter bar when button is clicked", () => {
+     const store = setupStore([]);
+ 
+     expect(getAllUi(store.getState()).filterBarVisible).toBe(false);
+ 
+     const wrapper = mount(Provider({store}, FilterBar({ serviceContainer })));
+     wrapper.find(".devtools-filter-icon").simulate("click");
+ 
+@@ -64,25 +200,25 @@ describe("FilterBar component:", () => {
+     const filterBtn = props => FilterButton(
+       Object.assign({}, {
+         active: true,
+         dispatch: store.dispatch
+       }, props)
+     );
+ 
+     let buttons = [
+-      filterBtn({ label: "Errors", filterKey: MESSAGE_LEVEL.ERROR }),
+-      filterBtn({ label: "Warnings", filterKey: MESSAGE_LEVEL.WARN }),
+-      filterBtn({ label: "Logs", filterKey: MESSAGE_LEVEL.LOG }),
+-      filterBtn({ label: "Info", filterKey: MESSAGE_LEVEL.INFO }),
+-      filterBtn({ label: "Debug", filterKey: MESSAGE_LEVEL.DEBUG }),
++      filterBtn({ label: "Errors", filterKey: FILTERS.ERROR }),
++      filterBtn({ label: "Warnings", filterKey: FILTERS.WARN }),
++      filterBtn({ label: "Logs", filterKey: FILTERS.LOG }),
++      filterBtn({ label: "Info", filterKey: FILTERS.INFO }),
++      filterBtn({ label: "Debug", filterKey: FILTERS.DEBUG }),
+       DOM.span({
+         className: "devtools-separator",
+       }),
+-      filterBtn({ label: "CSS", filterKey: "css" }),
++      filterBtn({ label: "CSS", filterKey: "css", active: false }),
+       filterBtn({ label: "XHR", filterKey: "netxhr", active: false }),
+       filterBtn({ label: "Requests", filterKey: "net", active: false }),
+     ];
+ 
+     secondaryBar.children().forEach((child, index) => {
+       expect(child.html()).toEqual(shallow(buttons[index]).html());
+     });
+   });
+diff --git a/devtools/client/webconsole/new-console-output/test/fixtures/L10n.js b/devtools/client/webconsole/new-console-output/test/fixtures/L10n.js
+--- a/devtools/client/webconsole/new-console-output/test/fixtures/L10n.js
++++ b/devtools/client/webconsole/new-console-output/test/fixtures/L10n.js
+@@ -32,16 +32,20 @@ class L10n {
+       case "webconsole.debugFilterButton.label":
+         return "Debug";
+       case "webconsole.cssFilterButton.label":
+         return "CSS";
+       case "webconsole.xhrFilterButton.label":
+         return "XHR";
+       case "webconsole.requestsFilterButton.label":
+         return "Requests";
++      case "messageRepeats.tooltip2":
++        return "#1 repeat;#1 repeats";
++      case "webconsole.filteredMessages.label":
++        return "#1 item hidden by filters;#1 items hidden by filters";
+       default:
+         return str;
+     }
+   }
+ 
+   getFormatStr(str) {
+     return this.getStr(str);
+   }
+diff --git a/devtools/client/webconsole/new-console-output/test/fixtures/PluralForm.js b/devtools/client/webconsole/new-console-output/test/fixtures/PluralForm.js
+--- a/devtools/client/webconsole/new-console-output/test/fixtures/PluralForm.js
++++ b/devtools/client/webconsole/new-console-output/test/fixtures/PluralForm.js
+@@ -1,18 +1,17 @@
+ /* Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/publicdomain/zero/1.0/ */
+ 
+ "use strict";
+ 
+ module.exports = {
+   PluralForm: {
+     get: function (occurence, str) {
+-      // @TODO Remove when loading the actual strings from webconsole.properties
+-      // is done in the L10n fixture.
+-      if (str === "messageRepeats.tooltip2") {
+-        return `${occurence} repeats`;
++      if (str.includes(";")) {
++        const [singular, plural] = str.split(";");
++        return occurence > 1 ? plural : singular;
+       }
+ 
+       return str;
+     }
+   }
+ };
+diff --git a/devtools/client/webconsole/new-console-output/test/fixtures/Services.js b/devtools/client/webconsole/new-console-output/test/fixtures/Services.js
+--- a/devtools/client/webconsole/new-console-output/test/fixtures/Services.js
++++ b/devtools/client/webconsole/new-console-output/test/fixtures/Services.js
+@@ -11,16 +11,17 @@ module.exports = {
+       switch (pref) {
+         case "devtools.hud.loglimit":
+           return 1000;
+       }
+       return null;
+     },
+     getBoolPref: pref => {
+       const falsey = [
++        PREFS.FILTER.CSS,
+         PREFS.FILTER.NET,
+         PREFS.FILTER.NETXHR,
+         PREFS.UI.FILTER_BAR,
+       ];
+       return !falsey.includes(pref);
+     },
+     setBoolPref: () => {},
+     clearUserPref: () => {},
+diff --git a/devtools/client/webconsole/new-console-output/test/helpers.js b/devtools/client/webconsole/new-console-output/test/helpers.js
+--- a/devtools/client/webconsole/new-console-output/test/helpers.js
++++ b/devtools/client/webconsole/new-console-output/test/helpers.js
+@@ -29,17 +29,17 @@ function setupActions() {
+   };
+ 
+   return wrappedActions;
+ }
+ 
+ /**
+  * Prepare the store for use in testing.
+  */
+-function setupStore(input, hud, options) {
++function setupStore(input = [], hud, options) {
+   const store = configureStore(hud, options);
+ 
+   // Add the messages from the input commands to the store.
+   input.forEach((cmd) => {
+     store.dispatch(actions.messageAdd(stubPackets.get(cmd)));
+   });
+ 
+   return store;
+diff --git a/devtools/client/webconsole/new-console-output/test/store/filters.test.js b/devtools/client/webconsole/new-console-output/test/store/filters.test.js
+--- a/devtools/client/webconsole/new-console-output/test/store/filters.test.js
++++ b/devtools/client/webconsole/new-console-output/test/store/filters.test.js
+@@ -6,17 +6,17 @@
+ const expect = require("expect");
+ 
+ const actions = require("devtools/client/webconsole/new-console-output/actions/index");
+ const { messageAdd } = require("devtools/client/webconsole/new-console-output/actions/index");
+ const { ConsoleCommand } = require("devtools/client/webconsole/new-console-output/types");
+ const { getVisibleMessages } = require("devtools/client/webconsole/new-console-output/selectors/messages");
+ const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
+ const { setupStore } = require("devtools/client/webconsole/new-console-output/test/helpers");
+-const { MESSAGE_LEVEL } = require("devtools/client/webconsole/new-console-output/constants");
++const { FILTERS } = require("devtools/client/webconsole/new-console-output/constants");
+ const { stubPackets } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index");
+ const { stubPreparedMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index");
+ 
+ describe("Filtering", () => {
+   let store;
+   let numMessages;
+   // Number of messages in prepareBaseStore which are not filtered out, i.e. Evaluation
+   // Results, console commands and console.groups .
+@@ -32,56 +32,56 @@ describe("Filtering", () => {
+    * Tests for filter buttons in Console toolbar. The test switches off
+    * all filters and consequently tests one by one on the list of messages
+    * created in `prepareBaseStore` method.
+    */
+   describe("Level filter", () => {
+     beforeEach(() => {
+       // Switch off all filters (include those which are on by default).
+       store.dispatch(actions.filtersClear());
+-      store.dispatch(actions.filterToggle(MESSAGE_LEVEL.DEBUG));
+-      store.dispatch(actions.filterToggle(MESSAGE_LEVEL.ERROR));
+-      store.dispatch(actions.filterToggle(MESSAGE_LEVEL.INFO));
+-      store.dispatch(actions.filterToggle(MESSAGE_LEVEL.LOG));
+-      store.dispatch(actions.filterToggle(MESSAGE_LEVEL.WARN));
++      store.dispatch(actions.filterToggle(FILTERS.DEBUG));
++      store.dispatch(actions.filterToggle(FILTERS.ERROR));
++      store.dispatch(actions.filterToggle(FILTERS.INFO));
++      store.dispatch(actions.filterToggle(FILTERS.LOG));
++      store.dispatch(actions.filterToggle(FILTERS.WARN));
+ 
+       let messages = getVisibleMessages(store.getState());
+       expect(messages.length).toEqual(numUnfilterableMessages);
+     });
+ 
+     it("filters log messages", () => {
+-      store.dispatch(actions.filterToggle(MESSAGE_LEVEL.LOG));
++      store.dispatch(actions.filterToggle(FILTERS.LOG));
+ 
+       let messages = getVisibleMessages(store.getState());
+       expect(messages.length).toEqual(numUnfilterableMessages + 5);
+     });
+ 
+     it("filters debug messages", () => {
+-      store.dispatch(actions.filterToggle(MESSAGE_LEVEL.DEBUG));
++      store.dispatch(actions.filterToggle(FILTERS.DEBUG));
+ 
+       let messages = getVisibleMessages(store.getState());
+       expect(messages.length).toEqual(numUnfilterableMessages + 1);
+     });
+ 
+     it("filters info messages", () => {
+-      store.dispatch(actions.filterToggle(MESSAGE_LEVEL.INFO));
++      store.dispatch(actions.filterToggle(FILTERS.INFO));
+ 
+       let messages = getVisibleMessages(store.getState());
+       expect(messages.length).toEqual(numUnfilterableMessages + 1);
+     });
+ 
+     it("filters warning messages", () => {
+-      store.dispatch(actions.filterToggle(MESSAGE_LEVEL.WARN));
++      store.dispatch(actions.filterToggle(FILTERS.WARN));
+ 
+       let messages = getVisibleMessages(store.getState());
+       expect(messages.length).toEqual(numUnfilterableMessages + 1);
+     });
+ 
+     it("filters error messages", () => {
+-      store.dispatch(actions.filterToggle(MESSAGE_LEVEL.ERROR));
++      store.dispatch(actions.filterToggle(FILTERS.ERROR));
+ 
+       let messages = getVisibleMessages(store.getState());
+       expect(messages.length).toEqual(numUnfilterableMessages + 3);
+     });
+ 
+     it("filters css messages", () => {
+       let message = stubPreparedMessages.get(
+         "Unknown property ‘such-unknown-property’.  Declaration dropped."
+@@ -201,30 +201,34 @@ describe("Filtering", () => {
+   });
+ });
+ 
+ describe("Clear filters", () => {
+   it("clears all filters", () => {
+     const store = setupStore([]);
+ 
+     // Setup test case
+-    store.dispatch(actions.filterToggle(MESSAGE_LEVEL.ERROR));
+-    store.dispatch(actions.filterToggle("netxhr"));
++    store.dispatch(actions.filterToggle(FILTERS.ERROR));
++    store.dispatch(actions.filterToggle(FILTERS.CSS));
++    store.dispatch(actions.filterToggle(FILTERS.NET));
++    store.dispatch(actions.filterToggle(FILTERS.NETXHR));
+     store.dispatch(actions.filterTextSet("foobar"));
+ 
+     let filters = getAllFilters(store.getState());
+     expect(filters.toJS()).toEqual({
+-      "css": true,
+-      "debug": true,
+-      "error": false,
++      // default
++      "warn": true,
++      "log": true,
+       "info": true,
+-      "log": true,
+-      "net": false,
++      "debug": true,
++      "css": true,
++      // changed
++      "error": false,
++      "net": true,
+       "netxhr": true,
+-      "warn": true,
+       "text": "foobar",
+     });
+ 
+     store.dispatch(actions.filtersClear());
+ 
+     filters = getAllFilters(store.getState());
+     expect(filters.toJS()).toEqual({
+       "css": false,
+@@ -235,16 +239,62 @@ describe("Clear filters", () => {
+       "net": false,
+       "netxhr": false,
+       "warn": true,
+       "text": "",
+     });
+   });
+ });
+ 
++describe("Resets filters", () => {
++  it("resets default filters value to their original one.", () => {
++    const store = setupStore([]);
++
++    // Setup test case
++    store.dispatch(actions.filterToggle(FILTERS.ERROR));
++    store.dispatch(actions.filterToggle(FILTERS.LOG));
++    store.dispatch(actions.filterToggle(FILTERS.CSS));
++    store.dispatch(actions.filterToggle(FILTERS.NET));
++    store.dispatch(actions.filterToggle(FILTERS.NETXHR));
++    store.dispatch(actions.filterTextSet("foobar"));
++
++    let filters = getAllFilters(store.getState());
++    expect(filters.toJS()).toEqual({
++      // default
++      "warn": true,
++      "info": true,
++      "debug": true,
++      // changed
++      "error": false,
++      "log": false,
++      "css": true,
++      "net": true,
++      "netxhr": true,
++      "text": "foobar",
++    });
++
++    store.dispatch(actions.defaultFiltersReset());
++
++    filters = getAllFilters(store.getState());
++    expect(filters.toJS()).toEqual({
++      // default
++      "error": true,
++      "warn": true,
++      "log": true,
++      "info": true,
++      "debug": true,
++      "text": "",
++      // non-default filters weren't changed
++      "css": true,
++      "net": true,
++      "netxhr": true,
++    });
++  });
++});
++
+ function prepareBaseStore() {
+   const store = setupStore([
+     // Console API
+     "console.log('foobar', 'test')",
+     "console.warn('danger, will robinson!')",
+     "console.log(undefined)",
+     "console.count('bar')",
+     "console.log('鼬')",
+diff --git a/devtools/client/webconsole/new-console-output/test/store/hidden-messages.test.js b/devtools/client/webconsole/new-console-output/test/store/hidden-messages.test.js
+new file mode 100644
+--- /dev/null
++++ b/devtools/client/webconsole/new-console-output/test/store/hidden-messages.test.js
+@@ -0,0 +1,173 @@
++/* Any copyright is dedicated to the Public Domain.
++ * http://creativecommons.org/publicdomain/zero/1.0/ */
++
++"use strict";
++
++const expect = require("expect");
++
++const actions = require("devtools/client/webconsole/new-console-output/actions/index");
++const { getFilteredMessagesCount } = require("devtools/client/webconsole/new-console-output/selectors/messages");
++const { setupStore } = require("devtools/client/webconsole/new-console-output/test/helpers");
++const { FILTERS } = require("devtools/client/webconsole/new-console-output/constants");
++const { stubPackets } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index");
++
++describe("Filtering - Hidden messages", () => {
++  let store;
++
++  beforeEach(() => {
++    store = prepareBaseStore();
++    // Switch off all filters (include those which are on by default).
++    store.dispatch(actions.filtersClear());
++    store.dispatch(actions.filterToggle(FILTERS.DEBUG));
++    store.dispatch(actions.filterToggle(FILTERS.ERROR));
++    store.dispatch(actions.filterToggle(FILTERS.INFO));
++    store.dispatch(actions.filterToggle(FILTERS.LOG));
++    store.dispatch(actions.filterToggle(FILTERS.WARN));
++  });
++
++  it("has the expected numbers", () => {
++    let counter = getFilteredMessagesCount(store.getState());
++    expect(counter).toEqual(BASIC_TEST_CASE_FILTERED_MESSAGE_COUNT);
++  });
++
++  it("has the expected numbers when there is a text search", () => {
++    store.dispatch(actions.filterTextSet("danger, will robinson!"));
++    let counter = getFilteredMessagesCount(store.getState());
++    expect(counter).toEqual({
++      [FILTERS.ERROR]: 0,
++      // The warning message matches the text search.
++      [FILTERS.WARN]: 1,
++      [FILTERS.LOG]: 0,
++      [FILTERS.INFO]: 0,
++      [FILTERS.DEBUG]: 0,
++      [FILTERS.TEXT]: 10,
++      global: 11
++    });
++
++    // Numbers update if the text search is cleared.
++    store.dispatch(actions.filterTextSet(""));
++    counter = getFilteredMessagesCount(store.getState());
++    expect(counter).toEqual(BASIC_TEST_CASE_FILTERED_MESSAGE_COUNT);
++  });
++
++  it("updates when messages are added", () => {
++    MESSAGES.forEach(message =>
++      store.dispatch(actions.messageAdd(stubPackets.get(message))));
++
++    let counter = getFilteredMessagesCount(store.getState());
++    expect(counter).toEqual({
++      [FILTERS.ERROR]: 6,
++      [FILTERS.WARN]: 2,
++      [FILTERS.LOG]: 10,
++      [FILTERS.INFO]: 2,
++      [FILTERS.DEBUG]: 2,
++      [FILTERS.TEXT]: 0,
++      global: 22
++    });
++  });
++
++  it("updates when filters are toggled", () => {
++    store.dispatch(actions.filterToggle(FILTERS.LOG));
++
++    let counter = getFilteredMessagesCount(store.getState());
++    expect(counter).toEqual(Object.assign({}, BASIC_TEST_CASE_FILTERED_MESSAGE_COUNT, {
++      [FILTERS.LOG]: 0,
++      global: 6
++    }));
++
++    store.dispatch(actions.filterToggle(FILTERS.ERROR));
++
++    counter = getFilteredMessagesCount(store.getState());
++    expect(counter).toEqual(Object.assign({}, BASIC_TEST_CASE_FILTERED_MESSAGE_COUNT, {
++      [FILTERS.ERROR]: 0,
++      [FILTERS.LOG]: 0,
++      global: 3
++    }));
++
++    store.dispatch(actions.filterToggle(FILTERS.LOG));
++    store.dispatch(actions.filterToggle(FILTERS.ERROR));
++    counter = getFilteredMessagesCount(store.getState());
++    expect(counter).toEqual(BASIC_TEST_CASE_FILTERED_MESSAGE_COUNT);
++  });
++
++  it("has the expected numbers after message clear", () => {
++    // Add a text search to make sure it is handled as well.
++    store.dispatch(actions.filterTextSet("danger, will robinson!"));
++    store.dispatch(actions.messagesClear());
++    let counter = getFilteredMessagesCount(store.getState());
++    expect(counter).toEqual({
++      [FILTERS.ERROR]: 0,
++      [FILTERS.WARN]: 0,
++      [FILTERS.LOG]: 0,
++      [FILTERS.INFO]: 0,
++      [FILTERS.DEBUG]: 0,
++      [FILTERS.TEXT]: 0,
++      global: 0,
++    });
++  });
++
++  it("has the expected numbers after filter reset", () => {
++    // Add a text search to make sure it is handled as well.
++    store.dispatch(actions.filterTextSet("danger, will robinson!"));
++    store.dispatch(actions.defaultFiltersReset());
++    let counter = getFilteredMessagesCount(store.getState());
++    expect(counter).toEqual({
++      [FILTERS.ERROR]: 0,
++      [FILTERS.WARN]: 0,
++      [FILTERS.LOG]: 0,
++      [FILTERS.INFO]: 0,
++      [FILTERS.DEBUG]: 0,
++      [FILTERS.TEXT]: 0,
++      global: 0,
++    });
++  });
++
++  it("has the expected numbers after filter clear", () => {
++    // Add a text search to make sure it is handled as well.
++    store.dispatch(actions.filterTextSet("danger, will robinson!"));
++    store.dispatch(actions.filtersClear());
++    let counter = getFilteredMessagesCount(store.getState());
++    expect(counter).toEqual({
++      [FILTERS.ERROR]: 0,
++      [FILTERS.WARN]: 0,
++      [FILTERS.LOG]: 0,
++      [FILTERS.INFO]: 0,
++      [FILTERS.DEBUG]: 0,
++      [FILTERS.TEXT]: 0,
++      global: 0,
++    });
++  });
++});
++
++const MESSAGES = [
++  // Error
++  "ReferenceError: asdf is not defined",
++  "console.error('error message');",
++  "console.assert(false, {message: 'foobar'})",
++  // Warning
++  "console.warn('danger, will robinson!')",
++  // Log
++  "console.log('foobar', 'test')",
++  "console.log(undefined)",
++  "console.count('bar')",
++  "console.log('鼬')",
++  "console.table(['red', 'green', 'blue']);",
++  // Info
++  "console.info('info message');",
++  // Debug
++  "console.debug('debug message');",
++];
++
++const BASIC_TEST_CASE_FILTERED_MESSAGE_COUNT = {
++  [FILTERS.ERROR]: 3,
++  [FILTERS.WARN]: 1,
++  [FILTERS.LOG]: 5,
++  [FILTERS.INFO]: 1,
++  [FILTERS.DEBUG]: 1,
++  [FILTERS.TEXT]: 0,
++  global: 11
++};
++
++function prepareBaseStore() {
++  return setupStore(MESSAGES);
++}

+ 226 - 0
frg/253-58/mozilla-release58_428081.patch

@@ -0,0 +1,226 @@
+# HG changeset patch
+# User Aryeh Gregor <ayg@aryeh.name>
+# Date 1503238824 -10800
+#      Sun Aug 20 17:20:24 2017 +0300
+# Node ID af0a3f986e513b6db96f348f31beb145d3aa3975
+# Parent  ca1c512e2cfa42e5cfdbadfbdbab91819715222a
+Bug 834209 - Return HTMLCollection from HTMLDocument named getter; r=bkelly
+
+The spec says HTMLCollection, and this appears to be what all other
+browsers do.
+
+https://html.spec.whatwg.org/#dom-window-nameditem
+https://html.spec.whatwg.org/#dom-document-nameditem
+
+MozReview-Commit-ID: 87aABNaQmiz
+
+diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
+--- a/dom/base/nsDocument.cpp
++++ b/dom/base/nsDocument.cpp
+@@ -191,16 +191,17 @@
+ #include "mozilla/dom/nsCSPUtils.h"
+ #include "nsHTMLStyleSheet.h"
+ #include "nsHTMLCSSStyleSheet.h"
+ #include "mozilla/dom/DOMImplementation.h"
+ #include "mozilla/dom/ShadowRoot.h"
+ #include "mozilla/dom/Comment.h"
+ #include "nsTextNode.h"
+ #include "mozilla/dom/Link.h"
++#include "mozilla/dom/HTMLCollectionBinding.h"
+ #include "mozilla/dom/HTMLElementBinding.h"
+ #include "nsXULAppAPI.h"
+ #include "mozilla/dom/Touch.h"
+ #include "mozilla/dom/TouchEvent.h"
+ 
+ #include "mozilla/Preferences.h"
+ 
+ #include "imgILoader.h"
+@@ -507,21 +508,140 @@ nsIdentifierMapEntry::SetImageElement(El
+   Element* oldElement = GetImageIdElement();
+   mImageElement = aElement;
+   Element* newElement = GetImageIdElement();
+   if (oldElement != newElement) {
+     FireChangeCallbacks(oldElement, newElement, true);
+   }
+ }
+ 
++namespace mozilla {
++namespace dom {
++class SimpleHTMLCollection final : public nsSimpleContentList
++                                 , public nsIHTMLCollection
++{
++public:
++  explicit SimpleHTMLCollection(nsINode* aRoot) : nsSimpleContentList(aRoot) {}
++
++  NS_DECL_ISUPPORTS_INHERITED
++
++  // nsIDOMHTMLCollection
++  NS_DECL_NSIDOMHTMLCOLLECTION
++
++  virtual nsINode* GetParentObject() override
++  {
++    return nsSimpleContentList::GetParentObject();
++  }
++  virtual Element* GetElementAt(uint32_t aIndex) override
++  {
++    return mElements.SafeElementAt(aIndex)->AsElement();
++  }
++
++  virtual Element* GetFirstNamedElement(const nsAString& aName,
++                                        bool& aFound) override
++  {
++    aFound = false;
++    nsCOMPtr<nsIAtom> name = NS_Atomize(aName);
++    for (uint32_t i = 0; i < mElements.Length(); i++) {
++      MOZ_DIAGNOSTIC_ASSERT(mElements[i]);
++      Element* element = mElements[i]->AsElement();
++      if (element->GetID() == name ||
++          (element->HasName() &&
++           element->GetParsedAttr(nsGkAtoms::name)->GetAtomValue() == name)) {
++        aFound = true;
++        return element;
++      }
++    }
++    return nullptr;
++  }
++
++  virtual void GetSupportedNames(nsTArray<nsString>& aNames) override
++  {
++    AutoTArray<nsIAtom*, 8> atoms;
++    for (uint32_t i = 0; i < mElements.Length(); i++) {
++      MOZ_DIAGNOSTIC_ASSERT(mElements[i]);
++      Element* element = mElements[i]->AsElement();
++
++      nsIAtom* id = element->GetID();
++      MOZ_ASSERT(id != nsGkAtoms::_empty);
++      if (id && !atoms.Contains(id)) {
++        atoms.AppendElement(id);
++      }
++
++      if (element->HasName()) {
++        nsIAtom* name = element->GetParsedAttr(nsGkAtoms::name)->GetAtomValue();
++        MOZ_ASSERT(name && name != nsGkAtoms::_empty);
++        if (name && !atoms.Contains(name)) {
++          atoms.AppendElement(name);
++        }
++      }
++    }
++
++    nsString* names = aNames.AppendElements(atoms.Length());
++    for (uint32_t i = 0; i < atoms.Length(); i++) {
++      atoms[i]->ToString(names[i]);
++    }
++  }
++
++  virtual JSObject* GetWrapperPreserveColorInternal() override
++  {
++    return nsWrapperCache::GetWrapperPreserveColor();
++  }
++  virtual void PreserveWrapperInternal(nsISupports* aScriptObjectHolder) override
++  {
++    nsWrapperCache::PreserveWrapper(aScriptObjectHolder);
++  }
++  virtual JSObject* WrapObject(JSContext *aCx,
++                               JS::Handle<JSObject*> aGivenProto) override
++  {
++    return HTMLCollectionBinding::Wrap(aCx, this, aGivenProto);
++  }
++
++  using nsBaseContentList::Length;
++  using nsBaseContentList::Item;
++  using nsIHTMLCollection::NamedItem;
++
++private:
++  virtual ~SimpleHTMLCollection() {}
++};
++
++NS_IMPL_ISUPPORTS_INHERITED(SimpleHTMLCollection, nsSimpleContentList,
++                            nsIHTMLCollection, nsIDOMHTMLCollection)
++
++NS_IMETHODIMP
++SimpleHTMLCollection::GetLength(uint32_t* aLength)
++{
++  *aLength = Length();
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++SimpleHTMLCollection::Item(uint32_t aIdx, nsIDOMNode** aRetVal)
++{
++  nsCOMPtr<nsIDOMNode> retVal = Item(aIdx)->AsDOMNode();
++  retVal.forget(aRetVal);
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++SimpleHTMLCollection::NamedItem(const nsAString& aName, nsIDOMNode** aRetVal)
++{
++  nsCOMPtr<nsIDOMNode> retVal = NamedItem(aName)->AsDOMNode();
++  retVal.forget(aRetVal);
++  return NS_OK;
++}
++
++} // namespace dom
++} // namespace mozilla
++
+ void
+ nsIdentifierMapEntry::AddNameElement(nsINode* aNode, Element* aElement)
+ {
+   if (!mNameContentList) {
+-    mNameContentList = new nsSimpleContentList(aNode);
++    mNameContentList = new SimpleHTMLCollection(aNode);
+   }
+ 
+   mNameContentList->AppendElement(aElement);
+ }
+ 
+ void
+ nsIdentifierMapEntry::RemoveNameElement(Element* aElement)
+ {
+diff --git a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-04.html.ini b/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-04.html.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-04.html.ini
++++ /dev/null
+@@ -1,5 +0,0 @@
+-[nameditem-04.html]
+-  type: testharness
+-  [If there are two forms, a collection should be returned. (name)]
+-    expected: FAIL
+-
+diff --git a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-05.html.ini b/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-05.html.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-05.html.ini
++++ /dev/null
+@@ -1,5 +0,0 @@
+-[nameditem-05.html]
+-  type: testharness
+-  [If there are two embeds, a collection should be returned. (name)]
+-    expected: FAIL
+-
+diff --git a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-06.html.ini b/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-06.html.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-06.html.ini
++++ /dev/null
+@@ -1,5 +0,0 @@
+-[nameditem-06.html]
+-  type: testharness
+-  [If there are two imgs, a collection should be returned. (name)]
+-    expected: FAIL
+-
+diff --git a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-07.html.ini b/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-07.html.ini
+--- a/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-07.html.ini
++++ b/testing/web-platform/meta/html/dom/documents/dom-tree-accessors/nameditem-07.html.ini
+@@ -1,13 +1,10 @@
+ [nameditem-07.html]
+   type: testharness
+-  [If there are two objects, a collection should be returned. (name)]
+-    expected: FAIL
+-
+   [If there are two objects, a collection should be returned. (id)]
+     expected: FAIL
+ 
+   [If there are two objects, a collection should be returned. (name and id)]
+     expected: FAIL
+ 
+   [If there are two objects, a collection should be returned. (id and name)]
+     expected: FAIL

+ 150 - 0
frg/253-58/mozilla-release58_428082.patch

@@ -0,0 +1,150 @@
+# HG changeset patch
+# User Masayuki Nakano <masayuki@d-toybox.com>
+# Date 1503303821 -32400
+#      Mon Aug 21 17:23:41 2017 +0900
+# Node ID f77110e64bbd80bcb16bc5eac66dde13a690464a
+# Parent  a43b1005eb4c2864adf1cd6818bc502afed3ed9e
+Bug 1392181 - part1: nsTextFragment::SetTo() shouldn't use CheckedInt r=smaug
+
+nsTextFragment::SetTo() may be hot path of performance test but it needs to be
+careful for computing allocation size.  However, nsTextFragment uses uint32_t
+with only 29 bits to store its text length and using CheckedInt sometimes causes
+appearing CheckedInt in profile.  So, using CheckedInt in it doesn't make sense
+(and also wrong).
+
+This patch defines NS_MAX_TEXT_FRAGMENT_LENGTH and make SetTo() check the length
+of new text by itself.
+
+MozReview-Commit-ID: 5zHtU1Kk6X2
+
+diff --git a/dom/base/nsTextFragment.cpp b/dom/base/nsTextFragment.cpp
+--- a/dom/base/nsTextFragment.cpp
++++ b/dom/base/nsTextFragment.cpp
+@@ -332,31 +332,31 @@ nsTextFragment::Append(const char16_t* a
+   // This is a common case because some callsites create a textnode
+   // with a value by creating the node and then calling AppendData.
+   if (mState.mLength == 0) {
+     return SetTo(aBuffer, aLength, aUpdateBidi, aForce2b);
+   }
+ 
+   // Should we optimize for aData.Length() == 0?
+ 
+-  CheckedUint32 length = mState.mLength;
+-  length += aLength;
+-
+-  if (!length.isValid()) {
+-    return false;
++  // FYI: Don't use CheckedInt in this method since here is very hot path
++  //      in some performance tests.
++  if (NS_MAX_TEXT_FRAGMENT_LENGTH - mState.mLength < aLength) {
++    return false;  // Would be overflown if we'd keep handling.
+   }
+ 
+   if (mState.mIs2b) {
+-    length *= sizeof(char16_t);
+-    if (!length.isValid()) {
+-      return false;
++    size_t size = mState.mLength + aLength;
++    if (SIZE_MAX / sizeof(char16_t) < size) {
++      return false;  // Would be overflown if we'd keep handling.
+     }
++    size *= sizeof(char16_t);
+ 
+     // Already a 2-byte string so the result will be too
+-    char16_t* buff = static_cast<char16_t*>(realloc(m2b, length.value()));
++    char16_t* buff = static_cast<char16_t*>(realloc(m2b, size));
+     if (!buff) {
+       return false;
+     }
+ 
+     memcpy(buff + mState.mLength, aBuffer, aLength * sizeof(char16_t));
+     mState.mLength += aLength;
+     m2b = buff;
+ 
+@@ -366,24 +366,25 @@ nsTextFragment::Append(const char16_t* a
+ 
+     return true;
+   }
+ 
+   // Current string is a 1-byte string, check if the new data fits in one byte too.
+   int32_t first16bit = aForce2b ? 0 : FirstNon8Bit(aBuffer, aBuffer + aLength);
+ 
+   if (first16bit != -1) { // aBuffer contains no non-8bit character
+-    length *= sizeof(char16_t);
+-    if (!length.isValid()) {
+-      return false;
++    size_t size = mState.mLength + aLength;
++    if (SIZE_MAX / sizeof(char16_t) < size) {
++      return false;  // Would be overflown if we'd keep handling.
+     }
++    size *= sizeof(char16_t);
+ 
+     // The old data was 1-byte, but the new is not so we have to expand it
+     // all to 2-byte
+-    char16_t* buff = static_cast<char16_t*>(malloc(length.value()));
++    char16_t* buff = static_cast<char16_t*>(malloc(size));
+     if (!buff) {
+       return false;
+     }
+ 
+     // Copy data into buff
+     LossyConvertEncoding8to16 converter(buff);
+     copy_string(m1b, m1b+mState.mLength, converter);
+ 
+@@ -401,25 +402,27 @@ nsTextFragment::Append(const char16_t* a
+     if (aUpdateBidi) {
+       UpdateBidiFlag(aBuffer + first16bit, aLength - first16bit);
+     }
+ 
+     return true;
+   }
+ 
+   // The new and the old data is all 1-byte
++  size_t size = mState.mLength + aLength;
++  MOZ_ASSERT(sizeof(char) == 1);
+   char* buff;
+   if (mState.mInHeap) {
+-    buff = static_cast<char*>(realloc(const_cast<char*>(m1b), length.value()));
++    buff = static_cast<char*>(realloc(const_cast<char*>(m1b), size));
+     if (!buff) {
+       return false;
+     }
+   }
+   else {
+-    buff = static_cast<char*>(malloc(length.value()));
++    buff = static_cast<char*>(malloc(size));
+     if (!buff) {
+       return false;
+     }
+ 
+     memcpy(buff, m1b, mState.mLength);
+     mState.mInHeap = true;
+   }
+ 
+diff --git a/dom/base/nsTextFragment.h b/dom/base/nsTextFragment.h
+--- a/dom/base/nsTextFragment.h
++++ b/dom/base/nsTextFragment.h
+@@ -214,19 +214,23 @@ public:
+     // uint32_t to ensure that the values are unsigned, because we
+     // want 0/1, not 0/-1!
+     // Making these bool causes Windows to not actually pack them,
+     // which causes crashes because we assume this structure is no more than
+     // 32 bits!
+     uint32_t mInHeap : 1;
+     uint32_t mIs2b : 1;
+     uint32_t mIsBidi : 1;
++    // Note that when you change the bits of mLength, you also need to change
++    // NS_MAX_TEXT_FRAGMENT_LENGTH.
+     uint32_t mLength : 29;
+   };
+ 
++#define NS_MAX_TEXT_FRAGMENT_LENGTH (static_cast<uint32_t>(0x1FFFFFFF))
++
+   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+ 
+ private:
+   void ReleaseText();
+ 
+   /**
+    * Scan the contents of the fragment and turn on mState.mIsBidi if it
+    * includes any Bidi characters.

+ 62 - 0
frg/253-58/mozilla-release58_428083.patch

@@ -0,0 +1,62 @@
+# HG changeset patch
+# User Masayuki Nakano <masayuki@d-toybox.com>
+# Date 1503306201 -32400
+#      Mon Aug 21 18:03:21 2017 +0900
+# Node ID 08c538a185408e3f79fc7a0a08fba042ebebc689
+# Parent  6efad7981f2db38a060430a25c600f6893ecf8c4
+Bug 1392181 - part2: HasRTLChars() should check if the character is at least equal or larger than the minimum RTL character, U+0590 r=emk
+
+HasRTLChars() appears in profile of attachment 8848015 after landing the patches
+for bug 1391538 because the landing made text in <input> or <textarea> always
+treated as non-single byte characters.  Therefore, HasRTLChars() is now called
+by nsTextFragment::SetTo() a lot in editors.
+
+HasRTLChar() checks if it's in an RTL character for each character until it
+becomes true.  However, if character is less than the minimum RTL character,
+U+0590, it works faster at least for Western languages.
+
+MozReview-Commit-ID: 4YecxQWUcmK
+
+diff --git a/intl/unicharutil/util/nsBidiUtils.cpp b/intl/unicharutil/util/nsBidiUtils.cpp
+--- a/intl/unicharutil/util/nsBidiUtils.cpp
++++ b/intl/unicharutil/util/nsBidiUtils.cpp
+@@ -1,15 +1,19 @@
+ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+  *
+  * 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/. */
+ #include "nsBidiUtils.h"
+ 
++namespace mozilla {
++static const uint32_t kMinRTLChar = 0x0590;
++} // namespace mozilla;
++
+ #define ARABIC_TO_HINDI_DIGIT_INCREMENT (START_HINDI_DIGITS - START_ARABIC_DIGITS)
+ #define PERSIAN_TO_HINDI_DIGIT_INCREMENT (START_HINDI_DIGITS - START_FARSI_DIGITS)
+ #define ARABIC_TO_PERSIAN_DIGIT_INCREMENT (START_FARSI_DIGITS - START_ARABIC_DIGITS)
+ #define NUM_TO_ARABIC(c) \
+   ((((c)>=START_HINDI_DIGITS) && ((c)<=END_HINDI_DIGITS)) ? \
+    ((c) - (uint16_t)ARABIC_TO_HINDI_DIGIT_INCREMENT) : \
+    ((((c)>=START_FARSI_DIGITS) && ((c)<=END_FARSI_DIGITS)) ? \
+     ((c) - (uint16_t)ARABIC_TO_PERSIAN_DIGIT_INCREMENT) : \
+@@ -85,16 +89,19 @@ nsresult HandleNumbers(char16_t* aBuffer
+ bool HasRTLChars(const char16_t* aText, uint32_t aLength)
+ {
+   // This is used to determine whether a string has right-to-left characters
+   // that mean it will require bidi processing.
+   const char16_t* cp = aText;
+   const char16_t* end = cp + aLength;
+   while (cp < end) {
+     uint32_t ch = *cp++;
++    if (ch < mozilla::kMinRTLChar) {
++      continue;
++    }
+     if (NS_IS_HIGH_SURROGATE(ch) && cp < end && NS_IS_LOW_SURROGATE(*cp)) {
+       ch = SURROGATE_TO_UCS4(ch, *cp++);
+     }
+     if (UTF32_CHAR_IS_BIDI(ch) || IsBidiControlRTL(ch)) {
+       return true;
+     }
+   }
+   return false;

+ 66 - 0
frg/253-58/mozilla-release58_428089.patch

@@ -0,0 +1,66 @@
+# HG changeset patch
+# User Tom Ritter <tom@mozilla.com>
+# Date 1503401712 18000
+#      Tue Aug 22 06:35:12 2017 -0500
+# Node ID 1fdd12bde0fde49c9b8210807f431ad606d11839
+# Parent  bce70f91e79d65377eb4b02433ff79ec9a982c94
+Bug 1392617 Fix comparison between signed and unsigned integer expressions r=aklotz
+
+The return of these functions is actually (DWORD) –1
+
+MozReview-Commit-ID: 112d6BTBt8O
+
+diff --git a/xpcom/threads/HangMonitor.cpp b/xpcom/threads/HangMonitor.cpp
+--- a/xpcom/threads/HangMonitor.cpp
++++ b/xpcom/threads/HangMonitor.cpp
+@@ -158,26 +158,26 @@ GetChromeHangReport(Telemetry::Processed
+     CONTEXT context;
+     context.ContextFlags = CONTEXT_CONTROL;
+     if (::GetThreadContext(winMainThreadHandle, &context)) {
+       suspended = true;
+     }
+   }
+ 
+   if (!suspended) {
+-    if (ret != -1) {
++    if (ret != (DWORD)-1) {
+       MOZ_ALWAYS_TRUE(::ResumeThread(winMainThreadHandle) != DWORD(-1));
+     }
+     return;
+   }
+ 
+   MozStackWalkThread(ChromeStackWalker, /* skipFrames */ 0, /* maxFrames */ 0,
+                      &rawStack, winMainThreadHandle, nullptr);
+   ret = ::ResumeThread(winMainThreadHandle);
+-  if (ret == -1) {
++  if (ret == (DWORD)-1) {
+     return;
+   }
+   aStack = Telemetry::GetStackAndModules(rawStack);
+ 
+   // Record system uptime (in minutes) at the time of the hang
+   aSystemUptime = ((GetTickCount() / 1000) - (gTimeout * 2)) / 60;
+ 
+   // Record Firefox uptime (in minutes) at the time of the hang
+diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp
+--- a/xpcom/threads/nsThread.cpp
++++ b/xpcom/threads/nsThread.cpp
+@@ -326,17 +326,17 @@ SetThreadAffinity(unsigned int cpu)
+   // to run them on the same processor. To run threads on different processors,
+   // tag them as belonging to different affinity sets. Tag 0, the default, means
+   // "no affinity" so let's pretend each CPU has its own tag `cpu+1`.
+   thread_affinity_policy_data_t policy;
+   policy.affinity_tag = cpu + 1;
+   MOZ_ALWAYS_TRUE(thread_policy_set(mach_thread_self(), THREAD_AFFINITY_POLICY,
+                                     &policy.affinity_tag, 1) == KERN_SUCCESS);
+ #elif defined(XP_WIN)
+-  MOZ_ALWAYS_TRUE(SetThreadIdealProcessor(GetCurrentThread(), cpu) != -1);
++  MOZ_ALWAYS_TRUE(SetThreadIdealProcessor(GetCurrentThread(), cpu) != (DWORD)-1);
+ #endif
+ }
+ 
+ static void
+ SetupCurrentThreadForChaosMode()
+ {
+   if (!ChaosMode::isActive(ChaosFeature::ThreadScheduling)) {
+     return;

+ 86 - 0
frg/253-58/mozilla-release58_428093.patch

@@ -0,0 +1,86 @@
+# HG changeset patch
+# User Andrew McCreight <continuation@gmail.com>
+# Date 1495648171 25200
+#      Wed May 24 10:49:31 2017 -0700
+# Node ID 08aa23aacd835ada368f053b8e9248a992aa0618
+# Parent  14bf8713f605842435b137cf707a3325680a5876
+Bug 1366896, part 1 - Factor out initialize code and make initialize work with CIDs. r=krizsa
+
+MozReview-Commit-ID: 3spZGOqlU1j
+
+diff --git a/js/xpconnect/src/XPCJSID.cpp b/js/xpconnect/src/XPCJSID.cpp
+--- a/js/xpconnect/src/XPCJSID.cpp
++++ b/js/xpconnect/src/XPCJSID.cpp
+@@ -565,18 +565,36 @@ NS_IMETHODIMP_(const nsID*) nsJSCID::Get
+     {return &mDetails->ID();}
+ 
+ NS_IMETHODIMP nsJSCID::GetValid(bool* aValid)
+     {return mDetails->GetValid(aValid);}
+ 
+ NS_IMETHODIMP nsJSCID::Equals(nsIJSID* other, bool* _retval)
+     {return mDetails->Equals(other, _retval);}
+ 
+-NS_IMETHODIMP nsJSCID::Initialize(const char* idString)
+-    {return mDetails->Initialize(idString);}
++NS_IMETHODIMP
++nsJSCID::Initialize(const char* str)
++{
++    if (str[0] == '{') {
++        NS_ENSURE_SUCCESS(mDetails->Initialize(str), NS_ERROR_FAILURE);
++    } else {
++        nsCOMPtr<nsIComponentRegistrar> registrar;
++        NS_GetComponentRegistrar(getter_AddRefs(registrar));
++        NS_ENSURE_TRUE(registrar, NS_ERROR_FAILURE);
++
++        nsCID* cid;
++        if (NS_FAILED(registrar->ContractIDToCID(str, &cid)))
++            return NS_ERROR_FAILURE;
++        bool success = mDetails->InitWithName(*cid, str);
++        free(cid);
++        if (!success)
++            return NS_ERROR_FAILURE;
++    }
++    return NS_OK;
++}
+ 
+ NS_IMETHODIMP nsJSCID::ToString(char** _retval)
+     {ResolveName(); return mDetails->ToString(_retval);}
+ 
+ void
+ nsJSCID::ResolveName()
+ {
+     if (!mDetails->NameIsSet())
+@@ -588,31 +606,18 @@ already_AddRefed<nsJSCID>
+ nsJSCID::NewID(const char* str)
+ {
+     if (!str) {
+         NS_ERROR("no string");
+         return nullptr;
+     }
+ 
+     RefPtr<nsJSCID> idObj = new nsJSCID();
+-    if (str[0] == '{') {
+-        NS_ENSURE_SUCCESS(idObj->Initialize(str), nullptr);
+-    } else {
+-        nsCOMPtr<nsIComponentRegistrar> registrar;
+-        NS_GetComponentRegistrar(getter_AddRefs(registrar));
+-        NS_ENSURE_TRUE(registrar, nullptr);
+-
+-        nsCID* cid;
+-        if (NS_FAILED(registrar->ContractIDToCID(str, &cid)))
+-            return nullptr;
+-        bool success = idObj->mDetails->InitWithName(*cid, str);
+-        free(cid);
+-        if (!success)
+-            return nullptr;
+-    }
++    if (NS_FAILED(idObj->Initialize(str)))
++        return nullptr;
+     return idObj.forget();
+ }
+ 
+ static const nsID*
+ GetIIDArg(uint32_t argc, const JS::Value& val, JSContext* cx)
+ {
+     const nsID* iid;
+ 

+ 79 - 0
frg/253-58/mozilla-release58_428094.patch

@@ -0,0 +1,79 @@
+# HG changeset patch
+# User Andrew McCreight <continuation@gmail.com>
+# Date 1495660331 25200
+#      Wed May 24 14:12:11 2017 -0700
+# Node ID ff26fa1ed97d43a8a63c6545219056fd8894b0bc
+# Parent  dea7aecebd8104252f7c35a46b6695ad33479b9b
+Bug 1366896, part 2 - Add and use Cc.Initialize method. r=krizsa
+
+MozReview-Commit-ID: Amqt9JsTMqG
+
+diff --git a/js/xpconnect/idl/xpccomponents.idl b/js/xpconnect/idl/xpccomponents.idl
+--- a/js/xpconnect/idl/xpccomponents.idl
++++ b/js/xpconnect/idl/xpccomponents.idl
+@@ -39,16 +39,18 @@ interface nsIXPCComponents_Interfaces : 
+ 
+ /**
+ * interface of Components.classes
+ * (interesting stuff only reflected into JavaScript)
+ */
+ [scriptable, uuid(978ff520-d26c-11d2-9842-006008962422)]
+ interface nsIXPCComponents_Classes : nsISupports
+ {
++  // Make it so that |cid| gets mapped to |idString|.
++  void initialize(in nsIJSCID cid, in string idString);
+ };
+ 
+ /**
+ * interface of Components.classesByID
+ * (interesting stuff only reflected into JavaScript)
+ */
+ [scriptable, uuid(336a9590-4d19-11d3-9893-006008962422)]
+ interface nsIXPCComponents_ClassesByID : nsISupports
+diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp
+--- a/js/xpconnect/src/XPCComponents.cpp
++++ b/js/xpconnect/src/XPCComponents.cpp
+@@ -686,16 +686,24 @@ nsXPCComponents_Classes::Resolve(nsIXPCo
+                                                      JSPROP_RESOLVING);
+                 }
+             }
+         }
+     }
+     return NS_OK;
+ }
+ 
++NS_IMETHODIMP
++nsXPCComponents_Classes::Initialize(nsIJSCID* cid,
++                                    const char* str)
++{
++    return cid->Initialize(str);
++}
++
++
+ /***************************************************************************/
+ /***************************************************************************/
+ /***************************************************************************/
+ 
+ class nsXPCComponents_ClassesByID final :
+   public nsIXPCComponents_ClassesByID,
+   public nsIXPCScriptable,
+   public nsIClassInfo
+diff --git a/testing/modules/AppInfo.jsm b/testing/modules/AppInfo.jsm
+--- a/testing/modules/AppInfo.jsm
++++ b/testing/modules/AppInfo.jsm
+@@ -123,10 +123,15 @@ this.updateAppInfo = function(options) {
+         throw Cr.NS_ERROR_NO_AGGREGATION;
+       }
+ 
+       return currentAppInfo.QueryInterface(iid);
+     },
+   };
+ 
+   registrar.registerFactory(id, "XULAppInfo", cid, factory);
++
++  // Ensure that Cc actually maps cid to the new shim AppInfo. This is
++  // needed when JSM global sharing is enabled, because some prior
++  // code may already have looked up |Cc[cid]|.
++  Cc.initialize(Cc[cid], cid);
+ };
+ 

+ 1394 - 0
frg/253-58/mozilla-release58_428103.patch

@@ -0,0 +1,1394 @@
+# HG changeset patch
+# User Emilio Cobos Alvarez <emilio@crisal.io>
+# Date 1503420342 18000
+#      Tue Aug 22 11:45:42 2017 -0500
+# Node ID b7d9efd6f870c9ec1e63273f158e689acc51266e
+# Parent  47302437c0edfc4455a13abd056fee767516e189
+servo: Merge #18170 - style: Move the StyleSheetSet into the Stylist (from emilio:stylist-stylesheet-set); r=SimonSapin
+
+This will allow tracking whether there have been only additions to the
+stylesheet set, and in that case don't destroy and completely rebuild the
+invalidation map.
+
+This is on top of #18143.
+
+Source-Repo: https://github.com/servo/servo
+Source-Revision: 019b125963d4db9b18991d3ab06042e475c83f9f
+
+diff --git a/servo/components/style/gecko/data.rs b/servo/components/style/gecko/data.rs
+--- a/servo/components/style/gecko/data.rs
++++ b/servo/components/style/gecko/data.rs
+@@ -11,17 +11,16 @@ use gecko_bindings::structs::{ServoStyle
+ use gecko_bindings::structs::RawGeckoPresContextOwned;
+ use gecko_bindings::structs::nsIDocument;
+ use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
+ use invalidation::media_queries::{MediaListKey, ToMediaListKey};
+ use media_queries::{Device, MediaList};
+ use properties::ComputedValues;
+ use servo_arc::Arc;
+ use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
+-use stylesheet_set::StylesheetSet;
+ use stylesheets::{PerOrigin, StylesheetContents, StylesheetInDocument};
+ use stylist::{ExtraStyleData, Stylist};
+ 
+ /// Little wrapper to a Gecko style sheet.
+ #[derive(PartialEq, Eq, Debug)]
+ pub struct GeckoStyleSheet(*const ServoStyleSheet);
+ 
+ impl ToMediaListKey for ::gecko::data::GeckoStyleSheet {
+@@ -109,19 +108,16 @@ impl StylesheetInDocument for GeckoStyle
+ }
+ 
+ /// The container for data that a Servo-backed Gecko document needs to style
+ /// itself.
+ pub struct PerDocumentStyleDataImpl {
+     /// Rule processor.
+     pub stylist: Stylist,
+ 
+-    /// List of stylesheets, mirrored from Gecko.
+-    pub stylesheets: StylesheetSet<GeckoStyleSheet>,
+-
+     /// List of effective @font-face and @counter-style rules.
+     pub extra_style_data: PerOrigin<ExtraStyleData>,
+ }
+ 
+ /// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
+ /// and unexpected races while trying to mutate it.
+ pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>);
+ 
+@@ -130,17 +126,16 @@ impl PerDocumentStyleData {
+     pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
+         let device = Device::new(pres_context);
+         let quirks_mode = unsafe {
+             (*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode
+         };
+ 
+         PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
+             stylist: Stylist::new(device, quirks_mode.into()),
+-            stylesheets: StylesheetSet::new(),
+             extra_style_data: Default::default(),
+         }))
+     }
+ 
+     /// Get an immutable reference to this style data.
+     pub fn borrow(&self) -> AtomicRef<PerDocumentStyleDataImpl> {
+         self.0.borrow()
+     }
+@@ -148,36 +143,30 @@ impl PerDocumentStyleData {
+     /// Get an mutable reference to this style data.
+     pub fn borrow_mut(&self) -> AtomicRefMut<PerDocumentStyleDataImpl> {
+         self.0.borrow_mut()
+     }
+ }
+ 
+ impl PerDocumentStyleDataImpl {
+     /// Recreate the style data if the stylesheets have changed.
+-    pub fn flush_stylesheets<E>(&mut self,
+-                                guard: &SharedRwLockReadGuard,
+-                                document_element: Option<E>)
+-        where E: TElement,
++    pub fn flush_stylesheets<E>(
++        &mut self,
++        guard: &SharedRwLockReadGuard,
++        document_element: Option<E>,
++    )
++    where
++        E: TElement,
+     {
+-        if !self.stylesheets.has_changed() {
+-            return;
+-        }
+-
+-        let author_style_disabled = self.stylesheets.author_style_disabled();
+-
+-        let (iter, dirty_origins) = self.stylesheets.flush(document_element);
+-        self.stylist.rebuild(
+-            iter,
++        self.stylist.flush(
+             &StylesheetGuards::same(guard),
+             /* ua_sheets = */ None,
+-            author_style_disabled,
+             &mut self.extra_style_data,
+-            dirty_origins,
+-        );
++            document_element,
++        )
+     }
+ 
+     /// Returns whether private browsing is enabled.
+     pub fn is_private_browsing_enabled(&self) -> bool {
+         let doc =
+             self.stylist.device().pres_context().mDocument.raw::<nsIDocument>();
+         unsafe { bindings::Gecko_IsPrivateBrowsingEnabled(doc) }
+     }
+diff --git a/servo/components/style/stylesheet_set.rs b/servo/components/style/stylesheet_set.rs
+--- a/servo/components/style/stylesheet_set.rs
++++ b/servo/components/style/stylesheet_set.rs
+@@ -102,70 +102,60 @@ where
+         if let Some(device) = device {
+             data.invalidations.collect_invalidations_for(device, sheet, guard);
+         }
+         data.dirty = true;
+     }
+ 
+     /// Appends a new stylesheet to the current set.
+     ///
+-    /// FIXME(emilio): `device` shouldn't be optional, but a bunch of work needs
+-    /// to happen to make the invalidations work properly in servo.
++    /// No device implies not computing invalidations.
+     pub fn append_stylesheet(
+         &mut self,
+         device: Option<&Device>,
+         sheet: S,
+         guard: &SharedRwLockReadGuard
+     ) {
+         debug!("StylesheetSet::append_stylesheet");
+         self.remove_stylesheet_if_present(&sheet);
+         self.collect_invalidations_for(device, &sheet, guard);
+         self.entries.push(StylesheetSetEntry { sheet });
+     }
+ 
+     /// Prepend a new stylesheet to the current set.
+-    ///
+-    /// FIXME(emilio): `device` shouldn't be optional, but a bunch of work needs
+-    /// to happen to make the invalidations work properly in servo.
+     pub fn prepend_stylesheet(
+         &mut self,
+         device: Option<&Device>,
+         sheet: S,
+         guard: &SharedRwLockReadGuard
+     ) {
+         debug!("StylesheetSet::prepend_stylesheet");
+         self.remove_stylesheet_if_present(&sheet);
+         self.collect_invalidations_for(device, &sheet, guard);
+         self.entries.insert(0, StylesheetSetEntry { sheet });
+     }
+ 
+     /// Insert a given stylesheet before another stylesheet in the document.
+-    ///
+-    /// FIXME(emilio): `device` shouldn't be optional, but a bunch of work needs
+-    /// to happen to make the invalidations work properly in servo.
+     pub fn insert_stylesheet_before(
+         &mut self,
+         device: Option<&Device>,
+         sheet: S,
+         before_sheet: S,
+-        guard: &SharedRwLockReadGuard
++        guard: &SharedRwLockReadGuard,
+     ) {
+         debug!("StylesheetSet::insert_stylesheet_before");
+         self.remove_stylesheet_if_present(&sheet);
+         let index = self.entries.iter().position(|entry| {
+             entry.sheet == before_sheet
+         }).expect("`before_sheet` stylesheet not found");
+         self.collect_invalidations_for(device, &sheet, guard);
+         self.entries.insert(index, StylesheetSetEntry { sheet });
+     }
+ 
+     /// Remove a given stylesheet from the set.
+-    ///
+-    /// FIXME(emilio): `device` shouldn't be optional, but a bunch of work needs
+-    /// to happen to make the invalidations work properly in servo.
+     pub fn remove_stylesheet(
+         &mut self,
+         device: Option<&Device>,
+         sheet: S,
+         guard: &SharedRwLockReadGuard,
+     ) {
+         debug!("StylesheetSet::remove_stylesheet");
+         self.remove_stylesheet_if_present(&sheet);
+diff --git a/servo/components/style/stylesheets/mod.rs b/servo/components/style/stylesheets/mod.rs
+--- a/servo/components/style/stylesheets/mod.rs
++++ b/servo/components/style/stylesheets/mod.rs
+@@ -39,22 +39,23 @@ pub use self::font_feature_values_rule::
+ pub use self::import_rule::ImportRule;
+ pub use self::keyframes_rule::KeyframesRule;
+ pub use self::loader::StylesheetLoader;
+ pub use self::media_rule::MediaRule;
+ pub use self::memory::{MallocSizeOf, MallocSizeOfFn, MallocSizeOfWithGuard};
+ #[cfg(feature = "gecko")]
+ pub use self::memory::{MallocSizeOfWithRepeats, SizeOfState};
+ pub use self::namespace_rule::NamespaceRule;
+-pub use self::origin::{Origin, OriginSet, PerOrigin};
++pub use self::origin::{Origin, OriginSet, PerOrigin, PerOriginIter};
+ pub use self::page_rule::PageRule;
+ pub use self::rule_parser::{State, TopLevelRuleParser};
+ pub use self::rule_list::{CssRules, CssRulesHelpers};
+ pub use self::rules_iterator::{AllRules, EffectiveRules, NestedRuleIterationCondition, RulesIterator};
+-pub use self::stylesheet::{Namespaces, Stylesheet, StylesheetContents, StylesheetInDocument, UserAgentStylesheets};
++pub use self::stylesheet::{Namespaces, Stylesheet, DocumentStyleSheet};
++pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets};
+ pub use self::style_rule::StyleRule;
+ pub use self::supports_rule::SupportsRule;
+ pub use self::viewport_rule::ViewportRule;
+ 
+ /// Extra data that the backend may need to resolve url values.
+ #[cfg(not(feature = "gecko"))]
+ pub type UrlExtraData = ::servo_url::ServoUrl;
+ 
+diff --git a/servo/components/style/stylesheets/stylesheet.rs b/servo/components/style/stylesheets/stylesheet.rs
+--- a/servo/components/style/stylesheets/stylesheet.rs
++++ b/servo/components/style/stylesheets/stylesheet.rs
+@@ -2,16 +2,17 @@
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ use {Prefix, Namespace};
+ use context::QuirksMode;
+ use cssparser::{Parser, RuleListParser, ParserInput};
+ use error_reporting::{ParseErrorReporter, ContextualParseError};
+ use fnv::FnvHashMap;
++use invalidation::media_queries::{MediaListKey, ToMediaListKey};
+ use media_queries::{MediaList, Device};
+ use parking_lot::RwLock;
+ use parser::ParserContext;
+ use servo_arc::Arc;
+ use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard};
+ use std::mem;
+ use std::sync::atomic::{AtomicBool, Ordering};
+ use style_traits::PARSING_MODE_DEFAULT;
+@@ -270,16 +271,51 @@ impl StylesheetInDocument for Stylesheet
+         Some(self.media.read_with(guard))
+     }
+ 
+     fn enabled(&self) -> bool {
+         !self.disabled()
+     }
+ }
+ 
++/// A simple wrapper over an `Arc<Stylesheet>`, with pointer comparison, and
++/// suitable for its use in a `StylesheetSet`.
++#[derive(Clone)]
++#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
++pub struct DocumentStyleSheet(
++    #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
++    pub Arc<Stylesheet>
++);
++
++impl PartialEq for DocumentStyleSheet {
++    fn eq(&self, other: &Self) -> bool {
++        Arc::ptr_eq(&self.0, &other.0)
++    }
++}
++
++impl ToMediaListKey for DocumentStyleSheet {
++    fn to_media_list_key(&self) -> MediaListKey {
++        self.0.to_media_list_key()
++    }
++}
++
++impl StylesheetInDocument for DocumentStyleSheet {
++    fn contents(&self, guard: &SharedRwLockReadGuard) -> &StylesheetContents {
++        self.0.contents(guard)
++    }
++
++    fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
++        self.0.media(guard)
++    }
++
++    fn enabled(&self) -> bool {
++        self.0.enabled()
++    }
++}
++
+ impl Stylesheet {
+     /// Updates an empty stylesheet from a given string of text.
+     pub fn update_from_str(existing: &Stylesheet,
+                            css: &str,
+                            url_data: UrlExtraData,
+                            stylesheet_loader: Option<&StylesheetLoader>,
+                            error_reporter: &ParseErrorReporter,
+                            line_number_offset: u64) {
+diff --git a/servo/components/style/stylist.rs b/servo/components/style/stylist.rs
+--- a/servo/components/style/stylist.rs
++++ b/servo/components/style/stylist.rs
+@@ -31,210 +31,83 @@ use selectors::matching::VisitedHandling
+ use selectors::parser::{AncestorHashes, Combinator, Component, Selector};
+ use selectors::parser::{SelectorIter, SelectorMethods};
+ use selectors::sink::Push;
+ use selectors::visitor::SelectorVisitor;
+ use servo_arc::{Arc, ArcBorrow};
+ use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
+ use smallvec::VecLike;
+ use std::fmt::Debug;
++use std::ops;
+ use style_traits::viewport::ViewportConstraints;
++use stylesheet_set::{StylesheetSet, StylesheetIterator};
+ #[cfg(feature = "gecko")]
+ use stylesheets::{CounterStyleRule, FontFaceRule};
+ use stylesheets::{CssRule, StyleRule};
+-use stylesheets::{StylesheetInDocument, Origin, OriginSet, PerOrigin};
++use stylesheets::{StylesheetInDocument, Origin, OriginSet, PerOrigin, PerOriginIter};
+ use stylesheets::UserAgentStylesheets;
+ use stylesheets::keyframes_rule::KeyframesAnimation;
+ use stylesheets::viewport_rule::{self, MaybeNew, ViewportRule};
+ use thread_state;
+ 
+ pub use ::fnv::FnvHashMap;
+ 
+-/// This structure holds all the selectors and device characteristics
+-/// for a given document. The selectors are converted into `Rule`s
+-/// (defined in rust-selectors), and sorted into `SelectorMap`s keyed
+-/// off stylesheet origin and pseudo-element (see `CascadeData`).
+-///
+-/// This structure is effectively created once per pipeline, in the
+-/// LayoutThread corresponding to that pipeline.
++/// The type of the stylesheets that the stylist contains.
++#[cfg(feature = "servo")]
++pub type StylistSheet = ::stylesheets::DocumentStyleSheet;
++
++/// The type of the stylesheets that the stylist contains.
++#[cfg(feature = "gecko")]
++pub type StylistSheet = ::gecko::data::GeckoStyleSheet;
++
++/// All the computed information for a stylesheet.
++#[derive(Default)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-pub struct Stylist {
+-    /// Device that the stylist is currently evaluating against.
+-    ///
+-    /// This field deserves a bigger comment due to the different use that Gecko
+-    /// and Servo give to it (that we should eventually unify).
+-    ///
+-    /// With Gecko, the device is never changed. Gecko manually tracks whether
+-    /// the device data should be reconstructed, and "resets" the state of the
+-    /// device.
+-    ///
+-    /// On Servo, on the other hand, the device is a really cheap representation
+-    /// that is recreated each time some constraint changes and calling
+-    /// `set_device`.
+-    device: Device,
+-
+-    /// Viewport constraints based on the current device.
+-    viewport_constraints: Option<ViewportConstraints>,
+-
+-    /// If true, the quirks-mode stylesheet is applied.
+-    #[cfg_attr(feature = "servo", ignore_heap_size_of = "defined in selectors")]
+-    quirks_mode: QuirksMode,
+-
+-    /// Selector maps for all of the style sheets in the stylist, after
+-    /// evalutaing media rules against the current device, split out per
+-    /// cascade level.
+-    cascade_data: PerOrigin<CascadeData>,
+-
+-    /// The rule tree, that stores the results of selector matching.
+-    rule_tree: RuleTree,
++struct DocumentCascadeData {
++    /// Common data for all the origins.
++    per_origin: PerOrigin<CascadeData>,
+ 
+     /// Applicable declarations for a given non-eagerly cascaded pseudo-element.
++    ///
+     /// These are eagerly computed once, and then used to resolve the new
+     /// computed values on the fly on layout.
+     ///
++    /// These are only filled from UA stylesheets.
++    ///
+     /// FIXME(emilio): Use the rule tree!
+     precomputed_pseudo_element_decls: PerPseudoElementMap<Vec<ApplicableDeclarationBlock>>,
+-
+-    /// The total number of times the stylist has been rebuilt.
+-    num_rebuilds: usize,
+-}
+-
+-/// What cascade levels to include when styling elements.
+-#[derive(Copy, Clone, PartialEq)]
+-pub enum RuleInclusion {
+-    /// Include rules for style sheets at all cascade levels.  This is the
+-    /// normal rule inclusion mode.
+-    All,
+-    /// Only include rules from UA and user level sheets.  Used to implement
+-    /// `getDefaultComputedStyle`.
+-    DefaultOnly,
+-}
+-
+-#[cfg(feature = "gecko")]
+-impl From<StyleRuleInclusion> for RuleInclusion {
+-    fn from(value: StyleRuleInclusion) -> Self {
+-        match value {
+-            StyleRuleInclusion::All => RuleInclusion::All,
+-            StyleRuleInclusion::DefaultOnly => RuleInclusion::DefaultOnly,
+-        }
+-    }
+ }
+ 
+-impl Stylist {
+-    /// Construct a new `Stylist`, using given `Device` and `QuirksMode`.
+-    /// If more members are added here, think about whether they should
+-    /// be reset in clear().
+-    #[inline]
+-    pub fn new(device: Device, quirks_mode: QuirksMode) -> Self {
+-        Stylist {
+-            viewport_constraints: None,
+-            device: device,
+-            quirks_mode: quirks_mode,
+-
+-            cascade_data: Default::default(),
+-            precomputed_pseudo_element_decls: PerPseudoElementMap::default(),
+-            rule_tree: RuleTree::new(),
+-            num_rebuilds: 0,
+-        }
+-
+-        // FIXME: Add iso-8859-9.css when the document’s encoding is ISO-8859-8.
+-    }
+-
+-    /// Returns the number of selectors.
+-    pub fn num_selectors(&self) -> usize {
+-        self.cascade_data.iter_origins().map(|(d, _)| d.num_selectors).sum()
+-    }
+-
+-    /// Returns the number of declarations.
+-    pub fn num_declarations(&self) -> usize {
+-        self.cascade_data.iter_origins().map(|(d, _)| d.num_declarations).sum()
++impl DocumentCascadeData {
++    fn iter_origins(&self) -> PerOriginIter<CascadeData> {
++        self.per_origin.iter_origins()
+     }
+ 
+-    /// Returns the number of times the stylist has been rebuilt.
+-    pub fn num_rebuilds(&self) -> usize {
+-        self.num_rebuilds
+-    }
+-
+-    /// Returns the number of revalidation_selectors.
+-    pub fn num_revalidation_selectors(&self) -> usize {
+-        self.cascade_data.iter_origins()
+-            .map(|(d, _)| d.selectors_for_cache_revalidation.len()).sum()
+-    }
+-
+-    /// Returns the number of entries in invalidation maps.
+-    pub fn num_invalidations(&self) -> usize {
+-        self.cascade_data.iter_origins()
+-            .map(|(d, _)| d.invalidation_map.len()).sum()
+-    }
+-
+-    /// Invokes `f` with the `InvalidationMap` for each origin.
+-    ///
+-    /// NOTE(heycam) This might be better as an `iter_invalidation_maps`, once
+-    /// we have `impl trait` and can return that easily without bothering to
+-    /// create a whole new iterator type.
+-    pub fn each_invalidation_map<F>(&self, mut f: F)
+-        where F: FnMut(&InvalidationMap)
+-    {
+-        for (data, _) in self.cascade_data.iter_origins() {
+-            f(&data.invalidation_map)
+-        }
+-    }
+-
+-    /// Rebuild the stylist for the given document stylesheets, and optionally
+-    /// with a set of user agent stylesheets.
+-    pub fn rebuild<'a, I, S>(
++    /// Rebuild the cascade data for the given document stylesheets, and
++    /// optionally with a set of user agent stylesheets.
++    fn rebuild<'a, I, S>(
+         &mut self,
++        device: &Device,
++        quirks_mode: QuirksMode,
+         doc_stylesheets: I,
+         guards: &StylesheetGuards,
+         ua_stylesheets: Option<&UserAgentStylesheets>,
+         author_style_disabled: bool,
+         extra_data: &mut PerOrigin<ExtraStyleData>,
+         origins_to_rebuild: OriginSet,
+     )
+     where
+         I: Iterator<Item = &'a S> + Clone,
+         S: StylesheetInDocument + ToMediaListKey + 'static,
+     {
+         debug_assert!(!origins_to_rebuild.is_empty());
+ 
+-        self.num_rebuilds += 1;
+-
+-        // Update viewport_constraints regardless of which origins'
+-        // `CascadeData` we're updating.
+-        self.viewport_constraints = None;
+-        if viewport_rule::enabled() {
+-            // TODO(emilio): This doesn't look so efficient.
+-            //
+-            // Presumably when we properly implement this we can at least have a
+-            // bit on the stylesheet that says whether it contains viewport
+-            // rules to skip it entirely?
+-            //
+-            // Processing it with the rest of rules seems tricky since it
+-            // overrides the viewport size which may change the evaluation of
+-            // media queries (or may not? how are viewport units in media
+-            // queries defined?)
+-            let cascaded_rule = ViewportRule {
+-                declarations: viewport_rule::Cascade::from_stylesheets(
+-                    doc_stylesheets.clone(), guards.author, &self.device
+-                ).finish()
+-            };
+-
+-            self.viewport_constraints =
+-                ViewportConstraints::maybe_new(&self.device,
+-                                               &cascaded_rule,
+-                                               self.quirks_mode);
+-
+-            if let Some(ref constraints) = self.viewport_constraints {
+-                self.device.account_for_viewport_rule(constraints);
+-            }
+-        }
+-
+         for origin in origins_to_rebuild.iter() {
+             extra_data.borrow_mut_for_origin(&origin).clear();
+-            self.cascade_data.borrow_mut_for_origin(&origin).clear();
++            self.per_origin.borrow_mut_for_origin(&origin).clear();
+         }
+ 
+         if origins_to_rebuild.contains(Origin::UserAgent.into()) {
+             self.precomputed_pseudo_element_decls.clear();
+         }
+ 
+         if let Some(ua_stylesheets) = ua_stylesheets {
+             for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets {
+@@ -243,35 +116,39 @@ impl Stylist {
+ 
+                 debug_assert!(matches!(
+                     sheet_origin,
+                     Origin::UserAgent | Origin::User
+                 ));
+ 
+                 if origins_to_rebuild.contains(sheet_origin.into()) {
+                     self.add_stylesheet(
++                        device,
++                        quirks_mode,
+                         stylesheet,
+                         guards.ua_or_user,
+-                        extra_data
++                        extra_data,
+                     );
+                 }
+             }
+ 
+-            if self.quirks_mode != QuirksMode::NoQuirks {
++            if quirks_mode != QuirksMode::NoQuirks {
+                 let stylesheet = &ua_stylesheets.quirks_mode_stylesheet;
+                 let sheet_origin =
+                     stylesheet.contents(guards.ua_or_user).origin;
+ 
+                 debug_assert!(matches!(
+                     sheet_origin,
+                     Origin::UserAgent | Origin::User
+                 ));
+ 
+                 if origins_to_rebuild.contains(sheet_origin.into()) {
+                     self.add_stylesheet(
++                        device,
++                        quirks_mode,
+                         &ua_stylesheets.quirks_mode_stylesheet,
+                         guards.ua_or_user,
+                         extra_data
+                     );
+                 }
+             }
+         }
+ 
+@@ -280,43 +157,51 @@ impl Stylist {
+         let sheets_to_add = doc_stylesheets.filter(|s| {
+             let sheet_origin = s.contents(guards.author).origin;
+ 
+             origins_to_rebuild.contains(sheet_origin.into()) &&
+                 (!matches!(sheet_origin, Origin::Author) || !author_style_disabled)
+         });
+ 
+         for stylesheet in sheets_to_add {
+-            self.add_stylesheet(stylesheet, guards.author, extra_data);
++            self.add_stylesheet(
++                device,
++                quirks_mode,
++                stylesheet,
++                guards.author,
++                extra_data
++            );
+         }
+     }
+ 
+     fn add_stylesheet<S>(
+         &mut self,
++        device: &Device,
++        quirks_mode: QuirksMode,
+         stylesheet: &S,
+         guard: &SharedRwLockReadGuard,
+         _extra_data: &mut PerOrigin<ExtraStyleData>
+     )
+     where
+         S: StylesheetInDocument + ToMediaListKey + 'static,
+     {
+         if !stylesheet.enabled() ||
+-           !stylesheet.is_effective_for_device(&self.device, guard) {
++           !stylesheet.is_effective_for_device(device, guard) {
+             return;
+         }
+ 
+         let origin = stylesheet.origin(guard);
+         let origin_cascade_data =
+-            self.cascade_data.borrow_mut_for_origin(&origin);
++            self.per_origin.borrow_mut_for_origin(&origin);
+ 
+         origin_cascade_data
+             .effective_media_query_results
+             .saw_effective(stylesheet);
+ 
+-        for rule in stylesheet.effective_rules(&self.device, guard) {
++        for rule in stylesheet.effective_rules(device, guard) {
+             match *rule {
+                 CssRule::Style(ref locked) => {
+                     let style_rule = locked.read_with(&guard);
+                     origin_cascade_data.num_declarations +=
+                         style_rule.block.read_with(&guard).len();
+                     for selector in &style_rule.selectors.0 {
+                         origin_cascade_data.num_selectors += 1;
+ 
+@@ -347,45 +232,46 @@ impl Stylist {
+                                 origin_cascade_data
+                                     .pseudos_map
+                                     .get_or_insert_with(&pseudo.canonical(), SelectorMap::new)
+                                     .expect("Unexpected tree pseudo-element?")
+                             }
+                         };
+ 
+                         let hashes =
+-                            AncestorHashes::new(&selector, self.quirks_mode);
++                            AncestorHashes::new(&selector, quirks_mode);
+ 
+                         let rule = Rule::new(
+                             selector.clone(),
+                             hashes.clone(),
+                             locked.clone(),
+                             origin_cascade_data.rules_source_order
+                         );
+ 
+-                        map.insert(rule, self.quirks_mode);
++                        map.insert(rule, quirks_mode);
+ 
+                         origin_cascade_data
+                             .invalidation_map
+-                            .note_selector(selector, self.quirks_mode);
++                            .note_selector(selector, quirks_mode);
+                         let mut visitor = StylistSelectorVisitor {
+                             needs_revalidation: false,
+                             passed_rightmost_selector: false,
+                             attribute_dependencies: &mut origin_cascade_data.attribute_dependencies,
+                             style_attribute_dependency: &mut origin_cascade_data.style_attribute_dependency,
+                             state_dependencies: &mut origin_cascade_data.state_dependencies,
+                             mapped_ids: &mut origin_cascade_data.mapped_ids,
+                         };
+ 
+                         selector.visit(&mut visitor);
+ 
+                         if visitor.needs_revalidation {
+                             origin_cascade_data.selectors_for_cache_revalidation.insert(
+                                 RevalidationSelectorAndHashes::new(selector.clone(), hashes),
+-                                self.quirks_mode);
++                                quirks_mode
++                            );
+                         }
+                     }
+                     origin_cascade_data.rules_source_order += 1;
+                 }
+                 CssRule::Import(ref lock) => {
+                     let import_rule = lock.read_with(guard);
+                     origin_cascade_data
+                         .effective_media_query_results
+@@ -428,22 +314,300 @@ impl Stylist {
+                         .borrow_mut_for_origin(&origin)
+                         .add_counter_style(guard, &rule);
+                 }
+                 // We don't care about any other rule.
+                 _ => {}
+             }
+         }
+     }
++}
++
++/// A wrapper over a StylesheetSet that can be `Sync`, since it's only used and
++/// exposed via mutable methods in the `Stylist`.
++#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
++struct StylistStylesheetSet(StylesheetSet<StylistSheet>);
++// Read above to see why this is fine.
++unsafe impl Sync for StylistStylesheetSet {}
++
++impl StylistStylesheetSet {
++    fn new() -> Self {
++        StylistStylesheetSet(StylesheetSet::new())
++    }
++}
++
++impl ops::Deref for StylistStylesheetSet {
++    type Target = StylesheetSet<StylistSheet>;
++
++    fn deref(&self) -> &Self::Target {
++        &self.0
++    }
++}
++
++impl ops::DerefMut for StylistStylesheetSet {
++    fn deref_mut(&mut self) -> &mut Self::Target {
++        &mut self.0
++    }
++}
++
++/// This structure holds all the selectors and device characteristics
++/// for a given document. The selectors are converted into `Rule`s
++/// and sorted into `SelectorMap`s keyed off stylesheet origin and
++/// pseudo-element (see `CascadeData`).
++///
++/// This structure is effectively created once per pipeline, in the
++/// LayoutThread corresponding to that pipeline.
++#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
++pub struct Stylist {
++    /// Device that the stylist is currently evaluating against.
++    ///
++    /// This field deserves a bigger comment due to the different use that Gecko
++    /// and Servo give to it (that we should eventually unify).
++    ///
++    /// With Gecko, the device is never changed. Gecko manually tracks whether
++    /// the device data should be reconstructed, and "resets" the state of the
++    /// device.
++    ///
++    /// On Servo, on the other hand, the device is a really cheap representation
++    /// that is recreated each time some constraint changes and calling
++    /// `set_device`.
++    device: Device,
++
++    /// Viewport constraints based on the current device.
++    viewport_constraints: Option<ViewportConstraints>,
++
++    /// The list of stylesheets.
++    stylesheets: StylistStylesheetSet,
++
++    /// If true, the quirks-mode stylesheet is applied.
++    #[cfg_attr(feature = "servo", ignore_heap_size_of = "defined in selectors")]
++    quirks_mode: QuirksMode,
++
++    /// Selector maps for all of the style sheets in the stylist, after
++    /// evalutaing media rules against the current device, split out per
++    /// cascade level.
++    cascade_data: DocumentCascadeData,
++
++    /// The rule tree, that stores the results of selector matching.
++    rule_tree: RuleTree,
++
++    /// The total number of times the stylist has been rebuilt.
++    num_rebuilds: usize,
++}
++
++/// What cascade levels to include when styling elements.
++#[derive(Copy, Clone, PartialEq)]
++pub enum RuleInclusion {
++    /// Include rules for style sheets at all cascade levels.  This is the
++    /// normal rule inclusion mode.
++    All,
++    /// Only include rules from UA and user level sheets.  Used to implement
++    /// `getDefaultComputedStyle`.
++    DefaultOnly,
++}
++
++#[cfg(feature = "gecko")]
++impl From<StyleRuleInclusion> for RuleInclusion {
++    fn from(value: StyleRuleInclusion) -> Self {
++        match value {
++            StyleRuleInclusion::All => RuleInclusion::All,
++            StyleRuleInclusion::DefaultOnly => RuleInclusion::DefaultOnly,
++        }
++    }
++}
++
++impl Stylist {
++    /// Construct a new `Stylist`, using given `Device` and `QuirksMode`.
++    /// If more members are added here, think about whether they should
++    /// be reset in clear().
++    #[inline]
++    pub fn new(device: Device, quirks_mode: QuirksMode) -> Self {
++        Self {
++            viewport_constraints: None,
++            device,
++            quirks_mode,
++            stylesheets: StylistStylesheetSet::new(),
++            cascade_data: Default::default(),
++            rule_tree: RuleTree::new(),
++            num_rebuilds: 0,
++        }
++    }
++
++    /// Returns the number of selectors.
++    pub fn num_selectors(&self) -> usize {
++        self.cascade_data.iter_origins().map(|(d, _)| d.num_selectors).sum()
++    }
++
++    /// Returns the number of declarations.
++    pub fn num_declarations(&self) -> usize {
++        self.cascade_data.iter_origins().map(|(d, _)| d.num_declarations).sum()
++    }
++
++    /// Returns the number of times the stylist has been rebuilt.
++    pub fn num_rebuilds(&self) -> usize {
++        self.num_rebuilds
++    }
++
++    /// Returns the number of revalidation_selectors.
++    pub fn num_revalidation_selectors(&self) -> usize {
++        self.cascade_data.iter_origins()
++            .map(|(d, _)| d.selectors_for_cache_revalidation.len()).sum()
++    }
++
++    /// Returns the number of entries in invalidation maps.
++    pub fn num_invalidations(&self) -> usize {
++        self.cascade_data.iter_origins()
++            .map(|(d, _)| d.invalidation_map.len()).sum()
++    }
++
++    /// Invokes `f` with the `InvalidationMap` for each origin.
++    ///
++    /// NOTE(heycam) This might be better as an `iter_invalidation_maps`, once
++    /// we have `impl trait` and can return that easily without bothering to
++    /// create a whole new iterator type.
++    pub fn each_invalidation_map<F>(&self, mut f: F)
++        where F: FnMut(&InvalidationMap)
++    {
++        for (data, _) in self.cascade_data.iter_origins() {
++            f(&data.invalidation_map)
++        }
++    }
++
++    /// Flush the list of stylesheets if they changed, ensuring the stylist is
++    /// up-to-date.
++    ///
++    /// FIXME(emilio): Move the `ua_sheets` to the Stylist too?
++    pub fn flush<E>(
++        &mut self,
++        guards: &StylesheetGuards,
++        ua_sheets: Option<&UserAgentStylesheets>,
++        extra_data: &mut PerOrigin<ExtraStyleData>,
++        document_element: Option<E>,
++    )
++    where
++        E: TElement,
++    {
++        if !self.stylesheets.has_changed() {
++            return;
++        }
++
++        let author_style_disabled = self.stylesheets.author_style_disabled();
++        let (doc_stylesheets, origins_to_rebuild) = self.stylesheets.flush(document_element);
++
++        if origins_to_rebuild.is_empty() {
++            return;
++        }
++
++        self.num_rebuilds += 1;
++
++        // Update viewport_constraints regardless of which origins'
++        // `CascadeData` we're updating.
++        self.viewport_constraints = None;
++        if viewport_rule::enabled() {
++            // TODO(emilio): This doesn't look so efficient.
++            //
++            // Presumably when we properly implement this we can at least have a
++            // bit on the stylesheet that says whether it contains viewport
++            // rules to skip it entirely?
++            //
++            // Processing it with the rest of rules seems tricky since it
++            // overrides the viewport size which may change the evaluation of
++            // media queries (or may not? how are viewport units in media
++            // queries defined?)
++            let cascaded_rule = ViewportRule {
++                declarations: viewport_rule::Cascade::from_stylesheets(
++                    doc_stylesheets.clone(), guards.author, &self.device
++                ).finish()
++            };
++
++            self.viewport_constraints =
++                ViewportConstraints::maybe_new(&self.device,
++                                               &cascaded_rule,
++                                               self.quirks_mode);
++
++            if let Some(ref constraints) = self.viewport_constraints {
++                self.device.account_for_viewport_rule(constraints);
++            }
++        }
++
++        self.cascade_data.rebuild(
++            &self.device,
++            self.quirks_mode,
++            doc_stylesheets,
++            guards,
++            ua_sheets,
++            author_style_disabled,
++            extra_data,
++            origins_to_rebuild,
++        );
++    }
++
++    /// Insert a given stylesheet before another stylesheet in the document.
++    pub fn insert_stylesheet_before(
++        &mut self,
++        sheet: StylistSheet,
++        before_sheet: StylistSheet,
++        guard: &SharedRwLockReadGuard,
++    ) {
++        self.stylesheets.insert_stylesheet_before(
++            Some(&self.device),
++            sheet,
++            before_sheet,
++            guard,
++        )
++    }
++
++    /// Marks a given stylesheet origin as dirty, due to, for example, changes
++    /// in the declarations that affect a given rule.
++    ///
++    /// FIXME(emilio): Eventually it'd be nice for this to become more
++    /// fine-grained.
++    pub fn force_stylesheet_origins_dirty(&mut self, origins: OriginSet) {
++        self.stylesheets.force_dirty(origins)
++    }
++
++    /// Iterate over the given set of stylesheets.
++    ///
++    /// This is very intentionally exposed only on `&mut self`, since we don't
++    /// want to give access to the stylesheet list from worker threads.
++    pub fn iter_stylesheets(&mut self) -> StylesheetIterator<StylistSheet> {
++        self.stylesheets.iter()
++    }
++
++    /// Sets whether author style is enabled or not.
++    pub fn set_author_style_disabled(&mut self, disabled: bool) {
++        self.stylesheets.set_author_style_disabled(disabled);
++    }
++
++    /// Returns whether we've recorded any stylesheet change so far.
++    pub fn stylesheets_have_changed(&self) -> bool {
++        self.stylesheets.has_changed()
++    }
++
++    /// Appends a new stylesheet to the current set.
++    pub fn append_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard) {
++        self.stylesheets.append_stylesheet(Some(&self.device), sheet, guard)
++    }
++
++    /// Appends a new stylesheet to the current set.
++    pub fn prepend_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard) {
++        self.stylesheets.prepend_stylesheet(Some(&self.device), sheet, guard)
++    }
++
++    /// Remove a given stylesheet to the current set.
++    pub fn remove_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard) {
++        self.stylesheets.remove_stylesheet(Some(&self.device), sheet, guard)
++    }
+ 
+     /// Returns whether the given attribute might appear in an attribute
+     /// selector of some rule in the stylist.
+-    pub fn might_have_attribute_dependency(&self,
+-                                           local_name: &LocalName)
+-                                           -> bool {
++    pub fn might_have_attribute_dependency(
++        &self,
++        local_name: &LocalName,
++    ) -> bool {
+         if *local_name == local_name!("style") {
+             self.cascade_data
+                 .iter_origins()
+                 .any(|(d, _)| d.style_attribute_dependency)
+         } else {
+             self.cascade_data
+                 .iter_origins()
+                 .any(|(d, _)| {
+@@ -478,25 +642,26 @@ impl Stylist {
+                                          guards: &StylesheetGuards,
+                                          pseudo: &PseudoElement,
+                                          parent: Option<&ComputedValues>,
+                                          cascade_flags: CascadeFlags,
+                                          font_metrics: &FontMetricsProvider)
+                                          -> Arc<ComputedValues> {
+         debug_assert!(pseudo.is_precomputed());
+ 
+-        let rule_node = match self.precomputed_pseudo_element_decls.get(pseudo) {
+-            Some(declarations) => {
+-                self.rule_tree.insert_ordered_rules_with_important(
+-                    declarations.into_iter().map(|a| (a.source.clone(), a.level())),
+-                    guards
+-                )
+-            }
+-            None => self.rule_tree.root().clone(),
+-        };
++        let rule_node =
++            match self.cascade_data.precomputed_pseudo_element_decls.get(pseudo) {
++                Some(declarations) => {
++                    self.rule_tree.insert_ordered_rules_with_important(
++                        declarations.into_iter().map(|a| (a.source.clone(), a.level())),
++                        guards
++                    )
++                }
++                None => self.rule_tree.root().clone(),
++            };
+ 
+         // NOTE(emilio): We skip calculating the proper layout parent style
+         // here.
+         //
+         // It'd be fine to assert that this isn't called with a parent style
+         // where display contents is in effect, but in practice this is hard to
+         // do for stuff like :-moz-fieldset-content with a
+         // <fieldset style="display: contents">. That is, the computed value of
+@@ -518,21 +683,22 @@ impl Stylist {
+                             None,
+                             font_metrics,
+                             cascade_flags,
+                             self.quirks_mode)
+     }
+ 
+     /// Returns the style for an anonymous box of the given type.
+     #[cfg(feature = "servo")]
+-    pub fn style_for_anonymous(&self,
+-                               guards: &StylesheetGuards,
+-                               pseudo: &PseudoElement,
+-                               parent_style: &ComputedValues)
+-                               -> Arc<ComputedValues> {
++    pub fn style_for_anonymous(
++        &self,
++        guards: &StylesheetGuards,
++        pseudo: &PseudoElement,
++        parent_style: &ComputedValues
++    ) -> Arc<ComputedValues> {
+         use font_metrics::ServoMetricsProvider;
+ 
+         // For most (but not all) pseudo-elements, we inherit all values from the parent.
+         let inherit_all = match *pseudo {
+             PseudoElement::ServoText |
+             PseudoElement::ServoInputText => false,
+             PseudoElement::ServoAnonymousBlock |
+             PseudoElement::ServoAnonymousTable |
+@@ -549,18 +715,23 @@ impl Stylist {
+             PseudoElement::DetailsContent => {
+                 unreachable!("That pseudo doesn't represent an anonymous box!")
+             }
+         };
+         let mut cascade_flags = CascadeFlags::empty();
+         if inherit_all {
+             cascade_flags.insert(INHERIT_ALL);
+         }
+-        self.precomputed_values_for_pseudo(guards, &pseudo, Some(parent_style), cascade_flags,
+-                                           &ServoMetricsProvider)
++        self.precomputed_values_for_pseudo(
++            guards,
++            &pseudo,
++            Some(parent_style),
++            cascade_flags,
++            &ServoMetricsProvider
++        )
+     }
+ 
+     /// Computes a pseudo-element style lazily during layout.
+     ///
+     /// This can only be done for a certain set of pseudo-elements, like
+     /// :selection.
+     ///
+     /// Check the documentation on lazy pseudo-elements in
+@@ -844,77 +1015,69 @@ impl Stylist {
+     /// into account.
+     ///
+     /// feature = "servo" because gecko only has one device, and manually tracks
+     /// when the device is dirty.
+     ///
+     /// FIXME(emilio): The semantics of the device for Servo and Gecko are
+     /// different enough we may want to unify them.
+     #[cfg(feature = "servo")]
+-    pub fn set_device<'a, I, S>(
++    pub fn set_device(
+         &mut self,
+         mut device: Device,
+         guard: &SharedRwLockReadGuard,
+-        stylesheets: I,
+-    ) -> OriginSet
+-    where
+-        I: Iterator<Item = &'a S> + Clone,
+-        S: StylesheetInDocument + ToMediaListKey + 'static,
+-    {
+-        let cascaded_rule = ViewportRule {
+-            declarations: viewport_rule::Cascade::from_stylesheets(
+-                stylesheets.clone(),
+-                guard,
+-                &device
+-            ).finish(),
++    ) -> OriginSet {
++        let cascaded_rule = {
++            let stylesheets = self.stylesheets.iter();
++
++            ViewportRule {
++                declarations: viewport_rule::Cascade::from_stylesheets(
++                    stylesheets.clone(),
++                    guard,
++                    &device
++                ).finish(),
++            }
+         };
+ 
+         self.viewport_constraints =
+             ViewportConstraints::maybe_new(&device, &cascaded_rule, self.quirks_mode);
+ 
+         if let Some(ref constraints) = self.viewport_constraints {
+             device.account_for_viewport_rule(constraints);
+         }
+ 
+         self.device = device;
+-        self.media_features_change_changed_style(
+-            stylesheets,
+-            guard,
+-        )
++        self.media_features_change_changed_style(guard)
+     }
+ 
+     /// Returns whether, given a media feature change, any previously-applicable
+     /// style has become non-applicable, or vice-versa for each origin.
+-    pub fn media_features_change_changed_style<'a, I, S>(
++    pub fn media_features_change_changed_style(
+         &self,
+-        stylesheets: I,
+         guard: &SharedRwLockReadGuard,
+-    ) -> OriginSet
+-    where
+-        I: Iterator<Item = &'a S>,
+-        S: StylesheetInDocument + ToMediaListKey + 'static,
+-    {
++    ) -> OriginSet {
+         use invalidation::media_queries::PotentiallyEffectiveMediaRules;
+ 
+         debug!("Stylist::media_features_change_changed_style");
+ 
+         let mut origins = OriginSet::empty();
++        let stylesheets = self.stylesheets.iter();
+ 
+         'stylesheets_loop: for stylesheet in stylesheets {
+             let effective_now =
+                 stylesheet.is_effective_for_device(&self.device, guard);
+ 
+             let origin = stylesheet.origin(guard);
+ 
+             if origins.contains(origin.into()) {
+                 continue;
+             }
+ 
+             let origin_cascade_data =
+-                self.cascade_data.borrow_for_origin(&origin);
++                self.cascade_data.per_origin.borrow_for_origin(&origin);
+ 
+             let effective_then =
+                 origin_cascade_data
+                     .effective_media_query_results
+                     .was_effective(stylesheet);
+ 
+             if effective_now != effective_then {
+                 debug!(" > Stylesheet changed -> {}, {}",
+@@ -1029,17 +1192,17 @@ impl Stylist {
+         let mut matching_context =
+             MatchingContext::new(MatchingMode::Normal, None, self.quirks_mode);
+         let mut dummy_flag_setter = |_: &E, _: ElementSelectorFlags| {};
+ 
+         let rule_hash_target = element.rule_hash_target();
+ 
+         // nsXBLPrototypeResources::LoadResources() loads Chrome XBL style
+         // sheets under eAuthorSheetFeatures level.
+-        if let Some(map) = self.cascade_data.author.borrow_for_pseudo(pseudo_element) {
++        if let Some(map) = self.cascade_data.per_origin.author.borrow_for_pseudo(pseudo_element) {
+             map.get_all_matching_rules(element,
+                                        &rule_hash_target,
+                                        applicable_declarations,
+                                        &mut matching_context,
+                                        self.quirks_mode,
+                                        &mut dummy_flag_setter,
+                                        CascadeLevel::XBL);
+         }
+@@ -1076,17 +1239,17 @@ impl Stylist {
+         let rule_hash_target = element.rule_hash_target();
+ 
+         debug!("Determining if style is shareable: pseudo: {}",
+                pseudo_element.is_some());
+ 
+         let only_default_rules = rule_inclusion == RuleInclusion::DefaultOnly;
+ 
+         // Step 1: Normal user-agent rules.
+-        if let Some(map) = self.cascade_data.user_agent.borrow_for_pseudo(pseudo_element) {
++        if let Some(map) = self.cascade_data.per_origin.user_agent.borrow_for_pseudo(pseudo_element) {
+             map.get_all_matching_rules(element,
+                                        &rule_hash_target,
+                                        applicable_declarations,
+                                        context,
+                                        self.quirks_mode,
+                                        flags_setter,
+                                        CascadeLevel::UANormal);
+         }
+@@ -1112,17 +1275,17 @@ impl Stylist {
+         //
+         //     element.matches_user_and_author_rules() ||
+         //     (is_implemented_pseudo &&
+         //      rule_hash_target.matches_user_and_author_rules())
+         //
+         // Which may be more what you would probably expect.
+         if rule_hash_target.matches_user_and_author_rules() {
+             // Step 3a: User normal rules.
+-            if let Some(map) = self.cascade_data.user.borrow_for_pseudo(pseudo_element) {
++            if let Some(map) = self.cascade_data.per_origin.user.borrow_for_pseudo(pseudo_element) {
+                 map.get_all_matching_rules(element,
+                                            &rule_hash_target,
+                                            applicable_declarations,
+                                            context,
+                                            self.quirks_mode,
+                                            flags_setter,
+                                            CascadeLevel::UserNormal);
+             }
+@@ -1135,17 +1298,17 @@ impl Stylist {
+             element.get_declarations_from_xbl_bindings(pseudo_element,
+                                                        applicable_declarations);
+ 
+         if rule_hash_target.matches_user_and_author_rules() && !only_default_rules {
+             // Gecko skips author normal rules if cutting off inheritance.
+             // See nsStyleSet::FileRules().
+             if !cut_off_inheritance {
+                 // Step 3c: Author normal rules.
+-                if let Some(map) = self.cascade_data.author.borrow_for_pseudo(pseudo_element) {
++                if let Some(map) = self.cascade_data.per_origin.author.borrow_for_pseudo(pseudo_element) {
+                     map.get_all_matching_rules(element,
+                                                &rule_hash_target,
+                                                applicable_declarations,
+                                                context,
+                                                self.quirks_mode,
+                                                flags_setter,
+                                                CascadeLevel::AuthorNormal);
+                 }
+diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs
+--- a/servo/ports/geckolib/glue.rs
++++ b/servo/ports/geckolib/glue.rs
+@@ -210,17 +210,17 @@ fn traverse_subtree(element: GeckoElemen
+     if let Some(parent) = element.traversal_parent() {
+         if parent.borrow_data().map_or(true, |d| d.styles.is_display_none()) {
+             debug!("{:?} has unstyled parent {:?} - ignoring call to traverse_subtree", element, parent);
+             return;
+         }
+     }
+ 
+     let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
+-    debug_assert!(!per_doc_data.stylesheets.has_changed());
++    debug_assert!(!per_doc_data.stylist.stylesheets_have_changed());
+ 
+     let global_style_data = &*GLOBAL_STYLE_DATA;
+     let guard = global_style_data.shared_lock.read();
+     let shared_style_context = create_shared_context(&global_style_data,
+                                                      &guard,
+                                                      &per_doc_data,
+                                                      traversal_flags,
+                                                      snapshots);
+@@ -897,17 +897,17 @@ pub extern "C" fn Servo_StyleSet_AppendS
+     raw_data: RawServoStyleSetBorrowed,
+     sheet: *const ServoStyleSheet,
+ ) {
+     let global_style_data = &*GLOBAL_STYLE_DATA;
+     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
+     let data = &mut *data;
+     let guard = global_style_data.shared_lock.read();
+     let sheet = unsafe { GeckoStyleSheet::new(sheet) };
+-    data.stylesheets.append_stylesheet(Some(data.stylist.device()), sheet, &guard);
++    data.stylist.append_stylesheet(sheet, &guard);
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_StyleSet_MediumFeaturesChanged(
+     raw_data: RawServoStyleSetBorrowed,
+     viewport_units_used: *mut bool,
+ ) -> u8 {
+     let global_style_data = &*GLOBAL_STYLE_DATA;
+@@ -925,20 +925,17 @@ pub extern "C" fn Servo_StyleSet_MediumF
+     // less often.
+     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
+ 
+     unsafe {
+         *viewport_units_used = data.stylist.device().used_viewport_size();
+     }
+     data.stylist.device_mut().reset_computed_values();
+     let origins_in_which_rules_changed =
+-        data.stylist.media_features_change_changed_style(
+-            data.stylesheets.iter(),
+-            &guard,
+-        );
++        data.stylist.media_features_change_changed_style(&guard);
+ 
+     // We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
+     // work as return values with the Linux 32-bit ABI at the moment because
+     // they wrap the value in a struct, so for now just unwrap it.
+     OriginFlags::from(origins_in_which_rules_changed).0
+ }
+ 
+ #[no_mangle]
+@@ -946,49 +943,48 @@ pub extern "C" fn Servo_StyleSet_Prepend
+     raw_data: RawServoStyleSetBorrowed,
+     sheet: *const ServoStyleSheet,
+ ) {
+     let global_style_data = &*GLOBAL_STYLE_DATA;
+     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
+     let data = &mut *data;
+     let guard = global_style_data.shared_lock.read();
+     let sheet = unsafe { GeckoStyleSheet::new(sheet) };
+-    data.stylesheets.prepend_stylesheet(Some(data.stylist.device()), sheet, &guard);
++    data.stylist.prepend_stylesheet(sheet, &guard);
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(
+     raw_data: RawServoStyleSetBorrowed,
+     sheet: *const ServoStyleSheet,
+     before_sheet: *const ServoStyleSheet
+ ) {
+     let global_style_data = &*GLOBAL_STYLE_DATA;
+     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
+     let data = &mut *data;
+     let guard = global_style_data.shared_lock.read();
+     let sheet = unsafe { GeckoStyleSheet::new(sheet) };
+-    data.stylesheets.insert_stylesheet_before(
+-        Some(data.stylist.device()),
++    data.stylist.insert_stylesheet_before(
+         sheet,
+         unsafe { GeckoStyleSheet::new(before_sheet) },
+         &guard,
+     );
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(
+     raw_data: RawServoStyleSetBorrowed,
+     sheet: *const ServoStyleSheet
+ ) {
+     let global_style_data = &*GLOBAL_STYLE_DATA;
+     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
+     let data = &mut *data;
+     let guard = global_style_data.shared_lock.read();
+     let sheet = unsafe { GeckoStyleSheet::new(sheet) };
+-    data.stylesheets.remove_stylesheet(Some(data.stylist.device()), sheet, &guard);
++    data.stylist.remove_stylesheet(sheet, &guard);
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_StyleSet_FlushStyleSheets(
+     raw_data: RawServoStyleSetBorrowed,
+     doc_element: RawGeckoElementBorrowedOrNull,
+ ) {
+     let global_style_data = &*GLOBAL_STYLE_DATA;
+@@ -1000,18 +996,18 @@ pub extern "C" fn Servo_StyleSet_FlushSt
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(
+     raw_data: RawServoStyleSetBorrowed,
+     author_style_disabled: bool,
+     changed_origins: OriginFlags,
+ ) {
+     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
+-    data.stylesheets.force_dirty(OriginSet::from(changed_origins));
+-    data.stylesheets.set_author_style_disabled(author_style_disabled);
++    data.stylist.force_stylesheet_origins_dirty(OriginSet::from(changed_origins));
++    data.stylist.set_author_style_disabled(author_style_disabled);
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_StyleSheet_HasRules(
+     raw_contents: RawServoStyleSheetContentsBorrowed
+ ) -> bool {
+     let global_style_data = &*GLOBAL_STYLE_DATA;
+     let guard = global_style_data.shared_lock.read();

+ 788 - 0
frg/253-58/mozilla-release58_428111.patch

@@ -0,0 +1,788 @@
+# HG changeset patch
+# User Jan de Mooij <jdemooij@mozilla.com>
+# Date 1503386737 -7200
+#      Tue Aug 22 09:25:37 2017 +0200
+# Node ID 89df4227af85ff946e1611e73136c3525fdde353
+# Parent  48688db04b07bba483d69bb3ca7442e79d606bdb
+Bug 1390489 - Port StatementRow to WebIDL bindings. r=asuth,qdot
+
+diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf
+--- a/dom/bindings/Bindings.conf
++++ b/dom/bindings/Bindings.conf
+@@ -595,16 +595,21 @@ DOMInterfaces = {
+     'nativeType': 'mozilla::dom::HTMLCanvasPrintState',
+ },
+ 
+ 'MozChannel': {
+     'nativeType': 'nsIChannel',
+     'notflattened': True
+ },
+ 
++'MozStorageStatementRow': {
++    'headerFile': 'mozilla/storage/mozStorageStatementRow.h',
++    'nativeType': 'mozilla::storage::StatementRow',
++},
++
+ 'MutationObserver': {
+     'nativeType': 'nsDOMMutationObserver',
+ },
+ 
+ 'MutationRecord': {
+     'nativeType': 'nsDOMMutationRecord',
+     'headerFile': 'nsDOMMutationObserver.h',
+ },
+diff --git a/dom/webidl/MozStorageStatementRow.webidl b/dom/webidl/MozStorageStatementRow.webidl
+new file mode 100644
+--- /dev/null
++++ b/dom/webidl/MozStorageStatementRow.webidl
+@@ -0,0 +1,11 @@
++/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* 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/. */
++
++[ChromeOnly]
++interface MozStorageStatementRow
++{
++  [Throws]
++  getter any(DOMString name);
++};
+diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build
+--- a/dom/webidl/moz.build
++++ b/dom/webidl/moz.build
+@@ -668,16 +668,17 @@ WEBIDL_FILES = [
+     'MenuBoxObject.webidl',
+     'MessageChannel.webidl',
+     'MessageEvent.webidl',
+     'MessagePort.webidl',
+     'MimeType.webidl',
+     'MimeTypeArray.webidl',
+     'MouseEvent.webidl',
+     'MouseScrollEvent.webidl',
++    'MozStorageStatementRow.webidl',
+     'MutationEvent.webidl',
+     'MutationObserver.webidl',
+     'NamedNodeMap.webidl',
+     'NativeOSFileInternals.webidl',
+     'NetDashboard.webidl',
+     'NetworkInformation.webidl',
+     'NetworkOptions.webidl',
+     'NodeFilter.webidl',
+diff --git a/storage/moz.build b/storage/moz.build
+--- a/storage/moz.build
++++ b/storage/moz.build
+@@ -25,17 +25,16 @@ XPIDL_SOURCES += [
+     'mozIStoragePendingStatement.idl',
+     'mozIStorageProgressHandler.idl',
+     'mozIStorageResultSet.idl',
+     'mozIStorageRow.idl',
+     'mozIStorageService.idl',
+     'mozIStorageStatement.idl',
+     'mozIStorageStatementCallback.idl',
+     'mozIStorageStatementParams.idl',
+-    'mozIStorageStatementRow.idl',
+     'mozIStorageVacuumParticipant.idl',
+     'mozIStorageValueArray.idl',
+ ]
+ 
+ XPIDL_MODULE = 'storage'
+ 
+ EXPORTS += [
+     'mozStorageHelper.h',
+@@ -43,16 +42,17 @@ EXPORTS += [
+ 
+ EXPORTS.mozilla += [
+     'storage.h',
+ ]
+ 
+ # NOTE When adding something to this list, you probably need to add it to the
+ #      storage.h file too.
+ EXPORTS.mozilla.storage += [
++    'mozStorageStatementRow.h',
+     'StatementCache.h',
+     'Variant.h',
+     'Variant_inl.h',
+ ]
+ # SEE ABOVE NOTE!
+ 
+ UNIFIED_SOURCES += [
+     'FileSystemModule.cpp',
+diff --git a/storage/mozIStorageStatementRow.idl b/storage/mozIStorageStatementRow.idl
+deleted file mode 100644
+--- a/storage/mozIStorageStatementRow.idl
++++ /dev/null
+@@ -1,12 +0,0 @@
+-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsISupports.idl"
+-
+-[scriptable, uuid(02eeaf95-c3db-4182-9340-222c29f68f02)]
+-interface mozIStorageStatementRow : nsISupports {
+-  // Magic interface we return that implements nsIXPCScriptable, to allow
+-  // for by-name access to rows.
+-};
+diff --git a/storage/mozStorageStatement.h b/storage/mozStorageStatement.h
+--- a/storage/mozStorageStatement.h
++++ b/storage/mozStorageStatement.h
+@@ -21,16 +21,17 @@
+ 
+ class nsIXPConnectJSObjectHolder;
+ struct sqlite3_stmt;
+ 
+ namespace mozilla {
+ namespace storage {
+ class StatementJSHelper;
+ class Connection;
++class StatementRowHolder;
+ 
+ class Statement final : public mozIStorageStatement
+                       , public mozIStorageValueArray
+                       , public StorageBaseStatementInternal
+ {
+ public:
+   NS_DECL_THREADSAFE_ISUPPORTS
+   NS_DECL_MOZISTORAGESTATEMENT
+@@ -92,27 +93,33 @@ private:
+      */
+     RefPtr<BindingParamsArray> mParamsArray;
+ 
+     /**
+      * The following two members are only used with the JS helper.  They cache
+      * the row and params objects.
+      */
+     nsMainThreadPtrHandle<nsIXPConnectJSObjectHolder> mStatementParamsHolder;
+-    nsMainThreadPtrHandle<nsIXPConnectJSObjectHolder> mStatementRowHolder;
++    nsMainThreadPtrHandle<StatementRowHolder> mStatementRowHolder;
+ 
+   /**
+    * Internal version of finalize that allows us to tell it if it is being
+    * called from the destructor so it can know not to dispatch events that
+    * require a reference to us.
+    *
+    * @param aDestructing
+    *        Is the destructor calling?
+    */
+   nsresult internalFinalize(bool aDestructing);
+ 
+   friend class StatementJSHelper;
+ };
+ 
++inline nsISupports*
++ToSupports(Statement* p)
++{
++  return NS_ISUPPORTS_CAST(mozIStorageStatement*, p);
++}
++
+ } // namespace storage
+ } // namespace mozilla
+ 
+ #endif // mozStorageStatement_h
+diff --git a/storage/mozStorageStatementJSHelper.cpp b/storage/mozStorageStatementJSHelper.cpp
+--- a/storage/mozStorageStatementJSHelper.cpp
++++ b/storage/mozStorageStatementJSHelper.cpp
+@@ -82,49 +82,50 @@ stepFunc(JSContext *aCtx,
+ 
+ nsresult
+ StatementJSHelper::getRow(Statement *aStatement,
+                           JSContext *aCtx,
+                           JSObject *aScopeObj,
+                           JS::Value *_row)
+ {
+   MOZ_ASSERT(NS_IsMainThread());
+-  nsresult rv;
+ 
+ #ifdef DEBUG
+   int32_t state;
+   (void)aStatement->GetState(&state);
+   NS_ASSERTION(state == mozIStorageStatement::MOZ_STORAGE_STATEMENT_EXECUTING,
+                "Invalid state to get the row object - all calls will fail!");
+ #endif
+ 
++  JS::RootedObject scope(aCtx, aScopeObj);
++
+   if (!aStatement->mStatementRowHolder) {
+-    JS::RootedObject scope(aCtx, aScopeObj);
+-    nsCOMPtr<mozIStorageStatementRow> row(new StatementRow(aStatement));
++    dom::GlobalObject global(aCtx, scope);
++    if (global.Failed()) {
++      return NS_ERROR_UNEXPECTED;
++    }
++
++    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
++
++    RefPtr<StatementRow> row(new StatementRow(window, aStatement));
+     NS_ENSURE_TRUE(row, NS_ERROR_OUT_OF_MEMORY);
+ 
+-    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
+-    nsCOMPtr<nsIXPConnect> xpc(Service::getXPConnect());
+-    rv = xpc->WrapNativeHolder(
+-      aCtx,
+-      ::JS_GetGlobalForObject(aCtx, scope),
+-      row,
+-      NS_GET_IID(mozIStorageStatementRow),
+-      getter_AddRefs(holder)
+-    );
+-    NS_ENSURE_SUCCESS(rv, rv);
+-    RefPtr<StatementRowHolder> rowHolder = new StatementRowHolder(holder);
++    RefPtr<StatementRowHolder> rowHolder = new StatementRowHolder(row);
++    NS_ENSURE_TRUE(rowHolder, NS_ERROR_OUT_OF_MEMORY);
++
+     aStatement->mStatementRowHolder =
+-      new nsMainThreadPtrHolder<nsIXPConnectJSObjectHolder>(
++      new nsMainThreadPtrHolder<StatementRowHolder>(
+         "Statement::mStatementRowHolder", rowHolder);
+   }
+ 
+-  JS::Rooted<JSObject*> obj(aCtx);
+-  obj = aStatement->mStatementRowHolder->GetJSObject();
+-  NS_ENSURE_STATE(obj);
++  RefPtr<StatementRow> row(aStatement->mStatementRowHolder->Get());
++  JSObject* obj = row->WrapObject(aCtx, nullptr);
++  if (!obj) {
++    return NS_ERROR_UNEXPECTED;
++  }
+ 
+   _row->setObject(*obj);
+   return NS_OK;
+ }
+ 
+ nsresult
+ StatementJSHelper::getParams(Statement *aStatement,
+                              JSContext *aCtx,
+@@ -265,21 +266,20 @@ StatementParamsHolder::~StatementParamsH
+   // We are considered dead at this point, so any wrappers for row or params
+   // need to lose their reference to the statement.
+   nsCOMPtr<nsIXPConnectWrappedNative> wrapper = do_QueryInterface(mHolder);
+   nsCOMPtr<mozIStorageStatementParams> iObj = do_QueryWrappedNative(wrapper);
+   StatementParams *obj = static_cast<StatementParams *>(iObj.get());
+   obj->mStatement = nullptr;
+ }
+ 
++NS_IMPL_ISUPPORTS0(StatementRowHolder);
++
+ StatementRowHolder::~StatementRowHolder()
+ {
+   MOZ_ASSERT(NS_IsMainThread());
+   // We are considered dead at this point, so any wrappers for row or params
+   // need to lose their reference to the statement.
+-  nsCOMPtr<nsIXPConnectWrappedNative> wrapper = do_QueryInterface(mHolder);
+-  nsCOMPtr<mozIStorageStatementRow> iObj = do_QueryWrappedNative(wrapper);
+-  StatementRow *obj = static_cast<StatementRow *>(iObj.get());
+-  obj->mStatement = nullptr;
++  mRow->mStatement = nullptr;
+ }
+ 
+ } // namespace storage
+ } // namespace mozilla
+diff --git a/storage/mozStorageStatementJSHelper.h b/storage/mozStorageStatementJSHelper.h
+--- a/storage/mozStorageStatementJSHelper.h
++++ b/storage/mozStorageStatementJSHelper.h
+@@ -10,16 +10,18 @@
+ #include "nsIXPCScriptable.h"
+ #include "nsIXPConnect.h"
+ 
+ class Statement;
+ 
+ namespace mozilla {
+ namespace storage {
+ 
++class StatementRow;
++
+ class StatementJSHelper : public nsIXPCScriptable
+ {
+ public:
+   NS_DECL_ISUPPORTS
+   NS_DECL_NSIXPCSCRIPTABLE
+ 
+ private:
+   nsresult getRow(Statement *, JSContext *, JSObject *, JS::Value *);
+@@ -49,22 +51,32 @@ public:
+   explicit StatementParamsHolder(nsIXPConnectJSObjectHolder* aHolder)
+     : StatementJSObjectHolder(aHolder) {
+   }
+ 
+ private:
+   virtual ~StatementParamsHolder();
+ };
+ 
+-class StatementRowHolder final: public StatementJSObjectHolder {
++class StatementRowHolder final: public nsISupports {
+ public:
+-  explicit StatementRowHolder(nsIXPConnectJSObjectHolder* aHolder)
+-    : StatementJSObjectHolder(aHolder) {
++  NS_DECL_ISUPPORTS
++
++  explicit StatementRowHolder(StatementRow* aRow)
++    : mRow(aRow)
++  {
++  }
++
++  StatementRow* Get() const {
++    MOZ_ASSERT(mRow);
++    return mRow;
+   }
+ 
+ private:
+   virtual ~StatementRowHolder();
++
++  RefPtr<StatementRow> mRow;
+ };
+ 
+ } // namespace storage
+ } // namespace mozilla
+ 
+ #endif // MOZSTORAGESTATEMENTJSHELPER_H
+diff --git a/storage/mozStorageStatementRow.cpp b/storage/mozStorageStatementRow.cpp
+--- a/storage/mozStorageStatementRow.cpp
++++ b/storage/mozStorageStatementRow.cpp
+@@ -2,156 +2,157 @@
+  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
+  * 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/. */
+ 
+ #include "nsMemory.h"
+ #include "nsString.h"
+ 
++#include "mozilla/dom/MozStorageStatementRowBinding.h"
+ #include "mozStorageStatementRow.h"
+ #include "mozStorageStatement.h"
+ 
+ #include "jsapi.h"
+ 
+ #include "xpc_make_class.h"
+ 
+ namespace mozilla {
+ namespace storage {
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ //// StatementRow
+ 
+-StatementRow::StatementRow(Statement *aStatement)
+-: mStatement(aStatement)
++NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(StatementRow, mWindow)
++
++NS_INTERFACE_TABLE_HEAD(StatementRow)
++  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
++  NS_INTERFACE_TABLE(StatementRow, nsISupports)
++  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(StatementRow)
++NS_INTERFACE_MAP_END
++
++NS_IMPL_CYCLE_COLLECTING_ADDREF(StatementRow)
++NS_IMPL_CYCLE_COLLECTING_RELEASE(StatementRow)
++
++StatementRow::StatementRow(nsPIDOMWindowInner* aWindow, Statement *aStatement)
++: mWindow(aWindow),
++  mStatement(aStatement)
+ {
+ }
+ 
+-NS_IMPL_ISUPPORTS(
+-  StatementRow,
+-  mozIStorageStatementRow,
+-  nsIXPCScriptable
+-)
+-
+-////////////////////////////////////////////////////////////////////////////////
+-//// nsIXPCScriptable
+-
+-#define XPC_MAP_CLASSNAME         StatementRow
+-#define XPC_MAP_QUOTED_CLASSNAME "StatementRow"
+-#define XPC_MAP_FLAGS (XPC_SCRIPTABLE_WANT_GETPROPERTY | \
+-                       XPC_SCRIPTABLE_WANT_RESOLVE | \
+-                       XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
+-#include "xpc_map_end.h"
+-
+-NS_IMETHODIMP
+-StatementRow::GetProperty(nsIXPConnectWrappedNative *aWrapper,
+-                          JSContext *aCtx,
+-                          JSObject *aScopeObj,
+-                          jsid aId,
+-                          JS::Value *_vp,
+-                          bool *_retval)
++JSObject*
++StatementRow::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+ {
+-  NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED);
+-
+-  JS::RootedObject scope(aCtx, aScopeObj);
+-  if (JSID_IS_STRING(aId)) {
+-    ::JSAutoByteString idBytes(aCtx, JSID_TO_STRING(aId));
+-    NS_ENSURE_TRUE(!!idBytes, NS_ERROR_OUT_OF_MEMORY);
+-    nsDependentCString jsid(idBytes.ptr());
+-
+-    uint32_t idx;
+-    nsresult rv = mStatement->GetColumnIndex(jsid, &idx);
+-    NS_ENSURE_SUCCESS(rv, rv);
+-    int32_t type;
+-    rv = mStatement->GetTypeOfIndex(idx, &type);
+-    NS_ENSURE_SUCCESS(rv, rv);
++  return dom::MozStorageStatementRowBinding::Wrap(aCx, this, aGivenProto);
++}
+ 
+-    if (type == mozIStorageValueArray::VALUE_TYPE_INTEGER ||
+-        type == mozIStorageValueArray::VALUE_TYPE_FLOAT) {
+-      double dval;
+-      rv = mStatement->GetDouble(idx, &dval);
+-      NS_ENSURE_SUCCESS(rv, rv);
+-      *_vp = ::JS_NumberValue(dval);
+-    }
+-    else if (type == mozIStorageValueArray::VALUE_TYPE_TEXT) {
+-      uint32_t bytes;
+-      const char16_t *sval = reinterpret_cast<const char16_t *>(
+-        static_cast<mozIStorageStatement *>(mStatement)->
+-          AsSharedWString(idx, &bytes)
+-      );
+-      JSString *str = ::JS_NewUCStringCopyN(aCtx, sval, bytes / 2);
+-      if (!str) {
+-        *_retval = false;
+-        return NS_OK;
+-      }
+-      _vp->setString(str);
+-    }
+-    else if (type == mozIStorageValueArray::VALUE_TYPE_BLOB) {
+-      uint32_t length;
+-      const uint8_t *blob = static_cast<mozIStorageStatement *>(mStatement)->
+-        AsSharedBlob(idx, &length);
+-      JSObject *obj = ::JS_NewArrayObject(aCtx, length);
+-      if (!obj) {
+-        *_retval = false;
+-        return NS_OK;
+-      }
+-      _vp->setObject(*obj);
+-
+-      // Copy the blob over to the JS array.
+-      for (uint32_t i = 0; i < length; i++) {
+-        if (!::JS_DefineElement(aCtx, scope, i, blob[i], JSPROP_ENUMERATE)) {
+-          *_retval = false;
+-          return NS_OK;
+-        }
+-      }
+-    }
+-    else if (type == mozIStorageValueArray::VALUE_TYPE_NULL) {
+-      _vp->setNull();
+-    }
+-    else {
+-      NS_ERROR("unknown column type returned, what's going on?");
+-    }
++void
++StatementRow::NamedGetter(JSContext* aCx,
++                          const nsAString& aName,
++                          bool& aFound,
++                          JS::MutableHandle<JS::Value> aResult,
++                          mozilla::ErrorResult& aRv)
++{
++  if (!mStatement) {
++    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
++    return;
+   }
+ 
+-  return NS_OK;
+-}
++  nsCString name = NS_ConvertUTF16toUTF8(aName);
+ 
+-NS_IMETHODIMP
+-StatementRow::Resolve(nsIXPConnectWrappedNative *aWrapper,
+-                      JSContext *aCtx,
+-                      JSObject *aScopeObj,
+-                      jsid aId,
+-                      bool *aResolvedp,
+-                      bool *_retval)
+-{
+-  JS::Rooted<JSObject*> scopeObj(aCtx, aScopeObj);
+-
+-  NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED);
+-  // We do not throw at any point after this because we want to allow the
+-  // prototype chain to be checked for the property.
+-
+-  if (JSID_IS_STRING(aId)) {
+-    ::JSAutoByteString idBytes(aCtx, JSID_TO_STRING(aId));
+-    NS_ENSURE_TRUE(!!idBytes, NS_ERROR_OUT_OF_MEMORY);
+-    nsDependentCString name(idBytes.ptr());
+-
+-    uint32_t idx;
++  uint32_t idx;
++  {
+     nsresult rv = mStatement->GetColumnIndex(name, &idx);
+     if (NS_FAILED(rv)) {
+       // It's highly likely that the name doesn't exist, so let the JS engine
+       // check the prototype chain and throw if that doesn't have the property
+       // either.
+-      *aResolvedp = false;
+-      return NS_OK;
++      aFound = false;
++      return;
+     }
++  }
+ 
+-    JS::Rooted<jsid> id(aCtx, aId);
+-    *_retval = ::JS_DefinePropertyById(aCtx, scopeObj, id, JS::UndefinedHandleValue,
+-                                       JSPROP_RESOLVING);
+-    *aResolvedp = true;
+-    return NS_OK;
++  int32_t type;
++  aRv = mStatement->GetTypeOfIndex(idx, &type);
++  if (aRv.Failed()) {
++    return;
+   }
+ 
+-  return NS_OK;
++  switch (type) {
++  case mozIStorageValueArray::VALUE_TYPE_INTEGER:
++  case mozIStorageValueArray::VALUE_TYPE_FLOAT: {
++    double dval;
++    aRv = mStatement->GetDouble(idx, &dval);
++    if (aRv.Failed()) {
++      return;
++    }
++    aResult.set(::JS_NumberValue(dval));
++    break;
++  }
++  case mozIStorageValueArray::VALUE_TYPE_TEXT: {
++    uint32_t bytes;
++    const char16_t *sval = reinterpret_cast<const char16_t *>(
++        static_cast<mozIStorageStatement *>(mStatement)->
++          AsSharedWString(idx, &bytes)
++      );
++    JSString *str = ::JS_NewUCStringCopyN(aCx, sval, bytes / 2);
++    if (!str) {
++      aRv.Throw(NS_ERROR_UNEXPECTED);
++      return;
++    }
++    aResult.setString(str);
++    break;
++  }
++  case mozIStorageValueArray::VALUE_TYPE_BLOB: {
++    uint32_t length;
++    const uint8_t *blob = static_cast<mozIStorageStatement *>(mStatement)->
++      AsSharedBlob(idx, &length);
++    JS::Rooted<JSObject*> obj(aCx, ::JS_NewArrayObject(aCx, length));
++    if (!obj) {
++      aRv.Throw(NS_ERROR_UNEXPECTED);
++      return;
++    }
++    aResult.setObject(*obj);
++
++    // Copy the blob over to the JS array.
++    for (uint32_t i = 0; i < length; i++) {
++      if (!::JS_DefineElement(aCx, obj, i, blob[i], JSPROP_ENUMERATE)) {
++        aRv.Throw(NS_ERROR_UNEXPECTED);
++        return;
++      }
++    }
++    break;
++  }
++  case mozIStorageValueArray::VALUE_TYPE_NULL:
++    aResult.setNull();
++    break;
++  default:
++    NS_ERROR("unknown column type returned, what's going on?");
++    break;
++  }
++  aFound = true;
++}
++
++void
++StatementRow::GetSupportedNames(nsTArray<nsString>& aNames)
++{
++  if (!mStatement) {
++    return;
++  }
++
++  uint32_t columnCount;
++  nsresult rv = mStatement->GetColumnCount(&columnCount);
++  if (NS_WARN_IF(NS_FAILED(rv))) {
++    return;
++  }
++
++  for (uint32_t i = 0; i < columnCount; i++) {
++    nsAutoCString name;
++    nsresult rv = mStatement->GetColumnName(i, name);
++    if (NS_WARN_IF(NS_FAILED(rv))) {
++      return;
++    }
++    aNames.AppendElement(NS_ConvertUTF8toUTF16(name));
++  }
+ }
+ 
+ } // namespace storage
+ } // namespace mozilla
+diff --git a/storage/mozStorageStatementRow.h b/storage/mozStorageStatementRow.h
+--- a/storage/mozStorageStatementRow.h
++++ b/storage/mozStorageStatementRow.h
+@@ -2,38 +2,53 @@
+  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
+  * 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/. */
+ 
+ #ifndef MOZSTORAGESTATEMENTROW_H
+ #define MOZSTORAGESTATEMENTROW_H
+ 
+-#include "mozIStorageStatementRow.h"
+-#include "nsIXPCScriptable.h"
+ #include "mozilla/Attributes.h"
++#include "mozilla/ErrorResult.h"
++#include "nsPIDOMWindow.h"
++#include "nsWrapperCache.h"
+ 
+ namespace mozilla {
+ namespace storage {
+ 
+ class Statement;
+ 
+-class StatementRow final : public mozIStorageStatementRow
+-                         , public nsIXPCScriptable
++class StatementRow final : public nsISupports
++                         , public nsWrapperCache
+ {
+ public:
+-  NS_DECL_ISUPPORTS
+-  NS_DECL_MOZISTORAGESTATEMENTROW
+-  NS_DECL_NSIXPCSCRIPTABLE
++  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
++  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StatementRow)
++
++  explicit StatementRow(nsPIDOMWindowInner* aWindow, Statement *aStatement);
+ 
+-  explicit StatementRow(Statement *aStatement);
+-protected:
++  void NamedGetter(JSContext* aCx,
++                   const nsAString& aName,
++                   bool& aFound,
++                   JS::MutableHandle<JS::Value> aResult,
++                   mozilla::ErrorResult& aRv);
++  void GetSupportedNames(nsTArray<nsString>& aNames);
+ 
++  JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
++
++  nsPIDOMWindowInner* GetParentObject() const
++  {
++    return mWindow;
++  }
++
++private:
+   ~StatementRow() {}
+ 
++  nsCOMPtr<nsPIDOMWindowInner> mWindow;
+   Statement *mStatement;
+ 
+   friend class StatementRowHolder;
+ };
+ 
+ } // namespace storage
+ } // namespace mozilla
+ 
+diff --git a/storage/test/unit/test_js_helpers.js b/storage/test/unit/test_js_helpers.js
+--- a/storage/test/unit/test_js_helpers.js
++++ b/storage/test/unit/test_js_helpers.js
+@@ -19,27 +19,30 @@ function test_params_enumerate() {
+   // Make sure they are right.
+   let expected = ["a", "b", "c"];
+   let index = 0;
+   for (let name in stmt.params) {
+     if (name == "QueryInterface")
+       continue;
+     Assert.equal(name, expected[index++]);
+   }
++  Assert.equal(index, 3);
+ }
+ 
+ function test_params_prototype() {
+   let stmt = createStatement(
+     "SELECT * FROM sqlite_master"
+   );
+ 
+   // Set a property on the prototype and make sure it exist (will not be a
+   // bindable parameter, however).
+   Object.getPrototypeOf(stmt.params).test = 2;
+   Assert.equal(stmt.params.test, 2);
++
++  delete Object.getPrototypeOf(stmt.params).test;
+   stmt.finalize();
+ }
+ 
+ function test_row_prototype() {
+   let stmt = createStatement(
+     "SELECT * FROM sqlite_master"
+   );
+ 
+@@ -50,16 +53,44 @@ function test_row_prototype() {
+   Object.getPrototypeOf(stmt.row).test = 2;
+   Assert.equal(stmt.row.test, 2);
+ 
+   // Clean up after ourselves.
+   delete Object.getPrototypeOf(stmt.row).test;
+   stmt.finalize();
+ }
+ 
++function test_row_enumerate() {
++  let stmt = createStatement(
++    "SELECT * FROM test"
++  );
++
++  do_check_true(stmt.executeStep());
++
++  let expected = ["id", "string"];
++  let expected_values = [123, "foo"];
++  let index = 0;
++  for (let name in stmt.row) {
++    do_check_eq(name, expected[index]);
++    do_check_eq(stmt.row[name], expected_values[index]);
++    index++;
++  }
++  do_check_eq(index, 2);
++
++  // Save off the row helper, then forget the statement and trigger a GC.  We
++  // want to ensure that if the row helper is retained but the statement is
++  // destroyed, that no crash occurs and that the late access attempt simply
++  // throws an error.
++  let savedOffRow = stmt.row;
++  stmt = null;
++  Components.utils.forceGC();
++  Assert.throws(() => { return savedOffRow.string; },
++                "GC'ed statement should throw");
++}
++
+ function test_params_gets_sync() {
+   // Added for bug 562866.
+   /*
+   let stmt = createStatement(
+     "SELECT * FROM test WHERE id IN (:a, :b, :c)"
+   );
+ 
+   // Make sure we do not assert in getting the value.
+@@ -95,25 +126,29 @@ function test_params_gets_async() {
+   */
+ }
+ 
+ // Test Runner
+ 
+ var tests = [
+   test_params_enumerate,
+   test_params_prototype,
++  test_row_enumerate,
+   test_row_prototype,
+   test_params_gets_sync,
+   test_params_gets_async,
+ ];
+ function run_test() {
+   cleanup();
+ 
+   // Create our database.
+   getOpenedDatabase().executeSimpleSQL(
+     "CREATE TABLE test (" +
+-      "id INTEGER PRIMARY KEY " +
++      "id INTEGER PRIMARY KEY, string TEXT" +
+     ")"
+   );
++  getOpenedDatabase().executeSimpleSQL(
++    "INSERT INTO test (id, string) VALUES (123, 'foo')"
++  );
+ 
+   // Run the tests.
+   tests.forEach(test => test());
+ }

+ 387 - 0
frg/253-58/mozilla-release58_428113.patch

@@ -0,0 +1,387 @@
+# HG changeset patch
+# User Christoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
+# Date 1503389223 -7200
+#      Tue Aug 22 10:07:03 2017 +0200
+# Node ID 46d5697dc9e0b8ce53d5d02f7c5f228a5dab4914
+# Parent  7632f5bf482b3c54da65d624df037cdce3d89284
+Bug 1370843 - Provide correct triggeringPrincipal for dropLinks. r=smaug,tooru
+
+diff --git a/docshell/base/nsDocShellTreeOwner.cpp b/docshell/base/nsDocShellTreeOwner.cpp
+--- a/docshell/base/nsDocShellTreeOwner.cpp
++++ b/docshell/base/nsDocShellTreeOwner.cpp
+@@ -968,17 +968,16 @@ nsDocShellTreeOwner::HandleEvent(nsIDOME
+       nsIDroppedLinkItem** links;
+       if (webnav &&
+           NS_SUCCEEDED(handler->DropLinks(dragEvent, true, &linksCount, &links))) {
+         if (linksCount >= 1) {
+           nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
+           if (webBrowserChrome) {
+             nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(webBrowserChrome);
+             if (tabChild) {
+-              // Bug 1370843 - Explicitly pass triggeringPrincipal
+               nsresult rv = tabChild->RemoteDropLinks(linksCount, links);
+               for (uint32_t i = 0; i < linksCount; i++) {
+                 NS_RELEASE(links[i]);
+               }
+               free(links);
+               return rv;
+             }
+           }
+diff --git a/dom/base/contentAreaDropListener.js b/dom/base/contentAreaDropListener.js
+--- a/dom/base/contentAreaDropListener.js
++++ b/dom/base/contentAreaDropListener.js
+@@ -230,16 +230,25 @@ ContentAreaDropListener.prototype =
+       }
+     }
+     if (aCount)
+       aCount.value = links.length;
+ 
+     return links;
+   },
+ 
++  queryLinks: function(aDataTransfer, aCount)
++  {
++    let links = this._getDropLinks(aDataTransfer);
++    if (aCount) {
++      aCount.value = links.length;
++    }
++    return links;
++  },
++
+   _eventTargetIsDisabled: function(aEvent)
+   {
+     let ownerDoc = aEvent.originalTarget.ownerDocument;
+     if (!ownerDoc || !ownerDoc.defaultView)
+       return false;
+ 
+     return ownerDoc.defaultView
+                    .QueryInterface(Ci.nsIInterfaceRequestor)
+diff --git a/dom/base/nsIDroppedLinkHandler.idl b/dom/base/nsIDroppedLinkHandler.idl
+--- a/dom/base/nsIDroppedLinkHandler.idl
++++ b/dom/base/nsIDroppedLinkHandler.idl
+@@ -1,15 +1,16 @@
+ /* 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/. */
+ 
+ #include "nsISupports.idl"
+ #include "nsIPrincipal.idl"
+ 
++interface nsIDOMDataTransfer;
+ interface nsIDOMDragEvent;
+ 
+ [scriptable, uuid(69E14F91-2E09-4CA6-A511-A715C99A2804)]
+ interface nsIDroppedLinkItem : nsISupports
+ {
+   /**
+    * Returns the URL of the link.
+    */
+@@ -75,13 +76,23 @@ interface nsIDroppedLinkHandler : nsISup
+    *    current document's security context (URI_INHERITS_SECURITY_CONTEXT).
+    */
+   void dropLinks(in nsIDOMDragEvent aEvent,
+                  [optional] in boolean aDisallowInherit,
+                  [optional] out unsigned long aCount,
+                  [retval, array, size_is(aCount)] out nsIDroppedLinkItem aLinks);
+ 
+   /**
++   * Given a dataTransfer, allows caller to determine and verify links being
++   * dragged. Since drag/drop performs a roundtrip of parent, child, parent,
++   * it allows the parent to verify that the child did not modify links
++   * being dropped.
++   */
++  void queryLinks(in nsIDOMDataTransfer aDataTransfer,
++                  [optional] out unsigned long aCount,
++                  [retval, array, size_is(aCount)] out nsIDroppedLinkItem aLinks);
++
++  /**
+    * Given a drop event aEvent, determines the triggering principal for the
+    * event and returns it.
+    */
+   nsIPrincipal getTriggeringPrincipal(in nsIDOMDragEvent aEvent);
+ };
+diff --git a/dom/interfaces/base/nsIBrowser.idl b/dom/interfaces/base/nsIBrowser.idl
+--- a/dom/interfaces/base/nsIBrowser.idl
++++ b/dom/interfaces/base/nsIBrowser.idl
+@@ -1,14 +1,15 @@
+ /* 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/. */
+ #include "nsISupports.idl"
+ 
+ interface nsIFrameLoader;
++interface nsIPrincipal;
+ 
+ [scriptable, uuid(14e5a0cb-e223-4202-95e8-fe53275193ea)]
+ interface nsIBrowser : nsISupports
+ {
+   /**
+    * Gets an optional frame loader that is "related" to this browser.
+    * If this exists, then we should attempt to use the same content parent as
+    * this frame loader for any new tab parents.  For example, view source
+@@ -22,17 +23,18 @@ interface nsIBrowser : nsISupports
+    * content area.
+    *
+    * @param linksCount length of links
+    * @param links a flat array of url, name, and type for each link
+    * @param triggeringPrincipal a principal that initiated loading
+    *                            of the dropped links
+    */
+   void dropLinks(in unsigned long linksCount,
+-                 [array, size_is(linksCount)] in wstring links);
++                 [array, size_is(linksCount)] in wstring links,
++                 in nsIPrincipal aTriggeringPrincipal);
+ 
+   /**
+    * Flags for controlling the behavior of swapBrowsers
+    */
+ 
+   /**
+    * The default options. This is used for swapping browsers between windows
+    */
+diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp
+--- a/dom/ipc/TabParent.cpp
++++ b/dom/ipc/TabParent.cpp
+@@ -11,16 +11,17 @@
+ #ifdef ACCESSIBILITY
+ #include "mozilla/a11y/DocAccessibleParent.h"
+ #include "nsAccessibilityService.h"
+ #endif
+ #include "mozilla/BrowserElementParent.h"
+ #include "mozilla/dom/ContentBridgeParent.h"
+ #include "mozilla/dom/ContentParent.h"
+ #include "mozilla/dom/DataTransfer.h"
++#include "mozilla/dom/DataTransferItemList.h"
+ #include "mozilla/dom/Event.h"
+ #include "mozilla/dom/indexedDB/ActorsParent.h"
+ #include "mozilla/dom/IPCBlobUtils.h"
+ #include "mozilla/dom/PaymentRequestParent.h"
+ #include "mozilla/EventStateManager.h"
+ #include "mozilla/gfx/2D.h"
+ #include "mozilla/gfx/DataSurfaceHelpers.h"
+ #include "mozilla/gfx/GPUProcessManager.h"
+@@ -95,16 +96,17 @@
+ #include "ImageOps.h"
+ #include "UnitTransforms.h"
+ #include <algorithm>
+ #include "mozilla/WebBrowserPersistDocumentParent.h"
+ #include "nsIGroupedSHistory.h"
+ #include "PartialSHistory.h"
+ #include "ProcessPriorityManager.h"
+ #include "nsString.h"
++#include "NullPrincipal.h"
+ 
+ #ifdef XP_WIN
+ #include "mozilla/plugins/PluginWidgetParent.h"
+ #endif
+ 
+ #if defined(XP_WIN) && defined(ACCESSIBILITY)
+ #include "mozilla/a11y/AccessibleWrap.h"
+ #include "mozilla/a11y/nsWinUtils.h"
+@@ -532,22 +534,42 @@ TabParent::RecvSizeShellTo(const uint32_
+   return IPC_OK();
+ }
+ 
+ mozilla::ipc::IPCResult
+ TabParent::RecvDropLinks(nsTArray<nsString>&& aLinks)
+ {
+   nsCOMPtr<nsIBrowser> browser = do_QueryInterface(mFrameElement);
+   if (browser) {
++    // Verify that links have not been modified by the child. If links have
++    // not been modified then it's safe to load those links using the
++    // SystemPrincipal. If they have been modified by web content, then
++    // we use a NullPrincipal which still allows to load web links.
++    bool loadUsingSystemPrincipal = true;
++    if (aLinks.Length() != mVerifyDropLinks.Length()) {
++      loadUsingSystemPrincipal = false;
++    }
+     UniquePtr<const char16_t*[]> links;
+     links = MakeUnique<const char16_t*[]>(aLinks.Length());
+     for (uint32_t i = 0; i < aLinks.Length(); i++) {
++      if (loadUsingSystemPrincipal) {
++        if (!aLinks[i].Equals(mVerifyDropLinks[i])) {
++          loadUsingSystemPrincipal = false;
++        }
++      }
+       links[i] = aLinks[i].get();
+     }
+-    browser->DropLinks(aLinks.Length(), links.get());
++    mVerifyDropLinks.Clear();
++    nsCOMPtr<nsIPrincipal> triggeringPrincipal;
++    if (loadUsingSystemPrincipal) {
++      triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
++    } else {
++      triggeringPrincipal = NullPrincipal::Create();
++    }
++    browser->DropLinks(aLinks.Length(), links.get(), triggeringPrincipal);
+   }
+   return IPC_OK();
+ }
+ 
+ mozilla::ipc::IPCResult
+ TabParent::RecvEvent(const RemoteDOMEvent& aEvent)
+ {
+   nsCOMPtr<nsIDOMEvent> event = do_QueryInterface(aEvent.mEvent);
+@@ -1150,24 +1172,101 @@ TabParent::GetLayoutDeviceToCSSScale()
+   nsIDocument* doc = (content ? content->OwnerDoc() : nullptr);
+   nsIPresShell* shell = (doc ? doc->GetShell() : nullptr);
+   nsPresContext* ctx = (shell ? shell->GetPresContext() : nullptr);
+   return LayoutDeviceToCSSScale(ctx
+     ? (float)ctx->AppUnitsPerDevPixel() / nsPresContext::AppUnitsPerCSSPixel()
+     : 0.0f);
+ }
+ 
++bool
++TabParent::QueryDropLinksForVerification()
++{
++  // Before sending the dragEvent, we query the links being dragged and
++  // store them on the parent, to make sure the child can not modify links.
++  nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
++  if (!dragSession) {
++    NS_WARNING("No dragSession to query links for verification");
++    return false;
++  }
++
++  nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
++  dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
++  if (!initialDataTransfer) {
++    NS_WARNING("No initialDataTransfer to query links for verification");
++    return false;
++  }
++
++  nsCOMPtr<nsIDroppedLinkHandler> dropHandler =
++    do_GetService("@mozilla.org/content/dropped-link-handler;1");
++  if (!dropHandler) {
++    NS_WARNING("No dropHandler to query links for verification");
++    return false;
++  }
++
++  // No more than one drop event can happen simultaneously; reset the link
++  // verification array and store all links that are being dragged.
++  mVerifyDropLinks.Clear();
++
++  uint32_t linksCount = 0;
++  nsIDroppedLinkItem** droppedLinkedItems = nullptr;
++  dropHandler->QueryLinks(initialDataTransfer,
++                          &linksCount, &droppedLinkedItems);
++
++  // Since the entire event is cancelled if one of the links is invalid,
++  // we can store all links on the parent side without any prior
++  // validation checks.
++  nsresult rv = NS_OK;
++  for (uint32_t i = 0; i < linksCount; i++) {
++    nsString tmp;
++    rv = droppedLinkedItems[i]->GetUrl(tmp);
++    if (NS_FAILED(rv)) {
++      NS_WARNING("Failed to query url for verification");
++      break;
++    }
++    mVerifyDropLinks.AppendElement(tmp);
++
++    rv = droppedLinkedItems[i]->GetName(tmp);
++    if (NS_FAILED(rv)) {
++      NS_WARNING("Failed to query name for verification");
++      break;
++    }
++    mVerifyDropLinks.AppendElement(tmp);
++
++    rv = droppedLinkedItems[i]->GetType(tmp);
++    if (NS_FAILED(rv)) {
++      NS_WARNING("Failed to query type for verification");
++      break;
++    }
++    mVerifyDropLinks.AppendElement(tmp);
++  }
++  for (uint32_t i = 0; i < linksCount; i++) {
++    NS_IF_RELEASE(droppedLinkedItems[i]);
++  }
++  free(droppedLinkedItems);
++  if (NS_FAILED(rv)) {
++    mVerifyDropLinks.Clear();
++    return false;
++  }
++  return true;
++}
++
+ void
+ TabParent::SendRealDragEvent(WidgetDragEvent& aEvent, uint32_t aDragAction,
+                              uint32_t aDropEffect)
+ {
+   if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
+     return;
+   }
+   aEvent.mRefPoint += GetChildProcessOffset();
++  if (aEvent.mMessage == eDrop) {
++    if (!QueryDropLinksForVerification()) {
++      return;
++    }
++  }
+   DebugOnly<bool> ret =
+     PBrowserParent::SendRealDragEvent(aEvent, aDragAction, aDropEffect);
+   NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealDragEvent() failed");
+   MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+ }
+ 
+ LayoutDevicePoint
+ TabParent::AdjustTapToChildWidget(const LayoutDevicePoint& aPoint)
+diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h
+--- a/dom/ipc/TabParent.h
++++ b/dom/ipc/TabParent.h
+@@ -729,16 +729,22 @@ private:
+   uint32_t mCustomCursorHotspotX, mCustomCursorHotspotY;
+ 
+   // True if the cursor changes from the TabChild should change the widget
+   // cursor.  This happens whenever the cursor is in the tab's region.
+   bool mTabSetsCursor;
+ 
+   bool mHasContentOpener;
+ 
++  // When dropping links we perform a roundtrip from
++  // Parent (SendRealDragEvent) -> Child -> Parent (RecvDropLinks)
++  // and have to ensure that the child did not modify links to be loaded.
++  bool QueryDropLinksForVerification();
++  nsTArray<nsString> mVerifyDropLinks;
++
+ #ifdef DEBUG
+   int32_t mActiveSupressDisplayportCount;
+ #endif
+ 
+   ShowInfo GetShowInfo();
+ 
+ private:
+   // This is used when APZ needs to find the TabParent associated with a layer
+diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml
+--- a/toolkit/content/widgets/browser.xml
++++ b/toolkit/content/widgets/browser.xml
+@@ -1568,29 +1568,30 @@
+                                     aPrintProgressListener);
+           ]]>
+         </body>
+       </method>
+ 
+       <method name="dropLinks">
+         <parameter name="aLinksCount"/>
+         <parameter name="aLinks"/>
++        <parameter name="aTriggeringPrincipal"/>
+         <body><![CDATA[
+           if (!this.droppedLinkHandler) {
+             return false;
+           }
+           let links = [];
+           for (let i = 0; i < aLinksCount; i += 3) {
+             links.push({
+               url: aLinks[i],
+               name: aLinks[i + 1],
+               type: aLinks[i + 2],
+             });
+           }
+-          this.droppedLinkHandler(null, links);
++          this.droppedLinkHandler(null, links, aTriggeringPrincipal);
+           return true;
+         ]]></body>
+       </method>
+     </implementation>
+ 
+     <handlers>
+       <handler event="keypress" keycode="VK_F7" group="system">
+         <![CDATA[

+ 53 - 0
frg/253-58/mozilla-release58_428122.patch

@@ -0,0 +1,53 @@
+# HG changeset patch
+# User Yoshi Huang <allstars.chh@mozilla.com>
+# Date 1503388368 -28800
+#      Tue Aug 22 15:52:48 2017 +0800
+# Node ID 9667dcce1a8479b4152a67b780020de1f5d7b4d7
+# Parent  a747af7f73a6f881640c2c29196cefa1069060fe
+Bug 1371545 - Remove NS_ERROR_IMAGE_SRC_CHANGED and NS_ERROR_IMAGE_BLOCKED. r=smaug
+
+diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp
+--- a/dom/base/nsImageLoadingContent.cpp
++++ b/dom/base/nsImageLoadingContent.cpp
+@@ -1367,18 +1367,16 @@ nsImageLoadingContent::PrepareNextReques
+ 
+     mMostRecentRequestChange = now;
+   }
+ 
+   // We only want to cancel the existing current request if size is not
+   // available. bz says the web depends on this behavior.
+   // Otherwise, we get rid of any half-baked request that might be sitting there
+   // and make this one current.
+-  // TODO: Bug 583491
+-  // Investigate/Cleanup NS_ERROR_IMAGE_SRC_CHANGED use in nsImageFrame.cpp
+   return HaveSize(mCurrentRequest) ?
+            PreparePendingRequest(aImageLoadType) :
+            PrepareCurrentRequest(aImageLoadType);
+ }
+ 
+ nsresult
+ nsImageLoadingContent::SetBlockedRequest(int16_t aContentDecision)
+ {
+diff --git a/xpcom/base/ErrorList.py b/xpcom/base/ErrorList.py
+--- a/xpcom/base/ErrorList.py
++++ b/xpcom/base/ErrorList.py
+@@ -857,19 +857,16 @@ with modules["URILOADER"]:
+     errors["NS_REFRESHURI_HEADER_FOUND"] = SUCCESS(2)
+ 
+ 
+ 
+ # =======================================================================
+ # 25: NS_ERROR_MODULE_CONTENT
+ # =======================================================================
+ with modules["CONTENT"]:
+-    # Error codes for image loading
+-    errors["NS_ERROR_IMAGE_SRC_CHANGED"] = FAILURE(4)
+-    errors["NS_ERROR_IMAGE_BLOCKED"] = FAILURE(5)
+     # Error codes for content policy blocking
+     errors["NS_ERROR_CONTENT_BLOCKED"] = FAILURE(6)
+     errors["NS_ERROR_CONTENT_BLOCKED_SHOW_ALT"] = FAILURE(7)
+     # Success variations of content policy blocking
+     errors["NS_PROPTABLE_PROP_NOT_THERE"] = FAILURE(10)
+     # Error code for XBL
+     errors["NS_ERROR_XBL_BLOCKED"] = FAILURE(15)
+     # Error code for when the content process crashed

+ 34 - 0
frg/253-58/mozilla-release58_428135.patch

@@ -0,0 +1,34 @@
+# HG changeset patch
+# User Olli Pettay <Olli.Pettay@helsinki.fi>
+# Date 1503413178 -10800
+#      Tue Aug 22 17:46:18 2017 +0300
+# Node ID 64dbabacba57318ce3a7844adf428dbcdfa35ab0
+# Parent  9702cd9a9e41fab3bbd3a9b76eafc7f4cf6e2fe4
+Bug 1392569 - Make nsGenericDOMDataNode to use main thread only CC AddRef/Release, r=mccr8
+
+diff --git a/dom/base/nsGenericDOMDataNode.cpp b/dom/base/nsGenericDOMDataNode.cpp
+--- a/dom/base/nsGenericDOMDataNode.cpp
++++ b/dom/base/nsGenericDOMDataNode.cpp
+@@ -130,19 +130,19 @@ NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataN
+   NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
+   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
+                                  new nsNodeSupportsWeakRefTearoff(this))
+   // DOM bindings depend on the identity pointer being the
+   // same as nsINode (which nsIContent inherits).
+   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
+ NS_INTERFACE_MAP_END
+ 
+-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGenericDOMDataNode)
+-NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsGenericDOMDataNode,
+-                                                   nsNodeUtils::LastRelease(this))
++NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(nsGenericDOMDataNode)
++NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsGenericDOMDataNode,
++                                                                    nsNodeUtils::LastRelease(this))
+ 
+ 
+ void
+ nsGenericDOMDataNode::GetNodeValueInternal(nsAString& aNodeValue)
+ {
+   DebugOnly<nsresult> rv = GetData(aNodeValue);
+   NS_ASSERTION(NS_SUCCEEDED(rv), "GetData() failed!");
+ }

+ 136 - 0
frg/253-58/mozilla-release58_428136.patch

@@ -0,0 +1,136 @@
+# HG changeset patch
+# User Olli Pettay <Olli.Pettay@helsinki.fi>
+# Date 1503413220 -10800
+#      Tue Aug 22 17:47:00 2017 +0300
+# Node ID 5ba4dfac42cb422839bf54ced6929aff080870e7
+# Parent  4cf419a91a200e1ac842dd4cd04b7e00574f4ba4
+Bug 1392564 - Use nursery purple buffer for nsRange and RangeItem, r=mccr8
+
+diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp
+--- a/dom/base/nsRange.cpp
++++ b/dom/base/nsRange.cpp
+@@ -320,19 +320,19 @@ nsRange::CreateRange(nsIDOMNode* aStartC
+   range.forget(aRange);
+   return rv;
+ }
+ 
+ /******************************************************
+  * nsISupports
+  ******************************************************/
+ 
+-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsRange)
+-NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsRange,
+-                                                   DoSetRange(nullptr, 0, nullptr, 0, nullptr))
++NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(nsRange)
++NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsRange,
++                                                                    DoSetRange(nullptr, 0, nullptr, 0, nullptr))
+ 
+ // QueryInterface implementation for nsRange
+ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsRange)
+   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+   NS_INTERFACE_MAP_ENTRY(nsIDOMRange)
+   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
+   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMRange)
+ NS_INTERFACE_MAP_END
+diff --git a/editor/libeditor/SelectionState.h b/editor/libeditor/SelectionState.h
+--- a/editor/libeditor/SelectionState.h
++++ b/editor/libeditor/SelectionState.h
+@@ -32,17 +32,17 @@ struct RangeItem final
+ private:
+   // Private destructor, to discourage deletion outside of Release():
+   ~RangeItem();
+ 
+ public:
+   void StoreRange(nsRange* aRange);
+   already_AddRefed<nsRange> GetRange();
+ 
+-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(RangeItem)
++  NS_INLINE_DECL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_NATIVE_REFCOUNTING(RangeItem)
+   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(RangeItem)
+ 
+   nsCOMPtr<nsINode> mStartContainer;
+   int32_t mStartOffset;
+   nsCOMPtr<nsINode> mEndContainer;
+   int32_t mEndOffset;
+ };
+ 
+diff --git a/xpcom/base/nsISupportsImpl.h b/xpcom/base/nsISupportsImpl.h
+--- a/xpcom/base/nsISupportsImpl.h
++++ b/xpcom/base/nsISupportsImpl.h
+@@ -442,25 +442,46 @@ public:
+     MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                      \
+     NS_ASSERT_OWNINGTHREAD(_class);                                           \
+     nsrefcnt count =                                                          \
+       mRefCnt.incr(static_cast<void*>(this),                                  \
+                    _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
+     NS_LOG_ADDREF(this, count, #_class, sizeof(*this));                       \
+     return count;
+ 
++#define NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_ADDREF_BODY(_class)     \
++    MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class)                     \
++    MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");           \
++    NS_ASSERT_OWNINGTHREAD(_class);                                \
++    nsrefcnt count =                                               \
++      mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>(          \
++        static_cast<void*>(this),                                  \
++        _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
++    NS_LOG_ADDREF(this, count, #_class, sizeof(*this));            \
++    return count;
++
+ #define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class)                                \
+     MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");                          \
+     NS_ASSERT_OWNINGTHREAD(_class);                                           \
+     nsrefcnt count =                                                          \
+       mRefCnt.decr(static_cast<void*>(this),                                  \
+                    _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
+     NS_LOG_RELEASE(this, count, #_class);                                     \
+     return count;
+ 
++#define NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_RELEASE_BODY(_class)    \
++    MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");               \
++    NS_ASSERT_OWNINGTHREAD(_class);                                \
++    nsrefcnt count =                                               \
++      mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>(          \
++        static_cast<void*>(this),                                  \
++        _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
++    NS_LOG_RELEASE(this, count, #_class);                          \
++    return count;
++
+ #define NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(_class)                        \
+ NS_METHOD_(MozExternalRefCountType) _class::AddRef(void)                      \
+ {                                                                             \
+   NS_IMPL_CC_NATIVE_ADDREF_BODY(_class)                                       \
+ }
+ 
+ #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(_class, _last) \
+ NS_METHOD_(MozExternalRefCountType) _class::Release(void)                        \
+@@ -502,16 +523,29 @@ public:                                 
+     NS_IMPL_CC_NATIVE_RELEASE_BODY(_class)                                    \
+   }                                                                           \
+   typedef mozilla::FalseType HasThreadSafeRefCnt;                             \
+ protected:                                                                    \
+   nsCycleCollectingAutoRefCnt mRefCnt;                                        \
+   NS_DECL_OWNINGTHREAD                                                        \
+ public:
+ 
++#define NS_INLINE_DECL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_NATIVE_REFCOUNTING(_class) \
++public:                                                                             \
++  NS_METHOD_(MozExternalRefCountType) AddRef(void) {                                \
++    NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_ADDREF_BODY(_class)                          \
++  }                                                                                 \
++  NS_METHOD_(MozExternalRefCountType) Release(void) {                               \
++    NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_RELEASE_BODY(_class)                         \
++  }                                                                                 \
++  typedef mozilla::FalseType HasThreadSafeRefCnt;                                   \
++protected:                                                                          \
++  nsCycleCollectingAutoRefCnt mRefCnt;                                              \
++  NS_DECL_OWNINGTHREAD                                                              \
++public:
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ /**
+  * Use this macro to declare and implement the AddRef & Release methods for a
+  * given non-XPCOM <i>_class</i>.
+  *
+  * @param _class The name of the class implementing the method

+ 24 - 0
frg/253-58/mozilla-release58_428145.patch

@@ -0,0 +1,24 @@
+# HG changeset patch
+# User Joel Maher <jmaher@mozilla.com>
+# Date 1503425822 14400
+#      Tue Aug 22 14:17:02 2017 -0400
+# Node ID ec5e6cc98d9b8aaac237eb89abd27534f1d758c3
+# Parent  049ef1d4eb2690857f88b03ea7bfeeb130ea2834
+Bug 1379808 - disable browser_test_zoom_text.js. a=testonly
+
+MozReview-Commit-ID: 4ZomQhmh00
+
+diff --git a/accessible/tests/browser/bounds/browser.ini b/accessible/tests/browser/bounds/browser.ini
+--- a/accessible/tests/browser/bounds/browser.ini
++++ b/accessible/tests/browser/bounds/browser.ini
+@@ -4,9 +4,9 @@ support-files =
+   head.js
+   !/accessible/tests/browser/events.js
+   !/accessible/tests/browser/shared-head.js
+   !/accessible/tests/mochitest/*.js
+   !/accessible/tests/mochitest/letters.gif
+ 
+ [browser_test_zoom.js]
+ [browser_test_zoom_text.js]
+-skip-if = os == 'win' # Bug 1372296
++skip-if = true # Bug 1372296, Bug 1379808, Bug 1391453

+ 30 - 0
frg/253-58/mozilla-release58_428146.patch

@@ -0,0 +1,30 @@
+# HG changeset patch
+# User Joel Maher <jmaher@mozilla.com>
+# Date 1503426104 14400
+#      Tue Aug 22 14:21:44 2017 -0400
+# Node ID 7f812a8f576dffab4beb422ea088d31ffd7cfd59
+# Parent  ec5e6cc98d9b8aaac237eb89abd27534f1d758c3
+Bug 1370784 - Disable image/test/mochitest/test_animSVGImage.html on windows. r=me a=testonly
+
+diff --git a/image/test/mochitest/mochitest.ini b/image/test/mochitest/mochitest.ini
+--- a/image/test/mochitest/mochitest.ini
++++ b/image/test/mochitest/mochitest.ini
+@@ -89,17 +89,17 @@ support-files =
+   12M-pixels-2.png
+ 
+ [test_animation.html]
+ skip-if = os == 'android'
+ [test_animation_operators.html]
+ [test_animation2.html]
+ skip-if = os == 'android'
+ [test_animSVGImage.html]
+-skip-if = os == 'android'
++skip-if = os == 'android' || os == 'win' # Bug 1370784
+ [test_animSVGImage2.html]
+ skip-if = os == 'android'
+ [test_background_image_anim.html]
+ skip-if = os == 'android'
+ [test_bug399925.html]
+ [test_bug435296.html]
+ skip-if = true # disabled - See bug 578591
+ [test_bug466586.html]

+ 26 - 0
frg/253-58/mozilla-release58_428147.patch

@@ -0,0 +1,26 @@
+# HG changeset patch
+# User Joel Maher <jmaher@mozilla.com>
+# Date 1503426841 14400
+#      Tue Aug 22 14:34:01 2017 -0400
+# Node ID fde25580274ffd59d3457d24d19c952e129a61d8
+# Parent  7f812a8f576dffab4beb422ea088d31ffd7cfd59
+Bug 1388550 - Disable /webrtc/RTCPeerConnection-addTrack.html on osx-stylo. r=me a=testonly
+
+MozReview-Commit-ID: 2GhNKqUFKK7
+
+diff --git a/testing/web-platform/meta/webrtc/RTCPeerConnection-addTrack.html.ini b/testing/web-platform/meta/webrtc/RTCPeerConnection-addTrack.html.ini
+--- a/testing/web-platform/meta/webrtc/RTCPeerConnection-addTrack.html.ini
++++ b/testing/web-platform/meta/webrtc/RTCPeerConnection-addTrack.html.ini
+@@ -1,10 +1,12 @@
+ [RTCPeerConnection-addTrack.html]
+   type: testharness
++  disabled:
++    if (os == "mac") and stylo: https://bugzilla.mozilla.org/show_bug.cgi?id=1388550
+   expected:
+     if not debug and not stylo and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): OK
+     if debug and not stylo and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): OK
+     TIMEOUT
+   [addTrack when pc is closed should throw InvalidStateError]
+     expected:
+       if not debug and not stylo and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL
+       if debug and not stylo and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL

+ 25 - 0
frg/253-58/mozilla-release58_428148.patch

@@ -0,0 +1,25 @@
+# HG changeset patch
+# User Joel Maher <jmaher@mozilla.com>
+# Date 1503426880 14400
+#      Tue Aug 22 14:34:40 2017 -0400
+# Node ID 426b9dd6bd3b71873d79ebe9127960b4df067301
+# Parent  fde25580274ffd59d3457d24d19c952e129a61d8
+Bug 1387923 - disable hr-time/timeOrigin.html on windows7. r=me a=testonly
+
+diff --git a/testing/web-platform/meta/hr-time/timeOrigin.html.ini b/testing/web-platform/meta/hr-time/timeOrigin.html.ini
+--- a/testing/web-platform/meta/hr-time/timeOrigin.html.ini
++++ b/testing/web-platform/meta/hr-time/timeOrigin.html.ini
+@@ -1,12 +1,13 @@
+ [timeOrigin.html]
+   type: testharness
+   disabled:
+     if (os == "linux") and (bits == 32): https://bugzilla.mozilla.org/show_bug.cgi?id=1387923
++    if (os == "win") and (version == "6.1.7601"): https://bugzilla.mozilla.org/show_bug.cgi?id=1387923
+   [Window timeOrigin is close to Date.now() when there is no system clock adjustment.]
+     expected:
+       if debug and not stylo and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
+       if debug and stylo and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL
+       if debug and not stylo and not e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL
+ 
+   [Window and worker timeOrigins are close when created one after another.]
+     expected:

+ 29 - 0
frg/253-58/mozilla-release58_428149.patch

@@ -0,0 +1,29 @@
+# HG changeset patch
+# User Joel Maher <jmaher@mozilla.com>
+# Date 1503427057 14400
+#      Tue Aug 22 14:37:37 2017 -0400
+# Node ID 4aac8fc2bd62c147aa36861b29e454245d1b3252
+# Parent  426b9dd6bd3b71873d79ebe9127960b4df067301
+Bug 1383576 - disable devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-reloading.js. r=me a=testonly
+
+diff --git a/devtools/client/debugger/new/test/mochitest/browser.ini b/devtools/client/debugger/new/test/mochitest/browser.ini
+--- a/devtools/client/debugger/new/test/mochitest/browser.ini
++++ b/devtools/client/debugger/new/test/mochitest/browser.ini
+@@ -41,16 +41,17 @@ support-files =
+   examples/script-switching-02.js
+   examples/script-switching-01.js
+   examples/times2.js
+ 
+ [browser_dbg-breaking.js]
+ [browser_dbg-breaking-from-console.js]
+ [browser_dbg-breakpoints.js]
+ [browser_dbg-breakpoints-reloading.js]
++skip-if = true # Bug 1383576
+ [browser_dbg-breakpoints-cond.js]
+ [browser_dbg-call-stack.js]
+ [browser_dbg-expressions.js]
+ [browser_dbg-scopes.js]
+ [browser_dbg-chrome-create.js]
+ [browser_dbg-chrome-debugging.js]
+ skip-if = debug # bug 1374187
+ [browser_dbg-console.js]

+ 29 - 0
frg/253-58/mozilla-release58_428150.patch

@@ -0,0 +1,29 @@
+# HG changeset patch
+# User Joel Maher <jmaher@mozilla.com>
+# Date 1503427184 14400
+#      Tue Aug 22 14:39:44 2017 -0400
+# Node ID f28adccedcd27a839c1e859d903b5c72233bb0e8
+# Parent  4aac8fc2bd62c147aa36861b29e454245d1b3252
+Bug 1258897 - disable test_ext_sendmessage_reply2.html. r=me a=testonly
+
+diff --git a/toolkit/components/extensions/test/mochitest/mochitest-common.ini b/toolkit/components/extensions/test/mochitest/mochitest-common.ini
+--- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini
++++ b/toolkit/components/extensions/test/mochitest/mochitest-common.ini
+@@ -92,16 +92,17 @@ skip-if = os == 'android' && debug # Bug
+ [test_ext_runtime_disconnect.html]
+ [test_ext_runtime_id.html]
+ [test_ext_sandbox_var.html]
+ [test_ext_sendmessage_doublereply.html]
+ [test_ext_sendmessage_frameId.html]
+ [test_ext_sendmessage_no_receiver.html]
+ [test_ext_sendmessage_reply.html]
+ [test_ext_sendmessage_reply2.html]
++skip-if = true # Bug 1258897
+ [test_ext_storage_content.html]
+ [test_ext_storage_tab.html]
+ [test_ext_storage_manager_capabilities.html]
+ scheme=https
+ [test_ext_test.html]
+ [test_ext_cookies.html]
+ [test_ext_background_api_injection.html]
+ [test_ext_background_generated_url.html]

+ 58 - 0
frg/253-58/mozilla-release58_428154.patch

@@ -0,0 +1,58 @@
+# HG changeset patch
+# User Joel Maher <jmaher@mozilla.com>
+# Date 1503431139 14400
+#      Tue Aug 22 15:45:39 2017 -0400
+# Node ID bdc0a51d961fec932a10f5692fe8047f7d763e29
+# Parent  f139e3a8bb1592bc49806745633cb07aaae1fc8f
+Bug 1386393 - remove old docshell/test/unit/test_bug414201_jfif.js. rs=paolo
+
+MozReview-Commit-ID: A5Ip1e8Fw2r
+
+diff --git a/docshell/test/unit/test_bug414201_jfif.js b/docshell/test/unit/test_bug414201_jfif.js
+deleted file mode 100644
+--- a/docshell/test/unit/test_bug414201_jfif.js
++++ /dev/null
+@@ -1,27 +0,0 @@
+-/* 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/. */
+-
+-/*
+- * Test for bug 414201
+- */
+-
+-function run_test()
+-{
+-    var ms = Components.classes["@mozilla.org/mime;1"].getService(Components.interfaces.nsIMIMEService);
+-
+-    /* Test a few common image types to make sure that they get the right extension */
+-    var types = {
+-        "image/jpeg": ["jpg", "jpeg"], /* accept either */
+-        "image/gif": ["gif"],
+-        "image/png": ["png"]
+-    };
+-
+-    /* Check whether the primary extension is what we'd expect */
+-    for (var mimetype in types) {
+-        var exts = types[mimetype];
+-        var primary = ms.getFromTypeAndExtension(mimetype, null).primaryExtension.toLowerCase();
+-
+-        do_check_true (exts.indexOf(primary) != -1);
+-    }
+-}
+diff --git a/docshell/test/unit/xpcshell.ini b/docshell/test/unit/xpcshell.ini
+--- a/docshell/test/unit/xpcshell.ini
++++ b/docshell/test/unit/xpcshell.ini
+@@ -1,12 +1,11 @@
+ [DEFAULT]
+ head = head_docshell.js
+ 
+-[test_bug414201_jfif.js]
+ [test_bug442584.js]
+ [test_nsDefaultURIFixup.js]
+ [test_nsDefaultURIFixup_search.js]
+ skip-if = os == 'android'
+ [test_nsDefaultURIFixup_info.js]
+ skip-if = os == 'android'
+ [test_nsIDownloadHistory.js]
+ [test_pb_notification.js]

+ 39 - 0
frg/253-58/mozilla-release58_428155.patch

@@ -0,0 +1,39 @@
+# HG changeset patch
+# User Nathan Froyd <froydnj@mozilla.com>
+# Date 1503432498 14400
+#      Tue Aug 22 16:08:18 2017 -0400
+# Node ID 6e60169d34d337fe3be5c306cfd0246a02d24f5a
+# Parent  bdc0a51d961fec932a10f5692fe8047f7d763e29
+Bug 1349821 - reduce iterations for 32-bit Windows to OOM in TestTArray.test_fallible; r=erahm
+
+diff --git a/xpcom/tests/gtest/TestTArray2.cpp b/xpcom/tests/gtest/TestTArray2.cpp
+--- a/xpcom/tests/gtest/TestTArray2.cpp
++++ b/xpcom/tests/gtest/TestTArray2.cpp
+@@ -897,17 +897,26 @@ TEST(TArray, test_fallible)
+     // avoid allocating more than 128MB overall because of the size padding it
+     // will cause, which depends on allocator behavior, so use 128MB - an
+     // arbitrary size larger than the array header, so that chances are good
+     // that allocations will always be 128MB.
+     bool success = arrays[i].SetCapacity(128 * 1024 * 1024 - 1024, fallible);
+     if (!success) {
+       // We got our OOM.  Check that it didn't come too early.
+       oomed = true;
+-      ASSERT_GE(i, size_t(8)) << "Got OOM on iteration " << i << ". Too early!";
++#ifdef XP_WIN
++      // 32-bit Windows sometimes OOMs on the 7th, sometimes on the 8th.  To
++      // keep the test green, choose the lower of those: the important thing
++      // here is that some allocations fail and some succeed.  We're not too
++      // concerned about how many iterations it takes.
++      const size_t kOOMIterations = 7;
++#else
++      const size_t kOOMIterations = 8;
++#endif
++      ASSERT_GE(i, kOOMIterations) << "Got OOM on iteration " << i << ". Too early!";
+     }
+   }
+ 
+   ASSERT_TRUE(oomed) << "Didn't OOM or crash?  nsTArray::SetCapacity"
+                         "must be lying.";
+ }
+ #endif
+ 

+ 43 - 0
frg/253-58/mozilla-release58_428156.patch

@@ -0,0 +1,43 @@
+# HG changeset patch
+# User Valentin Gosu <valentin.gosu@gmail.com>
+# Date 1503433899 -7200
+#      Tue Aug 22 22:31:39 2017 +0200
+# Node ID cae85787a705b8f5b839796b594169b63eff8157
+# Parent  6e60169d34d337fe3be5c306cfd0246a02d24f5a
+Bug 1392260 - Fix error in gzip_xml.py r=jgraham
+
+Reviewed by jgraham in bug 919391 comment 9
+
+MozReview-Commit-ID: 8db0q7QCJRT
+
+diff --git a/testing/web-platform/meta/resource-timing/test_resource_timing.html.ini b/testing/web-platform/meta/resource-timing/test_resource_timing.html.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/resource-timing/test_resource_timing.html.ini
++++ /dev/null
+@@ -1,5 +0,0 @@
+-[test_resource_timing.html]
+-  type: testharness
+-  [PerformanceEntry has correct network transfer attributes (xmlhttprequest)]
+-    expected: FAIL
+-
+diff --git a/testing/web-platform/tests/resource-timing/resources/gzip_xml.py b/testing/web-platform/tests/resource-timing/resources/gzip_xml.py
+--- a/testing/web-platform/tests/resource-timing/resources/gzip_xml.py
++++ b/testing/web-platform/tests/resource-timing/resources/gzip_xml.py
+@@ -1,13 +1,16 @@
+ import gzip as gzip_module
+ from cStringIO import StringIO
++import os
+ 
+ def main(request, response):
+-    f = open('resource-timing/resources/resource_timing_test0.xml', 'r')
++    dir_path = os.path.dirname(os.path.realpath(__file__))
++    file_path = os.path.join(dir_path, 'resource_timing_test0.xml')
++    f = open(file_path, 'r')
+     output = f.read()
+ 
+     out = StringIO()
+     with gzip_module.GzipFile(fileobj=out, mode="w") as f:
+       f.write(output)
+     output = out.getvalue()
+ 
+     headers = [("Content-type", "text/plain"),

+ 89 - 0
frg/253-58/mozilla-release58_428157.patch

@@ -0,0 +1,89 @@
+# HG changeset patch
+# User Valentin Gosu <valentin.gosu@gmail.com>
+# Date 1503433983 -7200
+#      Tue Aug 22 22:33:03 2017 +0200
+# Node ID df6171c99f7dfe1617c64355ea00e3a3f9710b39
+# Parent  cae85787a705b8f5b839796b594169b63eff8157
+Bug 1306646 - Match updated Timing-Allow-Origin definition for resource timing r=nwgh
+MozReview-Commit-ID: GQDhISc9WRD
+
+diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
+--- a/netwerk/protocol/http/HttpBaseChannel.cpp
++++ b/netwerk/protocol/http/HttpBaseChannel.cpp
+@@ -3734,27 +3734,38 @@ HttpBaseChannel::TimingAllowCheck(nsIPri
+ 
+   nsAutoCString headerValue;
+   rv = GetResponseHeader(NS_LITERAL_CSTRING("Timing-Allow-Origin"), headerValue);
+   if (NS_FAILED(rv)) {
+     *_retval = false;
+     return NS_OK;
+   }
+ 
+-  if (headerValue == "*") {
+-    *_retval = true;
+-    return NS_OK;
+-  }
+-
+   nsAutoCString origin;
+   nsContentUtils::GetASCIIOrigin(aOrigin, origin);
+ 
+-  if (headerValue == origin) {
+-    *_retval = true;
+-    return NS_OK;
++  Tokenizer p(headerValue);
++  Tokenizer::Token t;
++
++  p.Record();
++  nsAutoCString headerItem;
++  while (p.Next(t)) {
++    if (t.Type() == Tokenizer::TOKEN_EOF ||
++        t.Equals(Tokenizer::Token::Char(','))) {
++      p.Claim(headerItem);
++      headerItem.StripWhitespace();
++      // If the list item contains a case-sensitive match for the value of the
++      // origin, or a wildcard, return pass
++      if (headerItem == origin || headerItem == "*") {
++        *_retval = true;
++        return NS_OK;
++      }
++      // We start recording again for the following items in the list
++      p.Record();
++    }
+   }
+ 
+   *_retval = false;
+   return NS_OK;
+ }
+ 
+ NS_IMETHODIMP
+ HttpBaseChannel::GetLaunchServiceWorkerStart(TimeStamp* _retval) {
+diff --git a/testing/web-platform/meta/resource-timing/resource_TAO_match_origin.htm.ini b/testing/web-platform/meta/resource-timing/resource_TAO_match_origin.htm.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/resource-timing/resource_TAO_match_origin.htm.ini
++++ /dev/null
+@@ -1,5 +0,0 @@
+-[resource_TAO_match_origin.htm]
+-  type: testharness
+-  [redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, and responseStart -- should NOT be all returned as 0 when the Timing-Allow-Origin header value list contains a case-sensitive match for the value of the origin of the current document and TAO algorithm passes]
+-    expected: FAIL
+-
+diff --git a/testing/web-platform/meta/resource-timing/resource_TAO_match_wildcard.htm.ini b/testing/web-platform/meta/resource-timing/resource_TAO_match_wildcard.htm.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/resource-timing/resource_TAO_match_wildcard.htm.ini
++++ /dev/null
+@@ -1,5 +0,0 @@
+-[resource_TAO_match_wildcard.htm]
+-  type: testharness
+-  [redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, and responseStart -- should NOT be all returned as 0 when the Timing-Allow-Origin header value list contains a wildcard ("*") and TAO algorithm passes]
+-    expected: FAIL
+-
+diff --git a/testing/web-platform/meta/resource-timing/resource_TAO_multi.htm.ini b/testing/web-platform/meta/resource-timing/resource_TAO_multi.htm.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/resource-timing/resource_TAO_multi.htm.ini
++++ /dev/null
+@@ -1,5 +0,0 @@
+-[resource_TAO_multi.htm]
+-  type: testharness
+-  [redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, and responseStart -- should not be all returned as 0 when the HTTP response has multiple Timing-Allow-Origin header fields and the subsequent field value is separated by a comma, i.e. TAO algorithm passes]
+-    expected: FAIL
+-

+ 92 - 0
frg/253-58/mozilla-release58_428159.patch

@@ -0,0 +1,92 @@
+# HG changeset patch
+# User Jessica Jong <jjong@mozilla.com>
+# Date 1503016380 14400
+#      Thu Aug 17 20:33:00 2017 -0400
+# Node ID fecc3b17395a7265fc7ecfe638590b6211de6335
+# Parent  9e64af6b5158774cf588a4b194e3efc58c3fb5c9
+Bug 1371111 - Open picker when input element's padding area is clicked. r=mconley
+
+Currently, we listen to click events on the xbl binding; but actually we should
+listen to click events on the input element itself, so that we get called when
+the padding area is clicked.
+
+MozReview-Commit-ID: 8NQKrxSXUyL
+
+diff --git a/toolkit/content/widgets/datetimebox.xml b/toolkit/content/widgets/datetimebox.xml
+--- a/toolkit/content/widgets/datetimebox.xml
++++ b/toolkit/content/widgets/datetimebox.xml
+@@ -1230,16 +1230,20 @@
+         this.EVENTS.forEach((eventName) => {
+           this.addEventListener(eventName, this, { mozSystemGroup: true });
+         });
+         // Handle keypress separately since we need to catch it on capturing.
+         this.addEventListener("keypress", this, {
+           capture: true,
+           mozSystemGroup: true
+         });
++        // This is to open the picker when input element is clicked (this
++        // includes padding area).
++        this.mInputElement.addEventListener("click", this,
++                                            { mozSystemGroup: true });
+         // This is to close the picker when input element blurs.
+         this.mInputElement.addEventListener("blur", this,
+                                             { mozSystemGroup: true });
+       ]]>
+       </constructor>
+ 
+       <destructor>
+       <![CDATA[
+@@ -1247,23 +1251,27 @@
+ 
+         this.EVENTS.forEach((eventName) => {
+           this.removeEventListener(eventName, this, { mozSystemGroup: true });
+         });
+         this.removeEventListener("keypress", this, {
+           capture: true,
+           mozSystemGroup: true
+         });
++        this.mInputElement.removeEventListener("click", this,
++                                               { mozSystemGroup: true });
++        this.mInputElement.removeEventListener("blur", this,
++                                               { mozSystemGroup: true });
+       ]]>
+       </destructor>
+ 
+       <property name="EVENTS" readonly="true">
+         <getter>
+         <![CDATA[
+-          return ["click", "focus", "blur", "copy", "cut", "paste", "mousedown"];
++          return ["focus", "blur", "copy", "cut", "paste", "mousedown"];
+         ]]>
+         </getter>
+       </property>
+ 
+       <method name="log">
+         <parameter name="aMsg"/>
+         <body>
+         <![CDATA[
+@@ -1794,22 +1802,19 @@
+         ]]>
+         </body>
+       </method>
+ 
+       <method name="onClick">
+         <parameter name="aEvent"/>
+         <body>
+         <![CDATA[
+-          this.log("onClick originalTarget: " + aEvent.originalTarget);
++          this.log("onClick originalTarget: " + aEvent.originalTarget +
++                   " target: " + aEvent.target);
+ 
+-          // XXX: .originalTarget is not expected.
+-          // When clicking on one of the inner text boxes, the .originalTarget is
+-          // a HTMLDivElement and when clicking on the reset button, it's a
+-          // HTMLButtonElement.
+           if (aEvent.defaultPrevented || this.isDisabled() || this.isReadonly()) {
+             return;
+           }
+ 
+           if (aEvent.originalTarget == this.mResetButton) {
+             this.clearInputFields(false);
+           } else if (!this.mIsPickerOpen) {
+             this.mInputElement.openDateTimePicker(this.getCurrentValue());

+ 154 - 0
frg/253-58/mozilla-release58_428160.patch

@@ -0,0 +1,154 @@
+# HG changeset patch
+# User Amy Chung <amchung@mozilla.com>
+# Date 1503388080 14400
+#      Tue Aug 22 03:48:00 2017 -0400
+# Node ID 2d214c46769ab1f28f251a621164c10d647df8e8
+# Parent  fecc3b17395a7265fc7ecfe638590b6211de6335
+Bug 1376009 - Add mIPCOpen flag and check it before sending IPC messages to the parent. r=jdm
+
+diff --git a/netwerk/cookie/CookieServiceChild.cpp b/netwerk/cookie/CookieServiceChild.cpp
+--- a/netwerk/cookie/CookieServiceChild.cpp
++++ b/netwerk/cookie/CookieServiceChild.cpp
+@@ -51,18 +51,19 @@ CookieServiceChild::GetSingleton()
+ NS_IMPL_ISUPPORTS(CookieServiceChild,
+                   nsICookieService,
+                   nsIObserver,
+                   nsISupportsWeakReference)
+ 
+ CookieServiceChild::CookieServiceChild()
+   : mCookieBehavior(nsICookieService::BEHAVIOR_ACCEPT)
+   , mThirdPartySession(false)
++  , mLeaveSecureAlone(true)
+   , mIPCSync(false)
+-  , mLeaveSecureAlone(true)
++  , mIPCOpen(false)
+ {
+   NS_ASSERTION(IsNeckoChild(), "not a child process");
+ 
+   mozilla::dom::ContentChild* cc =
+     static_cast<mozilla::dom::ContentChild*>(gNeckoChild->Manager());
+   if (cc->IsShuttingDown()) {
+     return;
+   }
+@@ -74,16 +75,18 @@ CookieServiceChild::CookieServiceChild()
+ 
+   gNeckoChild->SetEventTargetForActor(
+     this,
+     SystemGroup::EventTargetFor(TaskCategory::Other));
+ 
+   // Create a child PCookieService actor.
+   gNeckoChild->SendPCookieServiceConstructor(this);
+ 
++  mIPCOpen = true;
++
+   mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
+   NS_ASSERTION(mTLDService, "couldn't get TLDService");
+ 
+   // Init our prefs and observer.
+   nsCOMPtr<nsIPrefBranch> prefBranch =
+     do_GetService(NS_PREFSERVICE_CONTRACTID);
+   NS_WARNING_ASSERTION(prefBranch, "no prefservice");
+   if (prefBranch) {
+@@ -96,18 +99,28 @@ CookieServiceChild::CookieServiceChild()
+ }
+ 
+ CookieServiceChild::~CookieServiceChild()
+ {
+   gCookieService = nullptr;
+ }
+ 
+ void
++CookieServiceChild::ActorDestroy(ActorDestroyReason why)
++{
++  mIPCOpen = false;
++}
++
++void
+ CookieServiceChild::TrackCookieLoad(nsIChannel *aChannel)
+ {
++  if (!mIPCOpen) {
++    return;
++  }
++
+   bool isForeign = false;
+   nsCOMPtr<nsIURI> uri;
+   aChannel->GetURI(getter_AddRefs(uri));
+   if (RequireThirdPartyCheck()) {
+     mThirdPartyUtil->IsThirdPartyChannel(aChannel, uri, &isForeign);
+   }
+   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+   mozilla::OriginAttributes attrs;
+@@ -436,16 +449,19 @@ CookieServiceChild::GetCookieStringInter
+   // Asynchronously call the parent.
+   bool isForeign = true;
+   if (RequireThirdPartyCheck())
+     mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
+   nsAutoCString result;
+   if (!mIPCSync) {
+     GetCookieStringFromCookieHashTable(aHostURI, !!isForeign, attrs, result);
+   } else {
++    if (!mIPCOpen) {
++      return NS_ERROR_NOT_AVAILABLE;
++    }
+     GetCookieStringSyncIPC(aHostURI, !!isForeign, attrs, result);
+   }
+ 
+   if (!result.IsEmpty())
+     *aCookieString = ToNewCString(result);
+ 
+   return NS_OK;
+ }
+@@ -484,18 +500,21 @@ CookieServiceChild::SetCookieStringInter
+   if (aChannel) {
+     nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+     if (loadInfo) {
+       attrs = loadInfo->GetOriginAttributes();
+     }
+   }
+ 
+   // Asynchronously call the parent.
+-  SendSetCookieString(uriParams, !!isForeign, cookieString,
+-                      stringServerTime, attrs, aFromHttp);
++  if (mIPCOpen) {
++    SendSetCookieString(uriParams, !!isForeign, cookieString,
++                        stringServerTime, attrs, aFromHttp);
++  }
++
+   if (mIPCSync) {
+     return NS_OK;
+   }
+ 
+   bool requireHostMatch;
+   nsCString baseDomain;
+   nsCookieService::
+     GetBaseDomain(mTLDService, aHostURI, baseDomain, requireHostMatch);
+diff --git a/netwerk/cookie/CookieServiceChild.h b/netwerk/cookie/CookieServiceChild.h
+--- a/netwerk/cookie/CookieServiceChild.h
++++ b/netwerk/cookie/CookieServiceChild.h
+@@ -109,22 +109,25 @@ protected:
+   virtual
+   mozilla::ipc::IPCResult RecvRemoveCookie(const CookieStruct &aCookie,
+                                            const OriginAttributes &aAttrs) override;
+ 
+   virtual
+   mozilla::ipc::IPCResult RecvAddCookie(const CookieStruct &aCookie,
+                                         const OriginAttributes &aAttrs) override;
+ 
++  virtual void ActorDestroy(ActorDestroyReason aWhy) override;
++
+   CookiesMap mCookiesMap;
+   nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil;
+   nsCOMPtr<nsIEffectiveTLDService> mTLDService;
+   uint8_t mCookieBehavior;
+   bool mThirdPartySession;
++  bool mLeaveSecureAlone;
+   bool mIPCSync;
+-  bool mLeaveSecureAlone;
++  bool mIPCOpen;
+ };
+ 
+ } // namespace net
+ } // namespace mozilla
+ 
+ #endif // mozilla_net_CookieServiceChild_h__
+ 

+ 40 - 0
frg/253-58/mozilla-release58_428161.patch

@@ -0,0 +1,40 @@
+# HG changeset patch
+# User Ekanan Ketunuti <ananuti@gmail.com>
+# Date 1503057939 -25200
+#      Fri Aug 18 19:05:39 2017 +0700
+# Node ID 3c3ec9970a727197dbfd717b6dceefb25d4efaaf
+# Parent  2d214c46769ab1f28f251a621164c10d647df8e8
+Bug 1391596 - Add cockatiel to the en-US dictionary. r=ehsan
+
+diff --git a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
++++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+@@ -1,9 +1,9 @@
+-52361
++52362
+ 0/nm
+ 0th/pt
+ 1/n1
+ 1st/p
+ 1th/tc
+ 2/nm
+ 2nd/p
+ 2th/tc
+@@ -19765,16 +19765,17 @@ coccyges
+ coccyx/M
+ cochineal/M
+ cochlea/SM
+ cochleae
+ cochlear
+ cock/MDGS
+ cockade/SM
+ cockamamie
++cockatiel/SM
+ cockatoo/SM
+ cockatrice/SM
+ cockchafer/S
+ cockcrow/SM
+ cockerel/SM
+ cockeyed
+ cockfight/MGS
+ cockfighting/M

+ 662 - 0
frg/253-58/mozilla-release58_428162.patch

@@ -0,0 +1,662 @@
+# HG changeset patch
+# User Honza Bambas <honzab.moz@firemni.cz>
+# Date 1502986560 14400
+#      Thu Aug 17 12:16:00 2017 -0400
+# Node ID 464568af8eb17b3eaeb143f4a7f9e233800e2612
+# Parent  3c3ec9970a727197dbfd717b6dceefb25d4efaaf
+Bug 1388448 - Logs for better network requests and context tracking. r=mcmanus
+
+diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
+--- a/dom/base/nsDocument.cpp
++++ b/dom/base/nsDocument.cpp
+@@ -3919,16 +3919,19 @@ nsDocument::CreateShell(nsPresContext* a
+   // Note: we don't hold a ref to the shell (it holds a ref to us)
+   mPresShell = shell;
+ 
+   // Make sure to never paint if we belong to an invisible DocShell.
+   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
+   if (docShell && docShell->IsInvisible())
+     shell->SetNeverPainting(true);
+ 
++  MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p with PressShell %p and DocShell %p",
++                                                this, shell.get(), docShell.get()));
++
+   mExternalResourceMap.ShowViewers();
+ 
+   UpdateFrameRequestCallbackSchedulingState();
+ 
+   // Now that we have a shell, we might have @font-face rules.
+   RebuildUserFontSet();
+ 
+   return shell.forget();
+@@ -5455,16 +5458,19 @@ nsDocument::EndLoad()
+ 
+ void
+ nsDocument::UnblockDOMContentLoaded()
+ {
+   MOZ_ASSERT(mBlockDOMContentLoaded);
+   if (--mBlockDOMContentLoaded != 0 || mDidFireDOMContentLoaded) {
+     return;
+   }
++
++  MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p UnblockDOMContentLoaded", this));
++
+   mDidFireDOMContentLoaded = true;
+ 
+   MOZ_ASSERT(mReadyState == READYSTATE_INTERACTIVE);
+   if (!mSynchronousDOMContentLoaded) {
+     MOZ_RELEASE_ASSERT(NS_IsMainThread());
+     nsCOMPtr<nsIRunnable> ev =
+       NewRunnableMethod("nsDocument::DispatchContentLoadedEvents",
+                         this,
+diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp
+--- a/layout/base/PresShell.cpp
++++ b/layout/base/PresShell.cpp
+@@ -832,16 +832,18 @@ PresShell::PresShell()
+   , mInResize(false)
+   , mApproximateFrameVisibilityVisited(false)
+   , mNextPaintCompressed(false)
+   , mHasCSSBackgroundColor(false)
+   , mScaleToResolution(false)
+   , mIsLastChromeOnlyEscapeKeyConsumed(false)
+   , mHasReceivedPaintMessage(false)
+ {
++  MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::PresShell this=%p", this));
++
+ #ifdef MOZ_REFLOW_PERF
+   mReflowCountMgr = new ReflowCountMgr();
+   mReflowCountMgr->SetPresContext(mPresContext);
+   mReflowCountMgr->SetPresShell(this);
+ #endif
+   mLastOSWake = mLoadBegin = TimeStamp::Now();
+ 
+   mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES;
+@@ -881,16 +883,18 @@ PresShell::PresShell()
+ 
+ NS_IMPL_ISUPPORTS(PresShell, nsIPresShell, nsIDocumentObserver,
+                   nsISelectionController,
+                   nsISelectionDisplay, nsIObserver, nsISupportsWeakReference,
+                   nsIMutationObserver)
+ 
+ PresShell::~PresShell()
+ {
++  MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::~PresShell this=%p", this));
++
+   if (!mHaveShutDown) {
+     NS_NOTREACHED("Someone did not call nsIPresShell::destroy");
+     Destroy();
+   }
+ 
+   NS_ASSERTION(mCurrentEventContentStack.Count() == 0,
+                "Huh, event content left on the stack in pres shell dtor!");
+   NS_ASSERTION(mFirstCallbackEventRequest == nullptr &&
+@@ -1721,16 +1725,18 @@ PresShell::Initialize(nscoord aWidth, ns
+     return NS_OK;
+   }
+ 
+   if (!mDocument) {
+     // Nothing to do
+     return NS_OK;
+   }
+ 
++  MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::Initialize this=%p", this));
++
+   NS_ASSERTION(!mDidInitialize, "Why are we being called?");
+ 
+   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
+   mDidInitialize = true;
+ 
+ #ifdef DEBUG
+   if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) {
+     if (mDocument) {
+@@ -3875,16 +3881,19 @@ PresShell::CaptureHistoryState(nsILayout
+ 
+ void
+ PresShell::ScheduleBeforeFirstPaint()
+ {
+   if (!mDocument->IsResourceDoc()) {
+     // Notify observers that a new page is about to be drawn. Execute this
+     // as soon as it is safe to run JS, which is guaranteed to be before we
+     // go back to the event loop and actually draw the page.
++    MOZ_LOG(gLog, LogLevel::Debug,
++           ("PresShell::ScheduleBeforeFirstPaint this=%p", this));
++
+     nsContentUtils::AddScriptRunner(new nsBeforeFirstPaintDispatcher(mDocument));
+   }
+ }
+ 
+ void
+ PresShell::UnsuppressAndInvalidate()
+ {
+   // Note: We ignore the EnsureVisible check for resource documents, because
+diff --git a/netwerk/base/nsChannelClassifier.cpp b/netwerk/base/nsChannelClassifier.cpp
+--- a/netwerk/base/nsChannelClassifier.cpp
++++ b/netwerk/base/nsChannelClassifier.cpp
+@@ -229,19 +229,25 @@ NS_IMPL_ISUPPORTS(nsChannelClassifier,
+ 
+ nsChannelClassifier::nsChannelClassifier(nsIChannel *aChannel)
+   : mIsAllowListed(false),
+     mSuspendedChannel(false),
+     mChannel(aChannel),
+     mTrackingProtectionEnabled(Nothing()),
+     mTrackingAnnotationEnabled(Nothing())
+ {
++  LOG(("nsChannelClassifier::nsChannelClassifier %p", this));
+   MOZ_ASSERT(mChannel);
+ }
+ 
++nsChannelClassifier::~nsChannelClassifier()
++{
++  LOG(("nsChannelClassifier::~nsChannelClassifier %p", this));
++}
++
+ bool
+ nsChannelClassifier::ShouldEnableTrackingProtection()
+ {
+   if (mTrackingProtectionEnabled) {
+     return mTrackingProtectionEnabled.value();
+   }
+ 
+   mTrackingProtectionEnabled = Some(false);
+diff --git a/netwerk/base/nsChannelClassifier.h b/netwerk/base/nsChannelClassifier.h
+--- a/netwerk/base/nsChannelClassifier.h
++++ b/netwerk/base/nsChannelClassifier.h
+@@ -61,17 +61,17 @@ private:
+     // True if the channel is on the allow list.
+     bool mIsAllowListed;
+     // True if the channel has been suspended.
+     bool mSuspendedChannel;
+     nsCOMPtr<nsIChannel> mChannel;
+     Maybe<bool> mTrackingProtectionEnabled;
+     Maybe<bool> mTrackingAnnotationEnabled;
+ 
+-    ~nsChannelClassifier() {}
++    ~nsChannelClassifier();
+     // Caches good classifications for the channel principal.
+     void MarkEntryClassified(nsresult status);
+     bool HasBeenClassified(nsIChannel *aChannel);
+     // Helper function so that we ensure we call ContinueBeginConnect once
+     // Start is called. Returns NS_OK if and only if we will get a callback
+     // from the classifier service.
+     nsresult StartInternal();
+     // Helper function to check a URI against the hostname whitelist
+diff --git a/netwerk/base/nsLoadGroup.cpp b/netwerk/base/nsLoadGroup.cpp
+--- a/netwerk/base/nsLoadGroup.cpp
++++ b/netwerk/base/nsLoadGroup.cpp
+@@ -413,16 +413,19 @@ nsLoadGroup::GetDefaultLoadRequest(nsIRe
+     *aRequest = mDefaultLoadRequest;
+     NS_IF_ADDREF(*aRequest);
+     return NS_OK;
+ }
+ 
+ NS_IMETHODIMP
+ nsLoadGroup::SetDefaultLoadRequest(nsIRequest *aRequest)
+ {
++    LOG(("nsLoadGroup::SetDefaultLoadRequest this=%p default-request=%p",
++         this, aRequest));
++
+     mDefaultLoadRequest = aRequest;
+     // Inherit the group load flags from the default load request
+     if (mDefaultLoadRequest) {
+         mDefaultLoadRequest->GetLoadFlags(&mLoadFlags);
+         //
+         // Mask off any bits that are not part of the nsIRequest flags.
+         // in particular, nsIChannel::LOAD_DOCUMENT_URI...
+         //
+@@ -752,16 +755,19 @@ nsLoadGroup::GetRootLoadGroup(nsILoadGro
+ }
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ // nsPILoadGroupInternal methods:
+ 
+ NS_IMETHODIMP
+ nsLoadGroup::OnEndPageLoad(nsIChannel *aDefaultChannel)
+ {
++    LOG(("nsLoadGroup::OnEndPageLoad this=%p default-request=%p",
++         this, aDefaultChannel));
++
+     // for the moment, nothing to do here.
+     return NS_OK;
+ }
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ // nsISupportsPriority methods:
+ 
+ NS_IMETHODIMP
+diff --git a/netwerk/dns/nsHostResolver.cpp b/netwerk/dns/nsHostResolver.cpp
+--- a/netwerk/dns/nsHostResolver.cpp
++++ b/netwerk/dns/nsHostResolver.cpp
+@@ -554,16 +554,18 @@ nsHostResolver::~nsHostResolver() = defa
+ 
+ nsresult
+ nsHostResolver::Init()
+ {
+     if (NS_FAILED(GetAddrInfoInit())) {
+         return NS_ERROR_FAILURE;
+     }
+ 
++    LOG(("nsHostResolver::Init this=%p", this));
++
+     mShutdown = false;
+ 
+ #if TTL_AVAILABLE
+     // The preferences probably haven't been loaded from the disk yet, so we
+     // need to register a callback that will set up the experiment once they
+     // are. We also need to explicitly set a value for the props otherwise the
+     // callback won't be called.
+     {
+diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
+--- a/netwerk/protocol/http/HttpBaseChannel.cpp
++++ b/netwerk/protocol/http/HttpBaseChannel.cpp
+@@ -260,16 +260,23 @@ HttpBaseChannel::ReleaseMainThreadOnlyRe
+   arrayToRelease.AppendElement(mTopWindowURI.forget());
+   arrayToRelease.AppendElement(mListener.forget());
+   arrayToRelease.AppendElement(mListenerContext.forget());
+   arrayToRelease.AppendElement(mCompressListener.forget());
+ 
+   NS_DispatchToMainThread(new ProxyReleaseRunnable(Move(arrayToRelease)));
+ }
+ 
++void
++HttpBaseChannel::SetIsTrackingResource()
++{
++  LOG(("HttpBaseChannel::SetIsTrackingResource %p", this));
++  mIsTrackingResource = true;
++}
++
+ nsresult
+ HttpBaseChannel::Init(nsIURI *aURI,
+                       uint32_t aCaps,
+                       nsProxyInfo *aProxyInfo,
+                       uint32_t aProxyResolveFlags,
+                       nsIURI *aProxyURI,
+                       uint64_t aChannelId)
+ {
+@@ -4063,16 +4070,18 @@ HttpBaseChannel::GetThrottleQueue(nsIInp
+ 
+ //------------------------------------------------------------------------------
+ 
+ bool
+ HttpBaseChannel::EnsureRequestContextID()
+ {
+     if (mRequestContextID) {
+         // Already have a request context ID, no need to do the rest of this work
++        LOG(("HttpBaseChannel::EnsureRequestContextID this=%p id=%" PRIx64,
++             this, mRequestContextID));
+         return true;
+     }
+ 
+     // Find the loadgroup at the end of the chain in order
+     // to make sure all channels derived from the load group
+     // use the same connection scope.
+     nsCOMPtr<nsILoadGroupChild> childLoadGroup = do_QueryInterface(mLoadGroup);
+     if (!childLoadGroup) {
+@@ -4082,16 +4091,20 @@ HttpBaseChannel::EnsureRequestContextID(
+     nsCOMPtr<nsILoadGroup> rootLoadGroup;
+     childLoadGroup->GetRootLoadGroup(getter_AddRefs(rootLoadGroup));
+     if (!rootLoadGroup) {
+         return false;
+     }
+ 
+     // Set the load group connection scope on the transaction
+     rootLoadGroup->GetRequestContextID(&mRequestContextID);
++
++    LOG(("HttpBaseChannel::EnsureRequestContextID this=%p id=%" PRIx64,
++         this, mRequestContextID));
++
+     return true;
+ }
+ 
+ void
+ HttpBaseChannel::EnsureTopLevelOuterContentWindowId()
+ {
+   if (mTopLevelOuterContentWindowId) {
+     return;
+diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h
+--- a/netwerk/protocol/http/HttpBaseChannel.h
++++ b/netwerk/protocol/http/HttpBaseChannel.h
+@@ -359,20 +359,17 @@ public: /* Necko internal use only... */
+     DoApplyContentConversions(nsIStreamListener *aNextListener,
+                               nsIStreamListener **aNewNextListener);
+ 
+     // Callback on STS thread called by CopyComplete when NS_AsyncCopy()
+     // is finished. This function works as a proxy function to dispatch
+     // |EnsureUploadStreamIsCloneableComplete| to main thread.
+     virtual void OnCopyComplete(nsresult aStatus);
+ 
+-    void SetIsTrackingResource()
+-    {
+-      mIsTrackingResource = true;
+-    }
++    void SetIsTrackingResource();
+ 
+     const uint64_t& ChannelId() const
+     {
+       return mChannelId;
+     }
+ 
+ protected:
+   // Handle notifying listener, removing from loadgroup if request failed.
+diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp
+--- a/netwerk/protocol/http/HttpChannelChild.cpp
++++ b/netwerk/protocol/http/HttpChannelChild.cpp
+@@ -1918,17 +1918,17 @@ HttpChannelChild::CleanupRedirectingChan
+ 
+ //-----------------------------------------------------------------------------
+ // HttpChannelChild::nsIChildChannel
+ //-----------------------------------------------------------------------------
+ 
+ NS_IMETHODIMP
+ HttpChannelChild::ConnectParent(uint32_t registrarId)
+ {
+-  LOG(("HttpChannelChild::ConnectParent [this=%p]\n", this));
++  LOG(("HttpChannelChild::ConnectParent [this=%p, id=%" PRIu32 "]\n", this, registrarId));
+   mozilla::dom::TabChild* tabChild = nullptr;
+   nsCOMPtr<nsITabChild> iTabChild;
+   GetCallback(iTabChild);
+   if (iTabChild) {
+     tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
+   }
+   if (MissingRequiredTabChild(tabChild, "http")) {
+     return NS_ERROR_ILLEGAL_VALUE;
+@@ -2592,16 +2592,19 @@ HttpChannelChild::ContinueAsyncOpen()
+   EnsureRequestContextID();
+   openArgs.requestContextID() = mRequestContextID;
+ 
+   openArgs.channelId() = mChannelId;
+ 
+   openArgs.contentWindowId() = contentWindowId;
+   openArgs.topLevelOuterContentWindowId() = mTopLevelOuterContentWindowId;
+ 
++  LOG(("HttpChannelChild::ContinueAsyncOpen this=%p gid=%" PRIu64 " topwinid=%" PRIx64,
++       this, mChannelId, mTopLevelOuterContentWindowId));
++
+   if (tabChild && !tabChild->IPCOpen()) {
+     return NS_ERROR_FAILURE;
+   }
+ 
+   ContentChild* cc = static_cast<ContentChild*>(gNeckoChild->Manager());
+   if (cc->IsShuttingDown()) {
+     return NS_ERROR_FAILURE;
+   }
+@@ -2923,16 +2926,18 @@ HttpChannelChild::ResumeAt(uint64_t star
+ 
+ //-----------------------------------------------------------------------------
+ // HttpChannelChild::nsISupportsPriority
+ //-----------------------------------------------------------------------------
+ 
+ NS_IMETHODIMP
+ HttpChannelChild::SetPriority(int32_t aPriority)
+ {
++  LOG(("HttpChannelChild::SetPriority %p p=%d", this, aPriority));
++
+   int16_t newValue = clamped<int32_t>(aPriority, INT16_MIN, INT16_MAX);
+   if (mPriority == newValue)
+     return NS_OK;
+   mPriority = newValue;
+   if (RemoteChannelExists())
+     SendSetPriority(mPriority);
+   return NS_OK;
+ }
+@@ -2943,36 +2948,45 @@ HttpChannelChild::SetPriority(int32_t aP
+ NS_IMETHODIMP
+ HttpChannelChild::SetClassFlags(uint32_t inFlags)
+ {
+   if (mClassOfService == inFlags) {
+     return NS_OK;
+   }
+ 
+   mClassOfService = inFlags;
++
++  LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService));
++
+   if (RemoteChannelExists()) {
+     SendSetClassOfService(mClassOfService);
+   }
+   return NS_OK;
+ }
+ 
+ NS_IMETHODIMP
+ HttpChannelChild::AddClassFlags(uint32_t inFlags)
+ {
+   mClassOfService |= inFlags;
++
++  LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService));
++
+   if (RemoteChannelExists()) {
+     SendSetClassOfService(mClassOfService);
+   }
+   return NS_OK;
+ }
+ 
+ NS_IMETHODIMP
+ HttpChannelChild::ClearClassFlags(uint32_t inFlags)
+ {
+   mClassOfService &= ~inFlags;
++
++  LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService));
++
+   if (RemoteChannelExists()) {
+     SendSetClassOfService(mClassOfService);
+   }
+   return NS_OK;
+ }
+ 
+ //-----------------------------------------------------------------------------
+ // HttpChannelChild::nsIProxiedChannel
+diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp
+--- a/netwerk/protocol/http/HttpChannelParent.cpp
++++ b/netwerk/protocol/http/HttpChannelParent.cpp
+@@ -489,18 +489,18 @@ HttpChannelParent::DoAsyncOpen(  const U
+     return false;
+   }
+   nsCOMPtr<nsIURI> originalUri = DeserializeURI(aOriginalURI);
+   nsCOMPtr<nsIURI> docUri = DeserializeURI(aDocURI);
+   nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
+   nsCOMPtr<nsIURI> apiRedirectToUri = DeserializeURI(aAPIRedirectToURI);
+   nsCOMPtr<nsIURI> topWindowUri = DeserializeURI(aTopWindowURI);
+ 
+-  LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s]\n",
+-       this, uri->GetSpecOrDefault().get()));
++  LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s, gid=%" PRIu64 " topwinid=%" PRIx64 "]\n",
++       this, uri->GetSpecOrDefault().get(), aChannelId, aTopLevelOuterContentWindowId));
+ 
+   nsresult rv;
+ 
+   nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
+   if (NS_FAILED(rv))
+     return SendFailedAsyncOpen(rv);
+ 
+   nsCOMPtr<nsILoadInfo> loadInfo;
+@@ -814,16 +814,18 @@ HttpChannelParent::ConnectChannel(const 
+   LOG(("  found channel %p, rv=%08" PRIx32, channel.get(), static_cast<uint32_t>(rv)));
+   mChannel = do_QueryObject(channel);
+   if (!mChannel) {
+     LOG(("  but it's not nsHttpChannel"));
+     Delete();
+     return true;
+   }
+ 
++  LOG(("  and it is nsHttpChannel %p", mChannel.get()));
++
+   mChannel->SetWarningReporter(this);
+ 
+   nsCOMPtr<nsINetworkInterceptController> controller;
+   NS_QueryNotificationCallbacks(channel, controller);
+   RefPtr<HttpChannelParentListener> parentListener = do_QueryObject(controller);
+   MOZ_ASSERT(parentListener);
+   parentListener->SetupInterceptionAfterRedirect(shouldIntercept);
+ 
+diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
+--- a/netwerk/protocol/http/nsHttpChannel.cpp
++++ b/netwerk/protocol/http/nsHttpChannel.cpp
+@@ -1091,17 +1091,18 @@ nsHttpChannel::SetupTransactionRequestCo
+     }
+ 
+     mTransaction->SetRequestContext(rc);
+ }
+ 
+ nsresult
+ nsHttpChannel::SetupTransaction()
+ {
+-    LOG(("nsHttpChannel::SetupTransaction [this=%p]\n", this));
++    LOG(("nsHttpChannel::SetupTransaction [this=%p, cos=%u, prio=%d]\n",
++         this, mClassOfService, mPriority));
+ 
+     NS_ENSURE_TRUE(!mTransaction, NS_ERROR_ALREADY_INITIALIZED);
+ 
+     nsresult rv;
+ 
+     mozilla::MutexAutoLock lock(mRCWNLock);
+ 
+     // If we're racing cache with network, conditional or byte range header
+@@ -6265,16 +6266,18 @@ bool
+ nsHttpChannel::InitLocalBlockList(const InitLocalBlockListCallback& aCallback)
+ {
+     mLocalBlocklist = false;
+ 
+     if (!(mLoadFlags & LOAD_CLASSIFY_URI)) {
+         return false;
+     }
+ 
++    LOG(("nsHttpChannel::InitLocalBlockList this=%p", this));
++
+     // Check to see if this principal exists on local blocklists.
+     RefPtr<nsChannelClassifier> channelClassifier =
+         GetOrCreateChannelClassifier();
+ 
+     // We skip speculative connections by setting mLocalBlocklist only
+     // when tracking protection is enabled. Though we could do this for
+     // both phishing and malware, it is not necessary for correctness,
+     // since no network events will be received while the
+@@ -6696,16 +6699,19 @@ nsHttpChannel::SetChannelIsForDownload(b
+ //-----------------------------------------------------------------------------
+ 
+ NS_IMETHODIMP
+ nsHttpChannel::SetPriority(int32_t value)
+ {
+     int16_t newValue = clamped<int32_t>(value, INT16_MIN, INT16_MAX);
+     if (mPriority == newValue)
+         return NS_OK;
++
++    LOG(("nsHttpChannel::SetPriority %p p=%d", this, newValue));
++
+     mPriority = newValue;
+     if (mTransaction) {
+         nsresult rv = gHttpHandler->RescheduleTransaction(mTransaction, mPriority);
+         if (NS_FAILED(rv)) {
+             LOG(("nsHttpChannel::SetPriority [this=%p] "
+                  "RescheduleTransaction failed (%08x)", this,
+                  static_cast<uint32_t>(rv)));
+         }
+@@ -7388,16 +7394,18 @@ nsHttpChannel::OnStopRequest(nsIRequest 
+         }
+ 
+         // If DoAuthRetry failed, or if we have been cancelled since showing
+         // the auth. dialog, then we need to send OnStartRequest now
+         if (authRetry || (mAuthRetryPending && NS_FAILED(status))) {
+             MOZ_ASSERT(NS_FAILED(status), "should have a failure code here");
+             // NOTE: since we have a failure status, we can ignore the return
+             // value from onStartRequest.
++            LOG(("  calling mListener->OnStartRequest [this=%p, listener=%p]\n",
++                 this, mListener.get()));
+             if (mListener) {
+                 MOZ_ASSERT(!mOnStartRequestCalled,
+                            "We should not call OnStartRequest twice.");
+                 mListener->OnStartRequest(this, mListenerContext);
+                 mOnStartRequestCalled = true;
+             } else {
+                 NS_WARNING("OnStartRequest skipped because of null listener");
+             }
+@@ -7526,17 +7534,17 @@ nsHttpChannel::OnStopRequest(nsIRequest 
+ 
+     // Register entry to the Performance resource timing
+     mozilla::dom::Performance* documentPerformance = GetPerformance();
+     if (documentPerformance) {
+         documentPerformance->AddEntry(this, this);
+     }
+ 
+     if (mListener) {
+-        LOG(("  calling OnStopRequest\n"));
++        LOG(("nsHttpChannel %p calling OnStopRequest\n", this));
+         MOZ_ASSERT(mOnStartRequestCalled,
+                    "OnStartRequest should be called before OnStopRequest");
+         MOZ_ASSERT(!mOnStopRequestCalled,
+                    "We should not call OnStopRequest twice");
+         mListener->OnStopRequest(this, mListenerContext, status);
+         mOnStopRequestCalled = true;
+     }
+ 
+diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp
+--- a/netwerk/protocol/http/nsHttpConnection.cpp
++++ b/netwerk/protocol/http/nsHttpConnection.cpp
+@@ -146,17 +146,17 @@ nsHttpConnection::Init(nsHttpConnectionI
+                        uint16_t maxHangTime,
+                        nsISocketTransport *transport,
+                        nsIAsyncInputStream *instream,
+                        nsIAsyncOutputStream *outstream,
+                        bool connectedTransport,
+                        nsIInterfaceRequestor *callbacks,
+                        PRIntervalTime rtt)
+ {
+-    LOG(("nsHttpConnection::Init this=%p", this));
++    LOG(("nsHttpConnection::Init this=%p sockettransport=%p", this, transport));
+     NS_ENSURE_ARG_POINTER(info);
+     NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED);
+ 
+     mConnectedTransport = connectedTransport;
+     mConnInfo = info;
+     MOZ_ASSERT(mConnInfo);
+     mLastWriteTime = mLastReadTime = PR_IntervalNow();
+     mRtt = rtt;
+diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp
+--- a/netwerk/protocol/http/nsHttpTransaction.cpp
++++ b/netwerk/protocol/http/nsHttpTransaction.cpp
+@@ -714,24 +714,28 @@ nsHttpTransaction::ReadRequestSegment(ns
+ {
+     // For the tracking of sent bytes that we used to do for the networkstats
+     // API, please see bug 1318883 where it was removed.
+ 
+     nsHttpTransaction *trans = (nsHttpTransaction *) closure;
+     nsresult rv = trans->mReader->OnReadSegment(buf, count, countRead);
+     if (NS_FAILED(rv)) return rv;
+ 
++    LOG(("nsHttpTransaction::ReadRequestSegment %p read=%u", trans, *countRead));
++
+     trans->mSentData = true;
+     return NS_OK;
+ }
+ 
+ nsresult
+ nsHttpTransaction::ReadSegments(nsAHttpSegmentReader *reader,
+                                 uint32_t count, uint32_t *countRead)
+ {
++    LOG(("nsHttpTransaction::ReadSegments %p", this));
++
+     MOZ_ASSERT(OnSocketThread(), "not on socket thread");
+ 
+     if (mTransactionDone) {
+         *countRead = 0;
+         return mStatus;
+     }
+ 
+     if (!mConnected && !m0RTTInProgress) {
+@@ -813,16 +817,18 @@ nsHttpTransaction::WritePipeSegment(nsIO
+ 
+     nsresult rv;
+     //
+     // OK, now let the caller fill this segment with data.
+     //
+     rv = trans->mWriter->OnWriteSegment(buf, count, countWritten);
+     if (NS_FAILED(rv)) return rv; // caller didn't want to write anything
+ 
++    LOG(("nsHttpTransaction::WritePipeSegment %p written=%u", trans, *countWritten));
++
+     MOZ_ASSERT(*countWritten > 0, "bad writer");
+     trans->mReceivedData = true;
+     trans->mTransferSize += *countWritten;
+ 
+     // Let the transaction "play" with the buffer.  It is free to modify
+     // the contents of the buffer and/or modify countWritten.
+     // - Bytes in HTTP headers don't count towards countWritten, so the input
+     // side of pipe (aka nsHttpChannel's mTransactionPump) won't hit

+ 29 - 0
frg/253-58/mozilla-release58_428163.patch

@@ -0,0 +1,29 @@
+# HG changeset patch
+# User Kate Ustiuzhanina <kustiuzhanina@mozilla.com>
+# Date 1503412098 -3600
+#      Tue Aug 22 15:28:18 2017 +0100
+# Node ID e240d265b038729647f31a1b887f7c3e33187bca
+# Parent  464568af8eb17b3eaeb143f4a7f9e233800e2612
+Bug 1390441 - Fix usePingSenderOnShutdown test via reseting TelemetrySend in tests. r=gfritzsche
+
+diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryHealthPing.js b/toolkit/components/telemetry/tests/unit/test_TelemetryHealthPing.js
+--- a/toolkit/components/telemetry/tests/unit/test_TelemetryHealthPing.js
++++ b/toolkit/components/telemetry/tests/unit/test_TelemetryHealthPing.js
+@@ -299,16 +299,17 @@ add_task(async function test_usePingSend
+     // We don't support the pingsender on Android, yet, see bug 1335917.
+     // We also don't support the pingsender testing on Treeherder for
+     // Linux 32 bit (due to missing libraries). So skip it there too.
+     // See bug 1310703 comment 78.
+     return;
+   }
+ 
+   TelemetryHealthPing.testReset();
++  await TelemetrySend.reset();
+   PingServer.clearRequests();
+ 
+   // This first failure should immediately trigger a ping.
+   // After this, subsequent failures should be throttled.
+   await TelemetryHealthPing.recordSendFailure("testFailure");
+   await PingServer.promiseNextPing();
+ 
+   TelemetryHealthPing.recordSendFailure("testFailure");

+ 35 - 0
frg/253-58/mozilla-release58_428164.patch

@@ -0,0 +1,35 @@
+# HG changeset patch
+# User Honza Bambas <honzab.moz@firemni.cz>
+# Date 1503313320 14400
+#      Mon Aug 21 07:02:00 2017 -0400
+# Node ID c092fcf5ef9a393c72b3dca39179a47d2f07c530
+# Parent  e240d265b038729647f31a1b887f7c3e33187bca
+Bug 1392264 - Return undispatched HTTP transaction to the queue in the same order as they were before. r=kershaw
+
+diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
++++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+@@ -1166,19 +1166,20 @@ nsHttpConnectionMgr::ProcessPendingQForE
+     // connection available for dispatching.
+     if (pendingQ.IsEmpty()) {
+         return dispatchedSuccessfully;
+     }
+ 
+     dispatchedSuccessfully |=
+         DispatchPendingQ(pendingQ, ent, considerAll);
+ 
+-    // Put the leftovers into connection entry
+-    for (const auto& transactionInfo : pendingQ) {
+-        ent->InsertTransaction(transactionInfo);
++    // Put the leftovers into connection entry, in the same order as they
++    // were before to keep the natural ordering.
++    for (const auto& transactionInfo : Reversed(pendingQ)) {
++        ent->InsertTransaction(transactionInfo, true);
+     }
+ 
+     // Only remove empty pendingQ when considerAll is true.
+     if (considerAll) {
+         ent->RemoveEmptyPendingQ();
+     }
+ 
+     return dispatchedSuccessfully;

+ 1477 - 0
frg/253-58/mozilla-release58_428169.patch

@@ -0,0 +1,1477 @@
+# HG changeset patch
+# User J. Ryan Stinnett <jryans@gmail.com>
+# Date 1503427359 18000
+#      Tue Aug 22 13:42:39 2017 -0500
+# Node ID 90e29632e2a19021ee687da92ee4dbeabeb50bae
+# Parent  2f8718989f5420c21f78bd8b82cade79ffeb436a
+servo: Merge #18190 - Stylo: Fix up Servo_StyleSheet_GetOrigin for Linux 32-bit ABI (from jryans:stylo-linux32-getorigin); r=emilio
+
+https://bugzilla.mozilla.org/show_bug.cgi?id=1392447
+
+Source-Repo: https://github.com/servo/servo
+Source-Revision: 5bfd5b966b19337f6b8ba9f95957bf7e49548b10
+
+diff --git a/servo/components/style/gecko/generated/atom_macro.rs b/servo/components/style/gecko/generated/atom_macro.rs
+--- a/servo/components/style/gecko/generated/atom_macro.rs
++++ b/servo/components/style/gecko/generated/atom_macro.rs
+@@ -4317,16 +4317,18 @@ cfg_if! {
+             #[link_name = "_ZN9nsGkAtoms18DisplayPortMarginsE"]
+             pub static nsGkAtoms_DisplayPortMargins: *mut nsIAtom;
+             #[link_name = "_ZN9nsGkAtoms15DisplayPortBaseE"]
+             pub static nsGkAtoms_DisplayPortBase: *mut nsIAtom;
+             #[link_name = "_ZN9nsGkAtoms30AsyncScrollLayerCreationFailedE"]
+             pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsIAtom;
+             #[link_name = "_ZN9nsGkAtoms19forcemessagemanagerE"]
+             pub static nsGkAtoms_forcemessagemanager: *mut nsIAtom;
++            #[link_name = "_ZN9nsGkAtoms16isPreloadBrowserE"]
++            pub static nsGkAtoms_isPreloadBrowser: *mut nsIAtom;
+             #[link_name = "_ZN9nsGkAtoms22color_picker_availableE"]
+             pub static nsGkAtoms_color_picker_available: *mut nsIAtom;
+             #[link_name = "_ZN9nsGkAtoms24scrollbar_start_backwardE"]
+             pub static nsGkAtoms_scrollbar_start_backward: *mut nsIAtom;
+             #[link_name = "_ZN9nsGkAtoms23scrollbar_start_forwardE"]
+             pub static nsGkAtoms_scrollbar_start_forward: *mut nsIAtom;
+             #[link_name = "_ZN9nsGkAtoms22scrollbar_end_backwardE"]
+             pub static nsGkAtoms_scrollbar_end_backward: *mut nsIAtom;
+@@ -9442,16 +9444,18 @@ cfg_if! {
+             #[link_name = "?DisplayPortMargins@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+             pub static nsGkAtoms_DisplayPortMargins: *mut nsIAtom;
+             #[link_name = "?DisplayPortBase@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+             pub static nsGkAtoms_DisplayPortBase: *mut nsIAtom;
+             #[link_name = "?AsyncScrollLayerCreationFailed@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+             pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsIAtom;
+             #[link_name = "?forcemessagemanager@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+             pub static nsGkAtoms_forcemessagemanager: *mut nsIAtom;
++            #[link_name = "?isPreloadBrowser@nsGkAtoms@@2PEAVnsIAtom@@EA"]
++            pub static nsGkAtoms_isPreloadBrowser: *mut nsIAtom;
+             #[link_name = "?color_picker_available@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+             pub static nsGkAtoms_color_picker_available: *mut nsIAtom;
+             #[link_name = "?scrollbar_start_backward@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+             pub static nsGkAtoms_scrollbar_start_backward: *mut nsIAtom;
+             #[link_name = "?scrollbar_start_forward@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+             pub static nsGkAtoms_scrollbar_start_forward: *mut nsIAtom;
+             #[link_name = "?scrollbar_end_backward@nsGkAtoms@@2PEAVnsIAtom@@EA"]
+             pub static nsGkAtoms_scrollbar_end_backward: *mut nsIAtom;
+@@ -14567,16 +14571,18 @@ cfg_if! {
+             #[link_name = "\x01?DisplayPortMargins@nsGkAtoms@@2PAVnsIAtom@@A"]
+             pub static nsGkAtoms_DisplayPortMargins: *mut nsIAtom;
+             #[link_name = "\x01?DisplayPortBase@nsGkAtoms@@2PAVnsIAtom@@A"]
+             pub static nsGkAtoms_DisplayPortBase: *mut nsIAtom;
+             #[link_name = "\x01?AsyncScrollLayerCreationFailed@nsGkAtoms@@2PAVnsIAtom@@A"]
+             pub static nsGkAtoms_AsyncScrollLayerCreationFailed: *mut nsIAtom;
+             #[link_name = "\x01?forcemessagemanager@nsGkAtoms@@2PAVnsIAtom@@A"]
+             pub static nsGkAtoms_forcemessagemanager: *mut nsIAtom;
++            #[link_name = "\x01?isPreloadBrowser@nsGkAtoms@@2PAVnsIAtom@@A"]
++            pub static nsGkAtoms_isPreloadBrowser: *mut nsIAtom;
+             #[link_name = "\x01?color_picker_available@nsGkAtoms@@2PAVnsIAtom@@A"]
+             pub static nsGkAtoms_color_picker_available: *mut nsIAtom;
+             #[link_name = "\x01?scrollbar_start_backward@nsGkAtoms@@2PAVnsIAtom@@A"]
+             pub static nsGkAtoms_scrollbar_start_backward: *mut nsIAtom;
+             #[link_name = "\x01?scrollbar_start_forward@nsGkAtoms@@2PAVnsIAtom@@A"]
+             pub static nsGkAtoms_scrollbar_start_forward: *mut nsIAtom;
+             #[link_name = "\x01?scrollbar_end_backward@nsGkAtoms@@2PAVnsIAtom@@A"]
+             pub static nsGkAtoms_scrollbar_end_backward: *mut nsIAtom;
+@@ -19695,16 +19701,18 @@ macro_rules! atom {
+ ("_displayportmargins") =>
+   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_DisplayPortMargins as *mut _) } };
+ ("_displayportbase") =>
+   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_DisplayPortBase as *mut _) } };
+ ("_asyncscrolllayercreationfailed") =>
+   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_AsyncScrollLayerCreationFailed as *mut _) } };
+ ("forcemessagemanager") =>
+   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_forcemessagemanager as *mut _) } };
++("isPreloadBrowser") =>
++  { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_isPreloadBrowser as *mut _) } };
+ ("color-picker-available") =>
+   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_color_picker_available as *mut _) } };
+ ("scrollbar-start-backward") =>
+   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_scrollbar_start_backward as *mut _) } };
+ ("scrollbar-start-forward") =>
+   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_scrollbar_start_forward as *mut _) } };
+ ("scrollbar-end-backward") =>
+   { unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_scrollbar_end_backward as *mut _) } };
+diff --git a/servo/components/style/gecko/generated/bindings.rs b/servo/components/style/gecko/generated/bindings.rs
+--- a/servo/components/style/gecko/generated/bindings.rs
++++ b/servo/components/style/gecko/generated/bindings.rs
+@@ -1066,21 +1066,16 @@ extern "C" {
+ extern "C" {
+     pub fn Gecko_NoteDirtyElement(element: RawGeckoElementBorrowed);
+ }
+ extern "C" {
+     pub fn Gecko_NoteAnimationOnlyDirtyElement(element:
+                                                    RawGeckoElementBorrowed);
+ }
+ extern "C" {
+-    pub fn Gecko_GetStyleContext(element: RawGeckoElementBorrowed,
+-                                 aPseudoTagOrNull: *mut nsIAtom)
+-     -> *mut nsStyleContext;
+-}
+-extern "C" {
+     pub fn Gecko_GetImplementedPseudo(element: RawGeckoElementBorrowed)
+      -> CSSPseudoElementType;
+ }
+ extern "C" {
+     pub fn Gecko_CalcStyleDifference(old_style: ServoStyleContextBorrowed,
+                                      new_style: ServoStyleContextBorrowed,
+                                      old_style_bits: u64,
+                                      any_style_changed: *mut bool) -> u32;
+@@ -1956,21 +1951,17 @@ extern "C" {
+     pub fn Servo_StyleSheet_SizeOfIncludingThis(malloc_size_of: MallocSizeOf,
+                                                 sheet:
+                                                     RawServoStyleSheetContentsBorrowed)
+      -> usize;
+ }
+ extern "C" {
+     pub fn Servo_StyleSheet_GetOrigin(sheet:
+                                           RawServoStyleSheetContentsBorrowed)
+-     -> OriginFlags;
+-}
+-extern "C" {
+-    pub fn Servo_StyleSheet_GetSourceMapURL(sheet: RawServoStyleSheetContentsBorrowed,
+-                                            result: *mut nsAString);
++     -> u8;
+ }
+ extern "C" {
+     pub fn Servo_StyleSet_Init(pres_context: RawGeckoPresContextOwned)
+      -> *mut RawServoStyleSet;
+ }
+ extern "C" {
+     pub fn Servo_StyleSet_RebuildCachedData(set: RawServoStyleSetBorrowed);
+ }
+diff --git a/servo/components/style/gecko/generated/structs_debug.rs b/servo/components/style/gecko/generated/structs_debug.rs
+--- a/servo/components/style/gecko/generated/structs_debug.rs
++++ b/servo/components/style/gecko/generated/structs_debug.rs
+@@ -1413,16 +1413,17 @@ pub mod root {
+         pub type Array_reverse_iterator<T> =
+             root::mozilla::ReverseIterator<T>;
+         pub type Array_const_reverse_iterator<T> =
+             root::mozilla::ReverseIterator<T>;
+         pub mod css {
+             #[allow(unused_imports)]
+             use self::super::super::super::root;
+             #[repr(C)]
++            #[derive(Debug)]
+             pub struct ErrorReporter {
+                 pub mError: root::nsAutoString,
+                 pub mErrorLine: ::nsstring::nsStringRepr,
+                 pub mFileName: ::nsstring::nsStringRepr,
+                 pub mScanner: *const root::nsCSSScanner,
+                 pub mSheet: *const root::mozilla::StyleSheet,
+                 pub mLoader: *const root::mozilla::css::Loader,
+                 pub mURI: *mut root::nsIURI,
+@@ -10291,40 +10292,22 @@ pub mod root {
+                     & ( * ( 0 as * const nsString_Segment ) ) . mLength as *
+                     const _ as usize } , 4usize , concat ! (
+                     "Alignment of field: " , stringify ! ( nsString_Segment )
+                     , "::" , stringify ! ( mLength ) ));
+     }
+     impl Clone for nsString_Segment {
+         fn clone(&self) -> Self { *self }
+     }
+-    #[repr(C)]
+-    pub struct nsAutoString {
+-        pub _base: root::nsFixedString,
+-        pub mStorage: [root::mozilla::detail::nsStringRepr_char_type; 64usize],
+-    }
+-    pub type nsAutoString_self_type = root::nsAutoString;
+-    pub const nsAutoString_kDefaultStorageSize:
+-              root::nsAutoString__bindgen_ty_1 =
+-        nsAutoString__bindgen_ty_1::kDefaultStorageSize;
+-    #[repr(u32)]
+-    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+-    pub enum nsAutoString__bindgen_ty_1 { kDefaultStorageSize = 64, }
+-    #[test]
+-    fn bindgen_test_layout_nsAutoString() {
+-        assert_eq!(::std::mem::size_of::<nsAutoString>() , 160usize , concat !
+-                   ( "Size of: " , stringify ! ( nsAutoString ) ));
+-        assert_eq! (::std::mem::align_of::<nsAutoString>() , 8usize , concat !
+-                    ( "Alignment of " , stringify ! ( nsAutoString ) ));
+-        assert_eq! (unsafe {
+-                    & ( * ( 0 as * const nsAutoString ) ) . mStorage as *
+-                    const _ as usize } , 32usize , concat ! (
+-                    "Alignment of field: " , stringify ! ( nsAutoString ) ,
+-                    "::" , stringify ! ( mStorage ) ));
+-    }
++    pub type nsAutoStringN_self_type = u8;
++    extern "C" {
++        #[link_name = "kStorageSize"]
++        pub static nsAutoStringN_kStorageSize: usize;
++    }
++    pub type nsAutoString = [u64; 20usize];
+     #[repr(C)]
+     pub struct nsStringComparator__bindgen_vtable(::std::os::raw::c_void);
+     #[repr(C)]
+     #[derive(Debug, Copy)]
+     pub struct nsStringComparator {
+         pub vtable_: *const nsStringComparator__bindgen_vtable,
+     }
+     pub type nsStringComparator_char_type = u16;
+@@ -10521,16 +10504,24 @@ pub mod root {
+     impl Clone for nsCycleCollectionParticipant {
+         fn clone(&self) -> Self { *self }
+     }
+     #[repr(C)]
+     #[derive(Debug, Copy)]
+     pub struct nsCycleCollectingAutoRefCnt {
+         pub mRefCntAndFlags: usize,
+     }
++    pub type nsCycleCollectingAutoRefCnt_Suspect =
++        ::std::option::Option<unsafe extern "C" fn(aPtr:
++                                                       *mut ::std::os::raw::c_void,
++                                                   aCp:
++                                                       *mut root::nsCycleCollectionParticipant,
++                                                   aRefCnt:
++                                                       *mut root::nsCycleCollectingAutoRefCnt,
++                                                   aShouldDelete: *mut bool)>;
+     #[test]
+     fn bindgen_test_layout_nsCycleCollectingAutoRefCnt() {
+         assert_eq!(::std::mem::size_of::<nsCycleCollectingAutoRefCnt>() ,
+                    8usize , concat ! (
+                    "Size of: " , stringify ! ( nsCycleCollectingAutoRefCnt )
+                    ));
+         assert_eq! (::std::mem::align_of::<nsCycleCollectingAutoRefCnt>() ,
+                     8usize , concat ! (
+@@ -10590,42 +10581,16 @@ pub mod root {
+     pub type AutoTArray_elem_type<E> = root::AutoTArray_base_type<E>;
+     #[repr(C)]
+     #[derive(Debug, Copy, Clone)]
+     pub struct AutoTArray__bindgen_ty_1 {
+         pub mAutoBuf: root::__BindgenUnionField<*mut ::std::os::raw::c_char>,
+         pub mAlign: root::__BindgenUnionField<u8>,
+         pub bindgen_union_field: u64,
+     }
+-    #[repr(C)]
+-    #[derive(Debug)]
+-    pub struct nsFixedString {
+-        pub _base: ::nsstring::nsStringRepr,
+-        pub mFixedCapacity: root::mozilla::detail::nsStringRepr_size_type,
+-        pub mFixedBuf: *mut root::mozilla::detail::nsStringRepr_char_type,
+-    }
+-    pub type nsFixedString_self_type = root::nsFixedString;
+-    pub type nsFixedString_fixed_string_type = root::nsFixedString;
+-    #[test]
+-    fn bindgen_test_layout_nsFixedString() {
+-        assert_eq!(::std::mem::size_of::<nsFixedString>() , 32usize , concat !
+-                   ( "Size of: " , stringify ! ( nsFixedString ) ));
+-        assert_eq! (::std::mem::align_of::<nsFixedString>() , 8usize , concat
+-                    ! ( "Alignment of " , stringify ! ( nsFixedString ) ));
+-        assert_eq! (unsafe {
+-                    & ( * ( 0 as * const nsFixedString ) ) . mFixedCapacity as
+-                    * const _ as usize } , 16usize , concat ! (
+-                    "Alignment of field: " , stringify ! ( nsFixedString ) ,
+-                    "::" , stringify ! ( mFixedCapacity ) ));
+-        assert_eq! (unsafe {
+-                    & ( * ( 0 as * const nsFixedString ) ) . mFixedBuf as *
+-                    const _ as usize } , 24usize , concat ! (
+-                    "Alignment of field: " , stringify ! ( nsFixedString ) ,
+-                    "::" , stringify ! ( mFixedBuf ) ));
+-    }
+     pub type PRUint32 = ::std::os::raw::c_uint;
+     pub type PRIntn = ::std::os::raw::c_int;
+     pub type PRUintn = ::std::os::raw::c_uint;
+     /// TYPES:       PRSize
+     /// DESCRIPTION:
+     /// A type for representing the size of objects.
+     pub type PRSize = usize;
+     #[repr(C)]
+@@ -33786,17 +33751,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::gfx::FontVariation>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_228717_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_228788_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsCSSSelector>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsCSSSelector> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsCSSSelector>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsCSSSelector> ) ));
+@@ -34142,17 +34107,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::binding_danger::TErrorResult ) ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::binding_danger::TErrorResult>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::mozilla::binding_danger::TErrorResult ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_230548_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_230622_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -34303,17 +34268,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::DeletePolicy ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::DeletePolicy>() , 1usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::DeletePolicy ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_iterator_open0_input_iterator_tag_UniquePtr_open1_JSErrorNotes_Note_DeletePolicy_open2_JSErrorNotes_Note_close2_close1_long__bindgen_ty_id_236167__bindgen_ty_id_236174_close0_instantiation() {
++    fn __bindgen_test_layout_iterator_open0_input_iterator_tag_UniquePtr_open1_JSErrorNotes_Note_DeletePolicy_open2_JSErrorNotes_Note_close2_close1_long__bindgen_ty_id_236242__bindgen_ty_id_236249_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::std::iterator>() , 1usize ,
+                    concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::std::iterator ) ));
+         assert_eq!(::std::mem::align_of::<root::std::iterator>() , 1usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::std::iterator ) ));
+@@ -34551,17 +34516,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_238666_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_238741_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -34619,17 +34584,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIObserver> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr<root::nsIObserver>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIObserver> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_238968_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239043_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -34731,17 +34696,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::URLExtraData> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::URLExtraData>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::URLExtraData> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_NotNull_open0__bindgen_ty_id_239510_close0_instantiation() {
++    fn __bindgen_test_layout_NotNull_open0__bindgen_ty_id_239588_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::mozilla::NotNull<*const root::mozilla::Encoding>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::NotNull<*const root::mozilla::Encoding> )
+                    ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::NotNull<*const root::mozilla::Encoding>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+@@ -35135,17 +35100,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239931_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_240009_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -35225,17 +35190,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::RefPtr<root::mozilla::ServoStyleSheet>>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::RefPtr<root::mozilla::ServoStyleSheet>>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_240330_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_240409_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -35326,17 +35291,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<::nsstring::nsStringRepr> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<::nsstring::nsStringRepr>>() ,
+                    8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<::nsstring::nsStringRepr> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241301_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241380_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -35415,28 +35380,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsCSSFontFaceRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::nsCSSFontFaceRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsCSSFontFaceRule> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241606_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241685_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241611_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241690_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -35483,17 +35448,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::CSSStyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::CSSStyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::CSSStyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_242102_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_242181_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -36131,17 +36096,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIWeakReference> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr<root::nsIWeakReference>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIWeakReference> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_244958_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_245037_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut ::std::os::raw::c_void>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut ::std::os::raw::c_void> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut ::std::os::raw::c_void>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut ::std::os::raw::c_void> ) ));
+@@ -36210,17 +36175,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::DefaultDelete ) ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::DefaultDelete>() ,
+                    1usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::mozilla::DefaultDelete ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_251248_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_251322_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::AudioContext>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::AudioContext> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::AudioContext>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::AudioContext> ) ));
+@@ -36243,28 +36208,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::CallbackObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::CallbackObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::CallbackObject> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_252417_close0_instantiation() {
++    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_252491_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_252421_close0_instantiation() {
++    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_252495_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+@@ -36276,17 +36241,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIGlobalObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr<root::nsIGlobalObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIGlobalObject> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_TenuredHeap_open0__bindgen_ty_id_252428_close0_instantiation() {
++    fn __bindgen_test_layout_TenuredHeap_open0__bindgen_ty_id_252502_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::TenuredHeap>() , 8usize ,
+                    concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::TenuredHeap ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::TenuredHeap>() , 8usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::TenuredHeap ) ));
+@@ -36355,17 +36320,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::CycleCollectedJSContext_RunInMetastableStateData>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::CycleCollectedJSContext_RunInMetastableStateData>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_253533_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_253607_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+@@ -36550,17 +36515,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<f64> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<f64>>() , 8usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<f64> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_254981_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_255055_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -36655,17 +36620,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsRefPtrHashKey<root::nsIAtom> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsRefPtrHashKey<root::nsIAtom>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsRefPtrHashKey<root::nsIAtom> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_257410_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_257463_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::CounterStyle>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::CounterStyle> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::CounterStyle>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::CounterStyle> ) ));
+@@ -37356,17 +37321,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsStyleImageRequest> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::nsStyleImageRequest>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsStyleImageRequest> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_259968_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_260021_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+@@ -37593,28 +37558,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIURI> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr<root::nsIURI>>() ,
+                    8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIURI> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267780_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267833_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267785_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267838_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37692,17 +37657,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::ShadowRoot> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::ShadowRoot>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::ShadowRoot> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267898_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267951_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37979,17 +37944,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsAutoPtr<root::mozilla::dom::ExplicitChildIterator>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsAutoPtr<root::mozilla::dom::ExplicitChildIterator>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269484_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269537_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -38001,28 +37966,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::Element> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269646_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269699_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269651_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269704_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -38144,28 +38109,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::gfx::FontVariation>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_272182_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_272231_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_272190_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_272239_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+diff --git a/servo/components/style/gecko/generated/structs_release.rs b/servo/components/style/gecko/generated/structs_release.rs
+--- a/servo/components/style/gecko/generated/structs_release.rs
++++ b/servo/components/style/gecko/generated/structs_release.rs
+@@ -1366,16 +1366,17 @@ pub mod root {
+         pub type Array_reverse_iterator<T> =
+             root::mozilla::ReverseIterator<T>;
+         pub type Array_const_reverse_iterator<T> =
+             root::mozilla::ReverseIterator<T>;
+         pub mod css {
+             #[allow(unused_imports)]
+             use self::super::super::super::root;
+             #[repr(C)]
++            #[derive(Debug)]
+             pub struct ErrorReporter {
+                 pub mError: root::nsAutoString,
+                 pub mErrorLine: ::nsstring::nsStringRepr,
+                 pub mFileName: ::nsstring::nsStringRepr,
+                 pub mScanner: *const root::nsCSSScanner,
+                 pub mSheet: *const root::mozilla::StyleSheet,
+                 pub mLoader: *const root::mozilla::css::Loader,
+                 pub mURI: *mut root::nsIURI,
+@@ -10137,40 +10138,22 @@ pub mod root {
+                     & ( * ( 0 as * const nsString_Segment ) ) . mLength as *
+                     const _ as usize } , 4usize , concat ! (
+                     "Alignment of field: " , stringify ! ( nsString_Segment )
+                     , "::" , stringify ! ( mLength ) ));
+     }
+     impl Clone for nsString_Segment {
+         fn clone(&self) -> Self { *self }
+     }
+-    #[repr(C)]
+-    pub struct nsAutoString {
+-        pub _base: root::nsFixedString,
+-        pub mStorage: [root::mozilla::detail::nsStringRepr_char_type; 64usize],
+-    }
+-    pub type nsAutoString_self_type = root::nsAutoString;
+-    pub const nsAutoString_kDefaultStorageSize:
+-              root::nsAutoString__bindgen_ty_1 =
+-        nsAutoString__bindgen_ty_1::kDefaultStorageSize;
+-    #[repr(u32)]
+-    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+-    pub enum nsAutoString__bindgen_ty_1 { kDefaultStorageSize = 64, }
+-    #[test]
+-    fn bindgen_test_layout_nsAutoString() {
+-        assert_eq!(::std::mem::size_of::<nsAutoString>() , 160usize , concat !
+-                   ( "Size of: " , stringify ! ( nsAutoString ) ));
+-        assert_eq! (::std::mem::align_of::<nsAutoString>() , 8usize , concat !
+-                    ( "Alignment of " , stringify ! ( nsAutoString ) ));
+-        assert_eq! (unsafe {
+-                    & ( * ( 0 as * const nsAutoString ) ) . mStorage as *
+-                    const _ as usize } , 32usize , concat ! (
+-                    "Alignment of field: " , stringify ! ( nsAutoString ) ,
+-                    "::" , stringify ! ( mStorage ) ));
+-    }
++    pub type nsAutoStringN_self_type = u8;
++    extern "C" {
++        #[link_name = "kStorageSize"]
++        pub static nsAutoStringN_kStorageSize: usize;
++    }
++    pub type nsAutoString = [u64; 20usize];
+     #[repr(C)]
+     pub struct nsStringComparator__bindgen_vtable(::std::os::raw::c_void);
+     #[repr(C)]
+     #[derive(Debug, Copy)]
+     pub struct nsStringComparator {
+         pub vtable_: *const nsStringComparator__bindgen_vtable,
+     }
+     pub type nsStringComparator_char_type = u16;
+@@ -10367,16 +10350,24 @@ pub mod root {
+     impl Clone for nsCycleCollectionParticipant {
+         fn clone(&self) -> Self { *self }
+     }
+     #[repr(C)]
+     #[derive(Debug, Copy)]
+     pub struct nsCycleCollectingAutoRefCnt {
+         pub mRefCntAndFlags: usize,
+     }
++    pub type nsCycleCollectingAutoRefCnt_Suspect =
++        ::std::option::Option<unsafe extern "C" fn(aPtr:
++                                                       *mut ::std::os::raw::c_void,
++                                                   aCp:
++                                                       *mut root::nsCycleCollectionParticipant,
++                                                   aRefCnt:
++                                                       *mut root::nsCycleCollectingAutoRefCnt,
++                                                   aShouldDelete: *mut bool)>;
+     #[test]
+     fn bindgen_test_layout_nsCycleCollectingAutoRefCnt() {
+         assert_eq!(::std::mem::size_of::<nsCycleCollectingAutoRefCnt>() ,
+                    8usize , concat ! (
+                    "Size of: " , stringify ! ( nsCycleCollectingAutoRefCnt )
+                    ));
+         assert_eq! (::std::mem::align_of::<nsCycleCollectingAutoRefCnt>() ,
+                     8usize , concat ! (
+@@ -10436,42 +10427,16 @@ pub mod root {
+     pub type AutoTArray_elem_type<E> = root::AutoTArray_base_type<E>;
+     #[repr(C)]
+     #[derive(Debug, Copy, Clone)]
+     pub struct AutoTArray__bindgen_ty_1 {
+         pub mAutoBuf: root::__BindgenUnionField<*mut ::std::os::raw::c_char>,
+         pub mAlign: root::__BindgenUnionField<u8>,
+         pub bindgen_union_field: u64,
+     }
+-    #[repr(C)]
+-    #[derive(Debug)]
+-    pub struct nsFixedString {
+-        pub _base: ::nsstring::nsStringRepr,
+-        pub mFixedCapacity: root::mozilla::detail::nsStringRepr_size_type,
+-        pub mFixedBuf: *mut root::mozilla::detail::nsStringRepr_char_type,
+-    }
+-    pub type nsFixedString_self_type = root::nsFixedString;
+-    pub type nsFixedString_fixed_string_type = root::nsFixedString;
+-    #[test]
+-    fn bindgen_test_layout_nsFixedString() {
+-        assert_eq!(::std::mem::size_of::<nsFixedString>() , 32usize , concat !
+-                   ( "Size of: " , stringify ! ( nsFixedString ) ));
+-        assert_eq! (::std::mem::align_of::<nsFixedString>() , 8usize , concat
+-                    ! ( "Alignment of " , stringify ! ( nsFixedString ) ));
+-        assert_eq! (unsafe {
+-                    & ( * ( 0 as * const nsFixedString ) ) . mFixedCapacity as
+-                    * const _ as usize } , 16usize , concat ! (
+-                    "Alignment of field: " , stringify ! ( nsFixedString ) ,
+-                    "::" , stringify ! ( mFixedCapacity ) ));
+-        assert_eq! (unsafe {
+-                    & ( * ( 0 as * const nsFixedString ) ) . mFixedBuf as *
+-                    const _ as usize } , 24usize , concat ! (
+-                    "Alignment of field: " , stringify ! ( nsFixedString ) ,
+-                    "::" , stringify ! ( mFixedBuf ) ));
+-    }
+     pub type PRUint32 = ::std::os::raw::c_uint;
+     pub type PRIntn = ::std::os::raw::c_int;
+     pub type PRUintn = ::std::os::raw::c_uint;
+     /// TYPES:       PRSize
+     /// DESCRIPTION:
+     /// A type for representing the size of objects.
+     pub type PRSize = usize;
+     #[repr(C)]
+@@ -33294,17 +33259,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::gfx::FontVariation>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_226349_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_226420_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsCSSSelector>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsCSSSelector> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsCSSSelector>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsCSSSelector> ) ));
+@@ -33650,17 +33615,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::binding_danger::TErrorResult ) ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::binding_danger::TErrorResult>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::mozilla::binding_danger::TErrorResult ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_228146_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_228220_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -33811,17 +33776,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::DeletePolicy ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::DeletePolicy>() , 1usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::DeletePolicy ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_iterator_open0_input_iterator_tag_UniquePtr_open1_JSErrorNotes_Note_DeletePolicy_open2_JSErrorNotes_Note_close2_close1_long__bindgen_ty_id_233737__bindgen_ty_id_233744_close0_instantiation() {
++    fn __bindgen_test_layout_iterator_open0_input_iterator_tag_UniquePtr_open1_JSErrorNotes_Note_DeletePolicy_open2_JSErrorNotes_Note_close2_close1_long__bindgen_ty_id_233812__bindgen_ty_id_233819_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::std::iterator>() , 1usize ,
+                    concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::std::iterator ) ));
+         assert_eq!(::std::mem::align_of::<root::std::iterator>() , 1usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::std::iterator ) ));
+@@ -34059,17 +34024,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_236234_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_236309_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -34127,17 +34092,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr>() , 8usize , concat
+                    ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_236536_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_236611_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -34239,17 +34204,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::URLExtraData> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::URLExtraData>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::URLExtraData> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_NotNull_open0__bindgen_ty_id_237078_close0_instantiation() {
++    fn __bindgen_test_layout_NotNull_open0__bindgen_ty_id_237156_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::mozilla::NotNull<*const root::mozilla::Encoding>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::NotNull<*const root::mozilla::Encoding> )
+                    ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::NotNull<*const root::mozilla::Encoding>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+@@ -34641,17 +34606,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_237497_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_237575_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -34731,17 +34696,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::RefPtr<root::mozilla::ServoStyleSheet>>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::RefPtr<root::mozilla::ServoStyleSheet>>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_237894_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_237973_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -34832,17 +34797,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<::nsstring::nsStringRepr> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<::nsstring::nsStringRepr>>() ,
+                    8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<::nsstring::nsStringRepr> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_238855_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_238934_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -34921,28 +34886,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsCSSFontFaceRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::nsCSSFontFaceRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsCSSFontFaceRule> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239158_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239237_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239163_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239242_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -34989,17 +34954,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::CSSStyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::CSSStyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::CSSStyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239638_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239717_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -35624,17 +35589,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr>() , 8usize , concat
+                    ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_242464_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_242543_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut ::std::os::raw::c_void>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut ::std::os::raw::c_void> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut ::std::os::raw::c_void>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut ::std::os::raw::c_void> ) ));
+@@ -35703,17 +35668,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::DefaultDelete ) ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::DefaultDelete>() ,
+                    1usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::mozilla::DefaultDelete ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_248737_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_248811_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::AudioContext>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::AudioContext> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::AudioContext>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::AudioContext> ) ));
+@@ -35736,28 +35701,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::CallbackObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::CallbackObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::CallbackObject> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_249906_close0_instantiation() {
++    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_249980_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_249910_close0_instantiation() {
++    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_249984_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+@@ -35769,17 +35734,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr>() , 8usize , concat
+                    ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_TenuredHeap_open0__bindgen_ty_id_249917_close0_instantiation() {
++    fn __bindgen_test_layout_TenuredHeap_open0__bindgen_ty_id_249991_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::TenuredHeap>() , 8usize ,
+                    concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::TenuredHeap ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::TenuredHeap>() , 8usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::TenuredHeap ) ));
+@@ -35848,17 +35813,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::CycleCollectedJSContext_RunInMetastableStateData>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::CycleCollectedJSContext_RunInMetastableStateData>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_251022_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_251096_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+@@ -36043,17 +36008,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<f64> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<f64>>() , 8usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<f64> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_252470_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_252544_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -36148,17 +36113,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsRefPtrHashKey<root::nsIAtom> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsRefPtrHashKey<root::nsIAtom>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsRefPtrHashKey<root::nsIAtom> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_254864_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_254917_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::CounterStyle>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::CounterStyle> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::CounterStyle>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::CounterStyle> ) ));
+@@ -36849,17 +36814,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsStyleImageRequest> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::nsStyleImageRequest>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsStyleImageRequest> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_257346_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_257399_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+@@ -37086,28 +37051,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr>() , 8usize , concat
+                    ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_265158_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_265211_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_265163_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_265216_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37185,17 +37150,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::ShadowRoot> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::ShadowRoot>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::ShadowRoot> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_265276_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_265329_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37472,17 +37437,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsAutoPtr<root::mozilla::dom::ExplicitChildIterator>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsAutoPtr<root::mozilla::dom::ExplicitChildIterator>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_266856_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_266909_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37494,28 +37459,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::Element> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267014_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267067_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267019_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267072_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37637,28 +37602,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::gfx::FontVariation>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269540_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269589_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269546_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269595_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs
+--- a/servo/ports/geckolib/glue.rs
++++ b/servo/ports/geckolib/glue.rs
+@@ -1050,22 +1050,26 @@ pub extern "C" fn Servo_StyleSheet_SizeO
+     let malloc_size_of = malloc_size_of.unwrap();
+     StylesheetContents::as_arc(&sheet)
+         .malloc_size_of_children(&guard, malloc_size_of)
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_StyleSheet_GetOrigin(
+     sheet: RawServoStyleSheetContentsBorrowed
+-) -> OriginFlags {
+-    match StylesheetContents::as_arc(&sheet).origin {
++) -> u8 {
++    let origin = match StylesheetContents::as_arc(&sheet).origin {
+         Origin::UserAgent => OriginFlags_UserAgent,
+         Origin::User => OriginFlags_User,
+         Origin::Author => OriginFlags_Author,
+-    }
++    };
++    // We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
++    // work as return values with the Linux 32-bit ABI at the moment because
++    // they wrap the value in a struct, so for now just unwrap it.
++    origin.0
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_StyleSheet_GetSourceMapURL(
+     sheet: RawServoStyleSheetContentsBorrowed,
+     result: *mut nsAString
+ ) {
+     let contents = StylesheetContents::as_arc(&sheet);

+ 60 - 0
frg/253-58/mozilla-release58_428170.patch

@@ -0,0 +1,60 @@
+# HG changeset patch
+# User J. Ryan Stinnett <jryans@gmail.com>
+# Date 1503358960 18000
+#      Mon Aug 21 18:42:40 2017 -0500
+# Node ID 8acd319d4e34d051a36176d1cbdc958dab78ea0e
+# Parent  90e29632e2a19021ee687da92ee4dbeabeb50bae
+Bug 1392447 - Fix up Servo_StyleSheet_GetOrigin for Linux 32-bit ABI. r=emilio
+
+Bindgen bitfield enums don't work as return values with the Linux 32-bit ABI at
+the moment because they wrap the value in a struct.
+
+This causes the Rust side to believe the caller will pass along space for the
+struct return value, while C++ believes it's just an integer value.
+
+MozReview-Commit-ID: JHDp0XAmQCG
+
+diff --git a/layout/style/ServoBindingList.h b/layout/style/ServoBindingList.h
+--- a/layout/style/ServoBindingList.h
++++ b/layout/style/ServoBindingList.h
+@@ -50,18 +50,20 @@ SERVO_BINDING_FUNC(Servo_StyleSheet_HasR
+ SERVO_BINDING_FUNC(Servo_StyleSheet_GetRules, ServoCssRulesStrong,
+                    RawServoStyleSheetContentsBorrowed sheet)
+ SERVO_BINDING_FUNC(Servo_StyleSheet_Clone, RawServoStyleSheetContentsStrong,
+                    RawServoStyleSheetContentsBorrowed sheet,
+                    const mozilla::ServoStyleSheet* reference_sheet);
+ SERVO_BINDING_FUNC(Servo_StyleSheet_SizeOfIncludingThis, size_t,
+                    mozilla::MallocSizeOf malloc_size_of,
+                    RawServoStyleSheetContentsBorrowed sheet)
+-SERVO_BINDING_FUNC(Servo_StyleSheet_GetOrigin,
+-                   mozilla::OriginFlags,
++// We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
++// work as return values with the Linux 32-bit ABI at the moment because
++// they wrap the value in a struct.
++SERVO_BINDING_FUNC(Servo_StyleSheet_GetOrigin, uint8_t,
+                    RawServoStyleSheetContentsBorrowed sheet)
+ SERVO_BINDING_FUNC(Servo_StyleSet_Init, RawServoStyleSet*, RawGeckoPresContextOwned pres_context)
+ SERVO_BINDING_FUNC(Servo_StyleSet_RebuildCachedData, void,
+                    RawServoStyleSetBorrowed set)
+ // We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
+ // work as return values with the Linux 32-bit ABI at the moment because
+ // they wrap the value in a struct.
+ SERVO_BINDING_FUNC(Servo_StyleSet_MediumFeaturesChanged, uint8_t,
+diff --git a/layout/style/ServoStyleSheet.cpp b/layout/style/ServoStyleSheet.cpp
+--- a/layout/style/ServoStyleSheet.cpp
++++ b/layout/style/ServoStyleSheet.cpp
+@@ -461,12 +461,13 @@ ServoStyleSheet::SizeOfIncludingThis(Mal
+     s = s->mNext ? s->mNext->AsServo() : nullptr;
+   }
+   return n;
+ }
+ 
+ OriginFlags
+ ServoStyleSheet::GetOrigin()
+ {
+-  return Servo_StyleSheet_GetOrigin(Inner()->mContents);
++  return static_cast<OriginFlags>(
++    Servo_StyleSheet_GetOrigin(Inner()->mContents));
+ }
+ 
+ } // namespace mozilla

+ 52 - 0
frg/253-58/mozilla-release58_428173.patch

@@ -0,0 +1,52 @@
+# HG changeset patch
+# User Dão Gottwald <dao@mozilla.com>
+# Date 1503431833 -7200
+#      Tue Aug 22 21:57:13 2017 +0200
+# Node ID cf3a6dfc75c2701b4a3ded74d2470e79fbae63d3
+# Parent  186a696c793cb0fce989f3b5769e986705b13a0f
+Bug 1392633 - Stop removing the background in non-sidebar documents using places.css. r=nhnt11
+
+MozReview-Commit-ID: IShakSTE4Zj
+
+diff --git a/browser/themes/linux/places/places.css b/browser/themes/linux/places/places.css
+--- a/browser/themes/linux/places/places.css
++++ b/browser/themes/linux/places/places.css
+@@ -1,15 +1,16 @@
+ /* 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/. */
+ 
+ /* Sidebars */
+ 
+-:root {
++#history-panel,
++#bookmarksPanel {
+   -moz-appearance: none;
+   background-color: transparent;
+ }
+ 
+ #sidebar-search-container {
+   padding: 4px;
+ }
+ 
+diff --git a/browser/themes/windows/places/places.css b/browser/themes/windows/places/places.css
+--- a/browser/themes/windows/places/places.css
++++ b/browser/themes/windows/places/places.css
+@@ -1,15 +1,16 @@
+ /* 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/. */
+ 
+ /* Sidebars */
+ 
+-:root {
++#history-panel,
++#bookmarksPanel {
+   background-color: transparent;
+ }
+ 
+ #sidebar-search-container {
+   padding: 4px;
+ }
+ 
+ .sidebar-placesTree {

+ 1245 - 0
frg/253-58/mozilla-release58_428174.patch

@@ -0,0 +1,1245 @@
+# HG changeset patch
+# User David Keeler <dkeeler@mozilla.com>
+# Date 1502928419 25200
+#      Wed Aug 16 17:06:59 2017 -0700
+# Node ID c76c0f1fadfe1f981f1fe1e9ddaafb5bf80ef602
+# Parent  cf3a6dfc75c2701b4a3ded74d2470e79fbae63d3
+bug 1391404 - fold nsIPKCS11 into nsIPKCS11ModuleDB r=Cykesiopka
+
+This also moves the implementation of nsIPKCS11ModuleDB into its own file.
+
+MozReview-Commit-ID: LYXixzbx3Ia
+
+diff --git a/security/manager/pki/resources/content/device_manager.js b/security/manager/pki/resources/content/device_manager.js
+--- a/security/manager/pki/resources/content/device_manager.js
++++ b/security/manager/pki/resources/content/device_manager.js
+@@ -7,18 +7,16 @@ const nsIPKCS11Slot = Components.interfa
+ const nsIPKCS11Module = Components.interfaces.nsIPKCS11Module;
+ const nsPKCS11ModuleDB = "@mozilla.org/security/pkcs11moduledb;1";
+ const nsIPKCS11ModuleDB = Components.interfaces.nsIPKCS11ModuleDB;
+ const nsIPK11Token = Components.interfaces.nsIPK11Token;
+ const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1";
+ const nsIPK11TokenDB = Components.interfaces.nsIPK11TokenDB;
+ const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
+ const nsDialogParamBlock = "@mozilla.org/embedcomp/dialogparam;1";
+-const nsIPKCS11 = Components.interfaces.nsIPKCS11;
+-const nsPKCS11ContractID = "@mozilla.org/security/pkcs11;1";
+ 
+ var { Services } = Components.utils.import("resource://gre/modules/Services.jsm", {});
+ 
+ var bundle;
+ var secmoddb;
+ var skip_enable_buttons = false;
+ 
+ var smartCardObserver = {
+@@ -37,20 +35,16 @@ function LoadModules() {
+   bundle = document.getElementById("pippki_bundle");
+   secmoddb = Components.classes[nsPKCS11ModuleDB].getService(nsIPKCS11ModuleDB);
+   Services.obs.addObserver(smartCardObserver, "smartcard-insert");
+   Services.obs.addObserver(smartCardObserver, "smartcard-remove");
+ 
+   RefreshDeviceList();
+ }
+ 
+-function getPKCS11() {
+-  return Components.classes[nsPKCS11ContractID].getService(nsIPKCS11);
+-}
+-
+ function getNSSString(name) {
+   return document.getElementById("pipnss_bundle").getString(name);
+ }
+ 
+ function doPrompt(msg) {
+   let prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
+     getService(Components.interfaces.nsIPromptService);
+   prompts.alert(window, null, msg);
+@@ -351,17 +345,17 @@ function doLoad() {
+   RefreshDeviceList();
+ }
+ 
+ function deleteSelected() {
+   getSelectedItem();
+   if (selected_module &&
+       doConfirm(getNSSString("DelModuleWarning"))) {
+     try {
+-      getPKCS11().deleteModule(selected_module.name);
++      secmoddb.deleteModule(selected_module.name);
+     } catch (e) {
+       doPrompt(getNSSString("DelModuleError"));
+       return false;
+     }
+     selected_module = null;
+     return true;
+   }
+   return false;
+diff --git a/security/manager/pki/resources/content/load_device.js b/security/manager/pki/resources/content/load_device.js
+--- a/security/manager/pki/resources/content/load_device.js
++++ b/security/manager/pki/resources/content/load_device.js
+@@ -34,19 +34,20 @@ function onBrowseBtnPress() {
+  * ondialogaccept() handler.
+  *
+  * @returns {Boolean} true to make the dialog close, false otherwise.
+  */
+ function onDialogAccept() {
+   let bundle = document.getElementById("pipnss_bundle");
+   let nameBox = document.getElementById("device_name");
+   let pathBox = document.getElementById("device_path");
+-  let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
++  let pkcs11ModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
++                         .getService(Ci.nsIPKCS11ModuleDB);
+ 
+   try {
+-    pkcs11.addModule(nameBox.value, pathBox.value, 0, 0);
++    pkcs11ModuleDB.addModule(nameBox.value, pathBox.value, 0, 0);
+   } catch (e) {
+     alertPromptService(null, bundle.getString("AddModuleFailure"));
+     return false;
+   }
+ 
+   return true;
+ }
+diff --git a/security/manager/ssl/PKCS11.cpp b/security/manager/ssl/PKCS11ModuleDB.cpp
+rename from security/manager/ssl/PKCS11.cpp
+rename to security/manager/ssl/PKCS11ModuleDB.cpp
+--- a/security/manager/ssl/PKCS11.cpp
++++ b/security/manager/ssl/PKCS11ModuleDB.cpp
+@@ -1,49 +1,45 @@
+ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim: set ts=8 sts=2 et sw=2 tw=80: */
+ /* 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/. */
+ 
+-#include "PKCS11.h"
++#include "PKCS11ModuleDB.h"
+ 
+ #include "ScopedNSSTypes.h"
+ #include "mozilla/Telemetry.h"
+ #include "nsCRTGlue.h"
++#include "nsIMutableArray.h"
+ #include "nsNSSComponent.h"
+ #include "nsNativeCharsetUtils.h"
++#include "nsPKCS11Slot.h"
+ #include "nsServiceManagerUtils.h"
+ 
+ namespace mozilla { namespace psm {
+ 
+-NS_INTERFACE_MAP_BEGIN(PKCS11)
+-  NS_INTERFACE_MAP_ENTRY(nsIPKCS11)
+-  NS_INTERFACE_MAP_ENTRY(nsISupports)
+-NS_INTERFACE_MAP_END
++NS_IMPL_ISUPPORTS(PKCS11ModuleDB, nsIPKCS11ModuleDB)
+ 
+-NS_IMPL_ADDREF(PKCS11)
+-NS_IMPL_RELEASE(PKCS11)
+-
+-PKCS11::PKCS11()
++PKCS11ModuleDB::PKCS11ModuleDB()
+ {
+ }
+ 
+-PKCS11::~PKCS11()
++PKCS11ModuleDB::~PKCS11ModuleDB()
+ {
+   nsNSSShutDownPreventionLock locker;
+   if (isAlreadyShutDown()) {
+     return;
+   }
+   shutdown(ShutdownCalledFrom::Object);
+ }
+ 
+ // Delete a PKCS11 module from the user's profile.
+ NS_IMETHODIMP
+-PKCS11::DeleteModule(const nsAString& aModuleName)
++PKCS11ModuleDB::DeleteModule(const nsAString& aModuleName)
+ {
+   nsNSSShutDownPreventionLock locker;
+   if (isAlreadyShutDown()) {
+     return NS_ERROR_NOT_AVAILABLE;
+   }
+ 
+   if (aModuleName.IsEmpty()) {
+     return NS_ERROR_INVALID_ARG;
+@@ -99,20 +95,20 @@ GetModuleNameForTelemetry(/*in*/ const S
+   }
+   if (result.Length() >= 70) {
+     result.Truncate(69);
+   }
+ }
+ 
+ // Add a new PKCS11 module to the user's profile.
+ NS_IMETHODIMP
+-PKCS11::AddModule(const nsAString& aModuleName,
+-                  const nsAString& aLibraryFullPath,
+-                  int32_t aCryptoMechanismFlags,
+-                  int32_t aCipherFlags)
++PKCS11ModuleDB::AddModule(const nsAString& aModuleName,
++                          const nsAString& aLibraryFullPath,
++                          int32_t aCryptoMechanismFlags,
++                          int32_t aCipherFlags)
+ {
+   nsNSSShutDownPreventionLock locker;
+   if (isAlreadyShutDown()) {
+     return NS_ERROR_NOT_AVAILABLE;
+   }
+ 
+   if (aModuleName.IsEmpty()) {
+     return NS_ERROR_INVALID_ARG;
+@@ -150,9 +146,214 @@ PKCS11::AddModule(const nsAString& aModu
+   // (it wouldn't give us anything useful anyway).
+   if (scalarKey.Length() > 0) {
+     Telemetry::ScalarSet(Telemetry::ScalarID::SECURITY_PKCS11_MODULES_LOADED,
+                          scalarKey, true);
+   }
+   return NS_OK;
+ }
+ 
++NS_IMETHODIMP
++PKCS11ModuleDB::GetInternal(nsIPKCS11Module** _retval)
++{
++  NS_ENSURE_ARG_POINTER(_retval);
++
++  nsNSSShutDownPreventionLock locker;
++  if (isAlreadyShutDown()) {
++    return NS_ERROR_NOT_AVAILABLE;
++  }
++
++  UniqueSECMODModule nssMod(
++    SECMOD_CreateModule(nullptr, SECMOD_INT_NAME, nullptr, SECMOD_INT_FLAGS));
++  if (!nssMod) {
++    return NS_ERROR_FAILURE;
++  }
++
++  nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod.get());
++  module.forget(_retval);
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++PKCS11ModuleDB::GetInternalFIPS(nsIPKCS11Module** _retval)
++{
++  NS_ENSURE_ARG_POINTER(_retval);
++
++  nsNSSShutDownPreventionLock locker;
++  if (isAlreadyShutDown()) {
++    return NS_ERROR_NOT_AVAILABLE;
++  }
++
++  UniqueSECMODModule nssMod(
++    SECMOD_CreateModule(nullptr, SECMOD_FIPS_NAME, nullptr, SECMOD_FIPS_FLAGS));
++  if (!nssMod) {
++    return NS_ERROR_FAILURE;
++  }
++
++  nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod.get());
++  module.forget(_retval);
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++PKCS11ModuleDB::FindModuleByName(const nsACString& name,
++                         /*out*/ nsIPKCS11Module** _retval)
++{
++  NS_ENSURE_ARG_POINTER(_retval);
++
++  nsNSSShutDownPreventionLock locker;
++  if (isAlreadyShutDown()) {
++    return NS_ERROR_NOT_AVAILABLE;
++  }
++
++  nsresult rv = BlockUntilLoadableRootsLoaded();
++  if (NS_FAILED(rv)) {
++    return rv;
++  }
++
++  UniqueSECMODModule mod(SECMOD_FindModule(PromiseFlatCString(name).get()));
++  if (!mod) {
++    return NS_ERROR_FAILURE;
++  }
++
++  nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(mod.get());
++  module.forget(_retval);
++  return NS_OK;
++}
++
++/* This is essentially the same as nsIPK11Token::findTokenByName, except
++ * that it returns an nsIPKCS11Slot, which may be desired.
++ */
++NS_IMETHODIMP
++PKCS11ModuleDB::FindSlotByName(const nsACString& name,
++                       /*out*/ nsIPKCS11Slot** _retval)
++{
++  NS_ENSURE_ARG_POINTER(_retval);
++
++  nsNSSShutDownPreventionLock locker;
++  if (isAlreadyShutDown()) {
++    return NS_ERROR_NOT_AVAILABLE;
++  }
++
++  nsresult rv = BlockUntilLoadableRootsLoaded();
++  if (NS_FAILED(rv)) {
++    return rv;
++  }
++
++  if (name.IsEmpty()) {
++    return NS_ERROR_ILLEGAL_VALUE;
++  }
++
++  UniquePK11SlotInfo slotInfo(
++    PK11_FindSlotByName(PromiseFlatCString(name).get()));
++  if (!slotInfo) {
++    return NS_ERROR_FAILURE;
++  }
++
++  nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotInfo.get());
++  slot.forget(_retval);
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++PKCS11ModuleDB::ListModules(nsISimpleEnumerator** _retval)
++{
++  NS_ENSURE_ARG_POINTER(_retval);
++
++  nsNSSShutDownPreventionLock locker;
++  if (isAlreadyShutDown()) {
++    return NS_ERROR_NOT_AVAILABLE;
++  }
++
++  nsresult rv = BlockUntilLoadableRootsLoaded();
++  if (NS_FAILED(rv)) {
++    return rv;
++  }
++
++  nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
++  if (!array) {
++    return NS_ERROR_FAILURE;
++  }
++
++  /* lock down the list for reading */
++  AutoSECMODListReadLock lock;
++  for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
++       list = list->next) {
++    nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
++    nsresult rv = array->AppendElement(module, false);
++    if (NS_FAILED(rv)) {
++      return rv;
++    }
++  }
++
++  /* Get the modules in the database that didn't load */
++  for (SECMODModuleList* list = SECMOD_GetDeadModuleList(); list;
++       list = list->next) {
++    nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
++    nsresult rv = array->AppendElement(module, false);
++    if (NS_FAILED(rv)) {
++      return rv;
++    }
++  }
++
++  return array->Enumerate(_retval);
++}
++
++NS_IMETHODIMP
++PKCS11ModuleDB::GetCanToggleFIPS(bool* aCanToggleFIPS)
++{
++  NS_ENSURE_ARG_POINTER(aCanToggleFIPS);
++
++  nsNSSShutDownPreventionLock locker;
++  if (isAlreadyShutDown()) {
++    return NS_ERROR_NOT_AVAILABLE;
++  }
++
++  *aCanToggleFIPS = SECMOD_CanDeleteInternalModule();
++  return NS_OK;
++}
++
++
++NS_IMETHODIMP
++PKCS11ModuleDB::ToggleFIPSMode()
++{
++  nsNSSShutDownPreventionLock locker;
++  if (isAlreadyShutDown()) {
++    return NS_ERROR_NOT_AVAILABLE;
++  }
++
++  // The way to toggle FIPS mode in NSS is extremely obscure. Basically, we
++  // delete the internal module, and it gets replaced with the opposite module
++  // (i.e. if it was FIPS before, then it becomes non-FIPS next).
++  // SECMOD_GetInternalModule() returns a pointer to a local copy of the
++  // internal module stashed in NSS.  We don't want to delete it since it will
++  // cause much pain in NSS.
++  SECMODModule* internal = SECMOD_GetInternalModule();
++  if (!internal) {
++    return NS_ERROR_FAILURE;
++  }
++
++  if (SECMOD_DeleteInternalModule(internal->commonName) != SECSuccess) {
++    return NS_ERROR_FAILURE;
++  }
++
++  if (PK11_IsFIPS()) {
++    Telemetry::Accumulate(Telemetry::FIPS_ENABLED, true);
++  }
++
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++PKCS11ModuleDB::GetIsFIPSEnabled(bool* aIsFIPSEnabled)
++{
++  NS_ENSURE_ARG_POINTER(aIsFIPSEnabled);
++
++  nsNSSShutDownPreventionLock locker;
++  if (isAlreadyShutDown()) {
++    return NS_ERROR_NOT_AVAILABLE;
++  }
++
++  *aIsFIPSEnabled = PK11_IsFIPS();
++  return NS_OK;
++}
++
+ } } // namespace mozilla::psm
+diff --git a/security/manager/ssl/PKCS11.h b/security/manager/ssl/PKCS11ModuleDB.h
+rename from security/manager/ssl/PKCS11.h
+rename to security/manager/ssl/PKCS11ModuleDB.h
+--- a/security/manager/ssl/PKCS11.h
++++ b/security/manager/ssl/PKCS11ModuleDB.h
+@@ -1,40 +1,41 @@
+ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+  *
+  * 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/. */
+-#ifndef PKCS11_h
+-#define PKCS11_h
++#ifndef PKCS11ModuleDB_h
++#define PKCS11ModuleDB_h
+ 
+-#include "nsIPKCS11.h"
++#include "nsIPKCS11ModuleDB.h"
+ 
+ #include "nsNSSShutDown.h"
+ #include "nsString.h"
+ 
+ namespace mozilla { namespace psm {
+ 
+-#define NS_PKCS11_CID \
+-  {0x74b7a390, 0x3b41, 0x11d4, { 0x8a, 0x80, 0x00, 0x60, 0x08, 0xc8, 0x44, 0xc3} }
++#define NS_PKCS11MODULEDB_CID \
++{ 0xff9fbcd7, 0x9517, 0x4334, \
++  { 0xb9, 0x7a, 0xce, 0xed, 0x78, 0x90, 0x99, 0x74 }}
+ 
+-class PKCS11 : public nsIPKCS11
+-             , public nsNSSShutDownObject
++class PKCS11ModuleDB : public nsIPKCS11ModuleDB
++                     , public nsNSSShutDownObject
+ {
+ public:
+-  PKCS11();
++  PKCS11ModuleDB();
+ 
+   NS_DECL_ISUPPORTS
+-  NS_DECL_NSIPKCS11
++  NS_DECL_NSIPKCS11MODULEDB
+ 
+ protected:
+-  virtual ~PKCS11();
++  virtual ~PKCS11ModuleDB();
+ 
+ private:
+   virtual void virtualDestroyNSSReference() override {}
+ };
+ 
+ void GetModuleNameForTelemetry(/*in*/ const SECMODModule* module,
+                                /*out*/nsString& result);
+ 
+ } } // namespace mozilla::psm
+ 
+-#endif // PKCS11_h
++#endif // PKCS11ModuleDB_h
+diff --git a/security/manager/ssl/moz.build b/security/manager/ssl/moz.build
+--- a/security/manager/ssl/moz.build
++++ b/security/manager/ssl/moz.build
+@@ -24,17 +24,16 @@ XPIDL_SOURCES += [
+     'nsIKeygenThread.idl',
+     'nsIKeyModule.idl',
+     'nsILocalCertService.idl',
+     'nsINSSErrorsService.idl',
+     'nsINSSU2FToken.idl',
+     'nsINSSVersion.idl',
+     'nsIPK11Token.idl',
+     'nsIPK11TokenDB.idl',
+-    'nsIPKCS11.idl',
+     'nsIPKCS11Module.idl',
+     'nsIPKCS11ModuleDB.idl',
+     'nsIPKCS11Slot.idl',
+     'nsIProtectedAuthThread.idl',
+     'nsISecretDecoderRing.idl',
+     'nsISecurityUITelemetry.idl',
+     'nsISiteSecurityService.idl',
+     'nsISSLStatus.idl',
+@@ -129,17 +128,17 @@ UNIFIED_SOURCES += [
+     'nsRandomGenerator.cpp',
+     'nsSecureBrowserUIImpl.cpp',
+     'nsSecurityHeaderParser.cpp',
+     'NSSErrorsService.cpp',
+     'nsSiteSecurityService.cpp',
+     'nsSSLSocketProvider.cpp',
+     'nsSSLStatus.cpp',
+     'nsTLSSocketProvider.cpp',
+-    'PKCS11.cpp',
++    'PKCS11ModuleDB.cpp',
+     'PSMContentListener.cpp',
+     'PSMRunnable.cpp',
+     'PublicKeyPinningService.cpp',
+     'RootCertificateTelemetryUtils.cpp',
+     'SecretDecoderRing.cpp',
+     'SharedSSLState.cpp',
+     'SSLServerCertVerification.cpp',
+     'TransportSecurityInfo.cpp',
+diff --git a/security/manager/ssl/nsIPKCS11.idl b/security/manager/ssl/nsIPKCS11.idl
+deleted file mode 100644
+--- a/security/manager/ssl/nsIPKCS11.idl
++++ /dev/null
+@@ -1,22 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsISupports.idl"
+-
+-%{C++
+-#define NS_PKCS11_CONTRACTID "@mozilla.org/security/pkcs11;1"
+-%}
+-
+-[scriptable, uuid(5743f870-958e-4f02-aef2-c0afeef67f05)]
+-interface nsIPKCS11 : nsISupports
+-{
+-  [must_use]
+-  void deleteModule(in AString moduleName);
+-  [must_use]
+-  void addModule(in AString moduleName,
+-                 in AString libraryFullPath,
+-                 in long cryptoMechanismFlags,
+-                 in long cipherFlags);
+-};
+diff --git a/security/manager/ssl/nsIPKCS11ModuleDB.idl b/security/manager/ssl/nsIPKCS11ModuleDB.idl
+--- a/security/manager/ssl/nsIPKCS11ModuleDB.idl
++++ b/security/manager/ssl/nsIPKCS11ModuleDB.idl
+@@ -13,16 +13,25 @@ interface nsISimpleEnumerator;
+ %{C++
+ #define NS_PKCS11MODULEDB_CONTRACTID "@mozilla.org/security/pkcs11moduledb;1"
+ %}
+ 
+ [scriptable, uuid(ff9fbcd7-9517-4334-b97a-ceed78909974)]
+ interface nsIPKCS11ModuleDB : nsISupports
+ {
+   [must_use]
++  void deleteModule(in AString moduleName);
++
++  [must_use]
++  void addModule(in AString moduleName,
++                 in AString libraryFullPath,
++                 in long cryptoMechanismFlags,
++                 in long cipherFlags);
++
++  [must_use]
+   nsIPKCS11Module getInternal();
+ 
+   [must_use]
+   nsIPKCS11Module getInternalFIPS();
+ 
+   [must_use]
+   nsIPKCS11Module findModuleByName(in AUTF8String name);
+ 
+diff --git a/security/manager/ssl/nsNSSComponent.cpp b/security/manager/ssl/nsNSSComponent.cpp
+--- a/security/manager/ssl/nsNSSComponent.cpp
++++ b/security/manager/ssl/nsNSSComponent.cpp
+@@ -3,17 +3,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/. */
+ 
+ #include "nsNSSComponent.h"
+ 
+ #include "ExtendedValidation.h"
+ #include "NSSCertDBTrustDomain.h"
+-#include "PKCS11.h"
++#include "PKCS11ModuleDB.h"
+ #include "ScopedNSSTypes.h"
+ #include "SharedSSLState.h"
+ #include "cert.h"
+ #include "certdb.h"
+ #include "mozStorageCID.h"
+ #include "mozilla/ArrayUtils.h"
+ #include "mozilla/Assertions.h"
+ #include "mozilla/Casting.h"
+diff --git a/security/manager/ssl/nsNSSModule.cpp b/security/manager/ssl/nsNSSModule.cpp
+--- a/security/manager/ssl/nsNSSModule.cpp
++++ b/security/manager/ssl/nsNSSModule.cpp
+@@ -2,17 +2,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/. */
+ 
+ #include "CertBlocklist.h"
+ #include "ContentSignatureVerifier.h"
+ #include "NSSErrorsService.h"
+-#include "PKCS11.h"
++#include "PKCS11ModuleDB.h"
+ #include "PSMContentListener.h"
+ #include "SecretDecoderRing.h"
+ #include "TransportSecurityInfo.h"
+ #include "mozilla/ModuleUtils.h"
+ #include "nsCURILoader.h"
+ #include "nsCertOverrideService.h"
+ #include "nsCryptoHash.h"
+ #include "nsDataSignatureVerifier.h"
+@@ -141,17 +141,16 @@ NS_DEFINE_NAMED_CID(NS_PKCS11MODULEDB_CI
+ NS_DEFINE_NAMED_CID(NS_PSMCONTENTLISTEN_CID);
+ NS_DEFINE_NAMED_CID(NS_X509CERT_CID);
+ NS_DEFINE_NAMED_CID(NS_X509CERTDB_CID);
+ NS_DEFINE_NAMED_CID(NS_X509CERTLIST_CID);
+ NS_DEFINE_NAMED_CID(NS_FORMPROCESSOR_CID);
+ #ifdef MOZ_XUL
+ NS_DEFINE_NAMED_CID(NS_CERTTREE_CID);
+ #endif
+-NS_DEFINE_NAMED_CID(NS_PKCS11_CID);
+ NS_DEFINE_NAMED_CID(NS_CRYPTO_HASH_CID);
+ NS_DEFINE_NAMED_CID(NS_CRYPTO_HMAC_CID);
+ NS_DEFINE_NAMED_CID(NS_NTLMAUTHMODULE_CID);
+ NS_DEFINE_NAMED_CID(NS_KEYMODULEOBJECT_CID);
+ NS_DEFINE_NAMED_CID(NS_KEYMODULEOBJECTFACTORY_CID);
+ NS_DEFINE_NAMED_CID(NS_DATASIGNATUREVERIFIER_CID);
+ NS_DEFINE_NAMED_CID(NS_CONTENTSIGNATUREVERIFIER_CID);
+ NS_DEFINE_NAMED_CID(NS_CERTOVERRIDE_CID);
+@@ -169,28 +168,27 @@ static const mozilla::Module::CIDEntry k
+   { &kNS_NSSCOMPONENT_CID, false, nullptr, nsNSSComponentConstructor },
+   { &kNS_SSLSOCKETPROVIDER_CID, false, nullptr,
+     Constructor<nsSSLSocketProvider> },
+   { &kNS_STARTTLSSOCKETPROVIDER_CID, false, nullptr,
+     Constructor<nsTLSSocketProvider> },
+   { &kNS_SECRETDECODERRING_CID, false, nullptr,
+     Constructor<SecretDecoderRing> },
+   { &kNS_PK11TOKENDB_CID, false, nullptr, Constructor<nsPK11TokenDB> },
+-  { &kNS_PKCS11MODULEDB_CID, false, nullptr, Constructor<nsPKCS11ModuleDB> },
++  { &kNS_PKCS11MODULEDB_CID, false, nullptr, Constructor<PKCS11ModuleDB> },
+   { &kNS_PSMCONTENTLISTEN_CID, false, nullptr, PSMContentListenerConstructor },
+   { &kNS_X509CERT_CID, false, nullptr,
+     Constructor<nsNSSCertificate, nullptr, ProcessRestriction::AnyProcess> },
+   { &kNS_X509CERTDB_CID, false, nullptr, Constructor<nsNSSCertificateDB> },
+   { &kNS_X509CERTLIST_CID, false, nullptr,
+     Constructor<nsNSSCertList, nullptr, ProcessRestriction::AnyProcess> },
+   { &kNS_FORMPROCESSOR_CID, false, nullptr, nsKeygenFormProcessor::Create },
+ #ifdef MOZ_XUL
+   { &kNS_CERTTREE_CID, false, nullptr, Constructor<nsCertTree> },
+ #endif
+-  { &kNS_PKCS11_CID, false, nullptr, Constructor<PKCS11> },
+   { &kNS_CRYPTO_HASH_CID, false, nullptr,
+     Constructor<nsCryptoHash, nullptr, ProcessRestriction::AnyProcess> },
+   { &kNS_CRYPTO_HMAC_CID, false, nullptr,
+     Constructor<nsCryptoHMAC, nullptr, ProcessRestriction::AnyProcess> },
+   { &kNS_NTLMAUTHMODULE_CID, false, nullptr,
+     Constructor<nsNTLMAuthModule, &nsNTLMAuthModule::InitTest> },
+   { &kNS_KEYMODULEOBJECT_CID, false, nullptr,
+     Constructor<nsKeyObject, nullptr, ProcessRestriction::AnyProcess> },
+@@ -238,17 +236,16 @@ static const mozilla::Module::ContractID
+   { NS_PKCS11MODULEDB_CONTRACTID, &kNS_PKCS11MODULEDB_CID },
+   { NS_PSMCONTENTLISTEN_CONTRACTID, &kNS_PSMCONTENTLISTEN_CID },
+   { NS_X509CERTDB_CONTRACTID, &kNS_X509CERTDB_CID },
+   { NS_X509CERTLIST_CONTRACTID, &kNS_X509CERTLIST_CID },
+   { NS_FORMPROCESSOR_CONTRACTID, &kNS_FORMPROCESSOR_CID },
+ #ifdef MOZ_XUL
+   { NS_CERTTREE_CONTRACTID, &kNS_CERTTREE_CID },
+ #endif
+-  { NS_PKCS11_CONTRACTID, &kNS_PKCS11_CID },
+   { NS_CRYPTO_HASH_CONTRACTID, &kNS_CRYPTO_HASH_CID },
+   { NS_CRYPTO_HMAC_CONTRACTID, &kNS_CRYPTO_HMAC_CID },
+   { "@mozilla.org/uriloader/psm-external-content-listener;1", &kNS_PSMCONTENTLISTEN_CID },
+   { NS_NTLMAUTHMODULE_CONTRACTID, &kNS_NTLMAUTHMODULE_CID },
+   { NS_KEYMODULEOBJECT_CONTRACTID, &kNS_KEYMODULEOBJECT_CID },
+   { NS_KEYMODULEOBJECTFACTORY_CONTRACTID, &kNS_KEYMODULEOBJECTFACTORY_CID },
+   { NS_DATASIGNATUREVERIFIER_CONTRACTID, &kNS_DATASIGNATUREVERIFIER_CID },
+   { NS_CONTENTSIGNATUREVERIFIER_CONTRACTID, &kNS_CONTENTSIGNATUREVERIFIER_CID },
+diff --git a/security/manager/ssl/nsPKCS11Slot.cpp b/security/manager/ssl/nsPKCS11Slot.cpp
+--- a/security/manager/ssl/nsPKCS11Slot.cpp
++++ b/security/manager/ssl/nsPKCS11Slot.cpp
+@@ -355,229 +355,8 @@ nsPKCS11Module::ListSlots(nsISimpleEnume
+       if (NS_FAILED(rv)) {
+         return rv;
+       }
+     }
+   }
+ 
+   return array->Enumerate(_retval);
+ }
+-
+-NS_IMPL_ISUPPORTS(nsPKCS11ModuleDB, nsIPKCS11ModuleDB)
+-
+-nsPKCS11ModuleDB::nsPKCS11ModuleDB()
+-{
+-}
+-
+-nsPKCS11ModuleDB::~nsPKCS11ModuleDB()
+-{
+-  nsNSSShutDownPreventionLock locker;
+-  if (isAlreadyShutDown()) {
+-    return;
+-  }
+-
+-  shutdown(ShutdownCalledFrom::Object);
+-}
+-
+-NS_IMETHODIMP
+-nsPKCS11ModuleDB::GetInternal(nsIPKCS11Module** _retval)
+-{
+-  NS_ENSURE_ARG_POINTER(_retval);
+-
+-  nsNSSShutDownPreventionLock locker;
+-  if (isAlreadyShutDown()) {
+-    return NS_ERROR_NOT_AVAILABLE;
+-  }
+-
+-  UniqueSECMODModule nssMod(
+-    SECMOD_CreateModule(nullptr, SECMOD_INT_NAME, nullptr, SECMOD_INT_FLAGS));
+-  if (!nssMod) {
+-    return NS_ERROR_FAILURE;
+-  }
+-
+-  nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod.get());
+-  module.forget(_retval);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-nsPKCS11ModuleDB::GetInternalFIPS(nsIPKCS11Module** _retval)
+-{
+-  NS_ENSURE_ARG_POINTER(_retval);
+-
+-  nsNSSShutDownPreventionLock locker;
+-  if (isAlreadyShutDown()) {
+-    return NS_ERROR_NOT_AVAILABLE;
+-  }
+-
+-  UniqueSECMODModule nssMod(
+-    SECMOD_CreateModule(nullptr, SECMOD_FIPS_NAME, nullptr, SECMOD_FIPS_FLAGS));
+-  if (!nssMod) {
+-    return NS_ERROR_FAILURE;
+-  }
+-
+-  nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(nssMod.get());
+-  module.forget(_retval);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-nsPKCS11ModuleDB::FindModuleByName(const nsACString& name,
+-                           /*out*/ nsIPKCS11Module** _retval)
+-{
+-  NS_ENSURE_ARG_POINTER(_retval);
+-
+-  nsNSSShutDownPreventionLock locker;
+-  if (isAlreadyShutDown()) {
+-    return NS_ERROR_NOT_AVAILABLE;
+-  }
+-
+-  nsresult rv = BlockUntilLoadableRootsLoaded();
+-  if (NS_FAILED(rv)) {
+-    return rv;
+-  }
+-
+-  UniqueSECMODModule mod(SECMOD_FindModule(PromiseFlatCString(name).get()));
+-  if (!mod) {
+-    return NS_ERROR_FAILURE;
+-  }
+-
+-  nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(mod.get());
+-  module.forget(_retval);
+-  return NS_OK;
+-}
+-
+-/* This is essentially the same as nsIPK11Token::findTokenByName, except
+- * that it returns an nsIPKCS11Slot, which may be desired.
+- */
+-NS_IMETHODIMP
+-nsPKCS11ModuleDB::FindSlotByName(const nsACString& name,
+-                         /*out*/ nsIPKCS11Slot** _retval)
+-{
+-  NS_ENSURE_ARG_POINTER(_retval);
+-
+-  nsNSSShutDownPreventionLock locker;
+-  if (isAlreadyShutDown()) {
+-    return NS_ERROR_NOT_AVAILABLE;
+-  }
+-
+-  nsresult rv = BlockUntilLoadableRootsLoaded();
+-  if (NS_FAILED(rv)) {
+-    return rv;
+-  }
+-
+-  if (name.IsEmpty()) {
+-    return NS_ERROR_ILLEGAL_VALUE;
+-  }
+-
+-  UniquePK11SlotInfo slotInfo(
+-    PK11_FindSlotByName(PromiseFlatCString(name).get()));
+-  if (!slotInfo) {
+-    return NS_ERROR_FAILURE;
+-  }
+-
+-  nsCOMPtr<nsIPKCS11Slot> slot = new nsPKCS11Slot(slotInfo.get());
+-  slot.forget(_retval);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-nsPKCS11ModuleDB::ListModules(nsISimpleEnumerator** _retval)
+-{
+-  NS_ENSURE_ARG_POINTER(_retval);
+-
+-  nsNSSShutDownPreventionLock locker;
+-  if (isAlreadyShutDown()) {
+-    return NS_ERROR_NOT_AVAILABLE;
+-  }
+-
+-  nsresult rv = BlockUntilLoadableRootsLoaded();
+-  if (NS_FAILED(rv)) {
+-    return rv;
+-  }
+-
+-  nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
+-  if (!array) {
+-    return NS_ERROR_FAILURE;
+-  }
+-
+-  /* lock down the list for reading */
+-  AutoSECMODListReadLock lock;
+-  for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
+-       list = list->next) {
+-    nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
+-    nsresult rv = array->AppendElement(module, false);
+-    if (NS_FAILED(rv)) {
+-      return rv;
+-    }
+-  }
+-
+-  /* Get the modules in the database that didn't load */
+-  for (SECMODModuleList* list = SECMOD_GetDeadModuleList(); list;
+-       list = list->next) {
+-    nsCOMPtr<nsIPKCS11Module> module = new nsPKCS11Module(list->module);
+-    nsresult rv = array->AppendElement(module, false);
+-    if (NS_FAILED(rv)) {
+-      return rv;
+-    }
+-  }
+-
+-  return array->Enumerate(_retval);
+-}
+-
+-NS_IMETHODIMP
+-nsPKCS11ModuleDB::GetCanToggleFIPS(bool* aCanToggleFIPS)
+-{
+-  NS_ENSURE_ARG_POINTER(aCanToggleFIPS);
+-
+-  nsNSSShutDownPreventionLock locker;
+-  if (isAlreadyShutDown()) {
+-    return NS_ERROR_NOT_AVAILABLE;
+-  }
+-
+-  *aCanToggleFIPS = SECMOD_CanDeleteInternalModule();
+-  return NS_OK;
+-}
+-
+-
+-NS_IMETHODIMP
+-nsPKCS11ModuleDB::ToggleFIPSMode()
+-{
+-  nsNSSShutDownPreventionLock locker;
+-  if (isAlreadyShutDown()) {
+-    return NS_ERROR_NOT_AVAILABLE;
+-  }
+-
+-  // The way to toggle FIPS mode in NSS is extremely obscure. Basically, we
+-  // delete the internal module, and it gets replaced with the opposite module
+-  // (i.e. if it was FIPS before, then it becomes non-FIPS next).
+-  // SECMOD_GetInternalModule() returns a pointer to a local copy of the
+-  // internal module stashed in NSS.  We don't want to delete it since it will
+-  // cause much pain in NSS.
+-  SECMODModule* internal = SECMOD_GetInternalModule();
+-  if (!internal) {
+-    return NS_ERROR_FAILURE;
+-  }
+-
+-  if (SECMOD_DeleteInternalModule(internal->commonName) != SECSuccess) {
+-    return NS_ERROR_FAILURE;
+-  }
+-
+-  if (PK11_IsFIPS()) {
+-    Telemetry::Accumulate(Telemetry::FIPS_ENABLED, true);
+-  }
+-
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-nsPKCS11ModuleDB::GetIsFIPSEnabled(bool* aIsFIPSEnabled)
+-{
+-  NS_ENSURE_ARG_POINTER(aIsFIPSEnabled);
+-
+-  nsNSSShutDownPreventionLock locker;
+-  if (isAlreadyShutDown()) {
+-    return NS_ERROR_NOT_AVAILABLE;
+-  }
+-
+-  *aIsFIPSEnabled = PK11_IsFIPS();
+-  return NS_OK;
+-}
+diff --git a/security/manager/ssl/nsPKCS11Slot.h b/security/manager/ssl/nsPKCS11Slot.h
+--- a/security/manager/ssl/nsPKCS11Slot.h
++++ b/security/manager/ssl/nsPKCS11Slot.h
+@@ -4,17 +4,16 @@
+  * 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/. */
+ 
+ #ifndef nsPKCS11Slot_h
+ #define nsPKCS11Slot_h
+ 
+ #include "ScopedNSSTypes.h"
+ #include "nsIPKCS11Module.h"
+-#include "nsIPKCS11ModuleDB.h"
+ #include "nsIPKCS11Slot.h"
+ #include "nsISupports.h"
+ #include "nsNSSShutDown.h"
+ #include "nsString.h"
+ #include "pk11func.h"
+ 
+ class nsPKCS11Slot : public nsIPKCS11Slot,
+                      public nsNSSShutDownObject
+@@ -57,29 +56,9 @@ protected:
+ 
+ private:
+   mozilla::UniqueSECMODModule mModule;
+ 
+   virtual void virtualDestroyNSSReference() override;
+   void destructorSafeDestroyNSSReference();
+ };
+ 
+-class nsPKCS11ModuleDB : public nsIPKCS11ModuleDB
+-                       , public nsNSSShutDownObject
+-{
+-public:
+-  NS_DECL_ISUPPORTS
+-  NS_DECL_NSIPKCS11MODULEDB
+-
+-  nsPKCS11ModuleDB();
+-
+-protected:
+-  virtual ~nsPKCS11ModuleDB();
+-
+-  // Nothing to release.
+-  virtual void virtualDestroyNSSReference() override {}
+-};
+-
+-#define NS_PKCS11MODULEDB_CID \
+-{ 0xff9fbcd7, 0x9517, 0x4334, \
+-  { 0xb9, 0x7a, 0xce, 0xed, 0x78, 0x90, 0x99, 0x74 }}
+-
+ #endif // nsPKCS11Slot_h
+diff --git a/security/manager/ssl/tests/mochitest/browser/browser_loadPKCS11Module_ui.js b/security/manager/ssl/tests/mochitest/browser/browser_loadPKCS11Module_ui.js
+--- a/security/manager/ssl/tests/mochitest/browser/browser_loadPKCS11Module_ui.js
++++ b/security/manager/ssl/tests/mochitest/browser/browser_loadPKCS11Module_ui.js
+@@ -2,17 +2,17 @@
+ // http://creativecommons.org/publicdomain/zero/1.0/
+ "use strict";
+ 
+ // Tests the dialog used for loading PKCS #11 modules.
+ 
+ const { MockRegistrar } =
+   Cu.import("resource://testing-common/MockRegistrar.jsm", {});
+ 
+-const gMockPKCS11 = {
++const gMockPKCS11ModuleDB = {
+   addModuleCallCount: 0,
+   expectedLibPath: "",
+   expectedModuleName: "",
+   throwOnAddModule: false,
+ 
+   addModule(moduleName, libraryFullPath, cryptoMechanismFlags, cipherFlags) {
+     this.addModuleCallCount++;
+     Assert.equal(moduleName, this.expectedModuleName,
+@@ -28,17 +28,49 @@ const gMockPKCS11 = {
+       throw new Error(`addModule: Throwing exception`);
+     }
+   },
+ 
+   deleteModule(moduleName) {
+     Assert.ok(false, `deleteModule: should not be called`);
+   },
+ 
+-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPKCS11])
++  getInternal() {
++    throw new Error("not expecting getInternal() to be called");
++  },
++
++  getInternalFIPS() {
++    throw new Error("not expecting getInternalFIPS() to be called");
++  },
++
++  findModuleByName() {
++    throw new Error("not expecting findModuleByName() to be called");
++  },
++
++  findSlotByName() {
++    throw new Error("not expecting findSlotByName() to be called");
++  },
++
++  listModules() {
++    throw new Error("not expecting listModules() to be called");
++  },
++
++  get canToggleFIPS() {
++    throw new Error("not expecting get canToggleFIPS() to be called");
++  },
++
++  toggleFIPSMode() {
++    throw new Error("not expecting toggleFIPSMode() to be called");
++  },
++
++  get isFIPSEnabled() {
++    throw new Error("not expecting get isFIPSEnabled() to be called");
++  },
++
++  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPKCS11ModuleDB])
+ };
+ 
+ const gMockPromptService = {
+   alertCallCount: 0,
+   expectedText: "",
+   expectedWindow: null,
+ 
+   alert(parent, dialogTitle, text) {
+@@ -49,18 +81,18 @@ const gMockPromptService = {
+     Assert.equal(text, this.expectedText,
+                  "alert: Actual and expected text should match");
+   },
+ 
+   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptService])
+ };
+ 
+ var gMockPKCS11CID =
+-  MockRegistrar.register("@mozilla.org/security/pkcs11;1",
+-                         gMockPKCS11);
++  MockRegistrar.register("@mozilla.org/security/pkcs11moduledb;1",
++                         gMockPKCS11ModuleDB);
+ var gMockPromptServiceCID =
+   MockRegistrar.register("@mozilla.org/embedcomp/prompt-service;1",
+                          gMockPromptService);
+ 
+ var gMockFilePicker = SpecialPowers.MockFilePicker;
+ gMockFilePicker.init(window);
+ 
+ var gTempFile = Cc["@mozilla.org/file/directory_service;1"]
+@@ -70,17 +102,17 @@ gTempFile.append("browser_loadPKCS11Modu
+ 
+ registerCleanupFunction(() => {
+   gMockFilePicker.cleanup();
+   MockRegistrar.unregister(gMockPKCS11CID);
+   MockRegistrar.unregister(gMockPromptServiceCID);
+ });
+ 
+ function resetCallCounts() {
+-  gMockPKCS11.addModuleCallCount = 0;
++  gMockPKCS11ModuleDB.addModuleCallCount = 0;
+   gMockPromptService.alertCallCount = 0;
+ }
+ 
+ /**
+  * Opens the dialog shown to load a PKCS #11 module.
+  *
+  * @returns {Promise}
+  *          A promise that resolves when the dialog has finished loading, with
+@@ -139,63 +171,63 @@ add_task(async function testBrowseButton
+   Assert.equal(pathBox.value, gTempFile.path,
+                "Path shown should be same as the one chosen in the file picker");
+ 
+   await BrowserTestUtils.closeWindow(win);
+ });
+ 
+ function testAddModuleHelper(win, throwOnAddModule) {
+   resetCallCounts();
+-  gMockPKCS11.expectedLibPath = gTempFile.path;
+-  gMockPKCS11.expectedModuleName = "test module";
+-  gMockPKCS11.throwOnAddModule = throwOnAddModule;
++  gMockPKCS11ModuleDB.expectedLibPath = gTempFile.path;
++  gMockPKCS11ModuleDB.expectedModuleName = "test module";
++  gMockPKCS11ModuleDB.throwOnAddModule = throwOnAddModule;
+ 
+   win.document.getElementById("device_name").value =
+-    gMockPKCS11.expectedModuleName;
++    gMockPKCS11ModuleDB.expectedModuleName;
+   win.document.getElementById("device_path").value =
+-    gMockPKCS11.expectedLibPath;
++    gMockPKCS11ModuleDB.expectedLibPath;
+ 
+   info("Accepting dialog");
+   win.document.getElementById("loaddevice").acceptDialog();
+ }
+ 
+ add_task(async function testAddModuleSuccess() {
+   let win = await openLoadModuleDialog();
+ 
+   testAddModuleHelper(win, false);
+   await BrowserTestUtils.windowClosed(win);
+ 
+-  Assert.equal(gMockPKCS11.addModuleCallCount, 1,
++  Assert.equal(gMockPKCS11ModuleDB.addModuleCallCount, 1,
+                "addModule() should have been called once");
+   Assert.equal(gMockPromptService.alertCallCount, 0,
+                "alert() should never have been called");
+ });
+ 
+ add_task(async function testAddModuleFailure() {
+   let win = await openLoadModuleDialog();
+   gMockPromptService.expectedText = "Unable to add module";
+   gMockPromptService.expectedWindow = win;
+ 
+   testAddModuleHelper(win, true);
+   // If adding a module fails, the dialog will not close. As such, we have to
+   // close the window ourselves.
+   await BrowserTestUtils.closeWindow(win);
+ 
+-  Assert.equal(gMockPKCS11.addModuleCallCount, 1,
++  Assert.equal(gMockPKCS11ModuleDB.addModuleCallCount, 1,
+                "addModule() should have been called once");
+   Assert.equal(gMockPromptService.alertCallCount, 1,
+                "alert() should have been called once");
+ });
+ 
+ add_task(async function testCancel() {
+   let win = await openLoadModuleDialog();
+   resetCallCounts();
+ 
+   info("Canceling dialog");
+   win.document.getElementById("loaddevice").cancelDialog();
+ 
+-  Assert.equal(gMockPKCS11.addModuleCallCount, 0,
++  Assert.equal(gMockPKCS11ModuleDB.addModuleCallCount, 0,
+                "addModule() should never have been called");
+   Assert.equal(gMockPromptService.alertCallCount, 0,
+                "alert() should never have been called");
+ 
+   await BrowserTestUtils.windowClosed(win);
+ });
+diff --git a/security/manager/ssl/tests/unit/head_psm.js b/security/manager/ssl/tests/unit/head_psm.js
+--- a/security/manager/ssl/tests/unit/head_psm.js
++++ b/security/manager/ssl/tests/unit/head_psm.js
+@@ -843,26 +843,27 @@ function asyncTestCertificateUsages(cert
+  *                  module gets reported.
+  */
+ function loadPKCS11TestModule(expectModuleUnloadToFail) {
+   let libraryFile = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
+   libraryFile.append("pkcs11testmodule");
+   libraryFile.append(ctypes.libraryName("pkcs11testmodule"));
+   ok(libraryFile.exists(), "The pkcs11testmodule file should exist");
+ 
+-  let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
++  let pkcs11ModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
++                         .getService(Ci.nsIPKCS11ModuleDB);
+   do_register_cleanup(() => {
+     try {
+-      pkcs11.deleteModule("PKCS11 Test Module");
++      pkcs11ModuleDB.deleteModule("PKCS11 Test Module");
+     } catch (e) {
+       Assert.ok(expectModuleUnloadToFail,
+                 `Module unload should suceed only when expected: ${e}`);
+     }
+   });
+-  pkcs11.addModule("PKCS11 Test Module", libraryFile.path, 0, 0);
++  pkcs11ModuleDB.addModule("PKCS11 Test Module", libraryFile.path, 0, 0);
+ }
+ 
+ /**
+  * @param {String} data
+  * @returns {String}
+  */
+ function hexify(data) {
+   // |slice(-2)| chomps off the last two characters of a string.
+diff --git a/security/manager/ssl/tests/unit/test_pkcs11_module.js b/security/manager/ssl/tests/unit/test_pkcs11_module.js
+--- a/security/manager/ssl/tests/unit/test_pkcs11_module.js
++++ b/security/manager/ssl/tests/unit/test_pkcs11_module.js
+@@ -134,18 +134,19 @@ function run_test() {
+         bundle.GetStringFromName("PrivateSlotDescription"),
+         "Spot check: actual and expected internal 'slot' names should be equal");
+   throws(() => gModuleDB.findSlotByName("Not Present"), /NS_ERROR_FAILURE/,
+          "Non-present 'slot' should not be findable by name via the module DB");
+   throws(() => gModuleDB.findSlotByName(""), /NS_ERROR_ILLEGAL_VALUE/,
+          "nsIPKCS11ModuleDB.findSlotByName should throw given an empty name");
+ 
+   // Check that deleting the test module makes it disappear from the module list.
+-  let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
+-  pkcs11.deleteModule("PKCS11 Test Module");
++  let pkcs11ModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
++                         .getService(Ci.nsIPKCS11ModuleDB);
++  pkcs11ModuleDB.deleteModule("PKCS11 Test Module");
+   checkTestModuleNotPresent();
+ 
+   // Check miscellaneous module DB methods and attributes.
+   notEqual(gModuleDB.getInternal(), null,
+            "The internal module should be present");
+   notEqual(gModuleDB.getInternalFIPS(), null,
+            "The internal FIPS module should be present");
+   ok(gModuleDB.canToggleFIPS, "It should be possible to toggle FIPS");
+diff --git a/security/manager/ssl/tests/unit/test_pkcs11_no_events_after_removal.js b/security/manager/ssl/tests/unit/test_pkcs11_no_events_after_removal.js
+--- a/security/manager/ssl/tests/unit/test_pkcs11_no_events_after_removal.js
++++ b/security/manager/ssl/tests/unit/test_pkcs11_no_events_after_removal.js
+@@ -10,19 +10,20 @@
+ // "smartcard-remove", respectively. This test ensures that these events
+ // are no longer emitted once the module has been unloaded.
+ 
+ // Ensure that the appropriate initialization has happened.
+ do_get_profile();
+ Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
+ 
+ function run_test() {
+-  let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
++  let pkcs11ModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
++                         .getService(Ci.nsIPKCS11ModuleDB);
+   loadPKCS11TestModule(true);
+-  pkcs11.deleteModule("PKCS11 Test Module");
++  pkcs11ModuleDB.deleteModule("PKCS11 Test Module");
+   Services.obs.addObserver(function() {
+     ok(false, "smartcard-insert event should not have been emitted");
+   }, "smartcard-insert");
+   Services.obs.addObserver(function() {
+     ok(false, "smartcard-remove event should not have been emitted");
+   }, "smartcard-remove");
+   do_timeout(500, do_test_finished);
+   do_test_pending();
+diff --git a/security/manager/ssl/tests/unit/test_pkcs11_safe_mode.js b/security/manager/ssl/tests/unit/test_pkcs11_safe_mode.js
+--- a/security/manager/ssl/tests/unit/test_pkcs11_safe_mode.js
++++ b/security/manager/ssl/tests/unit/test_pkcs11_safe_mode.js
+@@ -33,17 +33,19 @@ function run_test() {
+ 
+   let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+   const XULRUNTIME_CONTRACTID = "@mozilla.org/xre/runtime;1";
+   const XULRUNTIME_CID = Components.ID("{f0f0b230-5525-4127-98dc-7bca39059e70}");
+   registrar.registerFactory(XULRUNTIME_CID, "XULRuntime", XULRUNTIME_CONTRACTID,
+                             xulRuntimeFactory);
+ 
+   // When starting in safe mode, the test module should fail to load.
+-  let pkcs11 = Cc["@mozilla.org/security/pkcs11;1"].getService(Ci.nsIPKCS11);
++  let pkcs11ModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
++                         .getService(Ci.nsIPKCS11ModuleDB);
+   let libraryName = ctypes.libraryName("pkcs11testmodule");
+   let libraryFile = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
+   libraryFile.append("pkcs11testmodule");
+   libraryFile.append(libraryName);
+   ok(libraryFile.exists(), "The pkcs11testmodule file should exist");
+-  throws(() => pkcs11.addModule("PKCS11 Test Module", libraryFile.path, 0, 0),
++  throws(() => pkcs11ModuleDB.addModule("PKCS11 Test Module", libraryFile.path,
++                                        0, 0),
+          /NS_ERROR_FAILURE/, "addModule should throw when in safe mode");
+ }

+ 120 - 0
frg/253-58/mozilla-release58_428175.patch

@@ -0,0 +1,120 @@
+# HG changeset patch
+# User Andrew McCreight <continuation@gmail.com>
+# Date 1503431470 25200
+#      Tue Aug 22 12:51:10 2017 -0700
+# Node ID a97cc606c12fe499368c0ef5c7ad8b1cefa4cd9d
+# Parent  c76c0f1fadfe1f981f1fe1e9ddaafb5bf80ef602
+Bug 1390692 - Remove the unnecessary second QI entry for nsCycleCollectionISupports. r=peterv
+
+MozReview-Commit-ID: 4o2QZhdomg2
+
+diff --git a/xpcom/base/nsAgg.h b/xpcom/base/nsAgg.h
+--- a/xpcom/base/nsAgg.h
++++ b/xpcom/base/nsAgg.h
+@@ -247,19 +247,34 @@ public:
+ NS_DEFINE_STATIC_IID_ACCESSOR(nsAggregatedCycleCollectionParticipant,
+                               NS_AGGREGATED_CYCLECOLLECTIONPARTICIPANT_IID)
+ 
+ // for use with QI macros in nsISupportsUtils.h:
+ 
+ #define NS_INTERFACE_MAP_BEGIN_AGGREGATED(_class)                           \
+   NS_IMPL_AGGREGATED_QUERY_HEAD(_class)
+ 
++#define NS_IMPL_QUERY_CYCLE_COLLECTION(_class)                              \
++  if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) {       \
++    *aInstancePtr = NS_CYCLE_COLLECTION_PARTICIPANT(_class);                \
++    return NS_OK;                                                           \
++  } else
++
+ #define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_AGGREGATED(_class)          \
+   NS_IMPL_QUERY_CYCLE_COLLECTION(_class)
+ 
++#define NS_IMPL_QUERY_CYCLE_COLLECTION_ISUPPORTS(_class)                    \
++  if ( aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) ) {              \
++    *aInstancePtr = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this);    \
++    return NS_OK;                                                           \
++  } else
++
++#define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class)           \
++  NS_IMPL_QUERY_CYCLE_COLLECTION_ISUPPORTS(_class)
++
+ #define NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(_class)        \
+   NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_AGGREGATED(_class)                \
+   NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class)
+ 
+ #define NS_IMPL_AGGREGATED_QUERY_HEAD(_class)                               \
+ nsresult                                                                    \
+ _class::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr)        \
+ {                                                                           \
+diff --git a/xpcom/base/nsCycleCollectionParticipant.h b/xpcom/base/nsCycleCollectionParticipant.h
+--- a/xpcom/base/nsCycleCollectionParticipant.h
++++ b/xpcom/base/nsCycleCollectionParticipant.h
+@@ -281,34 +281,22 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsXPCOMCyc
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+ // Helpers for implementing a QI to nsXPCOMCycleCollectionParticipant
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ #define NS_CYCLE_COLLECTION_CLASSNAME(_class)                                  \
+         _class::NS_CYCLE_COLLECTION_INNERCLASS
+ 
+-#define NS_IMPL_QUERY_CYCLE_COLLECTION(_class)                                 \
+-  if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) {          \
+-    *aInstancePtr = NS_CYCLE_COLLECTION_PARTICIPANT(_class);                   \
+-    return NS_OK;                                                              \
+-  } else
+-
+-#define NS_IMPL_QUERY_CYCLE_COLLECTION_ISUPPORTS(_class)                       \
+-  if ( aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) ) {                 \
+-    *aInstancePtr = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this);       \
+-    return NS_OK;                                                              \
+-  } else
+-
+ // The IIDs for nsXPCOMCycleCollectionParticipant and nsCycleCollectionISupports
+ // are special in that they only differ in their last byte.  This allows for the
+ // optimization below where we first check the first three words of the IID and
+ // if we find a match we check the last word to decide which case we have to
+ // deal with.
+-#define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(_class)                        \
++#define NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(_class)                      \
+   if (TopThreeWordsEquals(aIID, NS_GET_IID(nsXPCOMCycleCollectionParticipant), \
+                           NS_GET_IID(nsCycleCollectionISupports)) &&           \
+        /* The calls to LowWordEquals here are repeated inside the if branch.   \
+           This is due to the fact that we need to maintain the if/else chain   \
+           for these macros, so that the control flow never enters the if branch\
+           unless if we're certain one of the LowWordEquals() branches will get \
+           executed. */                                                         \
+       (LowWordEquals(aIID, NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ||   \
+@@ -321,31 +309,22 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsXPCOMCyc
+       *aInstancePtr = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this);     \
+       return NS_OK;                                                            \
+     } else {                                                                   \
+       /* Avoid warnings about foundInterface being left uninitialized. */      \
+       foundInterface = nullptr;                                                \
+     }                                                                          \
+   } else
+ 
+-#define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class)              \
+-  NS_IMPL_QUERY_CYCLE_COLLECTION_ISUPPORTS(_class)
+-
+-#define NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(_class)                      \
+-  NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(_class)                              \
+-  NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class)
+-
+ #define NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(_class)                        \
+   NS_INTERFACE_MAP_BEGIN(_class)                                               \
+     NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(_class)
+ 
+ #define NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(_class)              \
+-  NS_INTERFACE_MAP_BEGIN(_class)                                               \
+-    NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(_class)                            \
+-    NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class)
++  NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(_class)
+ 
+ #define NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(_class)  \
+   if (rv == NS_OK) return rv; \
+   nsISupports* foundInterface; \
+   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(_class)
+ 
+ // The IIDs for nsXPCOMCycleCollectionParticipant and nsCycleCollectionISupports
+ // are special in that they only differ in their last byte.  This allows for the

+ 81 - 0
frg/253-58/mozilla-release58_428177.patch

@@ -0,0 +1,81 @@
+# HG changeset patch
+# User J.C. Jones <jjones@mozilla.com>
+# Date 1503342375 25200
+#      Mon Aug 21 12:06:15 2017 -0700
+# Node ID 3b20b255ba275f5ee09b05e3adf0e0c8f979bd6d
+# Parent  c78673f78219da25139dd3f3d20accde51b38135
+Bug 1392366 - WebAuthn must use the WebCrypto SHA-256 algorithm identifier r=keeler
+
+WD-05 changed the "hashAlg" parameter of the CollectedClientData definition
+from using an internally-defined "S256" string to identify the sha256 digest
+to the definition in WebCrypto [1]. This only appears once, hard-coded in
+WebAuthn (since U2F only supports SHA-256), so we need to change that one
+instance.
+
+[1] https://www.w3.org/TR/WebCryptoAPI/#sha-registration
+
+MozReview-Commit-ID: 8de2CIGBBGA
+
+diff --git a/dom/webauthn/WebAuthnManager.cpp b/dom/webauthn/WebAuthnManager.cpp
+--- a/dom/webauthn/WebAuthnManager.cpp
++++ b/dom/webauthn/WebAuthnManager.cpp
+@@ -114,17 +114,17 @@ AssembleClientData(const nsAString& aOri
+   nsresult rv = aChallenge.ToJwkBase64(challengeBase64);
+   if (NS_WARN_IF(NS_FAILED(rv))) {
+     return NS_ERROR_FAILURE;
+   }
+ 
+   CollectedClientData clientDataObject;
+   clientDataObject.mChallenge.Assign(challengeBase64);
+   clientDataObject.mOrigin.Assign(aOrigin);
+-  clientDataObject.mHashAlg.Assign(NS_LITERAL_STRING("S256"));
++  clientDataObject.mHashAlg.Assign(NS_LITERAL_STRING("SHA-256"));
+ 
+   nsAutoString temp;
+   if (NS_WARN_IF(!clientDataObject.ToJSON(temp))) {
+     return NS_ERROR_FAILURE;
+   }
+ 
+   aJsonOut.Assign(NS_ConvertUTF16toUTF8(temp));
+   return NS_OK;
+diff --git a/dom/webauthn/tests/test_webauthn_loopback.html b/dom/webauthn/tests/test_webauthn_loopback.html
+--- a/dom/webauthn/tests/test_webauthn_loopback.html
++++ b/dom/webauthn/tests/test_webauthn_loopback.html
+@@ -56,17 +56,17 @@ function() {
+     ok(aCredInfo.rawId.length > 0, "Key ID exists");
+     is(aCredInfo.id, bytesToBase64UrlSafe(aCredInfo.rawId), "Encoded Key ID and Raw Key ID match");
+ 
+     let clientData = JSON.parse(buffer2string(aCredInfo.response.clientDataJSON));
+     is(clientData.challenge, bytesToBase64UrlSafe(gCredentialChallenge), "Challenge is correct");
+     // WD-05 vs. WD-06: In WD-06, the second parameter should be "window.location.origin". Fix
+     // this in Bug 1384776
+     is(clientData.origin, document.domain, "Origin is correct");
+-    is(clientData.hashAlg, "S256", "Hash algorithm is correct");
++    is(clientData.hashAlg, "SHA-256", "Hash algorithm is correct");
+ 
+     return webAuthnDecodeCBORAttestation(aCredInfo.response.attestationObject.buffer)
+     .then(function(decodedResult) {
+       ok(decodedResult.flags == (flag_TUP | flag_AT), "User presence and Attestation Object must both be set");
+ 
+       aCredInfo.clientDataObj = clientData;
+       aCredInfo.publicKeyHandle = decodedResult.publicKeyHandle;
+       aCredInfo.attestationObject = decodedResult.attestationObject;
+@@ -91,17 +91,17 @@ function() {
+     is(aAssertion.id, bytesToBase64UrlSafe(aAssertion.rawId), "Encoded Key ID and Raw Key ID match");
+ 
+     ok(aAssertion.response.authenticatorData.length > 0, "Authenticator data exists");
+     let clientData = JSON.parse(buffer2string(aAssertion.response.clientDataJSON));
+     is(clientData.challenge, bytesToBase64UrlSafe(gAssertionChallenge), "Challenge is correct");
+     // WD-05 vs. WD-06: In WD-06, the second parameter should be "window.location.origin". Fix
+     // this in Bug 1384776
+     is(clientData.origin, document.domain, "Origin is correct");
+-    is(clientData.hashAlg, "S256", "Hash algorithm is correct");
++    is(clientData.hashAlg, "SHA-256", "Hash algorithm is correct");
+ 
+     return webAuthnDecodeAttestation(aAssertion.response.authenticatorData)
+     .then(function(decodedResult) {
+       ok(decodedResult.flags == flag_TUP, "User presence must be the only flag set");
+       is(decodedResult.counter.length, 4, "Counter must be 4 bytes");
+       return deriveAppAndChallengeParam(window.location.host, aAssertion.response.clientDataJSON, decodedResult)
+     })
+     .then(function(aParams) {

+ 34 - 0
frg/253-58/mozilla-release58_428178.patch

@@ -0,0 +1,34 @@
+# HG changeset patch
+# User Tom Ritter <tom@mozilla.com>
+# Date 1503400869 18000
+#      Tue Aug 22 06:21:09 2017 -0500
+# Node ID 2fd8398e3868cabcc543428f9424013122c8a7fa
+# Parent  3b20b255ba275f5ee09b05e3adf0e0c8f979bd6d
+Bug 1392609 Find returns an int32_t not a uint32_t r=froydnj
+
+MozReview-Commit-ID: 8jBe7CGbAvM
+
+diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp
+old mode 100644
+new mode 100755
+--- a/xpcom/io/nsLocalFileWin.cpp
++++ b/xpcom/io/nsLocalFileWin.cpp
+@@ -1200,17 +1200,17 @@ CleanupHandlerPath(nsString& aPath)
+ 
+   int32_t lastCommaPos = aPath.RFindChar(',');
+   if (lastCommaPos != kNotFound)
+     aPath.Truncate(lastCommaPos);
+ 
+   aPath.Append(' ');
+ 
+   // case insensitive
+-  uint32_t index = aPath.Find(".exe ", true);
++  int32_t index = aPath.Find(".exe ", true);
+   if (index == kNotFound)
+     index = aPath.Find(".dll ", true);
+   if (index == kNotFound)
+     index = aPath.Find(".cpl ", true);
+ 
+   if (index != kNotFound)
+     aPath.Truncate(index + 4);
+   aPath.Trim(" ", true, true);

+ 48 - 0
frg/253-58/mozilla-release58_428179.patch

@@ -0,0 +1,48 @@
+# HG changeset patch
+# User Tom Ritter <tom@mozilla.com>
+# Date 1503410255 18000
+#      Tue Aug 22 08:57:35 2017 -0500
+# Node ID 653a497d1bae70a93a1130dc15e8becf400678d4
+# Parent  2fd8398e3868cabcc543428f9424013122c8a7fa
+Bug 1392618 Fix comparison between signed and unsigned integer expressions r=dmajor
+
+MozReview-Commit-ID: JCfPClnoe2H
+
+diff --git a/xpcom/build/nsWindowsDllInterceptor.h b/xpcom/build/nsWindowsDllInterceptor.h
+old mode 100644
+new mode 100755
+--- a/xpcom/build/nsWindowsDllInterceptor.h
++++ b/xpcom/build/nsWindowsDllInterceptor.h
+@@ -117,30 +117,30 @@ class WindowsDllNopSpacePatcher
+ {
+   typedef uint8_t* byteptr_t;
+   HMODULE mModule;
+ 
+   // Dumb array for remembering the addresses of functions we've patched.
+   // (This should be nsTArray, but non-XPCOM code uses this class.)
+   static const size_t maxPatchedFns = 16;
+   byteptr_t mPatchedFns[maxPatchedFns];
+-  int mPatchedFnsLen;
++  size_t mPatchedFnsLen;
+ 
+ public:
+   WindowsDllNopSpacePatcher()
+     : mModule(0)
+     , mPatchedFnsLen(0)
+   {}
+ 
+ #if defined(_M_IX86)
+   ~WindowsDllNopSpacePatcher()
+   {
+     // Restore the mov edi, edi to the beginning of each function we patched.
+ 
+-    for (int i = 0; i < mPatchedFnsLen; i++) {
++    for (size_t i = 0; i < mPatchedFnsLen; i++) {
+       byteptr_t fn = mPatchedFns[i];
+ 
+       // Ensure we can write to the code.
+       AutoVirtualProtect protect(fn, 2, PAGE_EXECUTE_READWRITE);
+       if (!protect.Protect()) {
+         continue;
+       }
+ 

+ 65 - 0
frg/253-58/mozilla-release58_428180.patch

@@ -0,0 +1,65 @@
+# HG changeset patch
+# User Tom Ritter <tom@mozilla.com>
+# Date 1503410999 18000
+#      Tue Aug 22 09:09:59 2017 -0500
+# Node ID fa99ada38d28fbe9a9d2535d7353b6c8fc067273
+# Parent  653a497d1bae70a93a1130dc15e8becf400678d4
+Bug 1392626 Fix warning about unused consoleName r=rstrong
+
+MozReview-Commit-ID: IRPnvHfELqs
+
+diff --git a/modules/libmar/sign/nss_secutil.c b/modules/libmar/sign/nss_secutil.c
+old mode 100644
+new mode 100755
+--- a/modules/libmar/sign/nss_secutil.c
++++ b/modules/libmar/sign/nss_secutil.c
+@@ -9,24 +9,16 @@
+ 
+ #include "prprf.h"
+ #ifdef XP_WIN
+ #include <io.h>
+ #else
+ #include <unistd.h>
+ #endif
+ 
+-static char consoleName[] =  {
+-#ifdef XP_UNIX
+-  "/dev/tty"
+-#else
+-  "CON:"
+-#endif
+-};
+-
+ #if defined(_WINDOWS)
+ static char * quiet_fgets (char *buf, int length, FILE *input)
+ {
+   int c;
+   char *end = buf;
+ 
+   /* fflush (input); */
+   memset (buf, 0, length);
+@@ -63,16 +55,24 @@ char *
+ GetPasswordString(void *arg, char *prompt)
+ {
+   FILE *input = stdin;
+   char phrase[200] = {'\0'};
+   int isInputTerminal = isatty(fileno(stdin));
+ 
+ #ifndef _WINDOWS
+   if (isInputTerminal) {
++    static char consoleName[] =  {
++#ifdef XP_UNIX
++      "/dev/tty"
++#else
++      "CON:"
++#endif
++    };
++
+     input = fopen(consoleName, "r");
+     if (input == NULL) {
+       fprintf(stderr, "Error opening input terminal for read\n");
+       return NULL;
+     }
+   }
+ #endif 
+ 

+ 61 - 0
frg/253-58/mozilla-release58_428181.patch

@@ -0,0 +1,61 @@
+# HG changeset patch
+# User Tom Ritter <tom@mozilla.com>
+# Date 1503411391 18000
+#      Tue Aug 22 09:16:31 2017 -0500
+# Node ID 2375fd212b94d88587c08e9dc1d651ea5f8e9527
+# Parent  fa99ada38d28fbe9a9d2535d7353b6c8fc067273
+Bug 1392630 Remove unused variables r=froydnj
+
+MozReview-Commit-ID: eSbnMzdWZm
+
+diff --git a/xpcom/build/LateWriteChecks.cpp b/xpcom/build/LateWriteChecks.cpp
+old mode 100644
+new mode 100755
+--- a/xpcom/build/LateWriteChecks.cpp
++++ b/xpcom/build/LateWriteChecks.cpp
+@@ -135,17 +135,17 @@ LateWriteObserver::Observe(IOInterposeOb
+ 
+   // We want the sha1 of the entire file, so please don't write to fd
+   // directly; use sha1Stream.
+   FILE* stream;
+ #ifdef XP_WIN
+   HANDLE hFile;
+   do {
+     // mkstemp isn't supported so keep trying until we get a file
+-    int result = _mktemp_s(name, strlen(name) + 1);
++    _mktemp_s(name, strlen(name) + 1);
+     hFile = CreateFileA(name, GENERIC_WRITE, 0, nullptr, CREATE_NEW,
+                         FILE_ATTRIBUTE_NORMAL, nullptr);
+   } while (GetLastError() == ERROR_FILE_EXISTS);
+ 
+   if (hFile == INVALID_HANDLE_VALUE) {
+     MOZ_CRASH("Um, how did we get here?");
+   }
+ 
+diff --git a/xpcom/io/SpecialSystemDirectory.cpp b/xpcom/io/SpecialSystemDirectory.cpp
+old mode 100644
+new mode 100755
+--- a/xpcom/io/SpecialSystemDirectory.cpp
++++ b/xpcom/io/SpecialSystemDirectory.cpp
+@@ -118,19 +118,18 @@ SHLoadLibraryFromKnownFolder(REFKNOWNFOL
+  * through aFolderId.
+  */
+ static nsresult
+ GetLibrarySaveToPath(int aFallbackFolderId, REFKNOWNFOLDERID aFolderId,
+                      nsIFile** aFile)
+ {
+   RefPtr<IShellLibrary> shellLib;
+   RefPtr<IShellItem> savePath;
+-  HRESULT hr =
+-    SHLoadLibraryFromKnownFolder(aFolderId, STGM_READ,
+-                                 IID_IShellLibrary, getter_AddRefs(shellLib));
++  SHLoadLibraryFromKnownFolder(aFolderId, STGM_READ,
++                               IID_IShellLibrary, getter_AddRefs(shellLib));
+ 
+   if (shellLib &&
+       SUCCEEDED(shellLib->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem,
+                                                getter_AddRefs(savePath)))) {
+     wchar_t* str = nullptr;
+     if (SUCCEEDED(savePath->GetDisplayName(SIGDN_FILESYSPATH, &str))) {
+       nsAutoString path;
+       path.Assign(str);

+ 159 - 0
frg/253-58/mozilla-release58_428182.patch

@@ -0,0 +1,159 @@
+# HG changeset patch
+# User Brian Murray <bmurray7jhu@gmail.com>
+# Date 1499820307 25200
+#      Tue Jul 11 17:45:07 2017 -0700
+# Node ID 0d4f763f4080dd595f4fa4962ab4781c70e87d84
+# Parent  2375fd212b94d88587c08e9dc1d651ea5f8e9527
+Bug 1380204: Improve error handling in XZStream.cpp r=glandium
+
+Report init failure if uncompressed stream size is 0.
+Check for overflows when casting.
+Verify LZMA stream only has a single block.
+Detailed error logging.
+MozReview-Commit-ID: DZ4cWGxAzkw
+
+diff --git a/mozglue/linker/XZStream.cpp b/mozglue/linker/XZStream.cpp
+--- a/mozglue/linker/XZStream.cpp
++++ b/mozglue/linker/XZStream.cpp
+@@ -1,13 +1,13 @@
+ #include "XZStream.h"
+ 
+ #include <algorithm>
+-#include <cstring>
+ #include "mozilla/Assertions.h"
++#include "mozilla/CheckedInt.h"
+ #include "Logging.h"
+ 
+ // LZMA dictionary size, should have a minimum size for the given compression
+ // rate, see XZ Utils docs for details.
+ static const uint32_t kDictSize = 1 << 24;
+ 
+ static const size_t kFooterSize = 12;
+ 
+@@ -67,16 +67,19 @@ XZStream::Init()
+ 
+   mDec = xz_dec_init(XZ_DYNALLOC, kDictSize);
+ 
+   if (!mDec) {
+     return false;
+   }
+ 
+   mUncompSize = ParseUncompressedSize();
++  if (!mUncompSize) {
++    return false;
++  }
+ 
+   return true;
+ }
+ 
+ size_t
+ XZStream::Decode(void* aOutBuf, size_t aOutSize)
+ {
+   if (!mDec) {
+@@ -159,56 +162,76 @@ XZStream::ParseIndexSize() const
+   static const uint8_t kFooterMagic[] = {'Y', 'Z'};
+ 
+   const uint8_t* footer = mInBuf + mBuffers.in_size - kFooterSize;
+   // The magic bytes are at the end of the footer.
+   if (memcmp(reinterpret_cast<const void*>(kFooterMagic),
+              footer + kFooterSize - sizeof(kFooterMagic),
+              sizeof(kFooterMagic))) {
+     // Not a valid footer at stream end.
++    ERROR("XZ parsing: Invalid footer at end of stream");
+     return 0;
+   }
+   // Backward size is a 32 bit LE integer field positioned after the 32 bit CRC32
+   // code. It encodes the index size as a multiple of 4 bytes with a minimum
+   // size of 4 bytes.
+-  const uint32_t backwardSize = *(footer + 4);
+-  return (backwardSize + 1) * 4;
++  const uint32_t backwardSizeRaw = *(footer + 4);
++  // Check for overflow.
++  mozilla::CheckedInt<size_t> backwardSizeBytes(backwardSizeRaw);
++  backwardSizeBytes = (backwardSizeBytes + 1) * 4;
++  if (!backwardSizeBytes.isValid()) {
++    ERROR("XZ parsing: Cannot parse index size");
++    return 0;
++  }
++  return backwardSizeBytes.value();
+ }
+ 
+ size_t
+ XZStream::ParseUncompressedSize() const
+ {
+   static const uint8_t kIndexIndicator[] = {0x0};
+ 
+   const size_t indexSize = ParseIndexSize();
+   if (!indexSize) {
+     return 0;
+   }
+   // The footer follows directly the index, so we can use it as a reference.
+   const uint8_t* end = mInBuf + mBuffers.in_size;
+   const uint8_t* index = end - kFooterSize - indexSize;
+ 
+-  // The index consists of a one byte indicator followed by a VLI field for the
+-  // number of records (1 expected) followed by a list of records. One record
+-  // contains a VLI field for unpadded size followed by a VLI field for
+-  // uncompressed size.
++  // The xz stream index consists of three concatenated elements:
++  //  (1) 1 byte indicator (always OxOO)
++  //  (2) a Variable Length Integer (VLI) field for the number of records
++  //  (3) a list of records
++  // See https://tukaani.org/xz/xz-file-format-1.0.4.txt
++  // Each record contains a VLI field for unpadded size followed by a var field for
++  // uncompressed size. We only support xz streams with a single record.
++
+   if (memcmp(reinterpret_cast<const void*>(kIndexIndicator),
+              index, sizeof(kIndexIndicator))) {
+-    // Not a valid index.
++    ERROR("XZ parsing: Invalid stream index");
+     return 0;
+   }
+ 
+   index += sizeof(kIndexIndicator);
+   uint64_t numRecords = 0;
+   index += ParseVarLenInt(index, end - index, &numRecords);
+-  if (!numRecords) {
++  // Only streams with a single record are supported.
++  if (numRecords != 1) {
++    ERROR("XZ parsing: Multiple records not supported");
+     return 0;
+   }
+   uint64_t unpaddedSize = 0;
+   index += ParseVarLenInt(index, end - index, &unpaddedSize);
+   if (!unpaddedSize) {
++    ERROR("XZ parsing: Unpadded size is 0");
+     return 0;
+   }
+   uint64_t uncompressedSize = 0;
+   index += ParseVarLenInt(index, end - index, &uncompressedSize);
++  mozilla::CheckedInt<size_t> checkedSize(uncompressedSize);
++  if (!checkedSize.isValid()) {
++    ERROR("XZ parsing: Uncompressed stream size is too large");
++    return 0;
++  }
+ 
+-  return uncompressedSize;
++  return checkedSize.value();
+ }
+diff --git a/mozglue/linker/XZStream.h b/mozglue/linker/XZStream.h
+--- a/mozglue/linker/XZStream.h
++++ b/mozglue/linker/XZStream.h
+@@ -1,16 +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/. */
+ 
+ #ifndef XZSTREAM_h
+ #define XZSTREAM_h
+ 
+ #include <cstdlib>
++#include <stdint.h>
+ 
+ #define XZ_DEC_DYNALLOC
+ #include "xz.h"
+ 
+ // Used to decode XZ stream buffers.
+ class XZStream
+ {
+ public:

+ 1802 - 0
frg/253-58/mozilla-release58_428183.patch

@@ -0,0 +1,1802 @@
+# HG changeset patch
+# User Anthony Ramine <n.oxyde@gmail.com>
+# Date 1503431591 18000
+#      Tue Aug 22 14:53:11 2017 -0500
+# Node ID 088f0310b8c1da915eb0a23d007c52847b5341d8
+# Parent  0d4f763f4080dd595f4fa4962ab4781c70e87d84
+servo: Merge #18192 - Derive Animate and ToAnimatedZero (from servo:we-are-leaving-babylon); r=emilio
+
+ONLY PARSE NEEDS DERIVING NOW. THE HYPE IS REAL.
+
+Source-Repo: https://github.com/servo/servo
+Source-Revision: ec2dae90685da47c17cde9011736c893b037ff01
+
+diff --git a/servo/components/style/macros.rs b/servo/components/style/macros.rs
+--- a/servo/components/style/macros.rs
++++ b/servo/components/style/macros.rs
+@@ -79,30 +79,20 @@ macro_rules! add_impls_for_keyword_enum 
+         no_viewport_percentage!($name);
+     };
+ }
+ 
+ macro_rules! define_keyword_type {
+     ($name: ident, $css: expr) => {
+         #[allow(missing_docs)]
+         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-        #[derive(Clone, ComputeSquaredDistance, Copy, PartialEq, ToCss)]
++        #[derive(Animate, Clone, ComputeSquaredDistance, Copy, PartialEq)]
++        #[derive(ToAnimatedZero, ToCss)]
+         pub struct $name;
+ 
+-        impl $crate::values::animated::Animate for $name {
+-            #[inline]
+-            fn animate(
+-                &self,
+-                _other: &Self,
+-                _procedure: $crate::values::animated::Procedure,
+-            ) -> Result<Self, ()> {
+-                Ok($name)
+-            }
+-        }
+-
+         impl fmt::Debug for $name {
+             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                 write!(f, $css)
+             }
+         }
+ 
+         impl $crate::parser::Parse for $name {
+             fn parse<'i, 't>(_context: &$crate::parser::ParserContext,
+@@ -110,15 +100,10 @@ macro_rules! define_keyword_type {
+                              -> Result<$name, ::style_traits::ParseError<'i>> {
+                 input.expect_ident_matching($css).map(|_| $name).map_err(|e| e.into())
+             }
+         }
+ 
+         impl $crate::values::computed::ComputedValueAsSpecified for $name {}
+         impl $crate::values::animated::AnimatedValueAsComputed for $name {}
+         no_viewport_percentage!($name);
+-
+-        impl $crate::values::animated::ToAnimatedZero for $name {
+-            #[inline]
+-            fn to_animated_zero(&self) -> Result<Self, ()> { Ok($name) }
+-        }
+     };
+ }
+diff --git a/servo/components/style/properties/helpers.mako.rs b/servo/components/style/properties/helpers.mako.rs
+--- a/servo/components/style/properties/helpers.mako.rs
++++ b/servo/components/style/properties/helpers.mako.rs
+@@ -117,35 +117,28 @@
+             use smallvec::{IntoIter, SmallVec};
+             % endif
+             use values::computed::ComputedVecIter;
+ 
+             /// The computed value, effectively a list of single values.
+             #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+             #[derive(Clone, Debug, PartialEq)]
+             % if need_animatable or animation_value_type == "ComputedValue":
+-            #[derive(ComputeSquaredDistance)]
++            #[derive(Animate, ComputeSquaredDistance)]
+             % endif
+             pub struct T(
+                 % if allow_empty and allow_empty != "NotInitial":
+                 pub Vec<single_value::T>,
+                 % else:
+                 pub SmallVec<[single_value::T; 1]>,
+                 % endif
+             );
+ 
+             % if need_animatable or animation_value_type == "ComputedValue":
+-                use values::animated::{Animate, Procedure, ToAnimatedZero};
+-
+-                impl Animate for T {
+-                    #[inline]
+-                    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-                        Ok(T(self.0.animate(&other.0, procedure)?))
+-                    }
+-                }
++                use values::animated::{ToAnimatedZero};
+ 
+                 impl ToAnimatedZero for T {
+                     #[inline]
+                     fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+                 }
+             % endif
+ 
+             pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>;
+diff --git a/servo/components/style/properties/helpers/animated_properties.mako.rs b/servo/components/style/properties/helpers/animated_properties.mako.rs
+--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
++++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
+@@ -49,17 +49,17 @@ use values::computed::{Angle, BorderCorn
+ use values::computed::{ClipRect, Context, ComputedUrl, ComputedValueAsSpecified};
+ use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
+ use values::computed::{LengthOrPercentageOrNone, MaxLength, MozLength, NonNegativeAu};
+ use values::computed::{NonNegativeNumber, Number, NumberOrPercentage, Percentage};
+ use values::computed::{PositiveIntegerOrAuto, ToComputedValue};
+ use values::computed::length::{NonNegativeLengthOrAuto, NonNegativeLengthOrNormal};
+ use values::computed::length::NonNegativeLengthOrPercentage;
+ use values::distance::{ComputeSquaredDistance, SquaredDistance};
+-use values::generics::{GreaterThanOrEqualToOne, NonNegative};
++use values::generics::NonNegative;
+ use values::generics::effects::Filter;
+ use values::generics::position as generic_position;
+ use values::generics::svg::{SVGLength,  SvgLengthOrPercentageOrNumber, SVGPaint};
+ use values::generics::svg::{SVGPaintKind, SVGStrokeDashArray, SVGOpacity};
+ 
+ /// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list
+ pub trait RepeatableListAnimatable: Animate {}
+ 
+@@ -874,33 +874,16 @@ impl Animate for LengthOrPercentage {
+                 let this = CalcLengthOrPercentage::from(*this);
+                 let other = CalcLengthOrPercentage::from(*other);
+                 Ok(LengthOrPercentage::Calc(this.animate(&other, procedure)?))
+             }
+         }
+     }
+ }
+ 
+-impl ToAnimatedZero for LengthOrPercentage {
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-         match *self {
+-             LengthOrPercentage::Length(ref length) => {
+-                 Ok(LengthOrPercentage::Length(length.to_animated_zero()?))
+-             },
+-             LengthOrPercentage::Percentage(ref percentage) => {
+-                 Ok(LengthOrPercentage::Percentage(percentage.to_animated_zero()?))
+-             },
+-             LengthOrPercentage::Calc(ref calc) => {
+-                 Ok(LengthOrPercentage::Calc(calc.to_animated_zero()?))
+-             },
+-         }
+-    }
+-}
+-
+ /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+ impl Animate for LengthOrPercentageOrAuto {
+     #[inline]
+     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             (
+                 &LengthOrPercentageOrAuto::Length(ref this),
+                 &LengthOrPercentageOrAuto::Length(ref other),
+@@ -1115,60 +1098,19 @@ impl Into<FontStretch> for f64 {
+         let index = (self + 0.5).floor().min(9.0).max(1.0);
+         static FONT_STRETCH_ENUM_MAP: [FontStretch; 9] =
+             [ ultra_condensed, extra_condensed, condensed, semi_condensed, normal,
+               semi_expanded, expanded, extra_expanded, ultra_expanded ];
+         FONT_STRETCH_ENUM_MAP[(index - 1.0) as usize]
+     }
+ }
+ 
+-impl<H, V> Animate for generic_position::Position<H, V>
+-where
+-    H: Animate,
+-    V: Animate,
+-{
+-    #[inline]
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(generic_position::Position {
+-            horizontal: self.horizontal.animate(&other.horizontal, procedure)?,
+-            vertical: self.vertical.animate(&other.vertical, procedure)?,
+-        })
+-    }
+-}
+-
+-impl<H, V> ToAnimatedZero for generic_position::Position<H, V>
+-where
+-    H: ToAnimatedZero,
+-    V: ToAnimatedZero,
+-{
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-        Ok(generic_position::Position {
+-            horizontal: self.horizontal.to_animated_zero()?,
+-            vertical: self.vertical.to_animated_zero()?,
+-        })
+-    }
+-}
+-
+ impl<H, V> RepeatableListAnimatable for generic_position::Position<H, V>
+     where H: RepeatableListAnimatable, V: RepeatableListAnimatable {}
+ 
+-/// https://drafts.csswg.org/css-transitions/#animtype-rect
+-impl Animate for ClipRect {
+-    #[inline]
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(ClipRect {
+-            top: self.top.animate(&other.top, procedure)?,
+-            right: self.right.animate(&other.right, procedure)?,
+-            bottom: self.bottom.animate(&other.bottom, procedure)?,
+-            left: self.left.animate(&other.left, procedure)?,
+-        })
+-    }
+-}
+-
+ impl ToAnimatedZero for ClipRect {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+ }
+ 
+ /// Build an equivalent 'identity transform function list' based
+ /// on an existing transform list.
+ /// http://dev.w3.org/csswg/css-transforms/#none-transform-animation
+@@ -1348,18 +1290,18 @@ fn rotate_to_matrix(x: f32, y: f32, z: f
+ // distance from each matrix item, and this makes the result different from that in Gecko if we
+ // have skew factor in the ComputedMatrix.
+ pub struct InnerMatrix2D {
+     pub m11: CSSFloat, pub m12: CSSFloat,
+     pub m21: CSSFloat, pub m22: CSSFloat,
+ }
+ 
+ /// A 2d translation function.
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug)]
+ pub struct Translate2D(f32, f32);
+ 
+ /// A 2d scale function.
+ #[derive(Clone, ComputeSquaredDistance, Copy, Debug)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ pub struct Scale2D(f32, f32);
+ 
+ /// A decomposed 2d matrix.
+@@ -1382,25 +1324,16 @@ impl Animate for InnerMatrix2D {
+             m11: animate_multiplicative_factor(self.m11, other.m11, procedure)?,
+             m12: self.m12.animate(&other.m12, procedure)?,
+             m21: self.m21.animate(&other.m21, procedure)?,
+             m22: animate_multiplicative_factor(self.m22, other.m22, procedure)?,
+         })
+     }
+ }
+ 
+-impl Animate for Translate2D {
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(Translate2D(
+-            self.0.animate(&other.0, procedure)?,
+-            self.1.animate(&other.1, procedure)?,
+-        ))
+-    }
+-}
+-
+ impl Animate for Scale2D {
+     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(Scale2D(
+             animate_multiplicative_factor(self.0, other.0, procedure)?,
+             animate_multiplicative_factor(self.1, other.1, procedure)?,
+         ))
+     }
+ }
+@@ -1622,28 +1555,28 @@ impl From<ComputedMatrix> for RawGeckoGf
+         [ matrix.m11, matrix.m12, matrix.m13, matrix.m14,
+           matrix.m21, matrix.m22, matrix.m23, matrix.m24,
+           matrix.m31, matrix.m32, matrix.m33, matrix.m34,
+           matrix.m41, matrix.m42, matrix.m43, matrix.m44 ]
+     }
+ }
+ 
+ /// A 3d translation.
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug)]
+ pub struct Translate3D(f32, f32, f32);
+ 
+ /// A 3d scale function.
+ #[derive(Clone, ComputeSquaredDistance, Copy, Debug)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ pub struct Scale3D(f32, f32, f32);
+ 
+ /// A 3d skew function.
+-#[derive(Clone, Copy, Debug)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
++#[derive(Animate, Clone, Copy, Debug)]
+ pub struct Skew(f32, f32, f32);
+ 
+ /// A 3d perspective transformation.
+ #[derive(Clone, ComputeSquaredDistance, Copy, Debug)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ pub struct Perspective(f32, f32, f32, f32);
+ 
+ /// A quaternion used to represent a rotation.
+@@ -1915,46 +1848,26 @@ fn dot(a: [f32; 3], b: [f32; 3]) -> f32 
+ fn cross(row1: [f32; 3], row2: [f32; 3]) -> [f32; 3] {
+     [
+         row1[1] * row2[2] - row1[2] * row2[1],
+         row1[2] * row2[0] - row1[0] * row2[2],
+         row1[0] * row2[1] - row1[1] * row2[0]
+     ]
+ }
+ 
+-impl Animate for Translate3D {
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(Translate3D(
+-            self.0.animate(&other.0, procedure)?,
+-            self.1.animate(&other.1, procedure)?,
+-            self.2.animate(&other.2, procedure)?,
+-        ))
+-    }
+-}
+-
+ impl Animate for Scale3D {
+     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         Ok(Scale3D(
+             animate_multiplicative_factor(self.0, other.0, procedure)?,
+             animate_multiplicative_factor(self.1, other.1, procedure)?,
+             animate_multiplicative_factor(self.2, other.2, procedure)?,
+         ))
+     }
+ }
+ 
+-impl Animate for Skew {
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(Skew(
+-            self.0.animate(&other.0, procedure)?,
+-            self.1.animate(&other.1, procedure)?,
+-            self.2.animate(&other.2, procedure)?,
+-        ))
+-    }
+-}
+-
+ impl ComputeSquaredDistance for Skew {
+     // We have to use atan() to convert the skew factors into skew angles, so implement
+     // ComputeSquaredDistance manually.
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+         Ok(self.0.atan().compute_squared_distance(&other.0.atan())? +
+            self.1.atan().compute_squared_distance(&other.1.atan())? +
+            self.2.atan().compute_squared_distance(&other.2.atan())?)
+@@ -2459,35 +2372,16 @@ impl ToAnimatedZero for TransformList {
+                 Ok(TransformList(Some(
+                     list.iter().map(|op| op.to_animated_zero()).collect::<Result<Vec<_>, _>>()?
+                 )))
+             },
+         }
+     }
+ }
+ 
+-impl<T, U> Animate for Either<T, U>
+-where
+-    T: Animate,
+-    U: Animate,
+-{
+-    #[inline]
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        match (self, other) {
+-            (&Either::First(ref this), &Either::First(ref other)) => {
+-                Ok(Either::First(this.animate(other, procedure)?))
+-            },
+-            (&Either::Second(ref this), &Either::Second(ref other)) => {
+-                Ok(Either::Second(this.animate(other, procedure)?))
+-            },
+-            _ => Err(()),
+-        }
+-    }
+-}
+-
+ impl<A, B> ToAnimatedZero for Either<A, B>
+ where
+     A: ToAnimatedZero,
+     B: ToAnimatedZero,
+ {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         match *self {
+@@ -2684,38 +2578,16 @@ where
+                     NumberOrPercentage::Percentage(this.animate(other, procedure)?)
+                 ))
+             },
+             _ => Err(()),
+         }
+     }
+ }
+ 
+-impl<L, N> ToAnimatedZero for SvgLengthOrPercentageOrNumber<L, N>
+-where
+-    L: ToAnimatedZero,
+-    N: ToAnimatedZero,
+-{
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-        match *self {
+-            SvgLengthOrPercentageOrNumber::LengthOrPercentage(ref lop) => {
+-                Ok(SvgLengthOrPercentageOrNumber::LengthOrPercentage(
+-                    lop.to_animated_zero()?,
+-                ))
+-            },
+-            SvgLengthOrPercentageOrNumber::Number(ref num) => {
+-                Ok(SvgLengthOrPercentageOrNumber::Number(
+-                    num.to_animated_zero()?,
+-                ))
+-            },
+-        }
+-    }
+-}
+-
+ impl<L> Animate for SVGLength<L>
+ where
+     L: Animate + Clone,
+ {
+     #[inline]
+     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             (&SVGLength::Length(ref this), &SVGLength::Length(ref other)) => {
+@@ -2727,31 +2599,16 @@ where
+                 // an interpolation.
+                 let (this_weight, other_weight) = procedure.weights();
+                 Ok(if this_weight > other_weight { self.clone() } else { other.clone() })
+             },
+         }
+     }
+ }
+ 
+-impl<L> ToAnimatedZero for SVGLength<L>
+-where
+-    L: ToAnimatedZero,
+-{
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-        match *self {
+-            SVGLength::Length(ref length) => {
+-                Ok(SVGLength::Length(length.to_animated_zero()?))
+-            },
+-            SVGLength::ContextValue => Ok(SVGLength::ContextValue),
+-        }
+-    }
+-}
+-
+ /// https://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty
+ impl<L> Animate for SVGStrokeDashArray<L>
+ where
+     L: Clone + RepeatableListAnimatable,
+ {
+     #[inline]
+     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         if matches!(procedure, Procedure::Add | Procedure::Accumulate { .. }) {
+@@ -2767,17 +2624,17 @@ where
+                 Ok(if this_weight > other_weight { self.clone() } else { other.clone() })
+             },
+         }
+     }
+ }
+ 
+ impl<L> ToAnimatedZero for SVGStrokeDashArray<L>
+ where
+-    L: Clone + ToAnimatedZero
++    L: ToAnimatedZero,
+ {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         match *self {
+             SVGStrokeDashArray::Values(ref values) => {
+                 Ok(SVGStrokeDashArray::Values(
+                     values.iter().map(ToAnimatedZero::to_animated_zero).collect::<Result<Vec<_>, _>>()?,
+                 ))
+@@ -2803,29 +2660,16 @@ where
+                 // an interpolation.
+                 let (this_weight, other_weight) = procedure.weights();
+                 Ok(if this_weight > other_weight { self.clone() } else { other.clone() })
+             },
+         }
+     }
+ }
+ 
+-impl<OpacityType> ToAnimatedZero for SVGOpacity<OpacityType>
+-    where OpacityType: ToAnimatedZero + Clone
+-{
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-        match self {
+-            &SVGOpacity::Opacity(ref opacity) =>
+-                opacity.to_animated_zero().map(SVGOpacity::Opacity),
+-            other => Ok(other.clone()),
+-        }
+-    }
+-}
+-
+ <%
+     FILTER_FUNCTIONS = [ 'Blur', 'Brightness', 'Contrast', 'Grayscale',
+                          'HueRotate', 'Invert', 'Opacity', 'Saturate',
+                          'Sepia' ]
+ %>
+ 
+ /// https://drafts.fxtf.org/filters/#animation-of-filters
+ impl Animate for AnimatedFilter {
+@@ -2872,17 +2716,16 @@ impl ToAnimatedZero for AnimatedFilter {
+             % if product == "gecko":
+             Filter::DropShadow(ref this) => Ok(Filter::DropShadow(this.to_animated_zero()?)),
+             % endif
+             _ => Err(()),
+         }
+     }
+ }
+ 
+-
+ // FIXME(nox): This should be derived.
+ impl ComputeSquaredDistance for AnimatedFilter {
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+         match (self, other) {
+             % for func in FILTER_FUNCTIONS:
+             (&Filter::${func}(ref this), &Filter::${func}(ref other)) => {
+                 this.compute_squared_distance(other)
+             },
+@@ -2988,46 +2831,8 @@ sorted_shorthands = sorted(data.shorthan
+ sorted_shorthands = [(p, position) for position, p in enumerate(sorted_shorthands)]
+ %>
+     match *shorthand {
+         % for property, position in sorted_shorthands:
+             ShorthandId::${property.camel_case} => ${position},
+         % endfor
+     }
+ }
+-
+-impl<T> Animate for NonNegative<T>
+-where
+-    T: Animate,
+-{
+-    #[inline]
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(NonNegative(self.0.animate(&other.0, procedure)?))
+-    }
+-}
+-
+-impl<T> ToAnimatedZero for NonNegative<T>
+-    where T: ToAnimatedZero
+-{
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-        self.0.to_animated_zero().map(NonNegative::<T>)
+-    }
+-}
+-
+-impl<T> Animate for GreaterThanOrEqualToOne<T>
+-where
+-    T: Animate,
+-{
+-    #[inline]
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(GreaterThanOrEqualToOne(self.0.animate(&other.0, procedure)?))
+-    }
+-}
+-
+-impl<T> ToAnimatedZero for GreaterThanOrEqualToOne<T>
+-    where T: ToAnimatedZero
+-{
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-        self.0.to_animated_zero().map(GreaterThanOrEqualToOne::<T>)
+-    }
+-}
+diff --git a/servo/components/style/properties/longhand/inherited_table.mako.rs b/servo/components/style/properties/longhand/inherited_table.mako.rs
+--- a/servo/components/style/properties/longhand/inherited_table.mako.rs
++++ b/servo/components/style/properties/longhand/inherited_table.mako.rs
+@@ -21,37 +21,26 @@
+                          spec="https://drafts.csswg.org/css-tables/#propdef-caption-side")}
+ 
+ <%helpers:longhand name="border-spacing" animation_value_type="BorderSpacing" boxed="True"
+                    spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing">
+     use values::specified::{AllowQuirks, Length};
+     use values::specified::length::NonNegativeLength;
+ 
+     pub mod computed_value {
+-        use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
++        use values::animated::{ToAnimatedValue, ToAnimatedZero};
+         use values::computed::NonNegativeAu;
+ 
+         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-        #[derive(Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)]
++        #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)]
+         pub struct T {
+             pub horizontal: NonNegativeAu,
+             pub vertical: NonNegativeAu,
+         }
+ 
+-        /// https://drafts.csswg.org/css-transitions/#animtype-simple-list
+-        impl Animate for T {
+-            #[inline]
+-            fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-                Ok(T {
+-                    horizontal: self.horizontal.animate(&other.horizontal, procedure)?,
+-                    vertical: self.vertical.animate(&other.vertical, procedure)?,
+-                })
+-            }
+-        }
+-
+         impl ToAnimatedZero for T {
+             #[inline]
+             fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+         }
+ 
+         impl ToAnimatedValue for T {
+             type AnimatedValue = Self;
+ 
+diff --git a/servo/components/style/values/animated/color.rs b/servo/components/style/values/animated/color.rs
+--- a/servo/components/style/values/animated/color.rs
++++ b/servo/components/style/values/animated/color.rs
+@@ -7,17 +7,17 @@
+ use values::animated::{Animate, Procedure, ToAnimatedZero};
+ use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ 
+ /// An animated RGBA color.
+ ///
+ /// Unlike in computed values, each component value may exceed the
+ /// range `[0.0, 1.0]`.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, Copy, Debug, PartialEq)]
++#[derive(Clone, Copy, Debug, PartialEq, ToAnimatedZero)]
+ pub struct RGBA {
+     /// The red component.
+     pub red: f32,
+     /// The green component.
+     pub green: f32,
+     /// The blue component.
+     pub blue: f32,
+     /// The alpha component.
+@@ -64,23 +64,16 @@ impl ComputeSquaredDistance for RGBA {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+         let start = [ self.alpha, self.red * self.alpha, self.green * self.alpha, self.blue * self.alpha ];
+         let end = [ other.alpha, other.red * other.alpha, other.green * other.alpha, other.blue * other.alpha ];
+         start.iter().zip(&end).map(|(this, other)| this.compute_squared_distance(other)).sum()
+     }
+ }
+ 
+-impl ToAnimatedZero for RGBA {
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-        Ok(RGBA::transparent())
+-    }
+-}
+-
+ #[allow(missing_docs)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ #[derive(Clone, Copy, Debug, PartialEq)]
+ pub struct Color {
+     pub color: RGBA,
+     pub foreground_ratio: f32,
+ }
+ 
+diff --git a/servo/components/style/values/animated/effects.rs b/servo/components/style/values/animated/effects.rs
+--- a/servo/components/style/values/animated/effects.rs
++++ b/servo/components/style/values/animated/effects.rs
+@@ -134,16 +134,17 @@ impl ToAnimatedValue for ComputedTextSha
+     }
+ 
+     #[inline]
+     fn from_animated_value(animated: Self::AnimatedValue) -> Self {
+         ComputedTextShadowList(ToAnimatedValue::from_animated_value(animated.0))
+     }
+ }
+ 
++// FIXME(nox): This could be derived if we implement Animate for bool.
+ impl Animate for BoxShadow {
+     #[inline]
+     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         if self.inset != other.inset {
+             return Err(());
+         }
+         Ok(BoxShadow {
+             base: self.base.animate(&other.base, procedure)?,
+@@ -206,32 +207,8 @@ impl ToAnimatedValue for ComputedFilterL
+ }
+ 
+ impl ToAnimatedZero for FilterList {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> {
+         Ok(FilterList(vec![]))
+     }
+ }
+-
+-impl Animate for SimpleShadow {
+-    #[inline]
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(SimpleShadow {
+-            color: self.color.animate(&other.color, procedure)?,
+-            horizontal: self.horizontal.animate(&other.horizontal, procedure)?,
+-            vertical: self.vertical.animate(&other.vertical, procedure)?,
+-            blur: self.blur.animate(&other.blur, procedure)?,
+-        })
+-    }
+-}
+-
+-impl ToAnimatedZero for SimpleShadow {
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-        Ok(SimpleShadow {
+-            color: self.color.to_animated_zero()?,
+-            horizontal: self.horizontal.to_animated_zero()?,
+-            vertical: self.vertical.to_animated_zero()?,
+-            blur: self.blur.to_animated_zero()?,
+-        })
+-    }
+-}
+diff --git a/servo/components/style/values/computed/angle.rs b/servo/components/style/values/computed/angle.rs
+--- a/servo/components/style/values/computed/angle.rs
++++ b/servo/components/style/values/computed/angle.rs
+@@ -3,22 +3,22 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ //! Computed angles.
+ 
+ use std::{f32, f64, fmt};
+ use std::f64::consts::PI;
+ use style_traits::ToCss;
+ use values::CSSFloat;
+-use values::animated::{Animate, Procedure, ToAnimatedZero};
++use values::animated::{Animate, Procedure};
+ use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ 
+ /// A computed angle.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
+-#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, PartialOrd)]
++#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, PartialOrd, ToAnimatedZero)]
+ pub enum Angle {
+     /// An angle with degree unit.
+     Degree(CSSFloat),
+     /// An angle with gradian unit.
+     Gradian(CSSFloat),
+     /// An angle with radian unit.
+     Radian(CSSFloat),
+     /// An angle with turn unit.
+@@ -80,28 +80,16 @@ impl Animate for Angle {
+             },
+             _ => {
+                 Ok(Angle::from_radians(self.radians().animate(&other.radians(), procedure)?))
+             },
+         }
+     }
+ }
+ 
+-impl ToAnimatedZero for Angle {
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Angle, ()> {
+-        match *self {
+-            Angle::Degree(ref this) => Ok(Angle::Degree(this.to_animated_zero()?)),
+-            Angle::Gradian(ref this) => Ok(Angle::Gradian(this.to_animated_zero()?)),
+-            Angle::Radian(ref this) => Ok(Angle::Radian(this.to_animated_zero()?)),
+-            Angle::Turn(ref this) => Ok(Angle::Turn(this.to_animated_zero()?)),
+-        }
+-    }
+-}
+-
+ impl ComputeSquaredDistance for Angle {
+     #[inline]
+     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+         // Use the formula for calculating the distance between angles defined in SVG:
+         // https://www.w3.org/TR/SVG/animate.html#complexDistances
+         self.radians64().compute_squared_distance(&other.radians64())
+     }
+ }
+diff --git a/servo/components/style/values/computed/length.rs b/servo/components/style/values/computed/length.rs
+--- a/servo/components/style/values/computed/length.rs
++++ b/servo/components/style/values/computed/length.rs
+@@ -281,17 +281,17 @@ impl ToComputedValue for specified::Calc
+             percentage: computed.percentage,
+             ..Default::default()
+         }
+     }
+ }
+ 
+ #[allow(missing_docs)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, Copy, PartialEq, ToCss)]
++#[derive(Clone, Copy, PartialEq, ToAnimatedZero, ToCss)]
+ pub enum LengthOrPercentage {
+     Length(Au),
+     Percentage(Percentage),
+     Calc(CalcLengthOrPercentage),
+ }
+ 
+ impl ComputeSquaredDistance for LengthOrPercentage {
+     #[inline]
+diff --git a/servo/components/style/values/computed/mod.rs b/servo/components/style/values/computed/mod.rs
+--- a/servo/components/style/values/computed/mod.rs
++++ b/servo/components/style/values/computed/mod.rs
+@@ -434,17 +434,17 @@ pub type PositiveIntegerOrAuto = Either<
+ /// <length> | <percentage> | <number>
+ pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>;
+ 
+ /// NonNegativeLengthOrPercentage | NonNegativeNumber
+ pub type NonNegativeLengthOrPercentageOrNumber = Either<NonNegativeNumber, NonNegativeLengthOrPercentage>;
+ 
+ #[allow(missing_docs)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, Eq, PartialEq)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Eq, PartialEq)]
+ /// A computed cliprect for clip and image-region
+ pub struct ClipRect {
+     pub top: Option<Au>,
+     pub right: Option<Au>,
+     pub bottom: Option<Au>,
+     pub left: Option<Au>,
+ }
+ 
+diff --git a/servo/components/style/values/computed/percentage.rs b/servo/components/style/values/computed/percentage.rs
+--- a/servo/components/style/values/computed/percentage.rs
++++ b/servo/components/style/values/computed/percentage.rs
+@@ -2,21 +2,21 @@
+  * 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/. */
+ 
+ //! Computed percentages.
+ 
+ use std::fmt;
+ use style_traits::ToCss;
+ use values::{CSSFloat, serialize_percentage};
+-use values::animated::{Animate, Procedure, ToAnimatedZero};
+ 
+ /// A computed percentage.
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, Default, HasViewportPercentage, PartialEq, PartialOrd)]
+ #[cfg_attr(feature = "servo", derive(Deserialize, HeapSizeOf, Serialize))]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default)]
++#[derive(HasViewportPercentage, PartialEq, PartialOrd, ToAnimatedZero)]
+ pub struct Percentage(pub CSSFloat);
+ 
+ impl Percentage {
+     /// 0%
+     #[inline]
+     pub fn zero() -> Self {
+         Percentage(0.)
+     }
+@@ -29,31 +29,16 @@ impl Percentage {
+ 
+     /// Returns the absolute value for this percentage.
+     #[inline]
+     pub fn abs(&self) -> Self {
+         Percentage(self.0.abs())
+     }
+ }
+ 
+-/// https://drafts.csswg.org/css-transitions/#animtype-percentage
+-impl Animate for Percentage {
+-    #[inline]
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(Percentage(self.0.animate(&other.0, procedure)?))
+-    }
+-}
+-
+-impl ToAnimatedZero for Percentage {
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-        Ok(Percentage(0.))
+-    }
+-}
+-
+ impl ToCss for Percentage {
+     fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+     where
+         W: fmt::Write,
+     {
+         serialize_percentage(self.0, dest)
+     }
+ }
+diff --git a/servo/components/style/values/computed/text.rs b/servo/components/style/values/computed/text.rs
+--- a/servo/components/style/values/computed/text.rs
++++ b/servo/components/style/values/computed/text.rs
+@@ -1,16 +1,16 @@
+ /* 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/. */
+ 
+ //! Computed types for text properties.
+ 
+ use values::{CSSInteger, CSSFloat};
+-use values::animated::{Animate, Procedure, ToAnimatedZero};
++use values::animated::ToAnimatedZero;
+ use values::computed::{NonNegativeAu, NonNegativeNumber};
+ use values::computed::length::{Length, LengthOrPercentage};
+ use values::generics::text::InitialLetter as GenericInitialLetter;
+ use values::generics::text::LineHeight as GenericLineHeight;
+ use values::generics::text::Spacing;
+ 
+ /// A computed value for the `initial-letter` property.
+ pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
+@@ -19,34 +19,12 @@ pub type InitialLetter = GenericInitialL
+ pub type LetterSpacing = Spacing<Length>;
+ 
+ /// A computed value for the `word-spacing` property.
+ pub type WordSpacing = Spacing<LengthOrPercentage>;
+ 
+ /// A computed value for the `line-height` property.
+ pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeAu>;
+ 
+-impl Animate for LineHeight {
+-    #[inline]
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        match (self, other) {
+-            (&GenericLineHeight::Length(ref this), &GenericLineHeight::Length(ref other)) => {
+-                Ok(GenericLineHeight::Length(this.animate(other, procedure)?))
+-            },
+-            (&GenericLineHeight::Number(ref this), &GenericLineHeight::Number(ref other)) => {
+-                Ok(GenericLineHeight::Number(this.animate(other, procedure)?))
+-            },
+-            (&GenericLineHeight::Normal, &GenericLineHeight::Normal) => {
+-                Ok(GenericLineHeight::Normal)
+-            },
+-            #[cfg(feature = "gecko")]
+-            (&GenericLineHeight::MozBlockHeight, &GenericLineHeight::MozBlockHeight) => {
+-                Ok(GenericLineHeight::MozBlockHeight)
+-            },
+-            _ => Err(()),
+-        }
+-    }
+-}
+-
+ impl ToAnimatedZero for LineHeight {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+ }
+diff --git a/servo/components/style/values/computed/transform.rs b/servo/components/style/values/computed/transform.rs
+--- a/servo/components/style/values/computed/transform.rs
++++ b/servo/components/style/values/computed/transform.rs
+@@ -1,15 +1,14 @@
+ /* 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/. */
+ 
+ //! Computed types for CSS values that are related to transformations.
+ 
+-use values::animated::{Animate, Procedure, ToAnimatedZero};
+ use values::computed::{Length, LengthOrPercentage, Number, Percentage};
+ use values::generics::transform::TimingFunction as GenericTimingFunction;
+ use values::generics::transform::TransformOrigin as GenericTransformOrigin;
+ 
+ /// The computed value of a CSS `<transform-origin>`
+ pub type TransformOrigin = GenericTransformOrigin<LengthOrPercentage, LengthOrPercentage, Length>;
+ 
+ /// A computed timing function.
+@@ -21,30 +20,8 @@ impl TransformOrigin {
+     pub fn initial_value() -> Self {
+         Self::new(
+             LengthOrPercentage::Percentage(Percentage(0.5)),
+             LengthOrPercentage::Percentage(Percentage(0.5)),
+             Length::from_px(0),
+         )
+     }
+ }
+-
+-impl Animate for TransformOrigin {
+-    #[inline]
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(Self::new(
+-            self.horizontal.animate(&other.horizontal, procedure)?,
+-            self.vertical.animate(&other.vertical, procedure)?,
+-            self.depth.animate(&other.depth, procedure)?,
+-        ))
+-    }
+-}
+-
+-impl ToAnimatedZero for TransformOrigin {
+-    #[inline]
+-    fn to_animated_zero(&self) -> Result<Self, ()> {
+-        Ok(Self::new(
+-            self.horizontal.to_animated_zero()?,
+-            self.vertical.to_animated_zero()?,
+-            self.depth.to_animated_zero()?,
+-        ))
+-    }
+-}
+diff --git a/servo/components/style/values/generics/basic_shape.rs b/servo/components/style/values/generics/basic_shape.rs
+--- a/servo/components/style/values/generics/basic_shape.rs
++++ b/servo/components/style/values/generics/basic_shape.rs
+@@ -49,46 +49,47 @@ pub enum ShapeSource<BasicShape, Referen
+     Url(Url),
+     Shape(BasicShape, Option<ReferenceBox>),
+     Box(ReferenceBox),
+     None,
+ }
+ 
+ #[allow(missing_docs)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Debug, PartialEq, ToComputedValue, ToCss)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Debug, PartialEq)]
++#[derive(ToComputedValue, ToCss)]
+ pub enum BasicShape<H, V, LengthOrPercentage> {
+     Inset(InsetRect<LengthOrPercentage>),
+     Circle(Circle<H, V, LengthOrPercentage>),
+     Ellipse(Ellipse<H, V, LengthOrPercentage>),
+     Polygon(Polygon<LengthOrPercentage>),
+ }
+ 
+ /// https://drafts.csswg.org/css-shapes/#funcdef-inset
+ #[allow(missing_docs)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Debug, PartialEq, ToComputedValue)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Debug, PartialEq, ToComputedValue)]
+ pub struct InsetRect<LengthOrPercentage> {
+     pub rect: Rect<LengthOrPercentage>,
+     pub round: Option<BorderRadius<LengthOrPercentage>>,
+ }
+ 
+ /// https://drafts.csswg.org/css-shapes/#funcdef-circle
+ #[allow(missing_docs)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToComputedValue)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToComputedValue)]
+ pub struct Circle<H, V, LengthOrPercentage> {
+     pub position: Position<H, V>,
+     pub radius: ShapeRadius<LengthOrPercentage>,
+ }
+ 
+ /// https://drafts.csswg.org/css-shapes/#funcdef-ellipse
+ #[allow(missing_docs)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToComputedValue)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToComputedValue)]
+ pub struct Ellipse<H, V, LengthOrPercentage> {
+     pub position: Position<H, V>,
+     pub semiaxis_x: ShapeRadius<LengthOrPercentage>,
+     pub semiaxis_y: ShapeRadius<LengthOrPercentage>,
+ }
+ 
+ /// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
+ #[allow(missing_docs)]
+@@ -117,16 +118,18 @@ pub struct Polygon<LengthOrPercentage> {
+ // https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
+ // says that it can also be `inherit`
+ define_css_keyword_enum!(FillRule:
+     "nonzero" => NonZero,
+     "evenodd" => EvenOdd
+ );
+ add_impls_for_keyword_enum!(FillRule);
+ 
++// FIXME(nox): This should be derivable, but we need to implement Animate
++// on the T types.
+ impl<B, T, U> Animate for ShapeSource<B, T, U>
+ where
+     B: Animate,
+     T: Clone + PartialEq,
+ {
+     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             (
+@@ -169,96 +172,30 @@ impl<B, T, U> ToAnimatedZero for ShapeSo
+     }
+ }
+ 
+ impl<B, T, U> HasViewportPercentage for ShapeSource<B, T, U> {
+     #[inline]
+     fn has_viewport_percentage(&self) -> bool { false }
+ }
+ 
+-impl<H, V, L> Animate for BasicShape<H, V, L>
+-where
+-    H: Animate,
+-    V: Animate,
+-    L: Animate + Copy,
+-{
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        match (self, other) {
+-            (&BasicShape::Circle(ref this), &BasicShape::Circle(ref other)) => {
+-                Ok(BasicShape::Circle(this.animate(other, procedure)?))
+-            },
+-            (&BasicShape::Ellipse(ref this), &BasicShape::Ellipse(ref other)) => {
+-                Ok(BasicShape::Ellipse(this.animate(other, procedure)?))
+-            },
+-            (&BasicShape::Inset(ref this), &BasicShape::Inset(ref other)) => {
+-                Ok(BasicShape::Inset(this.animate(other, procedure)?))
+-            },
+-            (&BasicShape::Polygon(ref this), &BasicShape::Polygon(ref other)) => {
+-                Ok(BasicShape::Polygon(this.animate(other, procedure)?))
+-            },
+-            _ => Err(()),
+-        }
+-    }
+-}
+-
+-impl<L> Animate for InsetRect<L>
+-where
+-    L: Animate + Copy,
+-{
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(InsetRect {
+-            rect: self.rect.animate(&other.rect, procedure)?,
+-            round: self.round.animate(&other.round, procedure)?,
+-        })
+-    }
+-}
+-
+ impl<L> ToCss for InsetRect<L>
+     where L: ToCss + PartialEq
+ {
+     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+         dest.write_str("inset(")?;
+         self.rect.to_css(dest)?;
+         if let Some(ref radius) = self.round {
+             dest.write_str(" round ")?;
+             radius.to_css(dest)?;
+         }
+         dest.write_str(")")
+     }
+ }
+ 
+-impl<H, V, L> Animate for Circle<H, V, L>
+-where
+-    H: Animate,
+-    V: Animate,
+-    L: Animate,
+-{
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(Circle {
+-            position: self.position.animate(&other.position, procedure)?,
+-            radius: self.radius.animate(&other.radius, procedure)?,
+-        })
+-    }
+-}
+-
+-impl<H, V, L> Animate for Ellipse<H, V, L>
+-where
+-    H: Animate,
+-    V: Animate,
+-    L: Animate,
+-{
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(Ellipse {
+-            position: self.position.animate(&other.position, procedure)?,
+-            semiaxis_x: self.semiaxis_x.animate(&other.semiaxis_x, procedure)?,
+-            semiaxis_y: self.semiaxis_y.animate(&other.semiaxis_y, procedure)?,
+-        })
+-    }
+-}
+-
+ impl<L> Animate for ShapeRadius<L>
+ where
+     L: Animate,
+ {
+     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+         match (self, other) {
+             (&ShapeRadius::Length(ref this), &ShapeRadius::Length(ref other)) => {
+                 Ok(ShapeRadius::Length(this.animate(other, procedure)?))
+diff --git a/servo/components/style/values/generics/border.rs b/servo/components/style/values/generics/border.rs
+--- a/servo/components/style/values/generics/border.rs
++++ b/servo/components/style/values/generics/border.rs
+@@ -2,17 +2,16 @@
+  * 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/. */
+ 
+ //! Generic types for CSS values related to borders.
+ 
+ use euclid::Size2D;
+ use std::fmt;
+ use style_traits::ToCss;
+-use values::animated::{Animate, Procedure};
+ use values::generics::rect::Rect;
+ 
+ /// A generic value for a single side of a `border-image-width` property.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ #[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
+ pub enum BorderImageSideWidth<LengthOrPercentage, Number> {
+     /// `<length-or-percentage>`
+     Length(LengthOrPercentage),
+@@ -31,31 +30,33 @@ pub struct BorderImageSlice<NumberOrPerc
+     /// Whether to fill the middle part.
+     pub fill: bool,
+ }
+ 
+ /// A generic value for `border-radius`, `outline-radius` and `inset()`.
+ ///
+ /// https://drafts.csswg.org/css-backgrounds-3/#border-radius
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage)]
++#[derive(PartialEq, ToComputedValue)]
+ pub struct BorderRadius<LengthOrPercentage> {
+     /// The top left radius.
+     pub top_left: BorderCornerRadius<LengthOrPercentage>,
+     /// The top right radius.
+     pub top_right: BorderCornerRadius<LengthOrPercentage>,
+     /// The bottom right radius.
+     pub bottom_right: BorderCornerRadius<LengthOrPercentage>,
+     /// The bottom left radius.
+     pub bottom_left: BorderCornerRadius<LengthOrPercentage>,
+ }
+ 
+ /// A generic value for `border-*-radius` longhand properties.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage)]
++#[derive(PartialEq, ToComputedValue)]
+ pub struct BorderCornerRadius<L>(pub Size2D<L>);
+ 
+ impl<N> From<N> for BorderImageSlice<N>
+     where N: Clone,
+ {
+     #[inline]
+     fn from(value: N) -> Self {
+         Self {
+@@ -108,30 +109,16 @@ impl<L> BorderRadius<L>
+         if widths.0 != heights.0 || widths.1 != heights.1 || widths.2 != heights.2 || widths.3 != heights.3 {
+             dest.write_str(" / ")?;
+             heights.to_css(dest)?;
+         }
+         Ok(())
+     }
+ }
+ 
+-impl<L> Animate for BorderRadius<L>
+-where
+-    L: Animate + Copy,
+-{
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(BorderRadius::new(
+-            self.top_left.animate(&other.top_left, procedure)?,
+-            self.top_right.animate(&other.top_right, procedure)?,
+-            self.bottom_right.animate(&other.bottom_right, procedure)?,
+-            self.bottom_left.animate(&other.bottom_left, procedure)?,
+-        ))
+-    }
+-}
+-
+ impl<L> ToCss for BorderRadius<L>
+     where L: PartialEq + ToCss
+ {
+     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+         let BorderRadius {
+             top_left: ref tl,
+             top_right: ref tr,
+             bottom_right: ref br,
+@@ -154,26 +141,16 @@ impl<L> BorderCornerRadius<L> {
+ }
+ 
+ impl<L: Clone> From<L> for BorderCornerRadius<L> {
+     fn from(radius: L) -> Self {
+         Self::new(radius.clone(), radius)
+     }
+ }
+ 
+-impl<L> Animate for BorderCornerRadius<L>
+-where
+-    L: Animate + Copy,
+-{
+-    #[inline]
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(BorderCornerRadius(self.0.animate(&other.0, procedure)?))
+-    }
+-}
+-
+ impl<L> ToCss for BorderCornerRadius<L>
+     where L: ToCss,
+ {
+     fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+         where W: fmt::Write
+     {
+         self.0.width.to_css(dest)?;
+         dest.write_str(" ")?;
+diff --git a/servo/components/style/values/generics/effects.rs b/servo/components/style/values/generics/effects.rs
+--- a/servo/components/style/values/generics/effects.rs
++++ b/servo/components/style/values/generics/effects.rs
+@@ -60,17 +60,18 @@ pub enum Filter<Angle, Factor, Length, D
+     Url(SpecifiedUrl),
+ }
+ 
+ /// A generic value for the `drop-shadow()` filter and the `text-shadow` property.
+ ///
+ /// Contrary to the canonical order from the spec, the color is serialised
+ /// first, like in Gecko and Webkit.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue, ToCss)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Debug, HasViewportPercentage)]
++#[derive(PartialEq, ToAnimatedValue, ToAnimatedZero, ToCss)]
+ pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
+     /// Color.
+     pub color: Color,
+     /// Horizontal radius.
+     pub horizontal: SizeLength,
+     /// Vertical radius.
+     pub vertical: SizeLength,
+     /// Blur radius.
+diff --git a/servo/components/style/values/generics/mod.rs b/servo/components/style/values/generics/mod.rs
+--- a/servo/components/style/values/generics/mod.rs
++++ b/servo/components/style/values/generics/mod.rs
+@@ -263,17 +263,17 @@ impl ToCss for FontSettingTagFloat {
+     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+         dest.write_str(" ")?;
+         self.0.to_css(dest)
+     }
+ }
+ 
+ /// A wrapper of Non-negative values.
+ #[cfg_attr(feature = "servo", derive(Deserialize, HeapSizeOf, Serialize))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage)]
+-#[derive(PartialEq, PartialOrd, ToComputedValue, ToCss)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage)]
++#[derive(PartialEq, PartialOrd, ToAnimatedZero, ToComputedValue, ToCss)]
+ pub struct NonNegative<T>(pub T);
+ 
+ /// A wrapper of greater-than-or-equal-to-one values.
+ #[cfg_attr(feature = "servo", derive(Deserialize, HeapSizeOf, Serialize))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage)]
+-#[derive(PartialEq, PartialOrd, ToComputedValue, ToCss)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage)]
++#[derive(PartialEq, PartialOrd, ToAnimatedZero, ToComputedValue, ToCss)]
+ pub struct GreaterThanOrEqualToOne<T>(pub T);
+diff --git a/servo/components/style/values/generics/position.rs b/servo/components/style/values/generics/position.rs
+--- a/servo/components/style/values/generics/position.rs
++++ b/servo/components/style/values/generics/position.rs
+@@ -2,17 +2,18 @@
+  * 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/. */
+ 
+ //! Generic types for CSS handling of specified and computed values of
+ //! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position)
+ 
+ /// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position).
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug)]
++#[derive(HasViewportPercentage, PartialEq, ToAnimatedZero, ToComputedValue)]
+ pub struct Position<H, V> {
+     /// The horizontal component of position.
+     pub horizontal: H,
+     /// The vertical component of position.
+     pub vertical: V,
+ }
+ 
+ impl<H, V> Position<H, V> {
+diff --git a/servo/components/style/values/generics/rect.rs b/servo/components/style/values/generics/rect.rs
+--- a/servo/components/style/values/generics/rect.rs
++++ b/servo/components/style/values/generics/rect.rs
+@@ -3,22 +3,22 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ //! Generic types for CSS values that are composed of four sides.
+ 
+ use cssparser::Parser;
+ use parser::{Parse, ParserContext};
+ use std::fmt;
+ use style_traits::{ToCss, ParseError};
+-use values::animated::{Animate, Procedure};
+ 
+ /// A CSS value made of four components, where its `ToCss` impl will try to
+ /// serialize as few components as possible, like for example in `border-width`.
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug)]
++#[derive(HasViewportPercentage, PartialEq, ToComputedValue)]
+ pub struct Rect<T>(pub T, pub T, pub T, pub T);
+ 
+ impl<T> Rect<T> {
+     /// Returns a new `Rect<T>` value.
+     pub fn new(first: T, second: T, third: T, fourth: T) -> Self {
+         Rect(first, second, third, fourth)
+     }
+ }
+@@ -47,30 +47,16 @@ impl<T> Rect<T>
+             // <first> <second> <third>
+             return Ok(Self::new(first, second.clone(), third, second));
+         };
+         // <first> <second> <third> <fourth>
+         Ok(Self::new(first, second, third, fourth))
+     }
+ }
+ 
+-impl<L> Animate for Rect<L>
+-where
+-    L: Animate,
+-{
+-    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+-        Ok(Rect(
+-            self.0.animate(&other.0, procedure)?,
+-            self.1.animate(&other.1, procedure)?,
+-            self.2.animate(&other.2, procedure)?,
+-            self.3.animate(&other.3, procedure)?,
+-        ))
+-    }
+-}
+-
+ impl<T> From<T> for Rect<T>
+     where T: Clone
+ {
+     #[inline]
+     fn from(value: T) -> Self {
+         Self::new(value.clone(), value.clone(), value.clone(), value)
+     }
+ }
+diff --git a/servo/components/style/values/generics/svg.rs b/servo/components/style/values/generics/svg.rs
+--- a/servo/components/style/values/generics/svg.rs
++++ b/servo/components/style/values/generics/svg.rs
+@@ -97,22 +97,22 @@ impl<ColorType: Parse, UrlPaintServer: P
+         }
+     }
+ }
+ 
+ /// A value of <length> | <percentage> | <number> for svg which allow unitless length.
+ /// https://www.w3.org/TR/SVG11/painting.html#StrokeProperties
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ #[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)]
+-#[derive(ToCss, ToComputedValue)]
+-pub enum SvgLengthOrPercentageOrNumber<LengthOrPercentageType, NumberType> {
++#[derive(ToAnimatedZero, ToCss, ToComputedValue)]
++pub enum SvgLengthOrPercentageOrNumber<LengthOrPercentage, Number> {
+     /// <length> | <percentage>
+-    LengthOrPercentage(LengthOrPercentageType),
++    LengthOrPercentage(LengthOrPercentage),
+     /// <number>
+-    Number(NumberType),
++    Number(Number),
+ }
+ 
+ impl<L, N> ComputeSquaredDistance for SvgLengthOrPercentageOrNumber<L, N>
+     where
+         L: ComputeSquaredDistance + Copy + Into<NumberOrPercentage>,
+         N: ComputeSquaredDistance + Copy + Into<NumberOrPercentage>
+ {
+     #[inline]
+@@ -179,17 +179,18 @@ impl <LengthOrPercentageType: Parse, Num
+         }
+         Err(StyleParseError::UnspecifiedError.into())
+     }
+ }
+ 
+ /// An SVG length value supports `context-value` in addition to length.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+ #[derive(Clone, ComputeSquaredDistance, Copy, Debug, PartialEq)]
+-#[derive(HasViewportPercentage, ToAnimatedValue, ToComputedValue, ToCss)]
++#[derive(HasViewportPercentage, ToAnimatedValue, ToAnimatedZero)]
++#[derive(ToComputedValue, ToCss)]
+ pub enum SVGLength<LengthType> {
+     /// `<length> | <percentage> | <number>`
+     Length(LengthType),
+     /// `context-value`
+     ContextValue,
+ }
+ 
+ /// Generic value for stroke-dasharray.
+@@ -223,17 +224,18 @@ impl<LengthType> ToCss for SVGStrokeDash
+             }
+         }
+     }
+ }
+ 
+ /// An SVG opacity value accepts `context-{fill,stroke}-opacity` in
+ /// addition to opacity value.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, HasViewportPercentage, ToComputedValue, ToCss)]
++#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage)]
++#[derive(PartialEq, ToAnimatedZero, ToComputedValue, ToCss)]
+ pub enum SVGOpacity<OpacityType> {
+     /// `<opacity-value>`
+     Opacity(OpacityType),
+     /// `context-fill-opacity`
+     ContextFillOpacity,
+     /// `context-stroke-opacity`
+     ContextStrokeOpacity,
+ }
+diff --git a/servo/components/style/values/generics/text.rs b/servo/components/style/values/generics/text.rs
+--- a/servo/components/style/values/generics/text.rs
++++ b/servo/components/style/values/generics/text.rs
+@@ -105,17 +105,18 @@ where
+     V: From<Au>,
+ {
+     #[inline]
+     fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
+ }
+ 
+ /// A generic value for the `line-height` property.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue, ToCss)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug)]
++#[derive(HasViewportPercentage, PartialEq, ToAnimatedValue, ToCss)]
+ pub enum LineHeight<Number, LengthOrPercentage> {
+     /// `normal`
+     Normal,
+     /// `-moz-block-height`
+     #[cfg(feature = "gecko")]
+     MozBlockHeight,
+     /// `<number>`
+     Number(Number),
+diff --git a/servo/components/style/values/generics/transform.rs b/servo/components/style/values/generics/transform.rs
+--- a/servo/components/style/values/generics/transform.rs
++++ b/servo/components/style/values/generics/transform.rs
+@@ -19,17 +19,18 @@ pub struct Matrix<T, U = T> {
+     pub c: T,
+     pub d: T,
+     pub e: U,
+     pub f: U,
+ }
+ 
+ /// A generic transform origin.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage)]
++#[derive(PartialEq, ToAnimatedZero, ToComputedValue, ToCss)]
+ pub struct TransformOrigin<H, V, Depth> {
+     /// The horizontal origin.
+     pub horizontal: H,
+     /// The vertical origin.
+     pub vertical: V,
+     /// The depth.
+     pub depth: Depth,
+ }
+diff --git a/servo/components/style/values/mod.rs b/servo/components/style/values/mod.rs
+--- a/servo/components/style/values/mod.rs
++++ b/servo/components/style/values/mod.rs
+@@ -63,18 +63,18 @@ impl Parse for Impossible {
+         _input: &mut Parser<'i, 't>)
+     -> Result<Self, ParseError<'i>> {
+         Err(StyleParseError::UnspecifiedError.into())
+     }
+ }
+ 
+ /// A struct representing one of two kinds of values.
+ #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+-#[derive(Clone, ComputeSquaredDistance, Copy, HasViewportPercentage, PartialEq)]
+-#[derive(ToAnimatedValue, ToComputedValue, ToCss)]
++#[derive(Animate, Clone, ComputeSquaredDistance, Copy, HasViewportPercentage)]
++#[derive(PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
+ pub enum Either<A, B> {
+     /// The first value.
+     First(A),
+     /// The second kind of value.
+     Second(B),
+ }
+ 
+ impl<A: Debug, B: Debug> Debug for Either<A, B> {
+diff --git a/servo/components/style_derive/animate.rs b/servo/components/style_derive/animate.rs
+new file mode 100644
+--- /dev/null
++++ b/servo/components/style_derive/animate.rs
+@@ -0,0 +1,123 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++use quote;
++use std::borrow::Cow;
++use syn;
++use synstructure;
++
++pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
++    let name = &input.ident;
++    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
++    let mut where_clause = where_clause.clone();
++    for param in &input.generics.ty_params {
++        where_clause.predicates.push(where_predicate(syn::Ty::Path(None, param.ident.clone().into())))
++    }
++
++    let variants = variants(&input);
++    let mut match_body = quote!();
++    match_body.append_all(variants.iter().map(|variant| {
++        let name = match input.body {
++            syn::Body::Struct(_) => Cow::Borrowed(&input.ident),
++            syn::Body::Enum(_) => {
++                Cow::Owned(syn::Ident::from(format!("{}::{}", input.ident, variant.ident)))
++            },
++        };
++        let (this_pattern, this_info) = synstructure::match_pattern(
++            &name,
++            &variant.data,
++            &synstructure::BindOpts::with_prefix(
++                synstructure::BindStyle::Ref,
++                "this".to_owned(),
++            ),
++        );
++        let (other_pattern, other_info) = synstructure::match_pattern(
++            &name,
++            &variant.data,
++            &synstructure::BindOpts::with_prefix(
++                synstructure::BindStyle::Ref,
++                "other".to_owned(),
++            ),
++        );
++        let (result_value, result_info) = synstructure::match_pattern(
++            &name,
++            &variant.data,
++            &synstructure::BindOpts::with_prefix(
++                synstructure::BindStyle::Move,
++                "result".to_owned(),
++            ),
++        );
++        let mut computations = quote!();
++        let iter = result_info.iter().zip(this_info.iter().zip(&other_info));
++        computations.append_all(iter.map(|(result, (this, other))| {
++            where_clause.predicates.push(where_predicate(this.field.ty.clone()));
++            quote! {
++                let #result = ::values::animated::Animate::animate(#this, #other, procedure)?;
++            }
++        }));
++        quote! {
++            (&#this_pattern, &#other_pattern) => {
++                #computations
++                Ok(#result_value)
++            }
++        }
++    }));
++
++    if variants.len() > 1 {
++        match_body = quote! { #match_body, _ => Err(()), };
++    }
++
++    quote! {
++        impl #impl_generics ::values::animated::Animate for #name #ty_generics #where_clause {
++            #[allow(unused_variables, unused_imports)]
++            #[inline]
++            fn animate(
++                &self,
++                other: &Self,
++                procedure: ::values::animated::Procedure,
++            ) -> Result<Self, ()> {
++                match (self, other) {
++                    #match_body
++                }
++            }
++        }
++    }
++}
++
++fn variants(input: &syn::DeriveInput) -> Cow<[syn::Variant]> {
++    match input.body {
++        syn::Body::Enum(ref variants) => (&**variants).into(),
++        syn::Body::Struct(ref data) => {
++            vec![syn::Variant {
++                ident: input.ident.clone(),
++                attrs: input.attrs.clone(),
++                data: data.clone(),
++                discriminant: None,
++            }].into()
++        },
++    }
++}
++
++fn where_predicate(ty: syn::Ty) -> syn::WherePredicate {
++    syn::WherePredicate::BoundPredicate(
++        syn::WhereBoundPredicate {
++            bound_lifetimes: vec![],
++            bounded_ty: ty,
++            bounds: vec![syn::TyParamBound::Trait(
++                syn::PolyTraitRef {
++                    bound_lifetimes: vec![],
++                    trait_ref: syn::Path {
++                        global: true,
++                        segments: vec![
++                            "values".into(),
++                            "animated".into(),
++                            "Animate".into(),
++                        ],
++                    },
++                },
++                syn::TraitBoundModifier::None,
++            )],
++        },
++    )
++}
+diff --git a/servo/components/style_derive/lib.rs b/servo/components/style_derive/lib.rs
+--- a/servo/components/style_derive/lib.rs
++++ b/servo/components/style_derive/lib.rs
+@@ -4,22 +4,30 @@
+ 
+ extern crate proc_macro;
+ #[macro_use] extern crate quote;
+ extern crate syn;
+ extern crate synstructure;
+ 
+ use proc_macro::TokenStream;
+ 
++mod animate;
+ mod compute_squared_distance;
+ mod has_viewport_percentage;
+ mod to_animated_value;
++mod to_animated_zero;
+ mod to_computed_value;
+ mod to_css;
+ 
++#[proc_macro_derive(Animate)]
++pub fn derive_animate(stream: TokenStream) -> TokenStream {
++    let input = syn::parse_derive_input(&stream.to_string()).unwrap();
++    animate::derive(input).to_string().parse().unwrap()
++}
++
+ #[proc_macro_derive(ComputeSquaredDistance)]
+ pub fn derive_compute_squared_distance(stream: TokenStream) -> TokenStream {
+     let input = syn::parse_derive_input(&stream.to_string()).unwrap();
+     compute_squared_distance::derive(input).to_string().parse().unwrap()
+ }
+ 
+ #[proc_macro_derive(HasViewportPercentage)]
+ pub fn derive_has_viewport_percentage(stream: TokenStream) -> TokenStream {
+@@ -28,16 +36,22 @@ pub fn derive_has_viewport_percentage(st
+ }
+ 
+ #[proc_macro_derive(ToAnimatedValue)]
+ pub fn derive_to_animated_value(stream: TokenStream) -> TokenStream {
+     let input = syn::parse_derive_input(&stream.to_string()).unwrap();
+     to_animated_value::derive(input).to_string().parse().unwrap()
+ }
+ 
++#[proc_macro_derive(ToAnimatedZero)]
++pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream {
++    let input = syn::parse_derive_input(&stream.to_string()).unwrap();
++    to_animated_zero::derive(input).to_string().parse().unwrap()
++}
++
+ #[proc_macro_derive(ToComputedValue)]
+ pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream {
+     let input = syn::parse_derive_input(&stream.to_string()).unwrap();
+     to_computed_value::derive(input).to_string().parse().unwrap()
+ }
+ 
+ #[proc_macro_derive(ToCss, attributes(css))]
+ pub fn derive_to_css(stream: TokenStream) -> TokenStream {
+diff --git a/servo/components/style_derive/to_animated_zero.rs b/servo/components/style_derive/to_animated_zero.rs
+new file mode 100644
+--- /dev/null
++++ b/servo/components/style_derive/to_animated_zero.rs
+@@ -0,0 +1,79 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++use quote;
++use syn;
++use synstructure;
++
++pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
++    let name = &input.ident;
++    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
++    let mut where_clause = where_clause.clone();
++    for param in &input.generics.ty_params {
++        where_clause.predicates.push(
++            where_predicate(syn::Ty::Path(None, param.ident.clone().into())),
++        );
++    }
++
++    let to_body = match_body(&input);
++
++    quote! {
++        impl #impl_generics ::values::animated::ToAnimatedZero for #name #ty_generics #where_clause {
++            #[allow(unused_variables)]
++            #[inline]
++            fn to_animated_zero(&self) -> Result<Self, ()> {
++                match *self {
++                    #to_body
++                }
++            }
++        }
++    }
++}
++
++fn match_body(input: &syn::DeriveInput) -> quote::Tokens {
++    synstructure::each_variant(&input, &synstructure::BindStyle::Ref.into(), |fields, variant| {
++        let name = if let syn::Body::Enum(_) = input.body {
++            format!("{}::{}", input.ident, variant.ident).into()
++        } else {
++            variant.ident.clone()
++        };
++        let (zero, computed_fields) = synstructure::match_pattern(
++            &name,
++            &variant.data,
++            &synstructure::BindStyle::Move.into(),
++        );
++        let fields_pairs = fields.iter().zip(computed_fields.iter());
++        let mut computations = quote!();
++        computations.append_all(fields_pairs.map(|(field, computed_field)| {
++            quote! {
++                let #computed_field = ::values::animated::ToAnimatedZero::to_animated_zero(#field)?;
++            }
++        }));
++        Some(quote!(
++            #computations
++            Ok(#zero)
++        ))
++    })
++}
++
++fn where_predicate(ty: syn::Ty) -> syn::WherePredicate {
++    syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
++        bound_lifetimes: vec![],
++        bounded_ty: ty,
++        bounds: vec![syn::TyParamBound::Trait(
++            syn::PolyTraitRef {
++                bound_lifetimes: vec![],
++                trait_ref: syn::Path {
++                    global: true,
++                    segments: vec![
++                        "values".into(),
++                        "animated".into(),
++                        "ToAnimatedZero".into(),
++                    ],
++                },
++            },
++            syn::TraitBoundModifier::None,
++        )],
++    })
++}

+ 197 - 0
frg/253-58/mozilla-release58_428184.patch

@@ -0,0 +1,197 @@
+# HG changeset patch
+# User Jean-Yves Avenard <jyavenard@mozilla.com>
+# Date 1503333278 -7200
+#      Mon Aug 21 18:34:38 2017 +0200
+# Node ID 217de64cdcc66d0f6ee14fc387e48dafa4922b23
+# Parent  088f0310b8c1da915eb0a23d007c52847b5341d8
+Bug 1347518 - P1. Use SEI recovery point to mark keyframe. r=jesup
+
+Some streams do not include any IDR frames. However, they do include SEI recovery point markers. We use those to mark keyframes.
+
+MozReview-Commit-ID: IHfUx7fEgEJ
+
+diff --git a/media/libstagefright/binding/H264.cpp b/media/libstagefright/binding/H264.cpp
+--- a/media/libstagefright/binding/H264.cpp
++++ b/media/libstagefright/binding/H264.cpp
+@@ -800,19 +800,26 @@ H264::GetFrameType(const mozilla::MediaR
+     }
+     if (!nalLen) {
+       continue;
+     }
+     const uint8_t* p = reader.Read(nalLen);
+     if (!p) {
+       return FrameType::INVALID;
+     }
+-    if ((p[0] & 0x1f) == H264_NAL_IDR_SLICE) {
++    int8_t nalType = *p & 0x1f;
++    if (nalType == H264_NAL_IDR_SLICE) {
+       // IDR NAL.
+       return FrameType::I_FRAME;
++    } else if (nalType == H264_NAL_SEI) {
++      RefPtr<mozilla::MediaByteBuffer> decodedNAL = DecodeNALUnit(p, nalLen);
++      SEIRecoveryData data;
++      if (DecodeRecoverySEI(decodedNAL, data)) {
++        return FrameType::I_FRAME;
++      }
+     }
+   }
+ 
+   return FrameType::OTHER;
+ }
+ 
+ /* static */ already_AddRefed<mozilla::MediaByteBuffer>
+ H264::ExtractExtraData(const mozilla::MediaRawData* aSample)
+@@ -970,12 +977,80 @@ H264::CompareExtraData(const mozilla::Me
+       return false;
+     }
+     ++it1;
+     ++it2;
+   }
+   return true;
+ }
+ 
++static inline bool
++ReadSEIInt(ByteReader& aBr, uint32_t& aOutput)
++{
++  uint8_t tmpByte;
++
++  aOutput = 0;
++  if (!aBr.CanRead8()) {
++    return false;
++  }
++  tmpByte = aBr.ReadU8();
++  while (tmpByte == 0xFF) {
++    aOutput += 255;
++    if (!aBr.CanRead8()) {
++      return false;
++    }
++    tmpByte = aBr.ReadU8();
++  }
++  aOutput += tmpByte;   // this is the last byte
++  return true;
++}
++
++/* static */ bool
++H264::DecodeRecoverySEI(const mozilla::MediaByteBuffer* aSEI,
++                        SEIRecoveryData& aDest)
++{
++  if (!aSEI) {
++    return false;
++  }
++  // sei_rbsp() as per 7.3.2.3 Supplemental enhancement information RBSP syntax
++  ByteReader br(aSEI);
++
++  do {
++    // sei_message() as per
++    // 7.3.2.3.1 Supplemental enhancement information message syntax
++    uint32_t payloadType = 0;
++    if (!ReadSEIInt(br, payloadType)) {
++      return false;
++    }
++
++    uint32_t payloadSize = 0;
++    if (!ReadSEIInt(br, payloadSize)) {
++      return false;
++    }
++
++    // sei_payload(payloadType, payloadSize) as per
++    // D.1 SEI payload syntax.
++    const uint8_t* p = br.Read(payloadSize);
++    if (!p) {
++      return false;
++    }
++    if (payloadType == 6) { // SEI_RECOVERY_POINT
++      if (payloadSize == 0) {
++        // Invalid content, ignore.
++        continue;
++      }
++      // D.1.7 Recovery point SEI message syntax
++      BitReader br(p, payloadSize * 8);
++      aDest.recovery_frame_cnt = br.ReadUE();
++      aDest.exact_match_flag = br.ReadBit();
++      aDest.broken_link_flag = br.ReadBit();
++      aDest.changing_slice_group_idc = br.ReadBits(2);
++      return true;
++    }
++  } while(br.CanRead8() && br.PeekU8() != 0x80); // more_rbsp_data() msg[offset] != 0x80
++  // ignore the trailing bits rbsp_trailing_bits();
++  return false;
++}
++
+ #undef READUE
+ #undef READSE
+ 
+ } // namespace mp4_demuxer
+diff --git a/media/libstagefright/binding/include/mp4_demuxer/H264.h b/media/libstagefright/binding/include/mp4_demuxer/H264.h
+--- a/media/libstagefright/binding/include/mp4_demuxer/H264.h
++++ b/media/libstagefright/binding/include/mp4_demuxer/H264.h
+@@ -399,16 +399,51 @@ struct SPSData
+ 
+   bool scaling_matrix_present;
+   uint8_t scaling_matrix4x4[6][16];
+   uint8_t scaling_matrix8x8[6][64];
+ 
+   SPSData();
+ };
+ 
++struct SEIRecoveryData
++{
++  /*
++    recovery_frame_cnt specifies the recovery point of output pictures in output
++    order. All decoded pictures in output order are indicated to be correct or
++    approximately correct in content starting at the output order position of
++    the reference picture having the frame_num equal to the frame_num of the VCL
++    NAL units for the current access unit incremented by recovery_frame_cnt in
++    modulo MaxFrameNum arithmetic. recovery_frame_cnt shall be in the range of 0
++    to MaxFrameNum − 1, inclusive.
++  */
++  uint32_t recovery_frame_cnt = 0;
++  /*
++    exact_match_flag indicates whether decoded pictures at and subsequent to the
++    specified recovery point in output order derived by starting the decoding
++    process at the access unit associated with the recovery point SEI message
++    shall be an exact match to the pictures that would be produced by starting
++    the decoding process at the location of a previous IDR access unit in the
++    NAL unit stream. The value 0 indicates that the match need not be exact and
++    the value 1 indicates that the match shall be exact.
++  */
++  bool exact_match_flag = false;
++  /*
++    broken_link_flag indicates the presence or absence of a broken link in the
++    NAL unit stream at the location of the recovery point SEI message */
++  bool broken_link_flag = false;
++  /*
++    changing_slice_group_idc equal to 0 indicates that decoded pictures are
++    correct or approximately correct in content at and subsequent to the
++    recovery point in output order when all macroblocks of the primary coded
++    pictures are decoded within the changing slice group period
++  */
++  uint8_t changing_slice_group_idc = 0;
++};
++
+ class H264
+ {
+ public:
+   /* Check if out of band extradata contains a SPS NAL */
+   static bool HasSPS(const mozilla::MediaByteBuffer* aExtraData);
+   // Extract SPS and PPS NALs from aSample by looking into each NALs.
+   // aSample must be in AVCC format.
+   static already_AddRefed<mozilla::MediaByteBuffer> ExtractExtraData(
+@@ -449,13 +484,17 @@ private:
+   static already_AddRefed<mozilla::MediaByteBuffer> DecodeNALUnit(
+     const uint8_t* aNAL, size_t aLength);
+   /* Decode SPS NAL RBSP and fill SPSData structure */
+   static bool DecodeSPS(const mozilla::MediaByteBuffer* aSPS, SPSData& aDest);
+   static bool vui_parameters(BitReader& aBr, SPSData& aDest);
+   // Read HRD parameters, all data is ignored.
+   static void hrd_parameters(BitReader& aBr);
+   static uint8_t NumSPS(const mozilla::MediaByteBuffer* aExtraData);
++  // Decode SEI payload and return true if the SEI NAL indicates a recovery
++  // point.
++  static bool DecodeRecoverySEI(const mozilla::MediaByteBuffer* aSEI,
++                                SEIRecoveryData& aDest);
+ };
+ 
+ } // namespace mp4_demuxer
+ 
+ #endif // MP4_DEMUXER_H264_H_

+ 34 - 0
frg/253-58/mozilla-release58_428185.patch

@@ -0,0 +1,34 @@
+# HG changeset patch
+# User Jean-Yves Avenard <jyavenard@mozilla.com>
+# Date 1503334484 -7200
+#      Mon Aug 21 18:54:44 2017 +0200
+# Node ID dd4b954fb20a49c7ee17250b4cd07e83e748f14e
+# Parent  217de64cdcc66d0f6ee14fc387e48dafa4922b23
+Bug 1347518 - P2. Don't attempt to determine frame type when encrypted. r=cpearce
+
+The data being encrypted, is nonsensical. So we always rely on the container information
+
+MozReview-Commit-ID: 4uQ9l3Q1Ebl
+
+diff --git a/dom/media/fmp4/MP4Demuxer.cpp b/dom/media/fmp4/MP4Demuxer.cpp
+--- a/dom/media/fmp4/MP4Demuxer.cpp
++++ b/dom/media/fmp4/MP4Demuxer.cpp
+@@ -431,17 +431,17 @@ already_AddRefed<MediaRawData>
+ MP4TrackDemuxer::GetNextSample()
+ {
+   RefPtr<MediaRawData> sample = mIterator->GetNext();
+   if (!sample) {
+     return nullptr;
+   }
+   if (mInfo->GetAsVideoInfo()) {
+     sample->mExtraData = mInfo->GetAsVideoInfo()->mExtraData;
+-    if (mIsH264) {
++    if (mIsH264 && !sample->mCrypto.mValid) {
+       mp4_demuxer::H264::FrameType type =
+         mp4_demuxer::H264::GetFrameType(sample);
+       switch (type) {
+         case mp4_demuxer::H264::FrameType::I_FRAME: MOZ_FALLTHROUGH;
+         case mp4_demuxer::H264::FrameType::OTHER:
+         {
+           bool keyframe = type == mp4_demuxer::H264::FrameType::I_FRAME;
+           if (sample->mKeyframe != keyframe) {

+ 112 - 0
frg/253-58/mozilla-release58_428186.patch

@@ -0,0 +1,112 @@
+# HG changeset patch
+# User Andreas Tolfsen <ato@sny.no>
+# Date 1503338955 -3600
+#      Mon Aug 21 19:09:15 2017 +0100
+# Node ID bf2c23b8d6cc6d2c727b0c119434cd5d0166c100
+# Parent  dd4b954fb20a49c7ee17250b4cd07e83e748f14e
+Bug 1392346 - Decouple element staleness check from element.Store. r=automatedtester
+
+In preparation for a larger window tracking change to Marionette, we
+want to decouple the element staleness check from the element.Store.
+
+MozReview-Commit-ID: JNZqCc2eZqy
+
+diff --git a/testing/marionette/element.js b/testing/marionette/element.js
+--- a/testing/marionette/element.js
++++ b/testing/marionette/element.js
+@@ -176,34 +176,21 @@ element.Store = class {
+ 
+     try {
+       el = el.get();
+     } catch (e) {
+       el = null;
+       delete this.els[uuid];
+     }
+ 
+-    // use XPCNativeWrapper to compare elements (see bug 834266)
+-    let wrappedFrame = new XPCNativeWrapper(container.frame);
+-    let wrappedShadowRoot;
+-    if (container.shadowRoot) {
+-      wrappedShadowRoot = new XPCNativeWrapper(container.shadowRoot);
+-    }
+-    let wrappedEl = new XPCNativeWrapper(el);
+-    let wrappedContainer = {
+-      frame: wrappedFrame,
+-      shadowRoot: wrappedShadowRoot,
+-    };
+-    if (!el ||
+-        !(wrappedEl.ownerDocument == wrappedFrame.document) ||
+-        element.isDisconnected(wrappedEl, wrappedContainer)) {
++    if (element.isStale(el, container.frame, container.shadowRoot)) {
+       throw new StaleElementReferenceError(
+-          error.pprint`The element reference of ${el} stale: ` +
++          error.pprint`The element reference of ${el} stale; ` +
+               "either the element is no longer attached to the DOM " +
+-              "or the page has been refreshed");
++              "or the document has been refreshed");
+     }
+ 
+     return el;
+   }
+ };
+ 
+ /**
+  * Find a single element or a collection of elements starting at the
+@@ -632,16 +619,57 @@ element.isWebElementReference = function
+ };
+ 
+ element.generateUUID = function() {
+   let uuid = uuidGen.generateUUID().toString();
+   return uuid.substring(1, uuid.length - 1);
+ };
+ 
+ /**
++ * Determines if <var>el</var> is stale.
++ *
++ * A stale element is an element no longer attached to the DOM, which
++ * is provided through <var>window</var>.
++ *
++ * @param {Element} el
++ *     DOM element to check for staleness.
++ * @param {WindowProxy} window
++ *     Window global to check if <var>el</var> is still part of.
++ * @param {Element=} shadowRoot
++ *     Current shadow root element.
++ *
++ * @return {boolean}
++ *     True if <var>el</var> is stale, false otherwise.
++ */
++element.isStale = function(el, window, shadowRoot = undefined) {
++  if (typeof window == "undefined") {
++    throw new TypeError("Window global must be provided for staleness check");
++  }
++
++  // use XPCNativeWrapper to compare elements (see bug 834266)
++  let wrappedElement, wrappedWindow, wrappedShadowRoot;
++
++  wrappedElement = new XPCNativeWrapper(el);
++  wrappedWindow = new XPCNativeWrapper(window);
++  if (shadowRoot) {
++    wrappedShadowRoot = new XPCNativeWrapper(shadowRoot);
++  }
++
++  const container = {
++    frame: wrappedWindow,
++    shadowRoot: wrappedShadowRoot,
++  };
++
++  let sameDoc = wrappedElement.ownerDocument === wrappedWindow.document;
++  let disconn = element.isDisconnected(wrappedElement, container);
++
++  return !el || !sameDoc || disconn;
++};
++
++/**
+  * Check if the element is detached from the current frame as well as
+  * the optional shadow root (when inside a Shadow DOM context).
+  *
+  * @param {Element} el
+  *     Element to be checked.
+  * @param {Container} container
+  *     Container with |frame|, which is the window object that contains
+  *     the element, and an optional |shadowRoot|.

+ 726 - 0
frg/253-58/mozilla-release58_428187.patch

@@ -0,0 +1,726 @@
+# HG changeset patch
+# User Masatoshi Kimura <VYV03354@nifty.ne.jp>
+# Date 1503122653 -32400
+#      Sat Aug 19 15:04:13 2017 +0900
+# Node ID 7f2356284595291852fb4c8b1f374a8ac90c5007
+# Parent  bf2c23b8d6cc6d2c727b0c119434cd5d0166c100
+Bug 938704 - Make OS.File support modern iterators. r=florian,Yoric
+
+MozReview-Commit-ID: 8F1DtgakxM3
+
+diff --git a/browser/components/sessionstore/SessionWorker.js b/browser/components/sessionstore/SessionWorker.js
+--- a/browser/components/sessionstore/SessionWorker.js
++++ b/browser/components/sessionstore/SessionWorker.js
+@@ -367,17 +367,17 @@ var Agent = {
+ 
+     let exn = null;
+ 
+     let iterator = new File.DirectoryIterator(path);
+     try {
+       if (!iterator.exists()) {
+         return;
+       }
+-      for (let entry in iterator) {
++      for (let entry of iterator) {
+         if (entry.isDir) {
+           continue;
+         }
+         if (!prefix || entry.name.startsWith(prefix)) {
+           try {
+             File.remove(entry.path);
+           } catch (ex) {
+             // Don't stop immediately
+diff --git a/devtools/client/shared/file-watcher-worker.js b/devtools/client/shared/file-watcher-worker.js
+--- a/devtools/client/shared/file-watcher-worker.js
++++ b/devtools/client/shared/file-watcher-worker.js
+@@ -9,17 +9,17 @@ importScripts("resource://gre/modules/os
+ 
+ const modifiedTimes = new Map();
+ 
+ function gatherFiles(path, fileRegex) {
+   let files = [];
+   const iterator = new OS.File.DirectoryIterator(path);
+ 
+   try {
+-    for (let child in iterator) {
++    for (let child of iterator) {
+       // Don't descend into test directories. Saves us some time and
+       // there's no reason to.
+       if (child.isDir && !child.path.endsWith("/test")) {
+         files = files.concat(gatherFiles(child.path, fileRegex));
+       } else if (child.path.match(fileRegex)) {
+         let info;
+         try {
+           info = OS.File.stat(child.path);
+diff --git a/toolkit/components/osfile/modules/osfile_async_front.jsm b/toolkit/components/osfile/modules/osfile_async_front.jsm
+--- a/toolkit/components/osfile/modules/osfile_async_front.jsm
++++ b/toolkit/components/osfile/modules/osfile_async_front.jsm
+@@ -1240,189 +1240,132 @@ File.GET_DEBUG = function GET_DEBUG() {
+  */
+ var DirectoryIterator = function DirectoryIterator(path, options) {
+   /**
+    * Open the iterator on the worker thread
+    *
+    * @type {Promise}
+    * @resolves {*} A message accepted by the methods of DirectoryIterator
+    * in the worker thread
+-   * @rejects {StopIteration} If all entries have already been visited
+-   * or the iterator has been closed.
+    */
+-  this.__itmsg = Scheduler.post(
++  this._itmsg = Scheduler.post(
+     "new_DirectoryIterator", [Type.path.toMsg(path), options],
+     path
+   );
+   this._isClosed = false;
+ };
+ DirectoryIterator.prototype = {
+-  iterator() {
+-    return this;
+-  },
+-  __iterator__() {
++  [Symbol.asyncIterator]() {
+     return this;
+   },
+ 
+-  // Once close() is called, _itmsg should reject with a
+-  // StopIteration. However, we don't want to create the promise until
+-  // it's needed because it might never be used. In that case, we
+-  // would get a warning on the console.
+-  get _itmsg() {
+-    if (!this.__itmsg) {
+-      this.__itmsg = Promise.reject(StopIteration);
+-    }
+-    return this.__itmsg;
+-  },
++  _itmsg: null,
+ 
+   /**
+    * Determine whether the directory exists.
+    *
+    * @resolves {boolean}
+    */
+-  exists: function exists() {
+-    return this._itmsg.then(
+-      function onSuccess(iterator) {
+-        return Scheduler.post("DirectoryIterator_prototype_exists", [iterator]);
+-      }
+-    );
++  async exists() {
++    if (this._isClosed) {
++      return Promise.resolve(false);
++    }
++    let iterator = await this._itmsg;
++    return Scheduler.post("DirectoryIterator_prototype_exists", [iterator]);
+   },
+   /**
+    * Get the next entry in the directory.
+    *
+    * @return {Promise}
+-   * @resolves {OS.File.Entry}
+-   * @rejects {StopIteration} If all entries have already been visited.
++   * @resolves By definition of the async iterator protocol, either
++   * `{value: {File.Entry}, done: false}` if there is an unvisited entry
++   * in the directory, or `{value: undefined, done: true}`, otherwise.
+    */
+-  next: function next() {
+-    let self = this;
+-    let promise = this._itmsg;
+-
+-    // Get the iterator, call _next
+-    promise = promise.then(
+-      function withIterator(iterator) {
+-        return self._next(iterator);
+-      });
+-
+-    return promise;
++  async next() {
++    if (this._isClosed) {
++      return {value: undefined, done: true};
++    }
++    return this._next(await this._itmsg);
+   },
+   /**
+    * Get several entries at once.
+    *
+    * @param {number=} length If specified, the number of entries
+    * to return. If unspecified, return all remaining entries.
+    * @return {Promise}
+    * @resolves {Array} An array containing the |length| next entries.
+    */
+-  nextBatch: function nextBatch(size) {
++  async nextBatch(size) {
+     if (this._isClosed) {
+-      return Promise.resolve([]);
++      return [];
+     }
+-    let promise = this._itmsg;
+-    promise = promise.then(
+-      function withIterator(iterator) {
+-        return Scheduler.post("DirectoryIterator_prototype_nextBatch", [iterator, size]);
+-      });
+-    promise = promise.then(
+-      function withEntries(array) {
+-        return array.map(DirectoryIterator.Entry.fromMsg);
+-      });
+-    return promise;
++    let iterator = await this._itmsg;
++    let array = await Scheduler.post("DirectoryIterator_prototype_nextBatch", [iterator, size]);
++    return array.map(DirectoryIterator.Entry.fromMsg);
+   },
+   /**
+    * Apply a function to all elements of the directory sequentially.
+    *
+    * @param {Function} cb This function will be applied to all entries
+    * of the directory. It receives as arguments
+    *  - the OS.File.Entry corresponding to the entry;
+    *  - the index of the entry in the enumeration;
+    *  - the iterator itself - return |iterator.close()| to stop the loop.
+    *
+    * If the callback returns a promise, iteration waits until the
+    * promise is resolved before proceeding.
+    *
+    * @return {Promise} A promise resolved once the loop has reached
+    * its end.
+    */
+-  forEach: function forEach(cb, options) {
++  async forEach(cb, options) {
+     if (this._isClosed) {
+-      return Promise.resolve();
++      return undefined;
+     }
+-
+-    let self = this;
+     let position = 0;
+-    let iterator;
+-
+-    // Grab iterator
+-    let promise = this._itmsg.then(
+-      function(aIterator) {
+-        iterator = aIterator;
++    let iterator = await this._itmsg;
++    while (true) {
++      if (this._isClosed) {
++        return undefined;
+       }
+-    );
+-
+-    // Then iterate
+-    let loop = function loop() {
+-      if (self._isClosed) {
+-        return Promise.resolve();
++      let {value, done} = await this._next(iterator);
++      if (done) {
++        return undefined;
+       }
+-      return self._next(iterator).then(
+-        function onSuccess(value) {
+-          return Promise.resolve(cb(value, position++, self)).then(loop);
+-        },
+-        function onFailure(reason) {
+-          if (reason == StopIteration) {
+-            return;
+-          }
+-          throw reason;
+-        }
+-      );
+-    };
+-
+-    return promise.then(loop);
++      await cb(value, position++, this);
++    }
+   },
+   /**
+    * Auxiliary method: fetch the next item
+    *
+-   * @rejects {StopIteration} If all entries have already been visited
+-   * or the iterator has been closed.
++   * @resolves `{value: undefined, done: true}` If all entries have already
++   * been visited or the iterator has been closed.
+    */
+-  _next: function _next(iterator) {
++  async _next(iterator) {
+     if (this._isClosed) {
+-      return this._itmsg;
++      return {value: undefined, done: true};
+     }
+-    let self = this;
+-    let promise = Scheduler.post("DirectoryIterator_prototype_next", [iterator]);
+-    promise = promise.then(
+-      DirectoryIterator.Entry.fromMsg,
+-      function onReject(reason) {
+-        if (reason == StopIteration) {
+-          self.close();
+-          throw StopIteration;
+-        }
+-        throw reason;
+-      });
+-    return promise;
++    let {value, done} = await Scheduler.post("DirectoryIterator_prototype_next", [iterator]);
++    if (done) {
++      this.close();
++      return {value: undefined, done: true};
++    }
++    return {value: DirectoryIterator.Entry.fromMsg(value), done: false};
+   },
+   /**
+    * Close the iterator
+    */
+-  close: function close() {
++  async close() {
+     if (this._isClosed) {
+-      return Promise.resolve();
++      return undefined;
+     }
+     this._isClosed = true;
+-    let self = this;
+-    return this._itmsg.then(
+-      function withIterator(iterator) {
+-        // Set __itmsg to null so that the _itmsg getter returns a
+-        // rejected StopIteration promise if it's ever used.
+-        self.__itmsg = null;
+-        return Scheduler.post("DirectoryIterator_prototype_close", [iterator]);
+-      }
+-    );
++    let iterator = this._itmsg;
++    this._itmsg = null;
++    return Scheduler.post("DirectoryIterator_prototype_close", [iterator]);
+   }
+ };
+ 
+ DirectoryIterator.Entry = function Entry(value) {
+   return value;
+ };
+ DirectoryIterator.Entry.prototype = Object.create(SysAll.AbstractEntry.prototype);
+ 
+diff --git a/toolkit/components/osfile/modules/osfile_async_worker.js b/toolkit/components/osfile/modules/osfile_async_worker.js
+--- a/toolkit/components/osfile/modules/osfile_async_worker.js
++++ b/toolkit/components/osfile/modules/osfile_async_worker.js
+@@ -351,24 +351,22 @@ if (this.Components) {
+        function do_flush() {
+          return this.flush();
+        });
+    },
+    // Methods of OS.File.DirectoryIterator
+    DirectoryIterator_prototype_next: function next(dir) {
+      return withDir(dir,
+        function do_next() {
+-         try {
+-           return File.DirectoryIterator.Entry.toMsg(this.next());
+-         } catch (x) {
+-           if (x == StopIteration) {
+-             OpenedDirectoryIterators.remove(dir);
+-           }
+-           throw x;
++         let {value, done} = this.next();
++         if (done) {
++           OpenedDirectoryIterators.remove(dir);
++           return {value: undefined, done: true};
+          }
++         return {value: File.DirectoryIterator.Entry.toMsg(value), done: false};
+        }, false);
+    },
+    DirectoryIterator_prototype_nextBatch: function nextBatch(dir, size) {
+      return withDir(dir,
+        function do_nextBatch() {
+          let result;
+          try {
+            result = this.nextBatch(size);
+diff --git a/toolkit/components/osfile/modules/osfile_shared_front.jsm b/toolkit/components/osfile/modules/osfile_shared_front.jsm
+--- a/toolkit/components/osfile/modules/osfile_shared_front.jsm
++++ b/toolkit/components/osfile/modules/osfile_shared_front.jsm
+@@ -185,34 +185,34 @@ AbstractFile.openUnique = function openU
+ 
+ /**
+  * Code shared by iterators.
+  */
+ AbstractFile.AbstractIterator = function AbstractIterator() {
+ };
+ AbstractFile.AbstractIterator.prototype = {
+   /**
+-   * Allow iterating with |for|
++   * Allow iterating with |for-of|
+    */
+-  __iterator__: function __iterator__() {
++  [Symbol.iterator]() {
+     return this;
+   },
+   /**
+    * Apply a function to all elements of the directory sequentially.
+    *
+    * @param {Function} cb This function will be applied to all entries
+    * of the directory. It receives as arguments
+    *  - the OS.File.Entry corresponding to the entry;
+    *  - the index of the entry in the enumeration;
+    *  - the iterator itself - calling |close| on the iterator stops
+    *   the loop.
+    */
+   forEach: function forEach(cb) {
+     let index = 0;
+-    for (let entry in this) {
++    for (let entry of this) {
+       cb(entry, index++, this);
+     }
+   },
+   /**
+    * Return several entries at once.
+    *
+    * Entries are returned in the same order as a walk with |forEach| or
+    * |for(...)|.
+@@ -220,17 +220,17 @@ AbstractFile.AbstractIterator.prototype 
+    * @param {number=} length If specified, the number of entries
+    * to return. If unspecified, return all remaining entries.
+    * @return {Array} An array containing the next |length| entries, or
+    * less if the iteration contains less than |length| entries left.
+    */
+   nextBatch: function nextBatch(length) {
+     let array = [];
+     let i = 0;
+-    for (let entry in this) {
++    for (let entry of this) {
+       array.push(entry);
+       if (++i >= length) {
+         return array;
+       }
+     }
+     return array;
+   }
+ };
+@@ -498,17 +498,17 @@ AbstractFile.removeRecursive = function(
+   let iterator = new OS.File.DirectoryIterator(path);
+   if (!iterator.exists()) {
+     if (!("ignoreAbsent" in options) || options.ignoreAbsent) {
+       return;
+     }
+   }
+ 
+   try {
+-    for (let entry in iterator) {
++    for (let entry of iterator) {
+       if (entry.isDir) {
+         if (entry.isLink) {
+           // Unlike Unix symlinks, NTFS junctions or NTFS symlinks to
+           // directories are directories themselves. OS.File.remove()
+           // will not work for them.
+           OS.File.removeEmptyDir(entry.path, options);
+         } else {
+           // Normal directories.
+diff --git a/toolkit/components/osfile/modules/osfile_unix_front.jsm b/toolkit/components/osfile/modules/osfile_unix_front.jsm
+--- a/toolkit/components/osfile/modules/osfile_unix_front.jsm
++++ b/toolkit/components/osfile/modules/osfile_unix_front.jsm
+@@ -727,26 +727,26 @@
+      File.DirectoryIterator.prototype = Object.create(exports.OS.Shared.AbstractFile.AbstractIterator.prototype);
+ 
+      /**
+       * Return the next entry in the directory, if any such entry is
+       * available.
+       *
+       * Skip special directories "." and "..".
+       *
+-      * @return {File.Entry} The next entry in the directory.
+-      * @throws {StopIteration} Once all files in the directory have been
+-      * encountered.
++      * @return By definition of the iterator protocol, either
++      * `{value: {File.Entry}, done: false}` if there is an unvisited entry
++      * in the directory, or `{value: undefined, done: true}`, otherwise.
+       */
+      File.DirectoryIterator.prototype.next = function next() {
+        if (!this._exists) {
+          throw File.Error.noSuchFile("DirectoryIterator.prototype.next", this._path);
+        }
+        if (this._closed) {
+-         throw StopIteration;
++         return {value: undefined, done: true};
+        }
+        for (let entry = UnixFile.readdir(this._dir);
+             entry != null && !entry.isNull();
+             entry = UnixFile.readdir(this._dir)) {
+          let contents = entry.contents;
+          let name = contents.d_name.readString();
+          if (name == "." || name == "..") {
+            continue;
+@@ -759,20 +759,23 @@
+            throw_on_negative("lstat", UnixFile.lstat(path, gStatDataPtr), this._path);
+            isDir = (gStatData.st_mode & Const.S_IFMT) == Const.S_IFDIR;
+            isSymLink = (gStatData.st_mode & Const.S_IFMT) == Const.S_IFLNK;
+          } else {
+            isDir = contents.d_type == Const.DT_DIR;
+            isSymLink = contents.d_type == Const.DT_LNK;
+          }
+ 
+-         return new File.DirectoryIterator.Entry(isDir, isSymLink, name, this._path);
++         return {
++           value: new File.DirectoryIterator.Entry(isDir, isSymLink, name, this._path),
++           done: false
++         };
+        }
+        this.close();
+-       throw StopIteration;
++       return {value: undefined, done: true};
+      };
+ 
+      /**
+       * Close the iterator and recover all resources.
+       * You should call this once you have finished iterating on a directory.
+       */
+      File.DirectoryIterator.prototype.close = function close() {
+        if (this._closed) return;
+diff --git a/toolkit/components/osfile/modules/osfile_win_front.jsm b/toolkit/components/osfile/modules/osfile_win_front.jsm
+--- a/toolkit/components/osfile/modules/osfile_win_front.jsm
++++ b/toolkit/components/osfile/modules/osfile_win_front.jsm
+@@ -806,32 +806,35 @@
+      },
+ 
+      /**
+       * Return the next entry in the directory, if any such entry is
+       * available.
+       *
+       * Skip special directories "." and "..".
+       *
+-      * @return {File.Entry} The next entry in the directory.
+-      * @throws {StopIteration} Once all files in the directory have been
+-      * encountered.
++      * @return By definition of the iterator protocol, either
++      * `{value: {File.Entry}, done: false}` if there is an unvisited entry
++      * in the directory, or `{value: undefined, done: true}`, otherwise.
+       */
+      File.DirectoryIterator.prototype.next = function next() {
+          // FIXME: If we start supporting "\\?\"-prefixed paths, do not forget
+          // that "." and ".." are absolutely normal file names if _path starts
+          // with such prefix
+          for (let entry = this._next(); entry != null; entry = this._next()) {
+            let name = entry.cFileName.readString();
+            if (name == "." || name == "..") {
+              continue;
+            }
+-           return new File.DirectoryIterator.Entry(entry, this._path);
++           return {
++             value: new File.DirectoryIterator.Entry(entry, this._path),
++             done: false
++           };
+          }
+-         throw StopIteration;
++         return {value: undefined, done: true};
+      };
+ 
+      File.DirectoryIterator.prototype.close = function close() {
+        if (this._closed) {
+          return;
+        }
+        this._closed = true;
+        if (this._handle) {
+diff --git a/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js b/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js
+--- a/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js
++++ b/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js
+@@ -210,17 +210,17 @@ function test_iter_dir() {
+   let tmp_file = OS.File.open(tmp_file_name, {write: true, trunc: true});
+   tmp_file.close();
+ 
+   let parent = OS.File.getCurrentDirectory();
+   info("test_iter_dir: directory " + parent);
+   let iterator = new OS.File.DirectoryIterator(parent);
+   info("test_iter_dir: iterator created");
+   let encountered_tmp_file = false;
+-  for (let entry in iterator) {
++  for (let entry of iterator) {
+     // Checking that |name| can be decoded properly
+     info("test_iter_dir: encountering entry " + entry.name);
+ 
+     if (entry.name == tmp_file_name) {
+       encountered_tmp_file = true;
+       isnot(entry.isDir, "test_iter_dir: The temporary file is not a directory");
+       isnot(entry.isSymLink, "test_iter_dir: The temporary file is not a link");
+     }
+@@ -261,17 +261,17 @@ function test_iter_dir() {
+   ok(encountered_tmp_file, "test_iter_dir: We have found the temporary file");
+ 
+   info("test_iter_dir: Cleaning up");
+   iterator.close();
+ 
+   // Testing nextBatch()
+   iterator = new OS.File.DirectoryIterator(parent);
+   let allentries = [];
+-  for (let x in iterator) {
++  for (let x of iterator) {
+     allentries.push(x);
+   }
+   iterator.close();
+ 
+   ok(allentries.length >= 14, "test_iter_dir: Meta-check: the test directory should contain at least 14 items");
+ 
+   iterator = new OS.File.DirectoryIterator(parent);
+   let firstten = iterator.nextBatch(10);
+diff --git a/toolkit/components/search/nsSearchService.js b/toolkit/components/search/nsSearchService.js
+--- a/toolkit/components/search/nsSearchService.js
++++ b/toolkit/components/search/nsSearchService.js
+@@ -2968,22 +2968,19 @@ SearchService.prototype = {
+       locations = {hasMoreElements: () => false};
+     }
+     while (locations.hasMoreElements()) {
+       let dir = locations.getNext().QueryInterface(Ci.nsIFile);
+       let iterator = new OS.File.DirectoryIterator(dir.path,
+                                                    { winPattern: "*.xml" });
+       try {
+         // Add dir to distDirs if it contains any files.
+-        await checkForSyncCompletion(iterator.next());
+-        distDirs.push(dir);
+-      } catch (ex) {
+-        // Catch for StopIteration exception.
+-        if (ex.result == Cr.NS_ERROR_ALREADY_INITIALIZED) {
+-          throw ex;
++        let {done} = await checkForSyncCompletion(iterator.next());
++        if (!done) {
++          distDirs.push(dir);
+         }
+       } finally {
+         iterator.close();
+       }
+     }
+ 
+     // Add the non-empty directories of NS_APP_SEARCH_DIR_LIST to
+     // otherDirs...
+@@ -2993,22 +2990,19 @@ SearchService.prototype = {
+     while (locations.hasMoreElements()) {
+       let dir = locations.getNext().QueryInterface(Ci.nsIFile);
+       if (cache.engines && dir.equals(userSearchDir))
+         continue;
+       let iterator = new OS.File.DirectoryIterator(dir.path,
+                                                    { winPattern: "*.xml" });
+       try {
+         // Add dir to otherDirs if it contains any files.
+-        await checkForSyncCompletion(iterator.next());
+-        otherDirs.push(dir);
+-      } catch (ex) {
+-        // Catch for StopIteration exception.
+-        if (ex.result == Cr.NS_ERROR_ALREADY_INITIALIZED) {
+-          throw ex;
++        let {done} = await checkForSyncCompletion(iterator.next());
++        if (!done) {
++          otherDirs.push(dir);
+         }
+       } finally {
+         iterator.close();
+       }
+     }
+ 
+     let hasModifiedDir = async function(aList) {
+       let modifiedDir = false;
+diff --git a/toolkit/components/thumbnails/PageThumbsWorker.js b/toolkit/components/thumbnails/PageThumbsWorker.js
+--- a/toolkit/components/thumbnails/PageThumbsWorker.js
++++ b/toolkit/components/thumbnails/PageThumbsWorker.js
+@@ -84,17 +84,17 @@ var Agent = {
+     try {
+       if (!iter.exists()) {
+         return [];
+       }
+ 
+       let skip = new Set(skipFiles);
+ 
+       let entries = [];
+-      for (let entry in iter) {
++      for (let entry of iter) {
+         if (!entry.isDir && !entry.isSymLink && !skip.has(entry.name)) {
+           entries.push(entry);
+         }
+       }
+       return entries;
+     } finally {
+       iter.close();
+     }
+@@ -103,17 +103,17 @@ var Agent = {
+   moveOrDeleteAllThumbnails:
+   function Agent_moveOrDeleteAllThumbnails(pathFrom, pathTo) {
+     OS.File.makeDir(pathTo, {ignoreExisting: true});
+     if (pathFrom == pathTo) {
+       return true;
+     }
+     let iter = new OS.File.DirectoryIterator(pathFrom);
+     if (iter.exists()) {
+-      for (let entry in iter) {
++      for (let entry of iter) {
+         if (entry.isDir || entry.isSymLink) {
+           continue;
+         }
+ 
+ 
+         let from = OS.Path.join(pathFrom, entry.name);
+         let to = OS.Path.join(pathTo, entry.name);
+ 
+@@ -148,17 +148,17 @@ var Agent = {
+ 
+   copy: function Agent_copy(source, dest, options) {
+     return File.copy(source, dest, options);
+   },
+ 
+   wipe: function Agent_wipe(path) {
+     let iterator = new File.DirectoryIterator(path);
+     try {
+-      for (let entry in iterator) {
++      for (let entry of iterator) {
+         try {
+           File.remove(entry.path);
+         } catch (ex) {
+           // If a file cannot be removed, we should still continue.
+           // This can happen at least for any of the following reasons:
+           // - access denied;
+           // - file has been removed recently during a previous wipe
+           //  and the file system has not flushed that yet (yes, this
+diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
++++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+@@ -6562,40 +6562,43 @@ class SystemAddonInstallLocation extends
+     try {
+       iterator = new OS.File.DirectoryIterator(this._baseDir.path);
+     } catch (e) {
+       logger.error("Failed to clean updated system add-ons directories.", e);
+       return;
+     }
+ 
+     try {
+-      for (let promise in iterator) {
+-        let entry = await promise;
++      for (;;) {
++        let {value: entry, done} = await iterator.next();
++        if (done) {
++          break;
++        }
+ 
+         // Skip the directory currently in use
+         if (this._directory && this._directory.path == entry.path) {
+           continue;
+         }
+ 
+         // Skip the next directory
+         if (this._nextDir && this._nextDir.path == entry.path) {
+           continue;
+         }
+ 
+         if (entry.isDir) {
+-           await OS.File.removeDir(entry.path, {
+-             ignoreAbsent: true,
+-             ignorePermissions: true,
+-           });
+-         } else {
+-           await OS.File.remove(entry.path, {
+-             ignoreAbsent: true,
+-           });
+-         }
+-       }
++          await OS.File.removeDir(entry.path, {
++            ignoreAbsent: true,
++            ignorePermissions: true,
++          });
++        } else {
++          await OS.File.remove(entry.path, {
++            ignoreAbsent: true,
++          });
++        }
++      }
+ 
+     } catch (e) {
+       logger.error("Failed to clean updated system add-ons directories.", e);
+     } finally {
+       iterator.close();
+     }
+   }
+ 

+ 37 - 0
frg/253-58/mozilla-release58_428189.patch

@@ -0,0 +1,37 @@
+# HG changeset patch
+# User Julian Descottes <jdescottes@mozilla.com>
+# Date 1503428817 -7200
+#      Tue Aug 22 21:06:57 2017 +0200
+# Node ID 49655de50701a7e29f9444d525168a0f60ef30d1
+# Parent  b76db9ba7cf67949ae9e138da23603af48f9ee0e
+Bug 1354472 - use readable colors for netmonitor in dark theme;r=ntim
+
+MozReview-Commit-ID: J0Ke2W6Arj6
+
+diff --git a/devtools/client/netmonitor/src/assets/styles/netmonitor.css b/devtools/client/netmonitor/src/assets/styles/netmonitor.css
+--- a/devtools/client/netmonitor/src/assets/styles/netmonitor.css
++++ b/devtools/client/netmonitor/src/assets/styles/netmonitor.css
+@@ -133,21 +133,21 @@ body,
+   margin-inline-end: 10px;
+   margin-top: 4px;
+   margin-bottom: 4px;
+   width: 1px;
+   background: var(--theme-splitter-color);
+ }
+ 
+ .status-bar-label.dom-content-loaded {
+-  color: blue;
++  color: var(--theme-highlight-blue);
+ }
+ 
+ .status-bar-label.load {
+-  color: red;
++  color: var(--theme-highlight-red);
+ }
+ 
+ /* Request list empty panel */
+ 
+ .request-list-empty-notice {
+   margin: 0;
+   padding: 12px;
+   font-size: 120%;

+ 103 - 0
frg/253-58/mozilla-release58_428190.patch

@@ -0,0 +1,103 @@
+# HG changeset patch
+# User Julian Descottes <jdescottes@mozilla.com>
+# Date 1503412304 -7200
+#      Tue Aug 22 16:31:44 2017 +0200
+# Node ID 153b72f168d51548dc73f20cdf1f3d71513efceb
+# Parent  49655de50701a7e29f9444d525168a0f60ef30d1
+Bug 1392531 - create dedicated tab target instance for web-extensions;r=jdescottes
+
+MozReview-Commit-ID: G7EOfYnZuZw
+
+diff --git a/browser/components/extensions/ext-devtools.js b/browser/components/extensions/ext-devtools.js
+--- a/browser/components/extensions/ext-devtools.js
++++ b/browser/components/extensions/ext-devtools.js
+@@ -49,17 +49,18 @@ global.getDevToolsTargetForContext = asy
+     throw new Error("Unable to get a TabTarget for a context not associated to any toolbox");
+   }
+ 
+   if (!context.devToolsToolbox.target.isLocalTab) {
+     throw new Error("Unexpected target type: only local tabs are currently supported.");
+   }
+ 
+   const tab = context.devToolsToolbox.target.tab;
+-  context.devToolsTarget = DevToolsShim.getTargetForTab(tab);
++  context.devToolsTarget = DevToolsShim.createTargetForTab(tab);
++
+   await context.devToolsTarget.makeRemote();
+ 
+   return context.devToolsTarget;
+ };
+ 
+ /**
+  * Retrieve the devtools target for the devtools extension proxy context
+  * (lazily cloned from the target of the toolbox associated to the context
+diff --git a/devtools/client/framework/devtools.js b/devtools/client/framework/devtools.js
+--- a/devtools/client/framework/devtools.js
++++ b/devtools/client/framework/devtools.js
+@@ -6,16 +6,17 @@
+ 
+ const {Cu} = require("chrome");
+ const Services = require("Services");
+ 
+ const {DevToolsShim} = Cu.import("chrome://devtools-shim/content/DevToolsShim.jsm", {});
+ 
+ // Load gDevToolsBrowser toolbox lazily as they need gDevTools to be fully initialized
+ loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
++loader.lazyRequireGetter(this, "TabTarget", "devtools/client/framework/target", true);
+ loader.lazyRequireGetter(this, "Toolbox", "devtools/client/framework/toolbox", true);
+ loader.lazyRequireGetter(this, "ToolboxHostManager", "devtools/client/framework/toolbox-host-manager", true);
+ loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
+ loader.lazyRequireGetter(this, "HUDService", "devtools/client/webconsole/hudservice", true);
+ loader.lazyImporter(this, "ScratchpadManager", "resource://devtools/client/scratchpad/scratchpad-manager.jsm");
+ 
+ // Dependencies required for addon sdk compatibility layer.
+ loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
+@@ -579,16 +580,27 @@ DevTools.prototype = {
+    * Create a BrowserToolbox process linked to the provided addon id.
+    */
+   initBrowserToolboxProcessForAddon: function (addonID) {
+     BrowserToolboxProcess.init({ addonID });
+   },
+ 
+   /**
+    * Compatibility layer for web-extensions. Used by DevToolsShim for
++   * browser/components/extensions/ext-devtools.js
++   *
++   * web-extensions need to use dedicated instances of TabTarget and cannot reuse the
++   * cached instances managed by DevTools target factory.
++   */
++  createTargetForTab: function (tab) {
++    return new TabTarget(tab);
++  },
++
++  /**
++   * Compatibility layer for web-extensions. Used by DevToolsShim for
+    * browser/components/extensions/ext-devtools-inspectedWindow.js
+    */
+   createWebExtensionInspectedWindowFront: function (tabTarget) {
+     return new WebExtensionInspectedWindowFront(tabTarget.client, tabTarget.form);
+   },
+ 
+   /**
+    * Compatibility layer for web-extensions. Used by DevToolsShim for
+diff --git a/devtools/shim/DevToolsShim.jsm b/devtools/shim/DevToolsShim.jsm
+--- a/devtools/shim/DevToolsShim.jsm
++++ b/devtools/shim/DevToolsShim.jsm
+@@ -293,16 +293,17 @@ let addonSdkMethods = [
+ 
+ /**
+  * Compatibility layer for webextensions.
+  *
+  * Those methods are called only after a DevTools webextension was loaded in DevTools,
+  * therefore DevTools should always be available when they are called.
+  */
+ let webExtensionsMethods = [
++  "createTargetForTab",
+   "createWebExtensionInspectedWindowFront",
+   "getTargetForTab",
+   "getTheme",
+   "openBrowserConsole",
+ ];
+ 
+ for (let method of [...addonSdkMethods, ...webExtensionsMethods]) {
+   this.DevToolsShim[method] = function () {

+ 161 - 0
frg/253-58/mozilla-release58_428191.patch

@@ -0,0 +1,161 @@
+# HG changeset patch
+# User Julian Descottes <jdescottes@mozilla.com>
+# Date 1503412334 -7200
+#      Tue Aug 22 16:32:14 2017 +0200
+# Node ID cb33169e67e14d63cea1c8574fae969483ce72a8
+# Parent  153b72f168d51548dc73f20cdf1f3d71513efceb
+Bug 1392531 - add test for devtools extensions using inspected window from panel;r=rpl
+
+MozReview-Commit-ID: F1ZXG9JoySr
+
+diff --git a/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow.js b/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow.js
+--- a/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow.js
++++ b/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow.js
+@@ -1,16 +1,33 @@
+ /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+ /* vim: set sts=2 sw=2 et tw=80: */
+ "use strict";
+ 
+ const {DevToolsShim} = Cu.import("chrome://devtools-shim/content/DevToolsShim.jsm", {});
+ const {gDevTools} = DevToolsShim;
+ 
+ /**
++ * Helper that returns the id of the last additional/extension tool for a provided
++ * toolbox.
++ *
++ * @param {Object} toolbox
++ *        The DevTools toolbox object.
++ * @param {string} label
++ *        The expected label for the additional tool.
++ * @returns {string} the id of the last additional panel.
++ */
++function getAdditionalPanelId(toolbox, label) {
++  // Copy the tools array and pop the last element from it.
++  const panelDef = toolbox.getAdditionalTools().slice().pop();
++  is(panelDef.label, label, "Additional panel label is the expected label");
++  return panelDef.id;
++}
++
++/**
+  * this test file ensures that:
+  *
+  * - the devtools page gets only a subset of the runtime API namespace.
+  * - devtools.inspectedWindow.tabId is the same tabId that we can retrieve
+  *   in the background page using the tabs API namespace.
+  * - devtools API is available in the devtools page sub-frames when a valid
+  *   extension URL has been loaded.
+  * - devtools.inspectedWindow.eval:
+@@ -229,8 +246,113 @@ add_task(async function test_devtools_in
+   await gDevTools.closeToolbox(target);
+ 
+   await target.destroy();
+ 
+   await extension.unload();
+ 
+   await BrowserTestUtils.removeTab(tab);
+ });
++
++/**
++ * This test asserts that both the page and the panel can use devtools.inspectedWindow.
++ * See regression in Bug https://bugzilla.mozilla.org/show_bug.cgi?id=1392531
++ */
++add_task(async function test_devtools_inspectedWindow_eval_in_page_and_panel() {
++  const TEST_TARGET_URL = "http://mochi.test:8888/";
++  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_TARGET_URL);
++
++  async function devtools_page() {
++    await browser.devtools.panels.create("test-eval", "fake-icon.png", "devtools_panel.html");
++
++    browser.test.onMessage.addListener(async (msg, ...args) => {
++      if (msg !== "inspectedWindow-eval-request") {
++        browser.test.fail(`Unexpected test message received: ${msg}`);
++        return;
++      }
++
++      const [evalResult, errorResult] = await browser.devtools.inspectedWindow.eval(...args);
++      browser.test.sendMessage("inspectedWindow-page-eval-result", {
++        evalResult,
++        errorResult,
++      });
++    });
++
++    browser.test.sendMessage("devtools_panel_created");
++  }
++
++  function devtools_panel() {
++    browser.test.onMessage.addListener(async (msg, ...args) => {
++      if (msg !== "inspectedWindow-eval-request") {
++        browser.test.fail(`Unexpected test message received: ${msg}`);
++        return;
++      }
++
++      const [evalResult, errorResult] = await browser.devtools.inspectedWindow.eval(...args);
++      browser.test.sendMessage("inspectedWindow-panel-eval-result", {
++        evalResult,
++        errorResult,
++      });
++    });
++    browser.test.sendMessage("devtools_panel_initialized");
++  }
++
++  let extension = ExtensionTestUtils.loadExtension({
++    manifest: {
++      devtools_page: "devtools_page.html",
++    },
++    files: {
++      "devtools_page.html": `<!DOCTYPE html>
++      <html>
++       <head>
++         <meta charset="utf-8">
++         <script text="text/javascript" src="devtools_page.js"></script>
++       </head>
++       <body>
++       </body>
++      </html>`,
++      "devtools_page.js": devtools_page,
++      "devtools_panel.html":  `<!DOCTYPE html>
++      <html>
++       <head>
++         <meta charset="utf-8">
++       </head>
++       <body>
++         DEVTOOLS PANEL
++         <script src="devtools_panel.js"></script>
++       </body>
++      </html>`,
++      "devtools_panel.js": devtools_panel,
++    },
++  });
++
++  await extension.startup();
++
++  const target = gDevTools.getTargetForTab(tab);
++  const toolbox = await gDevTools.showToolbox(target, "webconsole");
++  info("developer toolbox opened");
++
++  info("Wait for devtools_panel_created event");
++  await extension.awaitMessage("devtools_panel_created");
++
++  info("Switch to the extension test panel");
++  await gDevTools.showToolbox(target, getAdditionalPanelId(toolbox, "test-eval"));
++
++  info("Wait for devtools_panel_initialized event");
++  await extension.awaitMessage("devtools_panel_initialized");
++
++  info(`test inspectedWindow.eval with eval(window.location.href)`);
++  extension.sendMessage(`inspectedWindow-eval-request`, "window.location.href");
++
++  info("Wait for response from the page");
++  let {evalResult} = await extension.awaitMessage(`inspectedWindow-page-eval-result`);
++  Assert.deepEqual(evalResult, TEST_TARGET_URL, "Got the expected eval result in the page");
++
++  info("Wait for response from the panel");
++  ({evalResult} = await extension.awaitMessage(`inspectedWindow-panel-eval-result`));
++  Assert.deepEqual(evalResult, TEST_TARGET_URL, "Got the expected eval result in the panel");
++
++  // Cleanup
++  await gDevTools.closeToolbox(target);
++  await target.destroy();
++  await extension.unload();
++  await BrowserTestUtils.removeTab(tab);
++});

+ 3119 - 0
frg/253-58/mozilla-release58_428195.patch

@@ -0,0 +1,3119 @@
+# HG changeset patch
+# User Masatoshi Kimura <VYV03354@nifty.ne.jp>
+# Date 1502728307 -32400
+#      Tue Aug 15 01:31:47 2017 +0900
+# Node ID 6aa160333132ace550feb005d1157cea446dba90
+# Parent  0ae21c1a172fe4ef5f45547a4985adec354b23ad
+Bug 1390209 - Remove unused nsIDOMHTML*Element interfaces. r=qdot
+
+MozReview-Commit-ID: DagD3IHhRZy
+
+diff --git a/accessible/html/HTMLImageMapAccessible.h b/accessible/html/HTMLImageMapAccessible.h
+--- a/accessible/html/HTMLImageMapAccessible.h
++++ b/accessible/html/HTMLImageMapAccessible.h
+@@ -3,17 +3,16 @@
+  * 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/. */
+ 
+ #ifndef mozilla_a11y_HTMLImageMapAccessible_h__
+ #define mozilla_a11y_HTMLImageMapAccessible_h__
+ 
+ #include "HTMLLinkAccessible.h"
+ #include "ImageAccessibleWrap.h"
+-#include "nsIDOMHTMLMapElement.h"
+ 
+ namespace mozilla {
+ namespace a11y {
+ 
+ /**
+  * Used for HTML image maps.
+  */
+ class HTMLImageMapAccessible final : public ImageAccessibleWrap
+diff --git a/dom/html/HTMLBodyElement.cpp b/dom/html/HTMLBodyElement.cpp
+--- a/dom/html/HTMLBodyElement.cpp
++++ b/dom/html/HTMLBodyElement.cpp
+@@ -33,123 +33,20 @@ HTMLBodyElement::~HTMLBodyElement()
+ }
+ 
+ JSObject*
+ HTMLBodyElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
+ {
+   return HTMLBodyElementBinding::Wrap(aCx, this, aGivenProto);
+ }
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLBodyElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLBodyElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLBodyElement, nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLBodyElement)
+ 
+-NS_IMETHODIMP
+-HTMLBodyElement::SetBackground(const nsAString& aBackground)
+-{
+-  ErrorResult rv;
+-  SetBackground(aBackground, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLBodyElement::GetBackground(nsAString& aBackground)
+-{
+-  DOMString background;
+-  GetBackground(background);
+-  background.ToString(aBackground);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLBodyElement::SetVLink(const nsAString& aVLink)
+-{
+-  ErrorResult rv;
+-  SetVLink(aVLink, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLBodyElement::GetVLink(nsAString& aVLink)
+-{
+-  DOMString vLink;
+-  GetVLink(vLink);
+-  vLink.ToString(aVLink);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLBodyElement::SetALink(const nsAString& aALink)
+-{
+-  ErrorResult rv;
+-  SetALink(aALink, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLBodyElement::GetALink(nsAString& aALink)
+-{
+-  DOMString aLink;
+-  GetALink(aLink);
+-  aLink.ToString(aALink);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLBodyElement::SetLink(const nsAString& aLink)
+-{
+-  ErrorResult rv;
+-  SetLink(aLink, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLBodyElement::GetLink(nsAString& aLink)
+-{
+-  DOMString link;
+-  GetLink(link);
+-  link.ToString(aLink);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLBodyElement::SetText(const nsAString& aText)
+-{
+-  ErrorResult rv;
+-  SetText(aText, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLBodyElement::GetText(nsAString& aText)
+-{
+-  DOMString text;
+-  GetText(text);
+-  text.ToString(aText);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLBodyElement::SetBgColor(const nsAString& aBgColor)
+-{
+-  ErrorResult rv;
+-  SetBgColor(aBgColor, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLBodyElement::GetBgColor(nsAString& aBgColor)
+-{
+-  DOMString bgColor;
+-  GetBgColor(bgColor);
+-  bgColor.ToString(aBgColor);
+-  return NS_OK;
+-}
+-
+ bool
+ HTMLBodyElement::ParseAttribute(int32_t aNamespaceID,
+                                 nsIAtom* aAttribute,
+                                 const nsAString& aValue,
+                                 nsAttrValue& aResult)
+ {
+   if (aNamespaceID == kNameSpaceID_None) {
+     if (aAttribute == nsGkAtoms::bgcolor ||
+diff --git a/dom/html/HTMLBodyElement.h b/dom/html/HTMLBodyElement.h
+--- a/dom/html/HTMLBodyElement.h
++++ b/dom/html/HTMLBodyElement.h
+@@ -3,97 +3,112 @@
+ /* 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/. */
+ #ifndef HTMLBodyElement_h___
+ #define HTMLBodyElement_h___
+ 
+ #include "mozilla/Attributes.h"
+ #include "nsGenericHTMLElement.h"
+-#include "nsIDOMHTMLBodyElement.h"
+ #include "nsIStyleRule.h"
+ 
+ namespace mozilla {
+ 
+ class TextEditor;
+ 
+ namespace dom {
+ 
+ class OnBeforeUnloadEventHandlerNonNull;
+ 
+-class HTMLBodyElement final : public nsGenericHTMLElement,
+-                              public nsIDOMHTMLBodyElement
++class HTMLBodyElement final : public nsGenericHTMLElement
+ {
+ public:
+   using Element::GetText;
+   using Element::SetText;
+ 
+   explicit HTMLBodyElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+     : nsGenericHTMLElement(aNodeInfo)
+   {
+   }
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLBodyElement
+-  NS_DECL_NSIDOMHTMLBODYELEMENT
+-
+   // Event listener stuff; we need to declare only the ones we need to
+   // forward to window that don't come from nsIDOMHTMLBodyElement.
+ #define EVENT(name_, id_, type_, struct_) /* nothing; handled by the shim */
+ #define WINDOW_EVENT_HELPER(name_, type_)                               \
+   type_* GetOn##name_();                                                \
+   void SetOn##name_(type_* handler);
+ #define WINDOW_EVENT(name_, id_, type_, struct_)                        \
+   WINDOW_EVENT_HELPER(name_, EventHandlerNonNull)
+ #define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_)                  \
+   WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
+ #include "mozilla/EventNameList.h" // IWYU pragma: keep
+ #undef BEFOREUNLOAD_EVENT
+ #undef WINDOW_EVENT
+ #undef WINDOW_EVENT_HELPER
+ #undef EVENT
+ 
+-  void GetText(DOMString& aText)
++  void GetText(nsAString& aText)
+   {
+     GetHTMLAttr(nsGkAtoms::text, aText);
+   }
++  void SetText(const nsAString& aText)
++  {
++    SetHTMLAttr(nsGkAtoms::text, aText);
++  }
+   void SetText(const nsAString& aText, ErrorResult& aError)
+   {
+     SetHTMLAttr(nsGkAtoms::text, aText, aError);
+   }
+-  void GetLink(DOMString& aLink)
++  void GetLink(nsAString& aLink)
+   {
+     GetHTMLAttr(nsGkAtoms::link, aLink);
+   }
++  void SetLink(const nsAString& aLink)
++  {
++    SetHTMLAttr(nsGkAtoms::link, aLink);
++  }
+   void SetLink(const nsAString& aLink, ErrorResult& aError)
+   {
+     SetHTMLAttr(nsGkAtoms::link, aLink, aError);
+   }
+-  void GetVLink(DOMString& aVLink)
++  void GetVLink(nsAString& aVLink)
+   {
+     GetHTMLAttr(nsGkAtoms::vlink, aVLink);
+   }
++  void SetVLink(const nsAString& aVLink)
++  {
++    SetHTMLAttr(nsGkAtoms::vlink, aVLink);
++  }
+   void SetVLink(const nsAString& aVLink, ErrorResult& aError)
+   {
+     SetHTMLAttr(nsGkAtoms::vlink, aVLink, aError);
+   }
+-  void GetALink(DOMString& aALink)
++  void GetALink(nsAString& aALink)
+   {
+     GetHTMLAttr(nsGkAtoms::alink, aALink);
+   }
++  void SetALink(const nsAString& aALink)
++  {
++    SetHTMLAttr(nsGkAtoms::alink, aALink);
++  }
+   void SetALink(const nsAString& aALink, ErrorResult& aError)
+   {
+     SetHTMLAttr(nsGkAtoms::alink, aALink, aError);
+   }
+-  void GetBgColor(DOMString& aBgColor)
++  void GetBgColor(nsAString& aBgColor)
+   {
+     GetHTMLAttr(nsGkAtoms::bgcolor, aBgColor);
+   }
++  void SetBgColor(const nsAString& aBgColor)
++  {
++    SetHTMLAttr(nsGkAtoms::bgcolor, aBgColor);
++  }
+   void SetBgColor(const nsAString& aBgColor, ErrorResult& aError)
+   {
+     SetHTMLAttr(nsGkAtoms::bgcolor, aBgColor, aError);
+   }
+   void GetBackground(DOMString& aBackground)
+   {
+     GetHTMLAttr(nsGkAtoms::background, aBackground);
+   }
+diff --git a/dom/html/HTMLFieldSetElement.cpp b/dom/html/HTMLFieldSetElement.cpp
+--- a/dom/html/HTMLFieldSetElement.cpp
++++ b/dom/html/HTMLFieldSetElement.cpp
+@@ -44,26 +44,22 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLF
+                                    mValidity, mElements)
+ 
+ NS_IMPL_ADDREF_INHERITED(HTMLFieldSetElement, Element)
+ NS_IMPL_RELEASE_INHERITED(HTMLFieldSetElement, Element)
+ 
+ // QueryInterface implementation for HTMLFieldSetElement
+ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLFieldSetElement)
+   NS_INTERFACE_TABLE_INHERITED(HTMLFieldSetElement,
+-                               nsIDOMHTMLFieldSetElement,
+                                nsIConstraintValidation)
+ NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLFieldSetElement)
+ 
+ 
+-NS_IMPL_BOOL_ATTR(HTMLFieldSetElement, Disabled, disabled)
+-NS_IMPL_STRING_ATTR(HTMLFieldSetElement, Name, name)
+-
+ bool
+ HTMLFieldSetElement::IsDisabledForEvents(EventMessage aMessage)
+ {
+   return IsElementDisabledForEvents(aMessage, nullptr);
+ }
+ 
+ // nsIContent
+ nsresult
+@@ -101,47 +97,32 @@ HTMLFieldSetElement::AfterSetAttr(int32_
+       }
+     }
+   }
+ 
+   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
+                                                 aValue, aOldValue, aNotify);
+ }
+ 
+-// nsIDOMHTMLFieldSetElement
+-
+-NS_IMETHODIMP
+-HTMLFieldSetElement::GetForm(nsIDOMHTMLFormElement** aForm)
+-{
+-  return nsGenericHTMLFormElement::GetForm(aForm);
+-}
+-
+ NS_IMETHODIMP
+ HTMLFieldSetElement::GetType(nsAString& aType)
+ {
+   aType.AssignLiteral("fieldset");
+   return NS_OK;
+ }
+ 
+ /* static */
+ bool
+ HTMLFieldSetElement::MatchListedElements(Element* aElement, int32_t aNamespaceID,
+                                          nsIAtom* aAtom, void* aData)
+ {
+   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aElement);
+   return formControl;
+ }
+ 
+-NS_IMETHODIMP
+-HTMLFieldSetElement::GetElements(nsIDOMHTMLCollection** aElements)
+-{
+-  NS_ADDREF(*aElements = Elements());
+-  return NS_OK;
+-}
+-
+ nsIHTMLCollection*
+ HTMLFieldSetElement::Elements()
+ {
+   if (!mElements) {
+     mElements = new nsContentList(this, MatchListedElements, nullptr, nullptr,
+                                   true);
+   }
+ 
+diff --git a/dom/html/HTMLFieldSetElement.h b/dom/html/HTMLFieldSetElement.h
+--- a/dom/html/HTMLFieldSetElement.h
++++ b/dom/html/HTMLFieldSetElement.h
+@@ -4,44 +4,39 @@
+  * 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/. */
+ 
+ #ifndef mozilla_dom_HTMLFieldSetElement_h
+ #define mozilla_dom_HTMLFieldSetElement_h
+ 
+ #include "mozilla/Attributes.h"
+ #include "nsGenericHTMLElement.h"
+-#include "nsIDOMHTMLFieldSetElement.h"
+ #include "nsIConstraintValidation.h"
+ #include "mozilla/dom/HTMLFormElement.h"
+ #include "mozilla/dom/ValidityState.h"
+ 
+ namespace mozilla {
+ class EventChainPreVisitor;
+ namespace dom {
+ 
+ class HTMLFieldSetElement final : public nsGenericHTMLFormElement,
+-                                  public nsIDOMHTMLFieldSetElement,
+                                   public nsIConstraintValidation
+ {
+ public:
+   using nsGenericHTMLFormElement::GetForm;
+   using nsIConstraintValidation::GetValidationMessage;
+   using nsIConstraintValidation::SetCustomValidity;
+ 
+   explicit HTMLFieldSetElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
+ 
+   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLFieldSetElement, fieldset)
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLFieldSetElement
+-  NS_DECL_NSIDOMHTMLFIELDSETELEMENT
+-
+   // nsIContent
+   virtual nsresult GetEventTargetParent(
+                      EventChainPreVisitor& aVisitor) override;
+   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+                                 const nsAttrValue* aValue,
+                                 const nsAttrValue* aOldValue,
+                                 bool aNotify) override;
+ 
+@@ -70,24 +65,27 @@ public:
+   {
+     return GetBoolAttr(nsGkAtoms::disabled);
+   }
+   void SetDisabled(bool aValue, ErrorResult& aRv)
+   {
+     SetHTMLBoolAttr(nsGkAtoms::disabled, aValue, aRv);
+   }
+ 
+-  // XPCOM GetName is OK for us
++  void GetName(nsAString& aValue)
++  {
++    GetHTMLAttr(nsGkAtoms::name, aValue);
++  }
+ 
+   void SetName(const nsAString& aValue, ErrorResult& aRv)
+   {
+     SetHTMLAttr(nsGkAtoms::name, aValue, aRv);
+   }
+ 
+-  // XPCOM GetType is OK for us
++  NS_IMETHOD GetType(nsAString & aType);
+ 
+   nsIHTMLCollection* Elements();
+ 
+   // XPCOM WillValidate is OK for us
+ 
+   // XPCOM Validity is OK for us
+ 
+   // XPCOM GetValidationMessage is OK for us
+diff --git a/dom/html/HTMLFrameSetElement.cpp b/dom/html/HTMLFrameSetElement.cpp
+--- a/dom/html/HTMLFrameSetElement.cpp
++++ b/dom/html/HTMLFrameSetElement.cpp
+@@ -21,55 +21,20 @@ HTMLFrameSetElement::~HTMLFrameSetElemen
+ }
+ 
+ JSObject*
+ HTMLFrameSetElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
+ {
+   return HTMLFrameSetElementBinding::Wrap(aCx, this, aGivenProto);
+ }
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLFrameSetElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLFrameSetElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLFrameSetElement, nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLFrameSetElement)
+ 
+-NS_IMETHODIMP
+-HTMLFrameSetElement::SetCols(const nsAString& aCols)
+-{
+-  ErrorResult rv;
+-  SetCols(aCols, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLFrameSetElement::GetCols(nsAString& aCols)
+-{
+-  DOMString cols;
+-  GetCols(cols);
+-  cols.ToString(aCols);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLFrameSetElement::SetRows(const nsAString& aRows)
+-{
+-  ErrorResult rv;
+-  SetRows(aRows, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLFrameSetElement::GetRows(nsAString& aRows)
+-{
+-  DOMString rows;
+-  GetRows(rows);
+-  rows.ToString(aRows);
+-  return NS_OK;
+-}
+-
+ nsresult
+ HTMLFrameSetElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+                                    const nsAttrValueOrString* aValue,
+                                    bool aNotify)
+ {
+   /* The main goal here is to see whether the _number_ of rows or
+    * columns has changed. If it has, we need to reframe; otherwise
+    * we want to reflow.
+diff --git a/dom/html/HTMLFrameSetElement.h b/dom/html/HTMLFrameSetElement.h
+--- a/dom/html/HTMLFrameSetElement.h
++++ b/dom/html/HTMLFrameSetElement.h
+@@ -4,17 +4,16 @@
+  * 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/. */
+ 
+ #ifndef HTMLFrameSetElement_h
+ #define HTMLFrameSetElement_h
+ 
+ #include "mozilla/Attributes.h"
+ #include "mozilla/UniquePtr.h"
+-#include "nsIDOMHTMLFrameSetElement.h"
+ #include "nsGenericHTMLElement.h"
+ 
+ /**
+  * The nsFramesetUnit enum is used to denote the type of each entry
+  * in the row or column spec.
+  */
+ enum nsFramesetUnit {
+   eFramesetUnit_Fixed = 0,
+@@ -39,37 +38,33 @@ struct nsFramesetSpec {
+ 
+ //----------------------------------------------------------------------
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+ class OnBeforeUnloadEventHandlerNonNull;
+ 
+-class HTMLFrameSetElement final : public nsGenericHTMLElement,
+-                                  public nsIDOMHTMLFrameSetElement
++class HTMLFrameSetElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLFrameSetElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+     : nsGenericHTMLElement(aNodeInfo),
+       mNumRows(0),
+       mNumCols(0),
+       mCurrentRowColHint(NS_STYLE_HINT_REFLOW)
+   {
+     SetHasWeirdParserInsertionMode();
+   }
+ 
+   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLFrameSetElement, frameset)
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLFrameSetElement
+-  NS_DECL_NSIDOMHTMLFRAMESETELEMENT
+-
+   void GetCols(DOMString& aCols)
+   {
+     GetHTMLAttr(nsGkAtoms::cols, aCols);
+   }
+   void SetCols(const nsAString& aCols, ErrorResult& aError)
+   {
+     SetHTMLAttr(nsGkAtoms::cols, aCols, aError);
+   }
+diff --git a/dom/html/HTMLHRElement.cpp b/dom/html/HTMLHRElement.cpp
+--- a/dom/html/HTMLHRElement.cpp
++++ b/dom/html/HTMLHRElement.cpp
+@@ -16,18 +16,17 @@ HTMLHRElement::HTMLHRElement(already_Add
+   : nsGenericHTMLElement(aNodeInfo)
+ {
+ }
+ 
+ HTMLHRElement::~HTMLHRElement()
+ {
+ }
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLHRElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLHRElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLHRElement, nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLHRElement)
+ 
+ 
+ bool
+ HTMLHRElement::ParseAttribute(int32_t aNamespaceID,
+                               nsIAtom* aAttribute,
+                               const nsAString& aValue,
+diff --git a/dom/html/HTMLHRElement.h b/dom/html/HTMLHRElement.h
+--- a/dom/html/HTMLHRElement.h
++++ b/dom/html/HTMLHRElement.h
+@@ -4,36 +4,31 @@
+  * 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/. */
+ 
+ 
+ #ifndef mozilla_dom_HTMLHRElement_h
+ #define mozilla_dom_HTMLHRElement_h
+ 
+ #include "nsGenericHTMLElement.h"
+-#include "nsIDOMHTMLHRElement.h"
+ #include "nsMappedAttributes.h"
+ #include "nsAttrValueInlines.h"
+ #include "nsRuleData.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+-class HTMLHRElement final : public nsGenericHTMLElement,
+-                            public nsIDOMHTMLHRElement
++class HTMLHRElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLHRElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLHRElement
+-  NS_DECL_NSIDOMHTMLHRELEMENT
+-
+   virtual bool ParseAttribute(int32_t aNamespaceID,
+                               nsIAtom* aAttribute,
+                               const nsAString& aValue,
+                               nsAttrValue& aResult) override;
+   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
+   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
+   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                          bool aPreallocateChildren) const override;
+diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp
+--- a/dom/html/HTMLImageElement.cpp
++++ b/dom/html/HTMLImageElement.cpp
+@@ -36,17 +36,16 @@
+ 
+ #include "imgIContainer.h"
+ #include "imgILoader.h"
+ #include "imgINotificationObserver.h"
+ #include "imgRequestProxy.h"
+ 
+ #include "nsILoadGroup.h"
+ 
+-#include "nsIDOMHTMLMapElement.h"
+ #include "mozilla/EventDispatcher.h"
+ #include "mozilla/EventStates.h"
+ #include "mozilla/GenericSpecifiedValuesInlines.h"
+ #include "mozilla/net/ReferrerPolicy.h"
+ 
+ #include "nsLayoutUtils.h"
+ 
+ using namespace mozilla::net;
+diff --git a/dom/html/HTMLLIElement.cpp b/dom/html/HTMLLIElement.cpp
+--- a/dom/html/HTMLLIElement.cpp
++++ b/dom/html/HTMLLIElement.cpp
+@@ -17,24 +17,20 @@ NS_IMPL_NS_NEW_HTML_ELEMENT(LI)
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+ HTMLLIElement::~HTMLLIElement()
+ {
+ }
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLLIElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLLIElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLLIElement, nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLLIElement)
+ 
+-NS_IMPL_STRING_ATTR(HTMLLIElement, Type, type)
+-NS_IMPL_INT_ATTR(HTMLLIElement, Value, value)
+-
+ // values that are handled case-insensitively
+ static const nsAttrValue::EnumTable kUnorderedListItemTypeTable[] = {
+   { "disc", NS_STYLE_LIST_STYLE_DISC },
+   { "circle", NS_STYLE_LIST_STYLE_CIRCLE },
+   { "round", NS_STYLE_LIST_STYLE_CIRCLE },
+   { "square", NS_STYLE_LIST_STYLE_SQUARE },
+   { nullptr, 0 }
+ };
+diff --git a/dom/html/HTMLLIElement.h b/dom/html/HTMLLIElement.h
+--- a/dom/html/HTMLLIElement.h
++++ b/dom/html/HTMLLIElement.h
+@@ -4,37 +4,32 @@
+  * 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/. */
+ 
+ #ifndef mozilla_dom_HTMLLIElement_h
+ #define mozilla_dom_HTMLLIElement_h
+ 
+ #include "mozilla/Attributes.h"
+ 
+-#include "nsIDOMHTMLLIElement.h"
+ #include "nsGenericHTMLElement.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+-class HTMLLIElement final : public nsGenericHTMLElement,
+-                            public nsIDOMHTMLLIElement
++class HTMLLIElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLLIElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+     : nsGenericHTMLElement(aNodeInfo)
+   {
+   }
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLLIElement
+-  NS_DECL_NSIDOMHTMLLIELEMENT
+-
+   virtual bool ParseAttribute(int32_t aNamespaceID,
+                                 nsIAtom* aAttribute,
+                                 const nsAString& aValue,
+                                 nsAttrValue& aResult) override;
+   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
+   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
+   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                          bool aPreallocateChildren) const override;
+diff --git a/dom/html/HTMLLabelElement.cpp b/dom/html/HTMLLabelElement.cpp
+--- a/dom/html/HTMLLabelElement.cpp
++++ b/dom/html/HTMLLabelElement.cpp
+@@ -30,56 +30,22 @@ HTMLLabelElement::~HTMLLabelElement()
+ JSObject*
+ HTMLLabelElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
+ {
+   return HTMLLabelElementBinding::Wrap(aCx, this, aGivenProto);
+ }
+ 
+ // nsISupports
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLLabelElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLLabelElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLLabelElement, nsGenericHTMLElement)
+ 
+ // nsIDOMHTMLLabelElement
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLLabelElement)
+ 
+-NS_IMETHODIMP
+-HTMLLabelElement::GetForm(nsIDOMHTMLFormElement** aForm)
+-{
+-  RefPtr<nsIDOMHTMLFormElement> form = GetForm();
+-  form.forget(aForm);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLLabelElement::GetControl(nsIDOMHTMLElement** aElement)
+-{
+-  nsCOMPtr<nsIDOMHTMLElement> element = do_QueryObject(GetLabeledElement());
+-  element.forget(aElement);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLLabelElement::SetHtmlFor(const nsAString& aHtmlFor)
+-{
+-  ErrorResult rv;
+-  SetHtmlFor(aHtmlFor, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLLabelElement::GetHtmlFor(nsAString& aHtmlFor)
+-{
+-  nsString htmlFor;
+-  GetHtmlFor(htmlFor);
+-  aHtmlFor = htmlFor;
+-  return NS_OK;
+-}
+-
+ HTMLFormElement*
+ HTMLLabelElement::GetForm() const
+ {
+   nsGenericHTMLElement* control = GetControl();
+   if (!control) {
+     return nullptr;
+   }
+ 
+diff --git a/dom/html/HTMLLabelElement.h b/dom/html/HTMLLabelElement.h
+--- a/dom/html/HTMLLabelElement.h
++++ b/dom/html/HTMLLabelElement.h
+@@ -7,24 +7,22 @@
+ /**
+  * Declaration of HTML <label> elements.
+  */
+ #ifndef HTMLLabelElement_h
+ #define HTMLLabelElement_h
+ 
+ #include "mozilla/Attributes.h"
+ #include "nsGenericHTMLElement.h"
+-#include "nsIDOMHTMLLabelElement.h"
+ 
+ namespace mozilla {
+ class EventChainPostVisitor;
+ namespace dom {
+ 
+-class HTMLLabelElement final : public nsGenericHTMLElement,
+-                               public nsIDOMHTMLLabelElement
++class HTMLLabelElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLLabelElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+     : nsGenericHTMLElement(aNodeInfo),
+       mHandlingEvent(false)
+   {
+   }
+ 
+@@ -34,27 +32,24 @@ public:
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+   // Element
+   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override
+   {
+     return true;
+   }
+ 
+-  // nsIDOMHTMLLabelElement
+-  NS_DECL_NSIDOMHTMLLABELELEMENT
+-
+   HTMLFormElement* GetForm() const;
+   void GetHtmlFor(nsString& aHtmlFor)
+   {
+     GetHTMLAttr(nsGkAtoms::_for, aHtmlFor);
+   }
+-  void SetHtmlFor(const nsAString& aHtmlFor, ErrorResult& aError)
++  void SetHtmlFor(const nsAString& aHtmlFor)
+   {
+-    SetHTMLAttr(nsGkAtoms::_for, aHtmlFor, aError);
++    SetHTMLAttr(nsGkAtoms::_for, aHtmlFor);
+   }
+   nsGenericHTMLElement* GetControl() const
+   {
+     return GetLabeledElement();
+   }
+ 
+   using nsGenericHTMLElement::Focus;
+   virtual void Focus(mozilla::ErrorResult& aError) override;
+diff --git a/dom/html/HTMLMapElement.cpp b/dom/html/HTMLMapElement.cpp
+--- a/dom/html/HTMLMapElement.cpp
++++ b/dom/html/HTMLMapElement.cpp
+@@ -29,17 +29,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+ 
+ NS_IMPL_ADDREF_INHERITED(HTMLMapElement, Element)
+ NS_IMPL_RELEASE_INHERITED(HTMLMapElement, Element)
+ 
+ 
+ // QueryInterface implementation for HTMLMapElement
+ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLMapElement)
+-  NS_INTERFACE_TABLE_INHERITED(HTMLMapElement, nsIDOMHTMLMapElement)
++  NS_INTERFACE_TABLE_INHERITED(HTMLMapElement, nsIDOMHTMLElement)
+ NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLMapElement)
+ 
+ 
+ nsIHTMLCollection*
+ HTMLMapElement::Areas()
+ {
+@@ -50,27 +50,16 @@ HTMLMapElement::Areas()
+                                nsGkAtoms::area,
+                                nsGkAtoms::area,
+                                false);
+   }
+ 
+   return mAreas;
+ }
+ 
+-NS_IMETHODIMP
+-HTMLMapElement::GetAreas(nsIDOMHTMLCollection** aAreas)
+-{
+-  NS_ENSURE_ARG_POINTER(aAreas);
+-  NS_ADDREF(*aAreas = Areas());
+-  return NS_OK;
+-}
+-
+-
+-NS_IMPL_STRING_ATTR(HTMLMapElement, Name, name)
+-
+ 
+ JSObject*
+ HTMLMapElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+ {
+   return HTMLMapElementBinding::Wrap(aCx, this, aGivenProto);
+ }
+ 
+ } // namespace dom
+diff --git a/dom/html/HTMLMapElement.h b/dom/html/HTMLMapElement.h
+--- a/dom/html/HTMLMapElement.h
++++ b/dom/html/HTMLMapElement.h
+@@ -4,43 +4,41 @@
+  * 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/. */
+ 
+ #ifndef mozilla_dom_HTMLMapElement_h
+ #define mozilla_dom_HTMLMapElement_h
+ 
+ #include "mozilla/Attributes.h"
+ #include "nsGenericHTMLElement.h"
+-#include "nsIDOMHTMLMapElement.h"
+ #include "nsGkAtoms.h"
+ 
+ class nsContentList;
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+-class HTMLMapElement final : public nsGenericHTMLElement,
+-                             public nsIDOMHTMLMapElement
++class HTMLMapElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLMapElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLMapElement
+-  NS_DECL_NSIDOMHTMLMAPELEMENT
+-
+   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                          bool aPreallocateChildren) const override;
+ 
+   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(HTMLMapElement,
+                                                      nsGenericHTMLElement)
+ 
+-  // XPCOM GetName is fine.
++  void GetName(nsAString& aValue)
++  {
++    GetHTMLAttr(nsGkAtoms::name, aValue);
++  }
+   void SetName(const nsAString& aName, ErrorResult& aError)
+   {
+     SetHTMLAttr(nsGkAtoms::name, aName, aError);
+   }
+   nsIHTMLCollection* Areas();
+ 
+   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+ 
+diff --git a/dom/html/HTMLMenuElement.cpp b/dom/html/HTMLMenuElement.cpp
+--- a/dom/html/HTMLMenuElement.cpp
++++ b/dom/html/HTMLMenuElement.cpp
+@@ -50,26 +50,20 @@ HTMLMenuElement::HTMLMenuElement(already
+   : nsGenericHTMLElement(aNodeInfo), mType(MENU_TYPE_TOOLBAR)
+ {
+ }
+ 
+ HTMLMenuElement::~HTMLMenuElement()
+ {
+ }
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLMenuElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLMenuElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLMenuElement, nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLMenuElement)
+ 
+-NS_IMPL_BOOL_ATTR(HTMLMenuElement, Compact, compact)
+-NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLMenuElement, Type, type,
+-                                kMenuDefaultType->tag)
+-NS_IMPL_STRING_ATTR(HTMLMenuElement, Label, label)
+-
+ 
+ void
+ HTMLMenuElement::SendShowEvent()
+ {
+   nsCOMPtr<nsIDocument> document = GetComposedDoc();
+   if (!document) {
+     return;
+   }
+diff --git a/dom/html/HTMLMenuElement.h b/dom/html/HTMLMenuElement.h
+--- a/dom/html/HTMLMenuElement.h
++++ b/dom/html/HTMLMenuElement.h
+@@ -3,61 +3,62 @@
+ /* 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/. */
+ 
+ #ifndef mozilla_dom_HTMLMenuElement_h
+ #define mozilla_dom_HTMLMenuElement_h
+ 
+ #include "mozilla/Attributes.h"
+-#include "nsIDOMHTMLMenuElement.h"
+ #include "nsGenericHTMLElement.h"
+ 
+ class nsIMenuBuilder;
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+-class HTMLMenuElement final : public nsGenericHTMLElement,
+-                              public nsIDOMHTMLMenuElement
++class HTMLMenuElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLMenuElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
+ 
+   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLMenuElement, menu)
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLMenuElement
+-  NS_DECL_NSIDOMHTMLMENUELEMENT
+-
+   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+                                 const nsAttrValue* aValue,
+                                 const nsAttrValue* aOldValue,
+                                 bool aNotify) override;
+   virtual bool ParseAttribute(int32_t aNamespaceID,
+                                 nsIAtom* aAttribute,
+                                 const nsAString& aValue,
+                                 nsAttrValue& aResult) override;
+ 
+   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                          bool aPreallocateChildren) const override;
+ 
+   uint8_t GetType() const { return mType; }
+ 
+   // WebIDL
+ 
+-  // The XPCOM GetType is OK for us
++  void GetType(nsAString& aValue)
++  {
++    GetHTMLAttr(nsGkAtoms::type, aValue);
++  }
+   void SetType(const nsAString& aType, ErrorResult& aError)
+   {
+     SetHTMLAttr(nsGkAtoms::type, aType, aError);
+   }
+ 
+-  // The XPCOM GetLabel is OK for us
++  void GetLabel(nsAString& aValue)
++  {
++    GetHTMLAttr(nsGkAtoms::label, aValue);
++  }
+   void SetLabel(const nsAString& aLabel, ErrorResult& aError)
+   {
+     SetHTMLAttr(nsGkAtoms::label, aLabel, aError);
+   }
+ 
+   bool Compact() const
+   {
+     return GetBoolAttr(nsGkAtoms::compact);
+diff --git a/dom/html/HTMLMetaElement.cpp b/dom/html/HTMLMetaElement.cpp
+--- a/dom/html/HTMLMetaElement.cpp
++++ b/dom/html/HTMLMetaElement.cpp
+@@ -22,27 +22,21 @@ HTMLMetaElement::HTMLMetaElement(already
+ {
+ }
+ 
+ HTMLMetaElement::~HTMLMetaElement()
+ {
+ }
+ 
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLMetaElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLMetaElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLMetaElement, nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLMetaElement)
+ 
+ 
+-NS_IMPL_STRING_ATTR(HTMLMetaElement, Content, content)
+-NS_IMPL_STRING_ATTR(HTMLMetaElement, HttpEquiv, httpEquiv)
+-NS_IMPL_STRING_ATTR(HTMLMetaElement, Name, name)
+-NS_IMPL_STRING_ATTR(HTMLMetaElement, Scheme, scheme)
+-
+ nsresult
+ HTMLMetaElement::SetMetaReferrer(nsIDocument* aDocument)
+ {
+   if (!aDocument ||
+       !AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::referrer, eIgnoreCase)) {
+     return NS_OK;
+   }
+   nsAutoString content;
+diff --git a/dom/html/HTMLMetaElement.h b/dom/html/HTMLMetaElement.h
+--- a/dom/html/HTMLMetaElement.h
++++ b/dom/html/HTMLMetaElement.h
+@@ -4,65 +4,73 @@
+  * 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/. */
+ 
+ #ifndef mozilla_dom_HTMLMetaElement_h
+ #define mozilla_dom_HTMLMetaElement_h
+ 
+ #include "mozilla/Attributes.h"
+ #include "nsGenericHTMLElement.h"
+-#include "nsIDOMHTMLMetaElement.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+-class HTMLMetaElement final : public nsGenericHTMLElement,
+-                              public nsIDOMHTMLMetaElement
++class HTMLMetaElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLMetaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLMetaElement
+-  NS_DECL_NSIDOMHTMLMETAELEMENT
+-
+   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                               nsIContent* aBindingParent,
+                               bool aCompileEventHandlers) override;
+   virtual void UnbindFromTree(bool aDeep = true,
+                               bool aNullParent = true) override;
+ 
+   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+                                 const nsAttrValue* aValue,
+                                 const nsAttrValue* aOldValue,
+                                 bool aNotify) override;
+ 
+   void CreateAndDispatchEvent(nsIDocument* aDoc, const nsAString& aEventName);
+ 
+   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                          bool aPreallocateChildren) const override;
+ 
+-  // XPCOM GetName is fine.
++  void GetName(nsAString& aValue)
++  {
++    GetHTMLAttr(nsGkAtoms::name, aValue);
++  }
+   void SetName(const nsAString& aName, ErrorResult& aRv)
+   {
+     SetHTMLAttr(nsGkAtoms::name, aName, aRv);
+   }
+-  // XPCOM GetHttpEquiv is fine.
++  void GetHttpEquiv(nsAString& aValue)
++  {
++    GetHTMLAttr(nsGkAtoms::httpEquiv, aValue);
++  }
+   void SetHttpEquiv(const nsAString& aHttpEquiv, ErrorResult& aRv)
+   {
+     SetHTMLAttr(nsGkAtoms::httpEquiv, aHttpEquiv, aRv);
+   }
+-  // XPCOM GetContent is fine.
++  nsresult GetContent(nsAString& aValue)
++  {
++    GetHTMLAttr(nsGkAtoms::content, aValue);
++    return NS_OK;
++  }
+   void SetContent(const nsAString& aContent, ErrorResult& aRv)
+   {
+     SetHTMLAttr(nsGkAtoms::content, aContent, aRv);
+   }
+-  // XPCOM GetScheme is fine.
++  void GetScheme(nsAString& aValue)
++  {
++    GetHTMLAttr(nsGkAtoms::scheme, aValue);
++  }
+   void SetScheme(const nsAString& aScheme, ErrorResult& aRv)
+   {
+     SetHTMLAttr(nsGkAtoms::scheme, aScheme, aRv);
+   }
+ 
+   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+ 
+ protected:
+diff --git a/dom/html/HTMLOptGroupElement.cpp b/dom/html/HTMLOptGroupElement.cpp
+--- a/dom/html/HTMLOptGroupElement.cpp
++++ b/dom/html/HTMLOptGroupElement.cpp
+@@ -32,18 +32,17 @@ HTMLOptGroupElement::HTMLOptGroupElement
+   AddStatesSilently(NS_EVENT_STATE_ENABLED);
+ }
+ 
+ HTMLOptGroupElement::~HTMLOptGroupElement()
+ {
+ }
+ 
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLOptGroupElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLOptGroupElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLOptGroupElement, nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLOptGroupElement)
+ 
+ 
+ nsresult
+ HTMLOptGroupElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
+ {
+   aVisitor.mCanHandle = false;
+diff --git a/dom/html/HTMLOptGroupElement.h b/dom/html/HTMLOptGroupElement.h
+--- a/dom/html/HTMLOptGroupElement.h
++++ b/dom/html/HTMLOptGroupElement.h
+@@ -3,37 +3,32 @@
+ /* 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/. */
+ 
+ #ifndef mozilla_dom_HTMLOptGroupElement_h
+ #define mozilla_dom_HTMLOptGroupElement_h
+ 
+ #include "mozilla/Attributes.h"
+-#include "nsIDOMHTMLOptGroupElement.h"
+ #include "nsGenericHTMLElement.h"
+ 
+ namespace mozilla {
+ class EventChainPreVisitor;
+ namespace dom {
+ 
+-class HTMLOptGroupElement final : public nsGenericHTMLElement,
+-                                  public nsIDOMHTMLOptGroupElement
++class HTMLOptGroupElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLOptGroupElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
+ 
+   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLOptGroupElement, optgroup)
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLOptGroupElement
+-  NS_DECL_NSIDOMHTMLOPTGROUPELEMENT
+-
+   // nsINode
+   virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
+                                  bool aNotify) override;
+   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
+ 
+   // nsIContent
+   virtual nsresult GetEventTargetParent(
+                      EventChainPreVisitor& aVisitor) override;
+diff --git a/dom/html/HTMLOptionElement.cpp b/dom/html/HTMLOptionElement.cpp
+--- a/dom/html/HTMLOptionElement.cpp
++++ b/dom/html/HTMLOptionElement.cpp
+@@ -2,17 +2,16 @@
+ /* vim: set ts=8 sts=2 et sw=2 tw=80: */
+ /* 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/. */
+ 
+ #include "mozilla/dom/HTMLOptionElement.h"
+ #include "mozilla/dom/HTMLOptionElementBinding.h"
+ #include "mozilla/dom/HTMLSelectElement.h"
+-#include "nsIDOMHTMLOptGroupElement.h"
+ #include "nsIDOMHTMLFormElement.h"
+ #include "nsGkAtoms.h"
+ #include "nsStyleConsts.h"
+ #include "nsIFormControl.h"
+ #include "nsIForm.h"
+ #include "nsIDOMNode.h"
+ #include "nsIDOMHTMLCollection.h"
+ #include "nsISelectControlFrame.h"
+diff --git a/dom/html/HTMLOptionsCollection.cpp b/dom/html/HTMLOptionsCollection.cpp
+--- a/dom/html/HTMLOptionsCollection.cpp
++++ b/dom/html/HTMLOptionsCollection.cpp
+@@ -15,17 +15,16 @@
+ #include "mozilla/dom/HTMLOptionElement.h"
+ #include "mozilla/dom/HTMLOptionsCollectionBinding.h"
+ #include "mozilla/dom/HTMLSelectElement.h"
+ #include "nsContentCreatorFunctions.h"
+ #include "nsError.h"
+ #include "nsGkAtoms.h"
+ #include "nsIComboboxControlFrame.h"
+ #include "nsIDocument.h"
+-#include "nsIDOMHTMLOptGroupElement.h"
+ #include "nsIFormControlFrame.h"
+ #include "nsIForm.h"
+ #include "nsIFormProcessor.h"
+ #include "nsIListControlFrame.h"
+ #include "nsLayoutUtils.h"
+ #include "nsMappedAttributes.h"
+ #include "nsRuleData.h"
+ #include "nsServiceManagerUtils.h"
+diff --git a/dom/html/HTMLParagraphElement.cpp b/dom/html/HTMLParagraphElement.cpp
+--- a/dom/html/HTMLParagraphElement.cpp
++++ b/dom/html/HTMLParagraphElement.cpp
+@@ -16,23 +16,20 @@ NS_IMPL_NS_NEW_HTML_ELEMENT(Paragraph)
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+ HTMLParagraphElement::~HTMLParagraphElement()
+ {
+ }
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLParagraphElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLParagraphElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLParagraphElement, nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLParagraphElement)
+ 
+-NS_IMPL_STRING_ATTR(HTMLParagraphElement, Align, align)
+-
+ bool
+ HTMLParagraphElement::ParseAttribute(int32_t aNamespaceID,
+                                      nsIAtom* aAttribute,
+                                      const nsAString& aValue,
+                                      nsAttrValue& aResult)
+ {
+   if (aAttribute == nsGkAtoms::align && aNamespaceID == kNameSpaceID_None) {
+     return ParseDivAlignValue(aValue, aResult);
+diff --git a/dom/html/HTMLParagraphElement.h b/dom/html/HTMLParagraphElement.h
+--- a/dom/html/HTMLParagraphElement.h
++++ b/dom/html/HTMLParagraphElement.h
+@@ -4,49 +4,47 @@
+  * 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/. */
+ 
+ #ifndef mozilla_dom_HTMLParagraphElement_h
+ #define mozilla_dom_HTMLParagraphElement_h
+ 
+ #include "mozilla/Attributes.h"
+ 
+-#include "nsIDOMHTMLParagraphElement.h"
+ #include "nsGenericHTMLElement.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+-class HTMLParagraphElement final : public nsGenericHTMLElement,
+-                                   public nsIDOMHTMLParagraphElement
++class HTMLParagraphElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLParagraphElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+     : nsGenericHTMLElement(aNodeInfo)
+   {
+   }
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLParagraphElement
+-  NS_DECL_NSIDOMHTMLPARAGRAPHELEMENT
+-
+   virtual bool ParseAttribute(int32_t aNamespaceID,
+                                 nsIAtom* aAttribute,
+                                 const nsAString& aValue,
+                                 nsAttrValue& aResult) override;
+   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
+   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
+ 
+   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                          bool aPreallocateChildren) const override;
+ 
+   // WebIDL API
+-  // The XPCOM GetAlign is fine for our purposes
++  void GetAlign(nsAString& aValue)
++  {
++    GetHTMLAttr(nsGkAtoms::align, aValue);
++  }
+   void SetAlign(const nsAString& aValue, mozilla::ErrorResult& rv)
+   {
+     SetHTMLAttr(nsGkAtoms::align, aValue, rv);
+   }
+ 
+ protected:
+   virtual ~HTMLParagraphElement();
+ 
+diff --git a/dom/html/HTMLPictureElement.cpp b/dom/html/HTMLPictureElement.cpp
+--- a/dom/html/HTMLPictureElement.cpp
++++ b/dom/html/HTMLPictureElement.cpp
+@@ -23,18 +23,17 @@ HTMLPictureElement::HTMLPictureElement(a
+   : nsGenericHTMLElement(aNodeInfo)
+ {
+ }
+ 
+ HTMLPictureElement::~HTMLPictureElement()
+ {
+ }
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLPictureElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLPictureElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLPictureElement, nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLPictureElement)
+ 
+ void
+ HTMLPictureElement::RemoveChildAt(uint32_t aIndex, bool aNotify)
+ {
+   nsCOMPtr<nsIContent> child = GetChildAt(aIndex);
+ 
+diff --git a/dom/html/HTMLPictureElement.h b/dom/html/HTMLPictureElement.h
+--- a/dom/html/HTMLPictureElement.h
++++ b/dom/html/HTMLPictureElement.h
+@@ -3,34 +3,29 @@
+ /* 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/. */
+ 
+ #ifndef mozilla_dom_HTMLPictureElement_h
+ #define mozilla_dom_HTMLPictureElement_h
+ 
+ #include "mozilla/Attributes.h"
+-#include "nsIDOMHTMLPictureElement.h"
+ #include "nsGenericHTMLElement.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+-class HTMLPictureElement final : public nsGenericHTMLElement,
+-                                 public nsIDOMHTMLPictureElement
++class HTMLPictureElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLPictureElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLPictureElement
+-  NS_DECL_NSIDOMHTMLPICTUREELEMENT
+-
+   virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
+                          bool aPreallocateChildren) const override;
+   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
+   virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify) override;
+ 
+ protected:
+   virtual ~HTMLPictureElement();
+ 
+diff --git a/dom/html/HTMLPreElement.cpp b/dom/html/HTMLPreElement.cpp
+--- a/dom/html/HTMLPreElement.cpp
++++ b/dom/html/HTMLPreElement.cpp
+@@ -17,23 +17,20 @@ NS_IMPL_NS_NEW_HTML_ELEMENT(Pre)
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+ HTMLPreElement::~HTMLPreElement()
+ {
+ }
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLPreElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLPreElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLPreElement, nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLPreElement)
+ 
+-NS_IMPL_INT_ATTR(HTMLPreElement, Width, width)
+-
+ bool
+ HTMLPreElement::ParseAttribute(int32_t aNamespaceID,
+                                nsIAtom* aAttribute,
+                                const nsAString& aValue,
+                                nsAttrValue& aResult)
+ {
+   if (aNamespaceID == kNameSpaceID_None) {
+     if (aAttribute == nsGkAtoms::width) {
+diff --git a/dom/html/HTMLPreElement.h b/dom/html/HTMLPreElement.h
+--- a/dom/html/HTMLPreElement.h
++++ b/dom/html/HTMLPreElement.h
+@@ -4,38 +4,32 @@
+  * 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/. */
+ 
+ #ifndef mozilla_dom_HTMLPreElement_h
+ #define mozilla_dom_HTMLPreElement_h
+ 
+ #include "mozilla/Attributes.h"
+ 
+-#include "nsIDOMHTMLPreElement.h"
+ #include "nsGenericHTMLElement.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+-class HTMLPreElement final : public nsGenericHTMLElement,
+-                             public nsIDOMHTMLPreElement
++class HTMLPreElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLPreElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+     : nsGenericHTMLElement(aNodeInfo)
+   {
+   }
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLPreElement
+-  NS_IMETHOD GetWidth(int32_t* aWidth) override;
+-  NS_IMETHOD SetWidth(int32_t aWidth) override;
+-
+   virtual bool ParseAttribute(int32_t aNamespaceID,
+                                 nsIAtom* aAttribute,
+                                 const nsAString& aValue,
+                                 nsAttrValue& aResult) override;
+   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
+   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
+ 
+   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+diff --git a/dom/html/HTMLSharedElement.cpp b/dom/html/HTMLSharedElement.cpp
+--- a/dom/html/HTMLSharedElement.cpp
++++ b/dom/html/HTMLSharedElement.cpp
+@@ -32,20 +32,16 @@ HTMLSharedElement::~HTMLSharedElement()
+ }
+ 
+ NS_IMPL_ADDREF_INHERITED(HTMLSharedElement, Element)
+ NS_IMPL_RELEASE_INHERITED(HTMLSharedElement, Element)
+ 
+ // QueryInterface implementation for HTMLSharedElement
+ NS_INTERFACE_MAP_BEGIN(HTMLSharedElement)
+   NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLBaseElement, base)
+-  NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLDirectoryElement, dir)
+-  NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLQuoteElement, q)
+-  NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLQuoteElement, blockquote)
+-  NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLHeadElement, head)
+   NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLHtmlElement, html)
+ NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
+ 
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLSharedElement)
+ 
+ // nsIDOMHTMLQuoteElement
+ // Empty
+diff --git a/dom/html/HTMLSharedElement.h b/dom/html/HTMLSharedElement.h
+--- a/dom/html/HTMLSharedElement.h
++++ b/dom/html/HTMLSharedElement.h
+@@ -3,35 +3,29 @@
+ /* 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/. */
+ 
+ #ifndef mozilla_dom_HTMLSharedElement_h
+ #define mozilla_dom_HTMLSharedElement_h
+ 
+ #include "nsIDOMHTMLBaseElement.h"
+-#include "nsIDOMHTMLDirectoryElement.h"
+-#include "nsIDOMHTMLQuoteElement.h"
+-#include "nsIDOMHTMLHeadElement.h"
+ #include "nsIDOMHTMLHtmlElement.h"
+ #include "nsGenericHTMLElement.h"
+ 
+ #include "nsGkAtoms.h"
+ 
+ #include "mozilla/Attributes.h"
+ #include "mozilla/Assertions.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+ class HTMLSharedElement final : public nsGenericHTMLElement,
+                                 public nsIDOMHTMLBaseElement,
+-                                public nsIDOMHTMLDirectoryElement,
+-                                public nsIDOMHTMLQuoteElement,
+-                                public nsIDOMHTMLHeadElement,
+                                 public nsIDOMHTMLHtmlElement
+ {
+ public:
+   explicit HTMLSharedElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+     : nsGenericHTMLElement(aNodeInfo)
+   {
+     if (mNodeInfo->Equals(nsGkAtoms::head) ||
+         mNodeInfo->Equals(nsGkAtoms::html)) {
+@@ -40,22 +34,16 @@ public:
+   }
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+   // nsIDOMHTMLBaseElement
+   NS_DECL_NSIDOMHTMLBASEELEMENT
+ 
+-  // nsIDOMHTMLQuoteElement
+-  NS_DECL_NSIDOMHTMLQUOTEELEMENT
+-
+-  // nsIDOMHTMLHeadElement
+-  NS_DECL_NSIDOMHTMLHEADELEMENT
+-
+   // nsIDOMHTMLHtmlElement
+   NS_DECL_NSIDOMHTMLHTMLELEMENT
+ 
+   // nsIContent
+   virtual bool ParseAttribute(int32_t aNamespaceID,
+                                 nsIAtom* aAttribute,
+                                 const nsAString& aValue,
+                                 nsAttrValue& aResult) override;
+diff --git a/dom/html/HTMLSharedListElement.cpp b/dom/html/HTMLSharedListElement.cpp
+--- a/dom/html/HTMLSharedListElement.cpp
++++ b/dom/html/HTMLSharedListElement.cpp
+@@ -25,18 +25,16 @@ HTMLSharedListElement::~HTMLSharedListEl
+ {
+ }
+ 
+ NS_IMPL_ADDREF_INHERITED(HTMLSharedListElement, Element)
+ NS_IMPL_RELEASE_INHERITED(HTMLSharedListElement, Element)
+ 
+ // QueryInterface implementation for nsHTMLSharedListElement
+ NS_INTERFACE_MAP_BEGIN(HTMLSharedListElement)
+-  NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLOListElement, ol)
+-  NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLUListElement, ul)
+ NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
+ 
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLSharedListElement)
+ 
+ 
+ // Shared with nsHTMLSharedElement.cpp
+ nsAttrValue::EnumTable kListTypeTable[] = {
+diff --git a/dom/html/HTMLSharedListElement.h b/dom/html/HTMLSharedListElement.h
+--- a/dom/html/HTMLSharedListElement.h
++++ b/dom/html/HTMLSharedListElement.h
+@@ -4,42 +4,32 @@
+  * 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/. */
+ 
+ #ifndef mozilla_dom_HTMLSharedListElement_h
+ #define mozilla_dom_HTMLSharedListElement_h
+ 
+ #include "mozilla/Attributes.h"
+ 
+-#include "nsIDOMHTMLOListElement.h"
+-#include "nsIDOMHTMLUListElement.h"
+ #include "nsGenericHTMLElement.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+-class HTMLSharedListElement final : public nsGenericHTMLElement,
+-                                    public nsIDOMHTMLOListElement,
+-                                    public nsIDOMHTMLUListElement
++class HTMLSharedListElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLSharedListElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+     : nsGenericHTMLElement(aNodeInfo)
+   {
+   }
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLOListElement
+-  NS_DECL_NSIDOMHTMLOLISTELEMENT
+-
+-  // nsIDOMHTMLUListElement
+-  // fully declared by NS_DECL_NSIDOMHTMLOLISTELEMENT
+-
+   virtual bool ParseAttribute(int32_t aNamespaceID,
+                                 nsIAtom* aAttribute,
+                                 const nsAString& aValue,
+                                 nsAttrValue& aResult) override;
+   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
+   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
+   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+                          bool aPreallocateChildren) const override;
+diff --git a/dom/html/HTMLStyleElement.cpp b/dom/html/HTMLStyleElement.cpp
+--- a/dom/html/HTMLStyleElement.cpp
++++ b/dom/html/HTMLStyleElement.cpp
+@@ -43,59 +43,38 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+ 
+ NS_IMPL_ADDREF_INHERITED(HTMLStyleElement, Element)
+ NS_IMPL_RELEASE_INHERITED(HTMLStyleElement, Element)
+ 
+ 
+ // QueryInterface implementation for HTMLStyleElement
+ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLStyleElement)
+   NS_INTERFACE_TABLE_INHERITED(HTMLStyleElement,
+-                               nsIDOMHTMLStyleElement,
+                                nsIStyleSheetLinkingElement,
+                                nsIMutationObserver)
+ NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLStyleElement)
+ 
+ 
+-NS_IMETHODIMP
+-HTMLStyleElement::GetMozDisabled(bool* aDisabled)
+-{
+-  NS_ENSURE_ARG_POINTER(aDisabled);
+-
+-  *aDisabled = Disabled();
+-  return NS_OK;
+-}
+-
+ bool
+ HTMLStyleElement::Disabled()
+ {
+   StyleSheet* ss = GetSheet();
+   return ss && ss->Disabled();
+ }
+ 
+-NS_IMETHODIMP
+-HTMLStyleElement::SetMozDisabled(bool aDisabled)
+-{
+-  SetDisabled(aDisabled);
+-  return NS_OK;
+-}
+-
+ void
+ HTMLStyleElement::SetDisabled(bool aDisabled)
+ {
+   if (StyleSheet* ss = GetSheet()) {
+     ss->SetDisabled(aDisabled);
+   }
+ }
+ 
+-NS_IMPL_STRING_ATTR(HTMLStyleElement, Media, media)
+-NS_IMPL_BOOL_ATTR(HTMLStyleElement, Scoped, scoped)
+-NS_IMPL_STRING_ATTR(HTMLStyleElement, Type, type)
+-
+ void
+ HTMLStyleElement::CharacterDataChanged(nsIDocument* aDocument,
+                                        nsIContent* aContent,
+                                        CharacterDataChangeInfo* aInfo)
+ {
+   ContentChanged(aContent);
+ }
+ 
+diff --git a/dom/html/HTMLStyleElement.h b/dom/html/HTMLStyleElement.h
+--- a/dom/html/HTMLStyleElement.h
++++ b/dom/html/HTMLStyleElement.h
+@@ -3,28 +3,26 @@
+ /* 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/. */
+ 
+ #ifndef mozilla_dom_HTMLStyleElement_h
+ #define mozilla_dom_HTMLStyleElement_h
+ 
+ #include "mozilla/Attributes.h"
+-#include "nsIDOMHTMLStyleElement.h"
+ #include "nsGenericHTMLElement.h"
+ #include "nsStyleLinkElement.h"
+ #include "nsStubMutationObserver.h"
+ 
+ class nsIDocument;
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+ class HTMLStyleElement final : public nsGenericHTMLElement,
+-                               public nsIDOMHTMLStyleElement,
+                                public nsStyleLinkElement,
+                                public nsStubMutationObserver
+ {
+ public:
+   explicit HTMLStyleElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+@@ -33,19 +31,16 @@ public:
+   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLStyleElement,
+                                            nsGenericHTMLElement)
+ 
+   NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) override;
+   using nsGenericHTMLElement::SetInnerHTML;
+   virtual void SetInnerHTML(const nsAString& aInnerHTML,
+                             mozilla::ErrorResult& aError) override;
+ 
+-  // nsIDOMHTMLStyleElement
+-  NS_DECL_NSIDOMHTMLSTYLEELEMENT
+-
+   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                               nsIContent* aBindingParent,
+                               bool aCompileEventHandlers) override;
+   virtual void UnbindFromTree(bool aDeep = true,
+                               bool aNullParent = true) override;
+   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+                                 const nsAttrValue* aValue,
+                                 const nsAttrValue* aOldValue,
+@@ -65,20 +60,28 @@ public:
+   void GetNonce(nsAString& aNonce) const
+   {
+     GetHTMLAttr(nsGkAtoms::nonce, aNonce);
+   }
+   void SetNonce(const nsAString& aNonce, ErrorResult& aRv)
+   {
+     SetHTMLAttr(nsGkAtoms::nonce, aNonce, aRv);
+   }
++  void GetMedia(nsAString& aValue)
++  {
++    GetHTMLAttr(nsGkAtoms::media, aValue);
++  }
+   void SetMedia(const nsAString& aMedia, ErrorResult& aError)
+   {
+     SetHTMLAttr(nsGkAtoms::media, aMedia, aError);
+   }
++  void GetType(nsAString& aValue)
++  {
++    GetHTMLAttr(nsGkAtoms::type, aValue);
++  }
+   void SetType(const nsAString& aType, ErrorResult& aError)
+   {
+     SetHTMLAttr(nsGkAtoms::type, aType, aError);
+   }
+   bool Scoped()
+   {
+     return GetBoolAttr(nsGkAtoms::scoped);
+   }
+diff --git a/dom/html/HTMLTableCellElement.cpp b/dom/html/HTMLTableCellElement.cpp
+--- a/dom/html/HTMLTableCellElement.cpp
++++ b/dom/html/HTMLTableCellElement.cpp
+@@ -24,18 +24,17 @@ HTMLTableCellElement::~HTMLTableCellElem
+ }
+ 
+ JSObject*
+ HTMLTableCellElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
+ {
+   return HTMLTableCellElementBinding::Wrap(aCx, this, aGivenProto);
+ }
+ 
+-NS_IMPL_ISUPPORTS_INHERITED(HTMLTableCellElement, nsGenericHTMLElement,
+-                            nsIDOMHTMLTableCellElement)
++NS_IMPL_ISUPPORTS_INHERITED0(HTMLTableCellElement, nsGenericHTMLElement)
+ 
+ NS_IMPL_ELEMENT_CLONE(HTMLTableCellElement)
+ 
+ 
+ // protected method
+ HTMLTableRowElement*
+ HTMLTableCellElement::GetRow() const
+ {
+@@ -90,23 +89,16 @@ HTMLTableCellElement::CellIndex() const
+       return i;
+     }
+   }
+ 
+   return -1;
+ }
+ 
+ NS_IMETHODIMP
+-HTMLTableCellElement::GetCellIndex(int32_t* aCellIndex)
+-{
+-  *aCellIndex = CellIndex();
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+ HTMLTableCellElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
+ {
+   nsresult rv = nsGenericHTMLElement::WalkContentStyleRules(aRuleWalker);
+   NS_ENSURE_SUCCESS(rv, rv);
+ 
+   if (nsMappedAttributes* tableInheritedAttributes = GetMappedAttributesInheritedFromTable()) {
+     if (tableInheritedAttributes) {
+       aRuleWalker->Forward(tableInheritedAttributes);
+@@ -120,248 +112,16 @@ HTMLTableCellElement::GetMappedAttribute
+ {
+   if (HTMLTableElement* table = GetTable()) {
+     return table->GetAttributesMappedForCell();
+   }
+ 
+   return nullptr;
+ }
+ 
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetAbbr(const nsAString& aAbbr)
+-{
+-  ErrorResult rv;
+-  SetAbbr(aAbbr, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetAbbr(nsAString& aAbbr)
+-{
+-  DOMString abbr;
+-  GetAbbr(abbr);
+-  abbr.ToString(aAbbr);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetAxis(const nsAString& aAxis)
+-{
+-  ErrorResult rv;
+-  SetAxis(aAxis, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetAxis(nsAString& aAxis)
+-{
+-  DOMString axis;
+-  GetAxis(axis);
+-  axis.ToString(aAxis);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetAlign(const nsAString& aAlign)
+-{
+-  ErrorResult rv;
+-  SetAlign(aAlign, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetAlign(nsAString& aAlign)
+-{
+-  DOMString align;
+-  GetAlign(align);
+-  align.ToString(aAlign);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetVAlign(const nsAString& aVAlign)
+-{
+-  ErrorResult rv;
+-  SetVAlign(aVAlign, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetVAlign(nsAString& aVAlign)
+-{
+-  DOMString vAlign;
+-  GetVAlign(vAlign);
+-  vAlign.ToString(aVAlign);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetCh(const nsAString& aCh)
+-{
+-  ErrorResult rv;
+-  SetCh(aCh, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetCh(nsAString& aCh)
+-{
+-  DOMString ch;
+-  GetCh(ch);
+-  ch.ToString(aCh);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetChOff(const nsAString& aChOff)
+-{
+-  ErrorResult rv;
+-  SetChOff(aChOff, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetChOff(nsAString& aChOff)
+-{
+-  DOMString chOff;
+-  GetChOff(chOff);
+-  chOff.ToString(aChOff);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetBgColor(const nsAString& aBgColor)
+-{
+-  ErrorResult rv;
+-  SetBgColor(aBgColor, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetBgColor(nsAString& aBgColor)
+-{
+-  DOMString bgColor;
+-  GetBgColor(bgColor);
+-  bgColor.ToString(aBgColor);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetHeight(const nsAString& aHeight)
+-{
+-  ErrorResult rv;
+-  SetHeight(aHeight, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetHeight(nsAString& aHeight)
+-{
+-  DOMString height;
+-  GetHeight(height);
+-  height.ToString(aHeight);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetWidth(const nsAString& aWidth)
+-{
+-  ErrorResult rv;
+-  SetWidth(aWidth, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetWidth(nsAString& aWidth)
+-{
+-  DOMString width;
+-  GetWidth(width);
+-  width.ToString(aWidth);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetNoWrap(bool aNoWrap)
+-{
+-  ErrorResult rv;
+-  SetNoWrap(aNoWrap, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetNoWrap(bool* aNoWrap)
+-{
+-  *aNoWrap = NoWrap();
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetScope(const nsAString& aScope)
+-{
+-  ErrorResult rv;
+-  SetScope(aScope, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetScope(nsAString& aScope)
+-{
+-  DOMString scope;
+-  GetScope(scope);
+-  scope.ToString(aScope);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetHeaders(const nsAString& aHeaders)
+-{
+-  ErrorResult rv;
+-  SetHeaders(aHeaders, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetHeaders(nsAString& aHeaders)
+-{
+-  DOMString headers;
+-  GetHeaders(headers);
+-  headers.ToString(aHeaders);
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetColSpan(int32_t aColSpan)
+-{
+-  ErrorResult rv;
+-  SetColSpan(aColSpan, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetColSpan(int32_t* aColSpan)
+-{
+-  *aColSpan = ColSpan();
+-  return NS_OK;
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::SetRowSpan(int32_t aRowSpan)
+-{
+-  ErrorResult rv;
+-  SetRowSpan(aRowSpan, rv);
+-  return rv.StealNSResult();
+-}
+-
+-NS_IMETHODIMP
+-HTMLTableCellElement::GetRowSpan(int32_t* aRowSpan)
+-{
+-  *aRowSpan = RowSpan();
+-  return NS_OK;
+-}
+-
+ void
+ HTMLTableCellElement::GetAlign(DOMString& aValue)
+ {
+   if (!GetAttr(kNameSpaceID_None, nsGkAtoms::align, aValue)) {
+     // There's no align attribute, ask the row for the alignment.
+     HTMLTableRowElement* row = GetRow();
+     if (row) {
+       row->GetAlign(aValue);
+diff --git a/dom/html/HTMLTableCellElement.h b/dom/html/HTMLTableCellElement.h
+--- a/dom/html/HTMLTableCellElement.h
++++ b/dom/html/HTMLTableCellElement.h
+@@ -3,39 +3,34 @@
+ /* 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/. */
+ #ifndef mozilla_dom_HTMLTableCellElement_h
+ #define mozilla_dom_HTMLTableCellElement_h
+ 
+ #include "mozilla/Attributes.h"
+ #include "nsGenericHTMLElement.h"
+-#include "nsIDOMHTMLTableCellElement.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ 
+ class HTMLTableElement;
+ 
+-class HTMLTableCellElement final : public nsGenericHTMLElement,
+-                                   public nsIDOMHTMLTableCellElement
++class HTMLTableCellElement final : public nsGenericHTMLElement
+ {
+ public:
+   explicit HTMLTableCellElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+     : nsGenericHTMLElement(aNodeInfo)
+   {
+     SetHasWeirdParserInsertionMode();
+   }
+ 
+   // nsISupports
+   NS_DECL_ISUPPORTS_INHERITED
+ 
+-  // nsIDOMHTMLTableCellElement
+-  NS_DECL_NSIDOMHTMLTABLECELLELEMENT
+-
+   uint32_t ColSpan() const
+   {
+     return GetIntAttr(nsGkAtoms::colspan, 1);
+   }
+   void SetColSpan(uint32_t aColSpan, ErrorResult& aError)
+   {
+     SetUnsignedIntAttr(nsGkAtoms::colspan, aColSpan, 1, aError);
+   }
+diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp
+--- a/dom/html/nsGenericHTMLElement.cpp
++++ b/dom/html/nsGenericHTMLElement.cpp
+@@ -25,17 +25,16 @@
+ #include "nsIContentViewer.h"
+ #include "mozilla/css/Declaration.h"
+ #include "nsIDocument.h"
+ #include "nsIDocumentEncoder.h"
+ #include "nsIDOMHTMLDocument.h"
+ #include "nsIDOMAttr.h"
+ #include "nsIDOMDocumentFragment.h"
+ #include "nsIDOMHTMLElement.h"
+-#include "nsIDOMHTMLMenuElement.h"
+ #include "nsIDOMWindow.h"
+ #include "nsIDOMDocument.h"
+ #include "nsMappedAttributes.h"
+ #include "nsHTMLStyleSheet.h"
+ #include "nsIHTMLDocument.h"
+ #include "nsPIDOMWindow.h"
+ #include "nsIURL.h"
+ #include "nsEscape.h"
+diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h
+--- a/dom/html/nsGenericHTMLElement.h
++++ b/dom/html/nsGenericHTMLElement.h
+@@ -10,24 +10,22 @@
+ #include "mozilla/EventForwards.h"
+ #include "nsMappedAttributeElement.h"
+ #include "nsIDOMHTMLElement.h"
+ #include "nsNameSpaceManager.h"  // for kNameSpaceID_None
+ #include "nsIFormControl.h"
+ #include "nsGkAtoms.h"
+ #include "nsContentCreatorFunctions.h"
+ #include "mozilla/ErrorResult.h"
+-#include "nsIDOMHTMLMenuElement.h"
+ #include "mozilla/dom/BindingDeclarations.h"
+ #include "mozilla/dom/DOMRect.h"
+ #include "mozilla/dom/ValidityState.h"
+ #include "mozilla/dom/Element.h"
+ 
+ class nsDOMTokenList;
+-class nsIDOMHTMLMenuElement;
+ class nsIFormControlFrame;
+ class nsIFrame;
+ class nsILayoutHistoryState;
+ class nsIURI;
+ class nsPresState;
+ struct nsSize;
+ 
+ namespace mozilla {
+diff --git a/dom/html/nsHTMLContentSink.cpp b/dom/html/nsHTMLContentSink.cpp
+--- a/dom/html/nsHTMLContentSink.cpp
++++ b/dom/html/nsHTMLContentSink.cpp
+@@ -44,17 +44,16 @@
+ #include "nsGkAtoms.h"
+ #include "nsContentUtils.h"
+ #include "nsIChannel.h"
+ #include "nsIHttpChannel.h"
+ #include "nsIDocShell.h"
+ #include "nsIDocument.h"
+ #include "nsStubDocumentObserver.h"
+ #include "nsIHTMLDocument.h"
+-#include "nsIDOMHTMLMapElement.h"
+ #include "nsICookieService.h"
+ #include "nsTArray.h"
+ #include "nsIScriptSecurityManager.h"
+ #include "nsIPrincipal.h"
+ #include "nsTextFragment.h"
+ #include "nsIScriptGlobalObject.h"
+ #include "nsNameSpaceManager.h"
+ 
+diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp
+--- a/dom/html/nsHTMLDocument.cpp
++++ b/dom/html/nsHTMLDocument.cpp
+@@ -52,17 +52,16 @@
+ #include "nsNetCID.h"
+ #include "nsICookieService.h"
+ 
+ #include "nsIServiceManager.h"
+ #include "nsIConsoleService.h"
+ #include "nsIComponentManager.h"
+ #include "nsParserCIID.h"
+ #include "nsIDOMHTMLElement.h"
+-#include "nsIDOMHTMLHeadElement.h"
+ #include "nsNameSpaceManager.h"
+ #include "nsGenericHTMLElement.h"
+ #include "mozilla/css/Loader.h"
+ #include "nsIHttpChannel.h"
+ #include "nsIFile.h"
+ #include "nsFrameSelection.h"
+ #include "nsISelectionPrivate.h"//for toStringwithformat code
+ 
+@@ -1145,17 +1144,17 @@ nsHTMLDocument::SetBody(nsGenericHTMLEle
+   if (currentBody) {
+     root->ReplaceChild(*newBody, *currentBody, rv);
+   } else {
+     root->AppendChild(*newBody, rv);
+   }
+ }
+ 
+ NS_IMETHODIMP
+-nsHTMLDocument::GetHead(nsIDOMHTMLHeadElement** aHead)
++nsHTMLDocument::GetHead(nsISupports** aHead)
+ {
+   *aHead = nullptr;
+ 
+   Element* head = GetHeadElement();
+ 
+   return head ? CallQueryInterface(head, aHead) : NS_OK;
+ }
+ 
+diff --git a/dom/interfaces/html/moz.build b/dom/interfaces/html/moz.build
+--- a/dom/interfaces/html/moz.build
++++ b/dom/interfaces/html/moz.build
+@@ -6,57 +6,37 @@
+ 
+ with Files("**"):
+     BUG_COMPONENT = ("Core", "DOM")
+ 
+ XPIDL_SOURCES += [
+     'nsIDOMHTMLAnchorElement.idl',
+     'nsIDOMHTMLAreaElement.idl',
+     'nsIDOMHTMLBaseElement.idl',
+-    'nsIDOMHTMLBodyElement.idl',
+     'nsIDOMHTMLButtonElement.idl',
+     'nsIDOMHTMLCanvasElement.idl',
+     'nsIDOMHTMLCollection.idl',
+-    'nsIDOMHTMLDirectoryElement.idl',
+     'nsIDOMHTMLDocument.idl',
+     'nsIDOMHTMLElement.idl',
+-    'nsIDOMHTMLFieldSetElement.idl',
+     'nsIDOMHTMLFormElement.idl',
+     'nsIDOMHTMLFrameElement.idl',
+-    'nsIDOMHTMLFrameSetElement.idl',
+-    'nsIDOMHTMLHeadElement.idl',
+-    'nsIDOMHTMLHRElement.idl',
+     'nsIDOMHTMLHtmlElement.idl',
+     'nsIDOMHTMLIFrameElement.idl',
+     'nsIDOMHTMLImageElement.idl',
+     'nsIDOMHTMLInputElement.idl',
+-    'nsIDOMHTMLLabelElement.idl',
+-    'nsIDOMHTMLLIElement.idl',
+     'nsIDOMHTMLLinkElement.idl',
+-    'nsIDOMHTMLMapElement.idl',
+     'nsIDOMHTMLMediaElement.idl',
+-    'nsIDOMHTMLMenuElement.idl',
+     'nsIDOMHTMLMenuItemElement.idl',
+-    'nsIDOMHTMLMetaElement.idl',
+     'nsIDOMHTMLObjectElement.idl',
+-    'nsIDOMHTMLOListElement.idl',
+-    'nsIDOMHTMLOptGroupElement.idl',
+     'nsIDOMHTMLOptionElement.idl',
+     'nsIDOMHTMLOptionsCollection.idl',
+-    'nsIDOMHTMLParagraphElement.idl',
+-    'nsIDOMHTMLPictureElement.idl',
+-    'nsIDOMHTMLPreElement.idl',
+-    'nsIDOMHTMLQuoteElement.idl',
+     'nsIDOMHTMLScriptElement.idl',
+     'nsIDOMHTMLSelectElement.idl',
+     'nsIDOMHTMLSourceElement.idl',
+-    'nsIDOMHTMLStyleElement.idl',
+-    'nsIDOMHTMLTableCellElement.idl',
+     'nsIDOMHTMLTextAreaElement.idl',
+-    'nsIDOMHTMLUListElement.idl',
+     'nsIDOMMozBrowserFrame.idl',
+     'nsIDOMTimeRanges.idl',
+     'nsIDOMValidityState.idl',
+     'nsIMozBrowserFrame.idl',
+ ]
+ 
+ XPIDL_MODULE = 'dom_html'
+ 
+diff --git a/dom/interfaces/html/nsIDOMHTMLBodyElement.idl b/dom/interfaces/html/nsIDOMHTMLBodyElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLBodyElement.idl
++++ /dev/null
+@@ -1,32 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-%{ C++
+-#include "jspubtd.h"
+-%}
+-
+-/**
+- * The nsIDOMHTMLBodyElement interface is the interface to a [X]HTML
+- * body element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(068630db-2c00-43dd-b167-495757a88236)]
+-interface nsIDOMHTMLBodyElement : nsISupports
+-{
+-           attribute DOMString        aLink;
+-           attribute DOMString        background;
+-           attribute DOMString        bgColor;
+-           attribute DOMString        link;
+-           attribute DOMString        text;
+-           attribute DOMString        vLink;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLDirectoryElement.idl b/dom/interfaces/html/nsIDOMHTMLDirectoryElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLDirectoryElement.idl
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLDirectoryElement interface is the interface to a
+- * [X]HTML dir element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-// Exists so that | element instanceof Ci.nsIDOMHTMLDirectoryElement | works.
+-[uuid(8cfff7a4-8b14-4ce0-97b0-babe78da16f8)]
+-interface nsIDOMHTMLDirectoryElement : nsISupports
+-{
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLDocument.idl b/dom/interfaces/html/nsIDOMHTMLDocument.idl
+--- a/dom/interfaces/html/nsIDOMHTMLDocument.idl
++++ b/dom/interfaces/html/nsIDOMHTMLDocument.idl
+@@ -14,17 +14,17 @@
+ interface nsISelection;
+ 
+ [uuid(cd31e61f-cfc2-4b91-9385-17b6a2d0633d)]
+ interface nsIDOMHTMLDocument : nsIDOMDocument
+ {
+            attribute DOMString            domain;
+            attribute DOMString            cookie;
+ 
+-  readonly attribute nsIDOMHTMLHeadElement head;
++  readonly attribute nsISupports          head;
+            attribute nsIDOMHTMLElement    body;
+ 
+   readonly attribute nsIDOMHTMLCollection images;
+   readonly attribute nsIDOMHTMLCollection embeds;
+   // mapped to attribute embeds for NS4 compat
+   readonly attribute nsIDOMHTMLCollection plugins;
+   readonly attribute nsIDOMHTMLCollection links;
+   readonly attribute nsIDOMHTMLCollection forms;
+diff --git a/dom/interfaces/html/nsIDOMHTMLFieldSetElement.idl b/dom/interfaces/html/nsIDOMHTMLFieldSetElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLFieldSetElement.idl
++++ /dev/null
+@@ -1,31 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLFieldSetElement interface is the interface to a
+- * [X]HTML fieldset element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-interface nsIDOMValidityState;
+-
+-[uuid(e3d91535-9da3-4c4b-a809-f17d85a4fb9f)]
+-interface nsIDOMHTMLFieldSetElement : nsISupports
+-{
+-           attribute boolean                disabled;
+-  readonly attribute nsIDOMHTMLFormElement  form;
+-           attribute DOMString              name;
+-
+-  readonly attribute DOMString              type;
+-
+-  readonly attribute nsIDOMHTMLCollection   elements;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLFrameSetElement.idl b/dom/interfaces/html/nsIDOMHTMLFrameSetElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLFrameSetElement.idl
++++ /dev/null
+@@ -1,28 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-%{ C++
+-#include "jspubtd.h"
+-%}
+-
+-/**
+- * The nsIDOMHTMLFrameSetElement interface is the interface to a
+- * [X]HTML frameset element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(14b29269-c387-4cff-8463-b0871ca0be3a)]
+-interface nsIDOMHTMLFrameSetElement : nsISupports
+-{
+-           attribute DOMString        cols;
+-           attribute DOMString        rows;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLHRElement.idl b/dom/interfaces/html/nsIDOMHTMLHRElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLHRElement.idl
++++ /dev/null
+@@ -1,11 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsISupports.idl"
+-
+-[uuid(30771953-b9f4-44de-b0fe-e490949af98b)]
+-interface nsIDOMHTMLHRElement : nsISupports
+-{
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLHeadElement.idl b/dom/interfaces/html/nsIDOMHTMLHeadElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLHeadElement.idl
++++ /dev/null
+@@ -1,22 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLHeadElement interface is the interface to a [X]HTML
+- * head element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(59b80014-00f5-412d-846f-725494122d42)]
+-interface nsIDOMHTMLHeadElement : nsISupports
+-{
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLLIElement.idl b/dom/interfaces/html/nsIDOMHTMLLIElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLLIElement.idl
++++ /dev/null
+@@ -1,24 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLLIElement interface is the interface to a [X]HTML li
+- * element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(17bd5c1c-3746-4268-a9f6-45018025f09c)]
+-interface nsIDOMHTMLLIElement : nsISupports
+-{
+-           attribute DOMString           type;
+-           attribute long                value;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLLabelElement.idl b/dom/interfaces/html/nsIDOMHTMLLabelElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLLabelElement.idl
++++ /dev/null
+@@ -1,25 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLLabelElement interface is the interface to a [X]HTML
+- * label element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(efc0eaf2-5756-4388-a229-fbec2033529d)]
+-interface nsIDOMHTMLLabelElement : nsISupports
+-{
+-  readonly attribute nsIDOMHTMLFormElement form;
+-           attribute DOMString             htmlFor;
+-  readonly attribute nsIDOMHTMLElement     control;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLMapElement.idl b/dom/interfaces/html/nsIDOMHTMLMapElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLMapElement.idl
++++ /dev/null
+@@ -1,24 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLMapElement interface is the interface to a [X]HTML
+- * map element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(3f49f8c6-2e9d-4323-b30c-2404d5ff1f57)]
+-interface nsIDOMHTMLMapElement : nsISupports
+-{
+-  readonly attribute nsIDOMHTMLCollection areas;
+-           attribute DOMString            name;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLMenuElement.idl b/dom/interfaces/html/nsIDOMHTMLMenuElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLMenuElement.idl
++++ /dev/null
+@@ -1,26 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLMenuElement interface is the interface to a [X]HTML
+- * menu element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(a1ca9af6-f865-4fdf-901d-5858bb0ad5ea)]
+-interface nsIDOMHTMLMenuElement : nsISupports
+-{
+-           attribute boolean          compact;
+-
+-           attribute DOMString        type;
+-           attribute DOMString        label;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLMetaElement.idl b/dom/interfaces/html/nsIDOMHTMLMetaElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLMetaElement.idl
++++ /dev/null
+@@ -1,26 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLMetaElement interface is the interface to a [X]HTML
+- * meta element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(2a3f789e-0667-464f-a8d7-6f58513443d9)]
+-interface nsIDOMHTMLMetaElement : nsISupports
+-{
+-           attribute DOMString        content;
+-           attribute DOMString        httpEquiv;
+-           attribute DOMString        name;
+-           attribute DOMString        scheme;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLOListElement.idl b/dom/interfaces/html/nsIDOMHTMLOListElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLOListElement.idl
++++ /dev/null
+@@ -1,11 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsISupports.idl"
+-
+-[uuid(d899642a-53e2-4eb4-9d65-4a666a45ee01)]
+-interface nsIDOMHTMLOListElement : nsISupports
+-{
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLOptGroupElement.idl b/dom/interfaces/html/nsIDOMHTMLOptGroupElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLOptGroupElement.idl
++++ /dev/null
+@@ -1,11 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsISupports.idl"
+-
+-[uuid(6fa79f99-4ce4-4634-840a-867fcfb32dba)]
+-interface nsIDOMHTMLOptGroupElement : nsISupports
+-{
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLParagraphElement.idl b/dom/interfaces/html/nsIDOMHTMLParagraphElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLParagraphElement.idl
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLParagraphElement interface is the interface to a
+- * [X]HTML p element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(b494e517-2388-4a63-80e7-2f73be3c38a3)]
+-interface nsIDOMHTMLParagraphElement : nsISupports
+-{
+-           attribute DOMString        align;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLPictureElement.idl b/dom/interfaces/html/nsIDOMHTMLPictureElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLPictureElement.idl
++++ /dev/null
+@@ -1,12 +0,0 @@
+-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* vim:set ts=2 sw=2 sts=2 et cindent: */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-[scriptable, uuid(e0e5ac7f-b969-494c-a61e-9d740e38abba)]
+-interface nsIDOMHTMLPictureElement : nsISupports
+-{
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLPreElement.idl b/dom/interfaces/html/nsIDOMHTMLPreElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLPreElement.idl
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLPreElement interface is the interface to a [X]HTML
+- * pre element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(a2441b77-ad22-4275-b1dd-1b58c044fd04)]
+-interface nsIDOMHTMLPreElement : nsISupports
+-{
+-           attribute long             width;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLQuoteElement.idl b/dom/interfaces/html/nsIDOMHTMLQuoteElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLQuoteElement.idl
++++ /dev/null
+@@ -1,11 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsISupports.idl"
+-
+-[uuid(f02502b5-32a6-4df7-8a57-1416553a3188)]
+-interface nsIDOMHTMLQuoteElement : nsISupports
+-{
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLStyleElement.idl b/dom/interfaces/html/nsIDOMHTMLStyleElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLStyleElement.idl
++++ /dev/null
+@@ -1,27 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLStyleElement interface is the interface to a [X]HTML
+- * style element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(fa326d22-8739-4eef-a80e-6449bde605d2)]
+-interface nsIDOMHTMLStyleElement : nsISupports
+-{
+-           [binaryname(MozDisabled)]
+-           attribute boolean          disabled;
+-           attribute DOMString        media;
+-           attribute DOMString        type;
+-           attribute boolean          scoped;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLTableCellElement.idl b/dom/interfaces/html/nsIDOMHTMLTableCellElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLTableCellElement.idl
++++ /dev/null
+@@ -1,37 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsIDOMHTMLElement.idl"
+-
+-/**
+- * The nsIDOMHTMLTableCellElement interface is the interface to a
+- * [X]HTML td element.
+- *
+- * This interface is trying to follow the DOM Level 2 HTML specification:
+- * http://www.w3.org/TR/DOM-Level-2-HTML/
+- *
+- * with changes from the work-in-progress WHATWG HTML specification:
+- * http://www.whatwg.org/specs/web-apps/current-work/
+- */
+-
+-[uuid(3203c36f-33fd-4628-8c88-77e82d38df1e)]
+-interface nsIDOMHTMLTableCellElement : nsISupports
+-{
+-  readonly attribute long             cellIndex;
+-           attribute DOMString        abbr;
+-           attribute DOMString        align;
+-           attribute DOMString        axis;
+-           attribute DOMString        bgColor;
+-           attribute DOMString        ch;
+-           attribute DOMString        chOff;
+-           attribute long             colSpan;
+-           attribute DOMString        headers;
+-           attribute DOMString        height;
+-           attribute boolean          noWrap;
+-           attribute long             rowSpan;
+-           attribute DOMString        scope;
+-           attribute DOMString        vAlign;
+-           attribute DOMString        width;
+-};
+diff --git a/dom/interfaces/html/nsIDOMHTMLUListElement.idl b/dom/interfaces/html/nsIDOMHTMLUListElement.idl
+deleted file mode 100644
+--- a/dom/interfaces/html/nsIDOMHTMLUListElement.idl
++++ /dev/null
+@@ -1,11 +0,0 @@
+-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+-/* 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/. */
+-
+-#include "nsISupports.idl"
+-
+-[uuid(8ba1ee8d-36a4-43fc-9148-5144c2a29c96)]
+-interface nsIDOMHTMLUListElement : nsISupports
+-{
+-};
+diff --git a/gfx/layers/apz/util/DoubleTapToZoom.cpp b/gfx/layers/apz/util/DoubleTapToZoom.cpp
+--- a/gfx/layers/apz/util/DoubleTapToZoom.cpp
++++ b/gfx/layers/apz/util/DoubleTapToZoom.cpp
+@@ -7,18 +7,16 @@
+ 
+ #include <algorithm>  // for std::min, std::max
+ 
+ #include "mozilla/AlreadyAddRefed.h"
+ #include "mozilla/dom/Element.h"
+ #include "nsCOMPtr.h"
+ #include "nsIContent.h"
+ #include "nsIDocument.h"
+-#include "nsIDOMHTMLLIElement.h"
+-#include "nsIDOMHTMLQuoteElement.h"
+ #include "nsIDOMWindow.h"
+ #include "nsIFrame.h"
+ #include "nsIFrameInlines.h"
+ #include "nsIPresShell.h"
+ #include "nsLayoutUtils.h"
+ #include "nsStyleConsts.h"
+ 
+ namespace mozilla {
+diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp
+--- a/layout/base/nsDocumentViewer.cpp
++++ b/layout/base/nsDocumentViewer.cpp
+@@ -60,17 +60,16 @@
+ #include "nsIInterfaceRequestorUtils.h"
+ #include "nsDocShell.h"
+ #include "nsIBaseWindow.h"
+ #include "nsILayoutHistoryState.h"
+ #include "nsCharsetSource.h"
+ #include "mozilla/ReflowInput.h"
+ #include "nsIImageLoadingContent.h"
+ #include "nsCopySupport.h"
+-#include "nsIDOMHTMLFrameSetElement.h"
+ #include "nsIDOMHTMLImageElement.h"
+ #ifdef MOZ_XUL
+ #include "nsIXULDocument.h"
+ #include "nsXULPopupManager.h"
+ #endif
+ 
+ #include "nsIClipboardHelper.h"
+ 
+diff --git a/layout/printing/nsPrintEngine.cpp b/layout/printing/nsPrintEngine.cpp
+--- a/layout/printing/nsPrintEngine.cpp
++++ b/layout/printing/nsPrintEngine.cpp
+@@ -36,17 +36,16 @@ static const char sPrintSettingsServiceC
+ 
+ // Printing Events
+ #include "nsPrintPreviewListener.h"
+ #include "nsThreadUtils.h"
+ 
+ // Printing
+ #include "nsIWebBrowserPrint.h"
+ #include "nsIDOMHTMLFrameElement.h"
+-#include "nsIDOMHTMLFrameSetElement.h"
+ #include "nsIDOMHTMLIFrameElement.h"
+ #include "nsIDOMHTMLObjectElement.h"
+ 
+ // Print Preview
+ #include "imgIContainer.h" // image animation mode constants
+ #include "nsIWebBrowserPrint.h" // needed for PrintPreview Navigation constants
+ 
+ // Print Progress
+diff --git a/layout/xul/nsImageBoxFrame.cpp b/layout/xul/nsImageBoxFrame.cpp
+--- a/layout/xul/nsImageBoxFrame.cpp
++++ b/layout/xul/nsImageBoxFrame.cpp
+@@ -29,17 +29,16 @@
+ #include "nsILinkHandler.h"
+ #include "nsIURL.h"
+ #include "nsILoadGroup.h"
+ #include "nsContainerFrame.h"
+ #include "nsCSSRendering.h"
+ #include "nsIDOMHTMLImageElement.h"
+ #include "nsNameSpaceManager.h"
+ #include "nsTextFragment.h"
+-#include "nsIDOMHTMLMapElement.h"
+ #include "nsTransform2D.h"
+ #include "nsITheme.h"
+ 
+ #include "nsIServiceManager.h"
+ #include "nsIURI.h"
+ #include "nsThreadUtils.h"
+ #include "nsDisplayList.h"
+ #include "ImageLayers.h"
+diff --git a/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp b/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp
+--- a/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp
++++ b/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp
+@@ -43,56 +43,37 @@
+ #include "nsIDOMFileList.h"
+ #include "nsIDOMFocusEvent.h"
+ #include "nsIDOMFormData.h"
+ #include "nsIDOMGeoPositionError.h"
+ #include "nsIDOMHistory.h"
+ #include "nsIDOMHTMLAnchorElement.h"
+ #include "nsIDOMHTMLAreaElement.h"
+ #include "nsIDOMHTMLBaseElement.h"
+-#include "nsIDOMHTMLBodyElement.h"
+ #include "nsIDOMHTMLButtonElement.h"
+ #include "nsIDOMHTMLCanvasElement.h"
+ #include "nsIDOMHTMLCollection.h"
+-#include "nsIDOMHTMLDirectoryElement.h"
+ #include "nsIDOMHTMLDocument.h"
+ #include "nsIDOMHTMLElement.h"
+-#include "nsIDOMHTMLFieldSetElement.h"
+ #include "nsIDOMHTMLFormElement.h"
+ #include "nsIDOMHTMLFrameElement.h"
+-#include "nsIDOMHTMLFrameSetElement.h"
+-#include "nsIDOMHTMLHRElement.h"
+-#include "nsIDOMHTMLHeadElement.h"
+ #include "nsIDOMHTMLHtmlElement.h"
+ #include "nsIDOMHTMLIFrameElement.h"
+ #include "nsIDOMHTMLImageElement.h"
+ #include "nsIDOMHTMLInputElement.h"
+-#include "nsIDOMHTMLLIElement.h"
+-#include "nsIDOMHTMLLabelElement.h"
+ #include "nsIDOMHTMLLinkElement.h"
+-#include "nsIDOMHTMLMapElement.h"
+ #include "nsIDOMHTMLMediaElement.h"
+-#include "nsIDOMHTMLMenuElement.h"
+ #include "nsIDOMHTMLMenuItemElement.h"
+-#include "nsIDOMHTMLMetaElement.h"
+-#include "nsIDOMHTMLOListElement.h"
+ #include "nsIDOMHTMLObjectElement.h"
+-#include "nsIDOMHTMLOptGroupElement.h"
+ #include "nsIDOMHTMLOptionElement.h"
+ #include "nsIDOMHTMLOptionsCollection.h"
+-#include "nsIDOMHTMLParagraphElement.h"
+-#include "nsIDOMHTMLPreElement.h"
+-#include "nsIDOMHTMLQuoteElement.h"
+ #include "nsIDOMHTMLScriptElement.h"
+ #include "nsIDOMHTMLSelectElement.h"
+ #include "nsIDOMHTMLSourceElement.h"
+-#include "nsIDOMHTMLStyleElement.h"
+-#include "nsIDOMHTMLTableCellElement.h"
+ #include "nsIDOMHTMLTextAreaElement.h"
+-#include "nsIDOMHTMLUListElement.h"
+ #include "nsIDOMKeyEvent.h"
+ #include "nsIDOMMediaList.h"
+ #include "nsIDOMMouseEvent.h"
+ #include "nsIDOMMouseScrollEvent.h"
+ #include "nsIDOMMutationEvent.h"
+ #include "nsIDOMMozNamedAttrMap.h"
+ #include "nsIDOMNode.h"
+ #include "nsIDOMNodeIterator.h"
+@@ -169,56 +150,38 @@
+ #include "mozilla/dom/EventTargetBinding.h"
+ #include "mozilla/dom/FileListBinding.h"
+ #include "mozilla/dom/FocusEventBinding.h"
+ #include "mozilla/dom/FormDataBinding.h"
+ #include "mozilla/dom/HistoryBinding.h"
+ #include "mozilla/dom/HTMLAnchorElementBinding.h"
+ #include "mozilla/dom/HTMLAreaElementBinding.h"
+ #include "mozilla/dom/HTMLBaseElementBinding.h"
+-#include "mozilla/dom/HTMLBodyElementBinding.h"
+ #include "mozilla/dom/HTMLButtonElementBinding.h"
+ #include "mozilla/dom/HTMLCanvasElementBinding.h"
+ #include "mozilla/dom/HTMLCollectionBinding.h"
+-#include "mozilla/dom/HTMLDirectoryElementBinding.h"
+ #include "mozilla/dom/HTMLDocumentBinding.h"
+ #include "mozilla/dom/HTMLElementBinding.h"
+-#include "mozilla/dom/HTMLFieldSetElementBinding.h"
+ #include "mozilla/dom/HTMLFormElementBinding.h"
+ #include "mozilla/dom/HTMLFrameElementBinding.h"
+ #include "mozilla/dom/HTMLFrameSetElementBinding.h"
+-#include "mozilla/dom/HTMLHRElementBinding.h"
+-#include "mozilla/dom/HTMLHeadElementBinding.h"
+ #include "mozilla/dom/HTMLHtmlElementBinding.h"
+ #include "mozilla/dom/HTMLIFrameElementBinding.h"
+ #include "mozilla/dom/HTMLImageElementBinding.h"
+ #include "mozilla/dom/HTMLInputElementBinding.h"
+-#include "mozilla/dom/HTMLLIElementBinding.h"
+-#include "mozilla/dom/HTMLLabelElementBinding.h"
+ #include "mozilla/dom/HTMLLinkElementBinding.h"
+-#include "mozilla/dom/HTMLMapElementBinding.h"
+ #include "mozilla/dom/HTMLMediaElementBinding.h"
+-#include "mozilla/dom/HTMLMenuElementBinding.h"
+ #include "mozilla/dom/HTMLMenuItemElementBinding.h"
+-#include "mozilla/dom/HTMLMetaElementBinding.h"
+-#include "mozilla/dom/HTMLOListElementBinding.h"
+ #include "mozilla/dom/HTMLObjectElementBinding.h"
+-#include "mozilla/dom/HTMLOptGroupElementBinding.h"
+ #include "mozilla/dom/HTMLOptionElementBinding.h"
+ #include "mozilla/dom/HTMLOptionsCollectionBinding.h"
+-#include "mozilla/dom/HTMLParagraphElementBinding.h"
+-#include "mozilla/dom/HTMLPreElementBinding.h"
+-#include "mozilla/dom/HTMLQuoteElementBinding.h"
+ #include "mozilla/dom/HTMLScriptElementBinding.h"
+ #include "mozilla/dom/HTMLSelectElementBinding.h"
+ #include "mozilla/dom/HTMLSourceElementBinding.h"
+-#include "mozilla/dom/HTMLStyleElementBinding.h"
+-#include "mozilla/dom/HTMLTableCellElementBinding.h"
+ #include "mozilla/dom/HTMLTextAreaElementBinding.h"
+-#include "mozilla/dom/HTMLUListElementBinding.h"
+ #include "mozilla/dom/KeyEventBinding.h"
+ #include "mozilla/dom/ListBoxObjectBinding.h"
+ #include "mozilla/dom/MediaListBinding.h"
+ #include "mozilla/dom/MessageEventBinding.h"
+ #include "mozilla/dom/MenuBoxObjectBinding.h"
+ #include "mozilla/dom/MouseEventBinding.h"
+ #include "mozilla/dom/MouseScrollEventBinding.h"
+ #include "mozilla/dom/MutationEventBinding.h"
+@@ -353,56 +316,37 @@ const ComponentsInterfaceShimEntry kComp
+   DEFINE_SHIM(FileList),
+   DEFINE_SHIM(FocusEvent),
+   DEFINE_SHIM(FormData),
+   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMGeoPositionError, PositionError),
+   DEFINE_SHIM(History),
+   DEFINE_SHIM(HTMLAnchorElement),
+   DEFINE_SHIM(HTMLAreaElement),
+   DEFINE_SHIM(HTMLBaseElement),
+-  DEFINE_SHIM(HTMLBodyElement),
+   DEFINE_SHIM(HTMLButtonElement),
+   DEFINE_SHIM(HTMLCanvasElement),
+   DEFINE_SHIM(HTMLCollection),
+-  DEFINE_SHIM(HTMLDirectoryElement),
+   DEFINE_SHIM(HTMLDocument),
+   DEFINE_SHIM(HTMLElement),
+-  DEFINE_SHIM(HTMLFieldSetElement),
+   DEFINE_SHIM(HTMLFormElement),
+   DEFINE_SHIM(HTMLFrameElement),
+-  DEFINE_SHIM(HTMLFrameSetElement),
+-  DEFINE_SHIM(HTMLHRElement),
+-  DEFINE_SHIM(HTMLHeadElement),
+   DEFINE_SHIM(HTMLHtmlElement),
+   DEFINE_SHIM(HTMLIFrameElement),
+   DEFINE_SHIM(HTMLImageElement),
+   DEFINE_SHIM(HTMLInputElement),
+-  DEFINE_SHIM(HTMLLIElement),
+-  DEFINE_SHIM(HTMLLabelElement),
+   DEFINE_SHIM(HTMLLinkElement),
+-  DEFINE_SHIM(HTMLMapElement),
+   DEFINE_SHIM(HTMLMediaElement),
+-  DEFINE_SHIM(HTMLMenuElement),
+   DEFINE_SHIM(HTMLMenuItemElement),
+-  DEFINE_SHIM(HTMLMetaElement),
+-  DEFINE_SHIM(HTMLOListElement),
+   DEFINE_SHIM(HTMLObjectElement),
+-  DEFINE_SHIM(HTMLOptGroupElement),
+   DEFINE_SHIM(HTMLOptionElement),
+   DEFINE_SHIM(HTMLOptionsCollection),
+-  DEFINE_SHIM(HTMLParagraphElement),
+-  DEFINE_SHIM(HTMLPreElement),
+-  DEFINE_SHIM(HTMLQuoteElement),
+   DEFINE_SHIM(HTMLScriptElement),
+   DEFINE_SHIM(HTMLSelectElement),
+   DEFINE_SHIM(HTMLSourceElement),
+-  DEFINE_SHIM(HTMLStyleElement),
+-  DEFINE_SHIM(HTMLTableCellElement),
+   DEFINE_SHIM(HTMLTextAreaElement),
+-  DEFINE_SHIM(HTMLUListElement),
+   DEFINE_SHIM(KeyEvent),
+   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIListBoxObject, ListBoxObject),
+   DEFINE_SHIM(MediaList),
+   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIMenuBoxObject, MenuBoxObject),
+   DEFINE_SHIM(MouseEvent),
+   DEFINE_SHIM(MouseScrollEvent),
+   DEFINE_SHIM(MutationEvent),
+   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMMozNamedAttrMap, NamedNodeMap),

+ 37 - 0
frg/253-58/mozilla-release58_428197.patch

@@ -0,0 +1,37 @@
+# HG changeset patch
+# User Tom Ritter <tom@mozilla.com>
+# Date 1503440727 18000
+#      Tue Aug 22 17:25:27 2017 -0500
+# Node ID acae3198b087f26a4f1da62588ec790f947125eb
+# Parent  9a9a28c1778e1aa2ec7ce852e7b4eb9cb7a25c85
+Bug 1392684 Remove const qualifier that gets discarded after function return in mscom::AgileReference r=aklotz
+
+gcc throws a warning-as-error saying that the const qualifier will be ignored by function callers.
+Remove the const qualifier to remove the warning.
+
+MozReview-Commit-ID: JRQMz6Zdcdz
+
+diff --git a/ipc/mscom/AgileReference.cpp b/ipc/mscom/AgileReference.cpp
+old mode 100644
+new mode 100755
+--- a/ipc/mscom/AgileReference.cpp
++++ b/ipc/mscom/AgileReference.cpp
+@@ -130,17 +130,17 @@ AgileReference::Resolve(REFIID aIid, voi
+   return originalInterface->QueryInterface(aIid, aOutInterface);
+ }
+ 
+ IGlobalInterfaceTable*
+ AgileReference::ObtainGit()
+ {
+   // Internally to COM, the Global Interface Table is a singleton, therefore we
+   // don't worry about holding onto this reference indefinitely.
+-  static IGlobalInterfaceTable * const sGit = []() -> IGlobalInterfaceTable * const {
++  static IGlobalInterfaceTable* sGit = []() -> IGlobalInterfaceTable* {
+     IGlobalInterfaceTable* result = nullptr;
+     DebugOnly<HRESULT> hr =
+       ::CoCreateInstance(CLSID_StdGlobalInterfaceTable, nullptr,
+                          CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable,
+                          reinterpret_cast<void**>(&result));
+     MOZ_ASSERT(SUCCEEDED(hr));
+     return result;
+   }();

+ 81 - 0
frg/253-58/mozilla-release58_428202.patch

@@ -0,0 +1,81 @@
+# HG changeset patch
+# User Mantaroh Yoshinaga <mantaroh@gmail.com>
+# Date 1503377146 -32400
+#      Tue Aug 22 13:45:46 2017 +0900
+# Node ID f5b6eedb70c9638a61f54fdb29e34c88e48ac2d7
+# Parent  401c2744f16bf758e1046d6bcf2947ec9ea64791
+Bug 1387986 - Enable stroke-* test of test_transitions_per_property.html on Servo. r=birtles
+
+MozReview-Commit-ID: 6OGzMPAEP6K
+
+diff --git a/layout/style/test/test_transitions_per_property.html b/layout/style/test/test_transitions_per_property.html
+--- a/layout/style/test/test_transitions_per_property.html
++++ b/layout/style/test/test_transitions_per_property.html
+@@ -56,23 +56,16 @@ function any_unit_to_num(str)
+ }
+ 
+ var FUNC_NEGATIVE = "cubic-bezier(0.25, -2, 0.75, 1)";
+ var FUNC_OVERONE = "cubic-bezier(0.25, 0, 0.75, 3)";
+ 
+ // After resolving Bug 1387080, we can remove this variable.
+ const isServo = SpecialPowers.DOMWindowUtils.isStyledByServo;
+ 
+-// The following properties will be skipped while using Servo backend.
+-var skippedProperties = {
+-    "stroke-dasharray": true,       // Bug 1387986
+-    "stroke-dashoffset": true,      // Bug 1369614
+-    "stroke-width": true,           // Bug 1369614
+-};
+-
+ var supported_properties = {
+     "border-bottom-left-radius": [ test_radius_transition ],
+     "border-bottom-right-radius": [ test_radius_transition ],
+     "border-top-left-radius": [ test_radius_transition ],
+     "border-top-right-radius": [ test_radius_transition ],
+     "-moz-box-flex": [ test_float_zeroToOne_transition,
+                        test_float_aboveOne_transition,
+                        test_float_zeroToOne_clamped ],
+@@ -983,21 +976,16 @@ function sample_array(array, count) {
+   }
+   return result;
+ }
+ 
+ // Test that transitions don't do anything (i.e., aren't supported) on
+ // the properties not in our test list above (and not transition
+ // properties themselves).
+ for (prop in gCSSProperties) {
+-  // Bug 1387080, we should remove this after passing all tests.
+-  if (isServo && (prop in skippedProperties)) {
+-    continue;
+-  }
+-
+   var info = gCSSProperties[prop];
+   if (!(prop in supported_properties) &&
+       info.type != CSS_TYPE_TRUE_SHORTHAND &&
+       !("alias_for" in info) &&
+       !prop.match(/^transition-/) &&
+       // FIXME (Bug 119078): THIS SHOULD REALLY NOT BE NEEDED!
+       prop != "-moz-binding" &&
+       prop != "mask") {
+@@ -1066,21 +1054,16 @@ for (prop in gCSSProperties) {
+ // Do 4-second linear transitions with -1 second transition delay and
+ // linear timing function so that we can expect the transition to be
+ // one quarter of the way through the value space right after changing
+ // the property.
+ div.style.setProperty("transition-duration", "4s", "");
+ div.style.setProperty("transition-delay", "-1s", "");
+ div.style.setProperty("transition-timing-function", "linear", "");
+ for (prop in supported_properties) {
+-  // Bug 1387080, we should remove this after passing all tests.
+-  if (isServo && (prop in skippedProperties)) {
+-    continue;
+-  }
+-
+   var tinfo = supported_properties[prop];
+   var info = gCSSProperties[prop];
+ 
+   isnot(info.type, CSS_TYPE_TRUE_SHORTHAND,
+         prop + " must not be a shorthand");
+   if ("prerequisites" in info) {
+     var prereqs = info.prerequisites;
+     for (var prereq in prereqs) {

+ 436 - 0
frg/253-58/mozilla-release58_428203.patch

@@ -0,0 +1,436 @@
+# HG changeset patch
+# User Imanol Fernandez <mortimergoro@gmail.com>
+# Date 1503441900 18000
+#      Tue Aug 22 17:45:00 2017 -0500
+# Node ID 0da9ca2ca770d4b53ec63fa793fe2d4ba6956720
+# Parent  f5b6eedb70c9638a61f54fdb29e34c88e48ac2d7
+servo: Merge #18177 - Implement WebGL OES_standard_derivatives extension (from MortimerGoro:oes_standard_derivatives); r=emilio
+
+<!-- Please describe your changes on the following line: -->
+
+Implement WebGL OES_standard_derivatives extension. Some Three.js 3D models fail to render because of the lack of this extension.
+
+---
+<!-- 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
+- [ ] These changes fix #__ (github issue number if applicable).
+
+<!-- Either: -->
+- [x] There are tests for these changes OR
+- [ ] These changes do not require tests because _____
+
+<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
+
+<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
+
+Source-Repo: https://github.com/servo/servo
+Source-Revision: 85e6f6f7cc7edc961e246d8ac50b8dc18b0b2617
+
+diff --git a/servo/components/canvas/webgl_thread.rs b/servo/components/canvas/webgl_thread.rs
+--- a/servo/components/canvas/webgl_thread.rs
++++ b/servo/components/canvas/webgl_thread.rs
+@@ -887,17 +887,18 @@ impl WebGLImpl {
+             gl::STENCIL_FAIL |
+             gl::STENCIL_FUNC |
+             gl::STENCIL_PASS_DEPTH_FAIL |
+             gl::STENCIL_PASS_DEPTH_PASS |
+             gl::STENCIL_REF |
+             gl::STENCIL_VALUE_MASK |
+             gl::STENCIL_WRITEMASK |
+             gl::SUBPIXEL_BITS |
+-            gl::UNPACK_ALIGNMENT =>
++            gl::UNPACK_ALIGNMENT |
++            gl::FRAGMENT_SHADER_DERIVATIVE_HINT =>
+             //gl::UNPACK_COLORSPACE_CONVERSION_WEBGL =>
+                 Ok(WebGLParameter::Int(gl.get_integer_v(param_id))),
+ 
+             gl::BLEND |
+             gl::CULL_FACE |
+             gl::DEPTH_TEST |
+             gl::DEPTH_WRITEMASK |
+             gl::DITHER |
+diff --git a/servo/components/script/dom/webgl_extensions/ext/mod.rs b/servo/components/script/dom/webgl_extensions/ext/mod.rs
+--- a/servo/components/script/dom/webgl_extensions/ext/mod.rs
++++ b/servo/components/script/dom/webgl_extensions/ext/mod.rs
+@@ -1,13 +1,14 @@
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
+ use super::{ext_constants, WebGLExtension, WebGLExtensions};
+ 
++pub mod oesstandardderivatives;
+ pub mod oestexturefloat;
+ pub mod oestexturefloatlinear;
+ pub mod oestexturehalffloat;
+ pub mod oestexturehalffloatlinear;
+ pub mod oesvertexarrayobject;
+ pub mod webglvertexarrayobjectoes;
+diff --git a/servo/components/script/dom/webgl_extensions/ext/oesstandardderivatives.rs b/servo/components/script/dom/webgl_extensions/ext/oesstandardderivatives.rs
+new file mode 100644
+--- /dev/null
++++ b/servo/components/script/dom/webgl_extensions/ext/oesstandardderivatives.rs
+@@ -0,0 +1,50 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++use dom::bindings::codegen::Bindings::OESStandardDerivativesBinding;
++use dom::bindings::codegen::Bindings::OESStandardDerivativesBinding::OESStandardDerivativesConstants;
++use dom::bindings::js::Root;
++use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
++use dom::webglrenderingcontext::WebGLRenderingContext;
++use dom_struct::dom_struct;
++use super::{WebGLExtension, WebGLExtensions};
++
++#[dom_struct]
++pub struct OESStandardDerivatives {
++    reflector_: Reflector,
++}
++
++impl OESStandardDerivatives {
++    fn new_inherited() -> OESStandardDerivatives {
++        Self {
++            reflector_: Reflector::new(),
++        }
++    }
++}
++
++impl WebGLExtension for OESStandardDerivatives {
++    type Extension = OESStandardDerivatives;
++    fn new(ctx: &WebGLRenderingContext) -> Root<OESStandardDerivatives> {
++        reflect_dom_object(box OESStandardDerivatives::new_inherited(),
++                           &*ctx.global(),
++                           OESStandardDerivativesBinding::Wrap)
++    }
++
++    fn is_supported(ext: &WebGLExtensions) -> bool {
++        if cfg!(any(target_os = "android", target_os = "ios")) {
++            return ext.supports_any_gl_extension(&["GL_OES_standard_derivatives"]);
++        }
++        // The standard derivatives are always available in desktop OpenGL.
++        true
++    }
++
++    fn enable(ext: &WebGLExtensions) {
++        ext.enable_hint_target(OESStandardDerivativesConstants::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
++        ext.enable_get_parameter_name(OESStandardDerivativesConstants::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
++    }
++
++    fn name() -> &'static str {
++        "OES_standard_derivatives"
++    }
++}
+diff --git a/servo/components/script/dom/webgl_extensions/extensions.rs b/servo/components/script/dom/webgl_extensions/extensions.rs
+--- a/servo/components/script/dom/webgl_extensions/extensions.rs
++++ b/servo/components/script/dom/webgl_extensions/extensions.rs
+@@ -1,16 +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/. */
+ 
+ use canvas_traits::webgl::WebGLError;
+ use core::iter::FromIterator;
+ use core::nonzero::NonZero;
+ use dom::bindings::cell::DOMRefCell;
++use dom::bindings::codegen::Bindings::OESStandardDerivativesBinding::OESStandardDerivativesConstants;
+ use dom::bindings::codegen::Bindings::OESTextureHalfFloatBinding::OESTextureHalfFloatConstants;
+ use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
+ use dom::bindings::js::Root;
+ use dom::bindings::trace::JSTraceable;
+ use dom::webglrenderingcontext::WebGLRenderingContext;
+ use gleam::gl::GLenum;
+ use heapsize::HeapSizeOf;
+ use js::jsapi::{JSContext, JSObject};
+@@ -30,34 +31,47 @@ const DEFAULT_DISABLED_TEX_TYPES: [GLenu
+ 
+ // Data types that are implemented for textures in WebGLRenderingContext
+ // but not allowed to use with linear filtering until the related WebGL Extensions are enabled.
+ // Example: https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/
+ const DEFAULT_NOT_FILTERABLE_TEX_TYPES: [GLenum; 2] = [
+     constants::FLOAT, OESTextureHalfFloatConstants::HALF_FLOAT_OES
+ ];
+ 
++// Param names that are implemented for getParameter WebGL function
++// but must trigger a InvalidEnum error until the related WebGL Extensions are enabled.
++// Example: https://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/
++const DEFAULT_DISABLED_GET_PARAMETER_NAMES: [GLenum; 1] = [
++    OESStandardDerivativesConstants::FRAGMENT_SHADER_DERIVATIVE_HINT_OES
++];
++
+ /// WebGL features that are enabled/disabled by WebGL Extensions.
+ #[derive(JSTraceable, HeapSizeOf)]
+ struct WebGLExtensionFeatures {
+     gl_extensions: HashSet<String>,
+     disabled_tex_types: HashSet<GLenum>,
+     not_filterable_tex_types: HashSet<GLenum>,
+     effective_tex_internal_formats: HashMap<TexFormatType, u32>,
+-    query_parameter_handlers: HashMap<GLenum, WebGLQueryParameterHandler>
++    query_parameter_handlers: HashMap<GLenum, WebGLQueryParameterHandler>,
++    /// WebGL Hint() targets enabled by extensions.
++    hint_targets: HashSet<GLenum>,
++    /// WebGL GetParameter() names enabled by extensions.
++    disabled_get_parameter_names: HashSet<GLenum>,
+ }
+ 
+ impl Default for WebGLExtensionFeatures {
+     fn default() -> WebGLExtensionFeatures {
+         WebGLExtensionFeatures {
+             gl_extensions: HashSet::new(),
+             disabled_tex_types: DEFAULT_DISABLED_TEX_TYPES.iter().cloned().collect(),
+             not_filterable_tex_types: DEFAULT_NOT_FILTERABLE_TEX_TYPES.iter().cloned().collect(),
+             effective_tex_internal_formats: HashMap::new(),
+-            query_parameter_handlers: HashMap::new()
++            query_parameter_handlers: HashMap::new(),
++            hint_targets: HashSet::new(),
++            disabled_get_parameter_names: DEFAULT_DISABLED_GET_PARAMETER_NAMES.iter().cloned().collect(),
+         }
+     }
+ }
+ 
+ /// Handles the list of implemented, supported and enabled WebGL extensions.
+ #[must_root]
+ #[derive(JSTraceable, HeapSizeOf)]
+ pub struct WebGLExtensions {
+@@ -100,18 +114,28 @@ impl WebGLExtensions {
+             if extension.is_supported(self) {
+                 Some(extension.instance_or_init(ctx, self))
+             } else {
+                 None
+             }
+         })
+     }
+ 
++    pub fn is_enabled<T>(&self) -> bool
++    where
++        T: 'static + WebGLExtension + JSTraceable + HeapSizeOf
++    {
++        let name = T::name().to_uppercase();
++        self.extensions.borrow().get(&name).map_or(false, |ext| { ext.is_enabled() })
++    }
++
+     pub fn get_dom_object<T>(&self) -> Option<Root<T::Extension>>
+-           where T: 'static + WebGLExtension + JSTraceable + HeapSizeOf {
++    where
++        T: 'static + WebGLExtension + JSTraceable + HeapSizeOf
++    {
+         let name = T::name().to_uppercase();
+         self.extensions.borrow().get(&name).and_then(|extension| {
+             extension.as_any().downcast_ref::<TypedWebGLExtensionWrapper<T>>().and_then(|extension| {
+                 extension.dom_object()
+             })
+         })
+     }
+ 
+@@ -167,17 +191,34 @@ impl WebGLExtensions {
+     }
+ 
+     pub fn get_query_parameter_handler(&self, name: GLenum) -> Option<Ref<Box<WebGLQueryParameterFunc>>> {
+         ref_filter_map(self.features.borrow(), |features| {
+             features.query_parameter_handlers.get(&name).map(|item| &item.func)
+         })
+     }
+ 
++    pub fn enable_hint_target(&self, name: GLenum) {
++        self.features.borrow_mut().hint_targets.insert(name);
++    }
++
++    pub fn is_hint_target_enabled(&self, name: GLenum) -> bool {
++        self.features.borrow().hint_targets.contains(&name)
++    }
++
++    pub fn enable_get_parameter_name(&self, name: GLenum) {
++        self.features.borrow_mut().disabled_get_parameter_names.remove(&name);
++    }
++
++    pub fn is_get_parameter_name_enabled(&self, name: GLenum) -> bool {
++        !self.features.borrow().disabled_get_parameter_names.contains(&name)
++    }
++
+     fn register_all_extensions(&self) {
++        self.register::<ext::oesstandardderivatives::OESStandardDerivatives>();
+         self.register::<ext::oestexturefloat::OESTextureFloat>();
+         self.register::<ext::oestexturefloatlinear::OESTextureFloatLinear>();
+         self.register::<ext::oestexturehalffloat::OESTextureHalfFloat>();
+         self.register::<ext::oestexturehalffloatlinear::OESTextureHalfFloatLinear>();
+         self.register::<ext::oesvertexarrayobject::OESVertexArrayObject>();
+     }
+ }
+ 
+diff --git a/servo/components/script/dom/webgl_extensions/wrapper.rs b/servo/components/script/dom/webgl_extensions/wrapper.rs
+--- a/servo/components/script/dom/webgl_extensions/wrapper.rs
++++ b/servo/components/script/dom/webgl_extensions/wrapper.rs
+@@ -15,16 +15,17 @@ use super::{WebGLExtension, WebGLExtensi
+ /// Trait used internally by WebGLExtensions to store and
+ /// handle the different WebGL extensions in a common list.
+ pub trait WebGLExtensionWrapper: JSTraceable + HeapSizeOf {
+     fn instance_or_init(&self,
+                         ctx: &WebGLRenderingContext,
+                         ext: &WebGLExtensions)
+                         -> NonZero<*mut JSObject>;
+     fn is_supported(&self, &WebGLExtensions) -> bool;
++    fn is_enabled(&self) -> bool;
+     fn enable(&self, ext: &WebGLExtensions);
+     fn name(&self) -> &'static str;
+     fn as_any(&self) -> &Any;
+ }
+ 
+ #[must_root]
+ #[derive(JSTraceable, HeapSizeOf)]
+ pub struct TypedWebGLExtensionWrapper<T: WebGLExtension> {
+@@ -57,17 +58,21 @@ impl<T> WebGLExtensionWrapper for TypedW
+             self.enable(ext);
+         }
+         unsafe {
+             NonZero::new_unchecked(extension.reflector().get_jsobject().get())
+         }
+     }
+ 
+     fn is_supported(&self, ext: &WebGLExtensions) -> bool {
+-        self.extension.get().is_some() || T::is_supported(ext)
++        self.is_enabled() || T::is_supported(ext)
++    }
++
++    fn is_enabled(&self) -> bool {
++        self.extension.get().is_some()
+     }
+ 
+     fn enable(&self, ext: &WebGLExtensions) {
+         T::enable(ext);
+     }
+ 
+     fn name(&self) -> &'static str {
+         T::name()
+diff --git a/servo/components/script/dom/webglrenderingcontext.rs b/servo/components/script/dom/webglrenderingcontext.rs
+--- a/servo/components/script/dom/webglrenderingcontext.rs
++++ b/servo/components/script/dom/webglrenderingcontext.rs
+@@ -1217,17 +1217,22 @@ impl WebGLRenderingContextMethods for We
+             }
+             constants::IMPLEMENTATION_COLOR_READ_TYPE => {
+                 if !self.validate_framebuffer_complete() {
+                     return NullValue();
+                 } else {
+                     return Int32Value(constants::UNSIGNED_BYTE as i32);
+                 }
+             }
+-            _ => {}
++            _ => {
++                if !self.extension_manager.is_get_parameter_name_enabled(parameter) {
++                    self.webgl_error(WebGLError::InvalidEnum);
++                    return NullValue();
++                }
++            }
+         }
+ 
+         // Handle GetParameter getters injected via WebGL extensions
+         if let Some(query_handler) = self.extension_manager.get_query_parameter_handler(parameter) {
+             match query_handler(cx, &self) {
+                 Ok(value) => {
+                     return value;
+                 },
+@@ -1827,17 +1832,17 @@ impl WebGLRenderingContextMethods for We
+         if self.validate_feature_enum(cap) {
+             self.send_command(WebGLCommand::Disable(cap));
+         }
+     }
+ 
+     // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9
+     fn CompileShader(&self, shader: Option<&WebGLShader>) {
+         if let Some(shader) = shader {
+-            shader.compile()
++            shader.compile(&self.extension_manager)
+         }
+     }
+ 
+     // TODO(emilio): Probably in the future we should keep track of the
+     // generated objects, either here or in the webgl thread
+     // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5
+     fn CreateBuffer(&self) -> Option<Root<WebGLBuffer>> {
+         WebGLBuffer::maybe_new(self.global().as_window(), self.webgl_sender.clone())
+@@ -2279,17 +2284,17 @@ impl WebGLRenderingContextMethods for We
+         let (sender, receiver) = webgl_channel().unwrap();
+         self.send_command(WebGLCommand::GetVertexAttribOffset(index, pname, sender));
+ 
+         handle_potential_webgl_error!(self, receiver.recv().unwrap(), 0) as i64
+     }
+ 
+     // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3
+     fn Hint(&self, target: u32, mode: u32) {
+-        if target != constants::GENERATE_MIPMAP_HINT {
++        if target != constants::GENERATE_MIPMAP_HINT && !self.extension_manager.is_hint_target_enabled(target) {
+             return self.webgl_error(InvalidEnum);
+         }
+ 
+         match mode {
+             constants::FASTEST |
+             constants::NICEST |
+             constants::DONT_CARE => (),
+ 
+diff --git a/servo/components/script/dom/webglshader.rs b/servo/components/script/dom/webglshader.rs
+--- a/servo/components/script/dom/webglshader.rs
++++ b/servo/components/script/dom/webglshader.rs
+@@ -5,16 +5,18 @@
+ // https://www.khronos.org/registry/webgl/specs/latest/1.0/webgl.idl
+ use angle::hl::{BuiltInResources, Output, ShaderValidator};
+ use canvas_traits::webgl::{webgl_channel, WebGLCommand, WebGLMsgSender, WebGLParameter, WebGLResult, WebGLShaderId};
+ use dom::bindings::cell::DOMRefCell;
+ use dom::bindings::codegen::Bindings::WebGLShaderBinding;
+ use dom::bindings::js::Root;
+ use dom::bindings::reflector::reflect_dom_object;
+ use dom::bindings::str::DOMString;
++use dom::webgl_extensions::WebGLExtensions;
++use dom::webgl_extensions::ext::oesstandardderivatives::OESStandardDerivatives;
+ use dom::webglobject::WebGLObject;
+ use dom::window::Window;
+ use dom_struct::dom_struct;
+ use std::cell::Cell;
+ use std::sync::{ONCE_INIT, Once};
+ 
+ #[derive(Clone, Copy, PartialEq, Debug, JSTraceable, HeapSizeOf)]
+ pub enum ShaderCompilationStatus {
+@@ -92,24 +94,25 @@ impl WebGLShader {
+         self.id
+     }
+ 
+     pub fn gl_type(&self) -> u32 {
+         self.gl_type
+     }
+ 
+     /// glCompileShader
+-    pub fn compile(&self) {
++    pub fn compile(&self, ext: &WebGLExtensions) {
+         if self.compilation_status.get() != ShaderCompilationStatus::NotCompiled {
+             debug!("Compiling already compiled shader {}", self.id);
+         }
+ 
+         if let Some(ref source) = *self.source.borrow() {
+             let mut params = BuiltInResources::default();
+             params.FragmentPrecisionHigh = 1;
++            params.OES_standard_derivatives = ext.is_enabled::<OESStandardDerivatives>() as i32;
+             let validator = ShaderValidator::for_webgl(self.gl_type,
+                                                        SHADER_OUTPUT_FORMAT,
+                                                        &params).unwrap();
+             match validator.compile_and_translate(&[source]) {
+                 Ok(translated_source) => {
+                     debug!("Shader translated: {}", translated_source);
+                     // NOTE: At this point we should be pretty sure that the compilation in the paint thread
+                     // will succeed.
+diff --git a/servo/components/script/dom/webidls/OESStandardDerivatives.webidl b/servo/components/script/dom/webidls/OESStandardDerivatives.webidl
+new file mode 100644
+--- /dev/null
++++ b/servo/components/script/dom/webidls/OESStandardDerivatives.webidl
+@@ -0,0 +1,12 @@
++/* 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/. */
++/*
++ * WebGL IDL definitions from the Khronos specification:
++ * https://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/
++ */
++
++[NoInterfaceObject]
++interface OESStandardDerivatives {
++    const GLenum FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B;
++};

+ 144 - 0
frg/253-58/mozilla-release58_428204.patch

@@ -0,0 +1,144 @@
+# HG changeset patch
+# User Timothy Guan-tin Chien <timdream@gmail.com>
+# Date 1503291453 -28800
+#      Mon Aug 21 12:57:33 2017 +0800
+# Node ID 829183c09b2c00d50e2919bcd024c42f80315e0c
+# Parent  0da9ca2ca770d4b53ec63fa793fe2d4ba6956720
+Bug 1392167 - Have getCurrentActiveTour() check states of all DOM elements. r=Fischer,gasolin
+
+MozReview-Commit-ID: DHu4ZKGXdfD
+
+diff --git a/browser/extensions/onboarding/test/browser/browser_onboarding_select_default_tour.js b/browser/extensions/onboarding/test/browser/browser_onboarding_select_default_tour.js
+--- a/browser/extensions/onboarding/test/browser/browser_onboarding_select_default_tour.js
++++ b/browser/extensions/onboarding/test/browser/browser_onboarding_select_default_tour.js
+@@ -26,65 +26,35 @@ add_task(async function test_default_tou
+   info("Make sure the default tour is active and open the right page");
+   let { activeNavItemId, activePageId } = await getCurrentActiveTour(tab.linkedBrowser);
+   is(`#${activeNavItemId}`, PRIVATE_BROWSING_TOUR_ID, "default tour is active");
+   is(activePageId, "onboarding-tour-private-browsing-page", "default tour page is shown");
+ 
+   await BrowserTestUtils.removeTab(tab);
+ });
+ 
+-add_task(async function test_first_tour_is_active_by_default() {
+-  resetOnboardingDefaultState();
+-  await SpecialPowers.pushPrefEnv({set: [
+-    ["browser.onboarding.tour-type", "new"],
+-    ["browser.onboarding.tourset-version", 1],
+-    ["browser.onboarding.seen-tourset-version", 1],
+-    ["browser.onboarding.newtour", "private,addons,customize"],
+-  ]});
+-
+-  let tab = await openTab(ABOUT_NEWTAB_URL);
+-  await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+-  await BrowserTestUtils.synthesizeMouseAtCenter(OVERLAY_ICON_ID, {}, tab.linkedBrowser);
+-  await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+-
+-  info("Make sure the default tour is selected");
+-  let doc = content && content.document;
+-  let dom = doc.querySelector(PRIVATE_BROWSING_TOUR_ID);
+-  ok(dom.classList.contains(CLASS_ACTIVE), "default tour is selected");
+-  let dom2 = doc.querySelector(ADDONS_TOUR_ID);
+-  ok(!dom2.classList.contains(CLASS_ACTIVE), "none default tour should not be selected");
+-  let dom3 = doc.querySelector(CUSTOMIZE_TOUR_ID);
+-  ok(!dom3.classList.contains(CLASS_ACTIVE), "none default tour should not be selected");
+-
+-  await BrowserTestUtils.removeTab(tab);
+-});
+-
+ add_task(async function test_select_first_uncomplete_tour() {
+   resetOnboardingDefaultState();
+   await SpecialPowers.pushPrefEnv({set: [
+     ["browser.onboarding.tour-type", "new"],
+     ["browser.onboarding.tourset-version", 1],
+     ["browser.onboarding.seen-tourset-version", 1],
+     ["browser.onboarding.newtour", "private,addons,customize"],
+   ]});
+   setTourCompletedState("onboarding-tour-private-browsing", true);
+ 
+   let tab = await openTab(ABOUT_NEWTAB_URL);
+   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+   await BrowserTestUtils.synthesizeMouseAtCenter(OVERLAY_ICON_ID, {}, tab.linkedBrowser);
+   await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+ 
+   info("Make sure the first uncomplete tour is selected");
+-  let doc = content && content.document;
+-  let dom = doc.querySelector(PRIVATE_BROWSING_TOUR_ID);
+-  ok(!dom.classList.contains(CLASS_ACTIVE), "the first tour is set completed and should not be selected");
+-  let dom2 = doc.querySelector(ADDONS_TOUR_ID);
+-  ok(dom2.classList.contains(CLASS_ACTIVE), "the first uncomplete tour is selected");
+-  let dom3 = doc.querySelector(CUSTOMIZE_TOUR_ID);
+-  ok(!dom3.classList.contains(CLASS_ACTIVE), "other tour should not be selected");
++  let { activeNavItemId, activePageId } = await getCurrentActiveTour(tab.linkedBrowser);
++  is(`#${activeNavItemId}`, ADDONS_TOUR_ID, "default tour is active");
++  is(activePageId, "onboarding-tour-addons-page", "default tour page is shown");
+ 
+   await BrowserTestUtils.removeTab(tab);
+ });
+ 
+ add_task(async function test_select_first_tour_when_all_tours_are_complete() {
+   resetOnboardingDefaultState();
+   await SpecialPowers.pushPrefEnv({set: [
+     ["browser.onboarding.tour-type", "new"],
+@@ -97,18 +67,14 @@ add_task(async function test_select_firs
+   setTourCompletedState("onboarding-tour-customize", true);
+ 
+   let tab = await openTab(ABOUT_NEWTAB_URL);
+   await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
+   await BrowserTestUtils.synthesizeMouseAtCenter(OVERLAY_ICON_ID, {}, tab.linkedBrowser);
+   await promiseOnboardingOverlayOpened(tab.linkedBrowser);
+ 
+   info("Make sure the first tour is selected when all tours are completed");
+-  let doc = content && content.document;
+-  let dom = doc.querySelector(PRIVATE_BROWSING_TOUR_ID);
+-  ok(dom.classList.contains(CLASS_ACTIVE), "should be selected when all tours are completed");
+-  let dom2 = doc.querySelector(ADDONS_TOUR_ID);
+-  ok(!dom2.classList.contains(CLASS_ACTIVE), "other tour should not be selected");
+-  let dom3 = doc.querySelector(CUSTOMIZE_TOUR_ID);
+-  ok(!dom3.classList.contains(CLASS_ACTIVE), "other tour should not be selected");
++  let { activeNavItemId, activePageId } = await getCurrentActiveTour(tab.linkedBrowser);
++  is(`#${activeNavItemId}`, PRIVATE_BROWSING_TOUR_ID, "default tour is active");
++  is(activePageId, "onboarding-tour-private-browsing-page", "default tour page is shown");
+ 
+   await BrowserTestUtils.removeTab(tab);
+ });
+diff --git a/browser/extensions/onboarding/test/browser/head.js b/browser/extensions/onboarding/test/browser/head.js
+--- a/browser/extensions/onboarding/test/browser/head.js
++++ b/browser/extensions/onboarding/test/browser/head.js
+@@ -175,26 +175,32 @@ function getCurrentNotificationTargetTou
+ 
+ function getCurrentActiveTour(browser) {
+   return ContentTask.spawn(browser, {}, function() {
+     let list = content.document.querySelector("#onboarding-tour-list");
+     let items = list.querySelectorAll(".onboarding-tour-item");
+     let activeNavItemId = null;
+     for (let item of items) {
+       if (item.classList.contains("onboarding-active")) {
+-        activeNavItemId = item.id;
+-        break;
++        if (!activeNavItemId) {
++          activeNavItemId = item.id;
++        } else {
++          ok(false, "There are more than one item marked as active.");
++        }
+       }
+     }
+     let activePageId = null;
+     let pages = content.document.querySelectorAll(".onboarding-tour-page");
+     for (let page of pages) {
+       if (page.style.display != "none") {
+-        activePageId = page.id;
+-        break;
++        if (!activePageId) {
++          activePageId = page.id;
++        } else {
++          ok(false, "Thre are more than one tour page visible.");
++        }
+       }
+     }
+     return { activeNavItemId, activePageId };
+   });
+ }
+ 
+ function waitUntilWindowIdle(browser) {
+   return ContentTask.spawn(browser, {}, function() {

+ 48 - 0
frg/253-58/mozilla-release58_428207.patch

@@ -0,0 +1,48 @@
+# HG changeset patch
+# User Josh Matthews <josh@joshmatthews.net>
+# Date 1503446112 18000
+#      Tue Aug 22 18:55:12 2017 -0500
+# Node ID 21a88d991f7aa7e5600acf3e3f8cad7313188885
+# Parent  82367773d75ab3e177ee9dde34785ed8eb617b87
+servo: Merge #18193 - Move fast checks into earlier Travis task (from servo:jdm-patch-2); r=SimonSapin
+
+This allows quicker feedback about whether the manifest needs updating; otherwise it has to wait until all builds and tests are complete.
+
+Source-Repo: https://github.com/servo/servo
+Source-Revision: 9c338a29294dc8ebf2c75dcdc3f2e67caef48ebe
+
+diff --git a/servo/.travis.yml b/servo/.travis.yml
+--- a/servo/.travis.yml
++++ b/servo/.travis.yml
+@@ -2,29 +2,29 @@ language: python
+ 
+ matrix:
+   fast_finish: true
+   include:
+     - sudo: false
+       script:
+          - ./mach test-tidy --no-progress --all
+          - ./mach test-tidy --no-progress --self-test
++         - bash etc/ci/check_no_panic.sh
++         - bash etc/ci/manifest_changed.sh
+       cache: false
+     - sudo: 9000
+       dist: trusty
+       script:
+          - ./mach build -d --verbose
+          - ./mach test-compiletest
+          - ./mach test-unit
+          - ./mach clean
+          - ./mach build-geckolib
+          - ./mach test-stylo
+-         - bash etc/ci/check_no_panic.sh
+          - bash etc/ci/lockfile_changed.sh
+-         - bash etc/ci/manifest_changed.sh
+       cache:
+         directories:
+           - .cargo
+           - .servo
+           - $HOME/.ccache
+       before_cache:
+         - ./mach clean-nightlies --keep 2 --force
+         - ./mach clean-cargo-cache --keep 2 --force

+ 105 - 0
frg/253-58/mozilla-release58_428212.patch

@@ -0,0 +1,105 @@
+# HG changeset patch
+# User Andrew McCreight <continuation@gmail.com>
+# Date 1503439245 25200
+#      Tue Aug 22 15:00:45 2017 -0700
+# Node ID dbabaeec0fbcd04531881466d983be47f4a0e512
+# Parent  bf49a4faa77d45e941696d2bc04c8f2544093702
+Bug 1392483 - ifdef out mNextIdleDeadline in a few more places. r=froydnj
+
+MozReview-Commit-ID: D9bW4jEHlhl
+
+diff --git a/xpcom/threads/PrioritizedEventQueue.h b/xpcom/threads/PrioritizedEventQueue.h
+--- a/xpcom/threads/PrioritizedEventQueue.h
++++ b/xpcom/threads/PrioritizedEventQueue.h
+@@ -54,20 +54,22 @@ public:
+   size_t Count(const MutexAutoLock& aProofOfLock) const final;
+ 
+   // When checking the idle deadline, we need to drop whatever mutex protects
+   // this queue. This method allows that mutex to be stored so that we can drop
+   // it and reacquire it when checking the idle deadline. The mutex must live at
+   // least as long as the queue.
+   void SetMutexRef(Mutex& aMutex) { mMutex = &aMutex; }
+ 
++#ifndef RELEASE_OR_BETA
+   // nsThread.cpp sends telemetry containing the most recently computed idle
+   // deadline. We store a reference to a field in nsThread where this deadline
+   // will be stored so that it can be fetched quickly for telemetry.
+   void SetNextIdleDeadlineRef(TimeStamp& aDeadline) { mNextIdleDeadline = &aDeadline; }
++#endif
+ 
+   void EnableInputEventPrioritization(const MutexAutoLock& aProofOfLock) final;
+ 
+ private:
+   class EnablePrioritizationRunnable;
+ 
+   // Returns a null TimeStamp if we're not in the idle period.
+   mozilla::TimeStamp GetIdleDeadline();
+@@ -76,19 +78,21 @@ private:
+   UniquePtr<InnerQueueT> mInputQueue;
+   UniquePtr<InnerQueueT> mNormalQueue;
+   UniquePtr<InnerQueueT> mIdleQueue;
+ 
+   // We need to drop the queue mutex when checking the idle deadline, so we keep
+   // a pointer to it here.
+   Mutex* mMutex = nullptr;
+ 
++#ifndef RELEASE_OR_BETA
+   // Pointer to a place where the most recently computed idle deadline is
+   // stored.
+   TimeStamp* mNextIdleDeadline = nullptr;
++#endif
+ 
+   // Try to process one high priority runnable after each normal
+   // priority runnable. This gives the processing model HTML spec has for
+   // 'Update the rendering' in the case only vsync messages are in the
+   // secondary queue and prevents starving the normal queue.
+   bool mProcessHighPriorityQueue = false;
+ 
+   // mIdlePeriod keeps track of the current idle period. If at any
+diff --git a/xpcom/threads/nsThread.h b/xpcom/threads/nsThread.h
+--- a/xpcom/threads/nsThread.h
++++ b/xpcom/threads/nsThread.h
+@@ -100,17 +100,19 @@ public:
+   static const uint32_t kRunnableNameBufSize = 1000;
+   static mozilla::Array<char, kRunnableNameBufSize> sMainThreadRunnableName;
+ 
+   void EnableInputEventPrioritization()
+   {
+     EventQueue()->EnableInputEventPrioritization();
+   }
+ 
++#ifndef RELEASE_OR_BETA
+   mozilla::TimeStamp& NextIdleDeadlineRef() { return mNextIdleDeadline; }
++#endif
+ 
+   mozilla::SynchronizedEventQueue* EventQueue() { return mEvents.get(); }
+ 
+   bool ShuttingDown()
+   {
+     return mShutdownContext != nullptr;
+   }
+ 
+diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp
+--- a/xpcom/threads/nsThreadManager.cpp
++++ b/xpcom/threads/nsThreadManager.cpp
+@@ -112,17 +112,20 @@ nsThreadManager::Init()
+   MainThreadQueueT* prioritizedRef = prioritized.get();
+   RefPtr<ThreadEventQueue<MainThreadQueueT>> queue =
+     new ThreadEventQueue<MainThreadQueueT>(Move(prioritized));
+ 
+   // Setup "main" thread
+   mMainThread = new nsThread(WrapNotNull(queue), nsThread::MAIN_THREAD, 0);
+ 
+   prioritizedRef->SetMutexRef(queue->MutexRef());
++
++#ifndef RELEASE_OR_BETA
+   prioritizedRef->SetNextIdleDeadlineRef(mMainThread->NextIdleDeadlineRef());
++#endif
+ 
+   nsresult rv = mMainThread->InitCurrentThread();
+   if (NS_FAILED(rv)) {
+     mMainThread = nullptr;
+     return rv;
+   }
+ 
+   // We need to keep a pointer to the current thread, so we can satisfy

File diff suppressed because it is too large
+ 35 - 0
frg/253-58/mozilla-release58_428214.patch


File diff suppressed because it is too large
+ 14 - 0
frg/253-58/mozilla-release58_428215.patch


File diff suppressed because it is too large
+ 14 - 0
frg/253-58/mozilla-release58_428216.patch


+ 2432 - 0
frg/253-58/mozilla-release58_428217.patch

@@ -0,0 +1,2432 @@
+# HG changeset patch
+# User Bobby Holley <bobbyholley@gmail.com>
+# Date 1503457474 18000
+#      Tue Aug 22 22:04:34 2017 -0500
+# Node ID 4e53218f68e9f8ba6aed53652f464fd75b3e6631
+# Parent  e16dba457260675669a0e81863849563b31a9ba2
+servo: Merge #18196 - stylo: Maintain a restyle root and use it to cull the traversal (from bholley:restyle_roots); r=emilio
+
+https://bugzilla.mozilla.org/show_bug.cgi?id=1383332
+
+Source-Repo: https://github.com/servo/servo
+Source-Revision: 20c73e7f7d620600f161f3c00cbe5a80b5e2a5a9
+
+diff --git a/servo/components/style/dom.rs b/servo/components/style/dom.rs
+--- a/servo/components/style/dom.rs
++++ b/servo/components/style/dom.rs
+@@ -496,23 +496,30 @@ pub trait TElement : Eq + PartialEq + De
+     }
+ 
+     /// Flag that this element has no descendant for animation-only restyle processing.
+     ///
+     /// Only safe to call with exclusive access to the element.
+     unsafe fn unset_animation_only_dirty_descendants(&self) {
+     }
+ 
+-    /// Clear all bits related to dirty descendant.
++    /// Clear all bits related describing the dirtiness of descendants.
+     ///
+     /// In Gecko, this corresponds to the regular dirty descendants bit, the
+     /// animation-only dirty descendants bit, and the lazy frame construction
+     /// descendants bit.
+     unsafe fn clear_descendants_bits(&self) { self.unset_dirty_descendants(); }
+ 
++    /// Clear all element flags related to dirtiness.
++    ///
++    /// In Gecko, this corresponds to the regular dirty descendants bit, the
++    /// animation-only dirty descendants bit, the lazy frame construction bit,
++    /// and the lazy frame construction descendants bit.
++    unsafe fn clear_dirty_bits(&self) { self.unset_dirty_descendants(); }
++
+     /// Returns true if this element is a visited link.
+     ///
+     /// Servo doesn't support visited styles yet.
+     fn is_visited_link(&self) -> bool { false }
+ 
+     /// Returns true if this element is native anonymous (only Gecko has native
+     /// anonymous content).
+     fn is_native_anonymous(&self) -> bool { false }
+@@ -713,38 +720,16 @@ pub trait TElement : Eq + PartialEq + De
+     /// looking at the element and its ancestors.  (This argument is used
+     /// to implement matching of `:lang()` against snapshots.)
+     fn match_element_lang(&self,
+                           override_lang: Option<Option<AttrValue>>,
+                           value: &PseudoClassStringArg)
+                           -> bool;
+ }
+ 
+-/// Trait abstracting over different kinds of dirty-descendants bits.
+-pub trait DescendantsBit<E: TElement> {
+-    /// Returns true if the Element has the bit.
+-    fn has(el: E) -> bool;
+-    /// Sets the bit on the Element.
+-    unsafe fn set(el: E);
+-}
+-
+-/// Implementation of DescendantsBit for the regular dirty descendants bit.
+-pub struct DirtyDescendants;
+-impl<E: TElement> DescendantsBit<E> for DirtyDescendants {
+-    fn has(el: E) -> bool { el.has_dirty_descendants() }
+-    unsafe fn set(el: E) { el.set_dirty_descendants(); }
+-}
+-
+-/// Implementation of DescendantsBit for the animation-only dirty descendants bit.
+-pub struct AnimationOnlyDirtyDescendants;
+-impl<E: TElement> DescendantsBit<E> for AnimationOnlyDirtyDescendants {
+-    fn has(el: E) -> bool { el.has_animation_only_dirty_descendants() }
+-    unsafe fn set(el: E) { el.set_animation_only_dirty_descendants(); }
+-}
+-
+ /// TNode and TElement aren't Send because we want to be careful and explicit
+ /// about our parallel traversal. However, there are certain situations
+ /// (including but not limited to the traversal) where we need to send DOM
+ /// objects to other threads.
+ ///
+ /// That's the reason why `SendNode` exists.
+ #[derive(Clone, Debug, PartialEq)]
+ pub struct SendNode<N: TNode>(N);
+diff --git a/servo/components/style/gecko/data.rs b/servo/components/style/gecko/data.rs
+--- a/servo/components/style/gecko/data.rs
++++ b/servo/components/style/gecko/data.rs
+@@ -147,17 +147,17 @@ impl PerDocumentStyleData {
+ }
+ 
+ impl PerDocumentStyleDataImpl {
+     /// Recreate the style data if the stylesheets have changed.
+     pub fn flush_stylesheets<E>(
+         &mut self,
+         guard: &SharedRwLockReadGuard,
+         document_element: Option<E>,
+-    )
++    ) -> bool
+     where
+         E: TElement,
+     {
+         self.stylist.flush(
+             &StylesheetGuards::same(guard),
+             /* ua_sheets = */ None,
+             &mut self.extra_style_data,
+             document_element,
+diff --git a/servo/components/style/gecko/generated/bindings.rs b/servo/components/style/gecko/generated/bindings.rs
+--- a/servo/components/style/gecko/generated/bindings.rs
++++ b/servo/components/style/gecko/generated/bindings.rs
+@@ -1912,16 +1912,20 @@ extern "C" {
+ }
+ extern "C" {
+     pub fn Servo_Element_GetPseudoComputedValues(node:
+                                                      RawGeckoElementBorrowed,
+                                                  index: usize)
+      -> ServoStyleContextStrong;
+ }
+ extern "C" {
++    pub fn Servo_Element_IsDisplayNone(element: RawGeckoElementBorrowed)
++     -> bool;
++}
++extern "C" {
+     pub fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
+                                           gecko_stylesheet:
+                                               *mut ServoStyleSheet,
+                                           data: *const nsACString,
+                                           parsing_mode: SheetParsingMode,
+                                           extra_data:
+                                               *mut RawGeckoURLExtraData,
+                                           line_number_offset: u32,
+diff --git a/servo/components/style/gecko/generated/structs_debug.rs b/servo/components/style/gecko/generated/structs_debug.rs
+--- a/servo/components/style/gecko/generated/structs_debug.rs
++++ b/servo/components/style/gecko/generated/structs_debug.rs
+@@ -1042,16 +1042,18 @@ pub mod root {
+         pub struct pair<_T1, _T2> {
+             pub first: _T1,
+             pub second: _T2,
+             pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<_T1>>,
+             pub _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell<_T2>>,
+         }
+         pub type pair_first_type<_T1> = _T1;
+         pub type pair_second_type<_T2> = _T2;
++        pub type pair__PCCP = u8;
++        pub type pair__PCCFP = u8;
+         #[repr(C)]
+         #[derive(Debug, Copy)]
+         pub struct input_iterator_tag {
+             pub _address: u8,
+         }
+         #[test]
+         fn bindgen_test_layout_input_iterator_tag() {
+             assert_eq!(::std::mem::size_of::<input_iterator_tag>() , 1usize ,
+@@ -2627,16 +2629,17 @@ pub mod root {
+                             concat ! (
+                             "Alignment of field: " , stringify ! (
+                             Element_MappedAttributeEntry ) , "::" , stringify
+                             ! ( attribute ) ));
+             }
+             impl Clone for Element_MappedAttributeEntry {
+                 fn clone(&self) -> Self { *self }
+             }
++            pub const Element_kAllServoDescendantBits: u32 = 25296896;
+             pub const Element_kFireMutationEvent: bool = true;
+             pub const Element_kDontFireMutationEvent: bool = false;
+             pub const Element_kNotifyDocumentObservers: bool = true;
+             pub const Element_kDontNotifyDocumentObservers: bool = false;
+             pub const Element_kCallAfterSetAttr: bool = true;
+             pub const Element_kDontCallAfterSetAttr: bool = false;
+             #[test]
+             fn bindgen_test_layout_Element() {
+@@ -4924,17 +4927,17 @@ pub mod root {
+                   root::mozilla::ServoTraversalFlags =
+             4;
+         pub const ServoTraversalFlags_Forgetful:
+                   root::mozilla::ServoTraversalFlags =
+             8;
+         pub const ServoTraversalFlags_AggressivelyForgetful:
+                   root::mozilla::ServoTraversalFlags =
+             16;
+-        pub const ServoTraversalFlags_ClearDirtyDescendants:
++        pub const ServoTraversalFlags_ClearDirtyBits:
+                   root::mozilla::ServoTraversalFlags =
+             32;
+         pub const ServoTraversalFlags_ClearAnimationOnlyDirtyDescendants:
+                   root::mozilla::ServoTraversalFlags =
+             64;
+         pub const ServoTraversalFlags_ParallelTraversal:
+                   root::mozilla::ServoTraversalFlags =
+             128;
+@@ -9503,25 +9506,16 @@ pub mod root {
+                         concat ! (
+                         "Alignment of " , stringify ! ( ServoMediaList ) ));
+             assert_eq! (unsafe {
+                         & ( * ( 0 as * const ServoMediaList ) ) . mRawList as
+                         * const _ as usize } , 56usize , concat ! (
+                         "Alignment of field: " , stringify ! ( ServoMediaList
+                         ) , "::" , stringify ! ( mRawList ) ));
+         }
+-        pub mod dmd {
+-            #[allow(unused_imports)]
+-            use self::super::super::super::root;
+-        }
+-        #[repr(C)]
+-        #[derive(Debug, Copy, Clone)]
+-        pub struct JSONWriteFunc {
+-            _unused: [u8; 0],
+-        }
+         /// A PostTraversalTask is a task to be performed immediately after a Servo
+         /// traversal.  There are just a few tasks we need to perform, so we use this
+         /// class rather than Runnables, to avoid virtual calls and some allocations.
+         ///
+         /// A PostTraversalTask is only safe to run immediately after the Servo
+         /// traversal, since it can hold raw pointers to DOM objects.
+         #[repr(C)]
+         #[derive(Debug, Copy)]
+@@ -10063,18 +10057,16 @@ pub mod root {
+         NS_ERROR_PHISHING_URI = 2153578527,
+         NS_ERROR_TRACKING_URI = 2153578530,
+         NS_ERROR_UNWANTED_URI = 2153578531,
+         NS_ERROR_BLOCKED_URI = 2153578533,
+         NS_ERROR_HARMFUL_URI = 2153578534,
+         NS_ERROR_SAVE_LINK_AS_TIMEOUT = 2153578528,
+         NS_ERROR_PARSED_DATA_CACHED = 2153578529,
+         NS_REFRESHURI_HEADER_FOUND = 6094850,
+-        NS_ERROR_IMAGE_SRC_CHANGED = 2153644036,
+-        NS_ERROR_IMAGE_BLOCKED = 2153644037,
+         NS_ERROR_CONTENT_BLOCKED = 2153644038,
+         NS_ERROR_CONTENT_BLOCKED_SHOW_ALT = 2153644039,
+         NS_PROPTABLE_PROP_NOT_THERE = 2153644042,
+         NS_ERROR_XBL_BLOCKED = 2153644047,
+         NS_ERROR_CONTENT_CRASHED = 2153644048,
+         NS_HTML_STYLE_PROPERTY_NOT_THERE = 6160386,
+         NS_CONTENT_BLOCKED = 6160392,
+         NS_CONTENT_BLOCKED_SHOW_ALT = 6160393,
+@@ -17059,16 +17051,18 @@ pub mod root {
+         pub mChildDocumentUseCounters: [u64; 2usize],
+         pub mNotifiedPageForUseCounter: [u64; 2usize],
+         pub mIncCounters: u16,
+         pub mUserHasInteracted: bool,
+         pub mPageUnloadingEventTimeStamp: root::mozilla::TimeStamp,
+         pub mDocGroup: root::RefPtr<root::mozilla::dom::DocGroup>,
+         pub mTrackingScripts: [u64; 6usize],
+         pub mBufferedCSPViolations: root::nsTArray<root::nsCOMPtr<root::nsIRunnable>>,
++        pub mServoRestyleRoot: root::nsCOMPtr<root::nsINode>,
++        pub mServoRestyleRootDirtyBits: u32,
+     }
+     pub type nsIDocument_GlobalObject = root::mozilla::dom::GlobalObject;
+     pub type nsIDocument_Encoding = root::mozilla::Encoding;
+     pub type nsIDocument_NotNull<T> = root::mozilla::NotNull<T>;
+     pub use self::super::root::mozilla::net::ReferrerPolicy as
+             nsIDocument_ReferrerPolicyEnum;
+     pub type nsIDocument_Element = root::mozilla::dom::Element;
+     pub type nsIDocument_FullscreenRequest =
+@@ -17353,17 +17347,17 @@ pub mod root {
+     #[repr(C)]
+     #[derive(Debug, Copy, Clone)]
+     pub struct nsIDocument_FrameRequest {
+         _unused: [u8; 0],
+     }
+     pub const nsIDocument_kSegmentSize: usize = 128;
+     #[test]
+     fn bindgen_test_layout_nsIDocument() {
+-        assert_eq!(::std::mem::size_of::<nsIDocument>() , 888usize , concat !
++        assert_eq!(::std::mem::size_of::<nsIDocument>() , 904usize , concat !
+                    ( "Size of: " , stringify ! ( nsIDocument ) ));
+         assert_eq! (::std::mem::align_of::<nsIDocument>() , 8usize , concat !
+                     ( "Alignment of " , stringify ! ( nsIDocument ) ));
+     }
+     impl nsIDocument {
+         #[inline]
+         pub fn mBidiEnabled(&self) -> bool {
+             let mut unit_field_val: u64 =
+@@ -25208,67 +25202,67 @@ pub mod root {
+     pub struct nsDOMMutationObserver {
+         _unused: [u8; 0],
+     }
+     #[repr(C)]
+     #[derive(Debug, Copy, Clone)]
+     pub struct nsRange {
+         _unused: [u8; 0],
+     }
+-    pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_LISTENERMANAGER;
+-    pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_PROPERTIES;
+-    pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_ANONYMOUS_ROOT;
+-    pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
+-    pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_NATIVE_ANONYMOUS_ROOT;
+-    pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_FORCE_XBL_BINDINGS;
+-    pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_MAY_BE_IN_BINDING_MNGR;
+-    pub const NODE_IS_EDITABLE: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_EDITABLE;
+-    pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_NATIVE_ANONYMOUS;
+-    pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_IN_SHADOW_TREE;
+-    pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_EMPTY_SELECTOR;
+-    pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_SLOW_SELECTOR;
+-    pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_EDGE_CHILD_SELECTOR;
+-    pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
+-    pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_ALL_SELECTOR_FLAGS;
+-    pub const NODE_NEEDS_FRAME: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_NEEDS_FRAME;
+-    pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_DESCENDANTS_NEED_FRAMES;
+-    pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_ACCESSKEY;
+-    pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_DIRECTION_RTL;
+-    pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_DIRECTION_LTR;
+-    pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_ALL_DIRECTION_FLAGS;
+-    pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_CHROME_ONLY_ACCESS;
+-    pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
+-    pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_TYPE_SPECIFIC_BITS_OFFSET;
+-    #[repr(u32)]
+-    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+-    pub enum _bindgen_ty_83 {
++    pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_LISTENERMANAGER;
++    pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_PROPERTIES;
++    pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_ANONYMOUS_ROOT;
++    pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
++    pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_NATIVE_ANONYMOUS_ROOT;
++    pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_FORCE_XBL_BINDINGS;
++    pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_MAY_BE_IN_BINDING_MNGR;
++    pub const NODE_IS_EDITABLE: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_EDITABLE;
++    pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_NATIVE_ANONYMOUS;
++    pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_IN_SHADOW_TREE;
++    pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_EMPTY_SELECTOR;
++    pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_SLOW_SELECTOR;
++    pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_EDGE_CHILD_SELECTOR;
++    pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
++    pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_ALL_SELECTOR_FLAGS;
++    pub const NODE_NEEDS_FRAME: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_NEEDS_FRAME;
++    pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_DESCENDANTS_NEED_FRAMES;
++    pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_ACCESSKEY;
++    pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_DIRECTION_RTL;
++    pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_DIRECTION_LTR;
++    pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_ALL_DIRECTION_FLAGS;
++    pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_CHROME_ONLY_ACCESS;
++    pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
++    pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_TYPE_SPECIFIC_BITS_OFFSET;
++    #[repr(u32)]
++    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
++    pub enum _bindgen_ty_72 {
+         NODE_HAS_LISTENERMANAGER = 4,
+         NODE_HAS_PROPERTIES = 8,
+         NODE_IS_ANONYMOUS_ROOT = 16,
+         NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE = 32,
+         NODE_IS_NATIVE_ANONYMOUS_ROOT = 64,
+         NODE_FORCE_XBL_BINDINGS = 128,
+         NODE_MAY_BE_IN_BINDING_MNGR = 256,
+         NODE_IS_EDITABLE = 512,
+@@ -32836,56 +32830,56 @@ pub mod root {
+     }
+     #[test]
+     fn bindgen_test_layout_nsISMILAttr() {
+         assert_eq!(::std::mem::size_of::<nsISMILAttr>() , 8usize , concat ! (
+                    "Size of: " , stringify ! ( nsISMILAttr ) ));
+         assert_eq! (::std::mem::align_of::<nsISMILAttr>() , 8usize , concat !
+                     ( "Alignment of " , stringify ! ( nsISMILAttr ) ));
+     }
+-    pub const ELEMENT_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_1;
+-    pub const ELEMENT_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_2;
+-    pub const ELEMENT_SHARED_RESTYLE_BIT_3: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_3;
+-    pub const ELEMENT_SHARED_RESTYLE_BIT_4: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_4;
+-    pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_1;
++    pub const ELEMENT_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_1;
++    pub const ELEMENT_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_2;
++    pub const ELEMENT_SHARED_RESTYLE_BIT_3: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_3;
++    pub const ELEMENT_SHARED_RESTYLE_BIT_4: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_4;
++    pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_1;
+     pub const ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO:
+-              root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_2;
+-    pub const ELEMENT_HAS_SNAPSHOT: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_3;
+-    pub const ELEMENT_HANDLED_SNAPSHOT: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_4;
+-    pub const ELEMENT_HAS_PENDING_RESTYLE: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_1;
+-    pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_2;
+-    pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE: root::_bindgen_ty_85
+-              =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_3;
++              root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_2;
++    pub const ELEMENT_HAS_SNAPSHOT: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_3;
++    pub const ELEMENT_HANDLED_SNAPSHOT: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_4;
++    pub const ELEMENT_HAS_PENDING_RESTYLE: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_1;
++    pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_2;
++    pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE: root::_bindgen_ty_74
++              =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_3;
+     pub const ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT:
+-              root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_4;
+-    pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR;
+-    pub const ELEMENT_PENDING_RESTYLE_FLAGS: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_PENDING_RESTYLE_FLAGS;
+-    pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS;
+-    pub const ELEMENT_ALL_RESTYLE_FLAGS: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_ALL_RESTYLE_FLAGS;
+-    pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_TYPE_SPECIFIC_BITS_OFFSET;
+-    #[repr(u32)]
+-    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+-    pub enum _bindgen_ty_85 {
++              root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_4;
++    pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR;
++    pub const ELEMENT_PENDING_RESTYLE_FLAGS: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_PENDING_RESTYLE_FLAGS;
++    pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS;
++    pub const ELEMENT_ALL_RESTYLE_FLAGS: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_ALL_RESTYLE_FLAGS;
++    pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_TYPE_SPECIFIC_BITS_OFFSET;
++    #[repr(u32)]
++    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
++    pub enum _bindgen_ty_74 {
+         ELEMENT_SHARED_RESTYLE_BIT_1 = 8388608,
+         ELEMENT_SHARED_RESTYLE_BIT_2 = 16777216,
+         ELEMENT_SHARED_RESTYLE_BIT_3 = 33554432,
+         ELEMENT_SHARED_RESTYLE_BIT_4 = 67108864,
+         ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR = 134217728,
+         ELEMENT_PENDING_RESTYLE_FLAGS = 41943040,
+         ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS = 83886080,
+         ELEMENT_ALL_RESTYLE_FLAGS = 260046848,
+@@ -33751,17 +33745,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::gfx::FontVariation>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_228788_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_203496_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsCSSSelector>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsCSSSelector> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsCSSSelector>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsCSSSelector> ) ));
+@@ -34107,17 +34101,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::binding_danger::TErrorResult ) ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::binding_danger::TErrorResult>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::mozilla::binding_danger::TErrorResult ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_230622_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_205330_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -34268,17 +34262,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::DeletePolicy ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::DeletePolicy>() , 1usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::DeletePolicy ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_iterator_open0_input_iterator_tag_UniquePtr_open1_JSErrorNotes_Note_DeletePolicy_open2_JSErrorNotes_Note_close2_close1_long__bindgen_ty_id_236242__bindgen_ty_id_236249_close0_instantiation() {
++    fn __bindgen_test_layout_iterator_open0_input_iterator_tag_UniquePtr_open1_JSErrorNotes_Note_DeletePolicy_open2_JSErrorNotes_Note_close2_close1_long__bindgen_ty_id_210954__bindgen_ty_id_210961_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::std::iterator>() , 1usize ,
+                    concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::std::iterator ) ));
+         assert_eq!(::std::mem::align_of::<root::std::iterator>() , 1usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::std::iterator ) ));
+@@ -34516,17 +34510,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_238741_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_213453_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -34584,17 +34578,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIObserver> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr<root::nsIObserver>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIObserver> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239043_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_213755_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -34696,17 +34690,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::URLExtraData> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::URLExtraData>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::URLExtraData> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_NotNull_open0__bindgen_ty_id_239588_close0_instantiation() {
++    fn __bindgen_test_layout_NotNull_open0__bindgen_ty_id_214304_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::mozilla::NotNull<*const root::mozilla::Encoding>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::NotNull<*const root::mozilla::Encoding> )
+                    ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::NotNull<*const root::mozilla::Encoding>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+@@ -35043,16 +35037,27 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIRunnable> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr<root::nsIRunnable>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIRunnable> ) ));
+     }
+     #[test]
++    fn __bindgen_test_layout_nsCOMPtr_open0_nsINode_close0_instantiation() {
++        assert_eq!(::std::mem::size_of::<root::nsCOMPtr<root::nsINode>>() ,
++                   8usize , concat ! (
++                   "Size of template specialization: " , stringify ! (
++                   root::nsCOMPtr<root::nsINode> ) ));
++        assert_eq!(::std::mem::align_of::<root::nsCOMPtr<root::nsINode>>() ,
++                   8usize , concat ! (
++                   "Alignment of template specialization: " , stringify ! (
++                   root::nsCOMPtr<root::nsINode> ) ));
++    }
++    #[test]
+     fn __bindgen_test_layout_RefPtr_open0_CSSRuleListImpl_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::RefPtr<root::CSSRuleListImpl>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::CSSRuleListImpl> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::CSSRuleListImpl>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+@@ -35100,17 +35105,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_240009_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_214728_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -35190,17 +35195,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::RefPtr<root::mozilla::ServoStyleSheet>>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::RefPtr<root::mozilla::ServoStyleSheet>>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_240409_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_215128_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -35291,17 +35296,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<::nsstring::nsStringRepr> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<::nsstring::nsStringRepr>>() ,
+                    8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<::nsstring::nsStringRepr> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241380_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_216101_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -35380,28 +35385,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsCSSFontFaceRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::nsCSSFontFaceRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsCSSFontFaceRule> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241685_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_216406_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241690_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_216411_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -35448,17 +35453,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::CSSStyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::CSSStyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::CSSStyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_242181_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_216902_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -36096,17 +36101,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIWeakReference> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr<root::nsIWeakReference>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIWeakReference> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_245037_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_219758_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut ::std::os::raw::c_void>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut ::std::os::raw::c_void> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut ::std::os::raw::c_void>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut ::std::os::raw::c_void> ) ));
+@@ -36175,17 +36180,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::DefaultDelete ) ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::DefaultDelete>() ,
+                    1usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::mozilla::DefaultDelete ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_251322_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_226043_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::AudioContext>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::AudioContext> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::AudioContext>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::AudioContext> ) ));
+@@ -36208,28 +36213,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::CallbackObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::CallbackObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::CallbackObject> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_252491_close0_instantiation() {
++    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_227212_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_252495_close0_instantiation() {
++    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_227216_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+@@ -36241,17 +36246,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIGlobalObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr<root::nsIGlobalObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIGlobalObject> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_TenuredHeap_open0__bindgen_ty_id_252502_close0_instantiation() {
++    fn __bindgen_test_layout_TenuredHeap_open0__bindgen_ty_id_227223_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::TenuredHeap>() , 8usize ,
+                    concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::TenuredHeap ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::TenuredHeap>() , 8usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::TenuredHeap ) ));
+@@ -36320,17 +36325,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::CycleCollectedJSContext_RunInMetastableStateData>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::CycleCollectedJSContext_RunInMetastableStateData>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_253607_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_228396_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+@@ -36515,17 +36520,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<f64> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<f64>>() , 8usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<f64> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_255055_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_229844_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -36620,17 +36625,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsRefPtrHashKey<root::nsIAtom> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsRefPtrHashKey<root::nsIAtom>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsRefPtrHashKey<root::nsIAtom> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_257463_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_232252_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::CounterStyle>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::CounterStyle> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::CounterStyle>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::CounterStyle> ) ));
+@@ -37321,17 +37326,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsStyleImageRequest> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::nsStyleImageRequest>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsStyleImageRequest> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_260021_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_234810_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+@@ -37558,28 +37563,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIURI> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr<root::nsIURI>>() ,
+                    8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr<root::nsIURI> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267833_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_242622_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267838_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_242627_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37657,17 +37662,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::ShadowRoot> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::ShadowRoot>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::ShadowRoot> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267951_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_242740_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37944,17 +37949,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsAutoPtr<root::mozilla::dom::ExplicitChildIterator>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsAutoPtr<root::mozilla::dom::ExplicitChildIterator>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269537_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_244326_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37966,28 +37971,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::Element> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269699_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_244488_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269704_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_244493_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -38109,28 +38114,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::gfx::FontVariation>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_272231_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_246732_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_272239_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_246740_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+diff --git a/servo/components/style/gecko/generated/structs_release.rs b/servo/components/style/gecko/generated/structs_release.rs
+--- a/servo/components/style/gecko/generated/structs_release.rs
++++ b/servo/components/style/gecko/generated/structs_release.rs
+@@ -1042,16 +1042,18 @@ pub mod root {
+         pub struct pair<_T1, _T2> {
+             pub first: _T1,
+             pub second: _T2,
+             pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<_T1>>,
+             pub _phantom_1: ::std::marker::PhantomData<::std::cell::UnsafeCell<_T2>>,
+         }
+         pub type pair_first_type<_T1> = _T1;
+         pub type pair_second_type<_T2> = _T2;
++        pub type pair__PCCP = u8;
++        pub type pair__PCCFP = u8;
+         #[repr(C)]
+         #[derive(Debug, Copy)]
+         pub struct input_iterator_tag {
+             pub _address: u8,
+         }
+         #[test]
+         fn bindgen_test_layout_input_iterator_tag() {
+             assert_eq!(::std::mem::size_of::<input_iterator_tag>() , 1usize ,
+@@ -2549,16 +2551,17 @@ pub mod root {
+                             concat ! (
+                             "Alignment of field: " , stringify ! (
+                             Element_MappedAttributeEntry ) , "::" , stringify
+                             ! ( attribute ) ));
+             }
+             impl Clone for Element_MappedAttributeEntry {
+                 fn clone(&self) -> Self { *self }
+             }
++            pub const Element_kAllServoDescendantBits: u32 = 25296896;
+             pub const Element_kFireMutationEvent: bool = true;
+             pub const Element_kDontFireMutationEvent: bool = false;
+             pub const Element_kNotifyDocumentObservers: bool = true;
+             pub const Element_kDontNotifyDocumentObservers: bool = false;
+             pub const Element_kCallAfterSetAttr: bool = true;
+             pub const Element_kDontCallAfterSetAttr: bool = false;
+             #[test]
+             fn bindgen_test_layout_Element() {
+@@ -4812,17 +4815,17 @@ pub mod root {
+                   root::mozilla::ServoTraversalFlags =
+             4;
+         pub const ServoTraversalFlags_Forgetful:
+                   root::mozilla::ServoTraversalFlags =
+             8;
+         pub const ServoTraversalFlags_AggressivelyForgetful:
+                   root::mozilla::ServoTraversalFlags =
+             16;
+-        pub const ServoTraversalFlags_ClearDirtyDescendants:
++        pub const ServoTraversalFlags_ClearDirtyBits:
+                   root::mozilla::ServoTraversalFlags =
+             32;
+         pub const ServoTraversalFlags_ClearAnimationOnlyDirtyDescendants:
+                   root::mozilla::ServoTraversalFlags =
+             64;
+         pub const ServoTraversalFlags_ParallelTraversal:
+                   root::mozilla::ServoTraversalFlags =
+             128;
+@@ -9349,25 +9352,16 @@ pub mod root {
+                         concat ! (
+                         "Alignment of " , stringify ! ( ServoMediaList ) ));
+             assert_eq! (unsafe {
+                         & ( * ( 0 as * const ServoMediaList ) ) . mRawList as
+                         * const _ as usize } , 48usize , concat ! (
+                         "Alignment of field: " , stringify ! ( ServoMediaList
+                         ) , "::" , stringify ! ( mRawList ) ));
+         }
+-        pub mod dmd {
+-            #[allow(unused_imports)]
+-            use self::super::super::super::root;
+-        }
+-        #[repr(C)]
+-        #[derive(Debug, Copy, Clone)]
+-        pub struct JSONWriteFunc {
+-            _unused: [u8; 0],
+-        }
+         /// A PostTraversalTask is a task to be performed immediately after a Servo
+         /// traversal.  There are just a few tasks we need to perform, so we use this
+         /// class rather than Runnables, to avoid virtual calls and some allocations.
+         ///
+         /// A PostTraversalTask is only safe to run immediately after the Servo
+         /// traversal, since it can hold raw pointers to DOM objects.
+         #[repr(C)]
+         #[derive(Debug, Copy)]
+@@ -9909,18 +9903,16 @@ pub mod root {
+         NS_ERROR_PHISHING_URI = 2153578527,
+         NS_ERROR_TRACKING_URI = 2153578530,
+         NS_ERROR_UNWANTED_URI = 2153578531,
+         NS_ERROR_BLOCKED_URI = 2153578533,
+         NS_ERROR_HARMFUL_URI = 2153578534,
+         NS_ERROR_SAVE_LINK_AS_TIMEOUT = 2153578528,
+         NS_ERROR_PARSED_DATA_CACHED = 2153578529,
+         NS_REFRESHURI_HEADER_FOUND = 6094850,
+-        NS_ERROR_IMAGE_SRC_CHANGED = 2153644036,
+-        NS_ERROR_IMAGE_BLOCKED = 2153644037,
+         NS_ERROR_CONTENT_BLOCKED = 2153644038,
+         NS_ERROR_CONTENT_BLOCKED_SHOW_ALT = 2153644039,
+         NS_PROPTABLE_PROP_NOT_THERE = 2153644042,
+         NS_ERROR_XBL_BLOCKED = 2153644047,
+         NS_ERROR_CONTENT_CRASHED = 2153644048,
+         NS_HTML_STYLE_PROPERTY_NOT_THERE = 6160386,
+         NS_CONTENT_BLOCKED = 6160392,
+         NS_CONTENT_BLOCKED_SHOW_ALT = 6160393,
+@@ -16825,16 +16817,18 @@ pub mod root {
+         pub mChildDocumentUseCounters: [u64; 2usize],
+         pub mNotifiedPageForUseCounter: [u64; 2usize],
+         pub mIncCounters: u16,
+         pub mUserHasInteracted: bool,
+         pub mPageUnloadingEventTimeStamp: root::mozilla::TimeStamp,
+         pub mDocGroup: root::RefPtr<root::mozilla::dom::DocGroup>,
+         pub mTrackingScripts: [u64; 5usize],
+         pub mBufferedCSPViolations: root::nsTArray<root::nsCOMPtr>,
++        pub mServoRestyleRoot: root::nsCOMPtr,
++        pub mServoRestyleRootDirtyBits: u32,
+     }
+     pub type nsIDocument_GlobalObject = root::mozilla::dom::GlobalObject;
+     pub type nsIDocument_Encoding = root::mozilla::Encoding;
+     pub type nsIDocument_NotNull<T> = root::mozilla::NotNull<T>;
+     pub use self::super::root::mozilla::net::ReferrerPolicy as
+             nsIDocument_ReferrerPolicyEnum;
+     pub type nsIDocument_Element = root::mozilla::dom::Element;
+     pub type nsIDocument_FullscreenRequest =
+@@ -17119,17 +17113,17 @@ pub mod root {
+     #[repr(C)]
+     #[derive(Debug, Copy, Clone)]
+     pub struct nsIDocument_FrameRequest {
+         _unused: [u8; 0],
+     }
+     pub const nsIDocument_kSegmentSize: usize = 128;
+     #[test]
+     fn bindgen_test_layout_nsIDocument() {
+-        assert_eq!(::std::mem::size_of::<nsIDocument>() , 864usize , concat !
++        assert_eq!(::std::mem::size_of::<nsIDocument>() , 880usize , concat !
+                    ( "Size of: " , stringify ! ( nsIDocument ) ));
+         assert_eq! (::std::mem::align_of::<nsIDocument>() , 8usize , concat !
+                     ( "Alignment of " , stringify ! ( nsIDocument ) ));
+     }
+     impl nsIDocument {
+         #[inline]
+         pub fn mBidiEnabled(&self) -> bool {
+             let mut unit_field_val: u64 =
+@@ -24812,67 +24806,67 @@ pub mod root {
+     pub struct nsDOMMutationObserver {
+         _unused: [u8; 0],
+     }
+     #[repr(C)]
+     #[derive(Debug, Copy, Clone)]
+     pub struct nsRange {
+         _unused: [u8; 0],
+     }
+-    pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_LISTENERMANAGER;
+-    pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_PROPERTIES;
+-    pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_ANONYMOUS_ROOT;
+-    pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
+-    pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_NATIVE_ANONYMOUS_ROOT;
+-    pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_FORCE_XBL_BINDINGS;
+-    pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_MAY_BE_IN_BINDING_MNGR;
+-    pub const NODE_IS_EDITABLE: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_EDITABLE;
+-    pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_NATIVE_ANONYMOUS;
+-    pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_IN_SHADOW_TREE;
+-    pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_EMPTY_SELECTOR;
+-    pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_SLOW_SELECTOR;
+-    pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_EDGE_CHILD_SELECTOR;
+-    pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
+-    pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_ALL_SELECTOR_FLAGS;
+-    pub const NODE_NEEDS_FRAME: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_NEEDS_FRAME;
+-    pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_DESCENDANTS_NEED_FRAMES;
+-    pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_ACCESSKEY;
+-    pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_DIRECTION_RTL;
+-    pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_HAS_DIRECTION_LTR;
+-    pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_ALL_DIRECTION_FLAGS;
+-    pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_CHROME_ONLY_ACCESS;
+-    pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
+-    pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_83 =
+-        _bindgen_ty_83::NODE_TYPE_SPECIFIC_BITS_OFFSET;
+-    #[repr(u32)]
+-    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+-    pub enum _bindgen_ty_83 {
++    pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_LISTENERMANAGER;
++    pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_PROPERTIES;
++    pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_ANONYMOUS_ROOT;
++    pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
++    pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_NATIVE_ANONYMOUS_ROOT;
++    pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_FORCE_XBL_BINDINGS;
++    pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_MAY_BE_IN_BINDING_MNGR;
++    pub const NODE_IS_EDITABLE: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_EDITABLE;
++    pub const NODE_IS_NATIVE_ANONYMOUS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_NATIVE_ANONYMOUS;
++    pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_IN_SHADOW_TREE;
++    pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_EMPTY_SELECTOR;
++    pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_SLOW_SELECTOR;
++    pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_EDGE_CHILD_SELECTOR;
++    pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
++    pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_ALL_SELECTOR_FLAGS;
++    pub const NODE_NEEDS_FRAME: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_NEEDS_FRAME;
++    pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_DESCENDANTS_NEED_FRAMES;
++    pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_ACCESSKEY;
++    pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_DIRECTION_RTL;
++    pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_HAS_DIRECTION_LTR;
++    pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_ALL_DIRECTION_FLAGS;
++    pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_CHROME_ONLY_ACCESS;
++    pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
++    pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_72 =
++        _bindgen_ty_72::NODE_TYPE_SPECIFIC_BITS_OFFSET;
++    #[repr(u32)]
++    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
++    pub enum _bindgen_ty_72 {
+         NODE_HAS_LISTENERMANAGER = 4,
+         NODE_HAS_PROPERTIES = 8,
+         NODE_IS_ANONYMOUS_ROOT = 16,
+         NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE = 32,
+         NODE_IS_NATIVE_ANONYMOUS_ROOT = 64,
+         NODE_FORCE_XBL_BINDINGS = 128,
+         NODE_MAY_BE_IN_BINDING_MNGR = 256,
+         NODE_IS_EDITABLE = 512,
+@@ -32344,56 +32338,56 @@ pub mod root {
+     }
+     #[test]
+     fn bindgen_test_layout_nsISMILAttr() {
+         assert_eq!(::std::mem::size_of::<nsISMILAttr>() , 8usize , concat ! (
+                    "Size of: " , stringify ! ( nsISMILAttr ) ));
+         assert_eq! (::std::mem::align_of::<nsISMILAttr>() , 8usize , concat !
+                     ( "Alignment of " , stringify ! ( nsISMILAttr ) ));
+     }
+-    pub const ELEMENT_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_1;
+-    pub const ELEMENT_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_2;
+-    pub const ELEMENT_SHARED_RESTYLE_BIT_3: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_3;
+-    pub const ELEMENT_SHARED_RESTYLE_BIT_4: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_4;
+-    pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_1;
++    pub const ELEMENT_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_1;
++    pub const ELEMENT_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_2;
++    pub const ELEMENT_SHARED_RESTYLE_BIT_3: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_3;
++    pub const ELEMENT_SHARED_RESTYLE_BIT_4: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_4;
++    pub const ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_1;
+     pub const ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO:
+-              root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_2;
+-    pub const ELEMENT_HAS_SNAPSHOT: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_3;
+-    pub const ELEMENT_HANDLED_SNAPSHOT: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_4;
+-    pub const ELEMENT_HAS_PENDING_RESTYLE: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_1;
+-    pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_2;
+-    pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE: root::_bindgen_ty_85
+-              =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_3;
++              root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_2;
++    pub const ELEMENT_HAS_SNAPSHOT: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_3;
++    pub const ELEMENT_HANDLED_SNAPSHOT: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_4;
++    pub const ELEMENT_HAS_PENDING_RESTYLE: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_1;
++    pub const ELEMENT_IS_POTENTIAL_RESTYLE_ROOT: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_2;
++    pub const ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE: root::_bindgen_ty_74
++              =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_3;
+     pub const ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT:
+-              root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_SHARED_RESTYLE_BIT_4;
+-    pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR;
+-    pub const ELEMENT_PENDING_RESTYLE_FLAGS: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_PENDING_RESTYLE_FLAGS;
+-    pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS;
+-    pub const ELEMENT_ALL_RESTYLE_FLAGS: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_ALL_RESTYLE_FLAGS;
+-    pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_85 =
+-        _bindgen_ty_85::ELEMENT_TYPE_SPECIFIC_BITS_OFFSET;
+-    #[repr(u32)]
+-    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+-    pub enum _bindgen_ty_85 {
++              root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_SHARED_RESTYLE_BIT_4;
++    pub const ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR;
++    pub const ELEMENT_PENDING_RESTYLE_FLAGS: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_PENDING_RESTYLE_FLAGS;
++    pub const ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS;
++    pub const ELEMENT_ALL_RESTYLE_FLAGS: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_ALL_RESTYLE_FLAGS;
++    pub const ELEMENT_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_74 =
++        _bindgen_ty_74::ELEMENT_TYPE_SPECIFIC_BITS_OFFSET;
++    #[repr(u32)]
++    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
++    pub enum _bindgen_ty_74 {
+         ELEMENT_SHARED_RESTYLE_BIT_1 = 8388608,
+         ELEMENT_SHARED_RESTYLE_BIT_2 = 16777216,
+         ELEMENT_SHARED_RESTYLE_BIT_3 = 33554432,
+         ELEMENT_SHARED_RESTYLE_BIT_4 = 67108864,
+         ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR = 134217728,
+         ELEMENT_PENDING_RESTYLE_FLAGS = 41943040,
+         ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS = 83886080,
+         ELEMENT_ALL_RESTYLE_FLAGS = 260046848,
+@@ -33259,17 +33253,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::gfx::FontVariation>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_226420_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_201132_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsCSSSelector>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsCSSSelector> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsCSSSelector>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsCSSSelector> ) ));
+@@ -33615,17 +33609,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::binding_danger::TErrorResult ) ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::binding_danger::TErrorResult>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::mozilla::binding_danger::TErrorResult ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_228220_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_202932_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -33776,17 +33770,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::DeletePolicy ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::DeletePolicy>() , 1usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::DeletePolicy ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_iterator_open0_input_iterator_tag_UniquePtr_open1_JSErrorNotes_Note_DeletePolicy_open2_JSErrorNotes_Note_close2_close1_long__bindgen_ty_id_233812__bindgen_ty_id_233819_close0_instantiation() {
++    fn __bindgen_test_layout_iterator_open0_input_iterator_tag_UniquePtr_open1_JSErrorNotes_Note_DeletePolicy_open2_JSErrorNotes_Note_close2_close1_long__bindgen_ty_id_208528__bindgen_ty_id_208535_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::std::iterator>() , 1usize ,
+                    concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::std::iterator ) ));
+         assert_eq!(::std::mem::align_of::<root::std::iterator>() , 1usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::std::iterator ) ));
+@@ -34024,17 +34018,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_236309_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_211025_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -34092,17 +34086,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr>() , 8usize , concat
+                    ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_236611_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_211327_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -34204,17 +34198,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::URLExtraData> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::URLExtraData>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::URLExtraData> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_NotNull_open0__bindgen_ty_id_237156_close0_instantiation() {
++    fn __bindgen_test_layout_NotNull_open0__bindgen_ty_id_211876_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::mozilla::NotNull<*const root::mozilla::Encoding>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::NotNull<*const root::mozilla::Encoding> )
+                    ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::NotNull<*const root::mozilla::Encoding>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+@@ -34549,16 +34543,27 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr>() , 8usize , concat
+                    ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+     }
+     #[test]
++    fn __bindgen_test_layout_nsCOMPtr_open0_nsINode_close0_instantiation() {
++        assert_eq!(::std::mem::size_of::<root::nsCOMPtr>() , 8usize , concat !
++                   (
++                   "Size of template specialization: " , stringify ! (
++                   root::nsCOMPtr ) ));
++        assert_eq!(::std::mem::align_of::<root::nsCOMPtr>() , 8usize , concat
++                   ! (
++                   "Alignment of template specialization: " , stringify ! (
++                   root::nsCOMPtr ) ));
++    }
++    #[test]
+     fn __bindgen_test_layout_RefPtr_open0_CSSRuleListImpl_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::RefPtr<root::CSSRuleListImpl>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::CSSRuleListImpl> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::CSSRuleListImpl>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+@@ -34606,17 +34611,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::StyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_237575_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_212298_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -34696,17 +34701,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::RefPtr<root::mozilla::ServoStyleSheet>>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::RefPtr<root::mozilla::ServoStyleSheet>>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_237973_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_212696_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -34797,17 +34802,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<::nsstring::nsStringRepr> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<::nsstring::nsStringRepr>>() ,
+                    8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<::nsstring::nsStringRepr> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_238934_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_213659_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -34886,28 +34891,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsCSSFontFaceRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::nsCSSFontFaceRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsCSSFontFaceRule> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239237_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_213962_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239242_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_213967_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -34954,17 +34959,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::CSSStyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::CSSStyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::CSSStyleSheet> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_239717_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_214442_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::StyleSheet>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::StyleSheet> ) ));
+@@ -35589,17 +35594,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr>() , 8usize , concat
+                    ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_242543_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_217268_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut ::std::os::raw::c_void>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut ::std::os::raw::c_void> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut ::std::os::raw::c_void>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut ::std::os::raw::c_void> ) ));
+@@ -35668,17 +35673,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::mozilla::DefaultDelete ) ));
+         assert_eq!(::std::mem::align_of::<root::mozilla::DefaultDelete>() ,
+                    1usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::mozilla::DefaultDelete ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_248811_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_223536_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::AudioContext>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::AudioContext> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::AudioContext>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::AudioContext> ) ));
+@@ -35701,28 +35706,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::CallbackObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::CallbackObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::CallbackObject> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_249980_close0_instantiation() {
++    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_224705_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_249984_close0_instantiation() {
++    fn __bindgen_test_layout_Heap_open0__bindgen_ty_id_224709_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::Heap<*mut root::JSObject>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::Heap<*mut root::JSObject> ) ));
+@@ -35734,17 +35739,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr>() , 8usize , concat
+                    ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_TenuredHeap_open0__bindgen_ty_id_249991_close0_instantiation() {
++    fn __bindgen_test_layout_TenuredHeap_open0__bindgen_ty_id_224716_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::JS::TenuredHeap>() , 8usize ,
+                    concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::JS::TenuredHeap ) ));
+         assert_eq!(::std::mem::align_of::<root::JS::TenuredHeap>() , 8usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::JS::TenuredHeap ) ));
+@@ -35813,17 +35818,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::CycleCollectedJSContext_RunInMetastableStateData>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::CycleCollectedJSContext_RunInMetastableStateData>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_251096_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_225889_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+@@ -36008,17 +36013,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<f64> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<f64>>() , 8usize ,
+                    concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<f64> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_252544_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_227337_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::dom::Element> ) ));
+@@ -36113,17 +36118,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsRefPtrHashKey<root::nsIAtom> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsRefPtrHashKey<root::nsIAtom>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsRefPtrHashKey<root::nsIAtom> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_254917_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_229710_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::CounterStyle>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::CounterStyle> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::CounterStyle>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::CounterStyle> ) ));
+@@ -36814,17 +36819,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsStyleImageRequest> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::nsStyleImageRequest>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::nsStyleImageRequest> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_257399_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_232192_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsISupports>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsISupports> ) ));
+@@ -37051,28 +37056,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+         assert_eq!(::std::mem::align_of::<root::nsCOMPtr>() , 8usize , concat
+                    ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsCOMPtr ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_265211_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_240004_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_265216_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_240009_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37150,17 +37155,17 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::ShadowRoot> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::ShadowRoot>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::ShadowRoot> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_265329_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_240122_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37437,17 +37442,17 @@ pub mod root {
+                    ) ));
+         assert_eq!(::std::mem::align_of::<root::nsAutoPtr<root::mozilla::dom::ExplicitChildIterator>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsAutoPtr<root::mozilla::dom::ExplicitChildIterator>
+                    ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_266909_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241702_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37459,28 +37464,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::Element> ) ));
+         assert_eq!(::std::mem::align_of::<root::RefPtr<root::mozilla::dom::Element>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::RefPtr<root::mozilla::dom::Element> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267067_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241860_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_267072_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_241865_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::nsIContent>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::nsIContent> ) ));
+@@ -37602,28 +37607,28 @@ pub mod root {
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<root::mozilla::gfx::FontVariation>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<root::mozilla::gfx::FontVariation> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269589_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_244094_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+     }
+     #[test]
+-    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_269595_close0_instantiation() {
++    fn __bindgen_test_layout_nsTArray_open0__bindgen_ty_id_244100_close0_instantiation() {
+         assert_eq!(::std::mem::size_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Size of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+         assert_eq!(::std::mem::align_of::<root::nsTArray<*mut root::mozilla::css::DocumentRule>>()
+                    , 8usize , concat ! (
+                    "Alignment of template specialization: " , stringify ! (
+                    root::nsTArray<*mut root::mozilla::css::DocumentRule> ) ));
+diff --git a/servo/components/style/gecko/wrapper.rs b/servo/components/style/gecko/wrapper.rs
+--- a/servo/components/style/gecko/wrapper.rs
++++ b/servo/components/style/gecko/wrapper.rs
+@@ -56,16 +56,17 @@ use gecko_bindings::structs;
+ use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode, RawGeckoXBLBinding};
+ use gecko_bindings::structs::{nsIAtom, nsIContent, nsINode_BooleanFlag};
+ use gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
+ use gecko_bindings::structs::ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO;
+ use gecko_bindings::structs::ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO;
+ use gecko_bindings::structs::ELEMENT_HAS_SNAPSHOT;
+ use gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
+ use gecko_bindings::structs::NODE_DESCENDANTS_NEED_FRAMES;
++use gecko_bindings::structs::NODE_NEEDS_FRAME;
+ use gecko_bindings::structs::nsChangeHint;
+ use gecko_bindings::structs::nsIDocument_DocumentTheme as DocumentTheme;
+ use gecko_bindings::structs::nsRestyleHint;
+ use gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
+ use logical_geometry::WritingMode;
+ use media_queries::Device;
+ use properties::{ComputedValues, parse_style_attribute};
+ use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
+@@ -488,16 +489,43 @@ impl<'le> GeckoElement<'le> {
+     fn set_flags(&self, flags: u32) {
+         unsafe { Gecko_SetNodeFlags(self.as_node().0, flags) }
+     }
+ 
+     fn unset_flags(&self, flags: u32) {
+         unsafe { Gecko_UnsetNodeFlags(self.as_node().0, flags) }
+     }
+ 
++    /// Returns true if this element has descendants for lazy frame construction.
++    pub fn descendants_need_frames(&self) -> bool {
++        self.flags() & (NODE_DESCENDANTS_NEED_FRAMES  as u32) != 0
++    }
++
++    /// Returns true if this element needs lazy frame construction.
++    pub fn needs_frame(&self) -> bool {
++        self.flags() & (NODE_NEEDS_FRAME as u32) != 0
++    }
++
++    /// Returns true if a traversal starting from this element requires a post-traversal.
++    pub fn needs_post_traversal(&self) -> bool {
++        debug!("needs_post_traversal: dd={}, aodd={}, lfcd={}, lfc={}, restyle={:?}",
++               self.has_dirty_descendants(),
++               self.has_animation_only_dirty_descendants(),
++               self.descendants_need_frames(),
++               self.needs_frame(),
++               self.borrow_data().unwrap().restyle);
++
++        let has_flag =
++            self.flags() & (ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
++                            ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
++                            NODE_DESCENDANTS_NEED_FRAMES as u32 |
++                            NODE_NEEDS_FRAME as u32) != 0;
++        has_flag || self.borrow_data().unwrap().restyle.contains_restyle_data()
++    }
++
+     /// Returns true if this element has a shadow root.
+     fn has_shadow_root(&self) -> bool {
+         self.get_extended_slots().map_or(false, |slots| !slots.mShadowRoot.mRawPtr.is_null())
+     }
+ 
+     /// Returns a reference to the DOM slots for this Element, if they exist.
+     fn get_dom_slots(&self) -> Option<&structs::FragmentOrElement_nsDOMSlots> {
+         let slots = self.as_node().0.mSlots as *const structs::FragmentOrElement_nsDOMSlots;
+@@ -1065,16 +1093,23 @@ impl<'le> TElement for GeckoElement<'le>
+ 
+     unsafe fn clear_descendants_bits(&self) {
+         self.unset_flags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
+                          ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
+                          NODE_DESCENDANTS_NEED_FRAMES as u32)
+     }
+ 
+     #[inline]
++    unsafe fn clear_dirty_bits(&self) {
++        self.unset_flags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
++                         ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
++                         NODE_DESCENDANTS_NEED_FRAMES as u32 |
++                         NODE_NEEDS_FRAME as u32)
++    }
++
+     fn is_visited_link(&self) -> bool {
+         use element_state::IN_VISITED_STATE;
+         self.get_state().intersects(IN_VISITED_STATE)
+     }
+ 
+     #[inline]
+     fn is_native_anonymous(&self) -> bool {
+         use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS;
+diff --git a/servo/components/style/invalidation/stylesheets.rs b/servo/components/style/invalidation/stylesheets.rs
+--- a/servo/components/style/invalidation/stylesheets.rs
++++ b/servo/components/style/invalidation/stylesheets.rs
+@@ -112,23 +112,27 @@ impl StylesheetInvalidationSet {
+         }
+ 
+         debug!(" > resulting invalidations: {:?}", self.invalid_scopes);
+         debug!(" > fully_invalid: {}", self.fully_invalid);
+     }
+ 
+     /// Clears the invalidation set, invalidating elements as needed if
+     /// `document_element` is provided.
+-    pub fn flush<E>(&mut self, document_element: Option<E>)
++    ///
++    /// Returns true if any invalidations ocurred.
++    pub fn flush<E>(&mut self, document_element: Option<E>) -> bool
+         where E: TElement,
+     {
+-        if let Some(e) = document_element {
+-            self.process_invalidations(e);
+-        }
++        let have_invalidations = match document_element {
++            Some(e) => self.process_invalidations(e),
++            None => false,
++        };
+         self.clear();
++        have_invalidations
+     }
+ 
+     /// Clears the invalidation set without processing.
+     pub fn clear(&mut self) {
+         self.invalid_scopes.clear();
+         self.fully_invalid = false;
+     }
+ 
+diff --git a/servo/components/style/stylesheet_set.rs b/servo/components/style/stylesheet_set.rs
+--- a/servo/components/style/stylesheet_set.rs
++++ b/servo/components/style/stylesheet_set.rs
+@@ -177,35 +177,38 @@ where
+     pub fn has_changed(&self) -> bool {
+         self.invalidation_data
+             .iter_origins()
+             .any(|(d, _)| d.dirty)
+     }
+ 
+     /// Flush the current set, unmarking it as dirty, and returns an iterator
+     /// over the new stylesheet list.
++    ///
++    /// Returns true if any elements were invalidated.
+     pub fn flush<E>(
+         &mut self,
+         document_element: Option<E>,
+-    ) -> (StylesheetIterator<S>, OriginSet)
++    ) -> (StylesheetIterator<S>, OriginSet, bool)
+     where
+         E: TElement,
+     {
+         debug!("StylesheetSet::flush");
+ 
+         let mut origins = OriginSet::empty();
++        let mut have_invalidations = false;
+         for (data, origin) in self.invalidation_data.iter_mut_origins() {
+             if data.dirty {
+-                data.invalidations.flush(document_element);
++                have_invalidations |= data.invalidations.flush(document_element);
+                 data.dirty = false;
+                 origins |= origin;
+             }
+         }
+ 
+-        (self.iter(), origins)
++        (self.iter(), origins, have_invalidations)
+     }
+ 
+     /// Flush stylesheets, but without running any of the invalidation passes.
+     ///
+     /// FIXME(emilio): This should eventually disappear. Please keep this
+     /// Servo-only.
+     #[cfg(feature = "servo")]
+     pub fn flush_without_invalidation(&mut self) -> (StylesheetIterator<S>, OriginSet) {
+diff --git a/servo/components/style/stylist.rs b/servo/components/style/stylist.rs
+--- a/servo/components/style/stylist.rs
++++ b/servo/components/style/stylist.rs
+@@ -476,29 +476,30 @@ impl Stylist {
+     ///
+     /// FIXME(emilio): Move the `ua_sheets` to the Stylist too?
+     pub fn flush<E>(
+         &mut self,
+         guards: &StylesheetGuards,
+         ua_sheets: Option<&UserAgentStylesheets>,
+         extra_data: &mut PerOrigin<ExtraStyleData>,
+         document_element: Option<E>,
+-    )
++    ) -> bool
+     where
+         E: TElement,
+     {
+         if !self.stylesheets.has_changed() {
+-            return;
++            return false;
+         }
+ 
+         let author_style_disabled = self.stylesheets.author_style_disabled();
+-        let (doc_stylesheets, origins_to_rebuild) = self.stylesheets.flush(document_element);
++        let (doc_stylesheets, origins_to_rebuild, have_invalidations) =
++            self.stylesheets.flush(document_element);
+ 
+         if origins_to_rebuild.is_empty() {
+-            return;
++            return have_invalidations;
+         }
+ 
+         self.num_rebuilds += 1;
+ 
+         // Update viewport_constraints regardless of which origins'
+         // `CascadeData` we're updating.
+         self.viewport_constraints = None;
+         if viewport_rule::enabled() {
+@@ -533,16 +534,18 @@ impl Stylist {
+             self.quirks_mode,
+             doc_stylesheets,
+             guards,
+             ua_sheets,
+             author_style_disabled,
+             extra_data,
+             origins_to_rebuild,
+         );
++
++        have_invalidations
+     }
+ 
+     /// Insert a given stylesheet before another stylesheet in the document.
+     pub fn insert_stylesheet_before(
+         &mut self,
+         sheet: StylistSheet,
+         before_sheet: StylistSheet,
+         guard: &SharedRwLockReadGuard,
+diff --git a/servo/components/style/traversal.rs b/servo/components/style/traversal.rs
+--- a/servo/components/style/traversal.rs
++++ b/servo/components/style/traversal.rs
+@@ -180,20 +180,26 @@ pub trait DomTraversal<E: TElement> : Sy
+             data.restyle.set_reconstructed_ancestor(false);
+         };
+ 
+         let parent = root.traversal_parent();
+         let parent_data = parent.as_ref().and_then(|p| p.borrow_data());
+         let should_traverse = Self::element_needs_traversal(
+             root,
+             flags,
+-            data.map(|d| &*d),
++            data.as_mut().map(|d| &**d),
+             parent_data.as_ref().map(|d| &**d)
+         );
+ 
++        // If we're not going to traverse at all, we may need to clear some state
++        // off the root (which would normally be done at the end of recalc_style_at).
++        if !should_traverse && data.is_some() {
++            clear_state_after_traversing(root, data.unwrap(), flags);
++        }
++
+         PreTraverseToken(should_traverse)
+     }
+ 
+     /// Returns true if traversal should visit a text node. The style system
+     /// never processes text nodes, but Servo overrides this to visit them for
+     /// flow construction when necessary.
+     fn text_node_needs_traversal(node: E::ConcreteNode, _parent_data: &ElementData) -> bool {
+         debug_assert!(node.is_text_node());
+@@ -587,49 +593,58 @@ where
+             element,
+             data,
+             propagated_hint,
+             data.restyle.reconstructed_self_or_ancestor(),
+             note_child
+         );
+     }
+ 
++    // FIXME(bholley): Make these assertions pass for servo.
++    if cfg!(feature = "gecko") && cfg!(debug_assertions) && data.styles.is_display_none() {
++        debug_assert!(!element.has_dirty_descendants());
++        debug_assert!(!element.has_animation_only_dirty_descendants());
++    }
++
++    debug_assert!(flags.for_animation_only() ||
++                  !flags.contains(ClearDirtyBits) ||
++                  !element.has_animation_only_dirty_descendants(),
++                  "Should have cleared animation bits already");
++    clear_state_after_traversing(element, data, flags);
++
++    context.thread_local.end_element(element);
++}
++
++fn clear_state_after_traversing<E>(
++    element: E,
++    data: &mut ElementData,
++    flags: TraversalFlags
++)
++where
++    E: TElement,
++{
++    use traversal_flags::*;
++
+     // If we are in a forgetful traversal, drop the existing restyle
+     // data here, since we won't need to perform a post-traversal to pick up
+     // any change hints.
+     if flags.contains(Forgetful) {
+         data.clear_restyle_flags_and_damage();
+     }
+ 
+-    // Optionally clear the descendants bits.
+-    if data.styles.is_display_none() {
+-        // When this element is the root of a display:none subtree, we want to clear
+-        // the bits even if the style didn't change (since, if the style did change,
+-        // we'd have already cleared it above).
+-        //
+-        // This keeps the tree in a valid state without requiring the DOM to check
+-        // display:none on the parent when inserting new children (which can be
+-        // moderately expensive). Instead, DOM implementations can unconditionally
+-        // set the dirty descendants bit on any styled parent, and let the traversal
+-        // sort it out.
+-        //
+-        // Note that the NODE_DESCENDANTS_NEED_FRAMES bit should generally only be set
+-        // when appending content beneath an element with a frame (i.e. not
+-        // display:none), so clearing it here isn't strictly necessary, but good
+-        // belt-and-suspenders.
+-        unsafe { element.clear_descendants_bits(); }
+-    } else if flags.for_animation_only() {
+-        if flags.contains(ClearAnimationOnlyDirtyDescendants) {
++    // Clear dirty bits as appropriate.
++    if flags.for_animation_only() {
++        if flags.intersects(ClearDirtyBits | ClearAnimationOnlyDirtyDescendants) {
+             unsafe { element.unset_animation_only_dirty_descendants(); }
+         }
+-    } else if flags.contains(ClearDirtyDescendants) {
+-        unsafe { element.unset_dirty_descendants(); }
++    } else if flags.contains(ClearDirtyBits) {
++        // The animation traversal happens first, so we don't need to guard against
++        // clearing the animation bit on the regular traversal.
++        unsafe { element.clear_dirty_bits(); }
+     }
+-
+-    context.thread_local.end_element(element);
+ }
+ 
+ fn compute_style<E>(
+     traversal_data: &PerLevelTraversalData,
+     context: &mut StyleContext<E>,
+     element: E,
+     data: &mut ElementData
+ ) -> ChildCascadeRequirement
+@@ -850,11 +865,16 @@ where
+                 // By consequence, any element without data has no descendants with
+                 // data.
+                 if kid.get_data().is_some() {
+                     kid.clear_data();
+                     parents.push(kid);
+                 }
+             }
+         }
+-        p.clear_descendants_bits();
++        if p == root {
++            // Make sure not to clear NODE_NEEDS_FRAME on the root.
++            p.clear_descendants_bits();
++        } else {
++            p.clear_dirty_bits();
++        }
+     }
+ }
+diff --git a/servo/components/style/traversal_flags.rs b/servo/components/style/traversal_flags.rs
+--- a/servo/components/style/traversal_flags.rs
++++ b/servo/components/style/traversal_flags.rs
+@@ -22,18 +22,18 @@ bitflags! {
+         /// A forgetful traversal ignores the previous state of the frame tree, and
+         /// thus does not compute damage or maintain other state describing the styles
+         /// pre-traversal. A forgetful traversal is usually the right thing if you
+         /// aren't going to do a post-traversal.
+         const Forgetful = 1 << 3,
+         /// Actively seeks out and clears change hints that may have been posted into
+         /// the tree. Nonsensical without also passing Forgetful.
+         const AggressivelyForgetful = 1 << 4,
+-        /// Clears the dirty descendants bit in the subtree.
+-        const ClearDirtyDescendants = 1 << 5,
++        /// Clears all the dirty bits on the elements traversed.
++        const ClearDirtyBits = 1 << 5,
+         /// Clears the animation-only dirty descendants bit in the subtree.
+         const ClearAnimationOnlyDirtyDescendants = 1 << 6,
+         /// Allows the traversal to run in parallel if there are sufficient cores on
+         /// the machine.
+         const ParallelTraversal = 1 << 7,
+         /// Flush throttled animations. By default, we only update throttled animations
+         /// when we have other non-throttled work to do. With this flag, we
+         /// unconditionally tick and process them.
+@@ -62,17 +62,17 @@ pub fn assert_traversal_flags_match() {
+     }
+ 
+     check_traversal_flags! {
+         ServoTraversalFlags_AnimationOnly => AnimationOnly,
+         ServoTraversalFlags_ForCSSRuleChanges => ForCSSRuleChanges,
+         ServoTraversalFlags_UnstyledOnly => UnstyledOnly,
+         ServoTraversalFlags_Forgetful => Forgetful,
+         ServoTraversalFlags_AggressivelyForgetful => AggressivelyForgetful,
+-        ServoTraversalFlags_ClearDirtyDescendants => ClearDirtyDescendants,
++        ServoTraversalFlags_ClearDirtyBits => ClearDirtyBits,
+         ServoTraversalFlags_ClearAnimationOnlyDirtyDescendants =>
+             ClearAnimationOnlyDirtyDescendants,
+         ServoTraversalFlags_ParallelTraversal => ParallelTraversal,
+         ServoTraversalFlags_FlushThrottledAnimations => FlushThrottledAnimations,
+     }
+ }
+ 
+ impl TraversalFlags {
+diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs
+--- a/servo/ports/geckolib/glue.rs
++++ b/servo/ports/geckolib/glue.rs
+@@ -20,16 +20,17 @@ use style::element_state::ElementState;
+ use style::error_reporting::{NullReporter, ParseErrorReporter};
+ use style::font_metrics::{FontMetricsProvider, get_metrics_provider_for_product};
+ use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl};
+ use style::gecko::global_style_data::{GLOBAL_STYLE_DATA, GlobalStyleData, STYLE_THREAD_POOL};
+ use style::gecko::restyle_damage::GeckoRestyleDamage;
+ use style::gecko::selector_parser::PseudoElement;
+ use style::gecko::traversal::RecalcStyleOnly;
+ use style::gecko::wrapper::GeckoElement;
++use style::gecko_bindings::bindings;
+ use style::gecko_bindings::bindings::{RawGeckoElementBorrowed, RawGeckoElementBorrowedOrNull};
+ use style::gecko_bindings::bindings::{RawGeckoKeyframeListBorrowed, RawGeckoKeyframeListBorrowedMut};
+ use style::gecko_bindings::bindings::{RawServoDeclarationBlockBorrowed, RawServoDeclarationBlockStrong};
+ use style::gecko_bindings::bindings::{RawServoDocumentRule, RawServoDocumentRuleBorrowed};
+ use style::gecko_bindings::bindings::{RawServoFontFeatureValuesRule, RawServoFontFeatureValuesRuleBorrowed};
+ use style::gecko_bindings::bindings::{RawServoImportRule, RawServoImportRuleBorrowed};
+ use style::gecko_bindings::bindings::{RawServoKeyframe, RawServoKeyframeBorrowed, RawServoKeyframeStrong};
+ use style::gecko_bindings::bindings::{RawServoKeyframesRule, RawServoKeyframesRuleBorrowed};
+@@ -286,24 +287,24 @@ pub extern "C" fn Servo_TraverseSubtree(
+         }
+     }
+ 
+     traverse_subtree(element,
+                      raw_data,
+                      traversal_flags,
+                      unsafe { &*snapshots });
+ 
+-    debug!("Servo_TraverseSubtree complete (dd={}, aodd={}, restyle={:?})",
++    debug!("Servo_TraverseSubtree complete (dd={}, aodd={}, lfcd={}, lfc={}, restyle={:?})",
+            element.has_dirty_descendants(),
+            element.has_animation_only_dirty_descendants(),
++           element.descendants_need_frames(),
++           element.needs_frame(),
+            element.borrow_data().unwrap().restyle);
+ 
+-    element.has_dirty_descendants() ||
+-    element.has_animation_only_dirty_descendants() ||
+-    element.borrow_data().unwrap().restyle.contains_restyle_data()
++    element.needs_post_traversal()
+ }
+ 
+ /// Checks whether the rule tree has crossed its threshold for unused nodes, and
+ /// if so, frees them.
+ #[no_mangle]
+ pub extern "C" fn Servo_MaybeGCRuleTree(raw_data: RawServoStyleSetBorrowed) {
+     let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
+     unsafe {
+@@ -822,16 +823,24 @@ pub extern "C" fn Servo_Element_GetPseud
+ {
+     let element = GeckoElement(element);
+     let data = element.borrow_data().expect("Getting CVs that aren't present");
+     data.styles.pseudos.as_array()[index].as_ref().expect("Getting CVs that aren't present")
+         .clone().into()
+ }
+ 
+ #[no_mangle]
++pub extern "C" fn Servo_Element_IsDisplayNone(element: RawGeckoElementBorrowed) -> bool
++{
++    let element = GeckoElement(element);
++    let data = element.borrow_data().expect("Invoking Servo_Element_IsDisplayNone on unstyled element");
++    data.styles.is_display_none()
++}
++
++#[no_mangle]
+ pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyleSheetContentsStrong {
+     let global_style_data = &*GLOBAL_STYLE_DATA;
+     let origin = match mode {
+         SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
+         SheetParsingMode::eUserSheetFeatures => Origin::User,
+         SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
+         SheetParsingMode::eSafeAgentSheetFeatures => Origin::UserAgent,
+     };
+@@ -986,17 +995,22 @@ pub extern "C" fn Servo_StyleSet_RemoveS
+ pub extern "C" fn Servo_StyleSet_FlushStyleSheets(
+     raw_data: RawServoStyleSetBorrowed,
+     doc_element: RawGeckoElementBorrowedOrNull,
+ ) {
+     let global_style_data = &*GLOBAL_STYLE_DATA;
+     let guard = global_style_data.shared_lock.read();
+     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
+     let doc_element = doc_element.map(GeckoElement);
+-    data.flush_stylesheets(&guard, doc_element);
++    let have_invalidations = data.flush_stylesheets(&guard, doc_element);
++    if have_invalidations && doc_element.is_some() {
++        // The invalidation machinery propagates the bits up, but we still
++        // need to tell the gecko restyle root machinery about it.
++        unsafe { bindings::Gecko_NoteDirtyElement(doc_element.unwrap().0); }
++    }
+ }
+ 
+ #[no_mangle]
+ pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(
+     raw_data: RawServoStyleSetBorrowed,
+     author_style_disabled: bool,
+     changed_origins: OriginFlags,
+ ) {

+ 1316 - 0
frg/253-58/mozilla-release58_428218.patch

@@ -0,0 +1,1316 @@
+# HG changeset patch
+# User Bobby Holley <bobbyholley@gmail.com>
+# Date 1500428327 25200
+#      Tue Jul 18 18:38:47 2017 -0700
+# Node ID 86b793bcbcd090a4189814f14204a2e0ea7929ef
+# Parent  4e53218f68e9f8ba6aed53652f464fd75b3e6631
+Bug 1383332 - Track the restyle root and use it to do less work during the traversal. r=emilio
+
+MozReview-Commit-ID: A8O3JOpsv4E
+
+diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp
+--- a/dom/base/Element.cpp
++++ b/dom/base/Element.cpp
+@@ -1909,17 +1909,17 @@ Element::UnbindFromTree(bool aDeep, bool
+     DeleteProperty(nsGkAtoms::animationsProperty);
+   }
+ 
+   ClearInDocument();
+ 
+   // Computed style data isn't useful for detached nodes, and we'll need to
+   // recompute it anyway if we ever insert the nodes back into a document.
+   if (IsStyledByServo()) {
+-    ClearServoData();
++    ClearServoData(document);
+   } else {
+     MOZ_ASSERT(!HasServoData());
+   }
+ 
+   // Editable descendant count only counts descendants that
+   // are in the uncomposed document.
+   ResetEditableDescendantCount();
+ 
+@@ -4154,22 +4154,31 @@ Element::UpdateIntersectionObservation(D
+   if (auto entry = RegisteredIntersectionObservers()->Lookup(aObserver)) {
+     updated = entry.Data() != aThreshold;
+     entry.Data() = aThreshold;
+   }
+   return updated;
+ }
+ 
+ void
+-Element::ClearServoData() {
++Element::ClearServoData(nsIDocument* aDoc) {
+   MOZ_ASSERT(IsStyledByServo());
+ #ifdef MOZ_STYLO
+   Servo_Element_ClearData(this);
+   UnsetFlags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO |
+              ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO);
++
++  // Since this element is losing its servo data, nothing under it may have
++  // servo data either, so we can forget restyles rooted at this element. This
++  // is necessary for correctness, since we invoke ClearServoData in various
++  // places where an element's flattened tree parent changes, and such a change
++  // may also make an element invalid to be used as a restyle root.
++  if (aDoc && aDoc->GetServoRestyleRoot() == this) {
++    aDoc->ClearServoRestyleRoot();
++  }
+ #else
+   MOZ_CRASH("Accessing servo node data in non-stylo build");
+ #endif
+ }
+ 
+ void
+ Element::SetCustomElementData(CustomElementData* aData)
+ {
+@@ -4212,86 +4221,190 @@ Element::AddSizeOfExcludingThis(SizeOfSt
+                                        &aSizes.mComputedValuesDom);
+           }
+         }
+       }
+     }
+   }
+ }
+ 
+-struct DirtyDescendantsBit {
+-  static bool HasBit(const Element* aElement)
+-  {
+-    return aElement->HasDirtyDescendantsForServo();
+-  }
+-  static void SetBit(Element* aElement)
+-  {
+-    aElement->SetHasDirtyDescendantsForServo();
+-  }
+-};
+-
+-struct AnimationOnlyDirtyDescendantsBit {
+-  static bool HasBit(const Element* aElement)
+-  {
+-    return aElement->HasAnimationOnlyDirtyDescendantsForServo();
+-  }
+-  static void SetBit(Element* aElement)
+-  {
+-    aElement->SetHasAnimationOnlyDirtyDescendantsForServo();
+-  }
+-};
+-
+ #ifdef DEBUG
+-template<typename Traits>
+-bool
+-BitIsPropagated(const Element* aElement)
++static bool
++BitIsPropagated(const Element* aElement, uint32_t aBit, nsINode* aRestyleRoot)
+ {
+   const Element* curr = aElement;
+   while (curr) {
+-    if (!Traits::HasBit(curr)) {
++    if (curr == aRestyleRoot) {
++      return true;
++    }
++    if (!curr->HasFlag(aBit)) {
+       return false;
+     }
+     nsINode* parentNode = curr->GetParentNode();
+     curr = curr->GetFlattenedTreeParentElementForStyle();
+     MOZ_ASSERT_IF(!curr,
+                   parentNode == aElement->OwnerDoc() ||
+                   parentNode == parentNode->OwnerDoc()->GetRootElement());
+   }
+   return true;
+ }
+ #endif
+ 
+-template<typename Traits>
+-void
+-NoteDirtyElement(Element* aElement)
++// Sets |aBits| on aElement and all of its flattened-tree ancestors up to and
++// including aStopAt or the root element (whichever is encountered first).
++static inline Element*
++PropagateBits(Element* aElement, uint32_t aBits, nsINode* aStopAt)
++{
++  Element* curr = aElement;
++  while (curr && !curr->HasAllFlags(aBits)) {
++    curr->SetFlags(aBits);
++    if (curr == aStopAt) {
++      break;
++    }
++    curr = curr->GetFlattenedTreeParentElementForStyle();
++  }
++
++  return curr;
++}
++
++// Invokes PropagateBits on the parent element if |aNode| is not the document.
++static inline Element*
++PropagateBitsFromParent(nsINode* aNode, uint32_t aBits, nsINode* aStopAt)
++{
++  MOZ_ASSERT(aNode->IsElement() || aNode == aNode->OwnerDoc());
++  if (!aNode->IsElement()) {
++    return nullptr;
++  }
++
++  Element* parent = aNode->AsElement()->GetFlattenedTreeParentElementForStyle();
++  return PropagateBits(parent, aBits, aStopAt);
++}
++
++// Notes that a given element is "dirty" with respect to the given descendants
++// bit (which may be one of dirty descendants, dirty animation descendants, or
++// need frame construction for descendants).
++//
++// This function operates on the dirty element itself, despite the fact that the
++// bits are generally used to describe descendants. This allows restyle roots
++// to be scoped as tightly as possible. On the first call to NoteDirtyElement
++// since the last restyle, we don't set any descendant bits at all, and just set
++// the element as the restyle root.
++//
++// Because the style traversal handles multiple tasks (styling, animation-ticking,
++// and lazy frame construction), there are potentially three separate kinds of
++// dirtiness to track. Rather than maintaining three separate restyle roots, we
++// use a single root, and always bubble it up to be the nearest common ancestor
++// of all the dirty content in the tree. This means that we need to track the
++// types of dirtiness that the restyle root corresponds to, so
++// SetServoRestyleRoot accepts a bitfield along with an element.
++//
++// The overall algorithm is as follows:
++// * When the first dirty element is noted, we just set as the restyle root.
++// * When additional dirty elements are noted, we propagate the given bit up
++//   the tree, until we either reach the restyle root or the document root.
++// * If we reach the document root, we then propagate the bits associated with
++//   the restyle root up the tree until we cross the path of the new root. Once
++//   we find this common ancestor, we record it as the restyle root, and then
++//   clear the bits between the new restyle root and the document root.
++// * If we have dirty content beneath multiple "document style traversal roots"
++//   (which are the main DOM + each piece of document-level native-anoymous
++//   content), we set the restyle root to the nsINode of the document itself.
++//   This is the bail-out case where we traverse everything.
++static void
++NoteDirtyElement(Element* aElement, uint32_t aBit)
+ {
+   MOZ_ASSERT(aElement->IsInComposedDoc());
+-  nsIDocument* doc = aElement->GetComposedDoc();
+-  nsIPresShell* shell = doc->GetShell();
+-  NS_ENSURE_TRUE_VOID(shell);
+-  shell->EnsureStyleFlush();
++  MOZ_ASSERT(aElement->IsStyledByServo());
+ 
+   Element* parent = aElement->GetFlattenedTreeParentElementForStyle();
+-  if (!parent || !parent->HasServoData()) {
+-    // The bits only apply to styled elements.
++  if (MOZ_LIKELY(parent)) {
++    // If our parent is unstyled, we can inductively assume that it will be
++    // traversed when the time is right, and that the traversal will reach us
++    // when it happens. Nothing left to do.
++    if (!parent->HasServoData()) {
++      return;
++    }
++
++    // Similarly, if our parent already has the bit we're propagating, we can
++    // assume everything is already set up.
++    if (parent->HasFlag(aBit)) {
++      MOZ_ASSERT(aElement->GetComposedDoc()->GetServoRestyleRoot());
++      return;
++    }
++
++    // If the parent is styled but is display:none, we're done.
++    //
++    // We check for a frame to reduce the cases where we need the FFI call.
++    if (!parent->GetPrimaryFrame() && Servo_Element_IsDisplayNone(parent)) {
++      return;
++    }
++  }
++
++  nsIDocument* doc = aElement->GetComposedDoc();
++  if (nsIPresShell* shell = doc->GetShell()) {
++    shell->EnsureStyleFlush();
++  }
++
++  // If there's no existing restyle root, or if the root is already aElement,
++  // just note the root+bits and return.
++  nsINode* existingRoot = doc->GetServoRestyleRoot();
++  uint32_t existingBits = existingRoot ? doc->GetServoRestyleRootDirtyBits() : 0;
++  if (!existingRoot || existingRoot == aElement) {
++    doc->SetServoRestyleRoot(aElement, existingBits | aBit);
+     return;
+   }
+ 
+-  Element* curr = parent;
+-  while (curr && !Traits::HasBit(curr)) {
+-    Traits::SetBit(curr);
+-    curr = curr->GetFlattenedTreeParentElementForStyle();
+-  }
+-
+-  MOZ_ASSERT(BitIsPropagated<Traits>(parent));
++  // There is an existing restyle root - walk up the tree from our element,
++  // propagating bits as wel go.
++  const bool reachedDocRoot = !parent || !PropagateBits(parent, aBit, existingRoot);
++
++  if (!reachedDocRoot) {
++      // We're a descendant of the existing root. All that's left to do is to
++      // make sure the bit we propagated is also registered on the root.
++      doc->SetServoRestyleRoot(existingRoot, existingBits | aBit);
++  } else {
++    // We reached the root without crossing the pre-existing restyle root. We
++    // now need to find the nearest common ancestor, so climb up from the
++    // existing root, extending bits along the way.
++    if (Element* commonAncestor = PropagateBitsFromParent(existingRoot, existingBits, aElement)) {
++      // We found a common ancestor. Make that the new style root, and clear the
++      // bits between the new style root and the document root.
++      doc->SetServoRestyleRoot(commonAncestor, existingBits | aBit);
++      Element* curr = commonAncestor;
++      while ((curr = curr->GetFlattenedTreeParentElementForStyle())) {
++        MOZ_ASSERT(curr->HasFlag(aBit));
++        curr->UnsetFlags(aBit);
++      }
++    } else {
++      // We didn't find a common ancestor element. That means we're descended
++      // from two different document style roots, so the common ancestor is the
++      // document.
++      doc->SetServoRestyleRoot(doc, existingBits | aBit);
++    }
++  }
++
++  MOZ_ASSERT(aElement == doc->GetServoRestyleRoot() ||
++             BitIsPropagated(parent, aBit, doc->GetServoRestyleRoot()));
++  MOZ_ASSERT(doc->GetServoRestyleRootDirtyBits() & aBit);
+ }
+ 
+ void
+ Element::NoteDirtyForServo()
+ {
+-  NoteDirtyElement<DirtyDescendantsBit>(this);
++  NoteDirtyElement(this, ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
+ }
+ 
+ void
+ Element::NoteAnimationOnlyDirtyForServo()
+ {
+-  NoteDirtyElement<AnimationOnlyDirtyDescendantsBit>(this);
++  NoteDirtyElement(this, ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO);
+ }
++
++void
++Element::NoteDescendantsNeedFramesForServo()
++{
++  // Since lazy frame construction can be required for non-element nodes, this
++  // Note() method operates on the parent of the frame-requiring content, unlike
++  // the other Note() methods above (which operate directly on the element that
++  // needs processing).
++  NoteDirtyElement(this, NODE_DESCENDANTS_NEED_FRAMES);
++  SetFlags(NODE_DESCENDANTS_NEED_FRAMES);
++}
+diff --git a/dom/base/Element.h b/dom/base/Element.h
+--- a/dom/base/Element.h
++++ b/dom/base/Element.h
+@@ -463,18 +463,24 @@ public:
+       UpdateState(true);
+     }
+   }
+ 
+   bool GetBindingURL(nsIDocument* aDocument, css::URLValue **aResult);
+ 
+   Directionality GetComputedDirectionality() const;
+ 
++  static const uint32_t kAllServoDescendantBits =
++    ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO |
++    ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO |
++    NODE_DESCENDANTS_NEED_FRAMES;
++
+   void NoteDirtyForServo();
+   void NoteAnimationOnlyDirtyForServo();
++  void NoteDescendantsNeedFramesForServo();
+ 
+   bool HasDirtyDescendantsForServo() const
+   {
+     MOZ_ASSERT(IsStyledByServo());
+     return HasFlag(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
+   }
+ 
+   void SetHasDirtyDescendantsForServo() {
+@@ -501,17 +507,18 @@ public:
+     MOZ_ASSERT(IsStyledByServo());
+     UnsetFlags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO);
+   }
+ 
+   bool HasServoData() const {
+     return !!mServoData.Get();
+   }
+ 
+-  void ClearServoData();
++  void ClearServoData() { ClearServoData(GetComposedDoc()); }
++  void ClearServoData(nsIDocument* aDocument);
+ 
+   /**
+    * Gets the custom element data used by web components custom element.
+    * Custom element data is created at the first attempt to enqueue a callback.
+    *
+    * @return The custom element data or null if none.
+    */
+   inline CustomElementData* GetCustomElementData() const
+diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
+--- a/dom/base/nsDocument.cpp
++++ b/dom/base/nsDocument.cpp
+@@ -1501,17 +1501,18 @@ nsIDocument::nsIDocument()
+     mWindow(nullptr),
+     mBFCacheEntry(nullptr),
+     mInSyncOperationCount(0),
+     mBlockDOMContentLoaded(0),
+     mUseCounters(0),
+     mChildDocumentUseCounters(0),
+     mNotifiedPageForUseCounter(0),
+     mIncCounters(),
+-    mUserHasInteracted(false)
++    mUserHasInteracted(false),
++    mServoRestyleRootDirtyBits(0)
+ {
+   SetIsInDocument();
+   for (auto& cnt : mIncCounters) {
+     cnt = 0;
+   }
+ }
+ 
+ nsDocument::nsDocument(const char* aContentType)
+diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
+--- a/dom/base/nsIDocument.h
++++ b/dom/base/nsIDocument.h
+@@ -3025,16 +3025,36 @@ public:
+ 
+   // For more information on Flash classification, see
+   // toolkit/components/url-classifier/flash-block-lists.rst
+   virtual mozilla::dom::FlashClassification DocumentFlashClassification() = 0;
+   virtual bool IsThirdParty() = 0;
+ 
+   bool IsScopedStyleEnabled();
+ 
++  nsINode* GetServoRestyleRoot() const
++  {
++    return mServoRestyleRoot;
++  }
++
++  uint32_t GetServoRestyleRootDirtyBits() const
++  {
++    MOZ_ASSERT(mServoRestyleRoot);
++    MOZ_ASSERT(mServoRestyleRootDirtyBits);
++    return mServoRestyleRootDirtyBits;
++  }
++
++  void ClearServoRestyleRoot()
++  {
++    mServoRestyleRoot = nullptr;
++    mServoRestyleRootDirtyBits = 0;
++  }
++
++  inline void SetServoRestyleRoot(nsINode* aRoot, uint32_t aDirtyBits);
++
+ protected:
+   bool GetUseCounter(mozilla::UseCounter aUseCounter)
+   {
+     return mUseCounters[aUseCounter];
+   }
+ 
+   void SetChildDocumentUseCounter(mozilla::UseCounter aUseCounter)
+   {
+@@ -3544,16 +3564,27 @@ protected:
+   // The set of all the tracking script URLs.  URLs are added to this set by
+   // calling NoteScriptTrackingStatus().  Currently we assume that a URL not
+   // existing in the set means the corresponding script isn't a tracking script.
+   nsTHashtable<nsCStringHashKey> mTrackingScripts;
+ 
+   // CSP violation reports that have been buffered up due to a call to
+   // StartBufferingCSPViolations.
+   nsTArray<nsCOMPtr<nsIRunnable>> mBufferedCSPViolations;
++
++  // Restyle root for servo's style system.
++  //
++  // We store this as an nsINode, rather than as an Element, so that we can store
++  // the Document node as the restyle root if the entire document (along with all
++  // document-level native-anonymous content) needs to be restyled.
++  //
++  // We also track which "descendant" bits (normal/animation-only/lazy-fc) the
++  // root corresponds to.
++  nsCOMPtr<nsINode> mServoRestyleRoot;
++  uint32_t mServoRestyleRootDirtyBits;
+ };
+ 
+ NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
+ 
+ /**
+  * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
+  * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
+  * object is deleted.
+diff --git a/dom/base/nsIDocumentInlines.h b/dom/base/nsIDocumentInlines.h
+--- a/dom/base/nsIDocumentInlines.h
++++ b/dom/base/nsIDocumentInlines.h
+@@ -52,9 +52,22 @@ nsIDocument::FindDocStyleSheetInsertionP
+         break;
+       }
+     }
+   }
+ 
+   return size_t(index);
+ }
+ 
++inline void
++nsIDocument::SetServoRestyleRoot(nsINode* aRoot, uint32_t aDirtyBits)
++{
++  MOZ_ASSERT(aRoot);
++  MOZ_ASSERT(aDirtyBits);
++  MOZ_ASSERT((aDirtyBits & ~Element::kAllServoDescendantBits) == 0);
++
++  MOZ_ASSERT(aRoot == aRoot->OwnerDocAsNode() ||
++             (aRoot->IsElement() && aRoot->IsInComposedDoc()));
++  mServoRestyleRoot = aRoot;
++  mServoRestyleRootDirtyBits = aDirtyBits;
++}
++
+ #endif // nsIDocumentInlines_h
+diff --git a/dom/base/nsWrapperCache.h b/dom/base/nsWrapperCache.h
+--- a/dom/base/nsWrapperCache.h
++++ b/dom/base/nsWrapperCache.h
+@@ -259,16 +259,30 @@ public:
+   }
+ 
+   bool HasFlag(FlagsType aFlag) const
+   {
+     MOZ_ASSERT((aFlag & kWrapperFlagsMask) == 0, "Bad flag mask");
+     return !!(mFlags & aFlag);
+   }
+ 
++  // Identical to HasFlag, but more explicit about its handling of multiple
++  // flags.
++  bool HasAnyOfFlags(FlagsType aFlags) const
++  {
++    MOZ_ASSERT((aFlags & kWrapperFlagsMask) == 0, "Bad flag mask");
++    return !!(mFlags & aFlags);
++  }
++
++  bool HasAllFlags(FlagsType aFlags) const
++  {
++    MOZ_ASSERT((aFlags & kWrapperFlagsMask) == 0, "Bad flag mask");
++    return (mFlags & aFlags) == aFlags;
++  }
++
+   void SetFlags(FlagsType aFlagsToSet)
+   {
+     MOZ_ASSERT((aFlagsToSet & kWrapperFlagsMask) == 0, "Bad flag mask");
+     mFlags |= aFlagsToSet;
+   }
+ 
+   void UnsetFlags(FlagsType aFlagsToUnset)
+   {
+diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp
+--- a/layout/base/PresShell.cpp
++++ b/layout/base/PresShell.cpp
+@@ -1337,16 +1337,17 @@ PresShell::Destroy()
+   mStyleSet->BeginShutdown();
+   nsRefreshDriver* rd = GetPresContext()->RefreshDriver();
+ 
+   // This shell must be removed from the document before the frame
+   // hierarchy is torn down to avoid finding deleted frames through
+   // this presshell while the frames are being torn down
+   if (mDocument) {
+     NS_ASSERTION(mDocument->GetShell() == this, "Wrong shell?");
++    mDocument->ClearServoRestyleRoot();
+     mDocument->DeleteShell();
+ 
+     if (mDocument->HasAnimationController()) {
+       mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
+     }
+     for (DocumentTimeline* timeline : mDocument->Timelines()) {
+       timeline->NotifyRefreshDriverDestroying(rd);
+     }
+diff --git a/layout/base/ServoRestyleManager.cpp b/layout/base/ServoRestyleManager.cpp
+--- a/layout/base/ServoRestyleManager.cpp
++++ b/layout/base/ServoRestyleManager.cpp
+@@ -418,19 +418,17 @@ ServoRestyleManager::ClearRestyleStateFr
+       if (n->IsElement()) {
+         ClearRestyleStateFromSubtree(n->AsElement());
+       }
+     }
+   }
+ 
+   bool wasRestyled;
+   Unused << Servo_TakeChangeHint(aElement, &wasRestyled);
+-  aElement->UnsetHasDirtyDescendantsForServo();
+-  aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
+-  aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
++  aElement->UnsetFlags(Element::kAllServoDescendantBits);
+ }
+ 
+ /**
+  * This struct takes care of encapsulating some common state that text nodes may
+  * need to track during the post-traversal.
+  *
+  * This is currently used to properly compute change hints when the parent
+  * element of this node is a display: contents node, and also to avoid computing
+@@ -629,24 +627,16 @@ UpdateFramePseudoElementStyles(nsIFrame*
+   if (aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
+     static_cast<nsBlockFrame*>(aFrame)->UpdatePseudoElementStyles(aRestyleState);
+   }
+ 
+   UpdateBackdropIfNeeded(
+     aFrame, aRestyleState.StyleSet(), aRestyleState.ChangeList());
+ }
+ 
+-static inline bool
+-NeedsToTraverseElementChildren(const Element& aParent)
+-{
+-  return aParent.HasAnimationOnlyDirtyDescendantsForServo() ||
+-         aParent.HasDirtyDescendantsForServo() ||
+-         aParent.HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
+-}
+-
+ bool
+ ServoRestyleManager::ProcessPostTraversal(
+   Element* aElement,
+   ServoStyleContext* aParentContext,
+   ServoRestyleState& aRestyleState,
+   ServoTraversalFlags aFlags,
+   bool aParentWasRestyled)
+ {
+@@ -808,20 +798,19 @@ ServoRestyleManager::ProcessPostTraversa
+     // Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
+     // style or not, we need to call it *after* setting |newContext| to
+     // |styleFrame| to ensure the animated transform has been removed first.
+     AddLayerChangesForAnimation(
+       styleFrame, aElement, aRestyleState.ChangeList());
+   }
+ 
+   const bool traverseElementChildren =
+-    NeedsToTraverseElementChildren(*aElement);
+-  const bool descendantsNeedFrames =
+-    aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
+-  const bool traverseTextChildren = wasRestyled || descendantsNeedFrames;
++    aElement->HasAnyOfFlags(Element::kAllServoDescendantBits);
++  const bool traverseTextChildren =
++    wasRestyled || aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
+   bool recreatedAnyContext = wasRestyled;
+   if (traverseElementChildren || traverseTextChildren) {
+     StyleChildrenIterator it(aElement);
+     TextPostTraversalState textState(*upToDateContext,
+                                      displayContentsStyle && wasRestyled,
+                                      childrenRestyleState);
+     for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
+       if (traverseElementChildren && n->IsElement()) {
+@@ -866,20 +855,17 @@ ServoRestyleManager::ProcessPostTraversa
+       if (firstLineFrame) {
+         for (nsIFrame* kid : firstLineFrame->PrincipalChildList()) {
+           ReparentStyleContext(kid);
+         }
+       }
+     }
+   }
+ 
+-  aElement->UnsetHasDirtyDescendantsForServo();
+-  aElement->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
+-  aElement->UnsetHasAnimationOnlyDirtyDescendantsForServo();
+-
++  aElement->UnsetFlags(Element::kAllServoDescendantBits);
+   return recreatedAnyContext;
+ }
+ 
+ bool
+ ServoRestyleManager::ProcessPostTraversalForText(
+     nsIContent* aTextNode,
+     TextPostTraversalState& aPostTraversalState,
+     ServoRestyleState& aRestyleState,
+@@ -951,18 +937,29 @@ ServoRestyleManager::SnapshotFor(Element
+   // Can't wait to make ProcessPendingRestyles the only entry-point for styling,
+   // so this becomes much easier to reason about. Today is not that day though.
+   MOZ_ASSERT(aElement->HasServoData());
+   MOZ_ASSERT(!aElement->HasFlag(ELEMENT_HANDLED_SNAPSHOT));
+ 
+   ServoElementSnapshot* snapshot = mSnapshots.LookupOrAdd(aElement, aElement);
+   aElement->SetFlags(ELEMENT_HAS_SNAPSHOT);
+ 
+-  nsIPresShell* presShell = mPresContext->PresShell();
+-  presShell->EnsureStyleFlush();
++  // Now that we have a snapshot, make sure a restyle is triggered.
++  //
++  // If we have any later siblings, we need to flag the restyle on the parent,
++  // so that a traversal from the restyle root is guaranteed to reach those
++  // siblings (since the snapshot may generate hints for later siblings).
++  if (aElement->GetNextElementSibling()) {
++    Element* parent = aElement->GetFlattenedTreeParentElementForStyle();
++    MOZ_ASSERT(parent);
++    parent->NoteDirtyForServo();
++    parent->SetHasDirtyDescendantsForServo();
++  } else {
++    aElement->NoteDirtyForServo();
++  }
+ 
+   return *snapshot;
+ }
+ 
+ void
+ ServoRestyleManager::DoProcessPendingRestyles(ServoTraversalFlags aFlags)
+ {
+   MOZ_ASSERT(PresContext()->Document(), "No document?  Pshaw!");
+@@ -998,36 +995,47 @@ ServoRestyleManager::DoProcessPendingRes
+   if (mHaveNonAnimationRestyles) {
+     ++mAnimationGeneration;
+   }
+ 
+   if (mRestyleForCSSRuleChanges) {
+     aFlags |= ServoTraversalFlags::ForCSSRuleChanges;
+   }
+ 
+-  while (styleSet->StyleDocument(aFlags)) {
++  while (doc->GetServoRestyleRoot()) {
++    // Do the servo traversal.
++    bool needsPostTraversal = styleSet->StyleDocument(aFlags);
++
++    // If we don't need a post-traversal, we're done.
++    if (!needsPostTraversal) {
++      doc->ClearServoRestyleRoot();
++      break;
++    }
++
+     ClearSnapshots();
+ 
+     nsStyleChangeList currentChanges(StyleBackendType::Servo);
+     bool anyStyleChanged = false;
+ 
+     // Recreate style contexts, and queue up change hints (which also handle
+     // lazy frame construction).
+     {
+       AutoRestyleTimelineMarker marker(mPresContext->GetDocShell(), false);
+-      DocumentStyleRootIterator iter(doc);
++      DocumentStyleRootIterator iter(doc->GetServoRestyleRoot());
+       while (Element* root = iter.GetNextStyleRoot()) {
+         nsTArray<nsIFrame*> wrappersToRestyle;
+         ServoRestyleState state(*styleSet, currentChanges, wrappersToRestyle);
+         anyStyleChanged |=
+           ProcessPostTraversal(root, nullptr, state, aFlags,
+                                /* aParentWasRestyled = */ false);
+       }
+     }
+ 
++    doc->ClearServoRestyleRoot();
++
+     // Process the change hints.
+     //
+     // Unfortunately, the frame constructor can generate new change hints while
+     // processing existing ones. We redirect those into a secondary queue and
+     // iterate until there's nothing left.
+     {
+       AutoTimelineMarker marker(
+         mPresContext->GetDocShell(), "StylesApplyChanges");
+@@ -1151,18 +1159,16 @@ ServoRestyleManager::ContentStateChanged
+       !StyleSet()->HasStateDependency(*aElement, aChangedBits)) {
+     return;
+   }
+ 
+   ServoElementSnapshot& snapshot = SnapshotFor(aElement);
+   EventStates previousState = aElement->StyleState() ^ aChangedBits;
+   snapshot.AddState(previousState);
+ 
+-  aElement->NoteDirtyForServo();
+-
+   if (restyleHint || changeHint) {
+     Servo_NoteExplicitHints(aElement, restyleHint, changeHint);
+   }
+ 
+   // Assuming we need to invalidate cached style in getComputedStyle for
+   // undisplayed elements, since we don't know if it is needed.
+   IncrementUndisplayedRestyleGeneration();
+ }
+@@ -1270,18 +1276,16 @@ ServoRestyleManager::TakeSnapshotForAttr
+   mHaveNonAnimationRestyles = true;
+ 
+   ServoElementSnapshot& snapshot = SnapshotFor(aElement);
+   snapshot.AddAttrs(aElement, aNameSpaceID, aAttribute);
+ 
+   if (influencesOtherPseudoClassState) {
+     snapshot.AddOtherPseudoClassState(aElement);
+   }
+-
+-  aElement->NoteDirtyForServo();
+ }
+ 
+ // For some attribute changes we must restyle the whole subtree:
+ //
+ // * <td> is affected by the cellpadding on its ancestor table
+ // * lang="" and xml:lang="" can affect all descendants due to :lang()
+ //
+ static inline bool
+diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
+--- a/layout/base/nsCSSFrameConstructor.cpp
++++ b/layout/base/nsCSSFrameConstructor.cpp
+@@ -24,16 +24,17 @@
+ #include "mozilla/ServoBindings.h"
+ #include "nsAbsoluteContainingBlock.h"
+ #include "nsCSSPseudoElements.h"
+ #include "nsIAtom.h"
+ #include "nsIFrameInlines.h"
+ #include "nsGkAtoms.h"
+ #include "nsPresContext.h"
+ #include "nsIDocument.h"
++#include "nsIDocumentInlines.h"
+ #include "nsTableFrame.h"
+ #include "nsTableColFrame.h"
+ #include "nsTableRowFrame.h"
+ #include "nsTableCellFrame.h"
+ #include "nsIDOMHTMLDocument.h"
+ #include "nsHTMLParts.h"
+ #include "nsIPresShell.h"
+ #include "nsUnicharUtils.h"
+@@ -2543,16 +2544,19 @@ nsCSSFrameConstructor::ConstructDocEleme
+   // have stale restyle bits from a previous frame constructor for
+   // this document.  Unlike in AddFrameConstructionItems, it's safe to
+   // unset all element restyle flags, since we don't have any
+   // siblings.
+   aDocElement->UnsetRestyleFlagsIfGecko();
+ 
+   // --------- CREATE AREA OR BOX FRAME -------
+   if (ServoStyleSet* set = mPresShell->StyleSet()->GetAsServo()) {
++    // We need to explicitly set a restyle root for the first traversal.
++    aDocElement->OwnerDoc()->SetServoRestyleRoot(aDocElement->OwnerDocAsNode(),
++                                                 ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
+     // NOTE(emilio): If the root has a non-null binding, we'll stop at the
+     // document element and won't process any children, loading the bindings (or
+     // failing to do so) will take care of the rest.
+     set->StyleDocument(ServoTraversalFlags::Empty);
+   }
+ 
+   // FIXME: Should this use ResolveStyleContext?  (The calls in this
+   // function are the only case in nsCSSFrameConstructor where we don't
+@@ -7212,16 +7216,62 @@ nsCSSFrameConstructor::ReframeTextIfNeed
+     // NS_CREATE_FRAME_IF_NON_WHITESPACE flag)
+     return;
+   }
+   NS_ASSERTION(!aContent->GetPrimaryFrame(),
+                "Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
+   ContentInserted(aParentContent, aContent, nullptr, false);
+ }
+ 
++#ifdef DEBUG
++void
++nsCSSFrameConstructor::CheckBitsForLazyFrameConstruction(nsIContent* aParent)
++{
++  // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
++  // we want to assert, but leaf frames that process their own children and may
++  // ignore anonymous children (eg framesets) make this complicated. So we set
++  // these two booleans if we encounter these situations and unset them if we
++  // hit a node with a leaf frame.
++  //
++  // It's fine if one of node without primary frame is in a display:none
++  // subtree.
++  //
++  // Also, it's fine if one of the nodes without primary frame is a display:
++  // contents node except if it's the direct ancestor of the children we're
++  // recreating frames for.
++  bool noPrimaryFrame = false;
++  bool needsFrameBitSet = false;
++  nsIContent* content = aParent;
++  while (content &&
++         !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
++    if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
++      noPrimaryFrame = needsFrameBitSet = false;
++    }
++    if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
++      nsStyleContext* sc = GetDisplayNoneStyleFor(content);
++      noPrimaryFrame = !GetDisplayContentsStyleFor(content) &&
++        (sc && !sc->IsInDisplayNoneSubtree());
++    }
++    if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
++      needsFrameBitSet = true;
++    }
++
++    content = content->GetFlattenedTreeParent();
++  }
++  if (content && content->GetPrimaryFrame() &&
++      content->GetPrimaryFrame()->IsLeaf()) {
++    noPrimaryFrame = needsFrameBitSet = false;
++  }
++  NS_ASSERTION(!noPrimaryFrame, "Ancestors of nodes with frames to be "
++    "constructed lazily should have frames");
++  NS_ASSERTION(!needsFrameBitSet, "Ancestors of nodes with frames to be "
++    "constructed lazily should not have NEEDS_FRAME bit set");
++}
++#endif
++
+ // For inserts aChild should be valid, for appends it should be null.
+ // Returns true if this operation can be lazy, false if not.
+ bool
+ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
+                                             nsIContent* aContainer,
+                                             nsIContent* aChild)
+ {
+   // XXXmats no lazy frames for display:contents direct descendants yet
+@@ -7249,64 +7299,16 @@ nsCSSFrameConstructor::MaybeConstructLaz
+         return false;
+       }
+     }
+   }
+ 
+   // We can construct lazily; just need to set suitable bits in the content
+   // tree.
+ 
+-  // Walk up the tree setting the NODE_DESCENDANTS_NEED_FRAMES bit as we go.
+-  nsIContent* content = aChild->GetFlattenedTreeParent();
+-
+-#ifdef DEBUG
+-  // If we hit a node with no primary frame, or the NODE_NEEDS_FRAME bit set
+-  // we want to assert, but leaf frames that process their own children and may
+-  // ignore anonymous children (eg framesets) make this complicated. So we set
+-  // these two booleans if we encounter these situations and unset them if we
+-  // hit a node with a leaf frame.
+-  //
+-  // It's fine if one of node without primary frame is in a display:none
+-  // subtree.
+-  //
+-  // Also, it's fine if one of the nodes without primary frame is a display:
+-  // contents node except if it's the direct ancestor of the children we're
+-  // recreating frames for.
+-  bool noPrimaryFrame = false;
+-  bool needsFrameBitSet = false;
+-#endif
+-  while (content &&
+-         !content->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
+-#ifdef DEBUG
+-    if (content->GetPrimaryFrame() && content->GetPrimaryFrame()->IsLeaf()) {
+-      noPrimaryFrame = needsFrameBitSet = false;
+-    }
+-    if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
+-      nsStyleContext* sc = GetDisplayNoneStyleFor(content);
+-      noPrimaryFrame = !GetDisplayContentsStyleFor(content) &&
+-        (sc && !sc->IsInDisplayNoneSubtree());
+-    }
+-    if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
+-      needsFrameBitSet = true;
+-    }
+-#endif
+-    content->SetFlags(NODE_DESCENDANTS_NEED_FRAMES);
+-    content = content->GetFlattenedTreeParent();
+-  }
+-#ifdef DEBUG
+-  if (content && content->GetPrimaryFrame() &&
+-      content->GetPrimaryFrame()->IsLeaf()) {
+-    noPrimaryFrame = needsFrameBitSet = false;
+-  }
+-  NS_ASSERTION(!noPrimaryFrame, "Ancestors of nodes with frames to be "
+-    "constructed lazily should have frames");
+-  NS_ASSERTION(!needsFrameBitSet, "Ancestors of nodes with frames to be "
+-    "constructed lazily should not have NEEDS_FRAME bit set");
+-#endif
+-
+   // Set NODE_NEEDS_FRAME on the new nodes.
+   if (aOperation == CONTENTINSERT) {
+     NS_ASSERTION(!aChild->GetPrimaryFrame() ||
+                  aChild->GetPrimaryFrame()->GetContent() != aChild,
+                  //XXX the aChild->GetPrimaryFrame()->GetContent() != aChild
+                  // check is needed due to bug 135040. Remove it once that's
+                  // fixed.
+                  "setting NEEDS_FRAME on a node that already has a frame?");
+@@ -7318,18 +7320,29 @@ nsCSSFrameConstructor::MaybeConstructLaz
+                    //XXX the child->GetPrimaryFrame()->GetContent() != child
+                    // check is needed due to bug 135040. Remove it once that's
+                    // fixed.
+                    "setting NEEDS_FRAME on a node that already has a frame?");
+       child->SetFlags(NODE_NEEDS_FRAME);
+     }
+   }
+ 
++  // Walk up the tree setting the NODE_DESCENDANTS_NEED_FRAMES bit as we go.
++  // We need different handling for servo given the scoped restyle roots.
++  nsIContent* parent = aChild->GetFlattenedTreeParent();
++  CheckBitsForLazyFrameConstruction(parent);
++
+   if (mozilla::GeckoRestyleManager* geckoRM = RestyleManager()->GetAsGecko()) {
++    while (parent && !parent->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
++      parent->SetFlags(NODE_DESCENDANTS_NEED_FRAMES);
++      parent = parent->GetFlattenedTreeParent();
++    }
+     geckoRM->PostRestyleEventForLazyConstruction();
++  } else {
++    parent->AsElement()->NoteDescendantsNeedFramesForServo();
+   }
+ 
+   return true;
+ }
+ 
+ void
+ nsCSSFrameConstructor::CreateNeededFrames(
+     nsIContent* aContent,
+@@ -7550,21 +7563,16 @@ nsCSSFrameConstructor::LazilyStyleNewChi
+                                                 nsIContent* aEndChild)
+ {
+   for (nsIContent* child = aStartChild; child != aEndChild;
+        child = child->GetNextSibling()) {
+     if (child->IsElement()) {
+       child->AsElement()->NoteDirtyForServo();
+     }
+   }
+-
+-  // NoteDirtyForServo() will ensure a style flush, but we don't invoke it for
+-  // text nodes. So since this range might include no elements, we still need
+-  // to manually ensure a style flush.
+-  mPresShell->EnsureStyleFlush();
+ }
+ 
+ void
+ nsCSSFrameConstructor::StyleNewChildRange(nsIContent* aStartChild,
+                                           nsIContent* aEndChild)
+ {
+   ServoStyleSet* styleSet = mPresShell->StyleSet()->AsServo();
+ 
+diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h
+--- a/layout/base/nsCSSFrameConstructor.h
++++ b/layout/base/nsCSSFrameConstructor.h
+@@ -97,16 +97,22 @@ private:
+   };
+ 
+   // aChild is the child being inserted for inserts, and the first
+   // child being appended for appends.
+   bool MaybeConstructLazily(Operation aOperation,
+                               nsIContent* aContainer,
+                               nsIContent* aChild);
+ 
++#ifdef DEBUG
++  void CheckBitsForLazyFrameConstruction(nsIContent* aParent);
++#else
++  void CheckBitsForLazyFrameConstruction(nsIContent*) {}
++#endif
++
+   // Issues a single ContentInserted for each child of aContainer in the range
+   // [aStartChild, aEndChild).
+   void IssueSingleInsertNofications(nsIContent* aContainer,
+                                     nsIContent* aStartChild,
+                                     nsIContent* aEndChild,
+                                     bool aAllowLazyConstruction,
+                                     bool aForReconstruction);
+ 
+diff --git a/layout/style/DocumentStyleRootIterator.cpp b/layout/style/DocumentStyleRootIterator.cpp
+--- a/layout/style/DocumentStyleRootIterator.cpp
++++ b/layout/style/DocumentStyleRootIterator.cpp
+@@ -6,25 +6,33 @@
+ 
+ #include "DocumentStyleRootIterator.h"
+ 
+ #include "mozilla/dom/Element.h"
+ #include "nsContentUtils.h"
+ 
+ namespace mozilla {
+ 
+-DocumentStyleRootIterator::DocumentStyleRootIterator(nsIDocument* aDocument)
++DocumentStyleRootIterator::DocumentStyleRootIterator(nsINode* aStyleRoot)
+   : mPosition(0)
+ {
+   MOZ_COUNT_CTOR(DocumentStyleRootIterator);
+-  if (Element* root = aDocument->GetRootElement()) {
++  MOZ_ASSERT(aStyleRoot);
++  if (aStyleRoot->IsElement()) {
++    mStyleRoots.AppendElement(aStyleRoot->AsElement());
++    return;
++  }
++
++  nsIDocument* doc = aStyleRoot->OwnerDoc();
++  MOZ_ASSERT(doc == aStyleRoot);
++  if (Element* root = doc->GetRootElement()) {
+     mStyleRoots.AppendElement(root);
+   }
+   nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
+-      aDocument, mStyleRoots);
++      doc, mStyleRoots);
+ }
+ 
+ Element*
+ DocumentStyleRootIterator::GetNextStyleRoot()
+ {
+   for (;;) {
+     if (mPosition >= mStyleRoots.Length()) {
+       return nullptr;
+diff --git a/layout/style/DocumentStyleRootIterator.h b/layout/style/DocumentStyleRootIterator.h
+--- a/layout/style/DocumentStyleRootIterator.h
++++ b/layout/style/DocumentStyleRootIterator.h
+@@ -15,23 +15,27 @@ class nsIDocument;
+ namespace mozilla {
+ 
+ namespace dom {
+ class Element;
+ } // namespace dom
+ 
+ /**
+  * DocumentStyleRootIterator traverses the roots of the document from the
+- * perspective of the Servo-backed style system.  This will first traverse
+- * the document root, followed by any document level native anonymous content.
++ * perspective of the Servo-backed style system. In the general case, this
++ * will first traverse the document root, followed by any document level
++ * native anonymous content.
++ *
++ * If the caller passes an element to the constructor rather than the document,
++ * that element (and nothing else) is returned from GetNextStyleRoot.
+  */
+ class DocumentStyleRootIterator
+ {
+ public:
+-  explicit DocumentStyleRootIterator(nsIDocument* aDocument);
++  explicit DocumentStyleRootIterator(nsINode* aStyleRoot);
+   ~DocumentStyleRootIterator() { MOZ_COUNT_DTOR(DocumentStyleRootIterator); }
+ 
+   dom::Element* GetNextStyleRoot();
+ 
+ private:
+   AutoTArray<nsIContent*, 8> mStyleRoots;
+   uint32_t mPosition;
+ };
+diff --git a/layout/style/ServoBindingList.h b/layout/style/ServoBindingList.h
+--- a/layout/style/ServoBindingList.h
++++ b/layout/style/ServoBindingList.h
+@@ -28,16 +28,19 @@ SERVO_BINDING_FUNC(Servo_Element_HasPrim
+ SERVO_BINDING_FUNC(Servo_Element_GetPrimaryComputedValues,
+                    ServoStyleContextStrong,
+                    RawGeckoElementBorrowed node)
+ SERVO_BINDING_FUNC(Servo_Element_HasPseudoComputedValues, bool,
+                    RawGeckoElementBorrowed node, size_t index)
+ SERVO_BINDING_FUNC(Servo_Element_GetPseudoComputedValues,
+                    ServoStyleContextStrong,
+                    RawGeckoElementBorrowed node, size_t index)
++SERVO_BINDING_FUNC(Servo_Element_IsDisplayNone,
++                   bool,
++                   RawGeckoElementBorrowed element)
+ 
+ // Styleset and Stylesheet management
+ SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetContentsStrong,
+                    mozilla::css::Loader* loader,
+                    mozilla::ServoStyleSheet* gecko_stylesheet,
+                    const nsACString* data,
+                    mozilla::css::SheetParsingMode parsing_mode,
+                    RawGeckoURLExtraData* extra_data,
+diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp
+--- a/layout/style/ServoStyleSet.cpp
++++ b/layout/style/ServoStyleSet.cpp
+@@ -854,69 +854,81 @@ ServoStyleSet::HasStateDependentStyle(do
+   NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
+   return nsRestyleHint(0);
+ }
+ 
+ bool
+ ServoStyleSet::StyleDocument(ServoTraversalFlags aBaseFlags)
+ {
+   PreTraverse(aBaseFlags);
++  AutoPrepareTraversal guard(this);
++  const SnapshotTable& snapshots = Snapshots();
+ 
+   // Restyle the document from the root element and each of the document level
+   // NAC subtree roots.
+   bool postTraversalRequired = false;
+-  DocumentStyleRootIterator iter(mPresContext->Document());
++
++  nsIDocument* doc = mPresContext->Document();
++  Element* rootElement = doc->GetRootElement();
++  // NB: We distinguish between the main document and document-level NAC here.
++  const bool isInitialForMainDoc = rootElement && !rootElement->HasServoData();
++
++  // Do the first traversal.
++  DocumentStyleRootIterator iter(doc->GetServoRestyleRoot());
+   while (Element* root = iter.GetNextStyleRoot()) {
+     MOZ_ASSERT(MayTraverseFrom(const_cast<Element*>(root)));
+-    AutoPrepareTraversal guard(this);
+-    const SnapshotTable& snapshots = Snapshots();
+-    bool isInitial = !root->HasServoData();
+-    auto flags = aBaseFlags;
+ 
+     // If there were text nodes inserted into the document (but not elements),
+     // there may be lazy frame construction to do even if no styling is required.
+     postTraversalRequired |= root->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
+ 
+     // Allow the parallel traversal, unless we're traversing traversing one of
+     // the native anonymous document style roots, which are tiny and not worth
+     // parallelizing over.
+     //
+     // We only allow the parallel traversal in active (foreground) tabs.
++    auto flags = aBaseFlags;
+     if (!root->IsInNativeAnonymousSubtree() && mPresContext->PresShell()->IsActive()) {
+       flags |= ServoTraversalFlags::ParallelTraversal;
+     }
+ 
+-    // Do the first traversal.
+     bool required = Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, flags);
+-    MOZ_ASSERT_IF(isInitial, !required);
+     postTraversalRequired |= required;
++  }
+ 
+-    // If there are still animation restyles needed, trigger a second traversal to
+-    // update CSS animations or transitions' styles.
+-    //
+-    // We don't need to do this for SMIL since SMIL only updates its animation
+-    // values once at the begin of a tick. As a result, even if the previous
+-    // traversal caused, for example, the font-size to change, the SMIL style
+-    // won't be updated until the next tick anyway.
+-    if (mPresContext->EffectCompositor()->PreTraverse(flags)) {
+-      if (isInitial) {
+-        // We're doing initial styling, and the additional animation
+-        // traversal will change the styles that were set by the first traversal.
+-        // This would normally require a post-traversal to update the style
+-        // contexts, but since this is actually the initial styling, there are
+-        // no style contexts to update and no frames to apply the change hints to,
+-        // so we just do a forgetful traversal and clear the flags on the way.
+-        flags |= ServoTraversalFlags::Forgetful |
+-                 ServoTraversalFlags::ClearAnimationOnlyDirtyDescendants;
+-      }
++  // If there are still animation restyles needed, trigger a second traversal to
++  // update CSS animations or transitions' styles.
++  //
++  // Note that we need to check the style root again, because doing another
++  // PreTraverse on the EffectCompositor might alter the style root. But we
++  // don't need to worry about NAC, since document-level NAC shouldn't have
++  // animations.
++  //
++  // We don't need to do this for SMIL since SMIL only updates its animation
++  // values once at the begin of a tick. As a result, even if the previous
++  // traversal caused, for example, the font-size to change, the SMIL style
++  // won't be updated until the next tick anyway.
++  if (mPresContext->EffectCompositor()->PreTraverse(aBaseFlags)) {
++    nsINode* styleRoot = doc->GetServoRestyleRoot();
++    Element* root = styleRoot->IsElement() ? styleRoot->AsElement() : rootElement;
++    auto flags = aBaseFlags;
++    flags |= ServoTraversalFlags::ParallelTraversal;
++    if (isInitialForMainDoc) {
++      // We're doing initial styling, and the additional animation
++      // traversal will change the styles that were set by the first traversal.
++      // This would normally require a post-traversal to update the style
++      // contexts, but since this is actually the initial styling, there are
++      // no style contexts to update and no frames to apply the change hints to,
++      // so we just do a forgetful traversal and clear the flags on the way.
++      flags |= ServoTraversalFlags::Forgetful |
++               ServoTraversalFlags::ClearAnimationOnlyDirtyDescendants;
++    }
+ 
+-      required = Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, flags);
+-      MOZ_ASSERT_IF(isInitial, !required);
+-      postTraversalRequired |= required;
+-    }
++    bool required = Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, flags);
++    postTraversalRequired |= required;
+   }
+ 
+   return postTraversalRequired;
+ }
+ 
+ void
+ ServoStyleSet::StyleNewSubtree(Element* aRoot)
+ {
+@@ -944,16 +956,20 @@ ServoStyleSet::StyleNewSubtree(Element* 
+     MOZ_ASSERT(!postTraversalRequired);
+   }
+ }
+ 
+ void
+ ServoStyleSet::StyleNewChildren(Element* aParent)
+ {
+   MOZ_ASSERT(aParent->HasServoData(), "Should have called StyleNewSubtree");
++  if (Servo_Element_IsDisplayNone(aParent)) {
++    return;
++  }
++
+   PreTraverseSync();
+   AutoPrepareTraversal guard(this);
+ 
+   // Implementing StyleNewChildren correctly is very annoying, for two reasons:
+   // (1) We have to tiptoe around existing invalidations in the tree. In rare
+   //     cases Gecko calls into the frame constructor with pending invalidations,
+   //     and in other rare cases the frame constructor needs to perform
+   //     synchronous styling rather than using the normal lazy frame
+@@ -1013,20 +1029,35 @@ ServoStyleSet::StyleNewlyBoundElement(El
+   }
+ }
+ 
+ void
+ ServoStyleSet::StyleSubtreeForReconstruct(Element* aRoot)
+ {
+   MOZ_ASSERT(MayTraverseFrom(aRoot));
+   MOZ_ASSERT(aRoot->HasServoData());
++
++  // If the restyle root is beneath |aRoot|, there won't be any descendants bit
++  // leading us to aRoot. In this case, we need to traverse from the restyle
++  // root instead.
++  nsIDocument* doc = mPresContext->Document();
++  nsINode* restyleRoot = doc->GetServoRestyleRoot();
++  if (!restyleRoot) {
++    return;
++  }
++  Element* el = restyleRoot->IsElement() ? restyleRoot->AsElement() : nullptr;
++  if (el && nsContentUtils::ContentIsFlattenedTreeDescendantOf(el, aRoot)) {
++    MOZ_ASSERT(MayTraverseFrom(el));
++    aRoot = el;
++    doc->ClearServoRestyleRoot();
++  }
++
+   auto flags = ServoTraversalFlags::Forgetful |
+                ServoTraversalFlags::AggressivelyForgetful |
+-               ServoTraversalFlags::ClearDirtyDescendants |
+-               ServoTraversalFlags::ClearAnimationOnlyDirtyDescendants;
++               ServoTraversalFlags::ClearDirtyBits;
+   PreTraverse(flags);
+ 
+   AutoPrepareTraversal guard(this);
+ 
+   const SnapshotTable& snapshots = Snapshots();
+ 
+   DebugOnly<bool> postTraversalRequired =
+     Servo_TraverseSubtree(aRoot, mRawSet.get(), &snapshots, flags);
+@@ -1382,18 +1413,17 @@ ServoStyleSet::MayTraverseFrom(Element* 
+   if (!parent) {
+     return true;
+   }
+ 
+   if (!parent->HasServoData()) {
+     return false;
+   }
+ 
+-  RefPtr<ServoStyleContext> sc = Servo_ResolveStyleAllowStale(parent).Consume();
+-  return sc->StyleDisplay()->mDisplay != StyleDisplay::None;
++  return !Servo_Element_IsDisplayNone(parent);
+ }
+ 
+ void
+ ServoStyleSet::PrependSheetOfType(SheetType aType,
+                                   ServoStyleSheet* aSheet)
+ {
+   aSheet->AddStyleSet(this);
+   mSheets[aType].InsertElementAt(0, aSheet);
+diff --git a/layout/style/ServoTypes.h b/layout/style/ServoTypes.h
+--- a/layout/style/ServoTypes.h
++++ b/layout/style/ServoTypes.h
+@@ -65,19 +65,21 @@ enum class ServoTraversalFlags : uint32_
+   // A forgetful traversal ignores the previous state of the frame tree, and
+   // thus does not compute damage or maintain other state describing the styles
+   // pre-traversal. A forgetful traversal is usually the right thing if you
+   // aren't going to do a post-traversal.
+   Forgetful = 1 << 3,
+   // Actively seeks out and clears change hints that may have been posted into
+   // the tree. Nonsensical without also passing Forgetful.
+   AggressivelyForgetful = 1 << 4,
+-  // Clears the dirty descendants bit in the subtree.
+-  ClearDirtyDescendants = 1 << 5,
+-  // Clears the animation-only dirty descendants bit in the subtree.
++  // Clears all the dirty bits (dirty descendants, animation-only dirty-descendants,
++  // needs frame, descendants need frames) on the elements traversed.
++  // in the subtree.
++  ClearDirtyBits = 1 << 5,
++  // Clears only the animation-only dirty descendants bit in the subtree.
+   ClearAnimationOnlyDirtyDescendants = 1 << 6,
+   // Allows the traversal to run in parallel if there are sufficient cores on
+   // the machine.
+   ParallelTraversal = 1 << 7,
+   // Flush throttled animations. By default, we only update throttled animations
+   // when we have other non-throttled work to do. With this flag, we
+   // unconditionally tick and process them.
+   FlushThrottledAnimations = 1 << 8,
+diff --git a/testing/web-platform/meta/css/css-writing-modes-3/text-orientation-script-001.html.ini b/testing/web-platform/meta/css/css-writing-modes-3/text-orientation-script-001.html.ini
+--- a/testing/web-platform/meta/css/css-writing-modes-3/text-orientation-script-001.html.ini
++++ b/testing/web-platform/meta/css/css-writing-modes-3/text-orientation-script-001.html.ini
+@@ -1,12 +1,11 @@
+ [text-orientation-script-001.html]
+   type: testharness
+   expected:
+-    if stylo: TIMEOUT
+   [Default orientation for vo=R]
+     expected: FAIL
+ 
+   [Default orientation for vo=U]
+     expected: FAIL
+ 
+   [Default orientation for vo=Tr]
+     expected: FAIL

+ 25 - 0
frg/253-58/mozilla-release58_428220.patch

@@ -0,0 +1,25 @@
+# HG changeset patch
+# User Bobby Holley <bobbyholley@gmail.com>
+# Date 1503465304 25200
+#      Tue Aug 22 22:15:04 2017 -0700
+# Node ID 6bfd9f6f99c3e7b16c30629aba07013a4eba6a0a
+# Parent  7fa4d82e8c0936f3c586fdb69174aeddcffb0b81
+Bug 1383332 - Use correct annotation syntax. r=me
+
+MozReview-Commit-ID: BcUGGhuCIOL
+
+diff --git a/testing/web-platform/meta/css/css-writing-modes-3/text-orientation-script-001.html.ini b/testing/web-platform/meta/css/css-writing-modes-3/text-orientation-script-001.html.ini
+--- a/testing/web-platform/meta/css/css-writing-modes-3/text-orientation-script-001.html.ini
++++ b/testing/web-platform/meta/css/css-writing-modes-3/text-orientation-script-001.html.ini
+@@ -1,11 +1,10 @@
+ [text-orientation-script-001.html]
+   type: testharness
+-  expected:
+   [Default orientation for vo=R]
+     expected: FAIL
+ 
+   [Default orientation for vo=U]
+     expected: FAIL
+ 
+   [Default orientation for vo=Tr]
+     expected: FAIL

+ 1980 - 0
frg/253-58/mozilla-release58_428221.patch

@@ -0,0 +1,1980 @@
+# HG changeset patch
+# User Xidorn Quan <me@upsuper.org>
+# Date 1503465871 -36000
+#      Wed Aug 23 15:24:31 2017 +1000
+# Node ID 6b0ed8c3153218760359a86e62c5fd065f60bd98
+# Parent  6bfd9f6f99c3e7b16c30629aba07013a4eba6a0a
+Bug 1370779 followup 3 - Update several web-platform test expectation.
+
+MozReview-Commit-ID: D4ZnLAYk17b
+
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-002.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-002.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-002.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-002.html.ini
+@@ -355,120 +355,8 @@
+     expected: FAIL
+ 
+   [circle(at right 80px bottom 70%) serializes as circle(at right 80px top 30%) - computed]
+     expected: FAIL
+ 
+   [circle(at right 80px bottom 70px) serializes as circle(at right 80px bottom 70px) - computed]
+     expected: FAIL
+ 
+-  [circle(at center 60%) serializes as circle(at 50% 60%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at 60% center) serializes as circle(at 60% 50%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at center right 70%) serializes as circle(at 30% 50%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at center bottom 70%) serializes as circle(at 50% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at left bottom 70%) serializes as circle(at 0% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at top right 70%) serializes as circle(at 30% 0%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at bottom right 70%) serializes as circle(at 30% 100%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at right bottom 70%) serializes as circle(at 100% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at bottom 70% center) serializes as circle(at 50% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at bottom 70% left) serializes as circle(at 0% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at bottom 70% right) serializes as circle(at 100% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at right 80% center) serializes as circle(at 20% 50%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at right 80% bottom) serializes as circle(at 20% 100%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at right 80% top) serializes as circle(at 20% 0%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at left 50% bottom 70%) serializes as circle(at 50% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at left 50px bottom 70%) serializes as circle(at 50px 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at top 50% right 80%) serializes as circle(at 20% 50%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at top 50px right 80%) serializes as circle(at 20% 50px) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at bottom 70% left 50%) serializes as circle(at 50% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at bottom 70% left 50px) serializes as circle(at 50px 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at bottom 70% right 80%) serializes as circle(at 20% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at bottom 70% right 80px) serializes as circle(at right 80px top 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at bottom 70px right 80%) serializes as circle(at left 20% bottom 70px) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at right 80% top 50%) serializes as circle(at 20% 50%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at right 80% top 50px) serializes as circle(at 20% 50px) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at right 80% bottom 70%) serializes as circle(at 20% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at right 80% bottom 70px) serializes as circle(at left 20% bottom 70px) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [circle(at right 80px bottom 70%) serializes as circle(at right 80px top 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-004.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-004.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-004.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-004.html.ini
+@@ -2257,424 +2257,8 @@
+     expected: FAIL
+ 
+   [test unit (computed): vmax - circle(at right 80vmax bottom 70%)]
+     expected: FAIL
+ 
+   [test unit (computed): vmax - circle(at right 80vmax bottom 70vmax)]
+     expected: FAIL
+ 
+-  [test unit (inline): cm - circle(at left 50cm bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - circle(at top 50cm right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - circle(at bottom 70% left 50cm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - circle(at bottom 70% right 80cm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - circle(at bottom 70cm right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - circle(at right 80% top 50cm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - circle(at right 80% bottom 70cm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - circle(at right 80cm bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - circle(at left 50mm bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - circle(at top 50mm right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - circle(at bottom 70% left 50mm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - circle(at bottom 70% right 80mm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - circle(at bottom 70mm right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - circle(at right 80% top 50mm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - circle(at right 80% bottom 70mm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - circle(at right 80mm bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - circle(at left 50in bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - circle(at top 50in right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - circle(at bottom 70% left 50in)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - circle(at bottom 70% right 80in)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - circle(at bottom 70in right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - circle(at right 80% top 50in)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - circle(at right 80% bottom 70in)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - circle(at right 80in bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - circle(at left 50pt bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - circle(at top 50pt right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - circle(at bottom 70% left 50pt)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - circle(at bottom 70% right 80pt)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - circle(at bottom 70pt right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - circle(at right 80% top 50pt)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - circle(at right 80% bottom 70pt)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - circle(at right 80pt bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - circle(at left 50pc bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - circle(at top 50pc right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - circle(at bottom 70% left 50pc)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - circle(at bottom 70% right 80pc)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - circle(at bottom 70pc right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - circle(at right 80% top 50pc)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - circle(at right 80% bottom 70pc)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - circle(at right 80pc bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - circle(at left 50em bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - circle(at top 50em right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - circle(at bottom 70% left 50em)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - circle(at bottom 70% right 80em)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - circle(at bottom 70em right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - circle(at right 80% top 50em)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - circle(at right 80% bottom 70em)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - circle(at right 80em bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - circle(at left 50ex bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - circle(at top 50ex right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - circle(at bottom 70% left 50ex)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - circle(at bottom 70% right 80ex)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - circle(at bottom 70ex right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - circle(at right 80% top 50ex)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - circle(at right 80% bottom 70ex)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - circle(at right 80ex bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - circle(at left 50ch bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - circle(at top 50ch right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - circle(at bottom 70% left 50ch)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - circle(at bottom 70% right 80ch)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - circle(at bottom 70ch right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - circle(at right 80% top 50ch)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - circle(at right 80% bottom 70ch)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - circle(at right 80ch bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - circle(at left 50rem bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - circle(at top 50rem right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - circle(at bottom 70% left 50rem)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - circle(at bottom 70% right 80rem)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - circle(at bottom 70rem right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - circle(at right 80% top 50rem)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - circle(at right 80% bottom 70rem)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - circle(at right 80rem bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - circle(at left 50vw bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - circle(at top 50vw right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - circle(at bottom 70% left 50vw)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - circle(at bottom 70% right 80vw)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - circle(at bottom 70vw right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - circle(at right 80% top 50vw)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - circle(at right 80% bottom 70vw)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - circle(at right 80vw bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - circle(at left 50vh bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - circle(at top 50vh right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - circle(at bottom 70% left 50vh)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - circle(at bottom 70% right 80vh)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - circle(at bottom 70vh right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - circle(at right 80% top 50vh)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - circle(at right 80% bottom 70vh)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - circle(at right 80vh bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - circle(at left 50vmin bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - circle(at top 50vmin right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - circle(at bottom 70% left 50vmin)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - circle(at bottom 70% right 80vmin)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - circle(at bottom 70vmin right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - circle(at right 80% top 50vmin)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - circle(at right 80% bottom 70vmin)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - circle(at right 80vmin bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - circle(at left 50vmax bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - circle(at top 50vmax right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - circle(at bottom 70% left 50vmax)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - circle(at bottom 70% right 80vmax)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - circle(at bottom 70vmax right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - circle(at right 80% top 50vmax)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - circle(at right 80% bottom 70vmax)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - circle(at right 80vmax bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-010.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-010.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-010.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-010.html.ini
+@@ -29,12 +29,8 @@
+ 
+   [circle(calc(25%*3)) - computed style]
+     expected: FAIL
+ 
+   [circle(calc(10in)) - inline style]
+     expected:
+       if stylo: FAIL
+ 
+-  [circle(calc(30%)) - inline style]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-011.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-011.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-011.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-circle-011.html.ini
+@@ -41,12 +41,8 @@
+ 
+   [circle(at calc((12.5%*6 + 10in) / 4)) - computed style]
+     expected: FAIL
+ 
+   [circle(at calc(10in)) - inline style]
+     expected:
+       if stylo: FAIL
+ 
+-  [circle(at calc(30%)) - inline style]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-002.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-002.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-002.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-002.html.ini
+@@ -355,120 +355,8 @@
+     expected: FAIL
+ 
+   [ellipse(at right 80px bottom 70%) serializes as ellipse(at right 80px top 30%) - computed]
+     expected: FAIL
+ 
+   [ellipse(at right 80px bottom 70px) serializes as ellipse(at right 80px bottom 70px) - computed]
+     expected: FAIL
+ 
+-  [ellipse(at center 60%) serializes as ellipse(at 50% 60%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at 60% center) serializes as ellipse(at 60% 50%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at center right 70%) serializes as ellipse(at 30% 50%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at center bottom 70%) serializes as ellipse(at 50% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at left bottom 70%) serializes as ellipse(at 0% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at top right 70%) serializes as ellipse(at 30% 0%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at bottom right 70%) serializes as ellipse(at 30% 100%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at right bottom 70%) serializes as ellipse(at 100% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at bottom 70% center) serializes as ellipse(at 50% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at bottom 70% left) serializes as ellipse(at 0% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at bottom 70% right) serializes as ellipse(at 100% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at right 80% center) serializes as ellipse(at 20% 50%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at right 80% bottom) serializes as ellipse(at 20% 100%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at right 80% top) serializes as ellipse(at 20% 0%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at left 50% bottom 70%) serializes as ellipse(at 50% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at left 50px bottom 70%) serializes as ellipse(at 50px 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at top 50% right 80%) serializes as ellipse(at 20% 50%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at top 50px right 80%) serializes as ellipse(at 20% 50px) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at bottom 70% left 50%) serializes as ellipse(at 50% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at bottom 70% left 50px) serializes as ellipse(at 50px 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at bottom 70% right 80%) serializes as ellipse(at 20% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at bottom 70% right 80px) serializes as ellipse(at right 80px top 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at bottom 70px right 80%) serializes as ellipse(at left 20% bottom 70px) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at right 80% top 50%) serializes as ellipse(at 20% 50%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at right 80% top 50px) serializes as ellipse(at 20% 50px) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at right 80% bottom 70%) serializes as ellipse(at 20% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at right 80% bottom 70px) serializes as ellipse(at left 20% bottom 70px) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(at right 80px bottom 70%) serializes as ellipse(at right 80px top 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-004.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-004.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-004.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-004.html.ini
+@@ -2257,424 +2257,8 @@
+     expected: FAIL
+ 
+   [test unit (computed): vmax - ellipse(at right 80vmax bottom 70%)]
+     expected: FAIL
+ 
+   [test unit (computed): vmax - ellipse(at right 80vmax bottom 70vmax)]
+     expected: FAIL
+ 
+-  [test unit (inline): cm - ellipse(at left 50cm bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - ellipse(at top 50cm right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - ellipse(at bottom 70% left 50cm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - ellipse(at bottom 70% right 80cm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - ellipse(at bottom 70cm right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - ellipse(at right 80% top 50cm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - ellipse(at right 80% bottom 70cm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): cm - ellipse(at right 80cm bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - ellipse(at left 50mm bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - ellipse(at top 50mm right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - ellipse(at bottom 70% left 50mm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - ellipse(at bottom 70% right 80mm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - ellipse(at bottom 70mm right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - ellipse(at right 80% top 50mm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - ellipse(at right 80% bottom 70mm)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): mm - ellipse(at right 80mm bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - ellipse(at left 50in bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - ellipse(at top 50in right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - ellipse(at bottom 70% left 50in)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - ellipse(at bottom 70% right 80in)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - ellipse(at bottom 70in right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - ellipse(at right 80% top 50in)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - ellipse(at right 80% bottom 70in)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): in - ellipse(at right 80in bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - ellipse(at left 50pt bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - ellipse(at top 50pt right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - ellipse(at bottom 70% left 50pt)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - ellipse(at bottom 70% right 80pt)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - ellipse(at bottom 70pt right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - ellipse(at right 80% top 50pt)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - ellipse(at right 80% bottom 70pt)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pt - ellipse(at right 80pt bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - ellipse(at left 50pc bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - ellipse(at top 50pc right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - ellipse(at bottom 70% left 50pc)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - ellipse(at bottom 70% right 80pc)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - ellipse(at bottom 70pc right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - ellipse(at right 80% top 50pc)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - ellipse(at right 80% bottom 70pc)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): pc - ellipse(at right 80pc bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - ellipse(at left 50em bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - ellipse(at top 50em right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - ellipse(at bottom 70% left 50em)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - ellipse(at bottom 70% right 80em)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - ellipse(at bottom 70em right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - ellipse(at right 80% top 50em)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - ellipse(at right 80% bottom 70em)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): em - ellipse(at right 80em bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - ellipse(at left 50ex bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - ellipse(at top 50ex right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - ellipse(at bottom 70% left 50ex)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - ellipse(at bottom 70% right 80ex)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - ellipse(at bottom 70ex right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - ellipse(at right 80% top 50ex)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - ellipse(at right 80% bottom 70ex)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ex - ellipse(at right 80ex bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - ellipse(at left 50ch bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - ellipse(at top 50ch right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - ellipse(at bottom 70% left 50ch)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - ellipse(at bottom 70% right 80ch)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - ellipse(at bottom 70ch right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - ellipse(at right 80% top 50ch)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - ellipse(at right 80% bottom 70ch)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): ch - ellipse(at right 80ch bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - ellipse(at left 50rem bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - ellipse(at top 50rem right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - ellipse(at bottom 70% left 50rem)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - ellipse(at bottom 70% right 80rem)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - ellipse(at bottom 70rem right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - ellipse(at right 80% top 50rem)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - ellipse(at right 80% bottom 70rem)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): rem - ellipse(at right 80rem bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - ellipse(at left 50vw bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - ellipse(at top 50vw right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - ellipse(at bottom 70% left 50vw)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - ellipse(at bottom 70% right 80vw)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - ellipse(at bottom 70vw right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - ellipse(at right 80% top 50vw)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - ellipse(at right 80% bottom 70vw)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vw - ellipse(at right 80vw bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - ellipse(at left 50vh bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - ellipse(at top 50vh right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - ellipse(at bottom 70% left 50vh)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - ellipse(at bottom 70% right 80vh)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - ellipse(at bottom 70vh right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - ellipse(at right 80% top 50vh)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - ellipse(at right 80% bottom 70vh)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vh - ellipse(at right 80vh bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - ellipse(at left 50vmin bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - ellipse(at top 50vmin right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - ellipse(at bottom 70% left 50vmin)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - ellipse(at bottom 70% right 80vmin)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - ellipse(at bottom 70vmin right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - ellipse(at right 80% top 50vmin)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - ellipse(at right 80% bottom 70vmin)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmin - ellipse(at right 80vmin bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - ellipse(at left 50vmax bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - ellipse(at top 50vmax right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - ellipse(at bottom 70% left 50vmax)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - ellipse(at bottom 70% right 80vmax)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - ellipse(at bottom 70vmax right 80%)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - ellipse(at right 80% top 50vmax)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - ellipse(at right 80% bottom 70vmax)]
+-    expected:
+-      if stylo: FAIL
+-
+-  [test unit (inline): vmax - ellipse(at right 80vmax bottom 70%)]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-006.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-006.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-006.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-006.html.ini
+@@ -1,17 +1,5 @@
+ [shape-outside-ellipse-006.html]
+   type: testharness
+   [ellipse(+10.00px +20.230px) - computed]
+     expected: FAIL
+ 
+-  [ellipse(+30% 40%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(+50% +60%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [ellipse(+30.00% 40.567%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-010.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-010.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-010.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-010.html.ini
+@@ -101,20 +101,12 @@
+ 
+   [ellipse(calc(25%*3) calc(25%*3)) - computed style]
+     expected: FAIL
+ 
+   [ellipse(farthest-side calc(10in)) - inline style]
+     expected:
+       if stylo: FAIL
+ 
+-  [ellipse(farthest-side calc(30%)) - inline style]
+-    expected:
+-      if stylo: FAIL
+-
+   [ellipse(calc(10in) calc(10in)) - inline style]
+     expected:
+       if stylo: FAIL
+ 
+-  [ellipse(calc(30%) calc(30%)) - inline style]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-011.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-011.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-011.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-011.html.ini
+@@ -114,20 +114,12 @@
+     expected:
+       if stylo: PASS
+       FAIL
+ 
+   [ellipse(at calc(10in) 50%) - inline style]
+     expected:
+       if stylo: FAIL
+ 
+-  [ellipse(at calc(30%) 50%) - inline style]
+-    expected:
+-      if stylo: FAIL
+-
+   [ellipse(closest-side farthest-side at calc(10in) calc(10in)) - inline style]
+     expected:
+       if stylo: FAIL
+ 
+-  [ellipse(closest-side farthest-side at calc(30%) calc(30%)) - inline style]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-001.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-001.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-001.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-001.html.ini
+@@ -229,536 +229,8 @@
+     expected: FAIL
+ 
+   [Four args - % % ex % - computed]
+     expected: FAIL
+ 
+   [Four args - % % % ex - computed]
+     expected: FAIL
+ 
+-  [Three args - cm cm % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - cm % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % cm %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - cm cm % cm - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - cm cm % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - cm % % cm - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - cm % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % cm % cm - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % cm % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % cm - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - mm mm % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - mm % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % mm %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - mm mm % mm - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - mm mm % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - mm % % mm - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - mm % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % mm % mm - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % mm % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % mm - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - in in % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - in % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % in %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - in in % in - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - in in % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - in % % in - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - in % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % in % in - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % in % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % in - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - pt pt % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - pt % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % pt %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - pt pt % pt - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - pt pt % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - pt % % pt - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - pt % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % pt % pt - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % pt % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % pt - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - pc pc % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - pc % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % pc %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - pc pc % pc - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - pc pc % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - pc % % pc - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - pc % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % pc % pc - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % pc % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % pc - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - em em % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - em % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % em %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - em em % em - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - em em % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - em % % em - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - em % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % em % em - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % em % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % em - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - ex ex % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - ex % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % ex %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - ex ex % ex - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - ex ex % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - ex % % ex - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - ex % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % ex % ex - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % ex % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % ex - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - ch ch % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - ch % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % ch %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - ch ch % ch - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - ch ch % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - ch % % ch - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - ch % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % ch % ch - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % ch % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % ch - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - rem rem % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - rem % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % rem %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - rem rem % rem - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - rem rem % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - rem % % rem - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - rem % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % rem % rem - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % rem % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % rem - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - vw vw % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - vw % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % vw %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vw vw % vw - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vw vw % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vw % % vw - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vw % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % vw % vw - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % vw % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % vw - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - vh vh % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - vh % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % vh %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vh vh % vh - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vh vh % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vh % % vh - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vh % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % vh % vh - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % vh % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % vh - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - vmin vmin % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - vmin % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % vmin %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vmin vmin % vmin - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vmin vmin % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vmin % % vmin - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vmin % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % vmin % vmin - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % vmin % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % vmin - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - vmax vmax % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - vmax % %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three args - % vmax %  - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vmax vmax % vmax - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vmax vmax % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vmax % % vmax - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - vmax % % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % vmax % vmax - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % vmax % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Four args - % % % vmax - inline]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-002.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-002.html.ini
+deleted file mode 100644
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-002.html.ini
++++ /dev/null
+@@ -1,58 +0,0 @@
+-[shape-outside-inset-002.html]
+-  type: testharness
+-  [inset(10% round 10% / 10% 20% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% / 10% 20% 30% 40%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% / 10% 20% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% / 10% 20% 30% 40%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% 30% / 10%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% 30% / 10% 20%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% 30% / 10% 20% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% 30% / 10% 20% 30% 40%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% 30% 40%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% 30% 40% / 10%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% 30% 40% / 10% 20%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% 30% 40% / 10% 20% 30%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [inset(10% round 10% 20% 30% 40% / 10% 20% 30% 40%) - inline]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-008.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-008.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-008.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-008.html.ini
+@@ -25,17 +25,19 @@
+     expected: FAIL
+ 
+   [inset(calc(10in + 20px) calc(10in + 20px)) - inline style]
+     expected:
+       if stylo: PASS
+       FAIL
+ 
+   [inset(calc(30%) calc(30%)) - inline style]
+-    expected: FAIL
++    expected:
++      if stylo: PASS
++      FAIL
+ 
+   [inset(calc(100%/4) calc(100%/4)) - inline style]
+     expected:
+       if stylo: PASS
+       FAIL
+ 
+   [inset(calc(25%*3) calc(25%*3)) - inline style]
+     expected:
+@@ -65,12 +67,8 @@
+ 
+   [inset(calc(25%*3) calc(25%*3)) - computed style]
+     expected: FAIL
+ 
+   [inset(calc(10in)) - inline style]
+     expected:
+       if stylo: FAIL
+ 
+-  [inset(calc(30%)) - inline style]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-009.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-009.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-009.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-inset-009.html.ini
+@@ -4,17 +4,19 @@
+     expected: FAIL
+ 
+   [inset(10px 10px 10px 10px round calc(10in + 20px)) - inline style]
+     expected:
+       if stylo: PASS
+       FAIL
+ 
+   [inset(10px 10px 10px 10px round calc(30%)) - inline style]
+-    expected: FAIL
++    expected:
++      if stylo: PASS
++      FAIL
+ 
+   [inset(10px 10px 10px 10px round calc(100%/4)) - inline style]
+     expected:
+       if stylo: PASS
+       FAIL
+ 
+   [inset(10px 10px 10px 10px round calc(25%*3)) - inline style]
+     expected:
+@@ -31,17 +33,19 @@
+     expected: FAIL
+ 
+   [inset(10px 10px 10px 10px round calc(10in + 20px) calc(10in + 20px)) - inline style]
+     expected:
+       if stylo: PASS
+       FAIL
+ 
+   [inset(10px 10px 10px 10px round calc(30%) calc(30%)) - inline style]
+-    expected: FAIL
++    expected:
++      if stylo: PASS
++      FAIL
+ 
+   [inset(10px 10px 10px 10px round calc(100%/4) calc(100%/4)) - inline style]
+     expected:
+       if stylo: PASS
+       FAIL
+ 
+   [inset(10px 10px 10px 10px round calc(25%*3) calc(25%*3)) - inline style]
+     expected:
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-polygon-004.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-polygon-004.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-polygon-004.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-polygon-004.html.ini
+@@ -55,52 +55,8 @@
+     expected: FAIL
+ 
+   [Three vertices - rem rem, ch ch, rem rem - computed]
+     expected: FAIL
+ 
+   [Three vertices - rem rem, rem, rem, ch ch - computed]
+     expected: FAIL
+ 
+-  [Two vertices - % %, % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Two vertices - px px, % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three vertices - % %, % %, % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three vertices - px px, %, %, px px - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Two vertices - px %, % px - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three vertices - px px, % %, px px - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three vertices - px px, px, px, % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three vertices - px px, px px, % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three vertices - % %, %, %, % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three vertices - vw vw, vh vh, % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+-  [Three vertices - in in, pt pt, % % - inline]
+-    expected:
+-      if stylo: FAIL
+-
+diff --git a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-polygon-006.html.ini b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-polygon-006.html.ini
+--- a/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-polygon-006.html.ini
++++ b/testing/web-platform/meta/css/css-shapes-1/shape-outside/values/shape-outside-polygon-006.html.ini
+@@ -59,20 +59,12 @@
+ 
+   [polygon(evenodd, calc(25%*3) calc(25%*3), calc(25%*3) calc(25%*3)) - computed style]
+     expected: FAIL
+ 
+   [polygon(calc(10in) calc(10in)) - inline style]
+     expected:
+       if stylo: FAIL
+ 
+-  [polygon(calc(30%) calc(30%)) - inline style]
+-    expected:
+-      if stylo: FAIL
+-
+   [polygon(evenodd, calc(10in) calc(10in), calc(10in) calc(10in)) - inline style]
+     expected:
+       if stylo: FAIL
+ 
+-  [polygon(evenodd, calc(30%) calc(30%), calc(30%) calc(30%)) - inline style]
+-    expected:
+-      if stylo: FAIL
+-

Some files were not shown because too many files changed in this diff