Merge mozilla-inbound to mozilla-central. a=merge
authorAndreea Pavel <apavel@mozilla.com>
Mon, 03 Jun 2019 01:09:50 +0300
changeset 476566 6d71d3ca012438d7eac6e8f9471e198a10eabc70
parent 476557 781791b985b7ce8313fa9950ecde54b7bdeb4c3f (current diff)
parent 476565 ac0ad5d8e9a57c716e392c59b655853a728911b4 (diff)
child 476567 3a1135e99b22392d170911105dbdc3f09c0c4085
push id36100
push userapavel@mozilla.com
push dateSun, 02 Jun 2019 22:10:35 +0000
treeherdermozilla-central@6d71d3ca0124 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone69.0a1
first release with
nightly linux32
6d71d3ca0124 / 69.0a1 / 20190602221035 / files
nightly linux64
6d71d3ca0124 / 69.0a1 / 20190602221035 / files
nightly mac
6d71d3ca0124 / 69.0a1 / 20190602221035 / files
nightly win32
6d71d3ca0124 / 69.0a1 / 20190602221035 / files
nightly win64
6d71d3ca0124 / 69.0a1 / 20190602221035 / 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
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -2779,16 +2779,20 @@ bool nsFrameLoader::TryRemoteBrowser() {
 bool nsFrameLoader::IsRemoteFrame() {
   if (mIsRemoteFrame) {
     MOZ_ASSERT(!GetDocShell(), "Found a remote frame with a DocShell");
     return true;
   }
   return false;
 }
 
+RemoteBrowser* nsFrameLoader::GetRemoteBrowser() const {
+  return mRemoteBrowser;
+}
+
 BrowserParent* nsFrameLoader::GetBrowserParent() const {
   if (!mRemoteBrowser) {
     return nullptr;
   }
   RefPtr<BrowserHost> browserHost = mRemoteBrowser->AsBrowserHost();
   if (!browserHost) {
     return nullptr;
   }
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -307,16 +307,18 @@ class nsFrameLoader final : public nsStu
   /**
    * Returns whether this frame is a remote frame.
    *
    * This is true for either a top-level remote browser in the parent process,
    * or a remote subframe in the child process.
    */
   bool IsRemoteFrame();
 
+  mozilla::dom::RemoteBrowser* GetRemoteBrowser() const;
+
   /**
    * Returns the IPDL actor used if this is a top-level remote browser, or null
    * otherwise.
    */
   BrowserParent* GetBrowserParent() const;
 
   /**
    * Returns the IPDL actor used if this is an out-of-process iframe, or null
--- a/dom/ipc/BrowserBridgeHost.cpp
+++ b/dom/ipc/BrowserBridgeHost.cpp
@@ -1,16 +1,18 @@
 /* -*- 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 "mozilla/dom/BrowserBridgeHost.h"
 
+#include "mozilla/Unused.h"
+
 namespace mozilla {
 namespace dom {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserBridgeHost)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION(BrowserBridgeHost)
@@ -92,10 +94,18 @@ void BrowserBridgeHost::UpdateDimensions
   CSSSize unscaledSize = devicePixelSize / widgetScale;
   hal::ScreenOrientation orientation = hal::eScreenOrientation_Default;
   DimensionInfo di(unscaledRect, unscaledSize, orientation, clientOffset,
                    chromeOffset);
 
   Unused << mBridge->SendUpdateDimensions(di);
 }
 
+void BrowserBridgeHost::UpdateEffects(EffectsInfo aEffects) {
+  if (!mBridge || mEffectsInfo == aEffects) {
+    return;
+  }
+  mEffectsInfo = aEffects;
+  Unused << mBridge->SendUpdateEffects(mEffectsInfo);
+}
+
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/ipc/BrowserBridgeHost.h
+++ b/dom/ipc/BrowserBridgeHost.h
@@ -45,19 +45,22 @@ class BrowserBridgeHost : public RemoteB
   void ResumeLoad(uint64_t aPendingSwitchId) override;
   void DestroyStart() override;
   void DestroyComplete() override;
 
   bool Show(const ScreenIntSize& aSize, bool aParentIsActive) override;
   void UpdateDimensions(const nsIntRect& aRect,
                         const ScreenIntSize& aSize) override;
 
+  void UpdateEffects(EffectsInfo aInfo) override;
+
  private:
   virtual ~BrowserBridgeHost() = default;
 
   // The IPDL actor for proxying browser operations
   RefPtr<BrowserBridgeChild> mBridge;
+  EffectsInfo mEffectsInfo;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_BrowserBridgeHost_h
--- a/dom/ipc/BrowserBridgeParent.cpp
+++ b/dom/ipc/BrowserBridgeParent.cpp
@@ -82,17 +82,17 @@ nsresult BrowserBridgeParent::Init(const
     MOZ_ASSERT(false, "Browser Open Endpoint Failed");
     return NS_ERROR_FAILURE;
   }
 
   // Tell the content process to set up its PBrowserChild.
   bool ok = constructorSender->SendConstructBrowser(
       std::move(childEp), tabId, TabId(0), tabContext.AsIPCTabContext(),
       aBrowsingContext, aChromeFlags, constructorSender->ChildID(),
-      constructorSender->IsForBrowser());
+      constructorSender->IsForBrowser(), /* aIsTopLevel */ false);
   if (NS_WARN_IF(!ok)) {
     MOZ_ASSERT(false, "Browser Constructor Failed");
     return NS_ERROR_FAILURE;
   }
 
   // Set our BrowserParent object to the newly created browser.
   mBrowserParent = browserParent.forget();
   mBrowserParent->SetOwnerElement(Manager()->GetOwnerElement());
@@ -149,16 +149,21 @@ IPCResult BrowserBridgeParent::RecvResum
 }
 
 IPCResult BrowserBridgeParent::RecvUpdateDimensions(
     const DimensionInfo& aDimensions) {
   Unused << mBrowserParent->SendUpdateDimensions(aDimensions);
   return IPC_OK();
 }
 
+IPCResult BrowserBridgeParent::RecvUpdateEffects(const EffectsInfo& aEffects) {
+  Unused << mBrowserParent->SendUpdateEffects(aEffects);
+  return IPC_OK();
+}
+
 IPCResult BrowserBridgeParent::RecvRenderLayers(
     const bool& aEnabled, const bool& aForceRepaint,
     const layers::LayersObserverEpoch& aEpoch) {
   Unused << mBrowserParent->SendRenderLayers(aEnabled, aForceRepaint, aEpoch);
   return IPC_OK();
 }
 
 IPCResult BrowserBridgeParent::RecvNavigateByKey(
--- a/dom/ipc/BrowserBridgeParent.h
+++ b/dom/ipc/BrowserBridgeParent.h
@@ -62,16 +62,17 @@ class BrowserBridgeParent : public PBrow
 
   mozilla::ipc::IPCResult RecvShow(const ScreenIntSize& aSize,
                                    const bool& aParentIsActive,
                                    const nsSizeMode& aSizeMode);
   mozilla::ipc::IPCResult RecvLoadURL(const nsCString& aUrl);
   mozilla::ipc::IPCResult RecvResumeLoad(uint64_t aPendingSwitchID);
   mozilla::ipc::IPCResult RecvUpdateDimensions(
       const DimensionInfo& aDimensions);
+  mozilla::ipc::IPCResult RecvUpdateEffects(const EffectsInfo& aEffects);
   mozilla::ipc::IPCResult RecvRenderLayers(const bool& aEnabled,
                                            const bool& aForceRepaint,
                                            const LayersObserverEpoch& aEpoch);
 
   mozilla::ipc::IPCResult RecvNavigateByKey(const bool& aForward,
                                             const bool& aForDocumentNavigation);
 
   mozilla::ipc::IPCResult RecvDispatchSynthesizedMouseEvent(
--- a/dom/ipc/BrowserChild.cpp
+++ b/dom/ipc/BrowserChild.cpp
@@ -353,60 +353,64 @@ already_AddRefed<BrowserChild> BrowserCh
   RefPtr<BrowserChild> browserChild = iter->second;
   return browserChild.forget();
 }
 
 /*static*/
 already_AddRefed<BrowserChild> BrowserChild::Create(
     ContentChild* aManager, const TabId& aTabId, const TabId& aSameTabGroupAs,
     const TabContext& aContext, BrowsingContext* aBrowsingContext,
-    uint32_t aChromeFlags) {
+    uint32_t aChromeFlags, bool aIsTopLevel) {
   RefPtr<BrowserChild> groupChild = FindBrowserChild(aSameTabGroupAs);
   dom::TabGroup* group = groupChild ? groupChild->TabGroup() : nullptr;
-  RefPtr<BrowserChild> iframe = new BrowserChild(
-      aManager, aTabId, group, aContext, aBrowsingContext, aChromeFlags);
+  RefPtr<BrowserChild> iframe =
+      new BrowserChild(aManager, aTabId, group, aContext, aBrowsingContext,
+                       aChromeFlags, aIsTopLevel);
   return iframe.forget();
 }
 
 BrowserChild::BrowserChild(ContentChild* aManager, const TabId& aTabId,
                            dom::TabGroup* aTabGroup, const TabContext& aContext,
                            BrowsingContext* aBrowsingContext,
-                           uint32_t aChromeFlags)
+                           uint32_t aChromeFlags, bool aIsTopLevel)
     : TabContext(aContext),
       mTabGroup(aTabGroup),
       mManager(aManager),
       mBrowsingContext(aBrowsingContext),
       mChromeFlags(aChromeFlags),
       mMaxTouchPoints(0),
       mLayersId{0},
       mBeforeUnloadListeners(0),
+      mEffectsInfo{EffectsInfo::FullyHidden()},
       mDidFakeShow(false),
       mNotified(false),
       mTriedBrowserInit(false),
       mOrientation(hal::eScreenOrientation_PortraitPrimary),
       mIgnoreKeyPressEvent(false),
       mHasValidInnerSize(false),
       mDestroyed(false),
       mUniqueId(aTabId),
+      mIsTopLevel(aIsTopLevel),
       mHasSiblings(false),
       mIsTransparent(false),
       mIPCOpen(false),
       mParentIsActive(false),
       mDidSetRealShowInfo(false),
       mDidLoadURLInit(false),
       mAwaitingLA(false),
       mSkipKeyPress(false),
       mLayersObserverEpoch{1},
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
       mNativeWindowHandle(0),
 #endif
 #if defined(ACCESSIBILITY)
       mTopLevelDocAccessibleChild(nullptr),
 #endif
       mShouldSendWebProgressEventsToParent(false),
+      mRenderLayers(true),
       mPendingDocShellIsActive(false),
       mPendingDocShellReceivedMessage(false),
       mPendingRenderLayers(false),
       mPendingRenderLayersReceivedMessage(false),
       mPendingLayersObserverEpoch{0},
       mPendingDocShellBlockers(0),
       mCancelContentJSEpoch(0),
       mWidgetNativeData(0) {
@@ -1203,16 +1207,18 @@ mozilla::ipc::IPCResult BrowserChild::Re
 
   // We have now done enough initialization for the record/replay system to
   // create checkpoints. Create a checkpoint now, in case this process never
   // paints later on (the usual place where checkpoints occur).
   if (recordreplay::IsRecordingOrReplaying()) {
     recordreplay::child::CreateCheckpoint();
   }
 
+  UpdateVisibility(false);
+
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult BrowserChild::RecvInitRendering(
     const TextureFactoryIdentifier& aTextureFactoryIdentifier,
     const layers::LayersId& aLayersId,
     const CompositorOptions& aCompositorOptions, const bool& aLayersConnected) {
   mLayersConnected = Some(aLayersConnected);
@@ -2478,79 +2484,33 @@ mozilla::ipc::IPCResult BrowserChild::Re
     MOZ_ASSERT(lm);
 
     // We send the current layer observer epoch to the compositor so that
     // BrowserParent knows whether a layer update notification corresponds to
     // the latest RecvRenderLayers request that was made.
     lm->SetLayersObserverEpoch(mLayersObserverEpoch);
   }
 
+  mRenderLayers = aEnabled;
+
   if (aEnabled) {
     if (!aForceRepaint && IsVisible()) {
       // This request is a no-op. In this case, we still want a
       // MozLayerTreeReady notification to fire in the parent (so that it knows
       // that the child has updated its epoch). PaintWhileInterruptingJSNoOp
       // does that.
       if (IPCOpen()) {
         Unused << SendPaintWhileInterruptingJSNoOp(mLayersObserverEpoch);
         return IPC_OK();
       }
     }
-
-    if (!sVisibleTabs) {
-      sVisibleTabs = new nsTHashtable<nsPtrHashKey<BrowserChild>>();
-    }
-    sVisibleTabs->PutEntry(this);
-
-    MakeVisible();
-
-    nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
-    if (!docShell) {
-      return IPC_OK();
-    }
-
-    // We don't use BrowserChildBase::GetPresShell() here because that would
-    // create a content viewer if one doesn't exist yet. Creating a content
-    // viewer can cause JS to run, which we want to avoid.
-    // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
-    if (RefPtr<PresShell> presShell = docShell->GetPresShell()) {
-      presShell->SetIsActive(true);
-
-      if (nsIFrame* root = presShell->GetRootFrame()) {
-        FrameLayerBuilder::InvalidateAllLayersForFrame(
-            nsLayoutUtils::GetDisplayRootFrame(root));
-        root->SchedulePaint();
-      }
-
-      Telemetry::AutoTimer<Telemetry::TABCHILD_PAINT_TIME> timer;
-      // If we need to repaint, let's do that right away. No sense waiting until
-      // we get back to the event loop again. We suppress the display port so
-      // that we only paint what's visible. This ensures that the tab we're
-      // switching to paints as quickly as possible.
-      presShell->SuppressDisplayport(true);
-      if (nsContentUtils::IsSafeToRunScript()) {
-        WebWidget()->PaintNowIfNeeded();
-      } else {
-        RefPtr<nsViewManager> vm = presShell->GetViewManager();
-        if (nsView* view = vm->GetRootView()) {
-          presShell->Paint(view, view->GetBounds(), PaintFlags::PaintLayers);
-        }
-      }
-      presShell->SuppressDisplayport(false);
-    }
-  } else {
-    if (sVisibleTabs) {
-      sVisibleTabs->RemoveEntry(this);
-      // We don't delete sVisibleTabs here when it's empty since that
-      // could cause a lot of churn. Instead, we wait until ~BrowserChild.
-    }
-
-    MakeHidden();
   }
 
+  UpdateVisibility(true);
+
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult BrowserChild::RecvRequestRootPaint(
     const IntRect& aRect, const float& aScale, const nscolor& aBackgroundColor,
     RequestRootPaintResolver&& aResolve) {
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
   if (!docShell) {
@@ -2791,27 +2751,106 @@ void BrowserChild::NotifyPainted() {
     // Recording/replaying processes have a compositor but not a remote frame.
     if (!recordreplay::IsRecordingOrReplaying()) {
       SendNotifyCompositorTransaction();
     }
     mNotified = true;
   }
 }
 
-void BrowserChild::MakeVisible() {
+IPCResult BrowserChild::RecvUpdateEffects(const EffectsInfo& aEffects) {
+  mEffectsInfo = aEffects;
+  UpdateVisibility(false);
+  return IPC_OK();
+}
+
+bool BrowserChild::IsVisible() {
+  return mPuppetWidget && mPuppetWidget->IsVisible();
+}
+
+void BrowserChild::UpdateVisibility(bool aForceRepaint) {
+  bool shouldBeVisible = mIsTopLevel ? mRenderLayers : mEffectsInfo.mVisible;
+  bool isVisible = IsVisible();
+
+  if (shouldBeVisible != isVisible) {
+    if (shouldBeVisible) {
+      MakeVisible(aForceRepaint);
+    } else {
+      MakeHidden();
+    }
+  }
+}
+
+void BrowserChild::MakeVisible(bool aForceRepaint) {
   if (IsVisible()) {
     return;
   }
 
+  if (!sVisibleTabs) {
+    sVisibleTabs = new nsTHashtable<nsPtrHashKey<BrowserChild>>();
+  }
+  sVisibleTabs->PutEntry(this);
+
   if (mPuppetWidget) {
     mPuppetWidget->Show(true);
   }
+
+  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
+  if (!docShell) {
+    return;
+  }
+
+  // We don't use BrowserChildBase::GetPresShell() here because that would
+  // create a content viewer if one doesn't exist yet. Creating a content
+  // viewer can cause JS to run, which we want to avoid.
+  // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
+  if (RefPtr<PresShell> presShell = docShell->GetPresShell()) {
+    presShell->SetIsActive(true);
+  }
+
+  if (!aForceRepaint) {
+    return;
+  }
+
+  // We don't use BrowserChildBase::GetPresShell() here because that would
+  // create a content viewer if one doesn't exist yet. Creating a content
+  // viewer can cause JS to run, which we want to avoid.
+  // nsIDocShell::GetPresShell returns null if no content viewer exists yet.
+  if (RefPtr<PresShell> presShell = docShell->GetPresShell()) {
+    if (nsIFrame* root = presShell->GetRootFrame()) {
+      FrameLayerBuilder::InvalidateAllLayersForFrame(
+          nsLayoutUtils::GetDisplayRootFrame(root));
+      root->SchedulePaint();
+    }
+
+    Telemetry::AutoTimer<Telemetry::TABCHILD_PAINT_TIME> timer;
+    // If we need to repaint, let's do that right away. No sense waiting until
+    // we get back to the event loop again. We suppress the display port so
+    // that we only paint what's visible. This ensures that the tab we're
+    // switching to paints as quickly as possible.
+    presShell->SuppressDisplayport(true);
+    if (nsContentUtils::IsSafeToRunScript()) {
+      WebWidget()->PaintNowIfNeeded();
+    } else {
+      RefPtr<nsViewManager> vm = presShell->GetViewManager();
+      if (nsView* view = vm->GetRootView()) {
+        presShell->Paint(view, view->GetBounds(), PaintFlags::PaintLayers);
+      }
+    }
+    presShell->SuppressDisplayport(false);
+  }
 }
 
 void BrowserChild::MakeHidden() {
+  if (sVisibleTabs) {
+    sVisibleTabs->RemoveEntry(this);
+    // We don't delete sVisibleTabs here when it's empty since that
+    // could cause a lot of churn. Instead, we wait until ~BrowserChild.
+  }
+
   if (!IsVisible()) {
     return;
   }
 
   // Due to the nested event loop in ContentChild::ProvideWindowCommon,
   // it's possible to be told to become hidden before we're finished
   // setting up a layer manager. We should skip clearing cached layers
   // in that case, since doing so might accidentally put is into
@@ -2839,20 +2878,16 @@ void BrowserChild::MakeHidden() {
     }
   }
 
   if (mPuppetWidget) {
     mPuppetWidget->Show(false);
   }
 }
 
-bool BrowserChild::IsVisible() {
-  return mPuppetWidget && mPuppetWidget->IsVisible();
-}
-
 NS_IMETHODIMP
 BrowserChild::GetMessageManager(ContentFrameMessageManager** aResult) {
   RefPtr<ContentFrameMessageManager> mm(mBrowserChildMessageManager);
   mm.forget(aResult);
   return *aResult ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
--- a/dom/ipc/BrowserChild.h
+++ b/dom/ipc/BrowserChild.h
@@ -237,25 +237,25 @@ class BrowserChild final : public Browse
   static nsTArray<RefPtr<BrowserChild>> GetAll();
 
  public:
   /**
    * Create a new BrowserChild object.
    */
   BrowserChild(ContentChild* aManager, const TabId& aTabId, TabGroup* aTabGroup,
                const TabContext& aContext, BrowsingContext* aBrowsingContext,
-               uint32_t aChromeFlags);
+               uint32_t aChromeFlags, bool aIsTopLevel);
 
   nsresult Init(mozIDOMWindowProxy* aParent);
 
   /** Return a BrowserChild with the given attributes. */
   static already_AddRefed<BrowserChild> Create(
       ContentChild* aManager, const TabId& aTabId, const TabId& aSameTabGroupAs,
       const TabContext& aContext, BrowsingContext* aBrowsingContext,
-      uint32_t aChromeFlags);
+      uint32_t aChromeFlags, bool aIsTopLevel);
 
   // Let managees query if it is safe to send messages.
   bool IsDestroyed() const { return mDestroyed; }
 
   const TabId GetTabId() const {
     MOZ_ASSERT(mUniqueId != 0);
     return mUniqueId;
   }
@@ -302,16 +302,17 @@ class BrowserChild final : public Browse
       const Maybe<ZoomConstraints>& aConstraints) override;
 
   mozilla::ipc::IPCResult RecvLoadURL(const nsCString& aURI,
                                       const ShowInfo& aInfo);
 
   mozilla::ipc::IPCResult RecvResumeLoad(const uint64_t& aPendingSwitchID,
                                          const ShowInfo& aInfo);
 
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   mozilla::ipc::IPCResult RecvShow(const ScreenIntSize& aSize,
                                    const ShowInfo& aInfo,
                                    const bool& aParentIsActive,
                                    const nsSizeMode& aSizeMode);
 
   mozilla::ipc::IPCResult RecvInitRendering(
       const TextureFactoryIdentifier& aTextureFactoryIdentifier,
       const layers::LayersId& aLayersId,
@@ -469,28 +470,33 @@ class BrowserChild final : public Browse
   }
 
   hal::ScreenOrientation GetOrientation() const { return mOrientation; }
 
   void SetBackgroundColor(const nscolor& aColor);
 
   void NotifyPainted();
 
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual mozilla::ipc::IPCResult RecvUpdateEffects(
+      const EffectsInfo& aEffects);
+
   void RequestEditCommands(nsIWidget::NativeKeyBindingsType aType,
                            const WidgetKeyboardEvent& aEvent,
                            nsTArray<CommandInt>& aCommands);
 
+  bool IsVisible();
+
   /**
    * Signal to this BrowserChild that it should be made visible:
    * activated widget, retained layer tree, etc.  (Respectively,
    * made not visible.)
    */
-  void MakeVisible();
+  MOZ_CAN_RUN_SCRIPT void UpdateVisibility(bool aForceRepaint);
+  MOZ_CAN_RUN_SCRIPT void MakeVisible(bool aForceRepaint);
   void MakeHidden();
-  bool IsVisible();
 
   ContentChild* Manager() const { return mManager; }
 
   static inline BrowserChild* GetFrom(nsIDocShell* aDocShell) {
     if (!aDocShell) {
       return nullptr;
     }
 
@@ -837,16 +843,17 @@ class BrowserChild final : public Browse
   RefPtr<BrowsingContext> mBrowsingContext;
   RefPtr<nsBrowserStatusFilter> mStatusFilter;
   uint32_t mChromeFlags;
   uint32_t mMaxTouchPoints;
   layers::LayersId mLayersId;
   int64_t mBeforeUnloadListeners;
   CSSRect mUnscaledOuterRect;
   Maybe<bool> mLayersConnected;
+  EffectsInfo mEffectsInfo;
   bool mDidFakeShow;
   bool mNotified;
   bool mTriedBrowserInit;
   hal::ScreenOrientation mOrientation;
 
   bool mIgnoreKeyPressEvent;
   RefPtr<APZEventState> mAPZEventState;
   SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback;
@@ -854,16 +861,20 @@ class BrowserChild final : public Browse
   bool mDestroyed;
 
   // Position of client area relative to the outer window
   LayoutDeviceIntPoint mClientOffset;
   // Position of tab, relative to parent widget (typically the window)
   LayoutDeviceIntPoint mChromeOffset;
   TabId mUniqueId;
 
+  // Whether or not this browser is the child part of the top level PBrowser
+  // actor in a remote browser.
+  bool mIsTopLevel;
+
   // Whether or not this tab has siblings (other tabs in the same window).
   // This is one factor used when choosing to allow or deny a non-system
   // script's attempt to resize the window.
   bool mHasSiblings;
 
   // Holds the compositor options for the compositor rendering this tab,
   // once we find out which compositor that is.
   Maybe<mozilla::layers::CompositorOptions> mCompositorOptions;
@@ -913,16 +924,19 @@ class BrowserChild final : public Browse
 
 #if defined(ACCESSIBILITY)
   PDocAccessibleChild* mTopLevelDocAccessibleChild;
 #endif
   bool mCoalesceMouseMoveEvents;
 
   bool mShouldSendWebProgressEventsToParent;
 
+  // Whether we are rendering to the compositor or not.
+  bool mRenderLayers;
+
   // In some circumstances, a DocShell might be in a state where it is
   // "blocked", and we should not attempt to change its active state or
   // the underlying PresShell state until the DocShell becomes unblocked.
   // It is possible, however, for the parent process to send commands to
   // change those states while the DocShell is blocked. We store those
   // states temporarily as "pending", and only apply them once the DocShell
   // is no longer blocked.
   bool mPendingDocShellIsActive;
--- a/dom/ipc/BrowserHost.cpp
+++ b/dom/ipc/BrowserHost.cpp
@@ -1,16 +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 "mozilla/dom/BrowserHost.h"
 
+#include "mozilla/Unused.h"
 #include "mozilla/dom/CancelContentJSOptionsBinding.h"
 #include "mozilla/dom/WindowGlobalParent.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserHost)
   NS_INTERFACE_MAP_ENTRY(nsIRemoteTab)
@@ -19,17 +20,19 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION(BrowserHost, mRoot)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowserHost)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowserHost)
 
 BrowserHost::BrowserHost(BrowserParent* aParent)
-    : mId(aParent->GetTabId()), mRoot(aParent) {
+    : mId(aParent->GetTabId()),
+      mRoot(aParent),
+      mEffectsInfo{EffectsInfo::FullyHidden()} {
   mRoot->SetBrowserHost(this);
 }
 
 BrowserHost* BrowserHost::GetFrom(nsIRemoteTab* aRemoteTab) {
   return static_cast<BrowserHost*>(aRemoteTab);
 }
 
 mozilla::layers::LayersId BrowserHost::GetLayersId() const {
@@ -70,16 +73,24 @@ bool BrowserHost::Show(const ScreenIntSi
   return mRoot->Show(aSize, aParentIsActive);
 }
 
 void BrowserHost::UpdateDimensions(const nsIntRect& aRect,
                                    const ScreenIntSize& aSize) {
   mRoot->UpdateDimensions(aRect, aSize);
 }
 
+void BrowserHost::UpdateEffects(EffectsInfo aEffects) {
+  if (!mRoot || mEffectsInfo == aEffects) {
+    return;
+  }
+  mEffectsInfo = aEffects;
+  Unused << mRoot->SendUpdateEffects(mEffectsInfo);
+}
+
 /* attribute boolean docShellIsActive; */
 NS_IMETHODIMP
 BrowserHost::GetDocShellIsActive(bool* aDocShellIsActive) {
   if (!mRoot) {
     *aDocShellIsActive = false;
     return NS_OK;
   }
   *aDocShellIsActive = mRoot->GetDocShellIsActive();
@@ -108,19 +119,17 @@ BrowserHost::GetRenderLayers(bool* aRend
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BrowserHost::SetRenderLayers(bool aRenderLayers) {
   if (!mRoot) {
     return NS_OK;
   }
-  VisitAll([&](BrowserParent* aBrowserParent) {
-    aBrowserParent->SetRenderLayers(aRenderLayers);
-  });
+  mRoot->SetRenderLayers(aRenderLayers);
   return NS_OK;
 }
 
 /* readonly attribute boolean hasLayers; */
 NS_IMETHODIMP
 BrowserHost::GetHasLayers(bool* aHasLayers) {
   if (!mRoot) {
     *aHasLayers = false;
--- a/dom/ipc/BrowserHost.h
+++ b/dom/ipc/BrowserHost.h
@@ -84,22 +84,25 @@ class BrowserHost : public RemoteBrowser
   void ResumeLoad(uint64_t aPendingSwitchId) override;
   void DestroyStart() override;
   void DestroyComplete() override;
 
   bool Show(const ScreenIntSize& aSize, bool aParentIsActive) override;
   void UpdateDimensions(const nsIntRect& aRect,
                         const ScreenIntSize& aSize) override;
 
+  void UpdateEffects(EffectsInfo aInfo) override;
+
  private:
   virtual ~BrowserHost() = default;
 
   // The TabID for the root BrowserParent, we cache this so that we can access
   // it after the remote browser has been destroyed
   TabId mId;
   // The root BrowserParent of this remote browser
   RefPtr<BrowserParent> mRoot;
+  EffectsInfo mEffectsInfo;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_BrowserHost_h
--- a/dom/ipc/BrowserParent.cpp
+++ b/dom/ipc/BrowserParent.cpp
@@ -528,17 +528,19 @@ void BrowserParent::SetOwnerElement(Elem
 
   // Set our BrowsingContext's embedder if we're not embedded within a
   // BrowserBridgeParent.
   if (!GetBrowserBridgeParent() && mBrowsingContext && mFrameElement) {
     mBrowsingContext->SetEmbedderElement(mFrameElement);
   }
 
   VisitChildren([aElement](BrowserBridgeParent* aBrowser) {
-    aBrowser->GetBrowserParent()->SetOwnerElement(aElement);
+    if (auto* browserParent = aBrowser->GetBrowserParent()) {
+      browserParent->SetOwnerElement(aElement);
+    }
   });
 }
 
 void BrowserParent::CacheFrameLoader(nsFrameLoader* aFrameLoader) {
   mFrameLoader = aFrameLoader;
 }
 
 void BrowserParent::AddWindowListeners() {
@@ -1221,19 +1223,22 @@ bool BrowserParent::DeallocPWindowGlobal
   static_cast<WindowGlobalParent*>(aActor)->Release();
   return true;
 }
 
 IPCResult BrowserParent::RecvPBrowserBridgeConstructor(
     PBrowserBridgeParent* aActor, const nsString& aName,
     const nsString& aRemoteType, BrowsingContext* aBrowsingContext,
     const uint32_t& aChromeFlags) {
-  static_cast<BrowserBridgeParent*>(aActor)->Init(
+  nsresult rv = static_cast<BrowserBridgeParent*>(aActor)->Init(
       aName, aRemoteType, CanonicalBrowsingContext::Cast(aBrowsingContext),
       aChromeFlags);
+  if (NS_FAILED(rv)) {
+    return IPC_FAIL(this, "Failed to construct BrowserBridgeParent");
+  }
   return IPC_OK();
 }
 
 PBrowserBridgeParent* BrowserParent::AllocPBrowserBridgeParent(
     const nsString& aName, const nsString& aRemoteType,
     BrowsingContext* aBrowsingContext, const uint32_t& aChromeFlags) {
   // Reference freed in DeallocPBrowserBridgeParent.
   return do_AddRef(new BrowserBridgeParent()).take();
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -961,18 +961,19 @@ nsresult ContentChild::ProvideWindowComm
 
   RefPtr<BrowsingContext> openerBC =
       aParent ? nsPIDOMWindowOuter::From(aParent)->GetBrowsingContext()
               : nullptr;
   RefPtr<BrowsingContext> browsingContext = BrowsingContext::Create(
       nullptr, openerBC, aName, BrowsingContext::Type::Content);
 
   TabContext newTabContext = aTabOpener ? *aTabOpener : TabContext();
-  RefPtr<BrowserChild> newChild = new BrowserChild(
-      this, tabId, tabGroup, newTabContext, browsingContext, aChromeFlags);
+  RefPtr<BrowserChild> newChild =
+      new BrowserChild(this, tabId, tabGroup, newTabContext, browsingContext,
+                       aChromeFlags, /* aIsTopLevel */ true);
 
   if (aTabOpener) {
     MOZ_ASSERT(ipcContext->type() == IPCTabContext::TPopupIPCTabContext);
     ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
   }
 
   nsCOMPtr<nsIEventTarget> target =
       tabGroup->EventTargetFor(TaskCategory::Other);
@@ -1791,17 +1792,18 @@ bool ContentChild::DeallocPJavaScriptChi
   ReleaseJavaScriptChild(aChild);
   return true;
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvConstructBrowser(
     ManagedEndpoint<PBrowserChild>&& aBrowserEp, const TabId& aTabId,
     const TabId& aSameTabGroupAs, const IPCTabContext& aContext,
     BrowsingContext* aBrowsingContext, const uint32_t& aChromeFlags,
-    const ContentParentId& aCpID, const bool& aIsForBrowser) {
+    const ContentParentId& aCpID, const bool& aIsForBrowser,
+    const bool& aIsTopLevel) {
   MOZ_ASSERT(!IsShuttingDown());
 
   static bool hasRunOnce = false;
   if (!hasRunOnce) {
     hasRunOnce = true;
     MOZ_ASSERT(!gFirstIdleTask);
     RefPtr<CancelableRunnable> firstIdleTask =
         NewCancelableRunnableFunction("FirstIdleRunnable", FirstIdle);
@@ -1822,17 +1824,17 @@ mozilla::ipc::IPCResult ContentChild::Re
                              "the parent process. (%s)  Crashing...",
                              tc.GetInvalidReason())
                  .get());
     MOZ_CRASH("Invalid TabContext received from the parent process.");
   }
 
   RefPtr<BrowserChild> browserChild =
       BrowserChild::Create(this, aTabId, aSameTabGroupAs, tc.GetTabContext(),
-                           aBrowsingContext, aChromeFlags);
+                           aBrowsingContext, aChromeFlags, aIsTopLevel);
 
   // Bind the created BrowserChild to IPC to actually link the actor. The ref
   // here is released in DeallocPBrowserChild.
   if (NS_WARN_IF(!BindPBrowserEndpoint(std::move(aBrowserEp),
                                        do_AddRef(browserChild).take()))) {
     return IPC_FAIL(this, "BindPBrowserEndpoint failed");
   }
 
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -518,17 +518,18 @@ class ContentChild final : public PConte
   PFileDescriptorSetChild* AllocPFileDescriptorSetChild(const FileDescriptor&);
 
   bool DeallocPFileDescriptorSetChild(PFileDescriptorSetChild*);
 
   mozilla::ipc::IPCResult RecvConstructBrowser(
       ManagedEndpoint<PBrowserChild>&& aBrowserEp, const TabId& aTabId,
       const TabId& aSameTabGroupAs, const IPCTabContext& aContext,
       BrowsingContext* aBrowsingContext, const uint32_t& aChromeFlags,
-      const ContentParentId& aCpID, const bool& aIsForBrowser);
+      const ContentParentId& aCpID, const bool& aIsForBrowser,
+      const bool& aIsTopLevel);
 
   FORWARD_SHMEM_ALLOCATOR_TO(PContentChild)
 
   void GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries);
 
   PBrowserOrId GetBrowserOrId(BrowserChild* aBrowserChild);
 
   POfflineCacheUpdateChild* AllocPOfflineCacheUpdateChild(
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1201,17 +1201,18 @@ already_AddRefed<RemoteBrowser> ContentP
       return nullptr;
     }
 
     // Tell the content process to set up its PBrowserChild.
     bool ok = constructorSender->SendConstructBrowser(
         std::move(childEp), tabId,
         aSameTabGroupAs ? aSameTabGroupAs->GetTabId() : TabId(0),
         aContext.AsIPCTabContext(), aBrowsingContext, chromeFlags,
-        constructorSender->ChildID(), constructorSender->IsForBrowser());
+        constructorSender->ChildID(), constructorSender->IsForBrowser(),
+        /* aIsTopLevel */ true);
     if (NS_WARN_IF(!ok)) {
       return nullptr;
     }
 
     if (remoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
       // Tell the BrowserChild object that it was created due to a
       // Large-Allocation request.
       Unused << browserParent->SendAwaitLargeAlloc();
new file mode 100644
--- /dev/null
+++ b/dom/ipc/EffectsInfo.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_EffectsInfo_h
+#define mozilla_dom_EffectsInfo_h
+
+namespace mozilla {
+namespace dom {
+
+/**
+ * An EffectsInfo contains information for a remote browser about the graphical
+ * effects that are being applied to it by ancestor browsers in different
+ * processes.
+ *
+ * TODO: This struct currently only reports visibility, and should be extended
+ *       with information on clipping and scaling.
+ */
+class EffectsInfo {
+public:
+  EffectsInfo() {
+    *this = EffectsInfo::FullyHidden();
+  }
+  static EffectsInfo FullyVisible() { return EffectsInfo{true}; }
+  static EffectsInfo FullyHidden() { return EffectsInfo{false}; }
+
+  bool operator==(const EffectsInfo& aOther) {
+    return mVisible == aOther.mVisible;
+  }
+  bool operator!=(const EffectsInfo& aOther) { return !(*this == aOther); }
+
+  // If you add new state here, you must also update operator==
+  bool mVisible;
+  /*
+   * TODO: Add information for ancestor scaling and clipping.
+   */
+
+private:
+  explicit EffectsInfo(bool aVisible) : mVisible(aVisible) { }
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif  // mozilla_dom_EffectsInfo_h
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -81,16 +81,17 @@ using nsEventStatus from "mozilla/EventF
 using mozilla::Modifiers from "mozilla/EventForwards.h";
 using nsSizeMode from "nsIWidgetListener.h";
 using mozilla::widget::CandidateWindowPosition from "ipc/nsGUIEventIPC.h";
 using class mozilla::NativeEventData from "ipc/nsGUIEventIPC.h";
 using mozilla::FontRange from "ipc/nsGUIEventIPC.h";
 using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h";
 using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
 using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
+using mozilla::dom::EffectsInfo from "mozilla/dom/TabMessageUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 struct ShowInfo
 {
   nsString name;
   bool fullscreenAllowed;
@@ -607,16 +608,25 @@ parent:
      */
     async RemoteIsReadyToHandleInputEvents();
 
     /**
      * Child informs the parent that the layer tree is already available.
      */
     async PaintWhileInterruptingJSNoOp(LayersObserverEpoch aEpoch);
 
+child:
+    /**
+     * Parent informs the child of graphical effects that are being applied
+     * to the child browser.
+     */
+    async UpdateEffects(EffectsInfo aEffects);
+
+parent:
+
     /**
      * Sent by the child to the parent to inform it that an update to the
      * dimensions has been requested, likely through win.moveTo or resizeTo
      */
     async SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY, int32_t aCx, int32_t aCy);
 
     nested(inside_sync) sync DispatchWheelEvent(WidgetWheelEvent event);
     nested(inside_sync) sync DispatchMouseEvent(WidgetMouseEvent event);
--- a/dom/ipc/PBrowserBridge.ipdl
+++ b/dom/ipc/PBrowserBridge.ipdl
@@ -10,16 +10,17 @@ include protocol PDocAccessible;
 include DOMTypes;
 
 using ScreenIntSize from "Units.h";
 using nsSizeMode from "nsIWidgetListener.h";
 using mozilla::layers::LayersObserverEpoch from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::LayersId from "mozilla/layers/LayersTypes.h";
 using mozilla::WidgetMouseEvent from "ipc/nsGUIEventIPC.h";
 using mozilla::a11y::IDispatchHolder from "mozilla/a11y/IPCTypes.h";
+using mozilla::dom::EffectsInfo from "mozilla/dom/TabMessageUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 /**
  * A PBrowserBridge connects an iframe/browser in a content process to the
  * PBrowser that manages the embedded content.
  *
@@ -58,16 +59,18 @@ parent:
   async LoadURL(nsCString aSpec);
   async ResumeLoad(uint64_t aPendingSwitchID);
 
   // Out of process rendering.
   async Show(ScreenIntSize size, bool parentIsActive, nsSizeMode sizeMode);
   async UpdateDimensions(DimensionInfo dimensions) compressall;
   async RenderLayers(bool aEnabled, bool aForceRepaint, LayersObserverEpoch aEpoch);
 
+  async UpdateEffects(EffectsInfo aEffects);
+
   /**
    * Navigate by key (Tab/Shift+Tab/F6/Shift+f6).
    */
   async NavigateByKey(bool aForward, bool aForDocumentNavigation);
 
   /**
    * Dispatch the given synthesized mousemove event to the child.
    */
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -388,17 +388,17 @@ parent:
                                 uint32_t chromeFlags);
 
 child:
     async ConstructBrowser(ManagedEndpoint<PBrowserChild> browserEp,
                            TabId tabId, TabId sameTabGroupAs,
                            IPCTabContext context,
                            BrowsingContext browsingContext,
                            uint32_t chromeFlags, ContentParentId cpId,
-                           bool isForBrowser);
+                           bool isForBrowser, bool isTopLevel);
 
 both:
     async PFileDescriptorSet(FileDescriptor fd);
 
     // For parent->child, aBrowser must be non-null; aOuterWindowID can
     // be 0 to indicate the browser's current root document, or nonzero
     // to persist a subdocument.  For child->parent, arguments are
     // ignored and should be null/zero.
--- a/dom/ipc/RemoteBrowser.h
+++ b/dom/ipc/RemoteBrowser.h
@@ -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/. */
 
 #ifndef mozilla_dom_ipc_RemoteBrowser_h
 #define mozilla_dom_ipc_RemoteBrowser_h
 
 #include "mozilla/dom/BrowsingContext.h"
 #include "mozilla/dom/ipc/IdType.h"
+#include "mozilla/dom/EffectsInfo.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "nsILoadContext.h"
 #include "nsISupports.h"
 #include "nsISupportsImpl.h"
 #include "nsIURI.h"
 #include "nsRect.h"
 #include "Units.h"
 
@@ -50,14 +51,16 @@ class RemoteBrowser : public nsISupports
   virtual void LoadURL(nsIURI* aURI) = 0;
   virtual void ResumeLoad(uint64_t aPendingSwitchId) = 0;
   virtual void DestroyStart() = 0;
   virtual void DestroyComplete() = 0;
 
   virtual bool Show(const ScreenIntSize& aSize, bool aParentIsActive) = 0;
   virtual void UpdateDimensions(const nsIntRect& aRect,
                                 const ScreenIntSize& aSize) = 0;
+
+  virtual void UpdateEffects(EffectsInfo aInfo) = 0;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_ipc_RemoteBrowser_h
--- a/dom/ipc/TabMessageUtils.h
+++ b/dom/ipc/TabMessageUtils.h
@@ -9,16 +9,19 @@
 
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/dom/Event.h"
 #include "nsExceptionHandler.h"
 #include "nsIRemoteTab.h"
 #include "nsPIDOMWindow.h"
 #include "nsCOMPtr.h"
+#include "mozilla/dom/EffectsInfo.h"
+#include "mozilla/layers/LayersMessageUtils.h"
+#include "ipc/IPCMessageUtils.h"
 
 namespace mozilla {
 namespace dom {
 class Event;
 
 struct RemoteDOMEvent {
   // Make sure to set the owner after deserializing.
   RefPtr<Event> mEvent;
@@ -68,11 +71,25 @@ struct ParamTraits<UIStateChangeType>
 
 template <>
 struct ParamTraits<nsIRemoteTab::NavigationType>
     : public ContiguousEnumSerializerInclusive<
           nsIRemoteTab::NavigationType,
           nsIRemoteTab::NavigationType::NAVIGATE_BACK,
           nsIRemoteTab::NavigationType::NAVIGATE_URL> {};
 
+template <>
+struct ParamTraits<mozilla::dom::EffectsInfo> {
+  typedef mozilla::dom::EffectsInfo paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam) {
+    WriteParam(aMsg, aParam.mVisible);
+  }
+
+  static bool Read(const Message* aMsg, PickleIterator* aIter,
+                   paramType* aResult) {
+    return ReadParam(aMsg, aIter, &aResult->mVisible);
+  }
+};
+
 }  // namespace IPC
 
 #endif  // TABMESSAGE_UTILS_H
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -45,16 +45,17 @@ EXPORTS.mozilla.dom += [
     'CoalescedWheelData.h',
     'ContentChild.h',
     'ContentParent.h',
     'ContentProcess.h',
     'ContentProcessManager.h',
     'CPOWManagerGetter.h',
     'CSPMessageUtils.h',
     'DocShellMessageUtils.h',
+    'EffectsInfo.h',
     'FilePickerParent.h',
     'JSWindowActor.h',
     'JSWindowActorChild.h',
     'JSWindowActorParent.h',
     'JSWindowActorService.h',
     'MemoryReportRequest.h',
     'PermissionMessageUtils.h',
     'ReferrerInfoUtils.h',
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -367,16 +367,26 @@ WebRenderCanvasRendererAsync* WebRenderC
   return mCanvasRenderer.get();
 }
 
 WebRenderCanvasRendererAsync* WebRenderCanvasData::CreateCanvasRenderer() {
   mCanvasRenderer = MakeUnique<WebRenderCanvasRendererAsync>(mManager);
   return mCanvasRenderer.get();
 }
 
+WebRenderRemoteData::WebRenderRemoteData(RenderRootStateManager* aManager,
+                                         nsDisplayItem* aItem)
+    : WebRenderUserData(aManager, aItem) {}
+
+WebRenderRemoteData::~WebRenderRemoteData() {
+  if (mRemoteBrowser) {
+    mRemoteBrowser->UpdateEffects(mozilla::dom::EffectsInfo::FullyHidden());
+  }
+}
+
 WebRenderRenderRootData::WebRenderRenderRootData(
     RenderRootStateManager* aManager, nsDisplayItem* aItem)
     : WebRenderUserData(aManager, aItem) {}
 
 RenderRootBoundary& WebRenderRenderRootData::EnsureHasBoundary(
     wr::RenderRoot aChildType) {
   if (mBoundary) {
     MOZ_ASSERT(mBoundary->GetChildType() == aChildType);
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -8,16 +8,17 @@
 #define GFX_WEBRENDERUSERDATA_H
 
 #include <vector>
 #include "BasicLayers.h"  // for BasicLayerManager
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/layers/AnimationInfo.h"
 #include "mozilla/layers/RenderRootBoundary.h"
+#include "mozilla/dom/RemoteBrowser.h"
 #include "nsIFrame.h"
 #include "ImageTypes.h"
 
 class nsDisplayItemGeometry;
 
 namespace mozilla {
 namespace wr {
 class IpcResourceUpdateQueue;
@@ -73,16 +74,17 @@ class WebRenderUserData {
   virtual WebRenderCanvasData* AsCanvasData() { return nullptr; }
   virtual WebRenderGroupData* AsGroupData() { return nullptr; }
 
   enum class UserDataType {
     eImage,
     eFallback,
     eAnimation,
     eCanvas,
+    eRemote,
     eGroup,
     eMask,
     eRenderRoot,
   };
 
   virtual UserDataType GetType() = 0;
   bool IsUsed() { return mUsed; }
   void SetUsed(bool aUsed) { mUsed = aUsed; }
@@ -243,16 +245,32 @@ class WebRenderCanvasData : public WebRe
   void ClearCanvasRenderer();
   WebRenderCanvasRendererAsync* GetCanvasRenderer();
   WebRenderCanvasRendererAsync* CreateCanvasRenderer();
 
  protected:
   UniquePtr<WebRenderCanvasRendererAsync> mCanvasRenderer;
 };
 
+class WebRenderRemoteData : public WebRenderUserData {
+ public:
+  WebRenderRemoteData(RenderRootStateManager* aManager, nsDisplayItem* aItem);
+  virtual ~WebRenderRemoteData();
+
+  UserDataType GetType() override { return UserDataType::eRemote; }
+  static UserDataType Type() { return UserDataType::eRemote; }
+
+  void SetRemoteBrowser(dom::RemoteBrowser* aBrowser) {
+    mRemoteBrowser = aBrowser;
+  }
+
+ protected:
+  RefPtr<dom::RemoteBrowser> mRemoteBrowser;
+};
+
 class WebRenderRenderRootData : public WebRenderUserData {
  public:
   WebRenderRenderRootData(RenderRootStateManager* aManager,
                           nsDisplayItem* aItem);
   virtual ~WebRenderRenderRootData();
 
   UserDataType GetType() override { return UserDataType::eRenderRoot; }
   static UserDataType Type() { return UserDataType::eRenderRoot; }
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3536,16 +3536,27 @@ void PrintHitTestInfoStats(nsDisplayList
 
   printf(
       "List %p: total items: %d, hit test items: %d, ratio: %f, visible: %d, "
       "special: %d\n",
       &aList, total, hitTest, ratio, visible, special);
 }
 #endif
 
+// Apply a batch of effects updates generated during a paint to their
+// respective remote browsers.
+static void ApplyEffectsUpdates(
+    const nsDataHashtable<nsPtrHashKey<RemoteBrowser>, EffectsInfo>& aUpdates) {
+  for (auto iter = aUpdates.ConstIter(); !iter.Done(); iter.Next()) {
+    auto browser = iter.Key();
+    auto update = iter.Data();
+    browser->UpdateEffects(update);
+  }
+}
+
 nsresult nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext,
                                    nsIFrame* aFrame,
                                    const nsRegion& aDirtyRegion,
                                    nscolor aBackstop,
                                    nsDisplayListBuilderMode aBuilderMode,
                                    PaintFrameFlags aFlags) {
   AUTO_PROFILER_LABEL("nsLayoutUtils::PaintFrame", GRAPHICS);
   typedef RetainedDisplayListBuilder::PartialUpdateResult PartialUpdateResult;
@@ -4084,16 +4095,21 @@ nsresult nsLayoutUtils::PaintFrame(gfxCo
       layerManager->ScheduleComposite();
     }
 
     // Disable partial updates for the following paint as well, as we now have
     // a plugin-specific display list.
     builder.SetDisablePartialUpdates(true);
   }
 
+  // Apply effects updates if we were actually painting
+  if (isForPainting) {
+    ApplyEffectsUpdates(builder.GetEffectUpdates());
+  }
+
   builder.Check();
 
   {
     AUTO_PROFILER_TRACING("Paint", "DisplayListResources", GRAPHICS);
 
     // Flush the list so we don't trigger the IsEmpty-on-destruction assertion
     if (!useRetainedBuilder) {
       list.DeleteAll(&builder);
--- a/layout/ipc/RenderFrame.cpp
+++ b/layout/ipc/RenderFrame.cpp
@@ -16,16 +16,17 @@
 #include "nsStyleStructInlines.h"
 #include "nsSubDocumentFrame.h"
 #include "RenderFrame.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
 #include "mozilla/layers/WebRenderScrollData.h"
 #include "mozilla/webrender/WebRenderAPI.h"
+#include "mozilla/dom/EffectsInfo.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 namespace mozilla {
 namespace layout {
 
@@ -212,44 +213,49 @@ already_AddRefed<Layer> nsDisplayRemote:
     NS_WARNING("Remote iframe not rendered");
     return nullptr;
   }
 
   if (!mLayersId.IsValid()) {
     return nullptr;
   }
 
+  if (RefPtr<RemoteBrowser> remoteBrowser =
+          GetFrameLoader()->GetRemoteBrowser()) {
+    // Generate an effects update notifying the browser it is visible
+    aBuilder->AddEffectUpdate(remoteBrowser, EffectsInfo::FullyVisible());
+    // FrameLayerBuilder will take care of notifying the browser when it is no
+    // longer visible
+  }
+
   RefPtr<Layer> layer =
       aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this);
 
   if (!layer) {
     layer = aManager->CreateRefLayer();
   }
-
-  if (!layer) {
+  if (!layer || !layer->AsRefLayer()) {
     // Probably a temporary layer manager that doesn't know how to
     // use ref layers.
     return nullptr;
   }
+  RefLayer* refLayer = layer->AsRefLayer();
 
-  static_cast<RefLayer*>(layer.get())->SetReferentId(mLayersId);
   LayoutDeviceIntPoint offset = GetContentRectLayerOffset(Frame(), aBuilder);
   // We can only have an offset if we're a child of an inactive
   // container, but our display item is LAYER_ACTIVE_FORCE which
   // forces all layers above to be active.
   MOZ_ASSERT(aContainerParameters.mOffset == nsIntPoint());
   Matrix4x4 m = Matrix4x4::Translation(offset.x, offset.y, 0.0);
   // Remote content can't be repainted by us, so we multiply down
   // the resolution that our container expects onto our container.
   m.PreScale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0);
-  layer->SetBaseTransform(m);
-
-  if (layer->AsRefLayer()) {
-    layer->AsRefLayer()->SetEventRegionsOverride(mEventRegionsOverride);
-  }
+  refLayer->SetBaseTransform(m);
+  refLayer->SetEventRegionsOverride(mEventRegionsOverride);
+  refLayer->SetReferentId(mLayersId);
 
   return layer.forget();
 }
 
 void nsDisplayRemote::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
   DrawTarget* target = aCtx->GetDrawTarget();
   if (!target->IsRecording() || mTabId == 0) {
     NS_WARNING("Remote iframe not rendered");
@@ -267,16 +273,31 @@ bool nsDisplayRemote::CreateWebRenderCom
     mozilla::wr::IpcResourceUpdateQueue& aResources,
     const StackingContextHelper& aSc,
     mozilla::layers::RenderRootStateManager* aManager,
     nsDisplayListBuilder* aDisplayListBuilder) {
   if (!mLayersId.IsValid()) {
     return true;
   }
 
+  if (RefPtr<RemoteBrowser> remoteBrowser =
+          GetFrameLoader()->GetRemoteBrowser()) {
+    // Generate an effects update notifying the browser it is visible
+    aDisplayListBuilder->AddEffectUpdate(remoteBrowser,
+                                         EffectsInfo::FullyVisible());
+
+    // Create a WebRenderRemoteData to notify the RemoteBrowser when it is no
+    // longer visible
+    RefPtr<WebRenderRemoteData> userData =
+        aManager->CommandBuilder()
+            .CreateOrRecycleWebRenderUserData<WebRenderRemoteData>(
+                this, aBuilder.GetRenderRoot(), nullptr);
+    userData->SetRemoteBrowser(remoteBrowser);
+  }
+
   mOffset = GetContentRectLayerOffset(mFrame, aDisplayListBuilder);
 
   LayoutDeviceRect rect = LayoutDeviceRect::FromAppUnits(
       mFrame->GetContentRectRelativeToSelf(),
       mFrame->PresContext()->AppUnitsPerDevPixel());
   rect += mOffset;
 
   aBuilder.PushIFrame(mozilla::wr::ToRoundedLayoutRect(rect),
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -7,16 +7,18 @@
 #include "mozilla/DebugOnly.h"
 
 #include "FrameLayerBuilder.h"
 
 #include "gfxContext.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/dom/EffectsInfo.h"
+#include "mozilla/dom/RemoteBrowser.h"
 #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
 #include "mozilla/gfx/Matrix.h"
 #include "ActiveLayerTracker.h"
 #include "BasicLayers.h"
 #include "ImageContainer.h"
 #include "ImageLayers.h"
 #include "LayerTreeInvalidation.h"
 #include "Layers.h"
@@ -29,16 +31,17 @@
 #include "gfxEnv.h"
 #include "gfxUtils.h"
 #include "nsAutoPtr.h"
 #include "nsAnimationManager.h"
 #include "nsDisplayList.h"
 #include "nsDocShell.h"
 #include "nsIScrollableFrame.h"
 #include "nsImageFrame.h"
+#include "nsSubDocumentFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsPrintfCString.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsTransitionManager.h"
 #include "mozilla/LayerTimelineMarker.h"
 
 #include "mozilla/EffectCompositor.h"
@@ -382,26 +385,44 @@ DisplayItemData::~DisplayItemData() {
   sAliveDisplayItemDatas->RemoveEntry(entry);
 
   if (sAliveDisplayItemDatas->Count() == 0) {
     delete sAliveDisplayItemDatas;
     sAliveDisplayItemDatas = nullptr;
   }
 }
 
-void DisplayItemData::ClearAnimationCompositorState() {
+void DisplayItemData::NotifyRemoved() {
   if (mDisplayItemKey > static_cast<uint8_t>(DisplayItemType::TYPE_MAX)) {
     // This is sort of a hack. The display item key has higher bits set, which
     // means that it is not the only display item for the frame.
     // This branch skips separator transforms.
     return;
   }
 
   const DisplayItemType type = GetDisplayItemTypeFromKey(mDisplayItemKey);
 
+  if (type == DisplayItemType::TYPE_REMOTE) {
+    // TYPE_REMOTE doesn't support merging, so access it directly
+    MOZ_ASSERT(mFrameList.Length() == 1);
+    if (mFrameList.Length() != 1) {
+      return;
+    }
+
+    // This is a remote browser that is going away, notify it that it is now
+    // hidden
+    nsIFrame* frame = mFrameList[0];
+    nsSubDocumentFrame* subdoc = static_cast<nsSubDocumentFrame*>(frame);
+    nsFrameLoader* frameLoader = subdoc->FrameLoader();
+    if (frameLoader && frameLoader->GetRemoteBrowser()) {
+      frameLoader->GetRemoteBrowser()->UpdateEffects(
+          mozilla::dom::EffectsInfo::FullyHidden());
+    }
+  }
+
   // FIXME: Bug 1530857: Add background_color.
   if (type != DisplayItemType::TYPE_TRANSFORM &&
       type != DisplayItemType::TYPE_OPACITY) {
     return;
   }
 
   for (nsIFrame* frame : mFrameList) {
     EffectCompositor::ClearIsRunningOnCompositor(frame, type);
@@ -2233,16 +2254,28 @@ void FrameLayerBuilder::RemoveFrameFromL
 
     auto it = std::find(data->mParent->mDisplayItems.begin(),
                         data->mParent->mDisplayItems.end(), data);
     MOZ_ASSERT(it != data->mParent->mDisplayItems.end());
     std::iter_swap(it, data->mParent->mDisplayItems.end() - 1);
     data->mParent->mDisplayItems.pop_back();
   }
 
+  if (aFrame->IsSubDocumentFrame()) {
+    const nsSubDocumentFrame* subdoc =
+        static_cast<const nsSubDocumentFrame*>(aFrame);
+    nsFrameLoader* frameLoader = subdoc->FrameLoader();
+    if (frameLoader && frameLoader->GetRemoteBrowser()) {
+      // This is a remote browser that is going away, notify it that it is now
+      // hidden
+      frameLoader->GetRemoteBrowser()->UpdateEffects(
+          mozilla::dom::EffectsInfo::FullyHidden());
+    }
+  }
+
   arrayCopy.Clear();
   sDestroyedFrame = nullptr;
 }
 
 void FrameLayerBuilder::DidBeginRetainedLayerTransaction(
     LayerManager* aManager) {
   mRetainingManager = aManager;
   LayerManagerData* data = static_cast<LayerManagerData*>(
@@ -2285,17 +2318,17 @@ void FrameLayerBuilder::WillEndTransacti
               did->mDisplayItemKey, did->mFrameList[0], t);
         }
 #endif
         InvalidatePreTransformRect(
             t, did->mGeometry->ComputeInvalidationRegion(), did->mClip,
             GetLastPaintOffset(t), did->mTransform);
       }
 
-      did->ClearAnimationCompositorState();
+      did->NotifyRemoved();
 
       // Remove this item. Swapping it with the last element first is
       // quicker than erasing from the middle.
       if (iter != data->mDisplayItems.end() - 1) {
         std::iter_swap(iter, data->mDisplayItems.end() - 1);
         data->mDisplayItems.pop_back();
       } else {
         data->mDisplayItems.pop_back();
--- a/layout/painting/FrameLayerBuilder.h
+++ b/layout/painting/FrameLayerBuilder.h
@@ -81,17 +81,17 @@ class DisplayItemData final {
   friend class FrameLayerBuilder;
   friend class ContainerState;
 
   uint32_t GetDisplayItemKey() { return mDisplayItemKey; }
   layers::Layer* GetLayer() const { return mLayer; }
   nsDisplayItemGeometry* GetGeometry() const { return mGeometry.get(); }
   const DisplayItemClip& GetClip() const { return mClip; }
   void Invalidate() { mIsInvalid = true; }
-  void ClearAnimationCompositorState();
+  void NotifyRemoved();
   void SetItem(nsPaintedDisplayItem* aItem) { mItem = aItem; }
   nsPaintedDisplayItem* GetItem() const { return mItem; }
   nsIFrame* FirstFrame() const { return mFrameList[0]; }
   layers::BasicLayerManager* InactiveManager() const {
     return mInactiveManager;
   }
 
   bool HasMergedFrames() const { return mFrameList.Length() > 1; }
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -1226,16 +1226,17 @@ void nsDisplayListBuilder::BeginFrame() 
 }
 
 void nsDisplayListBuilder::EndFrame() {
   NS_ASSERTION(!mInInvalidSubtree,
                "Someone forgot to cleanup mInInvalidSubtree!");
   mFrameToAnimatedGeometryRootMap.Clear();
   mAGRBudgetSet.Clear();
   mActiveScrolledRoots.Clear();
+  mEffectsUpdates.Clear();
   FreeClipChains();
   FreeTemporaryItems();
   nsCSSRendering::EndFrameTreesLocked();
 }
 
 void nsDisplayListBuilder::MarkFrameForDisplay(nsIFrame* aFrame,
                                                nsIFrame* aStopAtFrame) {
   mFramesMarkedForDisplay.AppendElement(aFrame);
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -29,16 +29,18 @@
 #include "nsRect.h"
 #include "nsRegion.h"
 #include "nsDisplayListInvalidation.h"
 #include "DisplayItemClipChain.h"
 #include "DisplayListClipState.h"
 #include "LayerState.h"
 #include "FrameMetrics.h"
 #include "ImgDrawResult.h"
+#include "mozilla/dom/EffectsInfo.h"
+#include "mozilla/dom/RemoteBrowser.h"
 #include "mozilla/EffectCompositor.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/gfx/UserData.h"
 #include "mozilla/layers/LayerAttributes.h"
 #include "mozilla/layers/RenderRootBoundary.h"
 #include "mozilla/layers/ScrollableLayerGuid.h"
@@ -424,16 +426,19 @@ class nsDisplayListBuilder {
   typedef nsIWidget::ThemeGeometry ThemeGeometry;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
   typedef mozilla::layers::ScrollableLayerGuid::ViewID ViewID;
   typedef mozilla::gfx::CompositorHitTestInfo CompositorHitTestInfo;
   typedef mozilla::gfx::Matrix4x4 Matrix4x4;
   typedef mozilla::Maybe<mozilla::layers::ScrollDirection> MaybeScrollDirection;
+  typedef mozilla::dom::EffectsInfo EffectsInfo;
+  typedef mozilla::layers::LayersId LayersId;
+  typedef mozilla::dom::RemoteBrowser RemoteBrowser;
 
   /**
    * @param aReferenceFrame the frame at the root of the subtree; its origin
    * is the origin of the reference coordinate system for this display list
    * @param aMode encodes what the builder is being used for.
    * @param aBuildCaret whether or not we should include the caret in any
    * display lists that we make.
    */
@@ -1035,16 +1040,25 @@ class nsDisplayListBuilder {
    */
   void AdjustWindowDraggingRegion(nsIFrame* aFrame);
 
   LayoutDeviceIntRegion GetWindowDraggingRegion() const;
 
   void RemoveModifiedWindowRegions();
   void ClearRetainedWindowRegions();
 
+  const nsDataHashtable<nsPtrHashKey<RemoteBrowser>, EffectsInfo>&
+  GetEffectUpdates() const {
+    return mEffectsUpdates;
+  }
+
+  void AddEffectUpdate(RemoteBrowser* aBrowser, EffectsInfo aUpdate) {
+    mEffectsUpdates.Put(aBrowser, aUpdate);
+  }
+
   /**
    * Allocate memory in our arena. It will only be freed when this display list
    * builder is destroyed. This memory holds nsDisplayItems. nsDisplayItem
    * destructors are called as soon as the item is no longer used.
    */
   void* Allocate(size_t aSize, DisplayItemType aType);
 
   void Destroy(DisplayItemType aType, void* aPtr);
@@ -1890,16 +1904,18 @@ class nsDisplayListBuilder {
 
   // Area of animated geometry root budget already allocated
   uint32_t mUsedAGRBudget;
   // Set of frames already counted in budget
   nsTHashtable<nsPtrHashKey<nsIFrame>> mAGRBudgetSet;
 
   nsTArray<nsIFrame*> mModifiedFramesDuringBuilding;
 
+  nsDataHashtable<nsPtrHashKey<RemoteBrowser>, EffectsInfo> mEffectsUpdates;
+
   // Relative to mCurrentFrame.
   nsRect mVisibleRect;
   nsRect mDirtyRect;
 
   // Tracked regions used for retained display list.
   WeakFrameRegion mWindowExcludeGlassRegion;
   WeakFrameRegion mRetainedWindowDraggingRegion;
   WeakFrameRegion mRetainedWindowNoDraggingRegion;