Bug 1397426 - When short-circuiting a TabParent::RenderLayers call, still fire the layer tree event if we've been preserving layers. r?billm draft
authorMike Conley <mconley@mozilla.com>
Tue, 07 Nov 2017 15:08:47 -0500
changeset 700783 4ba6516e8a9f9d494105828ad161bf6104c42db9
parent 700782 e1cbc000c14bd7150999aa491006748486825df6
child 700784 e362345fe7eac4bba1b395fff847a5e9cf861032
push id89973
push usermconley@mozilla.com
push dateMon, 20 Nov 2017 22:09:48 +0000
reviewersbillm
bugs1397426
milestone59.0a1
Bug 1397426 - When short-circuiting a TabParent::RenderLayers call, still fire the layer tree event if we've been preserving layers. r?billm MozReview-Commit-ID: 7UT036vUY85
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -168,16 +168,17 @@ TabParent::TabParent(nsIContentParent* a
   , mCursor(eCursorInvalid)
   , mTabSetsCursor(false)
   , mHasContentOpener(false)
 #ifdef DEBUG
   , mActiveSupressDisplayportCount(0)
 #endif
   , mLayerTreeEpoch(0)
   , mPreserveLayers(false)
+  , mRenderLayers(false)
   , mRenderingLayers(false)
   , mHasPresented(false)
   , mHasBeforeUnload(false)
   , mIsMouseEnterIntoWidgetEventSuppressed(false)
 {
   MOZ_ASSERT(aManager);
   // When the input event queue is disabled, we don't need to handle the case
   // that some input events are dispatched before PBrowserConstructor.
@@ -2934,30 +2935,67 @@ TabParent::GetDocShellIsActive(bool* aIs
 
 NS_IMETHODIMP
 TabParent::GetIsPrerendered(bool* aIsPrerendered)
 {
   *aIsPrerendered = mIsPrerendered;
   return NS_OK;
 }
 
+class LayerTreeUpdateRunnable final
+  : public mozilla::Runnable
+{
+  RefPtr<TabParent> mTabParent;
+  uint64_t mEpoch;
+  bool mActive;
+
+public:
+  explicit LayerTreeUpdateRunnable(TabParent* aTabParent,
+                                   uint64_t aEpoch,
+                                   bool aActive)
+    : Runnable("dom::LayerTreeUpdateRunnable")
+    , mTabParent(aTabParent)
+    , mEpoch(aEpoch)
+    , mActive(aActive)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+  }
+
+private:
+  NS_IMETHOD Run() override {
+    MOZ_ASSERT(NS_IsMainThread());
+    mTabParent->LayerTreeUpdate(mEpoch, mActive);
+    return NS_OK;
+  }
+};
+
 NS_IMETHODIMP
 TabParent::RenderLayers(bool aEnabled)
 {
-  if (aEnabled == mRenderingLayers) {
+  if (aEnabled == mRenderLayers) {
+    if (aEnabled == mRenderingLayers && mPreserveLayers) {
+      // RenderLayers might be called when we've been preserving layers,
+      // and already had layers uploaded. In that case, the MozLayerTreeReady
+      // event will not naturally arrive, which can confuse the front-end
+      // layer. So we fire the event here.
+      RefPtr<LayerTreeUpdateRunnable> runnable =
+        new LayerTreeUpdateRunnable(this, mLayerTreeEpoch, aEnabled);
+      NS_DispatchToMainThread(runnable);
+    }
+
     return NS_OK;
   }
 
   // Preserve layers means that attempts to stop rendering layers
   // will be ignored.
   if (!aEnabled && mPreserveLayers) {
     return NS_OK;
   }
 
-  mRenderingLayers = aEnabled;
+  mRenderLayers = aEnabled;
 
   // Increment the epoch so that layer tree updates from previous
   // RenderLayers requests are ignored.
   mLayerTreeEpoch++;
 
   Unused << SendRenderLayers(aEnabled, mLayerTreeEpoch);
 
   // Ask the child to repaint using the PHangMonitor channel/thread (which may
@@ -3052,61 +3090,34 @@ TabParent::TransmitPermissionsForPrincip
 
 NS_IMETHODIMP
 TabParent::GetHasBeforeUnload(bool* aResult)
 {
   *aResult = mHasBeforeUnload;
   return NS_OK;
 }
 
-class LayerTreeUpdateRunnable final
-  : public mozilla::Runnable
-{
-  uint64_t mLayersId;
-  uint64_t mEpoch;
-  bool mActive;
-
-public:
-  explicit LayerTreeUpdateRunnable(uint64_t aLayersId,
-                                   uint64_t aEpoch,
-                                   bool aActive)
-    : Runnable("dom::LayerTreeUpdateRunnable")
-    , mLayersId(aLayersId)
-    , mEpoch(aEpoch)
-    , mActive(aActive)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-  }
-
-private:
-  NS_IMETHOD Run() override {
-    MOZ_ASSERT(NS_IsMainThread());
-    if (RefPtr<TabParent> tabParent = TabParent::GetTabParentFromLayersId(mLayersId)) {
-      tabParent->LayerTreeUpdate(mEpoch, mActive);
-    }
-    return NS_OK;
-  }
-};
-
 void
 TabParent::LayerTreeUpdate(uint64_t aEpoch, bool aActive)
 {
   // Ignore updates from old epochs. They might tell us that layers are
   // available when we've already sent a message to clear them. We can't trust
   // the update in that case since layers could disappear anytime after that.
   if (aEpoch != mLayerTreeEpoch || mIsDestroyed) {
     return;
   }
 
   nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(mFrameElement);
   if (!target) {
     NS_WARNING("Could not locate target for layer tree message.");
     return;
   }
 
+  mRenderingLayers = aActive;
+
   RefPtr<Event> event = NS_NewDOMEvent(mFrameElement, nullptr, nullptr);
   if (aActive) {
     mHasPresented = true;
     event->InitEvent(NS_LITERAL_STRING("MozLayerTreeReady"), true, false);
   } else {
     event->InitEvent(NS_LITERAL_STRING("MozLayerTreeCleared"), true, false);
   }
   event->SetTrusted(true);
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -777,17 +777,23 @@ private:
   static void RemoveTabParentFromTable(uint64_t aLayersId);
 
   uint64_t mLayerTreeEpoch;
 
   // If this flag is set, then the tab's layers will be preserved even when
   // the tab's docshell is inactive.
   bool mPreserveLayers;
 
-  // Holds the most recent value passed to the RenderLayers function.
+  // Holds the most recent value passed to the RenderLayers function. This
+  // does not necessarily mean that the layers have finished rendering
+  // and have uploaded - for that, use mRenderingLayers.
+  bool mRenderLayers;
+
+  // True if the compositor has reported that the TabChild has uploaded
+  // layers.
   bool mRenderingLayers;
 
   // True if this TabParent has had its layer tree sent to the compositor
   // at least once.
   bool mHasPresented;
 
   // True if at least one window hosted in the TabChild has added a
   // beforeunload event listener.