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
--- 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();