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 715457 873b6b91973b248c5b11ae8a136811a163f94e81
parent 715456 3909bfac189a980784fff998c6a71b1b38e7c9aa
child 715458 0e59b548c6c01d7feaf9f40c282ab2f55e47bab7
push id94165
push usermconley@mozilla.com
push dateWed, 03 Jan 2018 23:25:52 +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
@@ -169,16 +169,17 @@ TabParent::TabParent(nsIContentParent* a
   , mTabSetsCursor(false)
   , mHasContentOpener(false)
 #ifdef DEBUG
   , mActiveSupressDisplayportCount(0)
 #endif
   , mLayerTreeEpoch(0)
   , mPreserveLayers(false)
   , mRenderLayers(false)
+  , mHasLayers(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.
   mIsReadyToHandleInputEvents = !ContentParent::IsInputEventQueueSupported();
@@ -2946,16 +2947,31 @@ TabParent::GetIsPrerendered(bool* aIsPre
   *aIsPrerendered = mIsPrerendered;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TabParent::RenderLayers(bool aEnabled)
 {
   if (aEnabled == mRenderLayers) {
+    if (aEnabled && mHasLayers && 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<TabParent> self = this;
+      uint64_t epoch = mLayerTreeEpoch;
+      NS_DispatchToMainThread(NS_NewRunnableFunction(
+        "dom::TabParent::RenderLayers",
+        [self, epoch] () {
+          MOZ_ASSERT(NS_IsMainThread());
+          self->LayerTreeUpdate(epoch, true);
+        }));
+    }
+
     return NS_OK;
   }
 
   // Preserve layers means that attempts to stop rendering layers
   // will be ignored.
   if (!aEnabled && mPreserveLayers) {
     return NS_OK;
   }
@@ -3060,61 +3076,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;
   }
 
+  mHasLayers = 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,19 +777,25 @@ 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 mHasLayers.
   bool mRenderLayers;
 
+  // True if the compositor has reported that the TabChild has uploaded
+  // layers.
+  bool mHasLayers;
+
   // 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.
   bool mHasBeforeUnload;