merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 04 Dec 2015 11:57:23 +0100
changeset 275663 e02b17a2b5b8df7bb84f325fc08eedd2f3cab755
parent 275662 a36cc9262f70b95c830ce1ff3bd415f346b46415 (current diff)
parent 275600 cb2462db0b8653b4a42131a4d2a8ea92c534d4fb (diff)
child 275664 48f854ba48c09b38b05208ce8513cbc452af35fc
child 275748 4a9a6f9a2cf4e1243ed9d0224acd0edec3841f5b
child 275757 751f4a7dbf6ca840f42c2b08b6827089c68ec1c1
child 275793 cfb5851c96ea1e2bc63952026aaefe23a2420412
push id68897
push usercbook@mozilla.com
push dateFri, 04 Dec 2015 11:02:38 +0000
treeherdermozilla-inbound@48f854ba48c0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone45.0a1
first release with
nightly linux32
e02b17a2b5b8 / 45.0a1 / 20151204030208 / files
nightly linux64
e02b17a2b5b8 / 45.0a1 / 20151204030208 / files
nightly mac
e02b17a2b5b8 / 45.0a1 / 20151204030208 / files
nightly win32
e02b17a2b5b8 / 45.0a1 / 20151204030208 / files
nightly win64
e02b17a2b5b8 / 45.0a1 / 20151204030208 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
configure.in
dom/media/webm/AudioDecoder.cpp
dom/media/webm/SoftwareWebMVideoDecoder.cpp
dom/media/webm/SoftwareWebMVideoDecoder.h
dom/media/webm/WebMReader.cpp
dom/media/webm/WebMReader.h
mfbt/Constants.h
modules/libpref/init/all.js
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -2017,16 +2017,19 @@ DocAccessible::ValidateARIAOwned()
   }
 }
 
 void
 DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
 {
   nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.LookupOrAdd(aOwner);
 
+  MOZ_ASSERT(aOwner, "aOwner must be a valid pointer");
+  MOZ_ASSERT(aOwner->Elm(), "aOwner->Elm() must be a valid pointer");
+
   IDRefsIterator iter(this, aOwner->Elm(), nsGkAtoms::aria_owns);
   Accessible* child = nullptr;
 
   uint32_t arrayIdx = 0, insertIdx = aOwner->ChildCount() - children->Length();
   while ((child = iter.Next())) {
     // Same child on same position, no change.
     if (child->Parent() == aOwner &&
         child->IndexInParent() == static_cast<int32_t>(insertIdx)) {
--- a/configure.in
+++ b/configure.in
@@ -547,16 +547,17 @@ case "$target" in
         _CXX_MAJOR_VERSION=`echo ${CXX_VERSION} | cut -c 1-2`
 
         if test "$_CC_MAJOR_VERSION" != "$_CXX_MAJOR_VERSION"; then
             AC_MSG_ERROR([The major versions of \$CC and \$CXX do not match.])
         fi
 
         AC_DEFINE(_CRT_SECURE_NO_WARNINGS)
         AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS)
+        AC_DEFINE(_USE_MATH_DEFINES) # Otherwise MSVC's math.h doesn't #define M_PI.
 
         if test "$_CC_MAJOR_VERSION" = "18" -a "$_CC_BUILD_VERSION" -ge "30723"; then
             _CC_SUITE=12
             MSVS_VERSION=2013
             MSVC_C_RUNTIME_DLL=msvcr120.dll
             MSVC_CXX_RUNTIME_DLL=msvcp120.dll
         elif test "$_CC_MAJOR_VERSION" = "19"; then
             _CC_SUITE=14
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -1199,17 +1199,19 @@ Animation::GetCollection() const
              "An animation with an animation manager must have an effect");
 
   Element* targetElement;
   nsCSSPseudoElements::Type targetPseudoType;
   mEffect->GetTarget(targetElement, targetPseudoType);
   MOZ_ASSERT(targetElement,
              "An animation with an animation manager must have a target");
 
-  return manager->GetAnimations(targetElement, targetPseudoType, false);
+  return manager->GetAnimationCollection(targetElement,
+                                         targetPseudoType,
+                                         false /* aCreateIfNeeded */);
 }
 
 void
 Animation::DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag)
 {
   if (aSyncNotifyFlag == SyncNotifyFlag::Sync) {
     DoFinishNotificationImmediately();
   } else if (!mFinishNotificationTask.IsPending()) {
new file mode 100644
--- /dev/null
+++ b/dom/animation/AnimationUtils.cpp
@@ -0,0 +1,36 @@
+/* -*- 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 "AnimationUtils.h"
+
+#include "nsDebug.h"
+#include "nsIAtom.h"
+#include "nsIContent.h"
+#include "nsString.h"
+
+namespace mozilla {
+
+/* static */ void
+AnimationUtils::LogAsyncAnimationFailure(nsCString& aMessage,
+                                         const nsIContent* aContent)
+{
+  if (aContent) {
+    aMessage.AppendLiteral(" [");
+    aMessage.Append(nsAtomCString(aContent->NodeInfo()->NameAtom()));
+
+    nsIAtom* id = aContent->GetID();
+    if (id) {
+      aMessage.AppendLiteral(" with id '");
+      aMessage.Append(nsAtomCString(aContent->GetID()));
+      aMessage.Append('\'');
+    }
+    aMessage.Append(']');
+  }
+  aMessage.Append('\n');
+  printf_stderr("%s", aMessage.get());
+}
+
+} // namespace mozilla
--- a/dom/animation/AnimationUtils.h
+++ b/dom/animation/AnimationUtils.h
@@ -4,44 +4,48 @@
  * 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_AnimationUtils_h
 #define mozilla_dom_AnimationUtils_h
 
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/Nullable.h"
+#include "nsStringFwd.h"
+
+class nsIContent;
 
 namespace mozilla {
-namespace dom {
 
 class AnimationUtils
 {
 public:
-  static Nullable<double>
-    TimeDurationToDouble(const Nullable<TimeDuration>& aTime)
+  static dom::Nullable<double>
+    TimeDurationToDouble(const dom::Nullable<TimeDuration>& aTime)
   {
-    Nullable<double> result;
+    dom::Nullable<double> result;
 
     if (!aTime.IsNull()) {
       result.SetValue(aTime.Value().ToMilliseconds());
     }
 
     return result;
   }
 
-  static Nullable<TimeDuration>
-    DoubleToTimeDuration(const Nullable<double>& aTime)
+  static dom::Nullable<TimeDuration>
+    DoubleToTimeDuration(const dom::Nullable<double>& aTime)
   {
-    Nullable<TimeDuration> result;
+    dom::Nullable<TimeDuration> result;
 
     if (!aTime.IsNull()) {
       result.SetValue(TimeDuration::FromMilliseconds(aTime.Value()));
     }
 
     return result;
   }
+
+  static void LogAsyncAnimationFailure(nsCString& aMessage,
+                                       const nsIContent* aContent = nullptr);
 };
 
-} // namespace dom
 } // namespace mozilla
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/animation/EffectCompositor.cpp
@@ -0,0 +1,68 @@
+/* -*- 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 "EffectCompositor.h"
+
+#include "mozilla/dom/Animation.h"
+#include "mozilla/dom/KeyframeEffect.h"
+#include "mozilla/AnimationUtils.h"
+#include "mozilla/EffectSet.h"
+#include "nsLayoutUtils.h"
+
+using mozilla::dom::Animation;
+using mozilla::dom::KeyframeEffectReadOnly;
+
+namespace mozilla {
+
+/* static */ nsTArray<RefPtr<dom::Animation>>
+EffectCompositor::GetAnimationsForCompositor(const nsIFrame* aFrame,
+                                             nsCSSProperty aProperty)
+{
+  nsTArray<RefPtr<dom::Animation>> result;
+
+  if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
+    if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
+      nsCString message;
+      message.AppendLiteral("Performance warning: Async animations are "
+                            "disabled");
+      AnimationUtils::LogAsyncAnimationFailure(message);
+    }
+    return result;
+  }
+
+  if (aFrame->RefusedAsyncAnimation()) {
+    return result;
+  }
+
+  EffectSet* effects = EffectSet::GetEffectSet(aFrame);
+  if (!effects) {
+    return result;
+  }
+
+  for (KeyframeEffectReadOnly* effect : *effects) {
+    MOZ_ASSERT(effect && effect->GetAnimation());
+    Animation* animation = effect->GetAnimation();
+
+    if (!animation->IsPlaying()) {
+      continue;
+    }
+
+    if (effect->ShouldBlockCompositorAnimations(aFrame)) {
+      result.Clear();
+      return result;
+    }
+
+    if (!effect->HasAnimationOfProperty(aProperty)) {
+      continue;
+    }
+
+    result.AppendElement(animation);
+  }
+
+  return result;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/animation/EffectCompositor.h
@@ -0,0 +1,29 @@
+/* -*- 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_EffectCompositor_h
+#define mozilla_EffectCompositor_h
+
+#include "mozilla/RefPtr.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+
+namespace dom {
+class Animation;
+}
+
+class EffectCompositor
+{
+public:
+  static nsTArray<RefPtr<dom::Animation>>
+  GetAnimationsForCompositor(const nsIFrame* aFrame,
+                             nsCSSProperty aProperty);
+};
+
+} // namespace mozilla
+
+#endif // mozilla_EffectCompositor_h
--- a/dom/animation/EffectSet.cpp
+++ b/dom/animation/EffectSet.cpp
@@ -37,16 +37,52 @@ EffectSet::Traverse(nsCycleCollectionTra
 EffectSet::GetEffectSet(dom::Element* aElement,
                         nsCSSPseudoElements::Type aPseudoType)
 {
   nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType);
   return static_cast<EffectSet*>(aElement->GetProperty(propName));
 }
 
 /* static */ EffectSet*
+EffectSet::GetEffectSet(const nsIFrame* aFrame)
+{
+  nsIContent* content = aFrame->GetContent();
+  if (!content) {
+    return nullptr;
+  }
+
+  nsIAtom* propName;
+  if (aFrame->IsGeneratedContentFrame()) {
+    nsIFrame* parent = aFrame->GetParent();
+    if (parent->IsGeneratedContentFrame()) {
+      return nullptr;
+    }
+    nsIAtom* name = content->NodeInfo()->NameAtom();
+    if (name == nsGkAtoms::mozgeneratedcontentbefore) {
+      propName = nsGkAtoms::animationEffectsForBeforeProperty;
+    } else if (name == nsGkAtoms::mozgeneratedcontentafter) {
+      propName = nsGkAtoms::animationEffectsForAfterProperty;
+    } else {
+      return nullptr;
+    }
+    content = content->GetParent();
+    if (!content) {
+      return nullptr;
+    }
+  } else {
+    if (!content->MayHaveAnimations()) {
+      return nullptr;
+    }
+    propName = nsGkAtoms::animationEffectsProperty;
+  }
+
+  return static_cast<EffectSet*>(content->GetProperty(propName));
+}
+
+/* static */ EffectSet*
 EffectSet::GetOrCreateEffectSet(dom::Element* aElement,
                                 nsCSSPseudoElements::Type aPseudoType)
 {
   EffectSet* effectSet = GetEffectSet(aElement, aPseudoType);
   if (effectSet) {
     return effectSet;
   }
 
--- a/dom/animation/EffectSet.h
+++ b/dom/animation/EffectSet.h
@@ -40,16 +40,17 @@ public:
   static void PropertyDtor(void* aObject, nsIAtom* aPropertyName,
                            void* aPropertyValue, void* aData);
 
   // Methods for supporting cycle-collection
   void Traverse(nsCycleCollectionTraversalCallback& aCallback);
 
   static EffectSet* GetEffectSet(dom::Element* aElement,
                                  nsCSSPseudoElements::Type aPseudoType);
+  static EffectSet* GetEffectSet(const nsIFrame* aFrame);
   static EffectSet* GetOrCreateEffectSet(dom::Element* aElement,
                                          nsCSSPseudoElements::Type aPseudoType);
 
   void AddEffect(dom::KeyframeEffectReadOnly& aEffect);
   void RemoveEffect(dom::KeyframeEffectReadOnly& aEffect);
 
 private:
   typedef nsTHashtable<nsRefPtrHashKey<dom::KeyframeEffectReadOnly>>
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -4,16 +4,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/. */
 
 #include "mozilla/dom/KeyframeEffect.h"
 
 #include "mozilla/dom/AnimationEffectReadOnlyBinding.h"
 #include "mozilla/dom/KeyframeEffectBinding.h"
 #include "mozilla/dom/PropertyIndexedKeyframesBinding.h"
+#include "mozilla/AnimationUtils.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
 #include "mozilla/StyleAnimationValue.h"
 #include "AnimationCommon.h"
 #include "Layers.h" // For Layer
 #include "nsCSSParser.h"
 #include "nsCSSPropertySet.h"
 #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
@@ -50,17 +51,17 @@ GetComputedTimingDictionary(const Comput
   aRetVal.mIterations = aTiming.mIterationCount;
   aRetVal.mDuration.SetAsUnrestrictedDouble() = aTiming.mIterationDuration.ToMilliseconds();
   aRetVal.mDirection = aTiming.mDirection;
 
   // ComputedTimingProperties
   aRetVal.mActiveDuration = aComputedTiming.mActiveDuration.ToMilliseconds();
   aRetVal.mEndTime
     = std::max(aRetVal.mDelay + aRetVal.mActiveDuration + aRetVal.mEndDelay, 0.0);
-  aRetVal.mLocalTime = dom::AnimationUtils::TimeDurationToDouble(aLocalTime);
+  aRetVal.mLocalTime = AnimationUtils::TimeDurationToDouble(aLocalTime);
   aRetVal.mProgress = aComputedTiming.mProgress;
   if (!aRetVal.mProgress.IsNull()) {
     // Convert the returned currentIteration into Infinity if we set
     // (uint64_t) aComputedTiming.mCurrentIteration to UINT64_MAX
     double iteration = aComputedTiming.mCurrentIteration == UINT64_MAX
                      ? PositiveInfinity<double>()
                      : static_cast<double>(aComputedTiming.mCurrentIteration);
     aRetVal.mCurrentIteration.SetValue(iteration);
@@ -547,16 +548,22 @@ KeyframeEffectReadOnly::UpdateTargetRegi
     EffectSet* effectSet = EffectSet::GetOrCreateEffectSet(mTarget,
                                                            mPseudoType);
     effectSet->AddEffect(*this);
   } else {
     EffectSet* effectSet = EffectSet::GetEffectSet(mTarget, mPseudoType);
     if (effectSet) {
       effectSet->RemoveEffect(*this);
     }
+    // Any effects not in the effect set will not be included in the set of
+    // candidate effects for running on the compositor and hence they won't
+    // have their compositor status updated so we should do that now.
+    for (bool& isRunningOnCompositor : mIsPropertyRunningOnCompositor) {
+      isRunningOnCompositor = false;
+    }
   }
 }
 
 #ifdef DEBUG
 void
 DumpAnimationProperties(nsTArray<AnimationProperty>& aAnimationProperties)
 {
   for (auto& p : aAnimationProperties) {
@@ -1979,68 +1986,79 @@ KeyframeEffectReadOnly::CanAnimateTransf
   const nsIContent* aContent)
 {
   if (aFrame->Combines3DTransformWithAncestors() ||
       aFrame->Extend3DContext()) {
     if (aContent) {
       nsCString message;
       message.AppendLiteral("Gecko bug: Async animation of 'preserve-3d' "
         "transforms is not supported.  See bug 779598");
-      AnimationCollection::LogAsyncAnimationFailure(message, aContent);
+      AnimationUtils::LogAsyncAnimationFailure(message, aContent);
     }
     return false;
   }
   // Note that testing BackfaceIsHidden() is not a sufficient test for
   // what we need for animating backface-visibility correctly if we
   // remove the above test for Extend3DContext(); that would require
   // looking at backface-visibility on descendants as well.
   if (aFrame->StyleDisplay()->BackfaceIsHidden()) {
     if (aContent) {
       nsCString message;
       message.AppendLiteral("Gecko bug: Async animation of "
         "'backface-visibility: hidden' transforms is not supported."
         "  See bug 1186204.");
-      AnimationCollection::LogAsyncAnimationFailure(message, aContent);
+      AnimationUtils::LogAsyncAnimationFailure(message, aContent);
     }
     return false;
   }
   if (aFrame->IsSVGTransformed()) {
     if (aContent) {
       nsCString message;
       message.AppendLiteral("Gecko bug: Async 'transform' animations of "
         "aFrames with SVG transforms is not supported.  See bug 779599");
-      AnimationCollection::LogAsyncAnimationFailure(message, aContent);
+      AnimationUtils::LogAsyncAnimationFailure(message, aContent);
     }
     return false;
   }
 
   return true;
 }
 
-/* static */ bool
-KeyframeEffectReadOnly::CanAnimatePropertyOnCompositor(
-  const nsIFrame* aFrame,
-  nsCSSProperty aProperty)
+bool
+KeyframeEffectReadOnly::ShouldBlockCompositorAnimations(const nsIFrame*
+                                                          aFrame) const
 {
+  // We currently only expect this method to be called when this effect
+  // is attached to a playing Animation. If that ever changes we'll need
+  // to update this to only return true when that is the case since paused,
+  // filling, cancelled Animations etc. shouldn't stop other Animations from
+  // running on the compositor.
+  MOZ_ASSERT(mAnimation && mAnimation->IsPlaying());
+
   bool shouldLog = nsLayoutUtils::IsAnimationLoggingEnabled();
 
-  if (IsGeometricProperty(aProperty)) {
-    if (shouldLog) {
-      nsCString message;
-      message.AppendLiteral("Performance warning: Async animation of "
-        "'transform' or 'opacity' not possible due to animation of geometric"
-        "properties on the same element");
-      AnimationCollection::LogAsyncAnimationFailure(message,
-                                                    aFrame->GetContent());
+  for (const AnimationProperty& property : mProperties) {
+    // Check for geometric properties
+    if (IsGeometricProperty(property.mProperty)) {
+      if (shouldLog) {
+        nsCString message;
+        message.AppendLiteral("Performance warning: Async animation of "
+          "'transform' or 'opacity' not possible due to animation of geometric"
+          "properties on the same element");
+        AnimationUtils::LogAsyncAnimationFailure(message, aFrame->GetContent());
+      }
+      return true;
     }
-    return false;
-  }
-  if (aProperty == eCSSProperty_transform) {
-    if (!CanAnimateTransformOnCompositor(aFrame,
-          shouldLog ? aFrame->GetContent() : nullptr)) {
-      return false;
+
+    // Check for unsupported transform animations
+    if (property.mProperty == eCSSProperty_transform) {
+      if (!CanAnimateTransformOnCompositor(aFrame,
+            shouldLog ? aFrame->GetContent() : nullptr)) {
+        return true;
+      }
     }
   }
-  return true;
+
+  return false;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -282,19 +282,32 @@ public:
   // Returns true if |aProperty| is currently being animated on compositor.
   bool IsPropertyRunningOnCompositor(nsCSSProperty aProperty) const;
   // Returns true if at least one property is being animated on compositor.
   bool IsRunningOnCompositor() const;
   void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
 
   bool CanThrottle() const;
 
-  // Returns true |aProperty| can be run on compositor for |aFrame|.
-  static bool CanAnimatePropertyOnCompositor(const nsIFrame* aFrame,
-                                             nsCSSProperty aProperty);
+  // Returns true if this effect, applied to |aFrame|, contains
+  // properties that mean we shouldn't run *any* compositor animations on this
+  // element.
+  //
+  // For example, if we have an animation of geometric properties like 'left'
+  // and 'top' on an element, we force all 'transform' and 'opacity' animations
+  // running at the same time on the same element to run on the main thread.
+  //
+  // Similarly, some transform animations cannot be run on the compositor and
+  // when that is the case we simply disable all compositor animations
+  // on the same element.
+  //
+  // Bug 1218620 - It seems like we don't need to be this restrictive. Wouldn't
+  // it be ok to do 'opacity' animations on the compositor in either case?
+  bool ShouldBlockCompositorAnimations(const nsIFrame* aFrame) const;
+
   nsIDocument* GetRenderedDocument() const;
   nsPresContext* GetPresContext() const;
 
   inline AnimationCollection* GetCollection() const;
 
 protected:
   virtual ~KeyframeEffectReadOnly();
   void ResetIsRunningOnCompositor();
--- a/dom/animation/moz.build
+++ b/dom/animation/moz.build
@@ -14,26 +14,29 @@ EXPORTS.mozilla.dom += [
     'DocumentTimeline.h',
     'KeyframeEffect.h',
 ]
 
 EXPORTS.mozilla += [
     'AnimationComparator.h',
     'AnimationUtils.h',
     'ComputedTimingFunction.h',
+    'EffectCompositor.h',
     'EffectSet.h',
     'PendingAnimationTracker.h',
 ]
 
 UNIFIED_SOURCES += [
     'Animation.cpp',
     'AnimationEffectReadOnly.cpp',
     'AnimationTimeline.cpp',
+    'AnimationUtils.cpp',
     'ComputedTimingFunction.cpp',
     'DocumentTimeline.cpp',
+    'EffectCompositor.cpp',
     'EffectSet.cpp',
     'KeyframeEffect.cpp',
     'PendingAnimationTracker.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/dom/base',
 ]
--- a/dom/animation/test/chrome/test_running_on_compositor.html
+++ b/dom/animation/test/chrome/test_running_on_compositor.html
@@ -102,67 +102,62 @@ promise_test(function(t) {
 }, 'isRunningOnCompositor is false when the animation.pause() is called');
 
 promise_test(function(t) {
   var div = addDiv(t, { style: 'animation: anim 100s' });
   var animation = div.getAnimations()[0];
 
   return animation.ready.then(t.step_func(function() {
     animation.finish();
-    // We need to wait for two frames here to ensure isRunningOnCompositor
-    // flag is cleared. The first frame is for waking root refresh driver up,
-    // the second one is for clearing the flag.
-    // In most cases root refresh driver has been dormant because there is
-    // nothing to do for the root refresh driver (e.g. nothing change on
-    // chrome window). In the first frame document's refresh driver wakes the
-    // root refresh driver up as a result of animation's style changes.
-    // In the second frame the root refresh driver clears the flag as a
-    // result of a paint.
-    return waitForAnimationFrames(2);
+    assert_equals(animation.isRunningOnCompositor, false,
+       'Animation reports that it is NOT running on the compositor'
+       + ' immediately after animation.finish() is called');
+    // Check that we don't set the flag back again on the next tick.
+    return waitForFrame();
   })).then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, false,
        'Animation reports that it is NOT running on the compositor'
-       + ' when animation.finish() is called');
+       + ' on the next tick after animation.finish() is called');
   }));
 }, 'isRunningOnCompositor is false when the animation.finish() is called');
 
 promise_test(function(t) {
   var div = addDiv(t, { style: 'animation: anim 100s' });
   var animation = div.getAnimations()[0];
 
   return animation.ready.then(t.step_func(function() {
     animation.currentTime = 100000; // 100s
-    // We need to wait for up to two frames here to ensure the "is running on
-    // compositor" flag is cleared.
-    // See the description in the 'isRunningOnCompositor is false when the
-    // animation.finish() is called' test for the rationale.
-    return waitForAnimationFrames(2);
+    assert_equals(animation.isRunningOnCompositor, false,
+       'Animation reports that it is NOT running on the compositor'
+       + ' immediately after manually seeking the animation to the end');
+    // Check that we don't set the flag back again on the next tick.
+    return waitForFrame();
   })).then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, false,
        'Animation reports that it is NOT running on the compositor'
-       + ' when manually seeking the animation to the end');
+       + ' on the next tick after manually seeking the animation to the end');
   }));
 }, 'isRunningOnCompositor is false when manually seeking the animation to ' +
    'the end');
 
 promise_test(function(t) {
   var div = addDiv(t, { style: 'animation: anim 100s' });
   var animation = div.getAnimations()[0];
 
   return animation.ready.then(t.step_func(function() {
     animation.cancel();
-    // We need to wait for up to two frames here to ensure the "is running on
-    // compositor" flag is cleared.
-    // See the description in the 'isRunningOnCompositor is false when the
-    // animation.finish() is called' test for the rationale.
-    return waitForAnimationFrames(2);
+    assert_equals(animation.isRunningOnCompositor, false,
+       'Animation reports that it is NOT running on the compositor'
+       + ' immediately after animation.cancel() is called');
+    // Check that we don't set the flag back again on the next tick.
+    return waitForFrame();
   })).then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, false,
        'Animation reports that it is NOT running on the compositor'
-       + ' when animation.cancel() is called');
+       + ' on the next tick after animation.cancel() is called');
   }));
 }, 'isRunningOnCompositor is false when animation.cancel() is called');
 
 promise_test(function(t) {
   var div = addDiv(t, { style: 'animation: anim 100s 100s' });
   var animation = div.getAnimations()[0];
 
   return animation.ready.then(t.step_func(function() {
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -21,16 +21,17 @@ XPIDL_SOURCES += [
     'nsIDOMParser.idl',
     'nsIDOMSerializer.idl',
     'nsIDroppedLinkHandler.idl',
     'nsIEntropyCollector.idl',
     'nsIFrameLoader.idl',
     'nsIImageLoadingContent.idl',
     'nsIMessageManager.idl',
     'nsIObjectLoadingContent.idl',
+    'nsIRemoteWindowContext.idl',
     'nsIScriptChannel.idl',
     'nsIScriptLoaderObserver.idl',
     'nsISelection.idl',
     'nsISelectionController.idl',
     'nsISelectionDisplay.idl',
     'nsISelectionListener.idl',
     'nsISelectionPrivate.idl',
     'nsISimpleContentPolicy.idl',
--- a/dom/base/nsContentTypeParser.h
+++ b/dom/base/nsContentTypeParser.h
@@ -12,20 +12,17 @@
 class nsIMIMEHeaderParam;
 
 class nsContentTypeParser {
 public:
   explicit nsContentTypeParser(const nsAString& aString);
   ~nsContentTypeParser();
 
   nsresult GetParameter(const char* aParameterName, nsAString& aResult);
-  nsresult GetType(nsAString& aResult)
-  {
-    return GetParameter(nullptr, aResult);
-  }
+  nsresult GetType(nsAString& aResult);
 
 private:
   NS_ConvertUTF16toUTF8 mString;
   nsIMIMEHeaderParam*   mService;
 };
 
 #endif
 
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6052,16 +6052,25 @@ nsresult
 nsContentTypeParser::GetParameter(const char* aParameterName, nsAString& aResult)
 {
   NS_ENSURE_TRUE(mService, NS_ERROR_FAILURE);
   return mService->GetParameterHTTP(mString, aParameterName,
                                     EmptyCString(), false, nullptr,
                                     aResult);
 }
 
+nsresult
+nsContentTypeParser::GetType(nsAString& aResult)
+{
+  nsresult rv = GetParameter(nullptr, aResult);
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsContentUtils::ASCIIToLower(aResult);
+  return NS_OK;
+}
+
 /* static */
 
 bool
 nsContentUtils::CanAccessNativeAnon()
 {
   return LegacyIsCallerChromeOrNativeCode() || IsCallerContentXBL();
 }
 
new file mode 100644
--- /dev/null
+++ b/dom/base/nsIRemoteWindowContext.idl
@@ -0,0 +1,15 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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 "nsISupports.idl"
+
+interface nsIURI;
+
+[scriptable, builtinclass, uuid(94f4a92b-752e-4fd9-8345-11b069ca19f3)]
+interface nsIRemoteWindowContext : nsISupports
+{
+  void openURI(in nsIURI aURI, in uint32_t aFlags);
+};
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -88,21 +88,19 @@ TranslateWithoutValidation(const nsACStr
         glesslVersion = 100;
     }
 
     std::string reversionedSource = source;
     reversionedSource.erase(versionStrStart, versionStrLen);
 
     switch (glesslVersion) {
     case 100:
-        if (!versionStrLen) {
-            /* According to ARB_ES2_compatibility extension glsl
-             * should accept #version 100 for ES 2 shaders. */
-            reversionedSource.insert(versionStrStart, "#version 100\n");
-        }
+        /* According to ARB_ES2_compatibility extension glsl
+         * should accept #version 100 for ES 2 shaders. */
+        reversionedSource.insert(versionStrStart, "#version 100\n");
         break;
     case 300:
         reversionedSource.insert(versionStrStart, "#version 330\n");
         break;
     default:
         MOZ_CRASH("Bad `glesslVersion`.");
     }
 
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -88,26 +88,52 @@ ChooseValidatorCompileOptions(const ShBu
 
     return options;
 }
 
 } // namespace webgl
 
 ////////////////////////////////////////
 
+static ShShaderOutput
+ShaderOutput(gl::GLContext* gl)
+{
+    if (gl->IsGLES()) {
+        return SH_ESSL_OUTPUT;
+    } else {
+        uint32_t version = gl->ShadingLanguageVersion();
+        switch (version) {
+        case 100: return SH_GLSL_COMPATIBILITY_OUTPUT;
+        case 120: return SH_GLSL_COMPATIBILITY_OUTPUT;
+        case 130: return SH_GLSL_130_OUTPUT;
+        case 140: return SH_GLSL_140_OUTPUT;
+        case 150: return SH_GLSL_150_CORE_OUTPUT;
+        case 330: return SH_GLSL_330_CORE_OUTPUT;
+        case 400: return SH_GLSL_400_CORE_OUTPUT;
+        case 410: return SH_GLSL_410_CORE_OUTPUT;
+        case 420: return SH_GLSL_420_CORE_OUTPUT;
+        case 430: return SH_GLSL_430_CORE_OUTPUT;
+        case 440: return SH_GLSL_440_CORE_OUTPUT;
+        case 450: return SH_GLSL_450_CORE_OUTPUT;
+        default:
+            MOZ_CRASH("Unexpected GLSL version.");
+        }
+    }
+
+    return SH_GLSL_OUTPUT;
+}
+
 webgl::ShaderValidator*
 WebGLContext::CreateShaderValidator(GLenum shaderType) const
 {
     if (mBypassShaderValidation)
         return nullptr;
 
     ShShaderSpec spec = IsWebGL2() ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC;
-    ShShaderOutput outputLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT
-                                                 : SH_GLSL_OUTPUT;
-
+    ShShaderOutput outputLanguage = ShaderOutput(gl);
     ShBuiltInResources resources;
     memset(&resources, 0, sizeof(resources));
     ShInitBuiltInResources(&resources);
 
     resources.HashFunction = webgl::IdentifierHashFunc;
 
     resources.MaxVertexAttribs = mGLMaxVertexAttribs;
     resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -360,16 +360,23 @@ WebGLTexture::ValidateTexImageSpecificat
          *   and if either wt or ht are less than zero, then the error
          *   INVALID_VALUE is generated."
          */
         mContext->ErrorInvalidValue("%s: `width`/`height`/`depth` must be >= 0.",
                                     funcName);
         return false;
     }
 
+    if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP &&
+        width != height)
+    {
+        mContext->ErrorInvalidValue("%s: Cube map images must be square.", funcName);
+        return false;
+    }
+
     /* GLES 3.0.4, p133-134:
      * GL_MAX_TEXTURE_SIZE is *not* the max allowed texture size. Rather, it is the
      * max (width/height) size guaranteed not to generate an INVALID_VALUE for too-large
      * dimensions. Sizes larger than GL_MAX_TEXTURE_SIZE *may or may not* result in an
      * INVALID_VALUE, or possibly GL_OOM.
      *
      * However, we have needed to set our maximums lower in the past to prevent resource
      * corruption. Therefore we have mImplMaxTextureSize, which is neither necessarily
--- a/dom/canvas/test/webgl-mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest.ini
@@ -6,16 +6,17 @@ support-files =
   webgl-mochitest/driver-info.js
   webgl-mochitest/webgl-util.js
 
 [webgl-mochitest/test_backbuffer_channels.html]
 fail-if = (os == 'b2g')
 [webgl-mochitest/test_depth_readpixels.html]
 [webgl-mochitest/test_capture.html]
 support-files = captureStream_common.js
+[webgl-mochitest/test_cubemap_must_be_square.html]
 [webgl-mochitest/test_draw.html]
 [webgl-mochitest/test_fb_param.html]
 [webgl-mochitest/test_fb_param_crash.html]
 [webgl-mochitest/test_hidden_alpha.html]
 skip-if = (os == 'b2g') || buildapp == 'mulet' # Mulet - bug 1093639 (crashes in libLLVM-3.0.so)
 [webgl-mochitest/test_implicit_color_buffer_float.html]
 [webgl-mochitest/test_highp_fs.html]
 [webgl-mochitest/test_no_arr_points.html]
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test_cubemap_must_be_square.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta http-equiv='content-type' content='text/html; charset=utf-8'/>
+
+  <script src='/tests/SimpleTest/SimpleTest.js'></script>
+  <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
+  <script src='webgl-util.js'></script>
+</head>
+
+<body>
+<script>
+'use strict';
+
+(function() {
+  var c = document.createElement('canvas');
+  var gl = c.getContext('webgl');
+
+  ok(!gl.getError(), 'No error before.');
+
+  var tex = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
+  gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGBA, 4, 3, 0, gl.RGBA,
+                gl.UNSIGNED_BYTE, null);
+
+  var err = gl.getError();
+  ok(err == gl.INVALID_VALUE,
+     'Should be INVALID_VALUE (0x501) after, was 0x' + err.toString(16) + '.');
+})();
+
+ok(true, 'Test complete.');
+
+</script>
+</body>
+</html>
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -1304,16 +1304,18 @@ HTMLImageElement::SelectSourceForTagWith
   // <source> tags with no match would leave source yet-undetermined.
   return false;
 }
 
 void
 HTMLImageElement::DestroyContent()
 {
   mResponsiveSelector = nullptr;
+
+  nsGenericHTMLElement::DestroyContent();
 }
 
 void
 HTMLImageElement::MediaFeatureValuesChanged()
 {
   QueueImageLoadTask(false);
 }
 
new file mode 100644
--- /dev/null
+++ b/dom/html/crashtests/1230110.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+// This test case should not leak.
+function leak()
+{
+    var img = document.createElement("img");
+    var iframe = document.createElement("iframe");
+    img.appendChild(iframe);
+    document.body.appendChild(img);
+
+    document.addEventListener('Foo', function(){}, false);
+}
+</script>
+</head>
+<body onload="leak();"></body>
+</html>
--- a/dom/html/crashtests/crashtests.list
+++ b/dom/html/crashtests/crashtests.list
@@ -70,8 +70,10 @@ load 862084.html
 load 865147.html
 load 877910.html
 load 903106.html
 load 916322-1.html
 load 916322-2.html
 load 1032654.html
 pref(dom.image.srcset.enabled,true) load 1141260.html
 load 1228876.html
+load 1230110.html
+
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -134,16 +134,17 @@
 #include "nsIIdleService.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIMemoryInfoDumper.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
+#include "nsIRemoteWindowContext.h"
 #include "nsIScriptError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISiteSecurityService.h"
 #include "nsISpellChecker.h"
 #include "nsISupportsPrimitives.h"
 #include "nsISystemMessagesInternal.h"
 #include "nsITimer.h"
 #include "nsIURIFixup.h"
@@ -1686,16 +1687,57 @@ private:
 };
 
 StaticAutoPtr<LinkedList<SystemMessageHandledListener> >
     SystemMessageHandledListener::sListeners;
 
 NS_IMPL_ISUPPORTS(SystemMessageHandledListener,
                   nsITimerCallback)
 
+
+class RemoteWindowContext final : public nsIRemoteWindowContext
+                                , public nsIInterfaceRequestor
+{
+public:
+    explicit RemoteWindowContext(TabParent* aTabParent)
+    : mTabParent(aTabParent)
+    {
+    }
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIINTERFACEREQUESTOR
+    NS_DECL_NSIREMOTEWINDOWCONTEXT
+
+private:
+    ~RemoteWindowContext();
+    RefPtr<TabParent> mTabParent;
+};
+
+NS_IMPL_ISUPPORTS(RemoteWindowContext, nsIRemoteWindowContext, nsIInterfaceRequestor)
+
+RemoteWindowContext::~RemoteWindowContext()
+{
+}
+
+NS_IMETHODIMP
+RemoteWindowContext::GetInterface(const nsIID& aIID, void** aSink)
+{
+    return QueryInterface(aIID, aSink);
+}
+
+NS_IMETHODIMP
+RemoteWindowContext::OpenURI(nsIURI* aURI, uint32_t aFlags)
+{
+    URIParams uri;
+    SerializeURI(aURI, uri);
+
+    Unused << mTabParent->SendOpenURI(uri, aFlags);
+    return NS_OK;
+}
+
 } // namespace
 
 void
 ContentParent::MaybeTakeCPUWakeLock(Element* aFrameElement)
 {
     // Take the CPU wake lock on behalf of this processs if it's expecting a
     // system message.  We'll release the CPU lock once the message is
     // delivered, or after some period of time, which ever comes first.
@@ -4316,27 +4358,31 @@ ContentParent::RecvAccumulateMixedConten
     if (!ourURI) {
         return false;
     }
     nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive);
     return true;
 }
 
 bool
-ContentParent::RecvLoadURIExternal(const URIParams& uri)
+ContentParent::RecvLoadURIExternal(const URIParams& uri,
+                                   PBrowserParent* windowContext)
 {
     nsCOMPtr<nsIExternalProtocolService> extProtService(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
     if (!extProtService) {
         return true;
     }
     nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
     if (!ourURI) {
         return false;
     }
-    extProtService->LoadURI(ourURI, nullptr);
+
+    RefPtr<RemoteWindowContext> context =
+        new RemoteWindowContext(static_cast<TabParent*>(windowContext));
+    extProtService->LoadURI(ourURI, context);
     return true;
 }
 
 bool
 ContentParent::HasNotificationPermission(const IPC::Principal& aPrincipal)
 {
 #ifdef MOZ_CHILD_PERMISSIONS
     uint32_t permission = mozilla::CheckPermission(this, aPrincipal,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -793,17 +793,18 @@ private:
 
     virtual bool RecvCloseAlert(const nsString& aName,
                                 const IPC::Principal& aPrincipal) override;
 
     virtual bool RecvDisableNotifications(const IPC::Principal& aPrincipal) override;
 
     virtual bool RecvOpenNotificationSettings(const IPC::Principal& aPrincipal) override;
 
-    virtual bool RecvLoadURIExternal(const URIParams& uri) override;
+    virtual bool RecvLoadURIExternal(const URIParams& uri,
+                                     PBrowserParent* windowContext) override;
 
     virtual bool RecvSyncMessage(const nsString& aMsg,
                                  const ClonedMessageData& aData,
                                  InfallibleTArray<CpowEntry>&& aCpows,
                                  const IPC::Principal& aPrincipal,
                                  nsTArray<StructuredCloneData>* aRetvals) override;
     virtual bool RecvRpcMessage(const nsString& aMsg,
                                 const ClonedMessageData& aData,
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -551,16 +551,18 @@ child:
          ShowInfo info,
          TextureFactoryIdentifier textureFactoryIdentifier,
          uint64_t layersId,
          nullable PRenderFrame renderFrame,
          bool parentIsActive);
 
     LoadURL(nsCString uri, BrowserConfiguration config, ShowInfo info);
 
+    OpenURI(URIParams uri, uint32_t flags);
+
     CacheFileDescriptor(nsString path, FileDescriptor fd);
 
     UpdateDimensions(CSSRect rect, CSSSize size, nsSizeMode sizeMode,
                      ScreenOrientationInternal orientation,
                      LayoutDeviceIntPoint chromeDisp) compressall;
 
     UpdateFrame(FrameMetrics frame);
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -847,17 +847,17 @@ parent:
     PPresentation();
 
     // Services remoting
 
     async StartVisitedQuery(URIParams uri);
     async VisitURI(URIParams uri, OptionalURIParams referrer, uint32_t flags);
     async SetURITitle(URIParams uri, nsString title);
 
-    async LoadURIExternal(URIParams uri);
+    async LoadURIExternal(URIParams uri, PBrowser windowContext);
 
     // PrefService message
     sync ReadPrefsArray() returns (PrefSetting[] prefs);
 
     sync ReadFontList() returns (FontListEntry[] retValue);
 
     sync ReadDataStorageArray(nsString aFilename)
       returns (DataStorageItem[] retValue);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/dom/workers/ServiceWorkerManager.h"
 #include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
 #include "mozilla/plugins/PluginWidgetChild.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/ipc/DocumentRendererChild.h"
+#include "mozilla/ipc/URIUtils.h"
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/APZEventState.h"
 #include "mozilla/layers/CompositorChild.h"
@@ -96,16 +97,17 @@
 #include "nsIOService.h"
 #include "nsDOMClassInfoID.h"
 #include "nsColorPickerProxy.h"
 #include "nsContentPermissionHelper.h"
 #include "nsPresShell.h"
 #include "nsIAppsService.h"
 #include "nsNetUtil.h"
 #include "nsIPermissionManager.h"
+#include "nsIURILoader.h"
 #include "nsIScriptError.h"
 #include "mozilla/EventForwards.h"
 #include "nsDeviceContext.h"
 
 #define BROWSER_ELEMENT_CHILD_SCRIPT \
     NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
 
 #define TABC_LOG(...)
@@ -1259,16 +1261,41 @@ TabChild::RecvLoadURL(const nsCString& a
 #ifdef MOZ_CRASHREPORTER
     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), aURI);
 #endif
 
     return true;
 }
 
 bool
+TabChild::RecvOpenURI(const URIParams& aURI, const uint32_t& aFlags)
+{
+  nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
+  nsCOMPtr<nsIChannel> channel;
+  nsresult rv =
+    NS_NewChannel(getter_AddRefs(channel),
+                  uri,
+                  nsContentUtils::GetSystemPrincipal(),
+                  nsILoadInfo::SEC_NORMAL,
+                  nsIContentPolicy::TYPE_DOCUMENT);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return true;
+  }
+
+  nsCOMPtr<nsIURILoader> loader = do_GetService("@mozilla.org/uriloader;1");
+  if (NS_WARN_IF(!loader)) {
+    return true;
+  }
+
+  nsCOMPtr<nsIInterfaceRequestor> context(do_QueryInterface(WebNavigation()));
+  loader->OpenURI(channel, aFlags, context);
+  return true;
+}
+
+bool
 TabChild::RecvCacheFileDescriptor(const nsString& aPath,
                                   const FileDescriptor& aFileDescriptor)
 {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(!aPath.IsEmpty());
     MOZ_ASSERT(!mAppPackageFileDescriptorRecved);
 
     mAppPackageFileDescriptorRecved = true;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -296,16 +296,18 @@ public:
                                         JS::Handle<JSObject *> aCpows,
                                         nsIPrincipal* aPrincipal) override;
     virtual bool DoUpdateZoomConstraints(const uint32_t& aPresShellId,
                                          const ViewID& aViewId,
                                          const Maybe<ZoomConstraints>& aConstraints) override;
     virtual bool RecvLoadURL(const nsCString& aURI,
                              const BrowserConfiguration& aConfiguration,
                              const ShowInfo& aInfo) override;
+    virtual bool RecvOpenURI(const URIParams& aURI,
+                             const uint32_t& aFlags) override;
     virtual bool RecvCacheFileDescriptor(const nsString& aPath,
                                          const FileDescriptor& aFileDescriptor)
                                          override;
     virtual bool RecvShow(const ScreenIntSize& aSize,
                           const ShowInfo& aInfo,
                           const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                           const uint64_t& aLayersId,
                           PRenderFrameChild* aRenderFrame,
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -149,42 +149,38 @@ IsWaveType(const nsACString& aType)
     return false;
   }
 
   return CodecListContains(gWaveTypes, aType);
 }
 #endif
 
 #ifdef MOZ_WEBM
-static const char* const gWebMTypes[3] = {
-  "video/webm",
-  "audio/webm",
-  nullptr
-};
-
-static char const *const gWebMCodecs[7] = {
-  "vp8",
-  "vp8.0",
-  "vp9",
-  "vp9.0",
-  "vorbis",
-  "opus",
-  nullptr
-};
+static bool
+IsWebMSupportedType(const nsACString& aType,
+                    const nsAString& aCodecs = EmptyString())
+{
+  return WebMDecoder::CanHandleMediaType(aType, aCodecs);
+}
 #endif
 
 /* static */ bool
 DecoderTraits::IsWebMTypeAndEnabled(const nsACString& aType)
 {
 #ifdef MOZ_WEBM
-  if (!MediaDecoder::IsWebMEnabled()) {
-    return false;
-  }
+  return IsWebMSupportedType(aType);
+#endif
+  return false;
+}
 
-  return CodecListContains(gWebMTypes, aType);
+/* static */ bool
+DecoderTraits::IsWebMAudioType(const nsACString& aType)
+{
+#ifdef MOZ_WEBM
+  return aType.EqualsASCII("audio/webm");
 #endif
   return false;
 }
 
 #ifdef MOZ_GSTREAMER
 static bool
 IsGStreamerSupportedType(const nsACString& aMimeType)
 {
@@ -390,17 +386,23 @@ DecoderTraits::CanHandleCodecsType(const
   }
 #ifdef MOZ_WAVE
   if (IsWaveType(nsDependentCString(aMIMEType))) {
     codecList = gWaveCodecs;
   }
 #endif
 #if !defined(MOZ_OMX_WEBM_DECODER)
   if (IsWebMTypeAndEnabled(nsDependentCString(aMIMEType))) {
-    codecList = gWebMCodecs;
+    if (IsWebMSupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
+      return CANPLAY_YES;
+    } else {
+      // We can only reach this position if a particular codec was requested,
+      // webm is supported and working: the codec must be invalid.
+      return CANPLAY_NO;
+    }
   }
 #endif
 #ifdef MOZ_FMP4
   if (IsMP4TypeAndEnabled(nsDependentCString(aMIMEType))) {
     if (IsMP4SupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
       return CANPLAY_YES;
     } else {
       // We can only reach this position if a particular codec was requested,
@@ -596,20 +598,22 @@ InstantiateDecoder(const nsACString& aTy
 #endif
 #ifdef MOZ_ANDROID_OMX
   if (MediaDecoder::IsAndroidMediaEnabled() &&
       EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
     decoder = new AndroidMediaDecoder(aOwner, aType);
     return decoder.forget();
   }
 #endif
-  if (DecoderTraits::IsWebMTypeAndEnabled(aType)) {
+#ifdef MOZ_WEBM
+  if (IsWebMSupportedType(aType)) {
     decoder = new WebMDecoder(aOwner);
     return decoder.forget();
   }
+#endif
 #ifdef MOZ_DIRECTSHOW
   // Note: DirectShow should come before WMF, so that we prefer DirectShow's
   // MP3 support over WMF's.
   if (IsDirectShowSupportedType(aType)) {
     decoder = new DirectShowDecoder(aOwner);
     return decoder.forget();
   }
 #endif
@@ -666,21 +670,23 @@ MediaDecoderReader* DecoderTraits::Creat
   } else
 #endif
 #ifdef MOZ_ANDROID_OMX
   if (MediaDecoder::IsAndroidMediaEnabled() &&
       EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
     decoderReader = new AndroidMediaReader(aDecoder, aType);
   } else
 #endif
-  if (IsWebMTypeAndEnabled(aType)) {
+#ifdef MOZ_WEBM
+  if (IsWebMSupportedType(aType)) {
     decoderReader = Preferences::GetBool("media.format-reader.webm", true) ?
       static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new WebMDemuxer(aDecoder->GetResource()))) :
       new WebMReader(aDecoder);
   } else
+#endif
 #ifdef MOZ_DIRECTSHOW
   if (IsDirectShowSupportedType(aType)) {
     decoderReader = new DirectShowReader(aDecoder);
   } else
 #endif
   if (false) {} // dummy if to take care of the dangling else
 
   return decoderReader;
@@ -701,17 +707,19 @@ bool DecoderTraits::IsSupportedInVideoDo
     IsOggType(aType) ||
 #ifdef MOZ_OMX_DECODER
     // We support the formats in gB2GOnlyTypes only inside WebApps on firefoxOS
     // but not in general web content. Ensure we dont create a VideoDocument
     // when accessing those format URLs directly.
     (IsOmxSupportedType(aType) &&
      !IsB2GSupportOnlyType(aType)) ||
 #endif
-    IsWebMTypeAndEnabled(aType) ||
+#ifdef MOZ_WEBM
+    IsWebMSupportedType(aType) ||
+#endif
 #ifdef MOZ_GSTREAMER
     IsGStreamerSupportedType(aType) ||
 #endif
 #ifdef MOZ_ANDROID_OMX
     (MediaDecoder::IsAndroidMediaEnabled() && IsAndroidMediaType(aType)) ||
 #endif
 #ifdef MOZ_FMP4
     IsMP4SupportedType(aType) ||
--- a/dom/media/DecoderTraits.h
+++ b/dom/media/DecoderTraits.h
@@ -66,15 +66,16 @@ public:
   // vice versa.
   static bool IsSupportedInVideoDocument(const nsACString& aType);
 
   // Returns true if we should not start decoder until we receive
   // OnConnected signal. (currently RTSP only)
   static bool DecoderWaitsForOnConnected(const nsACString& aType);
 
   static bool IsWebMTypeAndEnabled(const nsACString& aType);
+  static bool IsWebMAudioType(const nsACString& aType);
   static bool IsMP4TypeAndEnabled(const nsACString& aType);
 };
 
 } // namespace mozilla
 
 #endif
 
--- a/dom/media/FrameStatistics.h
+++ b/dom/media/FrameStatistics.h
@@ -8,16 +8,18 @@
 #define FrameStatistics_h_
 
 namespace mozilla {
 
 // Frame decoding/painting related performance counters.
 // Threadsafe.
 class FrameStatistics {
 public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FrameStatistics);
+
   FrameStatistics() :
       mReentrantMonitor("FrameStats"),
       mParsedFrames(0),
       mDecodedFrames(0),
       mPresentedFrames(0),
       mDroppedFrames(0),
       mCorruptFrames(0) {}
 
@@ -75,16 +77,17 @@ public:
   }
 
   void NotifyCorruptFrame() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     ++mCorruptFrames;
   }
 
 private:
+  ~FrameStatistics() {}
 
   // ReentrantMonitor to protect access of playback statistics.
   ReentrantMonitor mReentrantMonitor;
 
   // Number of frames parsed and demuxed from media.
   // Access protected by mReentrantMonitor.
   uint32_t mParsedFrames;
 
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -497,16 +497,17 @@ MediaDecoder::MediaDecoder(MediaDecoderO
   , mDuration(std::numeric_limits<double>::quiet_NaN())
   , mResourceCallback(new ResourceCallback())
 #ifdef MOZ_EME
   , mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__))
 #endif
   , mIgnoreProgressData(false)
   , mInfiniteStream(false)
   , mOwner(aOwner)
+  , mFrameStats(new FrameStatistics())
   , mVideoFrameContainer(aOwner->GetVideoFrameContainer())
   , mPlaybackStatistics(new MediaChannelStatistics())
   , mPinnedForSeek(false)
   , mShuttingDown(false)
   , mPausedForPlaybackRateNull(false)
   , mMinimizePreroll(false)
   , mMediaTracksConstructed(false)
   , mFiredMetadataLoaded(false)
@@ -609,23 +610,26 @@ MediaDecoder::Shutdown()
 #ifdef MOZ_EME
   mCDMProxyPromiseHolder.RejectIfExists(true, __func__);
 #endif
 
   // This changes the decoder state to SHUTDOWN and does other things
   // necessary to unblock the state machine thread if it's blocked, so
   // the asynchronous shutdown in nsDestroyStateMachine won't deadlock.
   if (mDecoderStateMachine) {
-    mDecoderStateMachine->DispatchShutdown();
     mTimedMetadataListener.Disconnect();
     mMetadataLoadedListener.Disconnect();
     mFirstFrameLoadedListener.Disconnect();
     mOnPlaybackEvent.Disconnect();
     mOnSeekingStart.Disconnect();
     mOnMediaNotSeekable.Disconnect();
+
+    mDecoderStateMachine->BeginShutdown()->Then(
+      AbstractThread::MainThread(), __func__, this,
+      &MediaDecoder::FinishShutdown, &MediaDecoder::FinishShutdown);
   }
 
   // Force any outstanding seek and byterange requests to complete
   // to prevent shutdown from deadlocking.
   if (mResource) {
     mResource->Close();
   }
 
@@ -662,16 +666,24 @@ MediaDecoder::OnPlaybackEvent(MediaEvent
       DecodeError();
       break;
     case MediaEventType::Invalidate:
       Invalidate();
       break;
   }
 }
 
+void
+MediaDecoder::FinishShutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mDecoderStateMachine->BreakCycles();
+  SetStateMachine(nullptr);
+}
+
 MediaResourceCallback*
 MediaDecoder::GetResourceCallback() const
 {
   return mResourceCallback;
 }
 
 nsresult
 MediaDecoder::OpenResource(nsIStreamListener** aStreamListener)
@@ -1533,23 +1545,16 @@ MediaDecoder::NotifyDataArrived() {
 
 // Provide access to the state machine object
 MediaDecoderStateMachine*
 MediaDecoder::GetStateMachine() const {
   MOZ_ASSERT(NS_IsMainThread());
   return mDecoderStateMachine;
 }
 
-// Drop reference to state machine.  Only called during shutdown dance.
-void
-MediaDecoder::BreakCycles() {
-  MOZ_ASSERT(NS_IsMainThread());
-  SetStateMachine(nullptr);
-}
-
 void
 MediaDecoder::FireTimeUpdate()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mShuttingDown) {
     return;
   }
   mOwner->FireTimeUpdate(true);
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -631,19 +631,16 @@ private:
     MOZ_ASSERT(NS_IsMainThread());
     UpdateLogicalPosition(MediaDecoderEventVisibility::Observable);
   }
 
   // Find the end of the cached data starting at the current decoder
   // position.
   int64_t GetDownloadPosition();
 
-  // Drop reference to state machine.  Only called during shutdown dance.
-  virtual void BreakCycles();
-
   // Notifies the element that decoding has failed.
   void DecodeError();
 
   // Indicate whether the media is same-origin with the element.
   void UpdateSameOriginStatus(bool aSameOrigin);
 
   MediaDecoderOwner* GetOwner() override;
 
@@ -695,17 +692,17 @@ private:
 
   // Return statistics. This is used for progress events and other things.
   // This can be called from any thread. It's only a snapshot of the
   // current state, since other threads might be changing the state
   // at any time.
   MediaStatistics GetStatistics();
 
   // Return the frame decode/paint related statistics.
-  FrameStatistics& GetFrameStatistics() { return mFrameStats; }
+  FrameStatistics& GetFrameStatistics() { return *mFrameStats; }
 
   // Increments the parsed and decoded frame counters by the passed in counts.
   // Can be called on any thread.
   virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
                                    uint32_t aDropped) override
   {
     GetFrameStatistics().NotifyDecodedFrames(aParsed, aDecoded, aDropped);
   }
@@ -810,16 +807,18 @@ private:
 
   void OnPlaybackEvent(MediaEventType aEvent);
 
   void OnMediaNotSeekable()
   {
     SetMediaSeekable(false);
   }
 
+  void FinishShutdown();
+
   MediaEventProducer<void> mDataArrivedEvent;
 
   // The state machine object for handling the decoding. It is safe to
   // call methods of this object from other threads. Its internal data
   // is synchronised on a monitor. The lifetime of this object is
   // after mPlayState is LOADING and before mPlayState is SHUTDOWN. It
   // is safe to access it during this period.
   //
@@ -861,17 +860,17 @@ protected:
   void OnMetadataUpdate(TimedMetadata&& aMetadata);
 
   // This should only ever be accessed from the main thread.
   // It is set in Init and cleared in Shutdown when the element goes away.
   // The decoder does not add a reference the element.
   MediaDecoderOwner* const mOwner;
 
   // Counters related to decode and presentation of frames.
-  FrameStatistics mFrameStats;
+  const RefPtr<FrameStatistics> mFrameStats;
 
   const RefPtr<VideoFrameContainer> mVideoFrameContainer;
 
   // Data needed to estimate playback data rate. The timeline used for
   // this estimate is "decode time" (where the "current time" is the
   // time of the last decoded video frame).
   RefPtr<MediaChannelStatistics> mPlaybackStatistics;
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -57,29 +57,29 @@ using namespace mozilla::media;
 #define NS_DispatchToMainThread(...) CompileError_UseAbstractThreadDispatchInstead
 
 // avoid redefined macro in unified build
 #undef LOG
 #undef DECODER_LOG
 #undef VERBOSE_LOG
 
 #define LOG(m, l, x, ...) \
-  MOZ_LOG(m, l, ("Decoder=%p " x, mDecoder.get(), ##__VA_ARGS__))
+  MOZ_LOG(m, l, ("Decoder=%p " x, mDecoderID, ##__VA_ARGS__))
 #define DECODER_LOG(x, ...) \
   LOG(gMediaDecoderLog, LogLevel::Debug, x, ##__VA_ARGS__)
 #define VERBOSE_LOG(x, ...) \
   LOG(gMediaDecoderLog, LogLevel::Verbose, x, ##__VA_ARGS__)
 #define SAMPLE_LOG(x, ...) \
   LOG(gMediaSampleLog, LogLevel::Debug, x, ##__VA_ARGS__)
 
 // Somehow MSVC doesn't correctly delete the comma before ##__VA_ARGS__
 // when __VA_ARGS__ expands to nothing. This is a workaround for it.
 #define DECODER_WARN_HELPER(a, b) NS_WARNING b
 #define DECODER_WARN(x, ...) \
-  DECODER_WARN_HELPER(0, (nsPrintfCString("Decoder=%p " x, mDecoder.get(), ##__VA_ARGS__).get()))
+  DECODER_WARN_HELPER(0, (nsPrintfCString("Decoder=%p " x, mDecoderID, ##__VA_ARGS__).get()))
 
 // Certain constants get stored as member variables and then adjusted by various
 // scale factors on a per-decoder basis. We want to make sure to avoid using these
 // constants directly, so we put them in a namespace.
 namespace detail {
 
 // If audio queue has less than this many usecs of decoded audio, we won't risk
 // trying to decode the video, we'll skip decoding video up to the next
@@ -194,17 +194,20 @@ static void InitVideoQueuePrefs() {
     sVideoQueueSendToCompositorSize = Preferences::GetUint(
       "media.video-queue.send-to-compositor-size", VIDEO_QUEUE_SEND_TO_COMPOSITOR_SIZE);
   }
 }
 
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                                    MediaDecoderReader* aReader,
                                                    bool aRealTime) :
-  mDecoder(aDecoder),
+  mDecoderID(aDecoder),
+  mFrameStats(&aDecoder->GetFrameStatistics()),
+  mVideoFrameContainer(aDecoder->GetVideoFrameContainer()),
+  mAudioChannel(aDecoder->GetAudioChannel()),
   mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
                            /* aSupportsTailDispatch = */ true)),
   mWatchManager(this, mTaskQueue),
   mRealTime(aRealTime),
   mDispatchedStateMachine(false),
   mDelayedScheduler(mTaskQueue),
   mState(DECODER_STATE_DECODING_NONE, "MediaDecoderStateMachine::mState"),
   mCurrentFrameID(0),
@@ -275,17 +278,18 @@ MediaDecoderStateMachine::MediaDecoderSt
                    "MediaDecoderStateMachine::mCurrentPosition (Canonical)"),
   mPlaybackOffset(mTaskQueue, 0,
                   "MediaDecoderStateMachine::mPlaybackOffset (Canonical)")
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
   // Dispatch initialization that needs to happen on that task queue.
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::InitializationTask);
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArg<RefPtr<MediaDecoder>>(
+    this, &MediaDecoderStateMachine::InitializationTask, aDecoder);
   mTaskQueue->Dispatch(r.forget());
 
   InitVideoQueuePrefs();
 
   mBufferingWait = IsRealTime() ? 0 : 15;
   mLowDataThresholdUsecs = IsRealTime() ? 0 : detail::LOW_DATA_THRESHOLD_USECS;
 
 #ifdef XP_WIN
@@ -302,17 +306,17 @@ MediaDecoderStateMachine::MediaDecoderSt
   mVideoQueueListener = VideoQueue().PopEvent().Connect(
     mTaskQueue, this, &MediaDecoderStateMachine::OnVideoPopped);
 
   mMetadataManager.Connect(mReader->TimedMetadataEvent(), OwnerThread());
 
   mMediaSink = CreateMediaSink(mAudioCaptured);
 
 #ifdef MOZ_EME
-  mCDMProxyPromise.Begin(mDecoder->RequestCDMProxy()->Then(
+  mCDMProxyPromise.Begin(aDecoder->RequestCDMProxy()->Then(
     OwnerThread(), __func__, this,
     &MediaDecoderStateMachine::OnCDMProxyReady,
     &MediaDecoderStateMachine::OnCDMProxyNotReady));
 #endif
 }
 
 MediaDecoderStateMachine::~MediaDecoderStateMachine()
 {
@@ -322,35 +326,35 @@ MediaDecoderStateMachine::~MediaDecoderS
   mReader = nullptr;
 
 #ifdef XP_WIN
   timeEndPeriod(1);
 #endif
 }
 
 void
-MediaDecoderStateMachine::InitializationTask()
+MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // Connect mirrors.
   mBuffered.Connect(mReader->CanonicalBuffered());
-  mEstimatedDuration.Connect(mDecoder->CanonicalEstimatedDuration());
-  mExplicitDuration.Connect(mDecoder->CanonicalExplicitDuration());
-  mPlayState.Connect(mDecoder->CanonicalPlayState());
-  mNextPlayState.Connect(mDecoder->CanonicalNextPlayState());
-  mLogicallySeeking.Connect(mDecoder->CanonicalLogicallySeeking());
-  mVolume.Connect(mDecoder->CanonicalVolume());
-  mLogicalPlaybackRate.Connect(mDecoder->CanonicalPlaybackRate());
-  mPreservesPitch.Connect(mDecoder->CanonicalPreservesPitch());
-  mSameOriginMedia.Connect(mDecoder->CanonicalSameOriginMedia());
-  mPlaybackBytesPerSecond.Connect(mDecoder->CanonicalPlaybackBytesPerSecond());
-  mPlaybackRateReliable.Connect(mDecoder->CanonicalPlaybackRateReliable());
-  mDecoderPosition.Connect(mDecoder->CanonicalDecoderPosition());
-  mMediaSeekable.Connect(mDecoder->CanonicalMediaSeekable());
+  mEstimatedDuration.Connect(aDecoder->CanonicalEstimatedDuration());
+  mExplicitDuration.Connect(aDecoder->CanonicalExplicitDuration());
+  mPlayState.Connect(aDecoder->CanonicalPlayState());
+  mNextPlayState.Connect(aDecoder->CanonicalNextPlayState());
+  mLogicallySeeking.Connect(aDecoder->CanonicalLogicallySeeking());
+  mVolume.Connect(aDecoder->CanonicalVolume());
+  mLogicalPlaybackRate.Connect(aDecoder->CanonicalPlaybackRate());
+  mPreservesPitch.Connect(aDecoder->CanonicalPreservesPitch());
+  mSameOriginMedia.Connect(aDecoder->CanonicalSameOriginMedia());
+  mPlaybackBytesPerSecond.Connect(aDecoder->CanonicalPlaybackBytesPerSecond());
+  mPlaybackRateReliable.Connect(aDecoder->CanonicalPlaybackRateReliable());
+  mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition());
+  mMediaSeekable.Connect(aDecoder->CanonicalMediaSeekable());
 
   // Initialize watchers.
   mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated);
   mWatchManager.Watch(mState, &MediaDecoderStateMachine::UpdateNextFrameStatus);
   mWatchManager.Watch(mAudioCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
   mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
   mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged);
   mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
@@ -370,34 +374,34 @@ MediaDecoderStateMachine::Initialization
 media::MediaSink*
 MediaDecoderStateMachine::CreateAudioSink()
 {
   RefPtr<MediaDecoderStateMachine> self = this;
   auto audioSinkCreator = [self] () {
     MOZ_ASSERT(self->OnTaskQueue());
     return new DecodedAudioDataSink(
       self->mAudioQueue, self->GetMediaTime(),
-      self->mInfo.mAudio, self->mDecoder->GetAudioChannel());
+      self->mInfo.mAudio, self->mAudioChannel);
   };
   return new AudioSinkWrapper(mTaskQueue, audioSinkCreator);
 }
 
 already_AddRefed<media::MediaSink>
 MediaDecoderStateMachine::CreateMediaSink(bool aAudioCaptured)
 {
   // TODO: We can't really create a new DecodedStream until OutputStreamManager
   //       is extracted. It is tricky that the implementation of DecodedStream
   //       happens to allow reuse after shutdown without creating a new one.
   RefPtr<media::MediaSink> audioSink = aAudioCaptured ?
     mStreamSink : CreateAudioSink();
 
   RefPtr<media::MediaSink> mediaSink =
     new VideoSink(mTaskQueue, audioSink, mVideoQueue,
-                  mDecoder->GetVideoFrameContainer(), mRealTime,
-                  mDecoder->GetFrameStatistics(),
+                  mVideoFrameContainer, mRealTime,
+                  *mFrameStats,
                   sVideoQueueSendToCompositorSize);
   return mediaSink.forget();
 }
 
 bool MediaDecoderStateMachine::HasFutureAudio()
 {
   MOZ_ASSERT(OnTaskQueue());
   NS_ASSERTION(HasAudio(), "Should only call HasFutureAudio() when we have audio");
@@ -1294,17 +1298,18 @@ MediaDecoderStateMachine::SetDormant(boo
     DecodeTaskQueue()->Dispatch(r.forget());
   } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
     ScheduleStateMachine();
     mDecodingFirstFrame = true;
     SetState(DECODER_STATE_DECODING_NONE);
   }
 }
 
-void MediaDecoderStateMachine::Shutdown()
+RefPtr<ShutdownPromise>
+MediaDecoderStateMachine::Shutdown()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // Once we've entered the shutdown state here there's no going back.
   // Change state before issuing shutdown request to threads so those
   // threads can start exiting cleanly during the Shutdown call.
   ScheduleStateMachine();
   SetState(DECODER_STATE_SHUTDOWN);
@@ -1325,23 +1330,26 @@ void MediaDecoderStateMachine::Shutdown(
 
   mMediaSink->Shutdown();
 
   // Shut down our start time rendezvous.
   if (mStartTimeRendezvous) {
     mStartTimeRendezvous->Destroy();
   }
 
+  DECODER_LOG("Shutdown started");
+
   // Put a task in the decode queue to shutdown the reader.
   // the queue to spin down.
-  InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__, &MediaDecoderReader::Shutdown)
+  return InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
+                     &MediaDecoderReader::Shutdown)
     ->Then(OwnerThread(), __func__, this,
            &MediaDecoderStateMachine::FinishShutdown,
-           &MediaDecoderStateMachine::FinishShutdown);
-  DECODER_LOG("Shutdown started");
+           &MediaDecoderStateMachine::FinishShutdown)
+    ->CompletionPromise();
 }
 
 void MediaDecoderStateMachine::StartDecoding()
 {
   MOZ_ASSERT(OnTaskQueue());
   if (mState == DECODER_STATE_DECODING && !mDecodingFirstFrame) {
     return;
   }
@@ -2149,50 +2157,25 @@ MediaDecoderStateMachine::SeekCompleted(
   ScheduleStateMachine();
 
   if (video) {
     mMediaSink->Redraw();
     mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
   }
 }
 
-class DecoderDisposer
-{
-public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecoderDisposer)
-  DecoderDisposer(MediaDecoder* aDecoder, MediaDecoderStateMachine* aStateMachine)
-    : mDecoder(aDecoder), mStateMachine(aStateMachine) {}
-
-  void OnTaskQueueShutdown()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    MOZ_ASSERT(mStateMachine);
-    MOZ_ASSERT(mDecoder);
-    mStateMachine->BreakCycles();
-    mDecoder->BreakCycles();
-    mStateMachine = nullptr;
-    mDecoder = nullptr;
-  }
-
-private:
-  virtual ~DecoderDisposer() {}
-  RefPtr<MediaDecoder> mDecoder;
-  RefPtr<MediaDecoderStateMachine> mStateMachine;
-};
-
-void
-MediaDecoderStateMachine::DispatchShutdown()
+RefPtr<ShutdownPromise>
+MediaDecoderStateMachine::BeginShutdown()
 {
   mStreamSink->BeginShutdown();
-  nsCOMPtr<nsIRunnable> runnable =
-    NS_NewRunnableMethod(this, &MediaDecoderStateMachine::Shutdown);
-  OwnerThread()->Dispatch(runnable.forget());
+  return InvokeAsync(OwnerThread(), this, __func__,
+                     &MediaDecoderStateMachine::Shutdown);
 }
 
-void
+RefPtr<ShutdownPromise>
 MediaDecoderStateMachine::FinishShutdown()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // The reader's listeners hold references to the state machine,
   // creating a cycle which keeps the state machine and its shared
   // thread pools alive. So break it here.
 
@@ -2223,35 +2206,18 @@ MediaDecoderStateMachine::FinishShutdown
   mCurrentPosition.DisconnectAll();
   mPlaybackOffset.DisconnectAll();
 
   // Shut down the watch manager before shutting down our task queue.
   mWatchManager.Shutdown();
 
   MOZ_ASSERT(mState == DECODER_STATE_SHUTDOWN,
              "How did we escape from the shutdown state?");
-  // We must daisy-chain these events to destroy the decoder. We must
-  // destroy the decoder on the main thread, but we can't destroy the
-  // decoder while this thread holds the decoder monitor. We can't
-  // dispatch an event to the main thread to destroy the decoder from
-  // here, as the event may run before the dispatch returns, and we
-  // hold the decoder monitor here. We also want to guarantee that the
-  // state machine is destroyed on the main thread, and so the
-  // event runner running this function (which holds a reference to the
-  // state machine) needs to finish and be released in order to allow
-  // that. So we dispatch an event to run after this event runner has
-  // finished and released its monitor/references. That event then will
-  // dispatch an event to the main thread to release the decoder and
-  // state machine.
   DECODER_LOG("Shutting down state machine task queue");
-  RefPtr<DecoderDisposer> disposer = new DecoderDisposer(mDecoder, this);
-  OwnerThread()->BeginShutdown()->Then(AbstractThread::MainThread(), __func__,
-                                       disposer.get(),
-                                       &DecoderDisposer::OnTaskQueueShutdown,
-                                       &DecoderDisposer::OnTaskQueueShutdown);
+  return OwnerThread()->BeginShutdown();
 }
 
 nsresult MediaDecoderStateMachine::RunStateMachine()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   mDelayedScheduler.Reset(); // Must happen on state machine task queue.
   mDispatchedStateMachine = false;
@@ -2464,17 +2430,17 @@ MediaDecoderStateMachine::Reset()
 
 void
 MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // Update corrupt-frames statistics
   if (aData->mImage && !aData->mImage->IsValid()) {
-    FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
+    FrameStatistics& frameStats = *mFrameStats;
     frameStats.NotifyCorruptFrame();
     // If more than 10% of the last 30 frames have been corrupted, then try disabling
     // hardware acceleration. We use 10 as the corrupt value because RollingMean<>
     // only supports integer types.
     mCorruptFrames.insert(10);
     if (mReader->VideoIsHardwareAccelerated() &&
         frameStats.GetPresentedFrames() > 60 &&
         mCorruptFrames.mean() >= 2 /* 20% */) {
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -162,17 +162,17 @@ public:
   void RemoveOutputStream(MediaStream* aStream);
 
   // Seeks to the decoder to aTarget asynchronously.
   RefPtr<MediaDecoder::SeekPromise> InvokeSeek(SeekTarget aTarget);
 
   // Set/Unset dormant state.
   void DispatchSetDormant(bool aDormant);
 
-  void DispatchShutdown();
+  RefPtr<ShutdownPromise> BeginShutdown();
 
   void DispatchStartBuffering()
   {
     nsCOMPtr<nsIRunnable> runnable =
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::StartBuffering);
     OwnerThread()->Dispatch(runnable.forget());
   }
 
@@ -213,24 +213,23 @@ public:
       if (self->mAudioOffloading != aAudioOffloading) {
         self->mAudioOffloading = aAudioOffloading;
         self->ScheduleStateMachine();
       }
     });
     OwnerThread()->Dispatch(r.forget());
   }
 
-  // Drop reference to decoder.  Only called during shutdown dance.
+  // Drop reference to mReader and mResource. Only called during shutdown dance.
   void BreakCycles() {
     MOZ_ASSERT(NS_IsMainThread());
     if (mReader) {
       mReader->BreakCycles();
     }
     mResource = nullptr;
-    mDecoder = nullptr;
   }
 
   TimedMetadataEventSource& TimedMetadataEvent() {
     return mMetadataManager.TimedMetadataEvent();
   }
 
   MediaEventSource<void>& OnMediaNotSeekable() {
     return mReader->OnMediaNotSeekable();
@@ -271,27 +270,27 @@ public:
 private:
   // Functions used by assertions to ensure we're calling things
   // on the appropriate threads.
   bool OnTaskQueue() const;
 
   // Initialization that needs to happen on the task queue. This is the first
   // task that gets run on the task queue, and is dispatched from the MDSM
   // constructor immediately after the task queue is created.
-  void InitializationTask();
+  void InitializationTask(MediaDecoder* aDecoder);
 
   void SetDormant(bool aDormant);
 
   void SetAudioCaptured(bool aCaptured);
 
   RefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget);
 
-  void Shutdown();
+  RefPtr<ShutdownPromise> Shutdown();
 
-  void FinishShutdown();
+  RefPtr<ShutdownPromise> FinishShutdown();
 
   // Update the playback position. This can result in a timeupdate event
   // and an invalidate of the frame being dispatched asynchronously if
   // there is no such event currently queued.
   // Only called on the decoder thread. Must be called with
   // the decode monitor held.
   void UpdatePlaybackPosition(int64_t aTime);
 
@@ -661,26 +660,20 @@ private:
   void OnMediaSinkVideoError();
 
   // Return true if the video decoder's decode speed can not catch up the
   // play time.
   bool NeedToSkipToNextKeyframe();
 
   void AdjustAudioThresholds();
 
-  // The decoder object that created this state machine. The state machine
-  // holds a strong reference to the decoder to ensure that the decoder stays
-  // alive once media element has started the decoder shutdown process, and has
-  // dropped its reference to the decoder. This enables the state machine to
-  // keep using the decoder's monitor until the state machine has finished
-  // shutting down, without fear of the monitor being destroyed. After
-  // shutting down, the state machine will then release this reference,
-  // causing the decoder to be destroyed. This is accessed on the decode,
-  // state machine, audio and main threads.
-  RefPtr<MediaDecoder> mDecoder;
+  void* const mDecoderID;
+  const RefPtr<FrameStatistics> mFrameStats;
+  const RefPtr<VideoFrameContainer> mVideoFrameContainer;
+  const dom::AudioChannel mAudioChannel;
 
   // Task queue for running the state machine.
   RefPtr<TaskQueue> mTaskQueue;
 
   // State-watching manager.
   WatchManager<MediaDecoderStateMachine> mWatchManager;
 
   // True is we are decoding a realtime stream, like a camera stream.
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -505,16 +505,24 @@ MediaFormatReader::RequestVideoData(bool
     NS_WARNING("RequestVideoData on shutdown MediaFormatReader!");
     return VideoDataPromise::CreateAndReject(CANCELED, __func__);
   }
 
   media::TimeUnit timeThreshold{media::TimeUnit::FromMicroseconds(aTimeThreshold)};
   if (ShouldSkip(aSkipToNextKeyframe, timeThreshold)) {
     // Cancel any pending demux request.
     mVideo.mDemuxRequest.DisconnectIfExists();
+
+    // I think it's still possible for an output to have been sent from the decoder
+    // and is currently sitting in our event queue waiting to be processed. The following
+    // flush won't clear it, and when we return to the event loop it'll be added to our
+    // output queue and be used.
+    // This code will count that as dropped, which was the intent, but not quite true.
+    mDecoder->NotifyDecodedFrames(0, 0, SizeOfVideoQueueInFrames());
+
     Flush(TrackInfo::kVideoTrack);
     RefPtr<VideoDataPromise> p = mVideo.mPromise.Ensure(__func__);
     SkipVideoDemuxToNextKeyFrame(timeThreshold);
     return p;
   }
 
   RefPtr<VideoDataPromise> p = mVideo.mPromise.Ensure(__func__);
   NotifyDecodingRequested(TrackInfo::kVideoTrack);
--- a/dom/media/VideoFrameContainer.h
+++ b/dom/media/VideoFrameContainer.h
@@ -73,16 +73,18 @@ public:
     INVALIDATE_DEFAULT,
     INVALIDATE_FORCE
   };
   void Invalidate() { InvalidateWithFlags(INVALIDATE_DEFAULT); }
   B2G_ACL_EXPORT void InvalidateWithFlags(uint32_t aFlags);
   B2G_ACL_EXPORT ImageContainer* GetImageContainer();
   void ForgetElement() { mElement = nullptr; }
 
+  uint32_t GetDroppedImageCount() { return mImageContainer->GetDroppedImageCount(); }
+
 protected:
   void SetCurrentFramesLocked(const gfx::IntSize& aIntrinsicSize,
                               const nsTArray<ImageContainer::NonOwningImage>& aImages);
 
   // Non-addreffed pointer to the element. The element calls ForgetElement
   // to clear this reference when the element is destroyed.
   dom::HTMLMediaElement* mElement;
   RefPtr<ImageContainer> mImageContainer;
--- a/dom/media/compiledtest/TestAudioPacketizer.cpp
+++ b/dom/media/compiledtest/TestAudioPacketizer.cpp
@@ -1,16 +1,15 @@
 /* -*- 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 <stdint.h>
 #include <assert.h>
-#define _USE_MATH_DEFINES
 #include <math.h>
 #include "../AudioPacketizer.h"
 
 using namespace mozilla;
 
 template<typename T>
 class AutoBuffer
 {
--- a/dom/media/eme/EMEUtils.cpp
+++ b/dom/media/eme/EMEUtils.cpp
@@ -98,26 +98,16 @@ ParseKeySystem(const nsAString& aInputKe
       aOutKeySystem = keySystem;
       aOutCDMVersion = minCDMVersion;
       return true;
     }
   }
   return false;
 }
 
-void
-ConstructKeySystem(const nsAString& aKeySystem,
-                   const nsAString& aCDMVersion,
-                   nsAString& aOutKeySystem)
-{
-  aOutKeySystem.Append(aKeySystem);
-  aOutKeySystem.AppendLiteral(".");
-  aOutKeySystem.Append(aCDMVersion);
-}
-
 ArrayData
 GetArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView)
 {
   MOZ_ASSERT(aBufferOrView.IsArrayBuffer() || aBufferOrView.IsArrayBufferView());
   if (aBufferOrView.IsArrayBuffer()) {
     const dom::ArrayBuffer& buffer = aBufferOrView.GetAsArrayBuffer();
     buffer.ComputeLengthAndData();
     return ArrayData(buffer.Data(), buffer.Length());
--- a/dom/media/eme/EMEUtils.h
+++ b/dom/media/eme/EMEUtils.h
@@ -51,21 +51,16 @@ class ArrayBufferViewOrArrayBuffer;
 //
 // On success, aOutKeySystem contains the keySystem string stripped of the
 // min version number, and aOutMinCDMVersion contains the min version number
 // if present. If it was not present, aOutMinCDMVersion is NO_CDM_VERSION.
 bool ParseKeySystem(const nsAString& aKeySystem,
                     nsAString& aOutKeySystem,
                     int32_t& aOutMinCDMVersion);
 
-void
-ConstructKeySystem(const nsAString& aKeySystem,
-                   const nsAString& aCDMVersion,
-                   nsAString& aOutKeySystem);
-
 // Helper function to extract a copy of data coming in from JS in an
 // (ArrayBuffer or ArrayBufferView) IDL typed function argument.
 //
 // Only call this on a properly initialized ArrayBufferViewOrArrayBuffer.
 void
 CopyArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView,
                                      nsTArray<uint8_t>& aOutData);
 
--- a/dom/media/eme/MediaKeySession.cpp
+++ b/dom/media/eme/MediaKeySession.cpp
@@ -86,17 +86,17 @@ MediaKeyError*
 MediaKeySession::GetError() const
 {
   return mMediaKeyError;
 }
 
 void
 MediaKeySession::GetKeySystem(nsString& aOutKeySystem) const
 {
-  ConstructKeySystem(mKeySystem, mCDMVersion, aOutKeySystem);
+  aOutKeySystem.Assign(mKeySystem);
 }
 
 void
 MediaKeySession::GetSessionId(nsString& aSessionId) const
 {
   aSessionId = GetSessionId();
 }
 
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -75,17 +75,17 @@ nsPIDOMWindow*
 MediaKeySystemAccess::GetParentObject() const
 {
   return mParent;
 }
 
 void
 MediaKeySystemAccess::GetKeySystem(nsString& aOutKeySystem) const
 {
-  ConstructKeySystem(mKeySystem, mCDMVersion, aOutKeySystem);
+  aOutKeySystem.Assign(mKeySystem);
 }
 
 void
 MediaKeySystemAccess::GetConfiguration(MediaKeySystemConfiguration& aConfig)
 {
   aConfig = mConfig;
 }
 
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -120,17 +120,17 @@ JSObject*
 MediaKeys::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return MediaKeysBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 MediaKeys::GetKeySystem(nsString& aOutKeySystem) const
 {
-  ConstructKeySystem(mKeySystem, mCDMVersion, aOutKeySystem);
+  aOutKeySystem.Assign(mKeySystem);
 }
 
 already_AddRefed<DetailedPromise>
 MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, ErrorResult& aRv)
 {
   RefPtr<DetailedPromise> promise(MakePromise(aRv,
     NS_LITERAL_CSTRING("MediaKeys.setServerCertificate")));
   if (aRv.Failed()) {
--- a/dom/media/mediasink/VideoSink.cpp
+++ b/dom/media/mediasink/VideoSink.cpp
@@ -30,16 +30,17 @@ VideoSink::VideoSink(AbstractThread* aTh
   : mOwnerThread(aThread)
   , mAudioSink(aAudioSink)
   , mVideoQueue(aVideoQueue)
   , mContainer(aContainer)
   , mProducerID(ImageContainer::AllocateProducerID())
   , mRealTime(aRealTime)
   , mFrameStats(aFrameStats)
   , mVideoFrameEndTime(-1)
+  , mOldDroppedCount(0)
   , mHasVideo(false)
   , mUpdateScheduler(aThread)
   , mVideoQueueSendToCompositorSize(aVQueueSentToCompositerSize)
 {
   MOZ_ASSERT(mAudioSink, "AudioSink should exist.");
 }
 
 VideoSink::~VideoSink()
@@ -322,16 +323,20 @@ VideoSink::RenderVideoFrames(int32_t aMa
     img->mImage = frame->mImage;
     img->mFrameID = frame->mFrameID;
     img->mProducerID = mProducerID;
 
     VSINK_LOG_V("playing video frame %lld (id=%x) (vq-queued=%i)",
                 frame->mTime, frame->mFrameID, VideoQueue().GetSize());
   }
   mContainer->SetCurrentFrames(frames[0]->As<VideoData>()->mDisplay, images);
+
+  uint32_t dropped = mContainer->GetDroppedImageCount();
+  mFrameStats.NotifyDecodedFrames(0, 0, dropped - mOldDroppedCount);
+  mOldDroppedCount = dropped;
 }
 
 void
 VideoSink::UpdateRenderedVideoFrames()
 {
   AssertOwnerThread();
   MOZ_ASSERT(mAudioSink->IsPlaying(), "should be called while playing.");
 
--- a/dom/media/mediasink/VideoSink.h
+++ b/dom/media/mediasink/VideoSink.h
@@ -124,16 +124,18 @@ private:
   RefPtr<GenericPromise> mEndPromise;
   MozPromiseHolder<GenericPromise> mEndPromiseHolder;
   MozPromiseRequestHolder<GenericPromise> mVideoSinkEndRequest;
 
   // The presentation end time of the last video frame which has been displayed
   // in microseconds.
   int64_t mVideoFrameEndTime;
 
+  uint32_t mOldDroppedCount;
+
   // Event listeners for VideoQueue
   MediaEventListener mPushListener;
 
   // True if this sink is going to handle video track.
   bool mHasVideo;
 
   // Used to trigger another update of rendered frames in next round.
   DelayedScheduler mUpdateScheduler;
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -106,16 +106,18 @@ IsTypeSupported(const nsAString& aType)
         if (hasCodecs &&
             DecoderTraits::CanHandleCodecsType(mimeTypeUTF8.get(),
                                                codecs) == CANPLAY_NO) {
           return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
         }
         return NS_OK;
       } else if (DecoderTraits::IsWebMTypeAndEnabled(mimeTypeUTF8)) {
         if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) ||
+              (Preferences::GetBool("media.mediasource.webm.audio.enabled", true) &&
+               DecoderTraits::IsWebMAudioType(mimeTypeUTF8)) ||
               IsWebMForced())) {
           return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
         }
         if (hasCodecs &&
             DecoderTraits::CanHandleCodecsType(mimeTypeUTF8.get(),
                                                codecs) == CANPLAY_NO) {
           return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
         }
--- a/dom/media/test/test_eme_requestKeySystemAccess.html
+++ b/dom/media/test/test_eme_requestKeySystemAccess.html
@@ -7,17 +7,16 @@
   <script type="text/javascript" src="manifest.js"></script>
   <script type="text/javascript" src="eme.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 const CLEARKEY_ID = 'org.w3.clearkey';
-const CLEARKEY_VERSION = '1';
 const SUPPORTED_LABEL = "pass label";
 
 function ValidateConfig(name, expected, observed) {
   info("ValidateConfig " + name);
   info("expected cfg=" + JSON.stringify(expected));
   info("observed cfg=" + JSON.stringify(observed));
 
   is(observed.label, expected.label, name + " label should match");
@@ -46,17 +45,17 @@ function Test(test) {
     if (test.options) {
       p = navigator.requestMediaKeySystemAccess(test.keySystem, test.options);
     } else {
       p = navigator.requestMediaKeySystemAccess(test.keySystem);
     }
     p.then(
       function(keySystemAccess) {
         ok(test.shouldPass, name + " passed and was expected to " + (test.shouldPass ? "pass" : "fail"));
-        is(keySystemAccess.keySystem, CLEARKEY_ID + "." + CLEARKEY_VERSION, "CDM version should be in MediaKeySystemAccess.keySystem");
+        is(keySystemAccess.keySystem, CLEARKEY_ID, "CDM keySystem should be in MediaKeySystemAccess.keySystem");
         ValidateConfig(name, test.expectedConfig, keySystemAccess.getConfiguration());
         resolve();
       },
       function(ex) {
         if (test.shouldPass) {
           info(name + " failed: " + ex);
         }
         ok(!test.shouldPass, name + " failed and was expected to " + (test.shouldPass ? "pass" : "fail"));
--- a/dom/media/webaudio/blink/Biquad.cpp
+++ b/dom/media/webaudio/blink/Biquad.cpp
@@ -21,26 +21,21 @@
  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-// For M_PI
-// VS2015 requires <math.h> to be used; <cmath> doesn't seem to honor
-// _USE_MATH_DEFINES.
-#define _USE_MATH_DEFINES
-#include <math.h>
-
 #include "Biquad.h"
 
 #include <float.h>
 #include <algorithm>
+#include <math.h>
 
 namespace WebCore {
 
 Biquad::Biquad()
 {
     // Initialize as pass-thru (straight-wire, no filter effect)
     setNormalizedCoefficients(1, 0, 0, 1, 0, 0);
 
--- a/dom/media/webaudio/blink/DenormalDisabler.h
+++ b/dom/media/webaudio/blink/DenormalDisabler.h
@@ -20,17 +20,16 @@
  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef DenormalDisabler_h
 #define DenormalDisabler_h
 
-#define _USE_MATH_DEFINES
 #include <cmath>
 #include <float.h>
 
 namespace WebCore {
 
 // Deal with denormals. They can very seriously impact performance on x86.
 
 // Define HAVE_DENORMAL if we support flushing denormals to zero.
--- a/dom/media/webaudio/blink/DynamicsCompressorKernel.cpp
+++ b/dom/media/webaudio/blink/DynamicsCompressorKernel.cpp
@@ -25,19 +25,19 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "DynamicsCompressorKernel.h"
 
 #include "DenormalDisabler.h"
 #include <algorithm>
+#include <cmath>
 
 #include "mozilla/FloatingPoint.h"
-#include "mozilla/Constants.h"
 #include "WebAudioUtils.h"
 
 using namespace std;
 
 using namespace mozilla::dom; // for WebAudioUtils
 using mozilla::IsInfinite;
 using mozilla::IsNaN;
 using mozilla::MakeUnique;
--- a/dom/media/webm/WebMDecoder.cpp
+++ b/dom/media/webm/WebMDecoder.cpp
@@ -5,23 +5,75 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Preferences.h"
 #include "MediaDecoderStateMachine.h"
 #include "MediaFormatReader.h"
 #include "WebMDemuxer.h"
 #include "WebMReader.h"
 #include "WebMDecoder.h"
+#include "VideoUtils.h"
 
 namespace mozilla {
 
 MediaDecoderStateMachine* WebMDecoder::CreateStateMachine()
 {
   bool useFormatDecoder =
     Preferences::GetBool("media.format-reader.webm", true);
   RefPtr<MediaDecoderReader> reader = useFormatDecoder ?
       static_cast<MediaDecoderReader*>(new MediaFormatReader(this, new WebMDemuxer(GetResource()), GetVideoFrameContainer())) :
       new WebMReader(this);
   return new MediaDecoderStateMachine(this, reader);
 }
 
+/* static */
+bool
+WebMDecoder::IsEnabled()
+{
+  return Preferences::GetBool("media.webm.enabled");
+}
+
+/* static */
+bool
+WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
+                                const nsAString& aCodecs)
+{
+  if (!IsEnabled()) {
+    return false;
+  }
+
+  const bool isWebMAudio = aMIMETypeExcludingCodecs.EqualsASCII("audio/webm");
+  const bool isWebMVideo = aMIMETypeExcludingCodecs.EqualsASCII("video/webm");
+  if (!isWebMAudio && !isWebMVideo) {
+    return false;
+  }
+
+  nsTArray<nsCString> codecMimes;
+  if (aCodecs.IsEmpty()) {
+    // WebM guarantees that the only codecs it contained are vp8, vp9, opus or vorbis.
+    return true;
+  }
+  // Verify that all the codecs specified are ones that we expect that
+  // we can play.
+  nsTArray<nsString> codecs;
+  if (!ParseCodecsString(aCodecs, codecs)) {
+    return false;
+  }
+  for (const nsString& codec : codecs) {
+    if (codec.EqualsLiteral("opus") || codec.EqualsLiteral("vorbis")) {
+      continue;
+    }
+    // Note: Only accept VP8/VP9 in a video content type, not in an audio
+    // content type.
+    if (isWebMVideo &&
+        (codec.EqualsLiteral("vp8") || codec.EqualsLiteral("vp8.0") ||
+         codec.EqualsLiteral("vp9") || codec.EqualsLiteral("vp9.0"))) {
+
+      continue;
+    }
+    // Some unsupported codec.
+    return false;
+  }
+  return true;
+}
+
 } // namespace mozilla
 
--- a/dom/media/webm/WebMDecoder.h
+++ b/dom/media/webm/WebMDecoder.h
@@ -16,13 +16,23 @@ public:
   explicit WebMDecoder(MediaDecoderOwner* aOwner) : MediaDecoder(aOwner) {}
   virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) {
     if (!IsWebMEnabled()) {
       return nullptr;
     }
     return new WebMDecoder(aOwner);
   }
   virtual MediaDecoderStateMachine* CreateStateMachine();
+
+  // Returns true if the WebM backend is preffed on.
+  static bool IsEnabled();
+
+  // Returns true if aMIMEType is a type that we think we can render with the
+  // a WebM platform decoder backend. If aCodecs is non emtpy, it is filled
+  // with a comma-delimited list of codecs to check support for. Notes in
+  // out params whether the codecs string contains Opus/Vorbis or VP8/VP9.
+  static bool CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
+                                 const nsAString& aCodecs);
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -13,16 +13,17 @@
 #include "gfx2DGlue.h"
 #include "mozilla/Endian.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/SharedThreadPool.h"
 #include "MediaDataDemuxer.h"
 #include "nsAutoRef.h"
 #include "NesteggPacketHolder.h"
 #include "XiphExtradata.h"
+#include "prprf.h"
 
 #include <algorithm>
 #include <stdint.h>
 
 #define VPX_DONT_DEFINE_STDINT_TYPES
 #include "vpx/vp8dx.h"
 #include "vpx/vpx_decoder.h"
 
--- a/dom/media/webvtt/vtt.jsm
+++ b/dom/media/webvtt/vtt.jsm
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 this.EXPORTED_SYMBOLS = ["WebVTT"];
 
 /**
  * Code below is vtt.js the JS WebVTT implementation.
  * Current source code can be found at http://github.com/mozilla/vtt.js
  *
- * Code taken from commit 58d092419a1ee84e574ce2ba18bcbf92356fcb21
+ * Code taken from commit b89bfd06cd788a68c67e03f44561afe833db0849
  */
 /**
  * Copyright 2013 vtt.js Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
@@ -831,17 +831,18 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
   }
   CueStyleBox.prototype = _objCreate(StyleBox.prototype);
   CueStyleBox.prototype.constructor = CueStyleBox;
 
   // Represents the co-ordinates of an Element in a way that we can easily
   // compute things with such as if it overlaps or intersects with another Element.
   // Can initialize it with either a StyleBox or another BoxPosition.
   function BoxPosition(obj) {
-    var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent);
+    var isIE8 = (typeof navigator !== "undefined") &&
+      (/MSIE\s8\.0/).test(navigator.userAgent);
 
     // Either a BoxPosition was passed in and we need to copy it, or a StyleBox
     // was passed in and we need to copy the results of 'getBoundingClientRect'
     // as the object returned is readonly. All co-ordinate values are in reference
     // to the viewport origin (top left).
     var lh, height, width, top;
     if (obj.div) {
       height = obj.div.offsetHeight;
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -3032,17 +3032,17 @@ NS_IMETHODIMP nsPluginInstanceOwner::Cre
 void nsPluginInstanceOwner::FixUpPluginWindow(int32_t inPaintState)
 {
   if (!mPluginWindow || !mInstance || !mPluginFrame) {
     return;
   }
 
   SetPluginPort();
 
-  nsIntSize widgetClip = mPluginFrame->GetWidgetlessClipRect().Size();
+  LayoutDeviceIntSize widgetClip = mPluginFrame->GetWidgetlessClipRect().Size();
 
   mPluginWindow->x = 0;
   mPluginWindow->y = 0;
 
   NPRect oldClipRect = mPluginWindow->clipRect;
 
   // fix up the clipping region
   mPluginWindow->clipRect.top  = 0;
--- a/dom/svg/SVGContentUtils.h
+++ b/dom/svg/SVGContentUtils.h
@@ -3,17 +3,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/. */
 
 #ifndef MOZILLA_SVGCONTENTUTILS_H
 #define MOZILLA_SVGCONTENTUTILS_H
 
 // include math.h to pick up definition of M_ maths defines e.g. M_PI
-#define _USE_MATH_DEFINES
 #include <math.h>
 
 #include "mozilla/gfx/2D.h" // for StrokeOptions
 #include "mozilla/gfx/Matrix.h"
 #include "mozilla/RangedPtr.h"
 #include "nsError.h"
 #include "nsStringFwd.h"
 #include "gfx2DGlue.h"
--- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp
+++ b/dom/system/gonk/GonkGPSGeolocationProvider.cpp
@@ -11,22 +11,22 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "GonkGPSGeolocationProvider.h"
 
+#include <cmath>
 #include <pthread.h>
 #include <hardware/gps.h>
 
 #include "GeolocationUtil.h"
 #include "mozstumbler/MozStumbler.h"
-#include "mozilla/Constants.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "nsContentUtils.h"
 #include "nsGeoPosition.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsINetworkInterface.h"
 #include "nsIObserverService.h"
 #include "nsJSUtils.h"
--- a/gfx/2d/Blur.cpp
+++ b/gfx/2d/Blur.cpp
@@ -6,17 +6,16 @@
 
 #include "Blur.h"
 
 #include <algorithm>
 #include <math.h>
 #include <string.h>
 
 #include "mozilla/CheckedInt.h"
-#include "mozilla/Constants.h"
 
 #include "2D.h"
 #include "DataSurfaceHelpers.h"
 #include "Tools.h"
 
 #ifdef BUILD_ARM_NEON
 #include "mozilla/arm.h"
 #endif
--- a/gfx/2d/DrawCommand.h
+++ b/gfx/2d/DrawCommand.h
@@ -1,18 +1,16 @@
 /* -*- 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 MOZILLA_GFX_DRAWCOMMAND_H_
 #define MOZILLA_GFX_DRAWCOMMAND_H_
 
-
-#define _USE_MATH_DEFINES
 #include <math.h>
 
 #include "2D.h"
 #include "Filters.h"
 #include <vector>
 
 namespace mozilla {
 namespace gfx {
@@ -587,10 +585,9 @@ public:
     aDT->Flush();
   }
 };
 
 } // namespace gfx
 
 } // namespace mozilla
 
-
 #endif /* MOZILLA_GFX_DRAWCOMMAND_H_ */
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -11,22 +11,22 @@
 #include "ShadersD2D.h"
 #include "PathD2D.h"
 #include "GradientStopsD2D.h"
 #include "ScaledFontDWrite.h"
 #include "ImageScaling.h"
 #include "Logging.h"
 #include "Tools.h"
 #include <algorithm>
-#include "mozilla/Constants.h"
 #include "FilterNodeSoftware.h"
 
 #include "FilterNodeD2D1.h"
 #include "ExtendInputEffectD2D1.h"
 
+#include <cmath>
 #include <dwrite.h>
 
 // decltype is not usable for overloaded functions.
 typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
     D2D1_FACTORY_TYPE factoryType,
     REFIID iid,
     CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
     void **factory
--- a/gfx/2d/FilterNodeSoftware.cpp
+++ b/gfx/2d/FilterNodeSoftware.cpp
@@ -1,15 +1,13 @@
 /* -*- Mode: C++; tab-width: 20; 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/. */
 
-#define _USE_MATH_DEFINES
-
 #include <cmath>
 #include "DataSurfaceHelpers.h"
 #include "FilterNodeSoftware.h"
 #include "2D.h"
 #include "Tools.h"
 #include "Blur.h"
 #include <map>
 #include "FilterProcessing.h"
--- a/gfx/2d/PathD2D.cpp
+++ b/gfx/2d/PathD2D.cpp
@@ -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/. */
 
 #include "PathD2D.h"
 #include "HelpersD2D.h"
 #include <math.h>
 #include "DrawTargetD2D.h"
 #include "Logging.h"
-#include "mozilla/Constants.h"
 
 namespace mozilla {
 namespace gfx {
 
 // This class exists as a wrapper for ID2D1SimplifiedGeometry sink, it allows
 // a geometry to be duplicated into a geometry sink, while removing the final
 // figure end and thus allowing a figure that was implicitly closed to be
 // continued.
--- a/gfx/2d/PathHelpers.cpp
+++ b/gfx/2d/PathHelpers.cpp
@@ -1,16 +1,13 @@
 /* -*- Mode: C++; tab-width: 20; 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/. */
 
-#define _USE_MATH_DEFINES
-#include <cmath>
-
 #include "PathHelpers.h"
 
 namespace mozilla {
 namespace gfx {
 
 UserDataKey sDisablePixelSnapping;
 
 void
@@ -273,9 +270,8 @@ MaxStrokeExtents(const StrokeOptions& aS
 
   double dx = styleExpansionFactor * hypot(aTransform._11, aTransform._21);
   double dy = styleExpansionFactor * hypot(aTransform._22, aTransform._12);
   return Margin(dy, dx, dy, dx);
 }
 
 } // namespace gfx
 } // namespace mozilla
-
--- a/gfx/2d/PathHelpers.h
+++ b/gfx/2d/PathHelpers.h
@@ -2,19 +2,20 @@
  * 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_GFX_PATHHELPERS_H_
 #define MOZILLA_GFX_PATHHELPERS_H_
 
 #include "2D.h"
-#include "mozilla/Constants.h"
 #include "UserData.h"
 
+#include <cmath>
+
 namespace mozilla {
 namespace gfx {
 
 // Kappa constant for 90-degree angle
 const Float kKappaFactor = 0.55191497064665766025f;
 
 // Calculate kappa constant for partial curve. The sign of angle in the
 // tangent will actually ensure this is negative for a counter clockwise
--- a/gfx/2d/image_operations.cpp
+++ b/gfx/2d/image_operations.cpp
@@ -23,17 +23,16 @@
 // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 // SUCH DAMAGE.
 
 #include "base/basictypes.h"
 
-#define _USE_MATH_DEFINES
 #include <algorithm>
 #include <cmath>
 #include <limits>
 
 #include "image_operations.h"
 
 #include "base/stack_container.h"
 #include "convolver.h"
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -141,30 +141,27 @@ UNIFIED_SOURCES += [
     'FilterNodeSoftware.cpp',
     'FilterProcessing.cpp',
     'FilterProcessingScalar.cpp',
     'ImageScaling.cpp',
     'JobScheduler.cpp',
     'Matrix.cpp',
     'Path.cpp',
     'PathCairo.cpp',
+    'PathHelpers.cpp',
     'PathRecording.cpp',
     'Quaternion.cpp',
     'RecordedEvent.cpp',
     'Scale.cpp',
     'ScaledFontBase.cpp',
     'ScaledFontCairo.cpp',
     'SourceSurfaceCairo.cpp',
     'SourceSurfaceRawData.cpp',
 ]
 
-SOURCES += [
-    'PathHelpers.cpp', # Uses _USE_MATH_DEFINES
-]
-
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     EXPORTS.mozilla.gfx += [
         'QuartzSupport.h',
     ]
     SOURCES += [
         'MacIOSurface.cpp',
         'QuartzSupport.mm',
     ]
--- a/gfx/angle/src/commit.h
+++ b/gfx/angle/src/commit.h
@@ -1,3 +1,3 @@
-#define ANGLE_COMMIT_HASH "2eb89424cc6d"
+#define ANGLE_COMMIT_HASH "316930d51ea9"
 #define ANGLE_COMMIT_HASH_SIZE 12
-#define ANGLE_COMMIT_DATE "2015-11-28 17:17:38 -0500"
+#define ANGLE_COMMIT_DATE "2015-12-03 16:34:05 -0500"
--- a/gfx/angle/src/libANGLE/validationES3.cpp
+++ b/gfx/angle/src/libANGLE/validationES3.cpp
@@ -149,16 +149,18 @@ ES3FormatCombinationSet BuildES3FormatSe
     InsertES3FormatCombo(&set, GL_DEPTH24_STENCIL8,   GL_DEPTH_STENCIL,   GL_UNSIGNED_INT_24_8             );
     InsertES3FormatCombo(&set, GL_DEPTH32F_STENCIL8,  GL_DEPTH_STENCIL,   GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
 
     // From GL_EXT_sRGB
     InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8_EXT,   GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE                  );
     InsertES3FormatCombo(&set, GL_SRGB8,              GL_SRGB_EXT,       GL_UNSIGNED_BYTE                  );
 
     // From GL_OES_texture_float
+    InsertES3FormatCombo(&set, GL_RGBA,               GL_RGBA,            GL_FLOAT                         );
+    InsertES3FormatCombo(&set, GL_RGB,                GL_RGB,             GL_FLOAT                         );
     InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA,    GL_LUMINANCE_ALPHA, GL_FLOAT                         );
     InsertES3FormatCombo(&set, GL_LUMINANCE,          GL_LUMINANCE,       GL_FLOAT                         );
     InsertES3FormatCombo(&set, GL_ALPHA,              GL_ALPHA,           GL_FLOAT                         );
 
     // From GL_OES_texture_half_float
     InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA,    GL_LUMINANCE_ALPHA, GL_HALF_FLOAT                    );
     InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA,    GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES                );
     InsertES3FormatCombo(&set, GL_LUMINANCE,          GL_LUMINANCE,       GL_HALF_FLOAT                    );
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -175,16 +175,107 @@ static const char *sExtensionNames[] = {
     "GL_OES_texture_float_linear",
     "GL_OES_texture_half_float",
     "GL_OES_texture_half_float_linear",
     "GL_OES_texture_npot",
     "GL_OES_vertex_array_object"
 };
 
 static bool
+ParseGLSLVersion(GLContext* gl, uint32_t* out_version)
+{
+    if (gl->fGetError() != LOCAL_GL_NO_ERROR) {
+        MOZ_ASSERT(false, "An OpenGL error has been triggered before.");
+        return false;
+    }
+
+    /**
+     * OpenGL 2.x, 3.x, 4.x specifications:
+     *  The VERSION and SHADING_LANGUAGE_VERSION strings are laid out as follows:
+     *
+     *    <version number><space><vendor-specific information>
+     *
+     *  The version number is either of the form major_number.minor_number or
+     *  major_number.minor_number.release_number, where the numbers all have
+     *  one or more digits.
+     *
+     * SHADING_LANGUAGE_VERSION is *almost* identical to VERSION. The
+     * difference is that the minor version always has two digits and the
+     * prefix has an additional 'GLSL ES'
+     *
+     *
+     * OpenGL ES 2.0, 3.0 specifications:
+     *  The VERSION string is laid out as follows:
+     *
+     *     "OpenGL ES N.M vendor-specific information"
+     *
+     *  The version number is either of the form major_number.minor_number or
+     *  major_number.minor_number.release_number, where the numbers all have
+     *  one or more digits.
+     *
+     *
+     * Note:
+     *  We don't care about release_number.
+     */
+    const char* versionString = (const char*) gl->fGetString(LOCAL_GL_SHADING_LANGUAGE_VERSION);
+
+    if (gl->fGetError() != LOCAL_GL_NO_ERROR) {
+        MOZ_ASSERT(false, "glGetString(GL_SHADING_LANGUAGE_VERSION) has generated an error");
+        return false;
+    }
+
+    if (!versionString) {
+        // This happens on the Android emulators. We'll just return 100
+        *out_version = 100;
+        return true;
+    }
+
+    const char kGLESVersionPrefix[] = "OpenGL ES GLSL ES";
+    if (strncmp(versionString, kGLESVersionPrefix, strlen(kGLESVersionPrefix)) == 0)
+        versionString += strlen(kGLESVersionPrefix);
+
+    const char* itr = versionString;
+    char* end = nullptr;
+    auto majorVersion = strtol(itr, &end, 10);
+
+    if (!end) {
+        MOZ_ASSERT(false, "Failed to parse the GL major version number.");
+        return false;
+    }
+
+    if (*end != '.') {
+        MOZ_ASSERT(false, "Failed to parse GL's major-minor version number separator.");
+        return false;
+    }
+
+    // we skip the '.' between the major and the minor version
+    itr = end + 1;
+    end = nullptr;
+
+    auto minorVersion = strtol(itr, &end, 10);
+    if (!end) {
+        MOZ_ASSERT(false, "Failed to parse GL's minor version number.");
+        return false;
+    }
+
+    if (majorVersion <= 0 || majorVersion >= 100) {
+        MOZ_ASSERT(false, "Invalid major version.");
+        return false;
+    }
+
+    if (minorVersion < 0 || minorVersion >= 100) {
+        MOZ_ASSERT(false, "Invalid minor version.");
+        return false;
+    }
+
+    *out_version = (uint32_t) majorVersion * 100 + (uint32_t) minorVersion;
+    return true;
+}
+
+static bool
 ParseGLVersion(GLContext* gl, uint32_t* out_version)
 {
     if (gl->fGetError() != LOCAL_GL_NO_ERROR) {
         MOZ_ASSERT(false, "An OpenGL error has been triggered before.");
         return false;
     }
 
     /**
@@ -298,16 +389,17 @@ ParseGLVersion(GLContext* gl, uint32_t* 
 GLContext::GLContext(const SurfaceCaps& caps,
           GLContext* sharedContext,
           bool isOffscreen)
   : mInitialized(false),
     mIsOffscreen(isOffscreen),
     mContextLost(false),
     mVersion(0),
     mProfile(ContextProfile::Unknown),
+    mShadingLanguageVersion(0),
     mVendor(GLVendor::Other),
     mRenderer(GLRenderer::Other),
     mHasRobustness(false),
     mTopError(LOCAL_GL_NO_ERROR),
     mSharedContext(sharedContext),
     mCaps(caps),
     mScreen(nullptr),
     mLockedSurface(nullptr),
@@ -510,18 +602,22 @@ GLContext::InitWithPrefix(const char *pr
     mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
     MakeCurrent();
     if (mInitialized) {
         MOZ_ASSERT(mProfile != ContextProfile::Unknown);
 
         uint32_t version = 0;
         ParseGLVersion(this, &version);
 
+        mShadingLanguageVersion = 100;
+        ParseGLSLVersion(this, &mShadingLanguageVersion);
+
         if (ShouldSpew()) {
             printf_stderr("OpenGL version detected: %u\n", version);
+            printf_stderr("OpenGL shading language version detected: %u\n", mShadingLanguageVersion);
             printf_stderr("OpenGL vendor: %s\n", fGetString(LOCAL_GL_VENDOR));
             printf_stderr("OpenGL renderer: %s\n", fGetString(LOCAL_GL_RENDERER));
         }
 
         if (version >= mVersion) {
             mVersion = version;
         }
         // Don't fail if version < mVersion, see bug 999445,
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -297,16 +297,20 @@ public:
     inline uint32_t Version() const {
         return mVersion;
     }
 
     const char* VersionString() const {
         return mVersionString.get();
     }
 
+    inline uint32_t ShadingLanguageVersion() const {
+        return mShadingLanguageVersion;
+    }
+
     GLVendor Vendor() const {
         return mVendor;
     }
 
     GLRenderer Renderer() const {
         return mRenderer;
     }
 
@@ -341,16 +345,18 @@ protected:
     /**
      * mVersion store the OpenGL's version, multiplied by 100. For example, if
      * the context is an OpenGL 2.1 context, mVersion value will be 210.
      */
     uint32_t mVersion;
     nsCString mVersionString;
     ContextProfile mProfile;
 
+    uint32_t mShadingLanguageVersion;
+
     GLVendor mVendor;
     GLRenderer mRenderer;
 
     void SetProfileVersion(ContextProfile profile, uint32_t version) {
         MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before"
                                   " initialization!");
         MOZ_ASSERT(profile != ContextProfile::Unknown &&
                    profile != ContextProfile::OpenGL,
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -24,17 +24,16 @@
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/task.h"                  // for NewRunnableMethod, etc
 #include "base/tracked.h"               // for FROM_HERE
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxTypes.h"                   // for gfxFloat
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/BasicEvents.h"        // for Modifiers, MODIFIER_*
 #include "mozilla/ClearOnShutdown.h"    // for ClearOnShutdown
-#include "mozilla/Constants.h"          // for M_PI
 #include "mozilla/EventForwards.h"      // for nsEventStatus_*
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitorAutoEnter, etc
 #include "mozilla/StaticPtr.h"          // for StaticAutoPtr
 #include "mozilla/Telemetry.h"          // for Telemetry
 #include "mozilla/TimeStamp.h"          // for TimeDuration, TimeStamp
 #include "mozilla/dom/KeyframeEffect.h" // for ComputedTimingFunction
 #include "mozilla/dom/Touch.h"          // for Touch
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -1226,29 +1226,50 @@ CompositorD3D11::VerifyBufferSize()
 
   if (((swapDesc.BufferDesc.Width == mSize.width &&
        swapDesc.BufferDesc.Height == mSize.height) ||
        mSize.width <= 0 || mSize.height <= 0) &&
       !mVerifyBuffersFailed) {
     return true;
   }
 
+  ID3D11RenderTargetView* view = nullptr;
+  mContext->OMSetRenderTargets(1, &view, nullptr);
+
   if (mDefaultRT) {
+    RefPtr<ID3D11RenderTargetView> rtView = mDefaultRT->mRTView;
+
     // Make sure the texture, which belongs to the swapchain, is destroyed
     // before resizing the swapchain.
     if (mCurrentRT == mDefaultRT) {
       mCurrentRT = nullptr;
     }
     MOZ_ASSERT(mDefaultRT->hasOneRef());
     mDefaultRT = nullptr;
+
+    RefPtr<ID3D11Resource> resource;
+    rtView->GetResource(getter_AddRefs(resource));
+
+    ULONG newRefCnt = rtView.forget().take()->Release();
+
+    if (newRefCnt > 0) {
+      gfxCriticalError() << "mRTView not destroyed on final release!";
+    }
+
+    newRefCnt = resource.forget().take()->Release();
+
+    if (newRefCnt > 0) {
+      gfxCriticalError() << "Unexpecting lingering references to backbuffer!";
+    }
+
+    hr = mSwapChain->ResizeBuffers(1, mSize.width, mSize.height,
+                                   DXGI_FORMAT_B8G8R8A8_UNORM,
+                                   0);
   }
 
-  hr = mSwapChain->ResizeBuffers(1, mSize.width, mSize.height,
-                                 DXGI_FORMAT_B8G8R8A8_UNORM,
-                                 0);
   mVerifyBuffersFailed = FAILED(hr);
   if (mVerifyBuffersFailed) {
     gfxCriticalNote << "D3D11 swap resize buffers failed " << hexa(hr) << " on " << mSize;
     HandleError(hr);
   }
 
   return !mVerifyBuffersFailed;
 }
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -201,56 +201,55 @@ CompositorChild::RecvInvalidateAll()
 {
   if (mLayerManager) {
     FrameLayerBuilder::InvalidateAllLayers(mLayerManager);
   }
   return true;
 }
 
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
-static void CalculatePluginClip(const gfx::IntRect& aBounds,
-                                const nsTArray<gfx::IntRect>& aPluginClipRects,
-                                const nsIntPoint& aContentOffset,
-                                const nsIntRegion& aParentLayerVisibleRegion,
-                                nsTArray<gfx::IntRect>& aResult,
+static void CalculatePluginClip(const LayoutDeviceIntRect& aBounds,
+                                const nsTArray<LayoutDeviceIntRect>& aPluginClipRects,
+                                const LayoutDeviceIntPoint& aContentOffset,
+                                const LayoutDeviceIntRegion& aParentLayerVisibleRegion,
+                                nsTArray<LayoutDeviceIntRect>& aResult,
                                 LayoutDeviceIntRect& aVisibleBounds,
                                 bool& aPluginIsVisible)
 {
   aPluginIsVisible = true;
-  nsIntRegion contentVisibleRegion;
+  LayoutDeviceIntRegion contentVisibleRegion;
   // aPluginClipRects (plugin widget origin) - contains *visible* rects
   for (uint32_t idx = 0; idx < aPluginClipRects.Length(); idx++) {
-    gfx::IntRect rect = aPluginClipRects[idx];
+    LayoutDeviceIntRect rect = aPluginClipRects[idx];
     // shift to content origin
     rect.MoveBy(aBounds.x, aBounds.y);
     // accumulate visible rects
     contentVisibleRegion.OrWith(rect);
   }
   // apply layers clip (window origin)
-  nsIntRegion region = aParentLayerVisibleRegion;
+  LayoutDeviceIntRegion region = aParentLayerVisibleRegion;
   region.MoveBy(-aContentOffset.x, -aContentOffset.y);
   contentVisibleRegion.AndWith(region);
   if (contentVisibleRegion.IsEmpty()) {
     aPluginIsVisible = false;
     return;
   }
   // shift to plugin widget origin
   contentVisibleRegion.MoveBy(-aBounds.x, -aBounds.y);
-  nsIntRegionRectIterator iter(contentVisibleRegion);
-  for (const gfx::IntRect* rgnRect = iter.Next(); rgnRect; rgnRect = iter.Next()) {
+  LayoutDeviceIntRegion::RectIterator iter(contentVisibleRegion);
+  for (const LayoutDeviceIntRect* rgnRect = iter.Next(); rgnRect; rgnRect = iter.Next()) {
     aResult.AppendElement(*rgnRect);
-    aVisibleBounds.UnionRect(aVisibleBounds,
-                             LayoutDeviceIntRect::FromUnknownRect(*rgnRect));
+    aVisibleBounds.UnionRect(aVisibleBounds, *rgnRect);
   }
 }
 #endif
 
 bool
-CompositorChild::RecvUpdatePluginConfigurations(const nsIntPoint& aContentOffset,
-                                                const nsIntRegion& aParentLayerVisibleRegion,
+CompositorChild::RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint& aContentOffset,
+                                                const LayoutDeviceIntRegion& aParentLayerVisibleRegion,
                                                 nsTArray<PluginWindowData>&& aPlugins)
 {
 #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
   NS_NOTREACHED("CompositorChild::RecvUpdatePluginConfigurations calls "
                 "unexpected on this platform.");
   return false;
 #else
   // Now that we are on the main thread, update plugin widget config.
@@ -269,32 +268,33 @@ CompositorChild::RecvUpdatePluginConfigu
       NS_WARNING("Unexpected, plugin id not found!");
       continue;
     }
     if (!parent) {
       parent = widget->GetParent();
     }
     bool isVisible = aPlugins[pluginsIdx].visible();
     if (widget && !widget->Destroyed()) {
-      gfx::IntRect bounds;
+      LayoutDeviceIntRect bounds;
       LayoutDeviceIntRect visibleBounds;
       // If the plugin is visible update it's geometry.
       if (isVisible) {
         // bounds (content origin) - don't pass true to Resize, it triggers a
         // sync paint update to the plugin process on Windows, which happens
         // prior to clipping information being applied.
         bounds = aPlugins[pluginsIdx].bounds();
         rv = widget->Resize(aContentOffset.x + bounds.x,
                             aContentOffset.y + bounds.y,
                             bounds.width, bounds.height, false);
         NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
-        nsTArray<gfx::IntRect> rectsOut;
+        nsTArray<LayoutDeviceIntRect> rectsOut;
         // This call may change the value of isVisible
         CalculatePluginClip(bounds, aPlugins[pluginsIdx].clip(),
-                            aContentOffset, aParentLayerVisibleRegion,
+                            aContentOffset,
+                            aParentLayerVisibleRegion,
                             rectsOut, visibleBounds, isVisible);
         // content clipping region (widget origin)
         rv = widget->SetWindowClipRegion(rectsOut, false);
         NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
       }
 
       rv = widget->Enable(isVisible);
       NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
--- a/gfx/layers/ipc/CompositorChild.h
+++ b/gfx/layers/ipc/CompositorChild.h
@@ -80,18 +80,18 @@ public:
 
   virtual bool
   RecvInvalidateAll() override;
 
   virtual bool
   RecvOverfill(const uint32_t &aOverfill) override;
 
   virtual bool
-  RecvUpdatePluginConfigurations(const nsIntPoint& aContentOffset,
-                                 const nsIntRegion& aVisibleRegion,
+  RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint& aContentOffset,
+                                 const LayoutDeviceIntRegion& aVisibleRegion,
                                  nsTArray<PluginWindowData>&& aPlugins) override;
 
   virtual bool
   RecvHideAllPlugins(const uintptr_t& aParentWidget) override;
 
   /**
    * Request that the parent tell us when graphics are ready on GPU.
    * When we get that message, we bounce it to the TabParent via
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -2142,19 +2142,20 @@ CompositorParent::UpdatePluginWindowStat
         if (!pluginMetricsChanged &&
             mPluginsLayerVisibleRegion == visibleRegion &&
             mPluginsLayerOffset == offset) {
           PLUGINS_LOG("[%" PRIu64 "] no change", aId);
           return false;
         }
         mPluginsLayerOffset = offset;
         mPluginsLayerVisibleRegion = visibleRegion;
-        Unused <<
-          lts.mParent->SendUpdatePluginConfigurations(offset, visibleRegion,
-                                                      lts.mPluginData);
+        Unused << lts.mParent->SendUpdatePluginConfigurations(
+          LayoutDeviceIntPoint::FromUnknownPoint(offset),
+          LayoutDeviceIntRegion::FromUnknownRegion(visibleRegion),
+          lts.mPluginData);
         lts.mUpdatedPluginDataAvailable = false;
         PLUGINS_LOG("[%" PRIu64 "] updated", aId);
       } else {
         PLUGINS_LOG("[%" PRIu64 "] no visibility data", aId);
         return false;
       }
     } else {
       PLUGINS_LOG("[%" PRIu64 "] no content root", aId);
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -31,16 +31,17 @@ using mozilla::ScreenRotation from "mozi
 using nsCSSProperty from "nsCSSProperty.h";
 using mozilla::dom::ScreenOrientationInternal from "mozilla/dom/ScreenOrientation.h";
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using mozilla::LayerMargin from "Units.h";
 using mozilla::LayerPoint from "Units.h";
 using mozilla::LayerRect from "Units.h";
 using mozilla::LayerIntRegion from "Units.h";
 using mozilla::ParentLayerIntRect from "Units.h";
+using mozilla::LayoutDeviceIntRect from "Units.h";
 using mozilla::layers::ScaleMode from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::EventRegions from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::EventRegionsOverride from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h";
 using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
@@ -275,18 +276,18 @@ union SpecificLayerAttributes {
 struct LayerAttributes {
   CommonLayerAttributes common;
   SpecificLayerAttributes specific;
 };
 
 // See nsIWidget Configurations
 struct PluginWindowData {
   uintptr_t windowId;
-  IntRect[] clip;
-  IntRect bounds;
+  LayoutDeviceIntRect[] clip;
+  LayoutDeviceIntRect bounds;
   bool visible;
 };
 
 struct OpSetLayerAttributes {
   PLayer layer;
   LayerAttributes attrs;
 };
 
--- a/gfx/layers/ipc/PCompositor.ipdl
+++ b/gfx/layers/ipc/PCompositor.ipdl
@@ -14,16 +14,18 @@ include "nsRegion.h";
 
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
 using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
 using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
+using mozilla::LayoutDeviceIntPoint from "Units.h";
+using mozilla::LayoutDeviceIntRegion from "Units.h";
 using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
 using class mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUniformityData.h";
 
 namespace mozilla {
 namespace layers {
 
 
 /**
@@ -60,18 +62,18 @@ child:
    */
   async RemotePaintIsReady();
 
   /**
    * Bounce plugin widget configurations over to the main thread for
    * application on the widgets. Used on Windows and Linux in managing
    * plugin widgets.
    */
-  async UpdatePluginConfigurations(IntPoint aContentOffset,
-                                   nsIntRegion aVisibleRegion,
+  async UpdatePluginConfigurations(LayoutDeviceIntPoint aContentOffset,
+                                   LayoutDeviceIntRegion aVisibleRegion,
                                    PluginWindowData[] aPlugins);
 
   /**
    * Hides all registered plugin widgets associated with a particular chrome
    * widget.
    */
   async HideAllPlugins(uintptr_t aParentWidget);
 
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -476,17 +476,17 @@ ShadowLayerForwarder::StorePluginWidgetC
 {
   // Cache new plugin widget configs here until we call update, at which
   // point this data will get shipped over to chrome.
   mPluginWindowData.Clear();
   for (uint32_t idx = 0; idx < aConfigurations.Length(); idx++) {
     const nsIWidget::Configuration& configuration = aConfigurations[idx];
     mPluginWindowData.AppendElement(PluginWindowData(configuration.mWindowID,
                                                      configuration.mClipRegion,
-                                                     configuration.mBounds.ToUnknownRect(),
+                                                     configuration.mBounds,
                                                      configuration.mVisible));
   }
 }
 
 bool
 ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
                                      const nsIntRegion& aRegionToClear,
                                      uint64_t aId,
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -1,16 +1,13 @@
 /* -*- Mode: C++; tab-width: 20; 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/. */
 
-#ifdef _MSC_VER
-#define _USE_MATH_DEFINES
-#endif
 #include <math.h>
 
 #include "mozilla/Alignment.h"
 
 #include "cairo.h"
 
 #include "gfxContext.h"
 
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -1,19 +1,19 @@
 /* -*- Mode: C++; tab-width: 20; 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 GFX_PREFS_H
 #define GFX_PREFS_H
 
+#include <cmath>                 // for M_PI
 #include <stdint.h>
 #include "mozilla/Assertions.h"
-#include "mozilla/Constants.h"   // for M_PI
 
 // First time gfxPrefs::GetSingleton() needs to be called on the main thread,
 // before any of the methods accessing the values are used, but after
 // the Preferences system has been initialized.
 
 // The static methods to access the preference value are safe to call
 // from any thread after that first call.
 
--- a/js/src/asmjs/AsmJSSignalHandlers.cpp
+++ b/js/src/asmjs/AsmJSSignalHandlers.cpp
@@ -586,17 +586,18 @@ ComputeAccessAddress(EMULATOR_CONTEXT* c
                             AddressOfGPRegisterSlot(context, address.base()));
         result += base;
     }
 
     if (address.hasIndex()) {
         uintptr_t index;
         StoreValueFromGPReg(SharedMem<void*>::unshared(&index), sizeof(uintptr_t),
                             AddressOfGPRegisterSlot(context, address.index()));
-        result += index * (1 << address.scale());
+        MOZ_ASSERT(address.scale() < 32, "address shift overflow");
+        result += index * (uintptr_t(1) << address.scale());
     }
 
     return reinterpret_cast<uint8_t*>(result);
 }
 
 MOZ_COLD static uint8_t*
 EmulateHeapAccess(EMULATOR_CONTEXT* context, uint8_t* pc, uint8_t* faultingAddress,
                   const HeapAccess* heapAccess, const AsmJSModule& module)
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -890,17 +890,19 @@ SetSavedStacksRNGState(JSContext* cx, un
     CallArgs args = CallArgsFromVp(argc, vp);
     if (!args.requireAtLeast(cx, "setSavedStacksRNGState", 1))
         return false;
 
     int32_t seed;
     if (!ToInt32(cx, args[0], &seed))
         return false;
 
-    cx->compartment()->savedStacks().setRNGState(seed, seed * 33);
+    // Either one or the other of the seed arguments must be non-zero;
+    // make this true no matter what value 'seed' has.
+    cx->compartment()->savedStacks().setRNGState(seed, (seed + 1) * 33);
     return true;
 }
 
 static bool
 GetSavedFrameCount(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setNumber(cx->compartment()->savedStacks().count());
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -368,16 +368,17 @@ case "$target" in
         _CXX_MAJOR_VERSION=`echo ${CXX_VERSION} | cut -c 1-2`
 
         if test "$_CC_MAJOR_VERSION" != "$_CXX_MAJOR_VERSION"; then
             AC_MSG_ERROR([The major versions of \$CC and \$CXX do not match.])
         fi
 
         AC_DEFINE(_CRT_SECURE_NO_WARNINGS)
         AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS)
+        AC_DEFINE(_USE_MATH_DEFINES) # Otherwise MSVC's math.h doesn't #define M_PI.
 
         if test "$_CC_MAJOR_VERSION" = "18"; then
             _CC_SUITE=12
             MSVC_C_RUNTIME_DLL=msvcr120.dll
             MSVC_CXX_RUNTIME_DLL=msvcp120.dll
         elif test "$_CC_MAJOR_VERSION" = "19"; then
             _CC_SUITE=14
             MSVC_C_RUNTIME_DLL=vcruntime140.dll
--- a/js/src/jit-test/tests/debug/Memory-allocationSamplingProbability-02.js
+++ b/js/src/jit-test/tests/debug/Memory-allocationSamplingProbability-02.js
@@ -27,10 +27,10 @@ function measure(P, expected) {
 dbg.memory.trackingAllocationSites = true;
 
 // These are the sample counts that were correct when this test was last
 // updated; changes to SpiderMonkey may occasionally cause changes
 // here. Anything that is within a plausible range for the given sampling
 // probability is fine.
 measure(0.0, 0);
 measure(1.0, 100);
-measure(0.1, 7);
-measure(0.5, 44);
+measure(0.1, 11);
+measure(0.5, 49);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/saved-stacks/bug-1225474.js
@@ -0,0 +1,6 @@
+// setSavedStacksRNGState shouldn't crash regardless of the seed value passed.
+
+setSavedStacksRNGState(0);
+setSavedStacksRNGState({});
+setSavedStacksRNGState(false);
+setSavedStacksRNGState(NaN);
--- a/js/src/jit/mips-shared/Assembler-mips-shared.cpp
+++ b/js/src/jit/mips-shared/Assembler-mips-shared.cpp
@@ -83,16 +83,28 @@ InstImm::extractImm16(BOffImm16* dest)
 
 void
 AssemblerMIPSShared::finish()
 {
     MOZ_ASSERT(!isFinished);
     isFinished = true;
 }
 
+bool
+AssemblerMIPSShared::asmMergeWith(const AssemblerMIPSShared& other)
+{
+    if (!AssemblerShared::asmMergeWith(size(), other))
+        return false;
+    for (size_t i = 0; i < other.numLongJumps(); i++) {
+        size_t off = other.longJumps_[i];
+        addLongJump(BufferOffset(size() + off));
+    }
+    return m_buffer.appendBuffer(other.m_buffer);
+}
+
 uint32_t
 AssemblerMIPSShared::actualIndex(uint32_t idx_) const
 {
     return idx_;
 }
 
 uint8_t*
 AssemblerMIPSShared::PatchableJumpAddress(JitCode* code, uint32_t pe_)
@@ -121,17 +133,17 @@ AssemblerMIPSShared::copyPreBarrierTable
         memcpy(dest, preBarriers_.buffer(), preBarriers_.length());
 }
 
 void
 AssemblerMIPSShared::processCodeLabels(uint8_t* rawCode)
 {
     for (size_t i = 0; i < codeLabels_.length(); i++) {
         CodeLabel label = codeLabels_[i];
-        Bind(rawCode, label.dest(), rawCode + label.src()->offset());
+        Bind(rawCode, label.patchAt(), rawCode + label.target()->offset());
     }
 }
 
 AssemblerMIPSShared::Condition
 AssemblerMIPSShared::InvertCondition(Condition cond)
 {
     switch (cond) {
       case Equal:
@@ -1345,16 +1357,38 @@ AssemblerMIPSShared::retarget(Label* lab
             // the list hanging off of label, and dump that into target.
             DebugOnly<uint32_t> prev = target->use(label->offset());
             MOZ_ASSERT((int32_t)prev == Label::INVALID_OFFSET);
         }
     }
     label->reset();
 }
 
+void
+AssemblerMIPSShared::retargetWithOffset(size_t baseOffset, const LabelBase* label, Label* target)
+{
+    if (!label->used())
+        return;
+
+    MOZ_ASSERT(!target->bound());
+    int32_t next;
+    BufferOffset labelBranchOffset(label->offset() + baseOffset);
+    do {
+        Instruction* inst = editSrc(labelBranchOffset);
+        int32_t prev = target->use(labelBranchOffset.getOffset());
+
+        MOZ_RELEASE_ASSERT(prev == Label::INVALID_OFFSET || unsigned(prev) < size());
+
+        next = inst[1].encode();
+        inst[1].setData(prev);
+
+        labelBranchOffset = BufferOffset(next + baseOffset);
+    } while (next != LabelBase::INVALID_OFFSET);
+}
+
 void dbg_break() {}
 void
 AssemblerMIPSShared::as_break(uint32_t code)
 {
     MOZ_ASSERT(code <= MAX_BREAK_CODE);
     writeInst(op_special | code << FunctionBits | ff_break);
 }
 
--- a/js/src/jit/mips-shared/Assembler-mips-shared.h
+++ b/js/src/jit/mips-shared/Assembler-mips-shared.h
@@ -640,16 +640,28 @@ class MIPSBufferWithExecutableCopy : pub
         if (this->oom())
             return;
 
         for (Slice* cur = head; cur != nullptr; cur = cur->getNext()) {
             memcpy(buffer, &cur->instructions, cur->length());
             buffer += cur->length();
         }
     }
+
+    bool appendBuffer(const MIPSBufferWithExecutableCopy& other) {
+        if (this->oom())
+            return false;
+
+        for (Slice* cur = other.head; cur != nullptr; cur = cur->getNext()) {
+            this->putBytes(cur->length(), &cur->instructions);
+            if (this->oom())
+                return false;
+        }
+        return true;
+    }
 };
 
 class AssemblerMIPSShared : public AssemblerShared
 {
   public:
 
     enum Condition {
         Equal,
@@ -791,19 +803,17 @@ class AssemblerMIPSShared : public Assem
     static const Register getStackPointer() {
         return StackPointer;
     }
 
   protected:
     bool isFinished;
   public:
     void finish();
-    bool asmMergeWith(const AssemblerMIPSShared& other) {
-        MOZ_CRASH("NYI");
-    }
+    bool asmMergeWith(const AssemblerMIPSShared& other);
     void executableCopy(void* buffer);
     void copyJumpRelocationTable(uint8_t* dest);
     void copyDataRelocationTable(uint8_t* dest);
     void copyPreBarrierTable(uint8_t* dest);
 
     // Size of the instruction stream, in bytes.
     size_t size() const;
     // Size of the jump relocation table, in bytes.
@@ -1028,24 +1038,25 @@ class AssemblerMIPSShared : public Assem
     BufferOffset as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
                          FPConditionBit fcc = FCC0);
     BufferOffset as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
                          FPConditionBit fcc = FCC0);
 
     // label operations
     void bind(Label* label, BufferOffset boff = BufferOffset());
     virtual void bind(InstImm* inst, uintptr_t branch, uintptr_t target) = 0;
-    virtual void Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address) = 0;
+    virtual void Bind(uint8_t* rawCode, CodeOffset* label, const void* address) = 0;
+    void bind(CodeOffset* label) {
+        label->bind(currentOffset());
+    }
     uint32_t currentOffset() {
         return nextOffset().getOffset();
     }
     void retarget(Label* label, Label* target);
-    void retargetWithOffset(size_t offset, const LabelBase* label, Label* target) {
-        MOZ_CRASH("NYI");
-    }
+    void retargetWithOffset(size_t baseOffset, const LabelBase* label, Label* target);
 
     // See Bind
     size_t labelToPatchOffset(CodeOffset label) { return label.offset(); }
 
     void call(Label* label);
     void call(void* target);
 
     void as_break(uint32_t code);
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
@@ -1207,18 +1207,18 @@ MacroAssembler::callAndPushReturnAddress
 // ===============================================================
 // Jit Frames.
 
 uint32_t
 MacroAssembler::pushFakeReturnAddress(Register scratch)
 {
     CodeLabel cl;
 
-    ma_li(scratch, cl.dest());
+    ma_li(scratch, cl.patchAt());
     Push(scratch);
-    bind(cl.src());
+    bind(cl.target());
     uint32_t retAddr = currentOffset();
 
     addCodeLabel(cl);
     return retAddr;
 }
 
 //}}} check_macroassembler_style
--- a/js/src/jit/mips32/Assembler-mips32.cpp
+++ b/js/src/jit/mips32/Assembler-mips32.cpp
@@ -235,28 +235,23 @@ Assembler::trace(JSTracer* trc)
     }
     if (dataRelocations_.length()) {
         CompactBufferReader reader(dataRelocations_);
         ::TraceDataRelocations(trc, &m_buffer, reader);
     }
 }
 
 void
-Assembler::Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address)
+Assembler::Bind(uint8_t* rawCode, CodeOffset* label, const void* address)
 {
-    if (label->used()) {
-        int32_t src = label->offset();
-        do {
-            Instruction* inst = (Instruction*) (rawCode + src);
-            uint32_t next = Assembler::ExtractLuiOriValue(inst, inst->next());
-            Assembler::UpdateLuiOriValue(inst, inst->next(), (uint32_t)address);
-            src = next;
-        } while (src != AbsoluteLabel::INVALID_OFFSET);
+    if (label->bound()) {
+        intptr_t offset = label->offset();
+        Instruction* inst = (Instruction*) (rawCode + offset);
+        Assembler::UpdateLuiOriValue(inst, inst->next(), (uint32_t)address);
     }
-    label->bind();
 }
 
 void
 Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target)
 {
     int32_t offset = target - branch;
     InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
     InstImm inst_beq = InstImm(op_beq, zero, zero, BOffImm16(0));
--- a/js/src/jit/mips32/Assembler-mips32.h
+++ b/js/src/jit/mips32/Assembler-mips32.h
@@ -119,17 +119,17 @@ class Assembler : public AssemblerMIPSSh
         MOZ_ASSERT(reg.isDouble());
         return reg.singleOverlay(1);
     }
 
   public:
     using AssemblerMIPSShared::bind;
 
     void bind(RepatchLabel* label);
-    void Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address);
+    void Bind(uint8_t* rawCode, CodeOffset* label, const void* address);
 
     static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
     static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
 
     void bind(InstImm* inst, uintptr_t branch, uintptr_t target);
 
     // Copy the assembly code to the given buffer, and perform any pending
     // relocations relying on the target address.
--- a/js/src/jit/mips32/CodeGenerator-mips32.cpp
+++ b/js/src/jit/mips32/CodeGenerator-mips32.cpp
@@ -57,30 +57,30 @@ CodeGeneratorMIPS::visitOutOfLineBailout
 }
 
 void
 CodeGeneratorMIPS::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool)
 {
     MTableSwitch* mir = ool->mir();
 
     masm.haltingAlign(sizeof(void*));
-    masm.bind(ool->jumpLabel()->src());
+    masm.bind(ool->jumpLabel()->target());
     masm.addCodeLabel(*ool->jumpLabel());
 
     for (size_t i = 0; i < mir->numCases(); i++) {
         LBlock* caseblock = skipTrivialBlocks(mir->getCase(i))->lir();
         Label* caseheader = caseblock->label();
         uint32_t caseoffset = caseheader->offset();
 
         // The entries of the jump table need to be absolute addresses and thus
         // must be patched after codegen is finished.
         CodeLabel cl;
-        masm.ma_li(ScratchRegister, cl.dest());
+        masm.ma_li(ScratchRegister, cl.patchAt());
         masm.branch(ScratchRegister);
-        cl.src()->bind(caseoffset);
+        cl.target()->bind(caseoffset);
         masm.addCodeLabel(cl);
     }
 }
 
 void
 CodeGeneratorMIPS::emitTableSwitchDispatch(MTableSwitch* mir, Register index,
                                            Register address)
 {
@@ -96,17 +96,17 @@ CodeGeneratorMIPS::emitTableSwitchDispat
 
     // To fill in the CodeLabels for the case entries, we need to first
     // generate the case entries (we don't yet know their offsets in the
     // instruction stream).
     OutOfLineTableSwitch* ool = new(alloc()) OutOfLineTableSwitch(mir);
     addOutOfLineCode(ool, mir);
 
     // Compute the position where a pointer to the right case stands.
-    masm.ma_li(address, ool->jumpLabel()->dest());
+    masm.ma_li(address, ool->jumpLabel()->patchAt());
     masm.lshiftPtr(Imm32(4), index);
     masm.addPtr(index, address);
 
     masm.branch(address);
 }
 
 static const uint32_t FrameSizes[] = { 128, 256, 512, 1024 };
 
--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
+++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
@@ -307,24 +307,21 @@ MacroAssemblerMIPSCompat::inc64(Absolute
 
     as_addu(SecondScratchReg, ScratchRegister, SecondScratchReg);
 
     ma_li(ScratchRegister, Imm32((int32_t)dest.addr));
     as_sw(SecondScratchReg, ScratchRegister, 4);
 }
 
 void
-MacroAssemblerMIPS::ma_li(Register dest, AbsoluteLabel* label)
+MacroAssemblerMIPS::ma_li(Register dest, CodeOffset* label)
 {
-    MOZ_ASSERT(!label->bound());
-    // Thread the patch list through the unpatched address word in the
-    // instruction stream.
     BufferOffset bo = m_buffer.nextOffset();
-    ma_liPatchable(dest, Imm32(label->prev()));
-    label->setPrev(bo.getOffset());
+    ma_liPatchable(dest, ImmWord(/* placeholder */ 0));
+    label->bind(bo.getOffset());
 }
 
 void
 MacroAssemblerMIPS::ma_li(Register dest, ImmWord imm)
 {
     ma_li(dest, Imm32(uint32_t(imm.value)));
 }
 
--- a/js/src/jit/mips32/MacroAssembler-mips32.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32.h
@@ -49,17 +49,17 @@ class MacroAssemblerMIPS : public MacroA
     using MacroAssemblerMIPSShared::ma_li;
     using MacroAssemblerMIPSShared::ma_ss;
     using MacroAssemblerMIPSShared::ma_sd;
     using MacroAssemblerMIPSShared::ma_load;
     using MacroAssemblerMIPSShared::ma_store;
     using MacroAssemblerMIPSShared::ma_cmp_set;
     using MacroAssemblerMIPSShared::ma_subTestOverflow;
 
-    void ma_li(Register dest, AbsoluteLabel* label);
+    void ma_li(Register dest, CodeOffset* label);
 
     void ma_liPatchable(Register dest, Imm32 imm);
     void ma_li(Register dest, ImmWord imm);
     void ma_liPatchable(Register dest, ImmPtr imm);
     void ma_liPatchable(Register dest, ImmWord imm);
 
     // load
     void ma_load(Register dest, Address address, LoadStoreSize size = SizeWord,
--- a/js/src/jit/mips32/Trampoline-mips32.cpp
+++ b/js/src/jit/mips32/Trampoline-mips32.cpp
@@ -199,16 +199,17 @@ JitRuntime::generateEnterJIT(JSContext* 
     masm.storePtr(s3, Address(StackPointer, sizeof(uintptr_t))); // actual arguments
     masm.storePtr(s2, Address(StackPointer, 0)); // callee token
 
     masm.subPtr(StackPointer, s4);
     masm.makeFrameDescriptor(s4, JitFrame_Entry);
     masm.push(s4); // descriptor
 
     CodeLabel returnLabel;
+    CodeLabel oomReturnLabel;
     if (type == EnterJitBaseline) {
         // Handle OSR.
         AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
         regs.take(OsrFrameReg);
         regs.take(BaselineFrameReg);
         regs.take(reg_code);
         regs.take(ReturnReg);
 
@@ -222,17 +223,17 @@ JitRuntime::generateEnterJIT(JSContext* 
 
         Register scratch = regs.takeAny();
 
         Register numStackValues = regs.takeAny();
         masm.load32(slotNumStackValues, numStackValues);
 
         // Push return address.
         masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer);
-        masm.ma_li(scratch, returnLabel.dest());
+        masm.ma_li(scratch, returnLabel.patchAt());
         masm.storePtr(scratch, Address(StackPointer, 0));
 
         // Push previous frame pointer.
         masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer);
         masm.storePtr(BaselineFrameReg, Address(StackPointer, 0));
 
         // Reserve frame.
         Register framePtr = BaselineFrameReg;
@@ -293,17 +294,17 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.jump(jitcode);
 
         // OOM: load error value, discard return address and previous frame
         // pointer and return.
         masm.bind(&error);
         masm.movePtr(framePtr, StackPointer);
         masm.addPtr(Imm32(2 * sizeof(uintptr_t)), StackPointer);
         masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
-        masm.ma_li(scratch, returnLabel.dest());
+        masm.ma_li(scratch, oomReturnLabel.patchAt());
         masm.jump(scratch);
 
         masm.bind(&notOsr);
         // Load the scope chain in R1.
         MOZ_ASSERT(R1.scratchReg() != reg_code);
         masm.loadPtr(slotScopeChain, R1.scratchReg());
     }
 
@@ -311,18 +312,20 @@ JitRuntime::generateEnterJIT(JSContext* 
     // the stack would be aligned once the call is complete.
     masm.assertStackAlignment(JitStackAlignment, sizeof(uintptr_t));
 
     // Call the function with pushing return address to stack.
     masm.callJitNoProfiler(reg_code);
 
     if (type == EnterJitBaseline) {
         // Baseline OSR will return here.
-        masm.bind(returnLabel.src());
+        masm.bind(returnLabel.target());
         masm.addCodeLabel(returnLabel);
+        masm.bind(oomReturnLabel.target());
+        masm.addCodeLabel(oomReturnLabel);
     }
 
     // Pop arguments off the stack.
     // s0 <- 8*argc (size of all arguments we pushed on the stack)
     masm.pop(s0);
     masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), s0);
     masm.addPtr(s0, StackPointer);
 
--- a/js/src/jit/mips64/Assembler-mips64.cpp
+++ b/js/src/jit/mips64/Assembler-mips64.cpp
@@ -229,28 +229,23 @@ Assembler::trace(JSTracer* trc)
     }
     if (dataRelocations_.length()) {
         CompactBufferReader reader(dataRelocations_);
         ::TraceDataRelocations(trc, &m_buffer, reader);
     }
 }
 
 void
-Assembler::Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address)
+Assembler::Bind(uint8_t* rawCode, CodeOffset* label, const void* address)
 {
-    if (label->used()) {
-        int64_t src = label->offset();
-        do {
-            Instruction* inst = (Instruction*) (rawCode + src);
-            uint64_t next = Assembler::ExtractLoad64Value(inst);
-            Assembler::UpdateLoad64Value(inst, (uint64_t)address);
-            src = next;
-        } while (src != AbsoluteLabel::INVALID_OFFSET);
+    if (label->bound()) {
+        intptr_t offset = label->offset();
+        Instruction* inst = (Instruction*) (rawCode + offset);
+        Assembler::UpdateLoad64Value(inst, (uint64_t)address);
     }
-    label->bind();
 }
 
 void
 Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target)
 {
     int64_t offset = target - branch;
     InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
     InstImm inst_beq = InstImm(op_beq, zero, zero, BOffImm16(0));
--- a/js/src/jit/mips64/Assembler-mips64.h
+++ b/js/src/jit/mips64/Assembler-mips64.h
@@ -121,17 +121,17 @@ class Assembler : public AssemblerMIPSSh
     // MacroAssemblers hold onto gcthings, so they are traced by the GC.
     void trace(JSTracer* trc);
 
     static uintptr_t GetPointer(uint8_t*);
 
     using AssemblerMIPSShared::bind;
 
     void bind(RepatchLabel* label);
-    void Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address);
+    void Bind(uint8_t* rawCode, CodeOffset* label, const void* address);
 
     static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
     static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
 
     void bind(InstImm* inst, uintptr_t branch, uintptr_t target);
 
     // Copy the assembly code to the given buffer, and perform any pending
     // relocations relying on the target address.
--- a/js/src/jit/mips64/CodeGenerator-mips64.cpp
+++ b/js/src/jit/mips64/CodeGenerator-mips64.cpp
@@ -55,33 +55,33 @@ CodeGeneratorMIPS64::visitOutOfLineBailo
 }
 
 void
 CodeGeneratorMIPS64::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool)
 {
     MTableSwitch* mir = ool->mir();
 
     masm.haltingAlign(sizeof(void*));
-    masm.bind(ool->jumpLabel()->src());
+    masm.bind(ool->jumpLabel()->target());
     masm.addCodeLabel(*ool->jumpLabel());
 
     for (size_t i = 0; i < mir->numCases(); i++) {
         LBlock* caseblock = skipTrivialBlocks(mir->getCase(i))->lir();
         Label* caseheader = caseblock->label();
         uint32_t caseoffset = caseheader->offset();
 
         // The entries of the jump table need to be absolute addresses and thus
         // must be patched after codegen is finished. Each table entry uses 8
         // instructions (4 for load address, 2 for branch, and 2 padding).
         CodeLabel cl;
-        masm.ma_li(ScratchRegister, cl.dest());
+        masm.ma_li(ScratchRegister, cl.patchAt());
         masm.branch(ScratchRegister);
         masm.as_nop();
         masm.as_nop();
-        cl.src()->bind(caseoffset);
+        cl.target()->bind(caseoffset);
         masm.addCodeLabel(cl);
     }
 }
 
 void
 CodeGeneratorMIPS64::emitTableSwitchDispatch(MTableSwitch* mir, Register index,
                                              Register address)
 {
@@ -97,17 +97,17 @@ CodeGeneratorMIPS64::emitTableSwitchDisp
 
     // To fill in the CodeLabels for the case entries, we need to first
     // generate the case entries (we don't yet know their offsets in the
     // instruction stream).
     OutOfLineTableSwitch* ool = new(alloc()) OutOfLineTableSwitch(mir);
     addOutOfLineCode(ool, mir);
 
     // Compute the position where a pointer to the right case stands.
-    masm.ma_li(address, ool->jumpLabel()->dest());
+    masm.ma_li(address, ool->jumpLabel()->patchAt());
     // index = size of table entry * index.
     // See CodeGeneratorMIPS64::visitOutOfLineTableSwitch
     masm.lshiftPtr(Imm32(5), index);
     masm.addPtr(index, address);
 
     masm.branch(address);
 }
 
--- a/js/src/jit/mips64/MacroAssembler-mips64.cpp
+++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp
@@ -268,24 +268,21 @@ MacroAssemblerMIPS64Compat::inc64(Absolu
 
 void
 MacroAssemblerMIPS64Compat::movq(Register rs, Register rd)
 {
     ma_move(rd, rs);
 }
 
 void
-MacroAssemblerMIPS64::ma_li(Register dest, AbsoluteLabel* label)
+MacroAssemblerMIPS64::ma_li(Register dest, CodeOffset* label)
 {
-    MOZ_ASSERT(!label->bound());
-    // Thread the patch list through the unpatched address word in the
-    // instruction stream.
     BufferOffset bo = m_buffer.nextOffset();
-    ma_liPatchable(dest, ImmWord(label->prev()));
-    label->setPrev(bo.getOffset());
+    ma_liPatchable(dest, ImmWord(/* placeholder */ 0));
+    label->bind(bo.getOffset());
 }
 
 void
 MacroAssemblerMIPS64::ma_li(Register dest, ImmWord imm)
 {
     if ((int64_t)imm.value >= INT16_MIN  && (int64_t)imm.value <= INT16_MAX) {
         as_addiu(dest, zero, imm.value);
     } else if (imm.value <= UINT16_MAX) {
--- a/js/src/jit/mips64/MacroAssembler-mips64.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64.h
@@ -54,17 +54,17 @@ class MacroAssemblerMIPS64 : public Macr
     using MacroAssemblerMIPSShared::ma_li;
     using MacroAssemblerMIPSShared::ma_ss;
     using MacroAssemblerMIPSShared::ma_sd;
     using MacroAssemblerMIPSShared::ma_load;
     using MacroAssemblerMIPSShared::ma_store;
     using MacroAssemblerMIPSShared::ma_cmp_set;
     using MacroAssemblerMIPSShared::ma_subTestOverflow;
 
-    void ma_li(Register dest, AbsoluteLabel* label);
+    void ma_li(Register dest, CodeOffset* label);
     void ma_li(Register dest, ImmWord imm);
     void ma_liPatchable(Register dest, ImmPtr imm);
     void ma_liPatchable(Register dest, ImmWord imm, LiFlags flags = Li48);
 
     // Shift operations
     void ma_dsll(Register rd, Register rt, Imm32 shift);
     void ma_dsrl(Register rd, Register rt, Imm32 shift);
     void ma_dsra(Register rd, Register rt, Imm32 shift);
--- a/js/src/jit/mips64/Trampoline-mips64.cpp
+++ b/js/src/jit/mips64/Trampoline-mips64.cpp
@@ -192,16 +192,17 @@ JitRuntime::generateEnterJIT(JSContext* 
     masm.storePtr(s3, Address(StackPointer, sizeof(uintptr_t))); // actual arguments
     masm.storePtr(reg_token, Address(StackPointer, 0)); // callee token
 
     masm.subPtr(StackPointer, s4);
     masm.makeFrameDescriptor(s4, JitFrame_Entry);
     masm.push(s4); // descriptor
 
     CodeLabel returnLabel;
+    CodeLabel oomReturnLabel;
     if (type == EnterJitBaseline) {
         // Handle OSR.
         AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
         regs.take(OsrFrameReg);
         regs.take(BaselineFrameReg);
         regs.take(reg_code);
         regs.take(ReturnReg);
         regs.take(JSReturnOperand);
@@ -210,17 +211,17 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.ma_b(OsrFrameReg, OsrFrameReg, &notOsr, Assembler::Zero, ShortJump);
 
         Register numStackValues = reg_values;
         regs.take(numStackValues);
         Register scratch = regs.takeAny();
 
         // Push return address.
         masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer);
-        masm.ma_li(scratch, returnLabel.dest());
+        masm.ma_li(scratch, returnLabel.patchAt());
         masm.storePtr(scratch, Address(StackPointer, 0));
 
         // Push previous frame pointer.
         masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer);
         masm.storePtr(BaselineFrameReg, Address(StackPointer, 0));
 
         // Reserve frame.
         Register framePtr = BaselineFrameReg;
@@ -280,17 +281,17 @@ JitRuntime::generateEnterJIT(JSContext* 
         masm.jump(jitcode);
 
         // OOM: load error value, discard return address and previous frame
         // pointer and return.
         masm.bind(&error);
         masm.movePtr(framePtr, StackPointer);
         masm.addPtr(Imm32(2 * sizeof(uintptr_t)), StackPointer);
         masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
-        masm.ma_li(scratch, returnLabel.dest());
+        masm.ma_li(scratch, oomReturnLabel.patchAt());
         masm.jump(scratch);
 
         masm.bind(&notOsr);
         // Load the scope chain in R1.
         MOZ_ASSERT(R1.scratchReg() != reg_code);
         masm.ma_move(R1.scratchReg(), reg_chain);
     }
 
@@ -298,18 +299,20 @@ JitRuntime::generateEnterJIT(JSContext* 
     // the stack would be aligned once the call is complete.
     masm.assertStackAlignment(JitStackAlignment, sizeof(uintptr_t));
 
     // Call the function with pushing return address to stack.
     masm.callJitNoProfiler(reg_code);
 
     if (type == EnterJitBaseline) {
         // Baseline OSR will return here.
-        masm.bind(returnLabel.src());
+        masm.bind(returnLabel.target());
         masm.addCodeLabel(returnLabel);
+        masm.bind(oomReturnLabel.target());
+        masm.addCodeLabel(oomReturnLabel);
     }
 
     // Pop arguments off the stack.
     // s0 <- 8*argc (size of all arguments we pushed on the stack)
     masm.pop(s0);
     masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), s0);
     masm.addPtr(s0, StackPointer);
 
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -101,19 +101,21 @@ static MOZ_CONSTEXPR_VAR Register CallTe
 
 // Different argument registers for WIN64
 #if defined(_WIN64)
 static MOZ_CONSTEXPR_VAR Register IntArgReg0 = rcx;
 static MOZ_CONSTEXPR_VAR Register IntArgReg1 = rdx;
 static MOZ_CONSTEXPR_VAR Register IntArgReg2 = r8;
 static MOZ_CONSTEXPR_VAR Register IntArgReg3 = r9;
 static MOZ_CONSTEXPR_VAR uint32_t NumIntArgRegs = 4;
-static MOZ_CONSTEXPR_VAR Register IntArgRegs[NumIntArgRegs] = { rcx, rdx, r8, r9 };
+// Use "const" instead of MOZ_CONSTEXPR_VAR here to work around a bug
+// of VS2015 Update 1. See bug 1229604.
+static const Register IntArgRegs[NumIntArgRegs] = { rcx, rdx, r8, r9 };
 
-static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { rax, rdi, rbx, rsi };
+static const Register CallTempNonArgRegs[] = { rax, rdi, rbx, rsi };
 static const uint32_t NumCallTempNonArgRegs =
     mozilla::ArrayLength(CallTempNonArgRegs);
 
 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg0 = xmm0;
 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg1 = xmm1;
 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg2 = xmm2;
 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg3 = xmm3;
 static const uint32_t NumFloatArgRegs = 4;
@@ -121,19 +123,21 @@ static MOZ_CONSTEXPR_VAR FloatRegister F
 #else
 static MOZ_CONSTEXPR_VAR Register IntArgReg0 = rdi;
 static MOZ_CONSTEXPR_VAR Register IntArgReg1 = rsi;
 static MOZ_CONSTEXPR_VAR Register IntArgReg2 = rdx;
 static MOZ_CONSTEXPR_VAR Register IntArgReg3 = rcx;
 static MOZ_CONSTEXPR_VAR Register IntArgReg4 = r8;
 static MOZ_CONSTEXPR_VAR Register IntArgReg5 = r9;
 static MOZ_CONSTEXPR_VAR uint32_t NumIntArgRegs = 6;
-static MOZ_CONSTEXPR_VAR Register IntArgRegs[NumIntArgRegs] = { rdi, rsi, rdx, rcx, r8, r9 };
+static const Register IntArgRegs[NumIntArgRegs] = { rdi, rsi, rdx, rcx, r8, r9 };
 
-static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { rax, rbx };
+// Use "const" instead of MOZ_CONSTEXPR_VAR here to work around a bug
+// of VS2015 Update 1. See bug 1229604.
+static const Register CallTempNonArgRegs[] = { rax, rbx };
 static const uint32_t NumCallTempNonArgRegs =
     mozilla::ArrayLength(CallTempNonArgRegs);
 
 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg0 = xmm0;
 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg1 = xmm1;
 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg2 = xmm2;
 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg3 = xmm3;
 static MOZ_CONSTEXPR_VAR FloatRegister FloatArgReg4 = xmm4;
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -27,58 +27,58 @@ MacroAssemblerX64::loadConstantDouble(do
     if (!dbl)
         return;
     // The constants will be stored in a pool appended to the text (see
     // finish()), so they will always be a fixed distance from the
     // instructions which reference them. This allows the instructions to use
     // PC-relative addressing. Use "jump" label support code, because we need
     // the same PC-relative address patching that jumps use.
     JmpSrc j = masm.vmovsd_ripr(dest.encoding());
-    dbl->uses.append(CodeOffset(j.offset()));
+    propagateOOM(dbl->uses.append(CodeOffset(j.offset())));
 }
 
 void
 MacroAssemblerX64::loadConstantFloat32(float f, FloatRegister dest)
 {
     if (maybeInlineFloat(f, dest))
         return;
     Float* flt = getFloat(f);
     if (!flt)
         return;
     // See comment in loadConstantDouble
     JmpSrc j = masm.vmovss_ripr(dest.encoding());
-    flt->uses.append(CodeOffset(j.offset()));
+    propagateOOM(flt->uses.append(CodeOffset(j.offset())));
 }
 
 void
 MacroAssemblerX64::loadConstantInt32x4(const SimdConstant& v, FloatRegister dest)
 {
     MOZ_ASSERT(v.type() == SimdConstant::Int32x4);
     if (maybeInlineInt32x4(v, dest))
         return;
     SimdData* val = getSimdData(v);
     if (!val)
         return;
     MOZ_ASSERT(val->type() == SimdConstant::Int32x4);
     JmpSrc j = masm.vmovdqa_ripr(dest.encoding());
-    val->uses.append(CodeOffset(j.offset()));
+    propagateOOM(val->uses.append(CodeOffset(j.offset())));
 }
 
 void
 MacroAssemblerX64::loadConstantFloat32x4(const SimdConstant&v, FloatRegister dest)
 {
     MOZ_ASSERT(v.type() == SimdConstant::Float32x4);
     if (maybeInlineFloat32x4(v, dest))
         return;
     SimdData* val = getSimdData(v);
     if (!val)
         return;
     MOZ_ASSERT(val->type() == SimdConstant::Float32x4);
     JmpSrc j = masm.vmovaps_ripr(dest.encoding());
-    val->uses.append(CodeOffset(j.offset()));
+    propagateOOM(val->uses.append(CodeOffset(j.offset())));
 }
 
 void
 MacroAssemblerX64::bindOffsets(const MacroAssemblerX86Shared::UsesVector& uses)
 {
     for (CodeOffset use : uses) {
         JmpDst dst(currentOffset());
         JmpSrc src(use.offset());
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
@@ -221,151 +221,101 @@ MacroAssemblerX86Shared::atomicExchangeT
 
 template void
 MacroAssemblerX86Shared::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
                                                        Register value, Register temp, AnyRegister output);
 template void
 MacroAssemblerX86Shared::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
                                                        Register value, Register temp, AnyRegister output);
 
-MacroAssemblerX86Shared::Float*
-MacroAssemblerX86Shared::getFloat(float f)
+template<class T, class Map>
+T*
+MacroAssemblerX86Shared::getConstant(const typename T::Pod& value, Map& map,
+                                     Vector<T, 0, SystemAllocPolicy>& vec)
 {
-    if (!floatMap_.initialized()) {
-        enoughMemory_ &= floatMap_.init();
+    typedef typename Map::AddPtr AddPtr;
+    if (!map.initialized()) {
+        enoughMemory_ &= map.init();
         if (!enoughMemory_)
             return nullptr;
     }
-    size_t floatIndex;
-    if (FloatMap::AddPtr p = floatMap_.lookupForAdd(f)) {
-        floatIndex = p->value();
+    size_t index;
+    if (AddPtr p = map.lookupForAdd(value)) {
+        index = p->value();
     } else {
-        floatIndex = floats_.length();
-        enoughMemory_ &= floats_.append(Float(f));
+        index = vec.length();
+        enoughMemory_ &= vec.append(T(value));
         if (!enoughMemory_)
             return nullptr;
-        enoughMemory_ &= floatMap_.add(p, f, floatIndex);
+        enoughMemory_ &= map.add(p, value, index);
         if (!enoughMemory_)
             return nullptr;
     }
-    return &floats_[floatIndex];
+    return &vec[index];
+}
+
+MacroAssemblerX86Shared::Float*
+MacroAssemblerX86Shared::getFloat(float f)
+{
+    return getConstant<Float, FloatMap>(f, floatMap_, floats_);
 }
 
 MacroAssemblerX86Shared::Double*
 MacroAssemblerX86Shared::getDouble(double d)
 {
-    if (!doubleMap_.initialized()) {
-        enoughMemory_ &= doubleMap_.init();
-        if (!enoughMemory_)
-            return nullptr;
-    }
-    size_t doubleIndex;
-    if (DoubleMap::AddPtr p = doubleMap_.lookupForAdd(d)) {
-        doubleIndex = p->value();
-    } else {
-        doubleIndex = doubles_.length();
-        enoughMemory_ &= doubles_.append(Double(d));
-        if (!enoughMemory_)
-            return nullptr;
-        enoughMemory_ &= doubleMap_.add(p, d, doubleIndex);
-        if (!enoughMemory_)
-            return nullptr;
-    }
-    return &doubles_[doubleIndex];
+    return getConstant<Double, DoubleMap>(d, doubleMap_, doubles_);
 }
 
 MacroAssemblerX86Shared::SimdData*
 MacroAssemblerX86Shared::getSimdData(const SimdConstant& v)
 {
-    if (!simdMap_.initialized()) {
-        enoughMemory_ &= simdMap_.init();
-        if (!enoughMemory_)
-            return nullptr;
-    }
-    size_t index;
-    if (SimdMap::AddPtr p = simdMap_.lookupForAdd(v)) {
-        index = p->value();
-    } else {
-        index = simds_.length();
-        enoughMemory_ &= simds_.append(SimdData(v));
-        if (!enoughMemory_)
-            return nullptr;
-        enoughMemory_ &= simdMap_.add(p, v, index);
-        if (!enoughMemory_)
-            return nullptr;
-    }
-    return &simds_[index];
+    return getConstant<SimdData, SimdMap>(v, simdMap_, simds_);
 }
 
+template<class T, class Map>
 static bool
-AppendShiftedUses(const MacroAssemblerX86Shared::UsesVector& old, size_t delta,
-                  MacroAssemblerX86Shared::UsesVector* vec)
+MergeConstants(size_t delta, const Vector<T, 0, SystemAllocPolicy>& other,
+               Map& map, Vector<T, 0, SystemAllocPolicy>& vec)
 {
-    for (CodeOffset use : old) {
-        use.offsetBy(delta);
-        if (!vec->append(use))
-            return false;
+    typedef typename Map::AddPtr AddPtr;
+    if (!map.initialized() && !map.init())
+        return false;
+
+    for (const T& c : other) {
+        size_t index;
+        if (AddPtr p = map.lookupForAdd(c.value)) {
+            index = p->value();
+        } else {
+            index = vec.length();
+            if (!vec.append(T(c.value)) || !map.add(p, c.value, index))
+                return false;
+        }
+        MacroAssemblerX86Shared::UsesVector& uses = vec[index].uses;
+        for (CodeOffset use : c.uses) {
+            use.offsetBy(delta);
+            if (!uses.append(use))
+                return false;
+        }
     }
+
     return true;
 }
 
 bool
 MacroAssemblerX86Shared::asmMergeWith(const MacroAssemblerX86Shared& other)
 {
     size_t sizeBefore = masm.size();
-
     if (!Assembler::asmMergeWith(other))
         return false;
-
-    if (!doubleMap_.initialized() && !doubleMap_.init())
-        return false;
-    if (!floatMap_.initialized() && !floatMap_.init())
-        return false;
-    if (!simdMap_.initialized() && !simdMap_.init())
+    if (!MergeConstants<Double, DoubleMap>(sizeBefore, other.doubles_, doubleMap_, doubles_))
         return false;
-
-    for (const Double& d : other.doubles_) {
-        size_t index;
-        if (DoubleMap::AddPtr p = doubleMap_.lookupForAdd(d.value)) {
-            index = p->value();
-        } else {
-            index = doubles_.length();
-            if (!doubles_.append(Double(d.value)) || !doubleMap_.add(p, d.value, index))
-                return false;
-        }
-        if (!AppendShiftedUses(d.uses, sizeBefore, &doubles_[index].uses))
-            return false;
-    }
-
-    for (const Float& f : other.floats_) {
-        size_t index;
-        if (FloatMap::AddPtr p = floatMap_.lookupForAdd(f.value)) {
-            index = p->value();
-        } else {
-            index = floats_.length();
-            if (!floats_.append(Float(f.value)) || !floatMap_.add(p, f.value, index))
-                return false;
-        }
-        if (!AppendShiftedUses(f.uses, sizeBefore, &floats_[index].uses))
-            return false;
-    }
-
-    for (const SimdData& s : other.simds_) {
-        size_t index;
-        if (SimdMap::AddPtr p = simdMap_.lookupForAdd(s.value)) {
-            index = p->value();
-        } else {
-            index = simds_.length();
-            if (!simds_.append(SimdData(s.value)) || !simdMap_.add(p, s.value, index))
-                return false;
-        }
-        if (!AppendShiftedUses(s.uses, sizeBefore, &simds_[index].uses))
-            return false;
-    }
-
+    if (!MergeConstants<Float, FloatMap>(sizeBefore, other.floats_, floatMap_, floats_))
+        return false;
+    if (!MergeConstants<SimdData, SimdMap>(sizeBefore, other.simds_, simdMap_, simds_))
+        return false;
     return true;
 }
 
 //{{{ check_macroassembler_style
 // ===============================================================
 // Stack manipulation functions.
 
 void
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
@@ -44,58 +44,58 @@ class MacroAssemblerX86Shared : public A
     // Perform a downcast. Should be removed by Bug 996602.
     MacroAssembler& asMasm();
     const MacroAssembler& asMasm() const;
 
   public:
     typedef Vector<CodeOffset, 0, SystemAllocPolicy> UsesVector;
 
   protected:
+
     // For Double, Float and SimdData, make the move ctors explicit so that MSVC
     // knows what to use instead of copying these data structures.
-    struct Double {
-        double value;
+    template<class T>
+    struct Constant {
+        typedef T Pod;
+
+        T value;
         UsesVector uses;
-        explicit Double(double value) : value(value) {}
-        Double(Double&& other) : value(other.value), uses(mozilla::Move(other.uses)) {}
-        explicit Double(const Double&) = delete;
+
+        explicit Constant(const T& value) : value(value) {}
+        Constant(Constant<T>&& other) : value(other.value), uses(mozilla::Move(other.uses)) {}
+        explicit Constant(const Constant<T>&) = delete;
     };
 
-    // These use SystemAllocPolicy since asm.js releases memory after each
+    // Containers use SystemAllocPolicy since asm.js releases memory after each
     // function is compiled, and these need to live until after all functions
     // are compiled.
+    using Double = Constant<double>;
     Vector<Double, 0, SystemAllocPolicy> doubles_;
     typedef HashMap<double, size_t, DefaultHasher<double>, SystemAllocPolicy> DoubleMap;
     DoubleMap doubleMap_;
 
-    struct Float {
-        float value;
-        UsesVector uses;
-        explicit Float(float value) : value(value) {}
-        Float(Float&& other) : value(other.value), uses(mozilla::Move(other.uses)) {}
-        explicit Float(const Float&) = delete;
-    };
-
+    using Float = Constant<float>;
     Vector<Float, 0, SystemAllocPolicy> floats_;
     typedef HashMap<float, size_t, DefaultHasher<float>, SystemAllocPolicy> FloatMap;
     FloatMap floatMap_;
 
-    struct SimdData {
-        SimdConstant value;
-        UsesVector uses;
-        explicit SimdData(const SimdConstant& v) : value(v) {}
-        SimdData(SimdData&& other) : value(other.value), uses(mozilla::Move(other.uses)) {}
+    struct SimdData : public Constant<SimdConstant> {
+        explicit SimdData(SimdConstant d) : Constant<SimdConstant>(d) {}
+        SimdData(SimdData&& d) : Constant<SimdConstant>(mozilla::Move(d)) {}
         explicit SimdData(const SimdData&) = delete;
         SimdConstant::Type type() const { return value.type(); }
     };
 
     Vector<SimdData, 0, SystemAllocPolicy> simds_;
     typedef HashMap<SimdConstant, size_t, SimdConstant, SystemAllocPolicy> SimdMap;
     SimdMap simdMap_;
 
+    template<class T, class Map>
+    T* getConstant(const typename T::Pod& value, Map& map, Vector<T, 0, SystemAllocPolicy>& vec);
+
     Float* getFloat(float f);
     Double* getDouble(double d);
     SimdData* getSimdData(const SimdConstant& v);
 
     bool asmMergeWith(const MacroAssemblerX86Shared& other);
 
   public:
     using Assembler::call;
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -56,17 +56,19 @@ static MOZ_CONSTEXPR_VAR Register Argume
 static MOZ_CONSTEXPR_VAR Register CallTempReg0 = edi;
 static MOZ_CONSTEXPR_VAR Register CallTempReg1 = eax;
 static MOZ_CONSTEXPR_VAR Register CallTempReg2 = ebx;
 static MOZ_CONSTEXPR_VAR Register CallTempReg3 = ecx;
 static MOZ_CONSTEXPR_VAR Register CallTempReg4 = esi;
 static MOZ_CONSTEXPR_VAR Register CallTempReg5 = edx;
 
 // We have no arg regs, so our NonArgRegs are just our CallTempReg*
-static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { edi, eax, ebx, ecx, esi, edx };
+// Use "const" instead of MOZ_CONSTEXPR_VAR here to work around a bug
+// of VS2015 Update 1. See bug 1229604.
+static const Register CallTempNonArgRegs[] = { edi, eax, ebx, ecx, esi, edx };
 static const uint32_t NumCallTempNonArgRegs =
     mozilla::ArrayLength(CallTempNonArgRegs);
 
 class ABIArgGenerator
 {
     uint32_t stackOffset_;
     ABIArg current_;
 
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -94,77 +94,77 @@ void
 MacroAssemblerX86::loadConstantDouble(double d, FloatRegister dest)
 {
     if (maybeInlineDouble(d, dest))
         return;
     Double* dbl = getDouble(d);
     if (!dbl)
         return;
     masm.vmovsd_mr(nullptr, dest.encoding());
-    dbl->uses.append(CodeOffset(masm.size()));
+    propagateOOM(dbl->uses.append(CodeOffset(masm.size())));
 }
 
 void
 MacroAssemblerX86::addConstantDouble(double d, FloatRegister dest)
 {
     Double* dbl = getDouble(d);
     if (!dbl)
         return;
     masm.vaddsd_mr(nullptr, dest.encoding(), dest.encoding());
-    dbl->uses.append(CodeOffset(masm.size()));
+    propagateOOM(dbl->uses.append(CodeOffset(masm.size())));
 }
 
 void
 MacroAssemblerX86::loadConstantFloat32(float f, FloatRegister dest)
 {
     if (maybeInlineFloat(f, dest))
         return;
     Float* flt = getFloat(f);
     if (!flt)
         return;
     masm.vmovss_mr(nullptr, dest.encoding());
-    flt->uses.append(CodeOffset(masm.size()));
+    propagateOOM(flt->uses.append(CodeOffset(masm.size())));
 }
 
 void
 MacroAssemblerX86::addConstantFloat32(float f, FloatRegister dest)
 {
     Float* flt = getFloat(f);
     if (!flt)
         return;
     masm.vaddss_mr(nullptr, dest.encoding(), dest.encoding());
-    flt->uses.append(CodeOffset(masm.size()));
+    propagateOOM(flt->uses.append(CodeOffset(masm.size())));
 }
 
 void
 MacroAssemblerX86::loadConstantInt32x4(const SimdConstant& v, FloatRegister dest)
 {
     MOZ_ASSERT(v.type() == SimdConstant::Int32x4);
     if (maybeInlineInt32x4(v, dest))
         return;
     SimdData* i4 = getSimdData(v);
     if (!i4)
         return;
     MOZ_ASSERT(i4->type() == SimdConstant::Int32x4);
     masm.vmovdqa_mr(nullptr, dest.encoding());
-    i4->uses.append(CodeOffset(masm.size()));
+    propagateOOM(i4->uses.append(CodeOffset(masm.size())));
 }
 
 void
 MacroAssemblerX86::loadConstantFloat32x4(const SimdConstant& v, FloatRegister dest)
 {
     MOZ_ASSERT(v.type() == SimdConstant::Float32x4);
     if (maybeInlineFloat32x4(v, dest))
         return;
     SimdData* f4 = getSimdData(v);
     if (!f4)
         return;
     MOZ_ASSERT(f4->type() == SimdConstant::Float32x4);
     masm.vmovaps_mr(nullptr, dest.encoding());
-    f4->uses.append(CodeOffset(masm.size()));
+    propagateOOM(f4->uses.append(CodeOffset(masm.size())));
 }
 
 void
 MacroAssemblerX86::finish()
 {
     if (!doubles_.empty())
         masm.haltingAlign(sizeof(double));
     for (const Double& d : doubles_) {
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -114,11 +114,8 @@ LOCAL_INCLUDES += [
     '..',
 ]
 
 USE_LIBS += [
     'static:js',
 ]
 
 OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
-
-if not CONFIG['GNU_CXX']:
-    ALLOW_COMPILER_WARNINGS = True
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * JS math package.
  */
 
 #include "jsmath.h"
 
-#include "mozilla/Constants.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/unused.h"
 
 #include <algorithm>  // for std::max
 #include <fcntl.h>
 
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -4,42 +4,19 @@
  * 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 jsmath_h
 #define jsmath_h
 
 #include "mozilla/MemoryReporting.h"
 
-#include "NamespaceImports.h"
+#include <cmath>
 
-#ifndef M_PI
-# define M_PI            3.14159265358979323846
-#endif
-#ifndef M_E
-# define M_E             2.7182818284590452354
-#endif
-#ifndef M_LOG2E
-# define M_LOG2E         1.4426950408889634074
-#endif
-#ifndef M_LOG10E
-# define M_LOG10E        0.43429448190325182765
-#endif
-#ifndef M_LN2
-# define M_LN2           0.69314718055994530942
-#endif
-#ifndef M_LN10
-# define M_LN10          2.30258509299404568402
-#endif
-#ifndef M_SQRT2
-# define M_SQRT2         1.41421356237309504880
-#endif
-#ifndef M_SQRT1_2
-# define M_SQRT1_2       0.70710678118654752440
-#endif
+#include "NamespaceImports.h"
 
 namespace js {
 
 typedef double (*UnaryFunType)(double);
 
 class MathCache
 {
   public:
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -636,16 +636,18 @@ if CONFIG['_MSC_VER']:
     # pattern widely used in code in js/src, suppress this warning here.
     CXXFLAGS += ['-wd4805']
     # C4661 ("no suitable definition provided for explicit template
     # instantiation request") is emitted for all Parser methods that
     # have a Parser<FullParseHandler> definition but no
     # Parser<SyntaxParseHandler> definition, see bug 1167030.
     CXXFLAGS += ['-wd4661']
     CXXFLAGS += ['-we4067', '-we4258', '-we4275']
+    CXXFLAGS += ['-wd4146'] # FIXME: unary minus operator applied to unsigned type (bug 1229189)
+    CXXFLAGS += ['-wd4273'] # FIXME: inconsistent dll linkage (bug 1229666)
 
 if CONFIG['OS_ARCH'] not in ('WINNT', 'HP-UX'):
     OS_LIBS += [
         'm',
     ]
 
 if CONFIG['OS_ARCH'] == 'FreeBSD':
     OS_LIBS += [
@@ -664,19 +666,16 @@ if CONFIG['OS_ARCH'] == 'SunOS':
         'nsl',
         'socket',
     ]
 
 CFLAGS += CONFIG['MOZ_ICU_CFLAGS']
 CXXFLAGS += CONFIG['MOZ_ICU_CFLAGS']
 LOCAL_INCLUDES += CONFIG['MOZ_ICU_INCLUDES']
 
-if not CONFIG['GNU_CXX']:
-    ALLOW_COMPILER_WARNINGS = True
-
 NO_EXPAND_LIBS = True
 
 DIST_INSTALL = True
 
 # Prepare self-hosted JS code for embedding
 GENERATED_FILES += ['selfhosted.out.h']
 selfhosted = GENERATED_FILES['selfhosted.out.h']
 selfhosted.script = 'builtin/embedjs.py:generate_selfhosted'
--- a/js/src/shell/moz.build
+++ b/js/src/shell/moz.build
@@ -27,19 +27,16 @@ if CONFIG['_MSC_VER']:
 LOCAL_INCLUDES += [
     '!..',
     '..',
 ]
 
 OS_LIBS += CONFIG['EDITLINE_LIBS']
 OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
 
-if not CONFIG['GNU_CXX']:
-    ALLOW_COMPILER_WARNINGS = True
-
 # Prepare module loader JS code for embedding
 GENERATED_FILES += ['shellmoduleloader.out.h']
 shellmoduleloader = GENERATED_FILES['shellmoduleloader.out.h']
 shellmoduleloader.script = '../builtin/embedjs.py:generate_shellmoduleloader'
 shellmoduleloader.inputs = [
     '../js.msg',
     'ModuleLoader.js',
 ]
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Map/iterable.js
@@ -0,0 +1,15 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+let length;
+let iterable = {
+   [Symbol.iterator]() { return this; },
+   next() { length = arguments.length; return {done: true}; }
+};
+
+let m = new Map(iterable);
+// ensure no arguments are passed to next() during construction (Bug 1197095)
+assertEq(length, 0);
+
+if (typeof reportCompare === "function")
+  reportCompare(0, 0);
--- a/js/src/vm/ForOfIterator.cpp
+++ b/js/src/vm/ForOfIterator.cpp
@@ -118,17 +118,16 @@ ForOfIterator::nextFromOptimizedArray(Mu
 
     return GetElement(cx_, iterator, iterator, index++, vp);
 }
 
 bool
 ForOfIterator::next(MutableHandleValue vp, bool* done)
 {
     MOZ_ASSERT(iterator);
-
     if (index != NOT_ARRAY) {
         ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx_);
         if (!stubChain)
             return false;
 
         if (stubChain->isArrayNextStillSane())
             return nextFromOptimizedArray(vp, done);
 
@@ -138,21 +137,20 @@ ForOfIterator::next(MutableHandleValue v
             return false;
     }
 
     RootedValue method(cx_);
     if (!GetProperty(cx_, iterator, iterator, cx_->names().next, &method))
         return false;
 
     InvokeArgs args(cx_);
-    if (!args.init(1))
+    if (!args.init(0))
         return false;
     args.setCallee(method);
     args.setThis(ObjectValue(*iterator));
-    args[0].setUndefined();
     if (!Invoke(cx_, args))
         return false;
 
     RootedObject resultObj(cx_, ToObject(cx_, args.rval()));
     if (!resultObj)
         return false;
     RootedValue doneVal(cx_);
     if (!GetProperty(cx_, resultObj, resultObj, cx_->names().done, &doneVal))
--- a/js/src/vm/SavedStacks.h
+++ b/js/src/vm/SavedStacks.h
@@ -165,18 +165,22 @@ class SavedStacks {
     bool     initialized() const { return frames.initialized(); }
     bool     saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame, unsigned maxFrameCount = 0);
     bool     copyAsyncStack(JSContext* cx, HandleObject asyncStack, HandleString asyncCause,
                             MutableHandleSavedFrame adoptedStack, unsigned maxFrameCount = 0);
     void     sweep(JSRuntime* rt);
     void     trace(JSTracer* trc);
     uint32_t count();
     void     clear();
+    void     chooseSamplingProbability(JSCompartment*);
+
+    // Set the sampling random number generator's state to |state0| and
+    // |state1|. One or the other must be non-zero. See the comments for
+    // mozilla::non_crypto::XorShift128PlusRNG::setState for details.
     void     setRNGState(uint64_t state0, uint64_t state1) { bernoulli.setRandomState(state0, state1); }
-    void     chooseSamplingProbability(JSCompartment*);
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
   private:
     SavedFrame::Set frames;
     mozilla::FastBernoulliTrial bernoulli;
     bool creatingSavedFrame;
 
--- a/layout/base/ActiveLayerTracker.cpp
+++ b/layout/base/ActiveLayerTracker.cpp
@@ -1,16 +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/. */
 
 #include "ActiveLayerTracker.h"
 
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/dom/KeyframeEffect.h"
 #include "mozilla/gfx/Matrix.h"
+#include "mozilla/EffectSet.h"
 #include "mozilla/PodOperations.h"
 #include "nsExpirationTracker.h"
 #include "nsContainerFrame.h"
 #include "nsIContent.h"
 #include "nsRefreshDriver.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocument.h"
 #include "nsAnimationManager.h"
@@ -444,29 +446,25 @@ ActiveLayerTracker::IsOffsetOrMarginStyl
   // bug 1009693 is fixed. Until that happens, layerization isn't useful for
   // animations of these properties because we'll invalidate the layer contents
   // on every change anyway.
   // See bug 1151346 for a patch that adds a check for CSS animations.
   return false;
 }
 
 // A helper function for IsScaleSubjectToAnimation which returns true if the
-// given AnimationCollection contains a current effect that animates scale.
+// given EffectSet contains a current effect that animates scale.
 static bool
-ContainsAnimatedScale(AnimationCollection* aCollection, nsIFrame* aFrame)
+ContainsAnimatedScale(EffectSet& aEffects, nsIFrame* aFrame)
 {
-  if (!aCollection) {
-    return false;
-  }
-
-  for (dom::Animation* anim : aCollection->mAnimations) {
-    if (!anim->HasCurrentEffect()) {
+  for (dom::KeyframeEffectReadOnly* effect : aEffects) {
+    if (!effect->IsCurrent()) {
       continue;
     }
-    KeyframeEffectReadOnly* effect = anim->GetEffect();
+
     for (const AnimationProperty& prop : effect->Properties()) {
       if (prop.mProperty != eCSSProperty_transform) {
         continue;
       }
       for (AnimationPropertySegment segment : prop.mSegments) {
         gfxSize from = segment.mFromValue.GetScaleValue(aFrame);
         if (from != gfxSize(1.0f, 1.0f)) {
           return true;
@@ -486,37 +484,20 @@ ContainsAnimatedScale(AnimationCollectio
 ActiveLayerTracker::IsScaleSubjectToAnimation(nsIFrame* aFrame)
 {
   // Check whether JavaScript is animating this frame's scale.
   LayerActivity* layerActivity = GetLayerActivity(aFrame);
   if (layerActivity && layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE] >= 2) {
     return true;
   }
 
-  nsIContent* content = aFrame->GetContent();
-  if (!content || !content->IsElement()) {
-    return false;
-  }
-
-  nsCSSPseudoElements::Type pseudoType =
-    aFrame->StyleContext()->GetPseudoType();
-
-  // Check if any transitions associated with this frame may animate its scale.
-  AnimationCollection* transitions =
-    aFrame->PresContext()->TransitionManager()->GetAnimations(
-      content->AsElement(), pseudoType, false /* don't create */);
-  if (ContainsAnimatedScale(transitions, aFrame)) {
-    return true;
-  }
-
-  // Check if any animations associated with this frame may animate its scale.
-  AnimationCollection* animations =
-    aFrame->PresContext()->AnimationManager()->GetAnimations(
-      content->AsElement(), pseudoType, false /* don't create */);
-  if (ContainsAnimatedScale(animations, aFrame)) {
+  // Check if any animations, transitions, etc. associated with this frame may
+  // animate its scale.
+  EffectSet* effects = EffectSet::GetEffectSet(aFrame);
+  if (effects && ContainsAnimatedScale(*effects, aFrame)) {
     return true;
   }
 
   return false;
 }
 
 /* static */ void
 ActiveLayerTracker::NotifyContentChange(nsIFrame* aFrame)
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1330,29 +1330,20 @@ RestyleManager::AttributeChanged(Element
                                                          aOldValue,
                                                          rsdata);
   PostRestyleEvent(aElement, rshint, hint, &rsdata);
 }
 
 /* static */ uint64_t
 RestyleManager::GetMaxAnimationGenerationForFrame(nsIFrame* aFrame)
 {
-  nsIContent* content = aFrame->GetContent();
-  if (!content || !content->IsElement()) {
-    return 0;
-  }
-
-  nsCSSPseudoElements::Type pseudoType =
-    aFrame->StyleContext()->GetPseudoType();
   AnimationCollection* transitions =
-    aFrame->PresContext()->TransitionManager()->GetAnimations(
-      content->AsElement(), pseudoType, false /* don't create */);
+    aFrame->PresContext()->TransitionManager()->GetAnimationCollection(aFrame);
   AnimationCollection* animations =
-    aFrame->PresContext()->AnimationManager()->GetAnimations(
-      content->AsElement(), pseudoType, false /* don't create */);
+    aFrame->PresContext()->AnimationManager()->GetAnimationCollection(aFrame);
 
   return std::max(transitions ? transitions->mAnimationGeneration : 0,
                   animations ? animations->mAnimationGeneration : 0);
 }
 
 void
 RestyleManager::RestyleForEmptyChange(Element* aContainer)
 {
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -49,16 +49,18 @@
 #include "GeckoProfiler.h"
 #include "nsAnimationManager.h"
 #include "nsTransitionManager.h"
 #include "nsViewManager.h"
 #include "ImageLayers.h"
 #include "ImageContainer.h"
 #include "nsCanvasFrame.h"
 #include "StickyScrollContainer.h"
+#include "mozilla/AnimationUtils.h"
+#include "mozilla/EffectCompositor.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/PendingAnimationTracker.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/UniquePtr.h"
 #include "ActiveLayerTracker.h"
 #include "nsContentUtils.h"
 #include "nsPrintfCString.h"
@@ -522,23 +524,19 @@ nsDisplayListBuilder::AddAnimationsAndTr
     RestyleManager::GetMaxAnimationGenerationForFrame(aFrame);
   aLayer->SetAnimationGeneration(animationGeneration);
 
   nsPresContext* presContext = aFrame->PresContext();
   presContext->TransitionManager()->ClearIsRunningOnCompositor(aFrame,
                                                                aProperty);
   presContext->AnimationManager()->ClearIsRunningOnCompositor(aFrame,
                                                               aProperty);
-  AnimationCollection* transitions =
-    presContext->TransitionManager()->GetAnimationsForCompositor(aFrame,
-                                                                 aProperty);
-  AnimationCollection* animations =
-    presContext->AnimationManager()->GetAnimationsForCompositor(aFrame,
-                                                                aProperty);
-  if (!animations && !transitions) {
+  nsTArray<RefPtr<dom::Animation>> compositorAnimations =
+    EffectCompositor::GetAnimationsForCompositor(aFrame, aProperty);
+  if (compositorAnimations.IsEmpty()) {
     return;
   }
 
   // If the frame is not prerendered, bail out.
   // Do this check only during layer construction; during updating the
   // caller is required to check it appropriately.
   if (aItem && !aItem->CanUseAsyncAnimations(aBuilder)) {
     // AnimationManager or TransitionManager need to know that we refused to
@@ -584,27 +582,18 @@ nsDisplayListBuilder::AddAnimationsAndTr
     }
 
     data = TransformData(origin, offsetToTransformOrigin,
                          bounds, devPixelsToAppUnits);
   } else if (aProperty == eCSSProperty_opacity) {
     data = null_t();
   }
 
-  // When both are running, animations override transitions.  We want
-  // to add the ones that override last.
-  if (transitions) {
-    AddAnimationsForProperty(aFrame, aProperty, transitions->mAnimations,
-                             aLayer, data, pending);
-  }
-
-  if (animations) {
-    AddAnimationsForProperty(aFrame, aProperty, animations->mAnimations,
-                             aLayer, data, pending);
-  }
+  AddAnimationsForProperty(aFrame, aProperty, compositorAnimations,
+                           aLayer, data, pending);
 }
 
 nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
     Mode aMode, bool aBuildCaret)
     : mReferenceFrame(aReferenceFrame),
       mIgnoreScrollFrame(nullptr),
       mLayerEventRegions(nullptr),
       mCurrentTableItem(nullptr),
@@ -2543,18 +2532,27 @@ nsDisplayBackgroundImage::CanOptimizeToI
     return false;
   }
 
   if (!imageRenderer->IsContainerAvailable(aManager, aBuilder)) {
     // The image is not ready to be made into a layer yet.
     return false;
   }
 
-  // We currently can't handle tiled or partial backgrounds.
-  if (!state.mDestArea.IsEqualEdges(state.mFillArea)) {
+  // We currently can't handle tiled backgrounds.
+  if (!state.mDestArea.Contains(state.mFillArea)) {
+    return false;
+  }
+
+  // For 'contain' and 'cover', we allow any pixel of the image to be sampled
+  // because there isn't going to be any spriting/atlasing going on.
+  bool allowPartialImages =
+    (layer.mSize.mWidthType == nsStyleBackground::Size::eContain ||
+     layer.mSize.mWidthType == nsStyleBackground::Size::eCover);
+  if (!allowPartialImages && !state.mFillArea.Contains(state.mDestArea)) {
     return false;
   }
 
   // XXX Ignoring state.mAnchor. ImageLayer drawing snaps mDestArea edges to
   // layer pixel boundaries. This should be OK for now.
 
   int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   mImageLayerDestRect =
@@ -5384,18 +5382,17 @@ nsDisplayOpacity::CanUseAsyncAnimations(
 {
   if (ActiveLayerTracker::IsStyleAnimated(aBuilder, mFrame, eCSSProperty_opacity)) {
     return true;
   }
 
   if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
     nsCString message;
     message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for opacity animation");
-    AnimationCollection::LogAsyncAnimationFailure(message,
-                                                  Frame()->GetContent());
+    AnimationUtils::LogAsyncAnimationFailure(message, Frame()->GetContent());
   }
   return false;
 }
 
 bool
 nsDisplayTransform::ShouldPrerender(nsDisplayListBuilder* aBuilder) {
   if (!mMaybePrerender) {
     return false;
@@ -5436,18 +5433,17 @@ nsDisplayTransform::ShouldPrerenderTrans
   // have a compositor-animated transform, can be prerendered. An element
   // might have only just had its transform animated in which case
   // the ActiveLayerManager may not have been notified yet.
   if (!ActiveLayerTracker::IsStyleMaybeAnimated(aFrame, eCSSProperty_transform) &&
       !nsLayoutUtils::HasAnimationsForCompositor(aFrame, eCSSProperty_transform)) {
     if (aLogAnimations) {
       nsCString message;
       message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation");
-      AnimationCollection::LogAsyncAnimationFailure(message,
-                                                    aFrame->GetContent());
+      AnimationUtils::LogAsyncAnimationFailure(message, aFrame->GetContent());
     }
     return false;
   }
 
   nsSize refSize = aBuilder->RootReferenceFrame()->GetSize();
   // Only prerender if the transformed frame's size is <= the
   // reference frame size (~viewport), allowing a 1/8th fuzz factor
   // for shadows, borders, etc.
@@ -5476,18 +5472,17 @@ nsDisplayTransform::ShouldPrerenderTrans
     message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.height));
     message.AppendLiteral(") or the visual rectangle (");
     message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(visual.width));
     message.AppendLiteral(", ");
     message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(visual.height));
     message.AppendLiteral(") is larger than the max allowable value (");
     message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(maxInAppUnits));
     message.Append(')');
-    AnimationCollection::LogAsyncAnimationFailure(message,
-                                                  aFrame->GetContent());
+    AnimationUtils::LogAsyncAnimationFailure(message, aFrame->GetContent());
   }
   return false;
 }
 
 /* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
 static bool IsFrameVisible(nsIFrame* aFrame, const Matrix4x4& aMatrix)
 {
   if (aMatrix.IsSingular()) {
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -4,16 +4,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/. */
 
 #include "nsLayoutUtils.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/ClearOnShutdown.h"
+#include "mozilla/EffectCompositor.h"
+#include "mozilla/EffectSet.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsCharTraits.h"
 #include "nsFontMetrics.h"
@@ -367,82 +369,80 @@ FloatLogicalValuesEnabledPrefChangeCallb
   nsCSSProps::kClearKTable[sIndexOfInlineEndInClearTable].mKeyword =
     isFloatLogicalValuesEnabled ? eCSSKeyword_inline_end : eCSSKeyword_UNKNOWN;
 }
 
 bool
 nsLayoutUtils::HasAnimationsForCompositor(const nsIFrame* aFrame,
                                           nsCSSProperty aProperty)
 {
-  nsPresContext* presContext = aFrame->PresContext();
-  return presContext->AnimationManager()->GetAnimationsForCompositor(aFrame, aProperty) ||
-         presContext->TransitionManager()->GetAnimationsForCompositor(aFrame, aProperty);
+  // XXX Bug 1230056 - Add EffectCompositor::HasAnimationsForCompositor to
+  // avoid allocating an array here only to throw it away.
+  return !EffectCompositor::GetAnimationsForCompositor(aFrame,
+                                                       aProperty).IsEmpty();
+}
+
+template<typename TestType>
+static bool
+HasMatchingCurrentAnimations(const nsIFrame* aFrame, TestType&& aTest)
+{
+  EffectSet* effects = EffectSet::GetEffectSet(aFrame);
+  if (!effects) {
+    return false;
+  }
+
+  for (KeyframeEffectReadOnly* effect : *effects) {
+    if (!effect->IsCurrent()) {
+      continue;
+    }
+
+    if (aTest(*effect)) {
+      return true;
+    }
+  }
+
+  return false;
 }
 
 bool
 nsLayoutUtils::HasCurrentAnimationOfProperty(const nsIFrame* aFrame,
                                              nsCSSProperty aProperty)
 {
-  nsPresContext* presContext = aFrame->PresContext();
-  AnimationCollection* collection =
-    presContext->AnimationManager()->GetAnimationCollection(aFrame);
-  if (collection &&
-      collection->HasCurrentAnimationOfProperty(aProperty)) {
-    return true;
-  }
-  collection =
-    presContext->TransitionManager()->GetAnimationCollection(aFrame);
-  if (collection &&
-      collection->HasCurrentAnimationOfProperty(aProperty)) {
-    return true;
-  }
-  return false;
-}
-
-bool
-nsLayoutUtils::HasCurrentAnimations(const nsIFrame* aFrame)
-{
-  nsPresContext* presContext = aFrame->PresContext();
-  AnimationCollection* collection =
-    presContext->AnimationManager()->GetAnimationCollection(aFrame);
-  return collection &&
-         collection->HasCurrentAnimations();
+  return HasMatchingCurrentAnimations(aFrame,
+    [&aProperty](KeyframeEffectReadOnly& aEffect)
+    {
+      return aEffect.HasAnimationOfProperty(aProperty);
+    }
+  );
 }
 
 bool
 nsLayoutUtils::HasCurrentTransitions(const nsIFrame* aFrame)
 {
-  nsPresContext* presContext = aFrame->PresContext();
-  AnimationCollection* collection =
-    presContext->TransitionManager()->GetAnimationCollection(aFrame);
-  return collection &&
-         collection->HasCurrentAnimations();
+  return HasMatchingCurrentAnimations(aFrame,
+    [](KeyframeEffectReadOnly& aEffect)
+    {
+      // Since |aEffect| is current, it must have an associated Animation
+      // so we don't need to null-check the result of GetAnimation().
+      return aEffect.GetAnimation()->AsCSSTransition();
+    }
+  );
 }
 
 bool
 nsLayoutUtils::HasCurrentAnimationsForProperties(const nsIFrame* aFrame,
                                                  const nsCSSProperty* aProperties,
                                                  size_t aPropertyCount)
 {
-  nsPresContext* presContext = aFrame->PresContext();
-  AnimationCollection* collection =
-    presContext->AnimationManager()->GetAnimationCollection(aFrame);
-  if (collection &&
-      collection->HasCurrentAnimationsForProperties(aProperties,
-                                                    aPropertyCount)) {
-    return true;
-  }
-  collection =
-    presContext->TransitionManager()->GetAnimationCollection(aFrame);
-  if (collection &&
-      collection->HasCurrentAnimationsForProperties(aProperties,
-                                                    aPropertyCount)) {
-    return true;
-  }
-  return false;
+  return HasMatchingCurrentAnimations(aFrame,
+    [&aProperties, &aPropertyCount](KeyframeEffectReadOnly& aEffect)
+    {
+      return aEffect.HasAnimationOfProperties(aProperties, aPropertyCount);
+    }
+  );
 }
 
 static float
 GetSuitableScale(float aMaxScale, float aMinScale,
                  nscoord aVisibleDimension, nscoord aDisplayDimension)
 {
   float displayVisibleRatio = float(aDisplayDimension) /
                               float(aVisibleDimension);
@@ -459,25 +459,27 @@ GetSuitableScale(float aMaxScale, float 
     // (avoiding visually clunky delayerization).
     return aMaxScale;
   }
   return std::max(std::min(aMaxScale, displayVisibleRatio), aMinScale);
 }
 
 static void
 GetMinAndMaxScaleForAnimationProperty(const nsIFrame* aFrame,
-                                      AnimationCollection* aAnimations,
+                                      AnimationPtrArray& aAnimations,
                                       gfxSize& aMaxScale,
                                       gfxSize& aMinScale)
 {
-  for (size_t animIdx = aAnimations->mAnimations.Length(); animIdx-- != 0; ) {
-    dom::Animation* anim = aAnimations->mAnimations[animIdx];
-    if (!anim->IsRelevant()) {
-      continue;
-    }
+  for (dom::Animation* anim : aAnimations) {
+    // This method is only expected to be passed animations that are running on
+    // the compositor and we only pass playing animations to the compositor,
+    // which are, by definition, "relevant" animations (animations that are
+    // not yet finished or which are filling forwards).
+    MOZ_ASSERT(anim->IsRelevant());
+
     dom::KeyframeEffectReadOnly* effect = anim->GetEffect();
     for (size_t propIdx = effect->Properties().Length(); propIdx-- != 0; ) {
       AnimationProperty& prop = effect->Properties()[propIdx];
       if (prop.mProperty == eCSSProperty_transform) {
         for (uint32_t segIdx = prop.mSegments.Length(); segIdx-- != 0; ) {
           AnimationPropertySegment& segment = prop.mSegments[segIdx];
           gfxSize from = segment.mFromValue.GetScaleValue(aFrame);
           aMaxScale.width = std::max<float>(aMaxScale.width, from.width);
@@ -499,33 +501,22 @@ gfxSize
 nsLayoutUtils::ComputeSuitableScaleForAnimation(const nsIFrame* aFrame,
                                                 const nsSize& aVisibleSize,
                                                 const nsSize& aDisplaySize)
 {
   gfxSize maxScale(std::numeric_limits<gfxFloat>::min(),
                    std::numeric_limits<gfxFloat>::min());
   gfxSize minScale(std::numeric_limits<gfxFloat>::max(),
                    std::numeric_limits<gfxFloat>::max());
-  nsPresContext* presContext = aFrame->PresContext();
-
-  AnimationCollection* animations =
-    presContext->AnimationManager()->GetAnimationsForCompositor(
-      aFrame, eCSSProperty_transform);
-  if (animations) {
-    GetMinAndMaxScaleForAnimationProperty(aFrame, animations,
-                                          maxScale, minScale);
-  }
-
-  animations =
-    presContext->TransitionManager()->GetAnimationsForCompositor(
-      aFrame, eCSSProperty_transform);
-  if (animations) {
-    GetMinAndMaxScaleForAnimationProperty(aFrame, animations,
-                                          maxScale, minScale);
-  }
+
+  nsTArray<RefPtr<dom::Animation>> compositorAnimations =
+    EffectCompositor::GetAnimationsForCompositor(aFrame,
+                                                 eCSSProperty_transform);
+  GetMinAndMaxScaleForAnimationProperty(aFrame, compositorAnimations,
+                                        maxScale, minScale);
 
   if (maxScale.width == std::numeric_limits<gfxFloat>::min()) {
     // We didn't encounter a transform
     return gfxSize(1.0, 1.0);
   }
 
   return gfxSize(GetSuitableScale(maxScale.width, minScale.width,
                                   aVisibleSize.width, aDisplaySize.width),
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2201,24 +2201,17 @@ public:
   /**
    * Returns true if the frame has current (i.e. running or scheduled-to-run)
    * animations or transitions for the property.
    */
   static bool HasCurrentAnimationOfProperty(const nsIFrame* aFrame,
                                             nsCSSProperty aProperty);
 
   /**
-   * Returns true if the frame has any current animations.
-   * A current animation is any animation that has not yet finished playing
-   * including paused animations.
-   */
-  static bool HasCurrentAnimations(const nsIFrame* aFrame);
-
-  /**
-   * Returns true if the frame has any current transitions.
+   * Returns true if the frame has any current CSS transitions.
    * A current transition is any transition that has not yet finished playing
    * including paused transitions.
    */
   static bool HasCurrentTransitions(const nsIFrame* aFrame);
 
   /**
    * Returns true if the frame has any current animations or transitions
    * for any of the specified properties.
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -3094,21 +3094,21 @@ nsRootPresContext::CancelApplyPluginGeom
     mApplyPluginGeometryTimer = nullptr;
   }
 }
 
 #ifndef XP_MACOSX
 
 static bool
 HasOverlap(const LayoutDeviceIntPoint& aOffset1,
-           const nsTArray<nsIntRect>& aClipRects1,
+           const nsTArray<LayoutDeviceIntRect>& aClipRects1,
            const LayoutDeviceIntPoint& aOffset2,
-           const nsTArray<nsIntRect>& aClipRects2)
+           const nsTArray<LayoutDeviceIntRect>& aClipRects2)
 {
-  nsIntPoint offsetDelta = (aOffset1 - aOffset2).ToUnknownPoint();
+  LayoutDeviceIntPoint offsetDelta = aOffset1 - aOffset2;
   for (uint32_t i = 0; i < aClipRects1.Length(); ++i) {
     for (uint32_t j = 0; j < aClipRects2.Length(); ++j) {
       if ((aClipRects1[i] + offsetDelta).Intersects(aClipRects2[j])) {
         return true;
       }
     }
   }
   return false;
@@ -3144,17 +3144,17 @@ SortConfigurations(nsTArray<nsIWidget::C
     for (i = 0; i + 1 < pluginsToMove.Length(); ++i) {
       nsIWidget::Configuration* config = &pluginsToMove[i];
       bool foundOverlap = false;
       for (uint32_t j = 0; j < pluginsToMove.Length(); ++j) {
         if (i == j)
           continue;
         LayoutDeviceIntRect bounds;
         pluginsToMove[j].mChild->GetBounds(bounds);
-        nsAutoTArray<nsIntRect,1> clipRects;
+        nsAutoTArray<LayoutDeviceIntRect,1> clipRects;
         pluginsToMove[j].mChild->GetWindowClipRegion(&clipRects);
         if (HasOverlap(bounds.TopLeft(), clipRects,
                        config->mBounds.TopLeft(),
                        config->mClipRegion)) {
           foundOverlap = true;
           break;
         }
       }
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -751,32 +751,25 @@ nsImageFrame::MaybeDecodeForPredictedSiz
 
   // Request a decode.
   mImage->RequestDecodeForSize(predictedImageSize, flags);
 }
 
 nsRect
 nsImageFrame::PredictedDestRect(const nsRect& aFrameContentBox)
 {
-  // What is the rect painted by the image?  It's the image's "dest rect" (the
-  // rect where a full copy of the image is mapped), clipped to the container's
-  // content box.  So, we intersect those rects.
-
   // Note: To get the "dest rect", we have to provide the "constraint rect"
   // (which is the content-box, with the effects of fragmentation undone).
   nsRect constraintRect(aFrameContentBox.TopLeft(), mComputedSize);
   constraintRect.y -= GetContinuationOffset();
 
-  const nsRect destRect =
-    nsLayoutUtils::ComputeObjectDestRect(constraintRect,
-                                         mIntrinsicSize,
-                                         mIntrinsicRatio,
-                                         StylePosition());
-
-  return destRect.Intersect(aFrameContentBox);
+  return nsLayoutUtils::ComputeObjectDestRect(constraintRect,
+                                              mIntrinsicSize,
+                                              mIntrinsicRatio,
+                                              StylePosition());
 }
 
 void
 nsImageFrame::EnsureIntrinsicSizeAndRatio()
 {
   // If mIntrinsicSize.width and height are 0, then we need to update from the
   // image container.
   if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord &&
@@ -1639,17 +1632,18 @@ nsDisplayImage::GetLayerState(nsDisplayL
 }
 
 
 /* virtual */ nsRegion
 nsDisplayImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                 bool* aSnap)
 {
   if (mImage && mImage->IsOpaque()) {
-    return nsRegion(GetDestRect(aSnap));
+    const nsRect frameContentBox = GetBounds(aSnap);
+    return GetDestRect().Intersect(frameContentBox);
   }
   return nsRegion();
 }
 
 already_AddRefed<Layer>
 nsDisplayImage::BuildLayer(nsDisplayListBuilder* aBuilder,
                            LayerManager* aManager,
                            const ContainerLayerParameters& aParameters)
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -243,16 +243,17 @@ protected:
 
   /// Always sync decode our image when painting if @aForce is true.
   void SetForceSyncDecoding(bool aForce) { mForceSyncDecoding = aForce; }
 
   /**
    * Computes the predicted dest rect that we'll draw into, in app units, based
    * upon the provided frame content box. (The content box is what
    * nsDisplayImage::GetBounds() returns.)
+   * The result is not necessarily contained in the frame content box.
    */
   nsRect PredictedDestRect(const nsRect& aFrameContentBox);
 
 private:
   // random helpers
   inline void SpecToURI(const nsAString& aSpec, nsIIOService *aIOService,
                         nsIURI **aURI);
 
@@ -420,17 +421,18 @@ public:
   /**
    * Returns an ImageContainer for this image if the image type
    * supports it (TYPE_RASTER only).
    */
   virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
                                                         nsDisplayListBuilder* aBuilder) override;
 
   /**
-   * @return the dest rect we'll use when drawing this image, in app units.
+   * @return The dest rect we'll use when drawing this image, in app units.
+   *         Not necessarily contained in this item's bounds.
    */
   nsRect GetDestRect(bool* aSnap = nullptr);
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   nsRect GetBounds(bool* aSnap)
   {
--- a/layout/generic/nsPluginFrame.cpp
+++ b/layout/generic/nsPluginFrame.cpp
@@ -407,18 +407,17 @@ nsPluginFrame::GetWidgetConfiguration(ns
     // geometry updates and this should not be called. But apparently we
     // have bugs where mWidget sometimes is toplevel here. Bail out.
     NS_ERROR("Plugin widgets registered for geometry updates should not be toplevel");
     return;
   }
 
   nsIWidget::Configuration* configuration = aConfigurations->AppendElement();
   configuration->mChild = mWidget;
-  configuration->mBounds =
-    LayoutDeviceIntRect::FromUnknownRect(mNextConfigurationBounds);
+  configuration->mBounds = mNextConfigurationBounds;
   configuration->mClipRegion = mNextConfigurationClipRegion;
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
   if (XRE_IsContentProcess()) {
     configuration->mWindowID = (uintptr_t)mWidget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
     configuration->mVisible = mWidget->IsVisible();
   }
 #endif // defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
 }
@@ -1011,30 +1010,32 @@ nsDisplayPlugin::ComputeVisibility(nsDis
     nsPluginFrame* f = static_cast<nsPluginFrame*>(mFrame);
     if (!aBuilder->IsInTransform() || f->IsPaintedByGecko()) {
       // Since transforms induce reference frames, we don't need to worry
       // about this method fluffing out due to non-rectilinear transforms.
       nsRect rAncestor = nsLayoutUtils::TransformFrameRectToAncestor(f,
           f->GetContentRectRelativeToSelf(), ReferenceFrame());
       nscoord appUnitsPerDevPixel =
         ReferenceFrame()->PresContext()->AppUnitsPerDevPixel();
-      f->mNextConfigurationBounds = rAncestor.ToNearestPixels(appUnitsPerDevPixel);
+      f->mNextConfigurationBounds = LayoutDeviceIntRect::FromUnknownRect(
+        rAncestor.ToNearestPixels(appUnitsPerDevPixel));
 
       nsRegion visibleRegion;
       visibleRegion.And(*aVisibleRegion, GetClippedBounds(aBuilder));
       // Make visibleRegion relative to f
       visibleRegion.MoveBy(-ToReferenceFrame());
 
       f->mNextConfigurationClipRegion.Clear();
       nsRegionRectIterator iter(visibleRegion);
       for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
         nsRect rAncestor =
           nsLayoutUtils::TransformFrameRectToAncestor(f, *r, ReferenceFrame());
-        nsIntRect rPixels = rAncestor.ToNearestPixels(appUnitsPerDevPixel)
-            - f->mNextConfigurationBounds.TopLeft();
+        LayoutDeviceIntRect rPixels =
+          LayoutDeviceIntRect::FromUnknownRect(rAncestor.ToNearestPixels(appUnitsPerDevPixel)) -
+          f->mNextConfigurationBounds.TopLeft();
         if (!rPixels.IsEmpty()) {
           f->mNextConfigurationClipRegion.AppendElement(rPixels);
         }
       }
     }
 
     if (f->mInnerView) {
       // This should produce basically the same rectangle (but not relative
--- a/layout/generic/nsPluginFrame.h
+++ b/layout/generic/nsPluginFrame.h
@@ -47,16 +47,19 @@ typedef nsFrame nsPluginFrameSuper;
 class PluginFrameDidCompositeObserver;
 
 class nsPluginFrame : public nsPluginFrameSuper,
                       public nsIObjectFrame,
                       public nsIReflowCallback
 {
 public:
   typedef mozilla::LayerState LayerState;
+  typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint;
+  typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect;
+  typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::ImageContainer ImageContainer;
   typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
 
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
@@ -115,25 +118,25 @@ public:
    * position of the plugin's widget, on the assumption that it is not visible
    * (clipped out or covered by opaque content).
    * This will only be called for plugins which have been registered
    * with the root pres context for geometry updates.
    * If there is no widget associated with the plugin, this will have no effect.
    */
   void SetEmptyWidgetConfiguration()
   {
-    mNextConfigurationBounds = nsIntRect(0,0,0,0);
+    mNextConfigurationBounds = LayoutDeviceIntRect(0,0,0,0);
     mNextConfigurationClipRegion.Clear();
   }
   /**
    * Append the desired widget configuration to aConfigurations.
    */
   void GetWidgetConfiguration(nsTArray<nsIWidget::Configuration>* aConfigurations);
 
-  nsIntRect GetWidgetlessClipRect() {
+  LayoutDeviceIntRect GetWidgetlessClipRect() {
     return RegionFromArray(mNextConfigurationClipRegion).GetBounds();
   }
 
   /**
    * Called after all widget position/size/clip regions have been changed
    * (even if there isn't a widget for this plugin).
    */
   void DidSetWidgetGeometry();
@@ -244,17 +247,17 @@ protected:
 
   nsIntPoint GetWindowOriginInPixels(bool aWindowless);
   
   /*
    * If this frame is in a remote tab, return the tab offset to
    * the origin of the chrome window. In non-e10s, this return 0,0.
    * This api sends a sync ipc request so be careful about use.
    */
-  mozilla::LayoutDeviceIntPoint GetRemoteTabChromeOffset();
+  LayoutDeviceIntPoint GetRemoteTabChromeOffset();
 
   static void PaintPrintPlugin(nsIFrame* aFrame,
                                nsRenderingContext* aRenderingContext,
                                const nsRect& aDirtyRect, nsPoint aPt);
   void PrintPlugin(nsRenderingContext& aRenderingContext,
                    const nsRect& aDirtyRect);
   void PaintPlugin(nsDisplayListBuilder* aBuilder,
                    nsRenderingContext& aRenderingContext,
@@ -272,19 +275,20 @@ private:
   // mRootPresContextRegisteredWith, so that we can be sure we unregister
   // from the right root prest context in UnregisterPluginForGeometryUpdates.
   void RegisterPluginForGeometryUpdates();
 
   // Unregisters the plugin for geometry updated with the root pres context
   // stored in mRootPresContextRegisteredWith.
   void UnregisterPluginForGeometryUpdates();
 
-  static const nsIntRegion RegionFromArray(const nsTArray<nsIntRect>& aRects)
+  static const LayoutDeviceIntRegion
+  RegionFromArray(const nsTArray<LayoutDeviceIntRect>& aRects)
   {
-    nsIntRegion region;
+    LayoutDeviceIntRegion region;
     for (uint32_t i = 0; i < aRects.Length(); ++i) {
       region.Or(region, aRects[i]);
     }
     return region;
   }
 
   class PluginEventNotifier : public nsRunnable {
   public:
@@ -306,22 +310,22 @@ private:
    */
   PluginBackgroundSink*           mBackgroundSink;
 
   /**
    * Bounds that we should set the plugin's widget to in the next composite,
    * for plugins with widgets. For plugins without widgets, bounds in device
    * pixels relative to the nearest frame that's a display list reference frame.
    */
-  nsIntRect                       mNextConfigurationBounds;
+  LayoutDeviceIntRect             mNextConfigurationBounds;
   /**
    * Clip region that we should set the plugin's widget to
    * in the next composite. Only meaningful for plugins with widgets.
    */
-  nsTArray<nsIntRect>             mNextConfigurationClipRegion;
+  nsTArray<LayoutDeviceIntRect>   mNextConfigurationClipRegion;
 
   bool mReflowCallbackPosted;
 
   // We keep this reference to ensure we can always unregister the
   // plugins we register on the root PresContext.
   // This is only non-null while we have a plugin registered for geometry
   // updates.
   RefPtr<nsRootPresContext> mRootPresContextRegisteredWith;
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -47,16 +47,17 @@
 #include "nsIMathMLFrame.h"
 #include "nsPlaceholderFrame.h"
 #include "nsTextFrameUtils.h"
 #include "nsTextRunTransformations.h"
 #include "MathMLTextRunFactory.h"
 #include "nsExpirationTracker.h"
 #include "nsUnicodeProperties.h"
 #include "nsStyleUtil.h"
+#include "nsRubyFrame.h"
 
 #include "nsTextFragment.h"
 #include "nsGkAtoms.h"
 #include "nsFrameSelection.h"
 #include "nsRange.h"
 #include "nsCSSRendering.h"
 #include "nsContentUtils.h"
 #include "nsLineBreaker.h"
@@ -5150,16 +5151,29 @@ GenerateTextRunForEmphasisMarks(nsTextFr
     // The emphasis marks should always be rendered upright per spec.
     flags = gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
   }
   return aFontMetrics->GetThebesFontGroup()->
     MakeTextRun<char16_t>(emphasisString.get(), emphasisString.Length(),
                           ctx, appUnitsPerDevUnit, flags, nullptr);
 }
 
+static nsRubyFrame*
+FindRubyAncestor(nsTextFrame* aFrame)
+{
+  for (nsIFrame* frame = aFrame->GetParent();
+       frame && frame->IsFrameOfType(nsIFrame::eLineParticipant);
+       frame = frame->GetParent()) {
+    if (frame->GetType() == nsGkAtoms::rubyFrame) {
+      return static_cast<nsRubyFrame*>(frame);
+    }
+  }
+  return nullptr;
+}
+
 nsRect
 nsTextFrame::UpdateTextEmphasis(WritingMode aWM, PropertyProvider& aProvider)
 {
   const nsStyleText* styleText = StyleText();
   if (!styleText->HasTextEmphasis()) {
     Properties().Delete(EmphasisMarkProperty());
     return nsRect();
   }
@@ -5183,24 +5197,28 @@ nsTextFrame::UpdateTextEmphasis(WritingM
                            /* BStart to be computed below */0,
                            frameSize.ISize(aWM) + info->advance,
                            fm->MaxAscent() + fm->MaxDescent());
   // When the writing mode is vertical-lr the line is inverted, and thus
   // the ascent and descent are swapped.
   nscoord absOffset = (side == eLogicalSideBStart) != aWM.IsLineInverted() ?
     baseFontMetrics->MaxAscent() + fm->MaxDescent() :
     baseFontMetrics->MaxDescent() + fm->MaxAscent();
-  // XXX emphasis marks should be drawn outside ruby, see bug 1224013.
+  nscoord startLeading = 0;
+  nscoord endLeading = 0;
+  if (nsRubyFrame* ruby = FindRubyAncestor(this)) {
+    ruby->GetBlockLeadings(startLeading, endLeading);
+  }
   if (side == eLogicalSideBStart) {
-    info->baselineOffset = -absOffset;
-    overflowRect.BStart(aWM) = -overflowRect.BSize(aWM);
+    info->baselineOffset = -absOffset - startLeading;
+    overflowRect.BStart(aWM) = -overflowRect.BSize(aWM) - startLeading;
   } else {
     MOZ_ASSERT(side == eLogicalSideBEnd);
-    info->baselineOffset = absOffset;
-    overflowRect.BStart(aWM) = frameSize.BSize(aWM);
+    info->baselineOffset = absOffset + endLeading;
+    overflowRect.BStart(aWM) = frameSize.BSize(aWM) + endLeading;
   }
 
   Properties().Set(EmphasisMarkProperty(), info);
   return overflowRect.GetPhysicalRect(aWM, frameSize.GetPhysicalSize(aWM));
 }
 
 void
 nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
@@ -6195,27 +6213,28 @@ nsTextFrame::PaintTextWithSelection(gfxC
   DestroySelectionDetails(details);
   return true;
 }
 
 void
 nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM,
                                const gfxPoint& aTextBaselinePt,
                                uint32_t aOffset, uint32_t aLength,
+                               const nscolor* aDecorationOverrideColor,
                                PropertyProvider& aProvider)
 {
   auto info = static_cast<const EmphasisMarkInfo*>(
     Properties().Get(EmphasisMarkProperty()));
   if (!info) {
     MOZ_ASSERT(!StyleText()->HasTextEmphasis());
     return;
   }
 
-  nscolor color = nsLayoutUtils::
-    GetColor(this, eCSSProperty_text_emphasis_color);
+  nscolor color = aDecorationOverrideColor ? *aDecorationOverrideColor :
+    nsLayoutUtils::GetColor(this, eCSSProperty_text_emphasis_color);
   aContext->SetColor(Color::FromABGR(color));
   gfxPoint pt(aTextBaselinePt);
   if (!aWM.IsVertical()) {
     pt.y += info->baselineOffset;
   } else {
     if (aWM.IsVerticalRL()) {
       pt.x -= info->baselineOffset;
     } else {
@@ -6724,17 +6743,18 @@ nsTextFrame::DrawTextRunAndDecorations(
     }
 
     // CSS 2.1 mandates that text be painted after over/underlines, and *then*
     // line-throughs
     DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider, aTextColor,
                 aAdvanceWidth, aDrawSoftHyphen, aContextPaint, aCallbacks);
 
     // Emphasis marks
-    DrawEmphasisMarks(aCtx, wm, aTextBaselinePt, aOffset, aLength, aProvider);
+    DrawEmphasisMarks(aCtx, wm, aTextBaselinePt, aOffset, aLength,
+                      aDecorationOverrideColor, aProvider);
 
     // Line-throughs
     for (uint32_t i = aDecorations.mStrikes.Length(); i-- > 0; ) {
       const LineDecoration& dec = aDecorations.mStrikes[i];
       if (dec.mStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
         continue;
       }
 
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -441,16 +441,17 @@ public:
                                      SelectionDetails* aDetails,
                                      SelectionType aSelectionType,
                                      DrawPathCallbacks* aCallbacks);
 
   void DrawEmphasisMarks(gfxContext* aContext,
                          mozilla::WritingMode aWM,
                          const gfxPoint& aTextBaselinePt,
                          uint32_t aOffset, uint32_t aLength,
+                         const nscolor* aDecorationOverrideColor,
                          PropertyProvider& aProvider);
 
   virtual nscolor GetCaretColorAt(int32_t aOffset) override;
 
   int16_t GetSelectionStatus(int16_t* aSelectionFlags);
 
   int32_t GetContentOffset() const { return mContentOffset; }
   int32_t GetContentLength() const
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1200611-1-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Reference: Make sure the ImageLayer is sized correctly when using object-fit</title>
+
+<style type="text/css">
+
+.clip {
+  display: inline-block;
+  overflow: hidden;
+}
+
+img {
+  will-change: transform;
+  margin: -64px 0;
+  display: block;
+}
+
+</style>
+
+<span class="clip">
+  <img src="repeatable-diagonal-gradient.png">
+</span>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1200611-1.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Make sure the ImageLayer is sized correctly when using object-fit</title>
+
+<style type="text/css">
+
+img {
+  object-fit: cover;
+  width: 256px;
+  height: 128px;
+  will-change: transform;
+}
+
+</style>
+
+<img src="repeatable-diagonal-gradient.png">
--- a/layout/reftests/w3c-css/submitted/text-decor-3/reftest.list
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/reftest.list
@@ -101,8 +101,17 @@ skip-if(/^Windows\x20NT\x205\.1/.test(ht
 == text-emphasis-position-property-006a.html text-emphasis-position-property-006-ref.html
 == text-emphasis-position-property-006b.html text-emphasis-position-property-006-ref.html
 == text-emphasis-position-property-006c.html text-emphasis-position-property-006-ref.html
 == text-emphasis-position-property-006d.html text-emphasis-position-property-006-ref.html
 == text-emphasis-position-property-006e.html text-emphasis-position-property-006-ref.html
 == text-emphasis-position-property-006f.html text-emphasis-position-property-006-ref.html
 == text-emphasis-position-property-006g.html text-emphasis-position-property-006-ref.html
 # END tests from support/generate-text-emphasis-position-property-tests.py
+
+# START tests from support/generate-text-emphasis-ruby-tests.py
+== text-emphasis-ruby-001.html text-emphasis-ruby-001-ref.html
+== text-emphasis-ruby-002.html text-emphasis-ruby-002-ref.html
+== text-emphasis-ruby-003.html text-emphasis-ruby-003-ref.html
+== text-emphasis-ruby-003a.html text-emphasis-ruby-003-ref.html
+== text-emphasis-ruby-004.html text-emphasis-ruby-004-ref.html
+== text-emphasis-ruby-004a.html text-emphasis-ruby-004-ref.html
+# END tests from support/generate-text-emphasis-ruby-tests.py
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-ruby-tests.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# - * - coding: UTF-8 - * -
+
+"""
+This script generates tests text-emphasis-ruby-001 ~ 004 which tests
+emphasis marks with ruby in four directions. It outputs a list of all
+tests it generated in the format of Mozilla reftest.list to the stdout.
+"""
+
+from __future__ import unicode_literals
+
+TEST_FILE = 'text-emphasis-ruby-{:03}{}.html'
+TEST_TEMPLATE = '''<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test: text-emphasis and ruby, {wm}, {pos}</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-emphasis-position-property">
+<meta name="assert" content="emphasis marks are drawn outside the ruby">
+<link rel="match" href="reference/text-emphasis-ruby-{index:03}-ref.html">
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: {wm}; ruby-position: {ruby_pos}; text-emphasis-position: {posval}">ルビ<span style="text-emphasis: circle">と<ruby>圏<rt>けん</rt>点<rt>てん</rt></ruby>を</span>同時</div>
+'''
+
+REF_FILE = 'text-emphasis-ruby-{:03}-ref.html'
+REF_TEMPLATE = '''<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference: text-emphasis and ruby, {wm}, {pos}</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<style> rtc {{ font-variant-east-asian: inherit; }} </style>
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: {wm}; ruby-position: {posval}">ルビ<ruby>と<rtc>&#x25CF;</rtc>圏<rt>けん</rt><rtc>&#x25CF;</rtc>点<rt>てん</rt><rtc>&#x25CF;</rtc>を<rtc>&#x25CF;</rtc></ruby>同時</div>
+'''
+
+TEST_CASES = [
+        ('top', 'horizontal-tb', 'over', [
+            ('horizontal-tb', 'over right')]),
+        ('bottom', 'horizontal-tb', 'under', [
+            ('horizontal-tb', 'under right')]),
+        ('right', 'vertical-rl', 'over', [
+            ('vertical-rl', 'over right'),
+            ('vertical-lr', 'over right')]),
+        ('left', 'vertical-rl', 'under', [
+            ('vertical-rl', 'over left'),
+            ('vertical-lr', 'over left')]),
+    ]
+
+SUFFIXES = ['', 'a']
+
+def write_file(filename, content):
+    with open(filename, 'wb') as f:
+        f.write(content.encode('UTF-8'))
+
+print("# START tests from {}".format(__file__))
+idx = 0
+for pos, ref_wm, ruby_pos, subtests in TEST_CASES:
+    idx += 1
+    ref_file = REF_FILE.format(idx)
+    ref_content = REF_TEMPLATE.format(pos=pos, wm=ref_wm, posval=ruby_pos)
+    write_file(ref_file, ref_content)
+    suffix = iter(SUFFIXES)
+    for wm, posval in subtests:
+        test_file = TEST_FILE.format(idx, next(suffix))
+        test_content = TEST_TEMPLATE.format(
+            wm=wm, pos=pos, index=idx, ruby_pos=ruby_pos, posval=posval)
+        write_file(test_file, test_content)
+        print("== {} {}".format(test_file, ref_file))
+print("# END tests from {}".format(__file__))
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-emphasis-ruby-001-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference: text-emphasis and ruby, horizontal-tb, top</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<style> rtc { font-variant-east-asian: inherit; } </style>
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: horizontal-tb; ruby-position: over">ルビ<ruby>と<rtc>&#x25CF;</rtc>圏<rt>けん</rt><rtc>&#x25CF;</rtc>点<rt>てん</rt><rtc>&#x25CF;</rtc>を<rtc>&#x25CF;</rtc></ruby>同時</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-emphasis-ruby-001.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test: text-emphasis and ruby, horizontal-tb, top</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-emphasis-position-property">
+<meta name="assert" content="emphasis marks are drawn outside the ruby">
+<link rel="match" href="reference/text-emphasis-ruby-001-ref.html">
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: horizontal-tb; ruby-position: over; text-emphasis-position: over right">ルビ<span style="text-emphasis: circle">と<ruby>圏<rt>けん</rt>点<rt>てん</rt></ruby>を</span>同時</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-emphasis-ruby-002-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference: text-emphasis and ruby, horizontal-tb, bottom</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<style> rtc { font-variant-east-asian: inherit; } </style>
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: horizontal-tb; ruby-position: under">ルビ<ruby>と<rtc>&#x25CF;</rtc>圏<rt>けん</rt><rtc>&#x25CF;</rtc>点<rt>てん</rt><rtc>&#x25CF;</rtc>を<rtc>&#x25CF;</rtc></ruby>同時</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-emphasis-ruby-002.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test: text-emphasis and ruby, horizontal-tb, bottom</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-emphasis-position-property">
+<meta name="assert" content="emphasis marks are drawn outside the ruby">
+<link rel="match" href="reference/text-emphasis-ruby-002-ref.html">
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: horizontal-tb; ruby-position: under; text-emphasis-position: under right">ルビ<span style="text-emphasis: circle">と<ruby>圏<rt>けん</rt>点<rt>てん</rt></ruby>を</span>同時</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-emphasis-ruby-003-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference: text-emphasis and ruby, vertical-rl, right</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<style> rtc { font-variant-east-asian: inherit; } </style>
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: vertical-rl; ruby-position: over">ルビ<ruby>と<rtc>&#x25CF;</rtc>圏<rt>けん</rt><rtc>&#x25CF;</rtc>点<rt>てん</rt><rtc>&#x25CF;</rtc>を<rtc>&#x25CF;</rtc></ruby>同時</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-emphasis-ruby-003.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test: text-emphasis and ruby, vertical-rl, right</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-emphasis-position-property">
+<meta name="assert" content="emphasis marks are drawn outside the ruby">
+<link rel="match" href="reference/text-emphasis-ruby-003-ref.html">
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: vertical-rl; ruby-position: over; text-emphasis-position: over right">ルビ<span style="text-emphasis: circle">と<ruby>圏<rt>けん</rt>点<rt>てん</rt></ruby>を</span>同時</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-emphasis-ruby-003a.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test: text-emphasis and ruby, vertical-lr, right</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-emphasis-position-property">
+<meta name="assert" content="emphasis marks are drawn outside the ruby">
+<link rel="match" href="reference/text-emphasis-ruby-003-ref.html">
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: vertical-lr; ruby-position: over; text-emphasis-position: over right">ルビ<span style="text-emphasis: circle">と<ruby>圏<rt>けん</rt>点<rt>てん</rt></ruby>を</span>同時</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-emphasis-ruby-004-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference: text-emphasis and ruby, vertical-rl, left</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<style> rtc { font-variant-east-asian: inherit; } </style>
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: vertical-rl; ruby-position: under">ルビ<ruby>と<rtc>&#x25CF;</rtc>圏<rt>けん</rt><rtc>&#x25CF;</rtc>点<rt>てん</rt><rtc>&#x25CF;</rtc>を<rtc>&#x25CF;</rtc></ruby>同時</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-emphasis-ruby-004.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test: text-emphasis and ruby, vertical-rl, left</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-emphasis-position-property">
+<meta name="assert" content="emphasis marks are drawn outside the ruby">
+<link rel="match" href="reference/text-emphasis-ruby-004-ref.html">
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: vertical-rl; ruby-position: under; text-emphasis-position: over left">ルビ<span style="text-emphasis: circle">と<ruby>圏<rt>けん</rt>点<rt>てん</rt></ruby>を</span>同時</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/text-emphasis-ruby-004a.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test: text-emphasis and ruby, vertical-lr, left</title>
+<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-emphasis-position-property">
+<meta name="assert" content="emphasis marks are drawn outside the ruby">
+<link rel="match" href="reference/text-emphasis-ruby-004-ref.html">
+<p>Pass if the emphasis marks are outside the ruby:</p>
+<div style="line-height: 5; writing-mode: vertical-lr; ruby-position: under; text-emphasis-position: over left">ルビ<span style="text-emphasis: circle">と<ruby>圏<rt>けん</rt>点<rt>てん</rt></ruby>を</span>同時</div>
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -12,19 +12,20 @@
 #include "nsRuleData.h"
 #include "nsCSSPropertySet.h"
 #include "nsCSSValue.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMMutationObserver.h"
 #include "nsStyleContext.h"
 #include "nsIFrame.h"
 #include "nsLayoutUtils.h"
-#include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
 #include "FrameLayerBuilder.h"
 #include "nsDisplayList.h"
+#include "mozilla/AnimationUtils.h"
+#include "mozilla/EffectSet.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/KeyframeEffect.h"
 #include "RestyleManager.h"
 #include "nsRuleProcessorData.h"
 #include "nsStyleSet.h"
 #include "nsStyleChangeList.h"
 
 using mozilla::dom::Animation;
@@ -61,63 +62,104 @@ void
 CommonAnimationManager::RemoveAllElementCollections()
 {
  while (AnimationCollection* head = mElementCollections.getFirst()) {
    head->Destroy(); // Note: this removes 'head' from mElementCollections.
  }
 }
 
 AnimationCollection*
+CommonAnimationManager::GetAnimationCollection(dom::Element *aElement,
+                                               nsCSSPseudoElements::Type
+                                                 aPseudoType,
+                                               bool aCreateIfNeeded)
+{
+  if (!aCreateIfNeeded && mElementCollections.isEmpty()) {
+    // Early return for the most common case.
+    return nullptr;
+  }
+
+  nsIAtom *propName;
+  if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
+    propName = GetAnimationsAtom();
+  } else if (aPseudoType == nsCSSPseudoElements::ePseudo_before) {
+    propName = GetAnimationsBeforeAtom();
+  } else if (aPseudoType == nsCSSPseudoElements::ePseudo_after) {
+    propName = GetAnimationsAfterAtom();
+  } else {
+    NS_ASSERTION(!aCreateIfNeeded,
+                 "should never try to create transitions for pseudo "
+                 "other than :before or :after");
+    return nullptr;
+  }
+  AnimationCollection* collection =
+    static_cast<AnimationCollection*>(aElement->GetProperty(propName));
+  if (!collection && aCreateIfNeeded) {
+    // FIXME: Consider arena-allocating?
+    collection = new AnimationCollection(aElement, propName, this);
+    nsresult rv =
+      aElement->SetProperty(propName, collection,
+                            &AnimationCollection::PropertyDtor, false);
+    if (NS_FAILED(rv)) {
+      NS_WARNING("SetProperty failed");
+      // The collection must be destroyed via PropertyDtor, otherwise
+      // mCalledPropertyDtor assertion is triggered in destructor.
+      AnimationCollection::PropertyDtor(aElement, propName, collection, nullptr);
+      return nullptr;
+    }
+    if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
+      aElement->SetMayHaveAnimations();
+    }
+
+    AddElementCollection(collection);
+  }
+
+  return collection;
+}
+
+AnimationCollection*
 CommonAnimationManager::GetAnimationCollection(const nsIFrame* aFrame)
 {
   nsIContent* content = aFrame->GetContent();
   if (!content) {
     return nullptr;
   }
-  nsIAtom* animProp;
+
+  nsCSSPseudoElements::Type pseudoType =
+    nsCSSPseudoElements::ePseudo_NotPseudoElement;
+
   if (aFrame->IsGeneratedContentFrame()) {
     nsIFrame* parent = aFrame->GetParent();
     if (parent->IsGeneratedContentFrame()) {
       return nullptr;
     }
     nsIAtom* name = content->NodeInfo()->NameAtom();
     if (name == nsGkAtoms::mozgeneratedcontentbefore) {
-      animProp = GetAnimationsBeforeAtom();
+      pseudoType = nsCSSPseudoElements::ePseudo_before;
     } else if (name == nsGkAtoms::mozgeneratedcontentafter) {
-      animProp = GetAnimationsAfterAtom();
+      pseudoType = nsCSSPseudoElements::ePseudo_after;
     } else {
       return nullptr;
     }
     content = content->GetParent();
     if (!content) {
       return nullptr;
     }
   } else {
     if (!content->MayHaveAnimations()) {
       return nullptr;
     }
-    animProp = GetAnimationsAtom();
   }
 
-  return static_cast<AnimationCollection*>(content->GetProperty(animProp));
-}
-
-AnimationCollection*
-CommonAnimationManager::GetAnimationsForCompositor(const nsIFrame* aFrame,
-                                                   nsCSSProperty aProperty)
-{
-  AnimationCollection* collection = GetAnimationCollection(aFrame);
-  if (!collection ||
-      !collection->HasCurrentAnimationOfProperty(aProperty) ||
-      !collection->CanPerformOnCompositorThread(aFrame)) {
+  if (!content->IsElement()) {
     return nullptr;
   }
 
-  // This animation can be done on the compositor.
-  return collection;
+  return GetAnimationCollection(content->AsElement(), pseudoType,
+                                false /* aCreateIfNeeded */);
 }
 
 nsRestyleHint
 CommonAnimationManager::HasStateDependentStyle(StateRuleProcessorData* aData)
 {
   return nsRestyleHint(0);
 }
 
@@ -244,64 +286,16 @@ CommonAnimationManager::ExtractComputedV
                  StyleAnimationValue::eUnit_Enumerated,
                "unexpected unit");
     aComputedValue.SetIntValue(aComputedValue.GetIntValue(),
                                StyleAnimationValue::eUnit_Visibility);
   }
   return result;
 }
 
-AnimationCollection*
-CommonAnimationManager::GetAnimations(dom::Element *aElement,
-                                      nsCSSPseudoElements::Type aPseudoType,
-                                      bool aCreateIfNeeded)
-{
-  if (!aCreateIfNeeded && mElementCollections.isEmpty()) {
-    // Early return for the most common case.
-    return nullptr;
-  }
-
-  nsIAtom *propName;
-  if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
-    propName = GetAnimationsAtom();
-  } else if (aPseudoType == nsCSSPseudoElements::ePseudo_before) {
-    propName = GetAnimationsBeforeAtom();
-  } else if (aPseudoType == nsCSSPseudoElements::ePseudo_after) {
-    propName = GetAnimationsAfterAtom();
-  } else {
-    NS_ASSERTION(!aCreateIfNeeded,
-                 "should never try to create transitions for pseudo "
-                 "other than :before or :after");
-    return nullptr;
-  }
-  AnimationCollection* collection =
-    static_cast<AnimationCollection*>(aElement->GetProperty(propName));
-  if (!collection && aCreateIfNeeded) {
-    // FIXME: Consider arena-allocating?
-    collection = new AnimationCollection(aElement, propName, this);
-    nsresult rv =
-      aElement->SetProperty(propName, collection,
-                            &AnimationCollection::PropertyDtor, false);
-    if (NS_FAILED(rv)) {
-      NS_WARNING("SetProperty failed");
-      // The collection must be destroyed via PropertyDtor, otherwise
-      // mCalledPropertyDtor assertion is triggered in destructor.
-      AnimationCollection::PropertyDtor(aElement, propName, collection, nullptr);
-      return nullptr;
-    }
-    if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
-      aElement->SetMayHaveAnimations();
-    }
-
-    AddElementCollection(collection);
-  }
-
-  return collection;
-}
-
 void
 CommonAnimationManager::FlushAnimations()
 {
   TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
   for (AnimationCollection* collection = mElementCollections.getFirst();
        collection; collection = collection->getNext()) {
     if (collection->mStyleRuleRefreshTime == now) {
       continue;
@@ -327,17 +321,17 @@ CommonAnimationManager::GetAnimationRule
     "forbidden pseudo type");
 
   if (!mPresContext->IsDynamic()) {
     // For print or print preview, ignore animations.
     return nullptr;
   }
 
   AnimationCollection* collection =
-    GetAnimations(aElement, aPseudoType, false);
+    GetAnimationCollection(aElement, aPseudoType, false /* aCreateIfNeeded */);
   if (!collection) {
     return nullptr;
   }
 
   RestyleManager* restyleManager = mPresContext->RestyleManager();
   if (restyleManager->SkipAnimationRules()) {
     return nullptr;
   }
@@ -347,19 +341,23 @@ CommonAnimationManager::GetAnimationRule
 
   return collection->mStyleRule;
 }
 
 void
 CommonAnimationManager::ClearIsRunningOnCompositor(const nsIFrame* aFrame,
                                                    nsCSSProperty aProperty)
 {
-  AnimationCollection* collection = GetAnimationCollection(aFrame);
-  if (collection) {
-    collection->ClearIsRunningOnCompositor(aProperty);
+  EffectSet* effects = EffectSet::GetEffectSet(aFrame);
+  if (!effects) {
+    return;
+  }
+
+  for (KeyframeEffectReadOnly* effect : *effects) {
+    effect->SetIsRunningOnCompositor(aProperty, false);
   }
 }
 
 NS_IMPL_ISUPPORTS(AnimValuesStyleRule, nsIStyleRule)
 
 /* virtual */ void
 AnimValuesStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
 {
@@ -421,68 +419,16 @@ AnimValuesStyleRule::List(FILE* out, int
     AppendUTF16toUTF8(value, str);
     str.AppendLiteral("; ");
   }
   str.AppendLiteral("}\n");
   fprintf_stderr(out, "%s", str.get());
 }
 #endif
 
-bool
-AnimationCollection::CanPerformOnCompositorThread(const nsIFrame* aFrame) const
-{
-  if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
-    if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
-      nsCString message;
-      message.AppendLiteral("Performance warning: Async animations are disabled");
-      LogAsyncAnimationFailure(message);
-    }
-    return false;
-  }
-
-  if (aFrame->RefusedAsyncAnimation()) {
-    return false;
-  }
-
-  for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
-    const Animation* anim = mAnimations[animIdx];
-    if (!anim->IsPlaying()) {
-      continue;
-    }
-
-    const KeyframeEffectReadOnly* effect = anim->GetEffect();
-    MOZ_ASSERT(effect, "A playing animation should have an effect");
-
-    for (size_t propIdx = 0, propEnd = effect->Properties().Length();
-         propIdx != propEnd; ++propIdx) {
-      const AnimationProperty& prop = effect->Properties()[propIdx];
-      if (!KeyframeEffectReadOnly::CanAnimatePropertyOnCompositor(
-            aFrame,
-            prop.mProperty)) {
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
-bool
-AnimationCollection::HasCurrentAnimationOfProperty(nsCSSProperty
-                                                     aProperty) const
-{
-  for (Animation* animation : mAnimations) {
-    if (animation->HasCurrentEffect() &&
-        animation->GetEffect()->HasAnimationOfProperty(aProperty)) {
-      return true;
-    }
-  }
-  return false;
-}
-
 /*static*/ nsString
 AnimationCollection::PseudoTypeAsString(nsCSSPseudoElements::Type aPseudoType)
 {
   switch (aPseudoType) {
     case nsCSSPseudoElements::ePseudo_before:
       return NS_LITERAL_STRING("::before");
     case nsCSSPseudoElements::ePseudo_after:
       return NS_LITERAL_STRING("::after");
@@ -514,36 +460,16 @@ AnimationCollection::GetElementToRestyle
     return nullptr;
   }
   if (!pseudoFrame) {
     return nullptr;
   }
   return pseudoFrame->GetContent()->AsElement();
 }
 
-/* static */ void
-AnimationCollection::LogAsyncAnimationFailure(nsCString& aMessage,
-                                                     const nsIContent* aContent)
-{
-  if (aContent) {
-    aMessage.AppendLiteral(" [");
-    aMessage.Append(nsAtomCString(aContent->NodeInfo()->NameAtom()));
-
-    nsIAtom* id = aContent->GetID();
-    if (id) {
-      aMessage.AppendLiteral(" with id '");
-      aMessage.Append(nsAtomCString(aContent->GetID()));
-      aMessage.Append('\'');
-    }
-    aMessage.Append(']');
-  }
-  aMessage.Append('\n');
-  printf_stderr("%s", aMessage.get());
-}
-
 /*static*/ void
 AnimationCollection::PropertyDtor(void *aObject, nsIAtom *aPropertyName,
                                   void *aPropertyValue, void *aData)
 {
   AnimationCollection* collection =
     static_cast<AnimationCollection*>(aPropertyValue);
 #ifdef DEBUG
   MOZ_ASSERT(!collection->mCalledPropertyDtor, "can't call dtor twice");
@@ -602,27 +528,16 @@ AnimationCollection::EnsureStyleRuleFor(
   nsCSSPropertySet properties;
 
   for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
     mAnimations[animIdx]->ComposeStyle(mStyleRule, properties, mStyleChanging);
   }
 }
 
 void
-AnimationCollection::ClearIsRunningOnCompositor(nsCSSProperty aProperty)
-{
-  for (Animation* anim : mAnimations) {
-    dom::KeyframeEffectReadOnly* effect = anim->GetEffect();
-    if (effect) {
-      effect->SetIsRunningOnCompositor(aProperty, false);
-    }
-  }
-}
-
-void
 AnimationCollection::RequestRestyle(RestyleType aRestyleType)
 {
   MOZ_ASSERT(IsForElement() || IsForBeforePseudo() || IsForAfterPseudo(),
              "Unexpected mElementProperty; might restyle too much");
 
   nsPresContext* presContext = mManager->PresContext();
   if (!presContext) {
     // Pres context will be null after the manager is disconnected.
@@ -670,46 +585,16 @@ AnimationCollection::UpdateAnimationGene
 void
 AnimationCollection::UpdateCheckGeneration(
   nsPresContext* aPresContext)
 {
   mCheckGeneration =
     aPresContext->RestyleManager()->GetAnimationGeneration();
 }
 
-bool
-AnimationCollection::HasCurrentAnimations() const
-{
-  for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
-    if (mAnimations[animIdx]->HasCurrentEffect()) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-bool
-AnimationCollection::HasCurrentAnimationsForProperties(
-                              const nsCSSProperty* aProperties,
-                              size_t aPropertyCount) const
-{
-  for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
-    const Animation& anim = *mAnimations[animIdx];
-    const KeyframeEffectReadOnly* effect = anim.GetEffect();
-    if (effect &&
-        effect->IsCurrent() &&
-        effect->HasAnimationOfProperties(aProperties, aPropertyCount)) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
 nsPresContext*
 OwningElementRef::GetRenderedPresContext() const
 {
   if (!mElement) {
     return nullptr;
   }
 
   nsIDocument* doc = mElement->GetComposedDoc();
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -68,21 +68,16 @@ public:
    */
   void Disconnect();
 
   // Tell the restyle tracker about all the styles that we're currently
   // animating, so that it can update the animation rule for these
   // elements.
   void AddStyleUpdatesTo(RestyleTracker& aTracker);
 
-  AnimationCollection*
-  GetAnimations(dom::Element *aElement,
-                nsCSSPseudoElements::Type aPseudoType,
-                bool aCreateIfNeeded);
-
   // Returns true if aContent or any of its ancestors has an animation
   // or transition.
   static bool ContentOrAncestorHasAnimation(nsIContent* aContent) {
     do {
       if (aContent->GetProperty(nsGkAtoms::animationsProperty) ||
           aContent->GetProperty(nsGkAtoms::transitionsProperty)) {
         return true;
       }
@@ -98,24 +93,16 @@ public:
   nsIStyleRule* GetAnimationRule(dom::Element* aElement,
                                  nsCSSPseudoElements::Type aPseudoType);
 
   static bool ExtractComputedValueForTransition(
                   nsCSSProperty aProperty,
                   nsStyleContext* aStyleContext,
                   StyleAnimationValue& aComputedValue);
 
-  // For CSS properties that may be animated on a separate layer, represents
-  // a record of the corresponding layer type and change hint.
-  struct LayerAnimationRecord {
-    nsCSSProperty mProperty;
-    nsDisplayItem::Type mLayerType;
-    nsChangeHint mChangeHint;
-  };
-
   virtual bool IsAnimationManager() {
     return false;
   }
 
 protected:
   virtual ~CommonAnimationManager();
 
   void AddElementCollection(AnimationCollection* aCollection);
@@ -123,28 +110,24 @@ protected:
 
   bool NeedsRefresh() const;
 
   virtual nsIAtom* GetAnimationsAtom() = 0;
   virtual nsIAtom* GetAnimationsBeforeAtom() = 0;
   virtual nsIAtom* GetAnimationsAfterAtom() = 0;
 
 public:
-  // Return an AnimationCollection* if we have an animation for
-  // the frame aFrame that can be performed on the compositor thread (as
-  // defined by AnimationCollection::CanPerformOnCompositorThread).
-  //
-  // Note that this does not test whether the frame's layer uses
-  // off-main-thread compositing, although it does check whether
-  // off-main-thread compositing is enabled as a whole.
+  // Get (and optionally create) the collection of animations managed
+  // by this class for the given |aElement| and |aPseudoType|.
   AnimationCollection*
-  GetAnimationsForCompositor(const nsIFrame* aFrame,
-                             nsCSSProperty aProperty);
+  GetAnimationCollection(dom::Element *aElement,
+                         nsCSSPseudoElements::Type aPseudoType,
+                         bool aCreateIfNeeded);
 
-  // Given the frame aFrame with possibly animated content, finds its
+  // Given the frame |aFrame| with possibly animated content, finds its
   // associated collection of animations. If it is a generated content
   // frame, it may examine the parent frame to search for such animations.
   AnimationCollection*
   GetAnimationCollection(const nsIFrame* aFrame);
 
   void ClearIsRunningOnCompositor(const nsIFrame *aFrame,
                                   nsCSSProperty aProperty);
 protected:
@@ -261,17 +244,16 @@ struct AnimationCollection : public Link
     // This is needed in cases such as when an animation becomes paused or has
     // its playback rate changed. In such a case, although the computed style
     // and refresh driver time might not change, we still need to ensure the
     // corresponding animations on layers are updated to reflect the new
     // configuration of the animation.
     Layer
   };
   void RequestRestyle(RestyleType aRestyleType);
-  void ClearIsRunningOnCompositor(nsCSSProperty aProperty);
 
 public:
   // True if this animation can be performed on the compositor thread.
   //
   // Returns whether the state of this element's animations at the current
   // refresh driver time contains animation data that can be done on the
   // compositor thread.  (This is used for determining whether a layer
   // should be active, or whether to send data to the layer.)
@@ -331,19 +313,16 @@ public:
     dom::Element* element = GetElementToRestyle();
     if (element) {
       nsRestyleHint hint = IsForTransitions() ? eRestyle_CSSTransitions
                                               : eRestyle_CSSAnimations;
       aPresContext->PresShell()->RestyleForAnimation(element, hint);
     }
   }
 
-  static void LogAsyncAnimationFailure(nsCString& aMessage,
-                                       const nsIContent* aContent = nullptr);
-
   dom::Element *mElement;
 
   // the atom we use in mElement's prop table (must be a static atom,
   // i.e., in an atom list)
   nsIAtom *mElementProperty;
 
   CommonAnimationManager *mManager;
 
@@ -373,23 +352,16 @@ public:
   // it more than once per style change.  This should be greater than or
   // equal to mAnimationGeneration, except when the generation counter
   // cycles, or when animations are updated through the DOM Animation
   // interfaces.
   uint64_t mCheckGeneration;
   // Update mAnimationGeneration to nsCSSFrameConstructor's count
   void UpdateCheckGeneration(nsPresContext* aPresContext);
 
-  // Returns true if there is an animation that has yet to finish.
-  bool HasCurrentAnimations() const;
-  // Returns true if there is an animation of any of the specified properties
-  // that has yet to finish.
-  bool HasCurrentAnimationsForProperties(const nsCSSProperty* aProperties,
-                                         size_t aPropertyCount) const;
-
   // The refresh time associated with mStyleRule.
   TimeStamp mStyleRuleRefreshTime;
 
   // False when we know that our current style rule is valid
   // indefinitely into the future (because all of our animations are
   // either completed or paused).  May be invalidated by a style change.
   bool mStyleChanging;
 
--- a/layout/style/html.css
+++ b/layout/style/html.css
@@ -813,20 +813,18 @@ rtc, rt {
   line-height: 1;
 %ifndef XP_WIN
   /* The widely-used Windows font Meiryo doesn't work fine with this
    * setting, so disable this on Windows. We should re-enable it once
    * Microsoft fixes this issue. See bug 1164279. */
   font-variant-east-asian: ruby;
 %endif
 }
-@supports (text-emphasis: none) {
-  rtc, rt {
-    text-emphasis: none;
-  }
+rtc, rt {
+  text-emphasis: none;
 }
 rtc:lang(zh), rt:lang(zh) {
   ruby-align: center;
 }
 rtc:lang(zh-TW), rt:lang(zh-TW) {
   font-size: 30%; /* bopomofo */
   -moz-min-font-size-ratio: 30%;
 }
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -398,17 +398,19 @@ nsAnimationManager::CheckAnimationRule(n
 
   // Everything that causes our animation data to change triggers a
   // style change, which in turn triggers a non-animation restyle.
   // Likewise, when we initially construct frames, we're not in a
   // style change, but also not in an animation restyle.
 
   const nsStyleDisplay* disp = aStyleContext->StyleDisplay();
   AnimationCollection* collection =
-    GetAnimations(aElement, aStyleContext->GetPseudoType(), false);
+    GetAnimationCollection(aElement,
+                           aStyleContext->GetPseudoType(),
+                           false /* aCreateIfNeeded */);
   if (!collection &&
       disp->mAnimationNameCount == 1 &&
       disp->mAnimations[0].GetName().IsEmpty()) {
     return nullptr;
   }
 
   nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
 
@@ -531,18 +533,19 @@ nsAnimationManager::CheckAnimationRule(n
         // iterating over the list of old iterations.
         newAnim->CancelFromStyle();
         newAnim = nullptr;
         newAnimations.ReplaceElementAt(newIdx, oldAnim);
         collection->mAnimations.RemoveElementAt(oldIdx);
       }
     }
   } else {
-    collection =
-      GetAnimations(aElement, aStyleContext->GetPseudoType(), true);
+    collection = GetAnimationCollection(aElement,
+                                        aStyleContext->GetPseudoType(),
+                                        true /* aCreateIfNeeded */);
     for (Animation* animation : newAnimations) {
       // FIXME: Bug 1134163 - As above, we have shouldn't actually need to
       // queue events here. (But we do for now since some tests expect
       // animationstart events to be dispatched immediately.)
       animation->AsCSSAnimation()->QueueEvents();
     }
   }
   collection->mAnimations.SwapElements(newAnimations);
@@ -570,17 +573,17 @@ nsAnimationManager::CheckAnimationRule(n
 
 void
 nsAnimationManager::StopAnimationsForElement(
   mozilla::dom::Element* aElement,
   nsCSSPseudoElements::Type aPseudoType)
 {
   MOZ_ASSERT(aElement);
   AnimationCollection* collection =
-    GetAnimations(aElement, aPseudoType, false);
+    GetAnimationCollection(aElement, aPseudoType, false /* aCreateIfNeeded */);
   if (!collection) {
     return;
   }
 
   nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
   collection->Destroy();
 }
 
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -3264,46 +3264,50 @@ CSS_PROP_TEXTRESET(
     VARIANT_HK,
     kTextDecorationStyleKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_Custom)
 CSS_PROP_SHORTHAND(
     text-emphasis,
     text_emphasis,
     TextEmphasis,
-    CSS_PROPERTY_PARSE_FUNCTION,
+    CSS_PROPERTY_PARSE_FUNCTION |
+        CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
     "layout.css.text-emphasis.enabled")
 CSS_PROP_TEXT(
     text-emphasis-color,
     text_emphasis_color,
     TextEmphasisColor,
     CSS_PROPERTY_PARSE_VALUE |
-        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
+        CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED |
+        CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
     "layout.css.text-emphasis.enabled",
     VARIANT_HC,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_Custom)
 CSS_PROP_TEXT(
     text-emphasis-position,
     text_emphasis_position,
     TextEmphasisPosition,
     CSS_PROPERTY_PARSE_VALUE |
-        CSS_PROPERTY_VALUE_PARSER_FUNCTION,
+        CSS_PROPERTY_VALUE_PARSER_FUNCTION |
+        CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
     "layout.css.text-emphasis.enabled",
     0,
     kTextEmphasisPositionKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_TEXT(
     text-emphasis-style,
     text_emphasis_style,
     TextEmphasisStyle,
     CSS_PROPERTY_PARSE_VALUE |
-        CSS_PROPERTY_VALUE_PARSER_FUNCTION,
+        CSS_PROPERTY_VALUE_PARSER_FUNCTION |
+        CSS_PROPERTY_ENABLED_IN_UA_SHEETS,
     "layout.css.text-emphasis.enabled",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_TEXT(
     text-indent,
     text_indent,
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -299,17 +299,18 @@ nsTransitionManager::StyleContextChanged
                   aElement->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter),
                  "Unexpected aElement coming through");
 
     // Else the element we want to use from now on is the element the
     // :before or :after is attached to.
     aElement = aElement->GetParent()->AsElement();
   }
 
-  AnimationCollection* collection = GetAnimations(aElement, pseudoType, false);
+  AnimationCollection* collection =
+    GetAnimationCollection(aElement, pseudoType, false /* aCreateIfNeeded */);
   if (!collection &&
       disp->mTransitionPropertyCount == 1 &&
       disp->mTransitions[0].GetCombinedDuration() <= 0.0f) {
     return;
   }
 
   if (collection &&
       collection->mCheckGeneration ==
@@ -698,17 +699,19 @@ nsTransitionManager::ConsiderStartingTra
   // will add the animation to the PendingAnimationTracker of its effect's
   // document. When we come to make effect writeable (bug 1049975) we should
   // remove this dependency.
   animation->SetEffect(pt);
   animation->PlayFromStyle();
 
   if (!aElementTransitions) {
     aElementTransitions =
-      GetAnimations(aElement, aNewStyleContext->GetPseudoType(), true);
+      GetAnimationCollection(aElement,
+                             aNewStyleContext->GetPseudoType(),
+                             true /* aCreateIfNeeded */);
     if (!aElementTransitions) {
       NS_WARNING("allocating CommonAnimationManager failed");
       return;
     }
   }
 
   AnimationPtrArray& animations = aElementTransitions->mAnimations;
 #ifdef DEBUG
@@ -738,17 +741,18 @@ nsTransitionManager::ConsiderStartingTra
 }
 
 void
 nsTransitionManager::PruneCompletedTransitions(mozilla::dom::Element* aElement,
                                                nsCSSPseudoElements::Type
                                                  aPseudoType,
                                                nsStyleContext* aNewStyleContext)
 {
-  AnimationCollection* collection = GetAnimations(aElement, aPseudoType, false);
+  AnimationCollection* collection =
+    GetAnimationCollection(aElement, aPseudoType, false /* aCreateIfNeeded */);
   if (!collection) {
     return;
   }
 
   // Remove any finished transitions whose style doesn't match the new
   // style.
   // This is similar to some of the work that happens near the end of
   // nsTransitionManager::StyleContextChanged.
@@ -791,42 +795,45 @@ nsTransitionManager::PruneCompletedTrans
   }
 }
 
 void
 nsTransitionManager::UpdateCascadeResultsWithTransitions(
                        AnimationCollection* aTransitions)
 {
   AnimationCollection* animations = mPresContext->AnimationManager()->
-      GetAnimations(aTransitions->mElement,
-                    aTransitions->PseudoElementType(), false);
+      GetAnimationCollection(aTransitions->mElement,
+                             aTransitions->PseudoElementType(),
+                             false /* aCreateIfNeeded */);
   UpdateCascadeResults(aTransitions, animations);
 }
 
 void
 nsTransitionManager::UpdateCascadeResultsWithAnimations(
                        AnimationCollection* aAnimations)
 {
   AnimationCollection* transitions = mPresContext->TransitionManager()->
-      GetAnimations(aAnimations->mElement,
-                    aAnimations->PseudoElementType(), false);
+      GetAnimationCollection(aAnimations->mElement,
+                             aAnimations->PseudoElementType(),
+                             false /* aCreateIfNeeded */);
   UpdateCascadeResults(transitions, aAnimations);
 }
 
 void
 nsTransitionManager::UpdateCascadeResultsWithAnimationsToBeDestroyed(
                        const AnimationCollection* aAnimations)
 {
   // aAnimations is about to be destroyed.  So get transitions from it,
   // but then don't pass it to UpdateCascadeResults, since it has
   // information that may now be incorrect.
   AnimationCollection* transitions =
     mPresContext->TransitionManager()->
-      GetAnimations(aAnimations->mElement,
-                    aAnimations->PseudoElementType(), false);
+      GetAnimationCollection(aAnimations->mElement,
+                             aAnimations->PseudoElementType(),
+                             false /* aCreateIfNeeded */);
   UpdateCascadeResults(transitions, nullptr);
 }
 
 void
 nsTransitionManager::UpdateCascadeResults(AnimationCollection* aTransitions,
                                           AnimationCollection* aAnimations)
 {
   if (!aTransitions) {
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -2,17 +2,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/. */
 
 #ifndef NS_SVGUTILS_H
 #define NS_SVGUTILS_H
 
 // include math.h to pick up definition of M_ maths defines e.g. M_PI
-#define _USE_MATH_DEFINES
 #include <math.h>
 
 #include "DrawMode.h"
 #include "gfx2DGlue.h"
 #include "gfxMatrix.h"
 #include "gfxPoint.h"
 #include "gfxRect.h"
 #include "mozilla/gfx/Rect.h"
@@ -20,17 +19,16 @@
 #include "nsChangeHint.h"
 #include "nsColor.h"
 #include "nsCOMPtr.h"
 #include "nsID.h"
 #include "nsIFrame.h"
 #include "nsISupportsBase.h"
 #include "nsMathUtils.h"
 #include "nsStyleStruct.h"
-#include "mozilla/Constants.h"
 #include <algorithm>
 
 class gfxContext;
 class nsFrameList;
 class nsIContent;
 class nsIDocument;
 class nsIFrame;
 class nsPresContext;
--- a/media/libcubeb/src/moz.build
+++ b/media/libcubeb/src/moz.build
@@ -44,16 +44,17 @@ if CONFIG['OS_TARGET'] == 'Darwin':
 if CONFIG['OS_TARGET'] == 'WINNT':
     SOURCES += [
         'cubeb_resampler.cpp',
         'cubeb_wasapi.cpp',
         'cubeb_winmm.c',
     ]
     DEFINES['USE_WINMM'] = True
     DEFINES['USE_WASAPI'] = True
+    CXXFLAGS += ['-wd4005'] # C4005: '_USE_MATH_DEFINES' : macro redefinition
 
 if CONFIG['OS_TARGET'] == 'Android':
     SOURCES += ['cubeb_opensl.c']
     SOURCES += ['cubeb_resampler.cpp']
     DEFINES['USE_OPENSL'] = True
     if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
         SOURCES += [
             'cubeb_audiotrack.c',
deleted file mode 100644
--- a/mfbt/Constants.h
+++ /dev/null
@@ -1,16 +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/. */
-
-/* mfbt math constants. */
-
-#ifndef mozilla_Constants_h
-#define mozilla_Constants_h
-
-#ifndef M_PI
-#  define M_PI 3.14159265358979323846
-#endif
-
-#endif /* mozilla_Constants_h */
--- a/mfbt/moz.build
+++ b/mfbt/moz.build
@@ -25,17 +25,16 @@ EXPORTS.mozilla = [
     'BinarySearch.h',
     'BloomFilter.h',
     'Casting.h',
     'ChaosMode.h',
     'Char16.h',
     'CheckedInt.h',
     'Compiler.h',
     'Compression.h',
-    'Constants.h',
     'DebugOnly.h',
     'decimal/Decimal.h',
     'double-conversion/double-conversion.h',
     'double-conversion/utils.h',
     'Endian.h',
     'EnumeratedArray.h',
     'EnumeratedRange.h',
     'EnumSet.h',
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -495,16 +495,17 @@ pref("media.mediasource.enabled", true);
 
 pref("media.mediasource.mp4.enabled", true);
 
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
 pref("media.mediasource.webm.enabled", false);
 #else
 pref("media.mediasource.webm.enabled", true);
 #endif
+pref("media.mediasource.webm.audio.enabled", true);
 
 // Enable new MediaFormatReader architecture for plain webm.
 pref("media.format-reader.webm", true);
 
 #ifdef MOZ_WEBSPEECH
 pref("media.webspeech.recognition.enable", false);
 pref("media.webspeech.synth.enabled", false);
 #endif
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -1160,26 +1160,16 @@ nsCacheService::Init()
     mEnableMemoryDevice  = mObserver->MemoryCacheEnabled();
 
     RegisterWeakMemoryReporter(this);
 
     mInitialized = true;
     return NS_OK;
 }
 
-// static
-PLDHashOperator
-nsCacheService::ShutdownCustomCacheDeviceEnum(const nsAString& aProfileDir,
-                                              RefPtr<nsOfflineCacheDevice>& aDevice,
-                                              void* aUserArg)
-{
-    aDevice->Shutdown();
-    return PL_DHASH_REMOVE;
-}
-
 void
 nsCacheService::Shutdown()
 {
     // This method must be called on the main thread because mCacheIOThread must
     // only be modified on the main thread.
     if (!NS_IsMainThread()) {
         NS_RUNTIMEABORT("nsCacheService::Shutdown called off the main thread");
     }
@@ -1235,17 +1225,21 @@ nsCacheService::Shutdown()
         delete mDiskDevice;
         mDiskDevice = nullptr;
 
         if (mOfflineDevice)
             mOfflineDevice->Shutdown();
 
         NS_IF_RELEASE(mOfflineDevice);
 
-        mCustomOfflineDevices.Enumerate(&nsCacheService::ShutdownCustomCacheDeviceEnum, nullptr);
+        for (auto iter = mCustomOfflineDevices.Iter();
+             !iter.Done(); iter.Next()) {
+            iter.Data()->Shutdown();
+            iter.Remove();
+        }
 
         LogCacheStatistics();
 
         mClearingEntries = false;
         mCacheIOThread.swap(cacheIOThread);
     }
 
     if (cacheIOThread)
@@ -2377,18 +2371,21 @@ nsCacheService::OnProfileShutdown()
     if (gService->mDiskDevice && gService->mEnableDiskDevice) {
         gService->mDiskDevice->Shutdown();
     }
     gService->mEnableDiskDevice = false;
 
     if (gService->mOfflineDevice && gService->mEnableOfflineDevice) {
         gService->mOfflineDevice->Shutdown();
     }
-    gService->mCustomOfflineDevices.Enumerate(
-        &nsCacheService::ShutdownCustomCacheDeviceEnum, nullptr);
+    for (auto iter = gService->mCustomOfflineDevices.Iter();
+         !iter.Done(); iter.Next()) {
+        iter.Data()->Shutdown();
+        iter.Remove();
+    }
 
     gService->mEnableOfflineDevice = false;
 
     if (gService->mMemoryDevice) {
         // clear memory cache
         gService->mMemoryDevice->EvictEntries(nullptr);
     }
 
--- a/netwerk/cache/nsCacheService.h
+++ b/netwerk/cache/nsCacheService.h
@@ -306,20 +306,16 @@ private:
 
     nsresult         ProcessPendingRequests(nsCacheEntry * entry);
 
     void             ClearDoomList(void);
     void             DoomActiveEntries(DoomCheckFn check);
     void             CloseAllStreams();
     void             FireClearNetworkCacheStoredAnywhereNotification();
 
-    static
-    PLDHashOperator  ShutdownCustomCacheDeviceEnum(const nsAString& aProfileDir,
-                                                   RefPtr<nsOfflineCacheDevice>& aDevice,
-                                                   void* aUserArg);
     void LogCacheStatistics();
 
     nsresult         SetDiskSmartSize_Locked();
 
     /**
      *  Data Members
      */
 
--- a/netwerk/cache2/CacheFile.cpp
+++ b/netwerk/cache2/CacheFile.cpp
@@ -542,17 +542,35 @@ CacheFile::OnFileOpened(CacheFileHandle 
 
       if (mMetadata) {
         InitIndexEntry();
 
         // The entry was initialized as createNew, don't try to read metadata.
         mMetadata->SetHandle(mHandle);
 
         // Write all cached chunks, otherwise they may stay unwritten.
-        mCachedChunks.Enumerate(&CacheFile::WriteAllCachedChunks, this);
+        for (auto iter = mCachedChunks.Iter(); !iter.Done(); iter.Next()) {
+          uint32_t idx = iter.Key();
+          const RefPtr<CacheFileChunk>& chunk = iter.Data();
+
+          LOG(("CacheFile::OnFileOpened() - write [this=%p, idx=%u, chunk=%p]",
+               this, idx, chunk.get()));
+
+          mChunks.Put(idx, chunk);
+          chunk->mFile = this;
+          chunk->mActiveChunk = true;
+
+          MOZ_ASSERT(chunk->IsReady());
+
+          // This would be cleaner if we had an nsRefPtr constructor that took
+          // a RefPtr<Derived>.
+          ReleaseOutsideLock(RefPtr<nsISupports>(chunk));
+
+          iter.Remove();
+        }
 
         return NS_OK;
       }
     }
   }
 
   if (listener) {
     listener->OnFileReady(retval, isNew);
@@ -859,17 +877,17 @@ CacheFile::ThrowMemoryCachedData()
     LOG(("CacheFile::ThrowMemoryCachedData() - Ignoring request because the "
          "entry is still opening the file [this=%p]", this));
 
     return NS_ERROR_ABORT;
   }
 
   // We cannot release all cached chunks since we need to keep preloaded chunks
   // in memory. See initialization of mPreloadChunkCount for explanation.
-  mCachedChunks.Enumerate(&CacheFile::CleanUpCachedChunks, this);
+  CleanUpCachedChunks();
 
   return NS_OK;
 }
 
 nsresult
 CacheFile::GetElement(const char *aKey, char **_retval)
 {
   CacheFileAutoLock lock(this);
@@ -1564,17 +1582,17 @@ CacheFile::RemoveInput(CacheFileInputStr
 
   ReleaseOutsideLock(already_AddRefed<nsIInputStream>(static_cast<nsIInputStream*>(aInput)));
 
   if (!mMemoryOnly)
     WriteMetadataIfNeededLocked();
 
   // If the input didn't read all data, there might be left some preloaded
   // chunks that won't be used anymore.
-  mCachedChunks.Enumerate(&CacheFile::CleanUpCachedChunks, this);
+  CleanUpCachedChunks();
 
   Telemetry::Accumulate(Telemetry::NETWORK_CACHE_V2_INPUT_STREAM_STATUS,
                         StatusToTelemetryEnum(aStatus));
 
   return NS_OK;
 }
 
 nsresult
@@ -1709,21 +1727,50 @@ CacheFile::HaveChunkListeners(uint32_t a
 void
 CacheFile::NotifyListenersAboutOutputRemoval()
 {
   LOG(("CacheFile::NotifyListenersAboutOutputRemoval() [this=%p]", this));
 
   AssertOwnsLock();
 
   // First fail all chunk listeners that wait for non-existent chunk
-  mChunkListeners.Enumerate(&CacheFile::FailListenersIfNonExistentChunk,
-                            this);
+  for (auto iter = mChunkListeners.Iter(); !iter.Done(); iter.Next()) {
+    uint32_t idx = iter.Key();
+    nsAutoPtr<ChunkListeners>& listeners = iter.Data();
+
+    LOG(("CacheFile::NotifyListenersAboutOutputRemoval() - fail "
+         "[this=%p, idx=%u]", this, idx));
+
+    RefPtr<CacheFileChunk> chunk;
+    mChunks.Get(idx, getter_AddRefs(chunk));
+    if (chunk) {
+      MOZ_ASSERT(!chunk->IsReady());
+      continue;
+    }
+
+    for (uint32_t i = 0 ; i < listeners->mItems.Length() ; i++) {
+      ChunkListenerItem *item = listeners->mItems[i];
+      NotifyChunkListener(item->mCallback, item->mTarget,
+                          NS_ERROR_NOT_AVAILABLE, idx, nullptr);
+      delete item;
+    }
+
+    iter.Remove();
+  }
 
   // Fail all update listeners
-  mChunks.Enumerate(&CacheFile::FailUpdateListeners, this);
+  for (auto iter = mChunks.Iter(); !iter.Done(); iter.Next()) {
+    const RefPtr<CacheFileChunk>& chunk = iter.Data();
+    LOG(("CacheFile::NotifyListenersAboutOutputRemoval() - fail2 "
+         "[this=%p, idx=%u]", this, iter.Key()));
+
+    if (chunk->IsReady()) {
+      chunk->NotifyUpdateListeners();
+    }
+  }
 }
 
 bool
 CacheFile::DataSize(int64_t* aSize)
 {
   CacheFileAutoLock lock(this);
 
   if (mOutput)
@@ -1834,101 +1881,34 @@ CacheFile::PostWriteTimer()
   if (mMemoryOnly)
     return;
 
   LOG(("CacheFile::PostWriteTimer() [this=%p]", this));
 
   CacheFileIOManager::ScheduleMetadataWrite(this);
 }
 
-PLDHashOperator
-CacheFile::WriteAllCachedChunks(const uint32_t& aIdx,
-                                RefPtr<CacheFileChunk>& aChunk,
-                                void* aClosure)
+void
+CacheFile::CleanUpCachedChunks()
 {
-  CacheFile *file = static_cast<CacheFile*>(aClosure);
-
-  LOG(("CacheFile::WriteAllCachedChunks() [this=%p, idx=%u, chunk=%p]",
-       file, aIdx, aChunk.get()));
-
-  file->mChunks.Put(aIdx, aChunk);
-  aChunk->mFile = file;
-  aChunk->mActiveChunk = true;
-
-  MOZ_ASSERT(aChunk->IsReady());
-
-  // this would be cleaner if we had an nsRefPtr constructor
-  // that took a RefPtr<Derived>
-  file->ReleaseOutsideLock(RefPtr<nsISupports>(aChunk));
-
-  return PL_DHASH_REMOVE;
-}
-
-PLDHashOperator
-CacheFile::FailListenersIfNonExistentChunk(
-  const uint32_t& aIdx,
-  nsAutoPtr<ChunkListeners>& aListeners,
-  void* aClosure)
-{
-  CacheFile *file = static_cast<CacheFile*>(aClosure);
-
-  LOG(("CacheFile::FailListenersIfNonExistentChunk() [this=%p, idx=%u]",
-       file, aIdx));
-
-  RefPtr<CacheFileChunk> chunk;
-  file->mChunks.Get(aIdx, getter_AddRefs(chunk));
-  if (chunk) {
-    MOZ_ASSERT(!chunk->IsReady());
-    return PL_DHASH_NEXT;
-  }
+  for (auto iter = mCachedChunks.Iter(); !iter.Done(); iter.Next()) {
+    uint32_t idx = iter.Key();
+    const RefPtr<CacheFileChunk>& chunk = iter.Data();
 
-  for (uint32_t i = 0 ; i < aListeners->mItems.Length() ; i++) {
-    ChunkListenerItem *item = aListeners->mItems[i];
-    file->NotifyChunkListener(item->mCallback, item->mTarget,
-                              NS_ERROR_NOT_AVAILABLE, aIdx, nullptr);
-    delete item;
-  }
-
-  return PL_DHASH_REMOVE;
-}
-
-PLDHashOperator
-CacheFile::FailUpdateListeners(
-  const uint32_t& aIdx,
-  RefPtr<CacheFileChunk>& aChunk,
-  void* aClosure)
-{
-  CacheFile *file = static_cast<CacheFile*>(aClosure);
-  LOG(("CacheFile::FailUpdateListeners() [this=%p, idx=%u]",
-       file, aIdx));
+    LOG(("CacheFile::CleanUpCachedChunks() [this=%p, idx=%u, chunk=%p]", this,
+         idx, chunk.get()));
 
-  if (aChunk->IsReady()) {
-    aChunk->NotifyUpdateListeners();
-  }
-
-  return PL_DHASH_NEXT;
-}
+    if (MustKeepCachedChunk(idx)) {
+      LOG(("CacheFile::CleanUpCachedChunks() - Keeping chunk"));
+      continue;
+    }
 
-PLDHashOperator
-CacheFile::CleanUpCachedChunks(const uint32_t& aIdx,
-                               RefPtr<CacheFileChunk>& aChunk,
-                               void* aClosure)
-{
-  CacheFile *file = static_cast<CacheFile*>(aClosure);
-
-  LOG(("CacheFile::CleanUpCachedChunks() [this=%p, idx=%u, chunk=%p]", file,
-       aIdx, aChunk.get()));
-
-  if (file->MustKeepCachedChunk(aIdx)) {
-    LOG(("CacheFile::CleanUpCachedChunks() - Keeping chunk"));
-    return PL_DHASH_NEXT;
+    LOG(("CacheFile::CleanUpCachedChunks() - Removing chunk"));
+    iter.Remove();
   }
-
-  LOG(("CacheFile::CleanUpCachedChunks() - Removing chunk"));
-  return PL_DHASH_REMOVE;
 }
 
 nsresult
 CacheFile::PadChunkWithZeroes(uint32_t aChunkIdx)
 {
   AssertOwnsLock();
 
   // This method is used to pad last incomplete chunk with zeroes or create
--- a/netwerk/cache2/CacheFile.h
+++ b/netwerk/cache2/CacheFile.h
@@ -164,32 +164,17 @@ private:
   bool     HaveChunkListeners(uint32_t aIndex);
   void     NotifyListenersAboutOutputRemoval();
 
   bool IsDirty();
   void WriteMetadataIfNeeded();
   void WriteMetadataIfNeededLocked(bool aFireAndForget = false);
   void PostWriteTimer();
 
-  static PLDHashOperator WriteAllCachedChunks(const uint32_t& aIdx,
-                                              RefPtr<CacheFileChunk>& aChunk,
-                                              void* aClosure);
-
-  static PLDHashOperator FailListenersIfNonExistentChunk(
-                           const uint32_t& aIdx,
-                           nsAutoPtr<mozilla::net::ChunkListeners>& aListeners,
-                           void* aClosure);
-
-  static PLDHashOperator FailUpdateListeners(const uint32_t& aIdx,
-                                             RefPtr<CacheFileChunk>& aChunk,
-                                             void* aClosure);
-
-  static PLDHashOperator CleanUpCachedChunks(const uint32_t& aIdx,
-                                             RefPtr<CacheFileChunk>& aChunk,
-                                             void* aClosure);
+  void CleanUpCachedChunks();
 
   nsresult PadChunkWithZeroes(uint32_t aChunkIdx);
 
   void SetError(nsresult aStatus);
 
   nsresult InitIndexEntry();
 
   mozilla::Mutex mLock;
--- a/netwerk/cache2/CacheIndex.cpp
+++ b/netwerk/cache2/CacheIndex.cpp
@@ -105,20 +105,19 @@ public:
         mIndex->RemoveRecordFromFrecencyArray(mOldRecord);
         mIndex->InsertRecordToFrecencyArray(entry->mRec);
       }
     } else {
       // both entries were removed or not initialized, do nothing
     }
   }
 
-  // We cannot rely on nsTHashtable::GetEntry() in case we are enumerating the
-  // entries and returning PL_DHASH_REMOVE. Destructor is called before the
-  // entry is removed. Caller must call one of following methods to skip
-  // lookup in the hashtable.
+  // We cannot rely on nsTHashtable::GetEntry() in case we are removing entries
+  // while iterating. Destructor is called before the entry is removed. Caller
+  // must call one of following methods to skip lookup in the hashtable.
   void DoNotSearchInIndex()   { mDoNotSearchInIndex = true; }
   void DoNotSearchInUpdates() { mDoNotSearchInUpdates = true; }
 
 private:
   const CacheIndexEntry * FindEntry()
   {
     const CacheIndexEntry *entry = nullptr;
 
--- a/netwerk/cache2/CacheStorageService.cpp
+++ b/netwerk/cache2/CacheStorageService.cpp
@@ -1129,40 +1129,29 @@ void CacheStorageService::ForceEntryVali
   ForcedValidEntriesPrune(now);
 
   // This will be the timeout
   TimeStamp validUntil = now + TimeDuration::FromSeconds(aSecondsToTheFuture);
 
   mForcedValidEntries.Put(aCacheEntryKey, validUntil);
 }
 
-namespace {
-
-PLDHashOperator PruneForcedValidEntries(
-  const nsACString& aKey, TimeStamp& aTimeStamp, void* aClosure)
-{
-  TimeStamp* now = static_cast<TimeStamp*>(aClosure);
-  if (aTimeStamp < *now) {
-    return PL_DHASH_REMOVE;
-  }
-
-  return PL_DHASH_NEXT;
-}
-
-} // namespace
-
 // Cleans out the old entries in mForcedValidEntries
 void CacheStorageService::ForcedValidEntriesPrune(TimeStamp &now)
 {
   static TimeDuration const oneMinute = TimeDuration::FromSeconds(60);
   static TimeStamp dontPruneUntil = now + oneMinute;
   if (now < dontPruneUntil)
     return;
 
-  mForcedValidEntries.Enumerate(PruneForcedValidEntries, &now);
+  for (auto iter = mForcedValidEntries.Iter(); !iter.Done(); iter.Next()) {
+    if (iter.Data() < now) {
+      iter.Remove();
+    }
+  }
   dontPruneUntil = now + oneMinute;
 }
 
 void
 CacheStorageService::OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer,
                                                uint32_t aCurrentMemoryConsumption)
 {
   LOG(("CacheStorageService::OnMemoryConsumptionChange [consumer=%p, size=%u]",
@@ -1932,42 +1921,34 @@ bool TelemetryEntryKey(CacheEntry const*
     key.Assign(entry->GetStorageID());
     key.Append(':');
     key.Append(entryKey);
   }
 
   return true;
 }
 
-PLDHashOperator PrunePurgeTimeStamps(
-  const nsACString& aKey, TimeStamp& aTimeStamp, void* aClosure)
-{
-  TimeStamp* now = static_cast<TimeStamp*>(aClosure);
-  static TimeDuration const fifteenMinutes = TimeDuration::FromSeconds(900);
-
-  if (*now - aTimeStamp > fifteenMinutes) {
-    // We are not interested in resurrection of entries after 15 minutes
-    // of time.  This is also the limit for the telemetry.
-    return PL_DHASH_REMOVE;
-  }
-
-  return PL_DHASH_NEXT;
-}
-
 } // namespace
 
 void
 CacheStorageService::TelemetryPrune(TimeStamp &now)
 {
   static TimeDuration const oneMinute = TimeDuration::FromSeconds(60);
   static TimeStamp dontPruneUntil = now + oneMinute;
   if (now < dontPruneUntil)
     return;
 
-  mPurgeTimeStamps.Enumerate(PrunePurgeTimeStamps, &now);
+  static TimeDuration const fifteenMinutes = TimeDuration::FromSeconds(900);
+  for (auto iter = mPurgeTimeStamps.Iter(); !iter.Done(); iter.Next()) {
+    if (now - iter.Data() > fifteenMinutes) {
+      // We are not interested in resurrection of entries after 15 minutes
+      // of time.  This is also the limit for the telemetry.
+      iter.Remove();
+    }
+  }
   dontPruneUntil = now + oneMinute;
 }
 
 void
 CacheStorageService::TelemetryRecordEntryCreation(CacheEntry const* entry)
 {
   MOZ_ASSERT(CacheStorageService::IsOnManagementThread());
 
--- a/python/mozbuild/mozbuild/action/test_archive.py
+++ b/python/mozbuild/mozbuild/action/test_archive.py
@@ -91,16 +91,22 @@ ARCHIVE_FILES = {
             'pattern': 'tps/**',
         },
         {
             'source': buildconfig.topsrcdir,
             'base': 'services/sync/tests/tps',
             'pattern': '**',
             'dest': 'tps/tests',
         },
+        {
+            'source': buildconfig.topsrcdir,
+            'base': 'testing/web-platform/tests/tools/wptserve',
+            'pattern': '**',
+            'dest': 'tools/wptserve',
+        },
     ],
     'cppunittest': [
         {
             'source': STAGE,
             'base': '',
             'pattern': 'cppunittest/**',
         },
         # We don't ship these files if startup cache is disabled, which is
--- a/testing/mozharness/configs/merge_day/beta_to_release.py
+++ b/testing/mozharness/configs/merge_day/beta_to_release.py
@@ -1,15 +1,14 @@
 config = {
     "log_name": "beta_to_release",
     "version_files": [
         "browser/config/version.txt",
         "browser/config/version_display.txt",
         "config/milestone.txt",
-        "mobile/android/confvars.sh",  # TODO: remove this line before gecko 43 merge
         "b2g/confvars.sh",
     ],
     "replacements": [
         # File, from, to
         ("{}/{}".format(d, f),
         "ac_add_options --with-branding=mobile/android/branding/beta",
         "ac_add_options --with-branding=mobile/android/branding/official")
         for d in ["mobile/android/config/mozconfigs/android-api-11/",
--- a/testing/mozharness/mozharness/base/script.py
+++ b/testing/mozharness/mozharness/base/script.py
@@ -314,17 +314,19 @@ class ScriptMixin(PlatformMixin):
             None: None may be returned if no handler handles the request.
 
         Raises:
             urllib2.URLError: on errors
 
         .. _urllib2.urlopen:
         https://docs.python.org/2/library/urllib2.html#urllib2.urlopen
         """
-        return urllib2.urlopen(url, **kwargs)
+        # http://bugs.python.org/issue13359 - urllib2 does not automatically quote the URL
+        url_quoted = urllib2.quote(url, safe='%/:=&?~#+!$,;\'@()*[]|')
+        return urllib2.urlopen(url_quoted, **kwargs)
 
     def _download_file(self, url, file_name):
         """ Helper script for download_file()
         Additionaly this function logs all exceptions as warnings before
         re-raising them
 
         Args:
             url (str): string containing the URL with the file location
--- a/testing/web-platform/meta/media-source/mediasource-is-type-supported.html.ini
+++ b/testing/web-platform/meta/media-source/mediasource-is-type-supported.html.ini
@@ -20,27 +20,16 @@
   [Test invalid MIME format "video/webm;codecs=""]
     bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1191833
     expected: FAIL
 
   [Test invalid MIME format "video/webm;codecs="""]
     bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1191833
     expected: FAIL
 
-  [Test valid WebM type "AUDIO/WEBM;CODECS="vorbis""]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1191833
-    expected: FAIL
-
-  [Test invalid mismatch between major type and codec ID "audio/webm;codecs="vp8""]
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1191833
-    expected: FAIL
-
-  [Test valid MP4 type "audio/mp4;codecs="mp4a.67""]
-    expected: FAIL
-
   [Test valid MP4 type "video/mp4;codecs="avc1.4d001e""]
     expected:
       if (os == "win") and (version == "5.1.2600"): FAIL
 
   [Test valid MP4 type "video/mp4;codecs="avc1.42001e""]
     expected:
       if (os == "win") and (version == "5.1.2600"): FAIL
 
--- a/toolkit/components/url-classifier/content/listmanager.js
+++ b/toolkit/components/url-classifier/content/listmanager.js
@@ -10,16 +10,20 @@ Cu.import("resource://gre/modules/Servic
 // phishing or malware protection. The ListManager knows how to fetch,
 // update, and store lists.
 //
 // There is a single listmanager for the whole application.
 //
 // TODO more comprehensive update tests, for example add unittest check 
 //      that the listmanagers tables are properly written on updates
 
+// Lower and upper limits on the server-provided polling frequency
+const minDelayMs = 5 * 60 * 1000;
+const maxDelayMs = 24 * 60 * 60 * 1000;
+
 // Log only if browser.safebrowsing.debug is true
 this.log = function log(...stuff) {
   var prefs_ = new G_Preferences();
   var debug = prefs_.getPref("browser.safebrowsing.debug");
   if (!debug) {
     return;
   }
 
@@ -227,17 +231,17 @@ PROT_ListManager.prototype.kickoffUpdate
           + " provided by " + provider);
 
       // Use the initialUpdateDelay + fuzz unless we had previous updates
       // and the server told us when to try again.
       let updateDelay = initialUpdateDelay;
       let targetPref = "browser.safebrowsing.provider." + provider + ".nextupdatetime";
       let nextUpdate = this.prefs_.getPref(targetPref);
       if (nextUpdate) {
-        updateDelay = Math.max(0, nextUpdate - Date.now());
+        updateDelay = Math.min(maxDelayMs, Math.max(0, nextUpdate - Date.now()));
         log("Next update at " + nextUpdate);
       }
       log("Next update " + updateDelay + "ms from now");
 
       // Set the last update time to verify if data is still valid.
       let freshnessPref = "browser.safebrowsing.provider." + provider + ".lastupdatetime";
       let freshness = this.prefs_.getPref(freshnessPref);
       if (freshness) {
@@ -424,29 +428,33 @@ PROT_ListManager.prototype.makeUpdateReq
  * Callback function if the update request succeeded.
  * @param waitForUpdate String The number of seconds that the client should
  *        wait before requesting again.
  */
 PROT_ListManager.prototype.updateSuccess_ = function(tableList, updateUrl,
                                                      waitForUpdate) {
   log("update success for " + tableList + " from " + updateUrl + ": " +
       waitForUpdate + "\n");
-  var delay;
+  var delay = 0;
   if (waitForUpdate) {
-    delay = parseInt(waitForUpdate, 10);
+    delay = parseInt(waitForUpdate, 10) * 1000;
   }
-  // As long as the delay is something sane (5 minutes or more), update
+  // As long as the delay is something sane (5 min to 1 day), update
   // our delay time for requesting updates. We always use a non-repeating
   // timer since the delay is set differently at every callback.
-  if (delay >= (5 * 60)) {
-    log("Waiting " + delay + " seconds");
-    delay = delay * 1000;
+  if (delay > maxDelayMs) {
+    log("Ignoring delay from server (too long), waiting " +
+        maxDelayMs + "ms");
+    delay = maxDelayMs;
+  } else if (delay < minDelayMs) {
+    log("Ignoring delay from server (too short), waiting " +
+        this.updateInterval + "ms");
+    delay = this.updateInterval;
   } else {
-    log("Ignoring delay from server, waiting " + this.updateInterval / 1000);
-    delay = this.updateInterval;
+    log("Waiting " + delay + "ms");
   }
   this.updateCheckers_[updateUrl] =
     new G_Alarm(BindToObject(this.checkForUpdates, this, updateUrl),
                 delay, false);
 
   // Let the backoff object know that we completed successfully.
   this.requestBackoffs_[updateUrl].noteServerResponse(200);
 
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -1007,17 +1007,19 @@ nsExternalHelperAppService::LoadURI(nsIU
                                     nsIInterfaceRequestor *aWindowContext)
 {
   NS_ENSURE_ARG_POINTER(aURI);
 
   if (XRE_IsContentProcess()) {
     URIParams uri;
     SerializeURI(aURI, uri);
 
-    mozilla::dom::ContentChild::GetSingleton()->SendLoadURIExternal(uri);
+    nsCOMPtr<nsITabChild> tabChild(do_GetInterface(aWindowContext));
+    mozilla::dom::ContentChild::GetSingleton()->
+      SendLoadURIExternal(uri, static_cast<dom::TabChild*>(tabChild.get()));
     return NS_OK;
   }
 
   nsAutoCString spec;
   aURI->GetSpec(spec);
 
   if (spec.Find("%00") != -1)
     return NS_ERROR_MALFORMED_URI;
--- a/uriloader/exthandler/nsWebHandlerApp.js
+++ b/uriloader/exthandler/nsWebHandlerApp.js
@@ -75,16 +75,29 @@ nsWebHandlerApp.prototype = {
     // insert the encoded URI and create the object version 
     var uriSpecToSend = this.uriTemplate.replace("%s", escapedUriSpecToHandle);
     var ioService = Cc["@mozilla.org/network/io-service;1"].
                     getService(Ci.nsIIOService);
     var uriToSend = ioService.newURI(uriSpecToSend, null, null);
     
     // if we have a window context, use the URI loader to load there
     if (aWindowContext) {
+      try {
+        // getInterface throws if the object doesn't implement the given
+        // interface, so this try/catch statement is more of an if.
+        // If aWindowContext refers to a remote docshell, send the load
+        // request to the correct process.
+        aWindowContext.getInterface(Ci.nsIRemoteWindowContext)
+                      .openURI(uriToSend, Ci.nsIURILoader.IS_CONTENT_PREFERRED);
+        return;
+      } catch (e) {
+        if (e.result != Cr.NS_NOINTERFACE) {
+          throw e;
+        }
+      }
 
       // create a channel from this URI
       var channel = ioService.newChannelFromURI2(uriToSend,
                                                  null,      // aLoadingNode
                                                  Services.scriptSecurityManager.getSystemPrincipal(),
                                                  null,      // aTriggeringPrincipal
                                                  Ci.nsILoadInfo.SEC_NORMAL,
                                                  Ci.nsIContentPolicy.TYPE_OTHER);
--- a/view/nsViewManager.cpp
+++ b/view/nsViewManager.cpp
@@ -583,21 +583,21 @@ nsViewManager::InvalidateWidgetArea(nsVi
         // exclude them from the invalidation region IF we're not on
         // Mac. On Mac we need to draw under plugin widgets, because
         // plugin widgets are basically invisible
 #ifndef XP_MACOSX
         // GetBounds should compensate for chrome on a toplevel widget
         LayoutDeviceIntRect bounds;
         childWidget->GetBounds(bounds);
 
-        nsTArray<nsIntRect> clipRects;
+        nsTArray<LayoutDeviceIntRect> clipRects;
         childWidget->GetWindowClipRegion(&clipRects);
         for (uint32_t i = 0; i < clipRects.Length(); ++i) {
-          nsRect rr = ToAppUnits(clipRects[i] + bounds.TopLeft().ToUnknownPoint(),
-                                 AppUnitsPerDevPixel());
+          nsRect rr = LayoutDeviceIntRect::ToAppUnits(
+            clipRects[i] + bounds.TopLeft(), AppUnitsPerDevPixel());
           children.Or(children, rr - aWidgetView->ViewToWidgetOffset());
           children.SimplifyInward(20);
         }
 #endif
       }
     }
   }
 
--- a/widget/PluginWidgetProxy.cpp
+++ b/widget/PluginWidgetProxy.cpp
@@ -104,17 +104,17 @@ PluginWidgetProxy::Destroy()
     mActor->ProxyShutdown();
     mActor = nullptr;
   }
 
   return PuppetWidget::Destroy();
 }
 
 void
-PluginWidgetProxy::GetWindowClipRegion(nsTArray<nsIntRect>* aRects)
+PluginWidgetProxy::GetWindowClipRegion(nsTArray<LayoutDeviceIntRect>* aRects)
 {
   if (mClipRects && mClipRectCount) {
     aRects->AppendElements(mClipRects.get(), mClipRectCount);
   }
 }
 
 void*
 PluginWidgetProxy::GetNativeData(uint32_t aDataType)
--- a/widget/PluginWidgetProxy.h
+++ b/widget/PluginWidgetProxy.h
@@ -43,17 +43,17 @@ public:
 
   virtual nsIWidget* GetParent(void) override;
   virtual void* GetNativeData(uint32_t aDataType) override;
 #if defined(XP_WIN)
   void SetNativeData(uint32_t aDataType, uintptr_t aVal) override;
 #endif
   virtual nsTransparencyMode GetTransparencyMode() override
   { return eTransparencyOpaque; }
-  virtual void GetWindowClipRegion(nsTArray<nsIntRect>* aRects) override;
+  virtual void GetWindowClipRegion(nsTArray<LayoutDeviceIntRect>* aRects) override;
 
 public:
   /**
    * When tabs are closed PPluginWidget can terminate before plugin code is
    * finished tearing us down. When this happens plugin calls over mActor
    * fail triggering an abort in the content process. To protect against this
    * the connection tells us when it is torn down here so we can avoid making
    * calls while content finishes tearing us down.
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -2040,53 +2040,53 @@ gdk_window_flash(GdkWindow *    aGdkWind
   gdk_region_offset(aRegion, -x, -y);
 }
 #endif /* MOZ_X11 */
 #endif // DEBUG
 #endif
 
 #if (MOZ_WIDGET_GTK == 2)
 static bool
-ExtractExposeRegion(nsIntRegion& aRegion, GdkEventExpose* aEvent)
+ExtractExposeRegion(LayoutDeviceIntRegion& aRegion, GdkEventExpose* aEvent)
 {
   GdkRectangle* rects;
   gint nrects;
   gdk_region_get_rectangles(aEvent->region, &rects, &nrects);
 
   if (nrects > MAX_RECTS_IN_REGION) {
       // Just use the bounding box
       rects[0] = aEvent->area;
       nrects = 1;
   }
 
   for (GdkRectangle* r = rects; r < rects + nrects; r++) {
-      aRegion.Or(aRegion, nsIntRect(r->x, r->y, r->width, r->height));
+      aRegion.Or(aRegion, LayoutDeviceIntRect(r->x, r->y, r->width, r->height));
       LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height));
   }
 
   g_free(rects);
   return true;
 }
 
 #else
 # ifdef cairo_copy_clip_rectangle_list
 #  error "Looks like we're including Mozilla's cairo instead of system cairo"
 # endif
 static bool
-ExtractExposeRegion(nsIntRegion& aRegion, cairo_t* cr)
+ExtractExposeRegion(LayoutDeviceIntRegion& aRegion, cairo_t* cr)
 {
   cairo_rectangle_list_t* rects = cairo_copy_clip_rectangle_list(cr);
   if (rects->status != CAIRO_STATUS_SUCCESS) {
       NS_WARNING("Failed to obtain cairo rectangle list.");
       return false;
   }
 
   for (int i = 0; i < rects->num_rectangles; i++)  {
       const cairo_rectangle_t& r = rects->rectangles[i];
-      aRegion.Or(aRegion, nsIntRect(r.x, r.y, r.width, r.height));
+      aRegion.Or(aRegion, LayoutDeviceIntRect(r.x, r.y, r.width, r.height));
       LOGDRAW(("\t%d %d %d %d\n", r.x, r.y, r.width, r.height));
   }
 
   cairo_rectangle_list_destroy(rects);
   return true;
 }
 #endif
 
@@ -2110,39 +2110,39 @@ nsWindow::OnExposeEvent(cairo_t *cr)
     if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
         return FALSE;
 
     nsIWidgetListener *listener =
         mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
     if (!listener)
         return FALSE;
 
-    nsIntRegion exposeRegion;
+    LayoutDeviceIntRegion exposeRegion;
 #if (MOZ_WIDGET_GTK == 2)
     if (!ExtractExposeRegion(exposeRegion, aEvent)) {
 #else
     if (!ExtractExposeRegion(exposeRegion, cr)) {
 #endif
         return FALSE;
     }
 
     gint scale = GdkScaleFactor();
-    nsIntRegion region = exposeRegion;
+    LayoutDeviceIntRegion region = exposeRegion;
     region.ScaleRoundOut(scale, scale);
 
     ClientLayerManager *clientLayers =
         (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT)
         ? static_cast<ClientLayerManager*>(GetLayerManager())
         : nullptr;
 
     if (clientLayers && mCompositorParent) {
         // We need to paint to the screen even if nothing changed, since if we
         // don't have a compositing window manager, our pixels could be stale.
         clientLayers->SetNeedsComposite(true);
-        clientLayers->SendInvalidRegion(region);
+        clientLayers->SendInvalidRegion(region.ToUnknownRegion());
     }
 
     // Dispatch WillPaintWindow notification to allow scripts etc. to run
     // before we paint
     {
         listener->WillPaintWindow(this);
 
         // If the window has been destroyed during the will paint notification,
@@ -2165,17 +2165,17 @@ nsWindow::OnExposeEvent(cairo_t *cr)
 
     LOGDRAW(("sending expose event [%p] %p 0x%lx (rects follow):\n",
              (void *)this, (void *)mGdkWindow,
              gdk_x11_window_get_xid(mGdkWindow)));
 
     // Our bounds may have changed after calling WillPaintWindow.  Clip
     // to the new bounds here.  The region is relative to this
     // window.
-    region.And(region, nsIntRect(0, 0, mBounds.width, mBounds.height));
+    region.And(region, LayoutDeviceIntRect(0, 0, mBounds.width, mBounds.height));
 
     bool shaped = false;
     if (eTransparencyTransparent == GetTransparencyMode()) {
         GdkScreen *screen = gdk_window_get_screen(mGdkWindow);
         if (gdk_screen_is_composited(screen) &&
             gdk_window_get_visual(mGdkWindow) ==
             gdk_screen_get_rgba_visual(screen)) {
             // Remove possible shape mask from when window manger was not
@@ -2189,59 +2189,58 @@ nsWindow::OnExposeEvent(cairo_t *cr)
 
     if (!shaped) {
         GList *children =
             gdk_window_peek_children(mGdkWindow);
         while (children) {
             GdkWindow *gdkWin = GDK_WINDOW(children->data);
             nsWindow *kid = get_window_for_gdk_window(gdkWin);
             if (kid && gdk_window_is_visible(gdkWin)) {
-                nsAutoTArray<nsIntRect,1> clipRects;
+                nsAutoTArray<LayoutDeviceIntRect,1> clipRects;
                 kid->GetWindowClipRegion(&clipRects);
                 LayoutDeviceIntRect bounds;
                 kid->GetBounds(bounds);
                 for (uint32_t i = 0; i < clipRects.Length(); ++i) {
-                    nsIntRect r = clipRects[i] +
-                                  bounds.TopLeft().ToUnknownPoint();
+                    LayoutDeviceIntRect r = clipRects[i] + bounds.TopLeft();
                     region.Sub(region, r);
                 }
             }
             children = children->next;
         }
     }
 
     if (region.IsEmpty()) {
         return TRUE;
     }
 
     // If this widget uses OMTC...
     if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
-        listener->PaintWindow(this, region);
+        listener->PaintWindow(this, region.ToUnknownRegion());
         listener->DidPaintWindow();
         return TRUE;
     }
 
-    RefPtr<DrawTarget> dt = GetDrawTarget(region);
-    if(!dt) {
+    RefPtr<DrawTarget> dt = GetDrawTarget(region.ToUnknownRegion());
+    if (!dt) {
         return FALSE;
     }
     RefPtr<gfxContext> ctx;
 
 #ifdef MOZ_X11
     nsIntRect boundsRect; // for shaped only
 
     if (shaped) {
         // Collapse update area to the bounding box. This is so we only have to
         // call UpdateTranslucentWindowAlpha once. After we have dropped
         // support for non-Thebes graphics, UpdateTranslucentWindowAlpha will be
         // our private interface so we can rework things to avoid this.
-        boundsRect = region.GetBounds();
+        boundsRect = region.GetBounds().ToUnknownRect();
         dt->PushClipRect(Rect(boundsRect));
     } else {
-        gfxUtils::ClipToRegion(dt, region);
+        gfxUtils::ClipToRegion(dt, region.ToUnknownRegion());
     }
 
     BufferMode layerBuffering;
     if (shaped) {
         // The double buffering is done here to extract the shape mask.
         // (The shape mask won't be necessary when a visual with an alpha
         // channel is used on compositing window managers.)
         layerBuffering = BufferMode::BUFFER_NONE;
@@ -2273,17 +2272,17 @@ nsWindow::OnExposeEvent(cairo_t *cr)
 #endif
 
 #endif // MOZ_X11
 
     bool painted = false;
     {
       if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC) {
         AutoLayerManagerSetup setupLayerManager(this, ctx, layerBuffering);
-        painted = listener->PaintWindow(this, region);
+        painted = listener->PaintWindow(this, region.ToUnknownRegion());
       }
     }
 
 #ifdef MOZ_X11
     // PaintWindow can Destroy us (bug 378273), avoid doing any paint
     // operations below if that happened - it will lead to XError and exit().
     if (shaped) {
         if (MOZ_LIKELY(!mIsDestroyed)) {
@@ -2298,17 +2297,17 @@ nsWindow::OnExposeEvent(cairo_t *cr)
         }
     }
 
     ctx = nullptr;
     dt->PopClip();
 
 #  ifdef MOZ_HAVE_SHMIMAGE
     if (mShmImage && MOZ_LIKELY(!mIsDestroyed)) {
-      mShmImage->Put(mXDisplay, mXWindow, region);
+      mShmImage->Put(mXDisplay, mXWindow, region.ToUnknownRegion());
     }
 #  endif  // MOZ_HAVE_SHMIMAGE
 #endif // MOZ_X11
 
     listener->DidPaintWindow();
 
     // Synchronously flush any new dirty areas
 #if (MOZ_WIDGET_GTK == 2)
@@ -4303,29 +4302,29 @@ nsWindow::ConfigureChildren(const nsTArr
             w->Move(configuration.mBounds.x, configuration.mBounds.y);
         }
         w->SetWindowClipRegion(configuration.mClipRegion, false);
     }
     return NS_OK;
 }
 
 nsresult
-nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
+nsWindow::SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects,
                               bool aIntersectWithExisting)
 {
-    const nsTArray<nsIntRect>* newRects = &aRects;
-
-    nsAutoTArray<nsIntRect,1> intersectRects;
+    const nsTArray<LayoutDeviceIntRect>* newRects = &aRects;
+
+    nsAutoTArray<LayoutDeviceIntRect,1> intersectRects;
     if (aIntersectWithExisting) {
-        nsAutoTArray<nsIntRect,1> existingRects;
+        nsAutoTArray<LayoutDeviceIntRect,1> existingRects;
         GetWindowClipRegion(&existingRects);
 
-        nsIntRegion existingRegion = RegionFromArray(existingRects);
-        nsIntRegion newRegion = RegionFromArray(aRects);
-        nsIntRegion intersectRegion;
+        LayoutDeviceIntRegion existingRegion = RegionFromArray(existingRects);
+        LayoutDeviceIntRegion newRegion = RegionFromArray(aRects);
+        LayoutDeviceIntRegion intersectRegion;
         intersectRegion.And(newRegion, existingRegion);
 
         // If mClipRects is null we haven't set a clip rect yet, so we
         // need to set the clip even if it is equal.
         if (mClipRects && intersectRegion.IsEqual(existingRegion)) {
             return NS_OK;
         }
 
@@ -4341,27 +4340,27 @@ nsWindow::SetWindowClipRegion(const nsTA
     StoreWindowClipRegion(*newRects);
 
     if (!mGdkWindow)
         return NS_OK;
 
 #if (MOZ_WIDGET_GTK == 2)
     GdkRegion *region = gdk_region_new(); // aborts on OOM
     for (uint32_t i = 0; i < newRects->Length(); ++i) {
-        const nsIntRect& r = newRects->ElementAt(i);
+        const LayoutDeviceIntRect& r = newRects->ElementAt(i);
         GdkRectangle rect = { r.x, r.y, r.width, r.height };
         gdk_region_union_with_rect(region, &rect);
     }
 
     gdk_window_shape_combine_region(mGdkWindow, region, 0, 0);
     gdk_region_destroy(region);
 #else
     cairo_region_t *region = cairo_region_create();
     for (uint32_t i = 0; i < newRects->Length(); ++i) {
-        const nsIntRect& r = newRects->ElementAt(i);
+        const LayoutDeviceIntRect& r = newRects->ElementAt(i);
         cairo_rectangle_int_t rect = { r.x, r.y, r.width, r.height };
         cairo_region_union_rectangle(region, &rect);
     }
 
     gdk_window_shape_combine_region(mGdkWindow, region, 0, 0);
     cairo_region_destroy(region);
 #endif
 
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -145,17 +145,17 @@ public:
     NS_IMETHOD         SetIcon(const nsAString& aIconSpec) override;
     NS_IMETHOD         SetWindowClass(const nsAString& xulWinType) override;
     virtual LayoutDeviceIntPoint WidgetToScreenOffset() override;
     NS_IMETHOD         EnableDragDrop(bool aEnable) override;
     NS_IMETHOD         CaptureMouse(bool aCapture) override;
     NS_IMETHOD         CaptureRollupEvents(nsIRollupListener *aListener,
                                            bool aDoCapture) override;
     NS_IMETHOD         GetAttention(int32_t aCycleCount) override;
-    virtual nsresult   SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
+    virtual nsresult   SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects,
                                            bool aIntersectWithExisting) override;
     virtual bool       HasPendingInputEvent() override;
 
     virtual bool PrepareForFullscreenTransition(nsISupports** aData) override;
     virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage,
                                              uint16_t aDuration,
                                              nsISupports* aData,
                                              nsIRunnable* aCallback) override;
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -688,81 +688,82 @@ NS_IMETHODIMP nsBaseWidget::SetCursor(im
 void nsBaseWidget::SetTransparencyMode(nsTransparencyMode aMode) {
 }
 
 nsTransparencyMode nsBaseWidget::GetTransparencyMode() {
   return eTransparencyOpaque;
 }
 
 bool
-nsBaseWidget::IsWindowClipRegionEqual(const nsTArray<nsIntRect>& aRects)
+nsBaseWidget::IsWindowClipRegionEqual(const nsTArray<LayoutDeviceIntRect>& aRects)
 {
   return mClipRects &&
          mClipRectCount == aRects.Length() &&
-         memcmp(mClipRects.get(), aRects.Elements(), sizeof(nsIntRect)*mClipRectCount) == 0;
+         memcmp(mClipRects.get(), aRects.Elements(), sizeof(LayoutDeviceIntRect)*mClipRectCount) == 0;
 }
 
 void
-nsBaseWidget::StoreWindowClipRegion(const nsTArray<nsIntRect>& aRects)
+nsBaseWidget::StoreWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects)
 {
   mClipRectCount = aRects.Length();
-  mClipRects = MakeUnique<nsIntRect[]>(mClipRectCount);
+  mClipRects = MakeUnique<LayoutDeviceIntRect[]>(mClipRectCount);
   if (mClipRects) {
-    memcpy(mClipRects.get(), aRects.Elements(), sizeof(nsIntRect)*mClipRectCount);
+    memcpy(mClipRects.get(), aRects.Elements(), sizeof(LayoutDeviceIntRect)*mClipRectCount);
   }
 }
 
 void
-nsBaseWidget::GetWindowClipRegion(nsTArray<nsIntRect>* aRects)
+nsBaseWidget::GetWindowClipRegion(nsTArray<LayoutDeviceIntRect>* aRects)
 {
   if (mClipRects) {
     aRects->AppendElements(mClipRects.get(), mClipRectCount);
   } else {
-    aRects->AppendElement(nsIntRect(0, 0, mBounds.width, mBounds.height));
+    aRects->AppendElement(LayoutDeviceIntRect(0, 0, mBounds.width, mBounds.height));
   }
 }
 
-const nsIntRegion
-nsBaseWidget::RegionFromArray(const nsTArray<nsIntRect>& aRects)
+const LayoutDeviceIntRegion
+nsBaseWidget::RegionFromArray(const nsTArray<LayoutDeviceIntRect>& aRects)
 {
-  nsIntRegion region;
+  LayoutDeviceIntRegion region;
   for (uint32_t i = 0; i < aRects.Length(); ++i) {
     region.Or(region, aRects[i]);
   }
   return region;
 }
 
 void
-nsBaseWidget::ArrayFromRegion(const nsIntRegion& aRegion, nsTArray<nsIntRect>& aRects)
+nsBaseWidget::ArrayFromRegion(const LayoutDeviceIntRegion& aRegion,
+                              nsTArray<LayoutDeviceIntRect>& aRects)
 {
-  const nsIntRect* r;
-  for (nsIntRegionRectIterator iter(aRegion); (r = iter.Next());) {
+  const LayoutDeviceIntRect* r;
+  for (LayoutDeviceIntRegion::RectIterator iter(aRegion); (r = iter.Next()); ) {
     aRects.AppendElement(*r);
   }
 }
 
 nsresult
-nsBaseWidget::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
+nsBaseWidget::SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects,
                                   bool aIntersectWithExisting)
 {
   if (!aIntersectWithExisting) {
     StoreWindowClipRegion(aRects);
   } else {
     // get current rects
-    nsTArray<nsIntRect> currentRects;
+    nsTArray<LayoutDeviceIntRect> currentRects;
     GetWindowClipRegion(&currentRects);
     // create region from them
-    nsIntRegion currentRegion = RegionFromArray(currentRects);
+    LayoutDeviceIntRegion currentRegion = RegionFromArray(currentRects);
     // create region from new rects
-    nsIntRegion newRegion = RegionFromArray(aRects);
+    LayoutDeviceIntRegion newRegion = RegionFromArray(aRects);
     // intersect regions
-    nsIntRegion intersection;
+    LayoutDeviceIntRegion intersection;
     intersection.And(currentRegion, newRegion);
     // create int rect array from intersection
-    nsTArray<nsIntRect> rects;
+    nsTArray<LayoutDeviceIntRect> rects;
     ArrayFromRegion(intersection, rects);
     // store
     StoreWindowClipRegion(rects);
   }
   return NS_OK;
 }
 
 //-------------------------------------------------------------------------
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -134,17 +134,17 @@ public:
 
   virtual nsCursor        GetCursor() override;
   NS_IMETHOD              SetCursor(nsCursor aCursor) override;
   NS_IMETHOD              SetCursor(imgIContainer* aCursor,
                                     uint32_t aHotspotX, uint32_t aHotspotY) override;
   virtual void            ClearCachedCursor() override { mUpdateCursor = true; }
   virtual void            SetTransparencyMode(nsTransparencyMode aMode) override;
   virtual nsTransparencyMode GetTransparencyMode() override;
-  virtual void            GetWindowClipRegion(nsTArray<nsIntRect>* aRects) override;
+  virtual void            GetWindowClipRegion(nsTArray<LayoutDeviceIntRect>* aRects) override;
   NS_IMETHOD              SetWindowShadowStyle(int32_t aStyle) override;
   virtual void            SetShowsToolbarButton(bool aShow) override {}
   virtual void            SetShowsFullScreenButton(bool aShow) override {}
   virtual void            SetWindowAnimationType(WindowAnimationType aType) override {}
   NS_IMETHOD              HideWindowChrome(bool aShouldHide) override;
   virtual bool PrepareForFullscreenTransition(nsISupports** aData) override { return false; }
   virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage,
                                            uint16_t aDuration,
@@ -170,17 +170,17 @@ public:
   virtual void            DrawWindowOverlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) override {}
   virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawing() override;
   virtual void            EndRemoteDrawing() override { };
   virtual void            CleanupRemoteDrawing() override { };
   virtual void            UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override {}
   NS_IMETHOD              SetModal(bool aModal) override;
   virtual uint32_t        GetMaxTouchPoints() const override;
   NS_IMETHOD              SetWindowClass(const nsAString& xulWinType) override;
-  virtual nsresult        SetWindowClipRegion(const nsTArray<nsIntRect>& aRects, bool aIntersectWithExisting) override;
+  virtual nsresult        SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects, bool aIntersectWithExisting) override;
   // Return whether this widget interprets parameters to Move and Resize APIs
   // as "global display pixels" rather than "device pixels", and therefore
   // applies its GetDefaultScale() value to them before using them as mBounds
   // etc (which are always stored in device pixels).
   // Note that APIs that -get- the widget's position/size/bounds, rather than
   // -setting- them (i.e. moving or resizing the widget) will always return
   // values in the widget's device pixels.
   bool                    BoundsUseDisplayPixels() const {
@@ -358,18 +358,19 @@ protected:
   virtual already_AddRefed<GeckoContentController> CreateRootContentController();
 
   // Dispatch an event that has already been routed through APZ.
   nsEventStatus ProcessUntransformedAPZEvent(mozilla::WidgetInputEvent* aEvent,
                                              const ScrollableLayerGuid& aGuid,
                                              uint64_t aInputBlockId,
                                              nsEventStatus aApzResponse);
 
-  const nsIntRegion RegionFromArray(const nsTArray<nsIntRect>& aRects);
-  void ArrayFromRegion(const nsIntRegion& aRegion, nsTArray<nsIntRect>& aRects);
+  const LayoutDeviceIntRegion RegionFromArray(const nsTArray<LayoutDeviceIntRect>& aRects);
+  void ArrayFromRegion(const LayoutDeviceIntRegion& aRegion,
+                       nsTArray<LayoutDeviceIntRect>& aRects);
 
   virtual nsIContent* GetLastRollup() override
   {
     return mLastRollup;
   }
 
   virtual nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout,
                                             int32_t aNativeKeyCode,
@@ -423,20 +424,20 @@ protected:
   }
 
   virtual nsresult NotifyIMEInternal(const IMENotification& aIMENotification)
   { return NS_ERROR_NOT_IMPLEMENTED; }
 
 protected:
   // Utility to check if an array of clip rects is equal to our
   // internally stored clip rect array mClipRects.
-  bool IsWindowClipRegionEqual(const nsTArray<nsIntRect>& aRects);
+  bool IsWindowClipRegionEqual(const nsTArray<LayoutDeviceIntRect>& aRects);
 
   // Stores the clip rectangles in aRects into mClipRects.
-  void StoreWindowClipRegion(const nsTArray<nsIntRect>& aRects);
+  void StoreWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects);
 
   virtual already_AddRefed<nsIWidget>
   AllocateChildPopupWidget()
   {
     static NS_DEFINE_IID(kCPopUpCID, NS_CHILD_CID);
     nsCOMPtr<nsIWidget> widget = do_CreateInstance(kCPopUpCID);
     return widget.forget();
   }
@@ -505,17 +506,17 @@ protected:
   SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback;
   RefPtr<WidgetShutdownObserver> mShutdownObserver;
   RefPtr<TextEventDispatcher> mTextEventDispatcher;
   nsCursor          mCursor;
   nsBorderStyle     mBorderStyle;
   nsIntRect         mBounds;
   CSSIntRect*       mOriginalBounds;
   // When this pointer is null, the widget is not clipped
-  mozilla::UniquePtr<nsIntRect[]> mClipRects;
+  mozilla::UniquePtr<LayoutDeviceIntRect[]> mClipRects;
   uint32_t          mClipRectCount;
   nsSizeMode        mSizeMode;
   nsPopupLevel      mPopupLevel;
   nsPopupType       mPopupType;
   SizeConstraints   mSizeConstraints;
 
   bool              mUpdateCursor;
   bool              mUseAttachedEvents;
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -980,17 +980,17 @@ class nsIWidget : public nsISupports {
      * This represents a command to set the bounds and clip region of
      * a child widget.
      */
     struct Configuration {
         nsCOMPtr<nsIWidget> mChild;
         uintptr_t mWindowID; // e10s specific, the unique plugin port id
         bool mVisible; // e10s specific, widget visibility
         LayoutDeviceIntRect mBounds;
-        nsTArray<nsIntRect> mClipRegion;
+        nsTArray<LayoutDeviceIntRect> mClipRegion;
     };
 
     /**
      * Sets the clip region of each mChild (which must actually be a child
      * of this widget) to the union of the pixel rects given in
      * mClipRegion, all relative to the top-left of the child
      * widget. Clip regions are not implemented on all platforms and only
      * need to actually work for children that are plugins.
@@ -1000,25 +1000,25 @@ class nsIWidget : public nsISupports {
      * This will invalidate areas of the children that have changed, but
      * does not need to invalidate any part of this widget.
      *
      * Children should be moved in the order given; the array is
      * sorted so to minimize unnecessary invalidation if children are
      * moved in that order.
      */
     virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) = 0;
-    virtual nsresult SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
+    virtual nsresult SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects,
                                          bool aIntersectWithExisting) = 0;
 
     /**
      * Appends to aRects the rectangles constituting this widget's clip
      * region. If this widget is not clipped, appends a single rectangle
      * (0, 0, bounds.width, bounds.height).
      */
-    virtual void GetWindowClipRegion(nsTArray<nsIntRect>* aRects) = 0;
+    virtual void GetWindowClipRegion(nsTArray<LayoutDeviceIntRect>* aRects) = 0;
 
     /**
      * Register or unregister native plugin widgets which receive Configuration
      * data from the content process via the compositor.
      *
      * Lookups are used by the main thread via the compositor to lookup widgets
      * based on a unique window id. On Windows and Linux this is the
      * NS_NATIVE_PLUGIN_PORT (hwnd/XID). This tracking maintains a reference to
--- a/widget/windows/nsWinGesture.cpp
+++ b/widget/windows/nsWinGesture.cpp
@@ -7,21 +7,22 @@
  * nsWinGesture - Touch input handling for tablet displays.
  */
 
 #include "nscore.h"
 #include "nsWinGesture.h"
 #include "nsUXThemeData.h"
 #include "nsIDOMSimpleGestureEvent.h"
 #include "nsIDOMWheelEvent.h"
-#include "mozilla/Constants.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TouchEvents.h"
 
+#include <cmath>
+
 using namespace mozilla;
 using namespace mozilla::widget;
 
 extern PRLogModuleInfo* gWindowsLog;
 
 const wchar_t nsWinGesture::kGestureLibraryName[] =  L"user32.dll";
 HMODULE nsWinGesture::sLibraryHandle = nullptr;
 nsWinGesture::GetGestureInfoPtr nsWinGesture::getGestureInfo = nullptr;
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -1420,17 +1420,17 @@ NS_METHOD nsWindow::Move(double aX, doub
 
     UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE;
     // Workaround SetWindowPos bug with D3D9. If our window has a clip
     // region, some drivers or OSes may incorrectly copy into the clipped-out
     // area.
     if (IsPlugin() &&
         (!mLayerManager || mLayerManager->GetBackendType() == LayersBackend::LAYERS_D3D9) &&
         mClipRects &&
-        (mClipRectCount != 1 || !mClipRects[0].IsEqualInterior(nsIntRect(0, 0, mBounds.width, mBounds.height)))) {
+        (mClipRectCount != 1 || !mClipRects[0].IsEqualInterior(LayoutDeviceIntRect(0, 0, mBounds.width, mBounds.height)))) {
       flags |= SWP_NOCOPYBITS;
     }
     VERIFY(::SetWindowPos(mWnd, nullptr, x, y, 0, 0, flags));
 
     SetThemeRegion();
   }
   NotifyRollupGeometryChange();
   return NS_OK;
@@ -6552,38 +6552,38 @@ nsWindow::ConfigureChildren(const nsTArr
     }
     rv = w->SetWindowClipRegion(configuration.mClipRegion, false);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
 static HRGN
-CreateHRGNFromArray(const nsTArray<nsIntRect>& aRects)
+CreateHRGNFromArray(const nsTArray<LayoutDeviceIntRect>& aRects)
 {
   int32_t size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length();
   nsAutoTArray<uint8_t,100> buf;
   buf.SetLength(size);
   RGNDATA* data = reinterpret_cast<RGNDATA*>(buf.Elements());
   RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
   data->rdh.dwSize = sizeof(data->rdh);
   data->rdh.iType = RDH_RECTANGLES;
   data->rdh.nCount = aRects.Length();
-  nsIntRect bounds;
+  LayoutDeviceIntRect bounds;
   for (uint32_t i = 0; i < aRects.Length(); ++i) {
-    const nsIntRect& r = aRects[i];
+    const LayoutDeviceIntRect& r = aRects[i];
     bounds.UnionRect(bounds, r);
     ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost());
   }
   ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost());
   return ::ExtCreateRegion(nullptr, buf.Length(), data);
 }
 
 nsresult
-nsWindow::SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
+nsWindow::SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects,
                               bool aIntersectWithExisting)
 {
   if (IsWindowClipRegionEqual(aRects)) {
     return NS_OK;
   }
 
   nsBaseWidget::SetWindowClipRegion(aRects, aIntersectWithExisting);
 
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -448,17 +448,17 @@ protected:
   static bool             IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult);
   void                    IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam);
 
   /**
    * Misc.
    */
   void                    StopFlashing();
   static bool             IsTopLevelMouseExit(HWND aWnd);
-  virtual nsresult        SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
+  virtual nsresult        SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects,
                                               bool aIntersectWithExisting) override;
   nsIntRegion             GetRegionToPaint(bool aForceFullRepaint, 
                                            PAINTSTRUCT ps, HDC aDC);
   static void             ActivateOtherWindowHelper(HWND aWnd);
   void                    ClearCachedResources();
   nsIWidgetListener*      GetPaintListener();
   static bool             IsRenderMode(gfxWindowsPlatform::RenderMode aMode);
   virtual bool            PreRender(LayerManagerComposite*) override;
--- a/xpcom/ds/nsMathUtils.h
+++ b/xpcom/ds/nsMathUtils.h
@@ -2,18 +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/. */
 
 #ifndef nsMathUtils_h__
 #define nsMathUtils_h__
 
-#define _USE_MATH_DEFINES /* needed for M_ constants on Win32 */
-
 #include "nscore.h"
 #include <cmath>
 #include <float.h>
 
 #ifdef SOLARIS
 #include <ieeefp.h>
 #endif