Merge mozilla-central to autoland
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 02 May 2017 11:23:38 +0200
changeset 404112 b1eaeab8bc35aacda9a61d224c5bfb3e6887e8ef
parent 404111 6b0024a0be7465056df5d7c713c37205af0ab59b (current diff)
parent 404087 48c0fd9c9ec5d68061ea7b59358874ae8da72572 (diff)
child 404113 0cb6f9f404dcda29cfbca9c2414831c9e2f01af6
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland
layout/base/PresShell.cpp
layout/generic/nsSubDocumentFrame.cpp
layout/xul/nsBoxFrame.cpp
layout/xul/nsRootBoxFrame.cpp
layout/xul/nsScrollbarFrame.h
layout/xul/nsXULLabelFrame.h
modules/libpref/init/all.js
toolkit/components/telemetry/Histograms.json
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1476,16 +1476,19 @@ DocAccessible::DoInitialUpdate()
 {
   if (nsCoreUtils::IsTabDocument(mDocumentNode)) {
     mDocFlags |= eTabDocument;
     if (IPCAccessibilityActive()) {
       nsIDocShell* docShell = mDocumentNode->GetDocShell();
       if (RefPtr<dom::TabChild> tabChild = dom::TabChild::GetFrom(docShell)) {
         DocAccessibleChild* ipcDoc = new DocAccessibleChild(this, tabChild);
         SetIPCDoc(ipcDoc);
+        if (IsRoot()) {
+          tabChild->SetTopLevelDocAccessibleChild(ipcDoc);
+        }
 
 #if defined(XP_WIN)
         IAccessibleHolder holder(CreateHolderFromAccessible(this));
         int32_t childID = AccessibleWrap::GetChildIDFor(this);
 #else
         int32_t holder = 0, childID = 0;
 #endif
         tabChild->SendPDocAccessibleConstructor(ipcDoc, nullptr, 0, childID,
--- a/accessible/ipc/win/DocAccessibleChild.cpp
+++ b/accessible/ipc/win/DocAccessibleChild.cpp
@@ -97,28 +97,18 @@ DocAccessibleChild::PushDeferredEvent(Un
   if (mDoc && mDoc->IsRoot()) {
     topLevelIPCDoc = this;
   } else {
     auto tabChild = static_cast<dom::TabChild*>(Manager());
     if (!tabChild) {
       return;
     }
 
-    nsTArray<PDocAccessibleChild*> ipcDocAccs;
-    tabChild->ManagedPDocAccessibleChild(ipcDocAccs);
-
-    // Look for the top-level DocAccessibleChild - there will only be one
-    // per TabChild.
-    for (uint32_t i = 0, l = ipcDocAccs.Length(); i < l; ++i) {
-      auto ipcDocAcc = static_cast<DocAccessibleChild*>(ipcDocAccs[i]);
-      if (ipcDocAcc->mDoc && ipcDocAcc->mDoc->IsRoot()) {
-        topLevelIPCDoc = ipcDocAcc;
-        break;
-      }
-    }
+    topLevelIPCDoc =
+      static_cast<DocAccessibleChild*>(tabChild->GetTopLevelDocAccessibleChild());
   }
 
   if (topLevelIPCDoc) {
     topLevelIPCDoc->mDeferredEvents.AppendElement(Move(aEvent));
   }
 }
 
 bool
--- a/devtools/client/debugger/new/test/mochitest/head.js
+++ b/devtools/client/debugger/new/test/mochitest/head.js
@@ -548,27 +548,37 @@ function togglePauseOnExceptions(
 function invokeInTab(fnc) {
   info(`Invoking function ${fnc} in tab`);
   return ContentTask.spawn(gBrowser.selectedBrowser, fnc, function*(fnc) {
     content.wrappedJSObject[fnc](); // eslint-disable-line mozilla/no-cpows-in-tests, max-len
   });
 }
 
 const isLinux = Services.appinfo.OS === "Linux";
+const isMac = Services.appinfo.OS === "Darwin";
 const cmdOrCtrl = isLinux ? { ctrlKey: true } : { metaKey: true };
+// On Mac, going to beginning/end only works with meta+left/right.  On
+// Windows, it only works with home/end.  On Linux, apparently, either
+// ctrl+left/right or home/end work.
+const endKey = isMac ?
+      { code: "VK_RIGHT", modifiers: cmdOrCtrl } :
+      { code: "VK_END" };
+const startKey = isMac ? 
+      { code: "VK_LEFT", modifiers: cmdOrCtrl } :
+      { code: "VK_HOME" };
 const keyMappings = {
   sourceSearch: { code: "p", modifiers: cmdOrCtrl },
   fileSearch: { code: "f", modifiers: cmdOrCtrl },
   Enter: { code: "VK_RETURN" },
   Up: { code: "VK_UP" },
   Down: { code: "VK_DOWN" },
   Right: { code: "VK_RIGHT" },
   Left: { code: "VK_LEFT" },
-  End: { code: "VK_RIGHT", modifiers: cmdOrCtrl },
-  Start: { code: "VK_LEFT", modifiers: cmdOrCtrl },
+  End: endKey,
+  Start: startKey,
   Tab: { code: "VK_TAB" },
   Escape: { code: "VK_ESCAPE" },
   pauseKey: { code: "VK_F8" },
   resumeKey: { code: "VK_F8" },
   stepOverKey: { code: "VK_F10" },
   stepInKey: { code: "VK_F11", modifiers: { ctrlKey: isLinux } },
   stepOutKey: {
     code: "VK_F11",
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -98,16 +98,17 @@
 #include "nsIWidget.h"
 #include "nsIWidgetListener.h"
 #include "nsIBaseWindow.h"
 #include "nsIDeviceSensors.h"
 #include "nsIContent.h"
 #include "nsIDocShell.h"
 #include "nsIDocCharset.h"
 #include "nsIDocument.h"
+#include "nsIDocumentInlines.h"
 #include "Crypto.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMOfflineResourceList.h"
 #include "nsDOMString.h"
 #include "nsIEmbeddingSiteWindow.h"
 #include "nsThreadUtils.h"
@@ -972,16 +973,17 @@ NextWindowID();
 
 template<class T>
 nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMWindowOuter *aOuterWindow)
 : mFrameElement(nullptr), mDocShell(nullptr), mModalStateDepth(0),
   mMutationBits(0), mIsDocumentLoaded(false),
   mIsHandlingResizeEvent(false), mIsInnerWindow(aOuterWindow != nullptr),
   mMayHavePaintEventListener(false), mMayHaveTouchEventListener(false),
   mMayHaveMouseEnterLeaveEventListener(false),
+  mMayHaveMouseMoveEventListener(false),
   mMayHavePointerEnterLeaveEventListener(false),
   mInnerObjectsFreed(false),
   mIsModalContentWindow(false),
   mIsActive(false), mIsBackground(false),
   mMediaSuspend(Preferences::GetBool("media.block-autoplay-until-in-foreground", true) ?
     nsISuspendedTypes::SUSPENDED_BLOCK : nsISuspendedTypes::NONE_SUSPENDED),
   mAudioMuted(false), mAudioVolume(1.0), mAudioCaptured(false),
   mDesktopModeViewport(false), mIsRootOuterWindow(false), mInnerWindow(nullptr),
@@ -2039,16 +2041,33 @@ nsGlobalWindow::ClearControllers()
   }
 }
 
 void
 nsGlobalWindow::FreeInnerObjects()
 {
   NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
 
+  if (mDoc && !nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) {
+    EventTarget* win = this;
+    EventTarget* html = mDoc->GetHtmlElement();
+    EventTarget* body = mDoc->GetBodyElement();
+
+    bool mouseAware = AsInner()->HasMouseMoveEventListeners();
+    bool keyboardAware = win->MayHaveAPZAwareKeyEventListener() ||
+                         mDoc->MayHaveAPZAwareKeyEventListener() ||
+                         (html && html->MayHaveAPZAwareKeyEventListener()) ||
+                         (body && body->MayHaveAPZAwareKeyEventListener());
+
+    Telemetry::Accumulate(Telemetry::APZ_AWARE_MOUSEMOVE_LISTENERS,
+                          mouseAware ? 1 : 0);
+    Telemetry::Accumulate(Telemetry::APZ_AWARE_KEY_LISTENERS,
+                          keyboardAware ? 1 : 0);
+  }
+
   // Make sure that this is called before we null out the document and
   // other members that the window destroyed observers could
   // re-create.
   NotifyDOMWindowDestroyed(this);
   if (auto* reporter = nsWindowMemoryReporter::Get()) {
     reporter->ObserveDOMWindowDetached(this);
   }
 
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -534,16 +534,19 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
         if (elm) {
           window->SetMutationListeners(elm->MutationListenerBits());
           if (elm->MayHavePaintEventListener()) {
             window->SetHasPaintEventListeners();
           }
           if (elm->MayHaveTouchEventListener()) {
             window->SetHasTouchEventListeners();
           }
+          if (elm->MayHaveMouseMoveEventListener()) {
+            window->SetHasMouseMoveEventListeners();
+          }
           if (elm->MayHaveMouseEnterLeaveEventListener()) {
             window->SetHasMouseEnterLeaveEventListeners();
           }
           if (elm->MayHavePointerEnterLeaveEventListener()) {
             window->SetHasPointerEnterLeaveEventListeners();
           }
         }
       }
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -664,16 +664,17 @@ protected:
   uint32_t               mMutationBits;
 
   bool                   mIsDocumentLoaded;
   bool                   mIsHandlingResizeEvent;
   bool                   mIsInnerWindow;
   bool                   mMayHavePaintEventListener;
   bool                   mMayHaveTouchEventListener;
   bool                   mMayHaveMouseEnterLeaveEventListener;
+  bool                   mMayHaveMouseMoveEventListener;
   bool                   mMayHavePointerEnterLeaveEventListener;
 
   // Used to detect whether we have called FreeInnerObjects() (e.g. to ensure
   // that a call to ResumeTimeouts() after FreeInnerObjects() does nothing).
   // This member is only used by inner windows.
   bool                   mInnerObjectsFreed;
 
 
@@ -811,16 +812,34 @@ public:
       return;
     }
 
     mMutationBits |= aType;
   }
 
   /**
    * Call this to check whether some node (this window, its document,
+   * or content in that document) has or had a mousemove event listener.
+   */
+  bool HasMouseMoveEventListeners()
+  {
+    return mMayHaveMouseMoveEventListener;
+  }
+
+  /**
+   * Call this to indicate that some node (this window, its document,
+   * or content in that document) has or had a mousemove event listener.
+   */
+  void SetHasMouseMoveEventListeners()
+  {
+    mMayHaveMouseMoveEventListener = true;
+  }
+
+  /**
+   * Call this to check whether some node (this window, its document,
    * or content in that document) has a mouseenter/leave event listener.
    */
   bool HasMouseEnterLeaveEventListeners()
   {
     return mMayHaveMouseEnterLeaveEventListener;
   }
 
   /**
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3985,21 +3985,25 @@ class CGUpdateMemberSlotsMethod(CGAbstra
                 # we have hooked it up correctly to the outer window.  The
                 # window code handles doing the get itself.
                 if (self.descriptor.interface.identifier.name == "Window" and
                     (m.identifier.name == "window" or m.identifier.name == "self")):
                     continue
                 body += fill(
                     """
 
+                    static_assert(${slot} < js::shadow::Object::MAX_FIXED_SLOTS,
+                                  "Not enough fixed slots to fit '${interface}.${member}.  Ion's visitGetDOMMemberV/visitGetDOMMemberT assume StoreInSlot things are all in fixed slots.");
                     if (!get_${member}(aCx, aWrapper, aObject, args)) {
                       return false;
                     }
                     // Getter handled setting our reserved slots
                     """,
+                    slot=memberReservedSlot(m, self.descriptor),
+                    interface=self.descriptor.interface.identifier.name,
                     member=m.identifier.name)
 
         body += "\nreturn true;\n"
         return body
 
 
 class CGClearCachedValueMethod(CGAbstractMethod):
     def __init__(self, descriptor, member):
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -122,18 +122,20 @@ IsWebkitPrefixSupportEnabled()
 
 EventListenerManagerBase::EventListenerManagerBase()
   : mNoListenerForEvent(eVoidEvent)
   , mMayHavePaintEventListener(false)
   , mMayHaveMutationListeners(false)
   , mMayHaveCapturingListeners(false)
   , mMayHaveSystemGroupListeners(false)
   , mMayHaveTouchEventListener(false)
+  , mMayHaveMouseMoveEventListener(false)
   , mMayHaveMouseEnterLeaveEventListener(false)
   , mMayHavePointerEnterLeaveEventListener(false)
+  , mMayHaveAPZAwareKeyEventListener(false)
   , mMayHaveKeyEventListener(false)
   , mMayHaveInputOrCompositionEventListener(false)
   , mClearingListeners(false)
   , mIsMainThreadELM(NS_IsMainThread())
 {
   static_assert(sizeof(EventListenerManagerBase) == sizeof(uint32_t),
                 "Keep the size of EventListenerManagerBase size compact!");
 }
@@ -406,23 +408,31 @@ EventListenerManager::AddEventListenerIn
       window->SetHasGamepadEventListener();
     }
   } else if (aTypeAtom == nsGkAtoms::onkeydown ||
              aTypeAtom == nsGkAtoms::onkeypress ||
              aTypeAtom == nsGkAtoms::onkeyup) {
     if (!aFlags.mInSystemGroup) {
       mMayHaveKeyEventListener = true;
     }
+    if (!aFlags.mPassive && aTypeAtom != nsGkAtoms::onkeyup) {
+      mMayHaveAPZAwareKeyEventListener = true;
+    }
   } else if (aTypeAtom == nsGkAtoms::oncompositionend ||
              aTypeAtom == nsGkAtoms::oncompositionstart ||
              aTypeAtom == nsGkAtoms::oncompositionupdate ||
              aTypeAtom == nsGkAtoms::oninput) {
     if (!aFlags.mInSystemGroup) {
       mMayHaveInputOrCompositionEventListener = true;
     }
+  } else if (aTypeAtom == nsGkAtoms::onmousemove) {
+    mMayHaveMouseMoveEventListener = true;
+    if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
+      window->SetHasMouseMoveEventListeners();
+    }
   }
 
   if (IsApzAwareListener(listener)) {
     ProcessApzAwareEventListenerAdd();
   }
 
   if (mTarget) {
     if (aTypeAtom) {
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -156,23 +156,25 @@ protected:
   EventListenerManagerBase();
 
   EventMessage mNoListenerForEvent;
   uint16_t mMayHavePaintEventListener : 1;
   uint16_t mMayHaveMutationListeners : 1;
   uint16_t mMayHaveCapturingListeners : 1;
   uint16_t mMayHaveSystemGroupListeners : 1;
   uint16_t mMayHaveTouchEventListener : 1;
+  uint16_t mMayHaveMouseMoveEventListener : 1;
   uint16_t mMayHaveMouseEnterLeaveEventListener : 1;
   uint16_t mMayHavePointerEnterLeaveEventListener : 1;
+  uint16_t mMayHaveAPZAwareKeyEventListener : 1;
   uint16_t mMayHaveKeyEventListener : 1;
   uint16_t mMayHaveInputOrCompositionEventListener : 1;
   uint16_t mClearingListeners : 1;
   uint16_t mIsMainThreadELM : 1;
-  // uint16_t mUnused : 5;
+  // uint16_t mUnused : 3;
 };
 
 /*
  * Event listener manager
  */
 
 class EventListenerManager final : public EventListenerManagerBase
 {
@@ -434,19 +436,23 @@ public:
   bool MayHavePaintEventListener() { return mMayHavePaintEventListener; }
 
   /**
    * Returns true if there may be a touch event listener registered,
    * false if there definitely isn't.
    */
   bool MayHaveTouchEventListener() { return mMayHaveTouchEventListener; }
 
+  bool MayHaveMouseMoveEventListener() { return mMayHaveMouseMoveEventListener; }
+
   bool MayHaveMouseEnterLeaveEventListener() { return mMayHaveMouseEnterLeaveEventListener; }
   bool MayHavePointerEnterLeaveEventListener() { return mMayHavePointerEnterLeaveEventListener; }
 
+  bool MayHaveAPZAwareKeyEventListener() const { return mMayHaveAPZAwareKeyEventListener; }
+
   /**
    * Returns true if there may be a key event listener (keydown, keypress,
    * or keyup) registered, or false if there definitely isn't.
    */
   bool MayHaveKeyEventListener() { return mMayHaveKeyEventListener; }
 
   /**
    * Returns true if there may be an advanced input event listener (input,
--- a/dom/events/EventTarget.cpp
+++ b/dom/events/EventTarget.cpp
@@ -60,16 +60,23 @@ EventTarget::SetEventHandler(nsIAtom* aT
 bool
 EventTarget::IsApzAware() const
 {
   EventListenerManager* elm = GetExistingListenerManager();
   return elm && elm->HasApzAwareListeners();
 }
 
 bool
+EventTarget::MayHaveAPZAwareKeyEventListener() const
+{
+  EventListenerManager* elm = GetExistingListenerManager();
+  return elm && elm->MayHaveAPZAwareKeyEventListener();
+}
+
+bool
 EventTarget::DispatchEvent(Event& aEvent,
                            CallerType aCallerType,
                            ErrorResult& aRv)
 {
   bool result = false;
   aRv = DispatchEvent(&aEvent, &result);
   return !aEvent.DefaultPrevented(aCallerType);
 }
--- a/dom/events/EventTarget.h
+++ b/dom/events/EventTarget.h
@@ -95,16 +95,17 @@ public:
    * exist.
    */
   virtual EventListenerManager* GetExistingListenerManager() const = 0;
 
   // Called from AsyncEventDispatcher to notify it is running.
   virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) {}
 
   virtual bool IsApzAware() const;
+  bool MayHaveAPZAwareKeyEventListener() const;
 
 protected:
   EventHandlerNonNull* GetEventHandler(nsIAtom* aType,
                                        const nsAString& aTypeString);
   void SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
                        EventHandlerNonNull* aHandler);
 };
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -398,16 +398,19 @@ TabChild::TabChild(nsIContentChild* aMan
   , mDidSetRealShowInfo(false)
   , mDidLoadURLInit(false)
   , mAwaitingLA(false)
   , mSkipKeyPress(false)
   , mLayerObserverEpoch(0)
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
   , mNativeWindowHandle(0)
 #endif
+#if defined(ACCESSIBILITY)
+  , mTopLevelDocAccessibleChild(nullptr)
+#endif
 {
   nsWeakPtr weakPtrThis(do_GetWeakReference(static_cast<nsITabChild*>(this)));  // for capture by the lambda
   mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId,
                                                    const nsTArray<TouchBehaviorFlags>& aFlags)
   {
     if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(weakPtrThis)) {
       static_cast<TabChild*>(tabChild.get())->SetAllowedTouchBehavior(aInputBlockId, aFlags);
     }
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -670,16 +670,28 @@ public:
   // Large-Allocation header.
   bool StopAwaitingLargeAlloc();
   bool IsAwaitingLargeAlloc();
 
   already_AddRefed<nsISHistory> GetRelatedSHistory();
 
   mozilla::dom::TabGroup* TabGroup();
 
+#if defined(ACCESSIBILITY)
+  void SetTopLevelDocAccessibleChild(PDocAccessibleChild* aTopLevelChild)
+  {
+    mTopLevelDocAccessibleChild = aTopLevelChild;
+  }
+
+  PDocAccessibleChild* GetTopLevelDocAccessibleChild()
+  {
+    return mTopLevelDocAccessibleChild;
+  }
+#endif
+
 protected:
   virtual ~TabChild();
 
   virtual PRenderFrameChild* AllocPRenderFrameChild() override;
 
   virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) override;
 
   virtual mozilla::ipc::IPCResult RecvDestroy() override;
@@ -838,15 +850,19 @@ private:
   // The most recently seen layer observer epoch in RecvSetDocShellIsActive.
   uint64_t mLayerObserverEpoch;
 
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
   // The handle associated with the native window that contains this tab
   uintptr_t mNativeWindowHandle;
 #endif // defined(XP_WIN)
 
+#if defined(ACCESSIBILITY)
+  PDocAccessibleChild* mTopLevelDocAccessibleChild;
+#endif
+
   DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_TabChild_h
--- a/gfx/layers/LayerAttributes.h
+++ b/gfx/layers/LayerAttributes.h
@@ -39,23 +39,16 @@ public:
   {
   }
 
   //
   // Setters.
   // All set methods return true if values changed, false otherwise.
   //
 
-  bool SetLayerBounds(const gfx::IntRect& aLayerBounds) {
-    if (mLayerBounds.IsEqualEdges(aLayerBounds)) {
-      return false;
-    }
-    mLayerBounds = aLayerBounds;
-    return true;
-  }
   bool SetPostScale(float aXScale, float aYScale) {
     if (mPostXScale == aXScale && mPostYScale == aYScale) {
       return false;
     }
     mPostXScale = aXScale;
     mPostYScale = aYScale;
     return true;
   }
@@ -190,19 +183,16 @@ public:
     }
     return true;
   }
 
   //
   // Getters.
   //
 
-  const gfx::IntRect& LayerBounds() const {
-    return mLayerBounds;
-  }
   float PostXScale() const {
     return mPostXScale;
   }
   float PostYScale() const {
     return mPostYScale;
   }
   uint32_t ContentFlags() const {
     return mContentFlags;
@@ -260,35 +250,33 @@ public:
   const LayerRect& StickyScrollRangeOuter() const {
     return mStickyPositionData->mOuter;
   }
   const LayerRect& StickyScrollRangeInner() const {
     return mStickyPositionData->mInner;
   }
 
   bool operator ==(const SimpleLayerAttributes& aOther) const {
-    return mLayerBounds == aOther.mLayerBounds &&
-           mTransform == aOther.mTransform &&
+    return mTransform == aOther.mTransform &&
            mTransformIsPerspective == aOther.mTransformIsPerspective &&
            mScrolledClip == aOther.mScrolledClip &&
            mPostXScale == aOther.mPostXScale &&
            mPostYScale == aOther.mPostYScale &&
            mContentFlags == aOther.mContentFlags &&
            mOpacity == aOther.mOpacity &&
            mIsFixedPosition == aOther.mIsFixedPosition &&
            mScrollbarTargetContainerId == aOther.mScrollbarTargetContainerId &&
            mScrollbarDirection == aOther.mScrollbarDirection &&
            mScrollbarThumbRatio == aOther.mScrollbarThumbRatio &&
            mIsScrollbarContainer == aOther.mIsScrollbarContainer &&
            mMixBlendMode == aOther.mMixBlendMode &&
            mForceIsolatedGroup == aOther.mForceIsolatedGroup;
   }
 
 private:
-  gfx::IntRect mLayerBounds;
   gfx::Matrix4x4 mTransform;
   bool mTransformIsPerspective;
   Maybe<LayerClip> mScrolledClip;
   float mPostXScale;
   float mPostYScale;
   uint32_t mContentFlags;
   float mOpacity;
   bool mIsFixedPosition;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -571,18 +571,17 @@ Layer::CalculateScissorRect(const Render
   } else {
     currentClip = aCurrentScissorRect;
   }
 
   if (!clipLayer->GetLocalClipRect()) {
     return currentClip;
   }
 
-  if (GetLocalVisibleRegion().IsEmpty() &&
-      !(AsHostLayer() && AsHostLayer()->NeedToDrawCheckerboarding())) {
+  if (GetLocalVisibleRegion().IsEmpty()) {
     // When our visible region is empty, our parent may not have created the
     // intermediate surface that we would require for correct clipping; however,
     // this does not matter since we are invisible.
     // Make sure we still compute a clip rect if we want to draw checkboarding
     // for this layer, since we want to do this even if the layer is invisible.
     return RenderTargetIntRect(currentClip.TopLeft(), RenderTargetIntSize(0, 0));
   }
 
@@ -1845,19 +1844,16 @@ Layer::PrintInfo(std::stringstream& aStr
     AppendToString(aStream, GetBaseTransform(), " [transform=", "]");
   }
   if (!GetEffectiveTransform().IsIdentity()) {
     AppendToString(aStream, GetEffectiveTransform(), " [effective-transform=", "]");
   }
   if (GetTransformIsPerspective()) {
     aStream << " [perspective]";
   }
-  if (!GetLayerBounds().IsEmpty()) {
-    AppendToString(aStream, GetLayerBounds(), " [bounds=", "]");
-  }
   if (!mVisibleRegion.IsEmpty()) {
     AppendToString(aStream, mVisibleRegion.ToUnknownRegion(), " [visible=", "]");
   } else {
     aStream << " [not visible]";
   }
   if (!mEventRegions.IsEmpty()) {
     AppendToString(aStream, mEventRegions, " ", "");
   }
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -895,32 +895,16 @@ public:
     if (mSimpleAttrs.SetContentFlags(aFlags)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ContentFlags", this));
       MutatedSimple();
     }
   }
 
   /**
    * CONSTRUCTION PHASE ONLY
-   * The union of the bounds of all the display item that got flattened
-   * into this layer. This is intended to be an approximation to the
-   * size of the layer if the nearest scrollable ancestor had an infinitely
-   * large displayport. Computing this more exactly is too expensive,
-   * but this approximation is sufficient for what we need to use it for.
-   */
-  virtual void SetLayerBounds(const gfx::IntRect& aLayerBounds)
-  {
-    if (mSimpleAttrs.SetLayerBounds(aLayerBounds)) {
-      MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) LayerBounds", this));
-      MutatedSimple();
-    }
-  }
-
-  /**
-   * CONSTRUCTION PHASE ONLY
    * Tell this layer which region will be visible. The visible region
    * is a region which contains all the contents of the layer that can
    * actually affect the rendering of the window. It can exclude areas
    * that are covered by opaque contents of other layers, and it can
    * exclude areas where this layer simply contains no content at all.
    * (This can be an overapproximation to the "true" visible region.)
    *
    * There is no general guarantee that drawing outside the bounds of the
@@ -1335,17 +1319,16 @@ public:
 
   // These getters can be used anytime.
   float GetOpacity() { return mSimpleAttrs.Opacity(); }
   gfx::CompositionOp GetMixBlendMode() const { return mSimpleAttrs.MixBlendMode(); }
   const Maybe<ParentLayerIntRect>& GetClipRect() const { return mClipRect; }
   const Maybe<LayerClip>& GetScrolledClip() const { return mSimpleAttrs.ScrolledClip(); }
   Maybe<ParentLayerIntRect> GetScrolledClipRect() const;
   uint32_t GetContentFlags() { return mSimpleAttrs.ContentFlags(); }
-  const gfx::IntRect& GetLayerBounds() const { return mSimpleAttrs.LayerBounds(); }
   const LayerIntRegion& GetVisibleRegion() const { return mVisibleRegion; }
   const ScrollMetadata& GetScrollMetadata(uint32_t aIndex) const;
   const FrameMetrics& GetFrameMetrics(uint32_t aIndex) const;
   uint32_t GetScrollMetadataCount() const { return mScrollMetadata.Length(); }
   const nsTArray<ScrollMetadata>& GetAllScrollMetadata() { return mScrollMetadata; }
   bool HasScrollableFrameMetrics() const;
   bool IsScrollInfoLayer() const;
   const EventRegions& GetEventRegions() const { return mEventRegions; }
--- a/gfx/layers/client/ClientTiledPaintedLayer.cpp
+++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp
@@ -164,17 +164,17 @@ ClientTiledPaintedLayer::BeginPaint()
   const FrameMetrics& scrollMetrics = scrollAncestor.Metrics();
   const FrameMetrics& displayportMetrics = displayPortAncestor.Metrics();
 
   // Calculate the transform required to convert ParentLayer space of our
   // display port ancestor to the Layer space of this layer.
   ParentLayerToLayerMatrix4x4 transformDisplayPortToLayer =
     GetTransformToAncestorsParentLayer(this, displayPortAncestor).Inverse();
 
-  LayerRect layerBounds = ViewAs<LayerPixel>(Rect(GetLayerBounds()));
+  LayerRect layerBounds(GetVisibleRegion().GetBounds());
 
   // Compute the critical display port that applies to this layer in the
   // LayoutDevice space of this layer, but only if there is no OMT animation
   // on this layer. If there is an OMT animation then we need to draw the whole
   // visible region of this layer as determined by layout, because we don't know
   // what parts of it might move into view in the compositor.
   mPaintData.mHasTransformAnimation = hasTransformAnimation;
   if (!mPaintData.mHasTransformAnimation &&
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -1213,17 +1213,17 @@ ClientMultiTiledLayerBuffer::ComputeProg
       return aIsRepeated;
     }
   }
 
   Maybe<LayerRect> transformedCompositionBounds =
     GetCompositorSideCompositionBounds(scrollAncestor,
                                        aPaintData->mTransformToCompBounds,
                                        viewTransform,
-                                       ViewAs<LayerPixel>(Rect(mPaintedLayer.GetLayerBounds())));
+                                       LayerRect(mPaintedLayer.GetVisibleRegion().GetBounds()));
 
   if (!transformedCompositionBounds) {
     aPaintData->mPaintFinished = true;
     return false;
   }
 
   TILING_LOG("TILING %p: Progressive update transformed compositor bounds %s\n", &mPaintedLayer, Stringify(*transformedCompositionBounds).c_str());
 
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -207,18 +207,17 @@ ContainerPrepare(ContainerT* aContainer,
 
     if (layerToRender->GetLayer()->IsBackfaceHidden()) {
       continue;
     }
 
     // We don't want to skip container layers because otherwise their mPrepared
     // may be null which is not allowed.
     if (!layerToRender->GetLayer()->AsContainerLayer()) {
-      if (!layerToRender->GetLayer()->IsVisible() &&
-          !layerToRender->NeedToDrawCheckerboarding(nullptr)) {
+      if (!layerToRender->GetLayer()->IsVisible()) {
         CULLING_LOG("Sublayer %p has no effective visible region\n", layerToRender->GetLayer());
         continue;
       }
 
       if (clipRect.IsEmpty()) {
         CULLING_LOG("Sublayer %p has an empty world clip rect\n", layerToRender->GetLayer());
         continue;
       }
@@ -418,34 +417,16 @@ RenderLayers(ContainerT* aContainer, Lay
       for (const auto& metadata : layer->GetAllScrollMetadata()) {
         if (metadata.IsApzForceDisabled()) {
           aManager->DisabledApzWarning();
           break;
         }
       }
     }
 
-    Color color;
-    if (layerToRender->NeedToDrawCheckerboarding(&color)) {
-      if (gfxPrefs::APZHighlightCheckerboardedAreas()) {
-        color = Color(255 / 255.f, 188 / 255.f, 217 / 255.f, 1.f); // "Cotton Candy"
-      }
-      // Ideally we would want to intersect the checkerboard region from the APZ with the layer bounds
-      // and only fill in that area. However the layer bounds takes into account the base translation
-      // for the painted layer whereas the checkerboard region does not. One does not simply
-      // intersect areas in different coordinate spaces. So we do this a little more permissively
-      // and only fill in the background when we know there is checkerboard, which in theory
-      // should only occur transiently.
-      EffectChain effectChain(layer);
-      effectChain.mPrimaryEffect = new EffectSolidColor(color);
-      aManager->GetCompositor()->DrawGeometry(gfx::Rect(layer->GetLayerBounds()), clipRect,
-                                              effectChain, layer->GetEffectiveOpacity(),
-                                              layer->GetEffectiveTransform(), Nothing());
-    }
-
     if (layerToRender->HasLayerBeenComposited()) {
       // Composer2D will compose this layer so skip GPU composition
       // this time. The flag will be reset for the next composition phase
       // at the beginning of LayerManagerComposite::Rener().
       gfx::IntRect clearRect = layerToRender->GetClearRect();
       if (!clearRect.IsEmpty()) {
         // Clear layer's visible rect on FrameBuffer with transparent pixels
         gfx::Rect fbRect(clearRect.x, clearRect.y, clearRect.width, clearRect.height);
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -1496,45 +1496,16 @@ HostLayer::GetShadowTransform() {
 }
 
 bool
 LayerComposite::HasStaleCompositor() const
 {
   return mCompositeManager->GetCompositor() != mCompositor;
 }
 
-static bool
-LayerHasCheckerboardingAPZC(Layer* aLayer, Color* aOutColor)
-{
-  bool answer = false;
-  for (LayerMetricsWrapper i(aLayer, LayerMetricsWrapper::StartAt::BOTTOM); i; i = i.GetParent()) {
-    if (!i.Metrics().IsScrollable()) {
-      continue;
-    }
-    if (i.GetApzc() && i.GetApzc()->IsCurrentlyCheckerboarding()) {
-      if (aOutColor) {
-        *aOutColor = i.Metadata().GetBackgroundColor();
-      }
-      answer = true;
-      break;
-    }
-    break;
-  }
-  return answer;
-}
-
-bool
-LayerComposite::NeedToDrawCheckerboarding(gfx::Color* aOutCheckerboardingColor)
-{
-  return GetLayer()->Manager()->AsyncPanZoomEnabled() &&
-         (GetLayer()->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
-         GetLayer()->IsOpaqueForVisibility() &&
-         LayerHasCheckerboardingAPZC(GetLayer(), aOutCheckerboardingColor);
-}
-
 #ifndef MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
 
 /*static*/ bool
 LayerManagerComposite::SupportsDirectTexturing()
 {
   return false;
 }
 
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -584,22 +584,16 @@ public:
   float GetShadowOpacity() { return mShadowOpacity; }
   const Maybe<ParentLayerIntRect>& GetShadowClipRect() { return mShadowClipRect; }
   const LayerIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
   const gfx::Matrix4x4& GetShadowBaseTransform() { return mShadowTransform; }
   gfx::Matrix4x4 GetShadowTransform();
   bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
   bool GetShadowOpacitySetByAnimation() { return mShadowOpacitySetByAnimation; }
 
-  /**
-   * Return true if a checkerboarding background color needs to be drawn
-   * for this layer.
-   */
-  virtual bool NeedToDrawCheckerboarding(gfx::Color* aOutCheckerboardingColor = nullptr) { return false; }
-
 protected:
   HostLayerManager* mCompositorManager;
 
   gfx::Matrix4x4 mShadowTransform;
   LayerIntRegion mShadowVisibleRegion;
   Maybe<ParentLayerIntRect> mShadowClipRect;
   float mShadowOpacity;
   bool mShadowTransformSetByAnimation;
@@ -689,18 +683,16 @@ public:
 
   /**
    * Return the part of the visible region that has been fully rendered.
    * While progressive drawing is in progress this region will be
    * a subset of the shadow visible region.
    */
   virtual nsIntRegion GetFullyRenderedRegion();
 
-  virtual bool NeedToDrawCheckerboarding(gfx::Color* aOutCheckerboardingColor = nullptr);
-
 protected:
   LayerManagerComposite* mCompositeManager;
 
   RefPtr<Compositor> mCompositor;
   bool mDestroyed;
   bool mLayerComposited;
   gfx::IntRect mClearRect;
 };
--- a/js/src/gc/ZoneGroup.cpp
+++ b/js/src/gc/ZoneGroup.cpp
@@ -52,22 +52,27 @@ ZoneGroup::~ZoneGroup()
 
     js_delete(jitZoneGroup.ref());
 
     if (this == runtime->gc.systemZoneGroup)
         runtime->gc.systemZoneGroup = nullptr;
 }
 
 void
-ZoneGroup::enter()
+ZoneGroup::enter(JSContext* cx)
 {
-    JSContext* cx = TlsContext.get();
     if (ownerContext().context() == cx) {
         MOZ_ASSERT(enterCount);
     } else {
+        if (useExclusiveLocking) {
+            MOZ_ASSERT(!usedByHelperThread);
+            while (ownerContext().context() != nullptr) {
+                cx->yieldToEmbedding();
+            }
+        }
         MOZ_RELEASE_ASSERT(ownerContext().context() == nullptr);
         MOZ_ASSERT(enterCount == 0);
         ownerContext_ = CooperatingContext(cx);
         if (cx->generationalDisabled)
             nursery().disable();
 
         // Finish any Ion compilations in this zone group, in case compilation
         // finished for some script in this group while no thread was in this
--- a/js/src/gc/ZoneGroup.h
+++ b/js/src/gc/ZoneGroup.h
@@ -36,21 +36,25 @@ class ZoneGroup
 
   private:
     // The context with exclusive access to this zone group.
     UnprotectedData<CooperatingContext> ownerContext_;
 
     // The number of times the context has entered this zone group.
     UnprotectedData<size_t> enterCount;
 
+    // If this flag is true, then we may need to block before entering this zone
+    // group. Blocking happens using JSContext::yieldToEmbedding.
+    UnprotectedData<bool> useExclusiveLocking;
+
   public:
     CooperatingContext& ownerContext() { return ownerContext_.ref(); }
     void* addressOfOwnerContext() { return &ownerContext_.ref().cx; }
 
-    void enter();
+    void enter(JSContext* cx);
     void leave();
     bool ownedByCurrentThread();
 
     // All zones in the group.
   private:
     ZoneGroupOrGCTaskData<ZoneVector> zones_;
   public:
     ZoneVector& zones() { return zones_.ref(); }
@@ -67,16 +71,19 @@ class ZoneGroup
     inline gc::StoreBuffer& storeBuffer();
 
     // Queue a thunk to run after the next minor GC.
     inline void callAfterMinorGC(void (*thunk)(void* data), void* data);
 
     inline bool isCollecting();
     inline bool isGCScheduled();
 
+    // See the useExclusiveLocking field above.
+    void setUseExclusiveLocking() { useExclusiveLocking = true; }
+
 #ifdef DEBUG
   private:
     // The number of possible bailing places encounters before forcefully bailing
     // in that place. Zero means inactive.
     ZoneGroupData<uint32_t> ionBailAfter_;
 
   public:
     void* addressOfIonBailAfter() { return &ionBailAfter_; }
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -196,20 +196,24 @@ struct JSContext : public JS::RootingCon
     }
 #ifdef DEBUG
     unsigned getEnterCompartmentDepth() const {
         return enterCompartmentDepth_;
     }
 #endif
 
   private:
-    // If |c| or |oldCompartment| is the atoms compartment, the
-    // |exclusiveAccessLock| must be held.
-    inline void enterCompartment(JSCompartment* c,
-                                 const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
+    // We distinguish between entering the atoms compartment and all other
+    // compartments. Entering the atoms compartment requires a lock. Also, we
+    // don't call enterZoneGroup when entering the atoms compartment since that
+    // can induce GC hazards.
+    inline void enterNonAtomsCompartment(JSCompartment* c);
+    inline void enterAtomsCompartment(JSCompartment* c,
+                                      const js::AutoLockForExclusiveAccess& lock);
+
     friend class js::AutoCompartment;
 
   public:
     template <typename T>
     inline void enterCompartmentOf(const T& target);
     inline void enterNullCompartment();
     inline void leaveCompartment(JSCompartment* oldCompartment,
                                  const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
@@ -298,20 +302,36 @@ struct JSContext : public JS::RootingCon
     static size_t offsetOfCompartment() {
         return offsetof(JSContext, compartment_);
     }
 
     friend class JS::AutoSaveExceptionState;
     friend class js::jit::DebugModeOSRVolatileJitFrameIterator;
     friend void js::ReportOverRecursed(JSContext*, unsigned errorNumber);
 
+    // Returns to the embedding to allow other cooperative threads to run. We
+    // may do this if we need access to a ZoneGroup that is in use by another
+    // thread.
+    void yieldToEmbedding() {
+        (*yieldCallback_)(this);
+    }
+
+    void setYieldCallback(js::YieldCallback callback) {
+        yieldCallback_ = callback;
+    }
+
   private:
     static JS::Error reportedError;
     static JS::OOM reportedOOM;
 
+    // This callback is used to ask the embedding to allow other cooperative
+    // threads to run. We may do this if we need access to a ZoneGroup that is
+    // in use by another thread.
+    js::ThreadLocalData<js::YieldCallback> yieldCallback_;
+
   public:
     inline JS::Result<> boolToResult(bool ok);
 
     /**
      * Intentionally awkward signpost method that is stationed on the
      * boundary between Result-using and non-Result-using code.
      */
     template <typename V, typename E>
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -446,35 +446,45 @@ JSContext::setPendingException(const js:
 
 inline bool
 JSContext::runningWithTrustedPrincipals()
 {
     return !compartment() || compartment()->principals() == runtime()->trustedPrincipals();
 }
 
 inline void
-JSContext::enterCompartment(
-    JSCompartment* c,
-    const js::AutoLockForExclusiveAccess* maybeLock /* = nullptr */)
+JSContext::enterNonAtomsCompartment(JSCompartment* c)
 {
     enterCompartmentDepth_++;
 
-    if (!c->zone()->isAtomsZone())
-        enterZoneGroup(c->zone()->group());
+    MOZ_ASSERT(!c->zone()->isAtomsZone());
+    enterZoneGroup(c->zone()->group());
 
     c->enter();
-    setCompartment(c, maybeLock);
+    setCompartment(c, nullptr);
+}
+
+inline void
+JSContext::enterAtomsCompartment(JSCompartment* c,
+                                 const js::AutoLockForExclusiveAccess& lock)
+{
+    enterCompartmentDepth_++;
+
+    MOZ_ASSERT(c->zone()->isAtomsZone());
+
+    c->enter();
+    setCompartment(c, &lock);
 }
 
 template <typename T>
 inline void
 JSContext::enterCompartmentOf(const T& target)
 {
     MOZ_ASSERT(JS::CellIsNotGray(target));
-    enterCompartment(target->compartment(), nullptr);
+    enterNonAtomsCompartment(target->compartment());
 }
 
 inline void
 JSContext::enterNullCompartment()
 {
     enterCompartmentDepth_++;
     setCompartment(nullptr);
 }
@@ -524,17 +534,17 @@ JSContext::setCompartment(JSCompartment*
     zone_ = comp ? comp->zone() : nullptr;
     arenas_ = zone_ ? &zone_->arenas : nullptr;
 }
 
 inline void
 JSContext::enterZoneGroup(js::ZoneGroup* group)
 {
     MOZ_ASSERT(this == js::TlsContext.get());
-    group->enter();
+    group->enter(this);
 }
 
 inline void
 JSContext::leaveZoneGroup(js::ZoneGroup* group)
 {
     MOZ_ASSERT(this == js::TlsContext.get());
     group->leave();
 }
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -1048,18 +1048,21 @@ class AutoCompartment
     template <typename T>
     inline AutoCompartment(JSContext* cx, const T& target);
     inline ~AutoCompartment();
 
     JSContext* context() const { return cx_; }
     JSCompartment* origin() const { return origin_; }
 
   protected:
+    inline AutoCompartment(JSContext* cx, JSCompartment* target);
+
+    // Used only for entering the atoms compartment.
     inline AutoCompartment(JSContext* cx, JSCompartment* target,
-                           AutoLockForExclusiveAccess* maybeLock = nullptr);
+                           AutoLockForExclusiveAccess& lock);
 
   private:
     AutoCompartment(const AutoCompartment&) = delete;
     AutoCompartment & operator=(const AutoCompartment&) = delete;
 };
 
 class AutoAtomsCompartment : protected AutoCompartment
 {
--- a/js/src/jscompartmentinlines.h
+++ b/js/src/jscompartmentinlines.h
@@ -39,34 +39,47 @@ template <typename T>
 js::AutoCompartment::AutoCompartment(JSContext* cx, const T& target)
   : cx_(cx),
     origin_(cx->compartment()),
     maybeLock_(nullptr)
 {
     cx_->enterCompartmentOf(target);
 }
 
-// Protected constructor that bypasses assertions in enterCompartmentOf.
+// Protected constructor that bypasses assertions in enterCompartmentOf. Used
+// only for entering the atoms compartment.
 js::AutoCompartment::AutoCompartment(JSContext* cx, JSCompartment* target,
-                                     js::AutoLockForExclusiveAccess* maybeLock /* = nullptr */)
+                                     js::AutoLockForExclusiveAccess& lock)
   : cx_(cx),
     origin_(cx->compartment()),
-    maybeLock_(maybeLock)
+    maybeLock_(&lock)
 {
-    cx_->enterCompartment(target, maybeLock);
+    MOZ_ASSERT(target->isAtomsCompartment());
+    cx_->enterAtomsCompartment(target, lock);
+}
+
+// Protected constructor that bypasses assertions in enterCompartmentOf. Should
+// not be used to enter the atoms compartment.
+js::AutoCompartment::AutoCompartment(JSContext* cx, JSCompartment* target)
+  : cx_(cx),
+    origin_(cx->compartment()),
+    maybeLock_(nullptr)
+{
+    MOZ_ASSERT(!target->isAtomsCompartment());
+    cx_->enterNonAtomsCompartment(target);
 }
 
 js::AutoCompartment::~AutoCompartment()
 {
     cx_->leaveCompartment(origin_, maybeLock_);
 }
 
 js::AutoAtomsCompartment::AutoAtomsCompartment(JSContext* cx,
                                                js::AutoLockForExclusiveAccess& lock)
-  : AutoCompartment(cx, cx->atomsCompartment(lock), &lock)
+  : AutoCompartment(cx, cx->atomsCompartment(lock), lock)
 {}
 
 js::AutoCompartmentUnchecked::AutoCompartmentUnchecked(JSContext* cx, JSCompartment* target)
   : AutoCompartment(cx, target)
 {}
 
 inline bool
 JSCompartment::wrap(JSContext* cx, JS::MutableHandleValue vp)
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1477,8 +1477,21 @@ js::EnableAccessValidation(JSContext* cx
     cx->enableAccessValidation = enabled;
 }
 
 JS_FRIEND_API(void)
 js::SetCompartmentValidAccessPtr(JSContext* cx, JS::HandleObject global, bool* accessp)
 {
     global->compartment()->setValidAccessPtr(accessp);
 }
+
+JS_FRIEND_API(void)
+js::SetCooperativeYieldCallback(JSContext* cx, YieldCallback callback)
+{
+    cx->setYieldCallback(callback);
+}
+
+JS_FRIEND_API(bool)
+js::SystemZoneAvailable(JSContext* cx)
+{
+    CooperatingContext& owner = cx->runtime()->gc.systemZoneGroup->ownerContext();
+    return owner.context() == cx || owner.context() == nullptr;
+}
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -2958,16 +2958,30 @@ EnableAccessValidation(JSContext* cx, bo
 
 // See EnableAccessValidation above. The caller must guarantee that accessp will
 // live at least as long as |global| is alive. The JS engine reads accessp from
 // threads that are allowed to run code on |global|, so all changes to *accessp
 // should be made from whichever thread owns |global| at a given time.
 extern JS_FRIEND_API(void)
 SetCompartmentValidAccessPtr(JSContext* cx, JS::HandleObject global, bool* accessp);
 
+// If the JS engine wants to block so that other cooperative threads can run, it
+// will call the yield callback. It may do this if it needs to access a ZoneGroup
+// that is held by another thread (such as the system zone group).
+typedef void
+(* YieldCallback)(JSContext* cx);
+
+extern JS_FRIEND_API(void)
+SetCooperativeYieldCallback(JSContext* cx, YieldCallback callback);
+
+// Returns true if the system zone is available (i.e., if no cooperative contexts
+// are using it now).
+extern JS_FRIEND_API(bool)
+SystemZoneAvailable(JSContext* cx);
+
 } /* namespace js */
 
 class NativeProfiler
 {
   public:
     virtual ~NativeProfiler() {};
     virtual void sampleNative(void* addr, uint32_t size) = 0;
     virtual void removeNative(void* addr) = 0;
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -6966,17 +6966,17 @@ js::NewCompartment(JSContext* cx, JSPrin
       case JS::NewZoneInExistingZoneGroup:
         group = static_cast<ZoneGroup*>(options.creationOptions().zonePointer());
         MOZ_ASSERT(group);
         break;
     }
 
     if (group) {
         // Take over ownership of the group while we create the compartment/zone.
-        group->enter();
+        group->enter(cx);
     } else {
         MOZ_ASSERT(!zone);
         group = cx->new_<ZoneGroup>(rt);
         if (!group)
             return nullptr;
 
         groupHolder.reset(group);
 
@@ -7037,16 +7037,17 @@ js::NewCompartment(JSContext* cx, JSPrin
             ReportOutOfMemory(cx);
             return nullptr;
         }
 
         // Lazily set the runtime's system zone group.
         if (zoneSpec == JS::SystemZone || zoneSpec == JS::NewZoneInSystemZoneGroup) {
             MOZ_RELEASE_ASSERT(!rt->gc.systemZoneGroup);
             rt->gc.systemZoneGroup = group;
+            group->setUseExclusiveLocking();
         }
     }
 
     zoneHolder.forget();
     groupHolder.forget();
     group->leave();
     return compartment.forget();
 }
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -5308,30 +5308,49 @@ PresShell::AddCanvasBackgroundColorItem(
   nscolor bgcolor = NS_ComposeColors(aBackstopColor, mCanvasBackgroundColor);
   if (NS_GET_A(bgcolor) == 0)
     return;
 
   // To make layers work better, we want to avoid having a big non-scrolled
   // color background behind a scrolled transparent background. Instead,
   // we'll try to move the color background into the scrolled content
   // by making nsDisplayCanvasBackground paint it.
-  if (!aFrame->GetParent()) {
+  // If we're only adding an unscrolled item, then pretend that we've
+  // already done it.
+  bool addedScrollingBackgroundColor = (aFlags & APPEND_UNSCROLLED_ONLY);
+  if (!aFrame->GetParent() && !addedScrollingBackgroundColor) {
     nsIScrollableFrame* sf =
       aFrame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
     if (sf) {
       nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame());
       if (canvasFrame && canvasFrame->IsVisibleForPainting(&aBuilder)) {
-        if (AddCanvasBackgroundColor(aList, canvasFrame, bgcolor, mHasCSSBackgroundColor))
-          return;
-      }
-    }
-  }
-
-  aList.AppendNewToBottom(
-    new (&aBuilder) nsDisplaySolidColor(&aBuilder, aFrame, aBounds, bgcolor));
+        addedScrollingBackgroundColor =
+          AddCanvasBackgroundColor(aList, canvasFrame, bgcolor, mHasCSSBackgroundColor);
+      }
+    }
+  }
+
+  // With async scrolling, we'd like to have two instances of the background
+  // color: one that scrolls with the content (for the reasons stated above),
+  // and one underneath which does not scroll with the content, but which can
+  // be shown during checkerboarding and overscroll.
+  // We can only do that if the color is opaque.
+  bool forceUnscrolledItem = nsLayoutUtils::UsesAsyncScrolling(aFrame) &&
+                             NS_GET_A(bgcolor) == 255;
+  if ((aFlags & ADD_FOR_SUBDOC) && gfxPrefs::LayoutUseContainersForRootFrames()) {
+    // If we're using ContainerLayers for a subdoc, then any items we add here will
+    // still be scrolled (since we're inside the container at this point), so don't
+    // bother and we will do it manually later.
+    forceUnscrolledItem = false;
+  }
+
+  if (!addedScrollingBackgroundColor || forceUnscrolledItem) {
+    aList.AppendNewToBottom(
+      new (&aBuilder) nsDisplaySolidColor(&aBuilder, aFrame, aBounds, bgcolor));
+  }
 }
 
 static bool IsTransparentContainerElement(nsPresContext* aPresContext)
 {
   nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
   if (!docShell) {
     return false;
   }
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1267,19 +1267,31 @@ public:
   virtual void UpdateCanvasBackground() = 0;
 
   /**
    * Add a solid color item to the bottom of aList with frame aFrame and bounds
    * aBounds. Checks first if this needs to be done by checking if aFrame is a
    * canvas frame (if the FORCE_DRAW flag is passed then this check is skipped).
    * aBackstopColor is composed behind the background color of the canvas, it is
    * transparent by default.
+   * We attempt to make the background color part of the scrolled canvas (to reduce
+   * transparent layers), and if async scrolling is enabled (and the background
+   * is opaque) then we add a second, unscrolled item to handle the checkerboarding
+   * case.
+   * ADD_FOR_SUBDOC shoud be specified when calling this for a subdocument, and
+   * LayoutUseContainersForRootFrame might cause the whole list to be scrolled. In
+   * that case the second unscrolled item will be elided.
+   * APPEND_UNSCROLLED_ONLY only attempts to add the unscrolled item, so that we
+   * can add it manually after LayoutUseContainersForRootFrame has built the
+   * scrolling ContainerLayer.
    */
   enum {
-    FORCE_DRAW = 0x01
+    FORCE_DRAW = 0x01,
+    ADD_FOR_SUBDOC = 0x02,
+    APPEND_UNSCROLLED_ONLY = 0x04,
   };
   virtual void AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder,
                                             nsDisplayList& aList,
                                             nsIFrame* aFrame,
                                             const nsRect& aBounds,
                                             nscolor aBackstopColor = NS_RGBA(0,0,0,0),
                                             uint32_t aFlags = 0) = 0;
 
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -489,17 +489,17 @@ nsSubDocumentFrame::BuildDisplayList(nsD
         // is used to compute the visible rect if AddCanvasBackgroundColorItem
         // creates a display item.
         nsIFrame* frame = subdocRootFrame ? subdocRootFrame : this;
         nsDisplayListBuilder::AutoBuildingDisplayList
           building(aBuilder, frame, dirty, true);
         // Add the canvas background color to the bottom of the list. This
         // happens after we've built the list so that AddCanvasBackgroundColorItem
         // can monkey with the contents if necessary.
-        uint32_t flags = nsIPresShell::FORCE_DRAW;
+        uint32_t flags = nsIPresShell::FORCE_DRAW | nsIPresShell::ADD_FOR_SUBDOC;
         presShell->AddCanvasBackgroundColorItem(
           *aBuilder, childItems, frame, bounds, NS_RGBA(0,0,0,0), flags);
       }
     }
   }
 
   if (subdocRootFrame) {
     aBuilder->LeavePresShell(subdocRootFrame, &childItems);
@@ -543,16 +543,39 @@ nsSubDocumentFrame::BuildDisplayList(nsD
   if (needsOwnLayer) {
     // We always want top level content documents to be in their own layer.
     nsDisplaySubDocument* layerItem = new (aBuilder) nsDisplaySubDocument(
       aBuilder, subdocRootFrame ? subdocRootFrame : this,
       &childItems, flags);
     childItems.AppendToTop(layerItem);
   }
 
+  // If we're using containers for root frames, then the earlier call
+  // to AddCanvasBackgroundColorItem won't have been able to add an
+  // unscrolled color item for overscroll. Try again now that we're
+  // outside the scrolled ContainerLayer.
+  if (!aBuilder->IsForEventDelivery() &&
+      gfxPrefs::LayoutUseContainersForRootFrames() &&
+      !nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
+     nsRect bounds = GetContentRectRelativeToSelf() +
+       aBuilder->ToReferenceFrame(this);
+
+    // Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
+    // is used to compute the visible rect if AddCanvasBackgroundColorItem
+    // creates a display item.
+    nsDisplayListBuilder::AutoBuildingDisplayList
+      building(aBuilder, this, dirty, true);
+    // Add the canvas background color to the bottom of the list. This
+    // happens after we've built the list so that AddCanvasBackgroundColorItem
+    // can monkey with the contents if necessary.
+    uint32_t flags = nsIPresShell::FORCE_DRAW | nsIPresShell::APPEND_UNSCROLLED_ONLY;
+    presShell->AddCanvasBackgroundColorItem(
+      *aBuilder, childItems, this, bounds, NS_RGBA(0,0,0,0), flags);
+   }
+
   if (aBuilder->IsForFrameVisibility()) {
     // We don't add the childItems to the return list as we're dealing with them here.
     presShell->RebuildApproximateFrameVisibilityDisplayList(childItems);
     childItems.DeleteAll();
   } else {
     aLists.Content()->AppendToTop(&childItems);
   }
 }
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -656,20 +656,16 @@ public:
   /*
    * Updates mCommonClipCount by checking for rounded rect clips in common
    * between the clip on a new item (aCurrentClip) and the common clips
    * on items already in the layer (the first mCommonClipCount rounded rects
    * in mItemClip).
    */
   void UpdateCommonClipCount(const DisplayItemClip& aCurrentClip);
   /**
-   * The union of all the bounds of the display items in this layer.
-   */
-  nsIntRect mBounds;
-  /**
    * The region of visible content above the layer and below the
    * next PaintedLayerData currently in the stack, if any.
    * This is a conservative approximation: it contains the true region.
    */
   nsIntRegion mVisibleAboveRegion;
   /**
    * All the display items that have been assigned to this painted layer.
    * These items get added by Accumulate().
@@ -1324,16 +1320,17 @@ protected:
   /**
    * Computes the snapped opaque area of aItem. Sets aList's opaque flag
    * if it covers the entire list bounds. Sets *aHideAllLayersBelow to true
    * this item covers the entire viewport so that all layers below are
    * permanently invisible.
    */
   nsIntRegion ComputeOpaqueRect(nsDisplayItem* aItem,
                                 AnimatedGeometryRoot* aAnimatedGeometryRoot,
+                                const ActiveScrolledRoot* aASR,
                                 const DisplayItemClip& aClip,
                                 nsDisplayList* aList,
                                 bool* aHideAllLayersBelow,
                                 bool* aOpaqueForAnimatedGeometryRootParent);
 
   /**
    * Return a PaintedLayerData object that is initialized for a layer that
    * aItem will be assigned to.
@@ -3236,20 +3233,16 @@ void ContainerState::FinishPaintedLayerD
     newLayerEntry->mVisibleRegion = data->mVisibleRegion;
     newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
     newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
     newLayerEntry->mOpaqueForAnimatedGeometryRootParent = data->mOpaqueForAnimatedGeometryRootParent;
   } else {
     SetOuterVisibleRegionForLayer(layer, data->mVisibleRegion);
   }
 
-  nsIntRect layerBounds = data->mBounds;
-  layerBounds.MoveBy(-GetTranslationForPaintedLayer(data->mLayer));
-  layer->SetLayerBounds(layerBounds);
-
 #ifdef MOZ_DUMP_PAINTING
   if (!data->mLog.IsEmpty()) {
     if (PaintedLayerData* containingPld = mLayerBuilder->GetContainingPaintedLayerData()) {
       containingPld->mLayer->AddExtraDumpInfo(nsCString(data->mLog));
     } else {
       layer->AddExtraDumpInfo(nsCString(data->mLog));
     }
   }
@@ -3436,20 +3429,16 @@ PaintedLayerData::Accumulate(ContainerSt
                             nsDisplayItem* aItem,
                             const nsIntRegion& aClippedOpaqueRegion,
                             const nsIntRect& aVisibleRect,
                             const DisplayItemClip& aClip,
                             LayerState aLayerState)
 {
   FLB_LOG_PAINTED_LAYER_DECISION(this, "Accumulating dp=%s(%p), f=%p against pld=%p\n", aItem->Name(), aItem, aItem->Frame(), this);
 
-  bool snap;
-  nsRect itemBounds = aItem->GetBounds(aState->mBuilder, &snap);
-  mBounds = mBounds.Union(aState->ScaleToOutsidePixels(itemBounds, snap));
-
   if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) {
     mForceTransparentSurface = true;
   }
   if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
     // Disable component alpha.
     // Note that the transform (if any) on the PaintedLayer is always an integer translation so
     // we don't have to factor that in here.
     aItem->DisableComponentAlpha();
@@ -3761,17 +3750,17 @@ ContainerState::GetDisplayPortForAnimate
 {
   if (mLastDisplayPortAGR == aAnimatedGeometryRoot) {
     return mLastDisplayPortRect;
   }
 
   mLastDisplayPortAGR = aAnimatedGeometryRoot;
 
   nsIScrollableFrame* sf = nsLayoutUtils::GetScrollableFrameFor(*aAnimatedGeometryRoot);
-  if (sf == nullptr) {
+  if (sf == nullptr || nsLayoutUtils::UsesAsyncScrolling(*aAnimatedGeometryRoot)) {
     mLastDisplayPortRect = nsRect();
     return mLastDisplayPortRect;
   }
 
   bool usingDisplayport =
     nsLayoutUtils::GetDisplayPort((*aAnimatedGeometryRoot)->GetContent(), &mLastDisplayPortRect,
                                   RelativeTo::ScrollFrame);
   if (!usingDisplayport) {
@@ -3782,16 +3771,17 @@ ContainerState::GetDisplayPortForAnimate
   nsIFrame* scrollFrame = do_QueryFrame(sf);
   mLastDisplayPortRect += scrollFrame->GetOffsetToCrossDoc(mContainerReferenceFrame);
   return mLastDisplayPortRect;
 }
 
 nsIntRegion
 ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
                                   AnimatedGeometryRoot* aAnimatedGeometryRoot,
+                                  const ActiveScrolledRoot* aASR,
                                   const DisplayItemClip& aClip,
                                   nsDisplayList* aList,
                                   bool* aHideAllLayersBelow,
                                   bool* aOpaqueForAnimatedGeometryRootParent)
 {
   bool snapOpaque;
   nsRegion opaque = aItem->GetOpaqueRegion(mBuilder, &snapOpaque);
   if (opaque.IsEmpty()) {
@@ -3800,16 +3790,17 @@ ContainerState::ComputeOpaqueRect(nsDisp
 
   nsIntRegion opaquePixels;
   nsRegion opaqueClipped;
   for (auto iter = opaque.RectIter(); !iter.Done(); iter.Next()) {
     opaqueClipped.Or(opaqueClipped,
                      aClip.ApproximateIntersectInward(iter.Get()));
   }
   if (aAnimatedGeometryRoot == mContainerAnimatedGeometryRoot &&
+      aASR == mContainerASR &&
       opaqueClipped.Contains(mContainerBounds)) {
     *aHideAllLayersBelow = true;
     aList->SetIsOpaque();
   }
   // Add opaque areas to the "exclude glass" region. Only do this when our
   // container layer is going to be the rootmost layer, otherwise transforms
   // etc will mess us up (and opaque contributions from other containers are
   // not needed).
@@ -4384,17 +4375,17 @@ ContainerState::ProcessDisplayItems(nsDi
           // to avoid failure caused by singular transforms.
           newLayerEntry->mUntransformedVisibleRegion = true;
           newLayerEntry->mVisibleRegion =
             item->GetVisibleRectForChildren().ToOutsidePixels(mAppUnitsPerDevPixel);
         } else {
           newLayerEntry->mVisibleRegion = itemVisibleRegion;
         }
         newLayerEntry->mOpaqueRegion = ComputeOpaqueRect(item,
-          animatedGeometryRoot, itemClip, aList,
+          animatedGeometryRoot, itemASR, itemClip, aList,
           &newLayerEntry->mHideAllLayersBelow,
           &newLayerEntry->mOpaqueForAnimatedGeometryRootParent);
       } else {
         bool useChildrenVisible =
           itemType == nsDisplayItem::TYPE_TRANSFORM &&
           (item->Frame()->IsPreserve3DLeaf() ||
            item->Frame()->HasPerspective());
         const nsIntRegion &visible = useChildrenVisible ?
@@ -4440,17 +4431,17 @@ ContainerState::ProcessDisplayItems(nsDi
         paintedLayerData->AccumulateEventRegions(this, eventRegions);
       } else {
         // check to see if the new item has rounded rect clips in common with
         // other items in the layer
         if (mManager->IsWidgetLayerManager()) {
           paintedLayerData->UpdateCommonClipCount(itemClip);
         }
         nsIntRegion opaquePixels = ComputeOpaqueRect(item,
-            animatedGeometryRoot, itemClip, aList,
+            animatedGeometryRoot, itemASR, itemClip, aList,
             &paintedLayerData->mHideAllLayersBelow,
             &paintedLayerData->mOpaqueForAnimatedGeometryRootParent);
         MOZ_ASSERT(nsIntRegion(itemDrawRect).Contains(opaquePixels));
         opaquePixels.AndWith(itemVisibleRect);
         paintedLayerData->Accumulate(this, item, opaquePixels,
             itemVisibleRect, itemClip, layerState);
 
         if (!paintedLayerData->mLayer) {
@@ -4923,26 +4914,29 @@ ContainerState::CollectOldLayers()
                    "Could not recycle mask layer, unsupported layer type.");
       mRecycledMaskImageLayers.Put(MaskLayerKey(layer, Some(i)), static_cast<ImageLayer*>(maskLayer));
     }
   }
 }
 
 struct OpaqueRegionEntry {
   AnimatedGeometryRoot* mAnimatedGeometryRoot;
+  const ActiveScrolledRoot* mASR;
   nsIntRegion mOpaqueRegion;
 };
 
 static OpaqueRegionEntry*
 FindOpaqueRegionEntry(nsTArray<OpaqueRegionEntry>& aEntries,
-                      AnimatedGeometryRoot* aAnimatedGeometryRoot)
+                      AnimatedGeometryRoot* aAnimatedGeometryRoot,
+                      const ActiveScrolledRoot* aASR)
 {
   for (uint32_t i = 0; i < aEntries.Length(); ++i) {
     OpaqueRegionEntry* d = &aEntries[i];
-    if (d->mAnimatedGeometryRoot == aAnimatedGeometryRoot) {
+    if (d->mAnimatedGeometryRoot == aAnimatedGeometryRoot &&
+        d->mASR == aASR) {
       return d;
     }
   }
   return nullptr;
 }
 
 const ActiveScrolledRoot*
 FindDirectChildASR(const ActiveScrolledRoot* aParent, const ActiveScrolledRoot* aDescendant)
@@ -5162,17 +5156,17 @@ ContainerState::PostprocessRetainedLayer
   int32_t opaqueRegionForContainer = -1;
 
   for (int32_t i = mNewChildLayers.Length() - 1; i >= 0; --i) {
     NewLayerEntry* e = &mNewChildLayers.ElementAt(i);
     if (!e->mLayer) {
       continue;
     }
 
-    OpaqueRegionEntry* data = FindOpaqueRegionEntry(opaqueRegions, e->mAnimatedGeometryRoot);
+    OpaqueRegionEntry* data = FindOpaqueRegionEntry(opaqueRegions, e->mAnimatedGeometryRoot, e->mASR);
 
     SetupScrollingMetadata(e);
 
     if (hideAll) {
       e->mVisibleRegion.SetEmpty();
     } else if (!e->mLayer->IsScrollbarContainer()) {
       Maybe<ParentLayerIntRect> clipRect = GetStationaryClipInContainer(e->mLayer);
       if (clipRect && opaqueRegionForContainer >= 0 &&
@@ -5185,29 +5179,33 @@ ContainerState::PostprocessRetainedLayer
 
     SetOuterVisibleRegionForLayer(e->mLayer,
                                   e->mVisibleRegion,
                                   e->mLayerContentsVisibleRect.width >= 0 ? &e->mLayerContentsVisibleRect : nullptr,
                                   e->mUntransformedVisibleRegion);
 
     if (!e->mOpaqueRegion.IsEmpty()) {
       AnimatedGeometryRoot* animatedGeometryRootToCover = e->mAnimatedGeometryRoot;
+      const ActiveScrolledRoot* asrToCover = e->mASR;
       if (e->mOpaqueForAnimatedGeometryRootParent &&
           e->mAnimatedGeometryRoot->mParentAGR == mContainerAnimatedGeometryRoot) {
         animatedGeometryRootToCover = mContainerAnimatedGeometryRoot;
-        data = FindOpaqueRegionEntry(opaqueRegions, animatedGeometryRootToCover);
+        asrToCover = mContainerASR;
+        data = FindOpaqueRegionEntry(opaqueRegions, animatedGeometryRootToCover, asrToCover);
       }
 
       if (!data) {
-        if (animatedGeometryRootToCover == mContainerAnimatedGeometryRoot) {
+        if (animatedGeometryRootToCover == mContainerAnimatedGeometryRoot &&
+            asrToCover == mContainerASR) {
           NS_ASSERTION(opaqueRegionForContainer == -1, "Already found it?");
           opaqueRegionForContainer = opaqueRegions.Length();
         }
         data = opaqueRegions.AppendElement();
         data->mAnimatedGeometryRoot = animatedGeometryRootToCover;
+        data->mASR = asrToCover;
       }
 
       nsIntRegion clippedOpaque = e->mOpaqueRegion;
       Maybe<ParentLayerIntRect> clipRect = e->mLayer->GetCombinedClipRect();
       if (clipRect) {
         clippedOpaque.AndWith(clipRect->ToUnknownRect());
       }
       if (e->mLayer->GetScrolledClip()) {
--- a/layout/reftests/async-scrolling/checkerboard-2-ref.html
+++ b/layout/reftests/async-scrolling/checkerboard-2-ref.html
@@ -1,6 +1,7 @@
 <!DOCTYPE HTML>
 <html>
 <body style="background-color: green; overflow:hidden">
+  <div style="position:fixed; left: 0px; top: 0px; width: 100px; height: 500px; background-color: purple; z-index: -1"></div>
   <div style="position:absolute; left: 0px; top: 0px; background-color: yellow; width: 100px; height: 200px"></div>
   <div style="position:fixed; left: 10px; top: 10px; width: 10px; height: 10px; background-color: blue"></div>
 </body>
--- a/layout/reftests/async-scrolling/checkerboard-3-ref.html
+++ b/layout/reftests/async-scrolling/checkerboard-3-ref.html
@@ -1,5 +1,6 @@
 <!DOCTYPE HTML>
 <html>
 <body style="background-color: green; overflow:hidden">
+  <div style="position:fixed; left: 0px; top: 0px; width: 100px; height: 500px; background-color: purple; z-index: -1"></div>
   <div style="position:fixed; left: 10px; top: 10px; width: 10px; height: 10px; background-color: blue"></div>
 </body>
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -8759,16 +8759,20 @@ CSSParserImpl::ParseGridTrackSize(nsCSSV
   if (!GetToken(true)) {
     return CSSParseResult::NotFound;
   }
   if (eCSSToken_Function != mToken.mType) {
     UngetToken();
     return CSSParseResult::NotFound;
   }
   if (mToken.mIdent.LowerCaseEqualsLiteral("fit-content")) {
+    if (requireFixedSize) {
+      UngetToken();
+      return CSSParseResult::Error;
+    }
     nsCSSValue::Array* func = aValue.InitFunction(eCSSKeyword_fit_content, 1);
     if (ParseGridTrackBreadth(func->Item(1)) == CSSParseResult::Ok &&
         func->Item(1).IsLengthPercentCalcUnit() &&
         ExpectSymbol(')', true)) {
       return CSSParseResult::Ok;
     }
     SkipUntil(')');
     return CSSParseResult::Error;
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -6233,16 +6233,17 @@ if (IsCSSPropertyPrefEnabled("layout.css
       "minmax(auto,0) [a] repeat(Auto-fit, 0) minmax(0,auto)",
       "minmax(calc(1% + 1px),auto) repeat(Auto-fit,[] 1%) minmax(auto,1%)",
       "[a] repeat( auto-fit,[a b] minmax(0,0) )",
       "[a] 40px repeat(auto-fit,[a b] minmax(1px, 0) [])",
       "[a] calc(1px - 99%) [b] repeat(auto-fit,[a b] minmax(1mm, 1%) [c]) [c]",
       "repeat(auto-fill,minmax(1%,auto))",
       "repeat(auto-fill,minmax(1em,min-content)) minmax(min-content,0)",
       "repeat(auto-fill,minmax(max-content,1mm))",
+      "repeat(2, fit-content(1px))",
       "fit-content(1px) 1fr",
       "[a] fit-content(calc(1px - 99%)) [b]",
       "[a] fit-content(10%) [b c] fit-content(1em)",
     ],
     invalid_values: [
       "",
       "normal",
       "40ms",
@@ -6277,16 +6278,18 @@ if (IsCSSPropertyPrefEnabled("layout.css
       "repeat(2.0, 20px)",
       "repeat(2.5, 20px)",
       "repeat(2, (foo))",
       "repeat(2, foo)",
       "40px calc(0px + rubbish)",
       "repeat(1, repeat(1, 20px))",
       "repeat(auto-fill, auto)",
       "repeat(auto-fit,auto)",
+      "repeat(auto-fill, fit-content(1px))",
+      "repeat(auto-fit, fit-content(1px))",
       "repeat(auto-fit,[])",
       "repeat(auto-fill, 0) repeat(auto-fit, 0) ",
       "repeat(auto-fit, 0) repeat(auto-fill, 0) ",
       "[a] repeat(auto-fit, 0) repeat(auto-fit, 0) ",
       "[a] repeat(auto-fill, 0) [a] repeat(auto-fill, 0) ",
       "repeat(auto-fill, 0 0)",
       "repeat(auto-fill, 0 [] 0)",
       "repeat(auto-fill, min-content)",
@@ -6298,16 +6301,18 @@ if (IsCSSPropertyPrefEnabled("layout.css
       "repeat(auto-fill,minmax(1fr,1em))",
       "repeat(auto-fill, 10px) auto",
       "auto repeat(auto-fit, 10px)",
       "minmax(min-content,max-content) repeat(auto-fit, 0)",
       "10px [a] 10px [b a] 1fr [b] repeat(auto-fill, 0)",
       "fit-content(-1px)",
       "fit-content(auto)",
       "fit-content(min-content)",
+      "fit-content(1px) repeat(auto-fit, 1px)",
+      "fit-content(1px) repeat(auto-fill, 1px)",
     ],
     unbalanced_values: [
       "(foo] 40px",
     ]
   };
   if (isGridTemplateSubgridValueEnabled) {
     gCSSProperties["grid-template-columns"].other_values.push(
       // See https://bugzilla.mozilla.org/show_bug.cgi?id=981300
--- a/layout/xul/grid/nsGridRowGroupFrame.h
+++ b/layout/xul/grid/nsGridRowGroupFrame.h
@@ -18,17 +18,17 @@
 #include "nsBoxFrame.h"
 
 /**
  * A frame representing a grid row (or column) group, which is usually
  * an element that is a child of a grid and contains all the rows (or
  * all the columns).  However, multiple levels of groups are allowed, so
  * the parent or child could instead be another group.
  */
-class nsGridRowGroupFrame : public nsBoxFrame
+class nsGridRowGroupFrame final : public nsBoxFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
       return MakeFrameName(NS_LITERAL_STRING("nsGridRowGroup"), aResult);
--- a/layout/xul/nsBoxFrame.cpp
+++ b/layout/xul/nsBoxFrame.cpp
@@ -1996,17 +1996,18 @@ nsBoxFrame::XULRelayoutChildAtOrdinal(ns
  * fallthrough behaviour would be complex. E.g. an element with "allowevents"
  * on top of the Content() list could receive the event even if it was covered
  * by a PositionedDescenants() element without "allowevents". It is best to
  * never convert a non-null hit into null.
  */
 // REVIEW: This is roughly of what nsMenuFrame::GetFrameForPoint used to do.
 // I've made 'allowevents' affect child elements because that seems the only
 // reasonable thing to do.
-class nsDisplayXULEventRedirector : public nsDisplayWrapList {
+class nsDisplayXULEventRedirector final : public nsDisplayWrapList
+{
 public:
   nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder,
                               nsIFrame* aFrame, nsDisplayItem* aItem,
                               nsIFrame* aTargetFrame)
     : nsDisplayWrapList(aBuilder, aFrame, aItem), mTargetFrame(aTargetFrame) {}
   nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder,
                               nsIFrame* aFrame, nsDisplayList* aList,
                               nsIFrame* aTargetFrame)
@@ -2048,17 +2049,17 @@ void nsDisplayXULEventRedirector::HitTes
     // add the target frame itself as the first candidate (see bug 562554).
     if (!topMostAdded) {
       topMostAdded = true;
       aOutFrames->AppendElement(mTargetFrame);
     }
   }
 }
 
-class nsXULEventRedirectorWrapper : public nsDisplayWrapper
+class nsXULEventRedirectorWrapper final : public nsDisplayWrapper
 {
 public:
   explicit nsXULEventRedirectorWrapper(nsIFrame* aTargetFrame)
       : mTargetFrame(aTargetFrame) {}
   virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
                                   nsIFrame* aFrame,
                                   nsDisplayList* aList) override {
     return new (aBuilder)
--- a/layout/xul/nsDeckFrame.h
+++ b/layout/xul/nsDeckFrame.h
@@ -12,17 +12,17 @@
 **/
 
 #ifndef nsDeckFrame_h___
 #define nsDeckFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "nsBoxFrame.h"
 
-class nsDeckFrame : public nsBoxFrame
+class nsDeckFrame final : public nsBoxFrame
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsDeckFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewDeckFrame(nsIPresShell* aPresShell,
                                    nsStyleContext* aContext);
--- a/layout/xul/nsDocElementBoxFrame.cpp
+++ b/layout/xul/nsDocElementBoxFrame.cpp
@@ -21,18 +21,18 @@
 #include "nsContentUtils.h"
 #include "nsContentList.h"
 #include "mozilla/dom/Element.h"
 
 //#define DEBUG_REFLOW
 
 using namespace mozilla::dom;
 
-class nsDocElementBoxFrame : public nsBoxFrame,
-                             public nsIAnonymousContentCreator
+class nsDocElementBoxFrame final : public nsBoxFrame
+                                 , public nsIAnonymousContentCreator
 {
 public:
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
   friend nsIFrame* NS_NewBoxFrame(nsIPresShell* aPresShell,
                                   nsStyleContext* aContext);
 
   explicit nsDocElementBoxFrame(nsStyleContext* aContext)
--- a/layout/xul/nsGroupBoxFrame.cpp
+++ b/layout/xul/nsGroupBoxFrame.cpp
@@ -13,17 +13,18 @@
 #include "nsRenderingContext.h"
 #include "nsStyleContext.h"
 #include "nsDisplayList.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::image;
 
-class nsGroupBoxFrame : public nsBoxFrame {
+class nsGroupBoxFrame final : public nsBoxFrame
+{
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   explicit nsGroupBoxFrame(nsStyleContext* aContext):
     nsBoxFrame(aContext) {}
 
   virtual nsresult GetXULBorderAndPadding(nsMargin& aBorderAndPadding) override;
 
@@ -78,17 +79,18 @@ public:
 nsIFrame*
 NS_NewGroupBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsGroupBoxFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsGroupBoxFrame)
 
-class nsDisplayXULGroupBorder : public nsDisplayItem {
+class nsDisplayXULGroupBorder final : public nsDisplayItem
+{
 public:
   nsDisplayXULGroupBorder(nsDisplayListBuilder* aBuilder,
                               nsGroupBoxFrame* aFrame) :
     nsDisplayItem(aBuilder, aFrame) {
     MOZ_COUNT_CTOR(nsDisplayXULGroupBorder);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayXULGroupBorder() {
--- a/layout/xul/nsImageBoxFrame.h
+++ b/layout/xul/nsImageBoxFrame.h
@@ -121,17 +121,18 @@ private:
   // Boolean variable to determine if the current image request has been
   // registered with the refresh driver.
   bool mRequestRegistered;
 
   bool mUseSrcAttr; ///< Whether or not the image src comes from an attribute.
   bool mSuppressStyleCheck;
 }; // class nsImageBoxFrame
 
-class nsDisplayXULImage : public nsDisplayImageContainer {
+class nsDisplayXULImage final : public nsDisplayImageContainer
+{
 public:
   nsDisplayXULImage(nsDisplayListBuilder* aBuilder,
                     nsImageBoxFrame* aFrame) :
     nsDisplayImageContainer(aBuilder, aFrame) {
     MOZ_COUNT_CTOR(nsDisplayXULImage);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayXULImage() {
--- a/layout/xul/nsListBoxLayout.h
+++ b/layout/xul/nsListBoxLayout.h
@@ -8,17 +8,17 @@
 
 #include "mozilla/Attributes.h"
 #include "nsGridRowGroupLayout.h"
 
 class nsIFrame;
 typedef class nsIFrame nsIFrame;
 class nsBoxLayoutState;
 
-class nsListBoxLayout : public nsGridRowGroupLayout
+class nsListBoxLayout final : public nsGridRowGroupLayout
 {
 public:
   nsListBoxLayout();
 
   // nsBoxLayout
   NS_IMETHOD XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState) override;
   virtual nsSize GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) override;
   virtual nsSize GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) override;
--- a/layout/xul/nsListItemFrame.h
+++ b/layout/xul/nsListItemFrame.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Attributes.h"
 #include "nsGridRowLeafFrame.h"
 
 nsIFrame* NS_NewListItemFrame(nsIPresShell* aPresShell,
                               nsStyleContext *aContext);
 
-class nsListItemFrame : public nsGridRowLeafFrame
+class nsListItemFrame final : public nsGridRowLeafFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewListItemFrame(nsIPresShell* aPresShell,
                                        nsStyleContext *aContext);
 
   // overridden so that children of listitems don't handle mouse events,
--- a/layout/xul/nsResizerFrame.h
+++ b/layout/xul/nsResizerFrame.h
@@ -6,17 +6,17 @@
 #define nsResizerFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
 #include "nsTitleBarFrame.h"
 
 class nsIBaseWindow;
 
-class nsResizerFrame : public nsTitleBarFrame 
+class nsResizerFrame final : public nsTitleBarFrame
 {
 protected:
   struct Direction {
     int8_t mHorizontal;
     int8_t mVertical;
   };
 
 public:
--- a/layout/xul/nsRootBoxFrame.cpp
+++ b/layout/xul/nsRootBoxFrame.cpp
@@ -36,17 +36,18 @@ nsIRootBox::GetRootBox(nsIPresShell* aSh
   if (rootFrame) {
     rootFrame = rootFrame->PrincipalChildList().FirstChild();
   }
 
   nsIRootBox* rootBox = do_QueryFrame(rootFrame);
   return rootBox;
 }
 
-class nsRootBoxFrame : public nsBoxFrame, public nsIRootBox {
+class nsRootBoxFrame final : public nsBoxFrame, public nsIRootBox
+{
 public:
 
   friend nsIFrame* NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   explicit nsRootBoxFrame(nsStyleContext* aContext);
 
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
--- a/layout/xul/nsScrollBoxFrame.cpp
+++ b/layout/xul/nsScrollBoxFrame.cpp
@@ -9,17 +9,17 @@
 #include "nsButtonBoxFrame.h"
 #include "nsITimer.h"
 #include "nsRepeatService.h"
 #include "mozilla/MouseEvents.h"
 #include "nsIContent.h"
 
 using namespace mozilla;
 
-class nsAutoRepeatBoxFrame : public nsButtonBoxFrame
+class nsAutoRepeatBoxFrame final : public nsButtonBoxFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell,
                                             nsStyleContext* aContext);
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
--- a/layout/xul/nsScrollbarButtonFrame.h
+++ b/layout/xul/nsScrollbarButtonFrame.h
@@ -13,17 +13,17 @@
 #ifndef nsScrollbarButtonFrame_h___
 #define nsScrollbarButtonFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "nsButtonBoxFrame.h"
 #include "nsITimer.h"
 #include "nsRepeatService.h"
 
-class nsScrollbarButtonFrame : public nsButtonBoxFrame
+class nsScrollbarButtonFrame final : public nsButtonBoxFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   explicit nsScrollbarButtonFrame(nsStyleContext* aContext):
     nsButtonBoxFrame(aContext), mCursorOnThis(false) {}
 
   // Overrides
--- a/layout/xul/nsScrollbarFrame.h
+++ b/layout/xul/nsScrollbarFrame.h
@@ -12,17 +12,17 @@
 
 #include "mozilla/Attributes.h"
 #include "nsBoxFrame.h"
 
 class nsIScrollbarMediator;
 
 nsIFrame* NS_NewScrollbarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
-class nsScrollbarFrame : public nsBoxFrame
+class nsScrollbarFrame final : public nsBoxFrame
 {
 public:
   explicit nsScrollbarFrame(nsStyleContext* aContext)
     : nsBoxFrame(aContext, mozilla::LayoutFrameType::Scrollbar)
     , mScrollbarMediator(nullptr)
   {}
 
   NS_DECL_QUERYFRAME_TARGET(nsScrollbarFrame)
--- a/layout/xul/nsSplitterFrame.h
+++ b/layout/xul/nsSplitterFrame.h
@@ -13,17 +13,17 @@
 
 #include "mozilla/Attributes.h"
 #include "nsBoxFrame.h"
 
 class nsSplitterFrameInner;
 
 nsIFrame* NS_NewSplitterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
-class nsSplitterFrame : public nsBoxFrame
+class nsSplitterFrame final : public nsBoxFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   explicit nsSplitterFrame(nsStyleContext* aContext);
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
 #ifdef DEBUG_FRAME_DUMP
--- a/layout/xul/nsStackFrame.h
+++ b/layout/xul/nsStackFrame.h
@@ -12,17 +12,17 @@
 **/
 
 #ifndef nsStackFrame_h___
 #define nsStackFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "nsBoxFrame.h"
 
-class nsStackFrame : public nsBoxFrame
+class nsStackFrame final : public nsBoxFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewStackFrame(nsIPresShell* aPresShell,
                                     nsStyleContext* aContext);
 
 #ifdef DEBUG_FRAME_DUMP
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -272,17 +272,18 @@ nsTextBoxFrame::UpdateAttributes(nsIAtom
 
     if (doUpdateTitle) {
         UpdateAccessTitle();
         aResize = true;
     }
 
 }
 
-class nsDisplayXULTextBox : public nsDisplayItem {
+class nsDisplayXULTextBox final : public nsDisplayItem
+{
 public:
   nsDisplayXULTextBox(nsDisplayListBuilder* aBuilder,
                       nsTextBoxFrame* aFrame) :
     nsDisplayItem(aBuilder, aFrame),
     mDisableSubpixelAA(false)
   {
     MOZ_COUNT_CTOR(nsDisplayXULTextBox);
   }
--- a/layout/xul/nsTextBoxFrame.h
+++ b/layout/xul/nsTextBoxFrame.h
@@ -7,17 +7,17 @@
 
 #include "mozilla/Attributes.h"
 #include "nsLeafBoxFrame.h"
 
 class nsAccessKeyInfo;
 class nsAsyncAccesskeyUpdate;
 class nsFontMetrics;
 
-class nsTextBoxFrame : public nsLeafBoxFrame
+class nsTextBoxFrame final : public nsLeafBoxFrame
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsTextBoxFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
   virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
--- a/layout/xul/nsXULLabelFrame.h
+++ b/layout/xul/nsXULLabelFrame.h
@@ -10,17 +10,17 @@
 
 #include "mozilla/Attributes.h"
 #include "nsBlockFrame.h"
 
 #ifndef MOZ_XUL
 #error "This file should not be included"
 #endif
 
-class nsXULLabelFrame : public nsBlockFrame
+class nsXULLabelFrame final : public nsBlockFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewXULLabelFrame(nsIPresShell* aPresShell,
                                        nsStyleContext *aContext);
   
   // nsIFrame
--- a/layout/xul/tree/nsTreeColFrame.cpp
+++ b/layout/xul/tree/nsTreeColFrame.cpp
@@ -48,17 +48,18 @@ nsTreeColFrame::Init(nsIContent*       a
 
 void
 nsTreeColFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   InvalidateColumns(false);
   nsBoxFrame::DestroyFrom(aDestructRoot);
 }
 
-class nsDisplayXULTreeColSplitterTarget : public nsDisplayItem {
+class nsDisplayXULTreeColSplitterTarget final : public nsDisplayItem
+{
 public:
   nsDisplayXULTreeColSplitterTarget(nsDisplayListBuilder* aBuilder,
                                     nsIFrame* aFrame) :
     nsDisplayItem(aBuilder, aFrame) {
     MOZ_COUNT_CTOR(nsDisplayXULTreeColSplitterTarget);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayXULTreeColSplitterTarget() {
--- a/layout/xul/tree/nsTreeColFrame.h
+++ b/layout/xul/tree/nsTreeColFrame.h
@@ -6,17 +6,17 @@
 #include "mozilla/Attributes.h"
 #include "nsBoxFrame.h"
 
 class nsITreeBoxObject;
 
 nsIFrame* NS_NewTreeColFrame(nsIPresShell* aPresShell, 
                              nsStyleContext* aContext);
 
-class nsTreeColFrame : public nsBoxFrame
+class nsTreeColFrame final : public nsBoxFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   explicit nsTreeColFrame(nsStyleContext* aContext):
     nsBoxFrame(aContext) {}
 
   virtual void Init(nsIContent*       aContent,
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1248,17 +1248,17 @@ pref("dom.forms.select.customstyling", t
 #endif
 pref("dom.select_popup_in_parent.enabled", false);
 
 // Enable Directory API. By default, disabled.
 pref("dom.input.dirpicker", false);
 
 // Enable not moving the cursor to end when a text input or textarea has .value
 // set to the value it already has.  By default, enabled.
-pref("dom.input.skip_cursor_move_for_same_value_set", false);
+pref("dom.input.skip_cursor_move_for_same_value_set", true);
 
 // Enables system messages and activities
 pref("dom.sysmsg.enabled", false);
 
 // Enable pre-installed applications.
 pref("dom.webapps.useCurrentProfile", false);
 
 pref("dom.cycle_collector.incremental", true);
--- a/mozglue/build/WindowsDllBlocklist.cpp
+++ b/mozglue/build/WindowsDllBlocklist.cpp
@@ -228,16 +228,18 @@ static const DllBlockInfo sWindowsDllBlo
 
   // smci*.dll - goobzo crashware (bug 1339908)
   { "smci32.dll", ALL_VERSIONS },
   { "smci64.dll", ALL_VERSIONS },
 
   // Crashes with Internet Download Manager, bug 1333486
   { "idmcchandler7.dll", ALL_VERSIONS },
   { "idmcchandler7_64.dll", ALL_VERSIONS },
+  { "idmcchandler5.dll", ALL_VERSIONS },
+  { "idmcchandler5_64.dll", ALL_VERSIONS },
 
   // Nahimic 2 breaks applicaton update (bug 1356637)
   { "nahimic2devprops.dll", ALL_VERSIONS },
 
   { nullptr, 0 }
 };
 
 #ifndef STATUS_DLL_NOT_FOUND
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -10438,16 +10438,30 @@
   },
   "GFX_CRASH": {
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 100,
     "releaseChannelCollection": "opt-out",
     "description": "Graphics Crash Reason (...)"
   },
+  "APZ_AWARE_KEY_LISTENERS": {
+    "alert_emails": ["rhunt@mozilla.com"],
+    "bug_numbers": [1352654],
+    "expires_in_version": "58",
+    "kind": "boolean",
+    "description": "The percentage of pages with a non-passive key event on the path to the root scrolling element that would disable APZ key scrolling. This is tracked for non system principal windows, so it applies to toplevel windows and subframes/iframes, but not chrome windows. "
+  },
+  "APZ_AWARE_MOUSEMOVE_LISTENERS": {
+    "alert_emails": ["rhunt@mozilla.com"],
+    "bug_numbers": [1352654],
+    "expires_in_version": "58",
+    "kind": "boolean",
+    "description": "The percentage of pages with a mousemove listener anywhere in the document that would disable APZ key scrolling. This is tracked for non system principal windows, so it applies to toplevel windows and subframes/iframes, but not chrome windows."
+  },
   "SCROLL_INPUT_METHODS": {
     "alert_emails": ["botond@mozilla.com"],
     "bug_numbers": [1238137],
     "expires_in_version": "60",
     "kind": "enumerated",
     "n_values": 64,
     "description": "Count of scroll actions triggered by different input methods. See gfx/layers/apz/util/ScrollInputMethods.h for a list of possible values and their meanings."
   },
--- a/tools/profiler/core/platform-linux-android.cpp
+++ b/tools/profiler/core/platform-linux-android.cpp
@@ -35,17 +35,16 @@
 
 #include <pthread.h>
 #include <semaphore.h>
 #include <signal.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
-#include <sys/prctl.h> // set name
 #include <stdlib.h>
 #include <sched.h>
 #include <ucontext.h>
 // Ubuntu Dapper requires memory pages to be marked as
 // executable. Otherwise, OS raises an exception when executing code
 // in that page.
 #include <sys/types.h>  // mmap & munmap
 #include <sys/mman.h>   // mmap & munmap
@@ -268,17 +267,16 @@ SigprofHandler(int aSignal, siginfo_t* a
 
   errno = savedErrno;
 }
 
 static void*
 ThreadEntry(void* aArg)
 {
   auto thread = static_cast<SamplerThread*>(aArg);
-  prctl(PR_SET_NAME, "SamplerThread", 0, 0, 0);
   thread->mSamplerTid = gettid();
   thread->Run();
   return nullptr;
 }
 
 SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration,
                              double aIntervalMilliseconds)
   : mActivityGeneration(aActivityGeneration)
--- a/tools/profiler/core/platform-macos.cpp
+++ b/tools/profiler/core/platform-macos.cpp
@@ -1,19 +1,17 @@
 /* -*- 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 <dlfcn.h>
 #include <unistd.h>
 #include <sys/mman.h>
 #include <mach/mach_init.h>
-#include <mach-o/dyld.h>
 #include <mach-o/getsect.h>
 
 #include <AvailabilityMacros.h>
 
 #include <pthread.h>
 #include <semaphore.h>
 #include <signal.h>
 #include <libkern/OSAtomic.h>
@@ -73,35 +71,20 @@ private:
   // because the latter doesn't provide thread manipulation primitives required.
   // For details, consult "Mac OS X Internals" book, Section 7.3.
   thread_act_t mProfiledThread;
 };
 
 ////////////////////////////////////////////////////////////////////////
 // BEGIN SamplerThread target specifics
 
-static void
-SetThreadName()
-{
-  // pthread_setname_np is only available in 10.6 or later, so test
-  // for it at runtime.
-  int (*dynamic_pthread_setname_np)(const char*);
-  *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
-    dlsym(RTLD_DEFAULT, "pthread_setname_np");
-  if (!dynamic_pthread_setname_np)
-    return;
-
-  dynamic_pthread_setname_np("SamplerThread");
-}
-
 static void*
 ThreadEntry(void* aArg)
 {
   auto thread = static_cast<SamplerThread*>(aArg);
-  SetThreadName();
   thread->Run();
   return nullptr;
 }
 
 SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration,
                              double aIntervalMilliseconds)
   : mActivityGeneration(aActivityGeneration)
   , mIntervalMicroseconds(
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -1769,16 +1769,18 @@ NewSamplerThread(PSLockRef aLock, uint32
   return new SamplerThread(aLock, aGeneration, aInterval);
 }
 
 // This function is the sampler thread.  This implementation is used for all
 // targets.
 void
 SamplerThread::Run()
 {
+  PR_SetCurrentThreadName("SamplerThread");
+
   // This will be positive if we are running behind schedule (sampling less
   // frequently than desired) and negative if we are ahead of schedule.
   TimeDuration lastSleepOvershoot = 0;
   TimeStamp sampleStart = TimeStamp::Now();
 
   while (true) {
     // This scope is for |lock|. It ends before we sleep below.
     {