Bug 1351777 - Use a BasicLayerManager in the content process if the corresponding parent-side layer manager isn't connected to the compositor. r?dvander draft
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 31 Mar 2017 11:43:21 -0400
changeset 554462 ea26f8d7ad9382ffe781200b57fac545941dde73
parent 554461 e398b8ee5c261c35d63938d3144284638f95a765
child 622335 0a8cae28accce9f8f9319c0eaf03e23c78d28537
push id51931
push userkgupta@mozilla.com
push dateFri, 31 Mar 2017 15:44:23 +0000
reviewersdvander
bugs1351777
milestone55.0a1
Bug 1351777 - Use a BasicLayerManager in the content process if the corresponding parent-side layer manager isn't connected to the compositor. r?dvander There are scenarios where we have a TabParent in the UI process hooked up to a PuppetWidget with a BasicLayerManager. Webextensions fall into this category. In this scenario, the parent-side layer manager is not hooked up to the compositor (that is, there is no entry in the CompositorBridge layer tree state map for the layers id). However, the content-side still ends up creating a ClientLayerManager or a WebRenderLayerManager, which expects the layers id to be registered in the compositor. This results in brokenness (in the case of the ClientLayerManager/PLayerTransaction) or crashes (in the case of WebRenderLayerManager/ PWebRenderBridge). Instead, this patch changes this scenario to have the content process use a BasicLayerManager which seems safer. MozReview-Commit-ID: 3f80aZrRrmD
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
widget/PuppetWidget.cpp
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -622,16 +622,17 @@ child:
      */
     async Show(ScreenIntSize size,
                ShowInfo info,
                bool parentIsActive,
                nsSizeMode sizeMode);
 
     async InitRendering(TextureFactoryIdentifier textureFactoryIdentifier,
                         uint64_t layersId,
+                        bool layersConnected,
                         nullable PRenderFrame renderFrame);
 
     async LoadURL(nsCString uri, ShowInfo info);
 
     async UpdateDimensions(CSSRect rect, CSSSize size,
                            ScreenOrientationInternal orientation,
                            LayoutDeviceIntPoint clientOffset,
                            LayoutDeviceIntPoint chromeDisp) compressall;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -368,16 +368,17 @@ TabChild::TabChild(nsIContentChild* aMan
                    const TabContext& aContext,
                    uint32_t aChromeFlags)
   : TabContext(aContext)
   , mRemoteFrame(nullptr)
   , mManager(aManager)
   , mChromeFlags(aChromeFlags)
   , mActiveSuppressDisplayport(0)
   , mLayersId(0)
+  , mLayersConnected(true)
   , mDidFakeShow(false)
   , mNotified(false)
   , mTriedBrowserInit(false)
   , mOrientation(eScreenOrientation_PortraitPrimary)
   , mIgnoreKeyPressEvent(false)
   , mHasValidInnerSize(false)
   , mDestroyed(false)
   , mUniqueId(aTabId)
@@ -1256,20 +1257,22 @@ TabChild::RecvShow(const ScreenIntSize& 
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvInitRendering(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                             const uint64_t& aLayersId,
+                            const bool& aLayersConnected,
                             PRenderFrameChild* aRenderFrame)
 {
   MOZ_ASSERT((!mDidFakeShow && aRenderFrame) || (mDidFakeShow && !aRenderFrame));
 
+  mLayersConnected = aLayersConnected;
   InitRenderingState(aTextureFactoryIdentifier, aLayersId, aRenderFrame);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvUpdateDimensions(const CSSRect& rect, const CSSSize& size,
                                const ScreenOrientationInternal& orientation,
                                const LayoutDeviceIntPoint& clientOffset,
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -338,16 +338,17 @@ public:
   RecvShow(const ScreenIntSize& aSize,
            const ShowInfo& aInfo,
            const bool& aParentIsActive,
            const nsSizeMode& aSizeMode) override;
 
   virtual mozilla::ipc::IPCResult
   RecvInitRendering(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                     const uint64_t& aLayersId,
+                    const bool& aLayersConnected,
                     PRenderFrameChild* aRenderFrame) override;
 
   virtual mozilla::ipc::IPCResult
   RecvUpdateDimensions(const CSSRect& aRect,
                        const CSSSize& aSize,
                        const ScreenOrientationInternal& aOrientation,
                        const LayoutDeviceIntPoint& aClientOffset,
                        const LayoutDeviceIntPoint& aChromeDisp) override;
@@ -547,16 +548,17 @@ public:
     nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webNav);
     return GetFrom(docShell);
   }
 
   static TabChild* GetFrom(nsIPresShell* aPresShell);
   static TabChild* GetFrom(uint64_t aLayersId);
 
   uint64_t LayersId() { return mLayersId; }
+  bool IsLayersConnected() { return mLayersConnected; }
 
   void DidComposite(uint64_t aTransactionId,
                     const TimeStamp& aCompositeStart,
                     const TimeStamp& aCompositeEnd);
 
   void DidRequestComposite(const TimeStamp& aCompositeReqStart,
                            const TimeStamp& aCompositeReqEnd);
 
@@ -769,16 +771,17 @@ private:
   RenderFrameChild* mRemoteFrame;
   RefPtr<nsIContentChild> mManager;
   RefPtr<TabChildSHistoryListener> mHistoryListener;
   uint32_t mChromeFlags;
   int32_t mActiveSuppressDisplayport;
   uint64_t mLayersId;
   CSSRect mUnscaledOuterRect;
   nscolor mLastBackgroundColor;
+  bool mLayersConnected;
   bool mDidFakeShow;
   bool mNotified;
   bool mTriedBrowserInit;
   ScreenOrientationInternal mOrientation;
 
   bool mIgnoreKeyPressEvent;
   RefPtr<APZEventState> mAPZEventState;
   SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -654,17 +654,18 @@ TabParent::InitRenderFrame()
       uint64_t layersId = renderFrame->GetLayersId();
       AddTabParentToTable(layersId, this);
       if (!SendPRenderFrameConstructor(renderFrame)) {
         return;
       }
 
       TextureFactoryIdentifier textureFactoryIdentifier;
       renderFrame->GetTextureFactoryIdentifier(&textureFactoryIdentifier);
-      Unused << SendInitRendering(textureFactoryIdentifier, layersId, renderFrame);
+      Unused << SendInitRendering(textureFactoryIdentifier, layersId,
+        renderFrame->IsLayersConnected(), renderFrame);
     }
   } else {
     // Otherwise, the child should have constructed the RenderFrame,
     // and we should already know about it.
     MOZ_ASSERT(GetRenderFrame());
   }
 }
 
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -82,16 +82,17 @@ GetFrom(nsFrameLoader* aFrameLoader)
   if (!doc) {
     return nullptr;
   }
   return nsContentUtils::LayerManagerForDocument(doc);
 }
 
 RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader)
   : mLayersId(0)
+  , mLayersConnected(false)
   , mFrameLoader(aFrameLoader)
   , mFrameLoaderDestroyed(false)
   , mAsyncPanZoomEnabled(false)
   , mInitted(false)
 {
   mInitted = Init(aFrameLoader);
 }
 
@@ -112,21 +113,21 @@ RenderFrameParent::Init(nsFrameLoader* a
   mAsyncPanZoomEnabled = lm && lm->AsyncPanZoomEnabled();
 
   TabParent* browser = TabParent::GetFrom(mFrameLoader);
   if (XRE_IsParentProcess()) {
     // Our remote frame will push layers updates to the compositor,
     // and we'll keep an indirect reference to that tree.
     browser->Manager()->AsContentParent()->AllocateLayerTreeId(browser, &mLayersId);
     if (lm && lm->GetCompositorBridgeChild()) {
-      lm->GetCompositorBridgeChild()->SendNotifyChildCreated(mLayersId);
+      mLayersConnected = lm->GetCompositorBridgeChild()->SendNotifyChildCreated(mLayersId);
     }
   } else if (XRE_IsContentProcess()) {
     ContentChild::GetSingleton()->SendAllocateLayerTreeId(browser->Manager()->ChildID(), browser->GetTabId(), &mLayersId);
-    CompositorBridgeChild::Get()->SendNotifyChildCreated(mLayersId);
+    mLayersConnected = CompositorBridgeChild::Get()->SendNotifyChildCreated(mLayersId);
   }
 
   mInitted = true;
   return true;
 }
 
 bool
 RenderFrameParent::IsInitted()
@@ -202,17 +203,17 @@ void
 RenderFrameParent::OwnerContentChanged(nsIContent* aContent)
 {
   MOZ_ASSERT(!mFrameLoader || mFrameLoader->GetOwnerContent() == aContent,
              "Don't build new map if owner is same!");
 
   RefPtr<LayerManager> lm = mFrameLoader ? GetFrom(mFrameLoader) : nullptr;
   // Perhaps the document containing this frame currently has no presentation?
   if (lm && lm->GetCompositorBridgeChild()) {
-    lm->GetCompositorBridgeChild()->SendAdoptChild(mLayersId);
+    mLayersConnected = lm->GetCompositorBridgeChild()->SendAdoptChild(mLayersId);
     FrameLayerBuilder::InvalidateAllLayers(lm);
   }
 }
 
 void
 RenderFrameParent::ActorDestroy(ActorDestroyReason why)
 {
   if (mLayersId != 0) {
@@ -306,17 +307,17 @@ RenderFrameParent::EnsureLayersConnected
   if (!lm) {
     return;
   }
 
   if (!lm->GetCompositorBridgeChild()) {
     return;
   }
 
-  lm->GetCompositorBridgeChild()->SendNotifyChildRecreated(mLayersId);
+  mLayersConnected = lm->GetCompositorBridgeChild()->SendNotifyChildRecreated(mLayersId);
 }
 
 } // namespace layout
 } // namespace mozilla
 
 nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
                                  nsSubDocumentFrame* aFrame,
                                  RenderFrameParent* aRemoteFrame)
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -76,16 +76,17 @@ public:
 
   void OwnerContentChanged(nsIContent* aContent);
 
   bool HitTest(const nsRect& aRect);
 
   void GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier);
 
   inline uint64_t GetLayersId() const { return mLayersId; }
+  inline bool IsLayersConnected() const { return mLayersConnected; }
 
   void TakeFocusForClickFromTap();
 
   void EnsureLayersConnected();
 
 protected:
   void ActorDestroy(ActorDestroyReason why) override;
 
@@ -94,16 +95,20 @@ protected:
 private:
   void TriggerRepaint();
   void DispatchEventForPanZoomController(const InputEvent& aEvent);
 
   // When our child frame is pushing transactions directly to the
   // compositor, this is the ID of its layer tree in the compositor's
   // context.
   uint64_t mLayersId;
+  // A flag that indicates whether or not the compositor knows about the
+  // layers id. In some cases this RenderFrameParent is not connected to the
+  // compositor and so this flag is false.
+  bool mLayersConnected;
 
   RefPtr<nsFrameLoader> mFrameLoader;
   RefPtr<ContainerLayer> mContainer;
 
   // True after Destroy() has been called, which is triggered
   // originally by nsFrameLoader::Destroy().  After this point, we can
   // no longer safely ask the frame loader to find its nearest layer
   // manager, because it may have been disconnected from the DOM.
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -602,17 +602,23 @@ PuppetWidget::GetLayerManager(PLayerTran
     if (XRE_IsParentProcess()) {
       // On the parent process there is no CompositorBridgeChild which confuses
       // some layers code, so we use basic layers instead. Note that we create
       // a non-retaining layer manager since we don't care about performance.
       mLayerManager = new BasicLayerManager(BasicLayerManager::BLM_OFFSCREEN);
       return mLayerManager;
     }
 
-    if (gfxVars::UseWebRender()) {
+    if (mTabChild && !mTabChild->IsLayersConnected()) {
+      // If we know for sure that the parent side of this TabChild is not
+      // connected to the compositor, we don't want to use a "remote" layer
+      // manager like WebRender or Client. Instead we use a Basic one which
+      // can do drawing in this process.
+      mLayerManager = new BasicLayerManager(this);
+    } else if (gfxVars::UseWebRender()) {
       mLayerManager = new WebRenderLayerManager(this);
     } else {
       mLayerManager = new ClientLayerManager(this);
     }
   }
 
   // Attach a shadow forwarder if none exists.
   ShadowLayerForwarder* lf = mLayerManager->AsShadowForwarder();