fune/layout/ipc/RenderFrame.cpp
Ryan Hunt 2feee8e648 Bug 1500257 part 8 - Remove dependency on RenderFrame from nsDisplayRemote. r=aosmond
This commit removes the dependency on RenderFrame from nsDisplayRemote so that
it can work in child processes with remote subframes. Instead nsDisplayRemote
now works with an nsFrameLoader, which will return the LayerId from either
the RenderFrame (for top-level remote browsers), or from RemoteFrameChild
(for remote subframes).

Differential Revision: https://phabricator.services.mozilla.com/D17448

--HG--
extra : source : 1e1b5cd23412a85fad19ab8ec5aacf31b3a9c9b6
extra : intermediate-source : a62c029510315d109faa9edb31216014e7c70367
extra : histedit_source : 3df246e632fbb71f731c856779e0d2201b3673a3
2019-01-23 11:07:57 -06:00

313 lines
11 KiB
C++

/* -*- 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 "base/basictypes.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/dom/RemoteFrameChild.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/LayerTransactionParent.h"
#include "nsFrameLoader.h"
#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"
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::layers;
namespace mozilla {
namespace layout {
static already_AddRefed<LayerManager> GetLayerManager(TabParent* aTabParent) {
if (Element* element = aTabParent->GetOwnerElement()) {
if (RefPtr<LayerManager> lm =
nsContentUtils::LayerManagerForContent(element)) {
return lm.forget();
}
return nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
}
return nullptr;
}
RenderFrame::RenderFrame()
: mLayersId{0},
mTabParent(nullptr),
mLayerManager(nullptr),
mInitialized(false),
mLayersConnected(false) {}
RenderFrame::~RenderFrame() {}
bool RenderFrame::Initialize(TabParent* aTabParent) {
if (mInitialized || !aTabParent) {
return false;
}
mTabParent = aTabParent;
RefPtr<LayerManager> lm = GetLayerManager(mTabParent);
PCompositorBridgeChild* compositor =
lm ? lm->GetCompositorBridgeChild() : nullptr;
mTabProcessId = mTabParent->Manager()->AsContentParent()->OtherPid();
// Our remote frame will push layers updates to the compositor,
// and we'll keep an indirect reference to that tree.
GPUProcessManager* gpm = GPUProcessManager::Get();
mLayersConnected = gpm->AllocateAndConnectLayerTreeId(
compositor, mTabProcessId, &mLayersId, &mCompositorOptions);
mInitialized = true;
return true;
}
void RenderFrame::Destroy() {
if (mLayersId.IsValid()) {
GPUProcessManager::Get()->UnmapLayerTreeId(mLayersId, mTabProcessId);
}
mTabParent = nullptr;
mLayerManager = nullptr;
}
void RenderFrame::EnsureLayersConnected(CompositorOptions* aCompositorOptions) {
RefPtr<LayerManager> lm = GetLayerManager(mTabParent);
if (!lm) {
return;
}
if (!lm->GetCompositorBridgeChild()) {
return;
}
mLayersConnected = lm->GetCompositorBridgeChild()->SendNotifyChildRecreated(
mLayersId, &mCompositorOptions);
*aCompositorOptions = mCompositorOptions;
}
LayerManager* RenderFrame::AttachLayerManager() {
RefPtr<LayerManager> lm;
if (mTabParent) {
lm = GetLayerManager(mTabParent);
}
// Perhaps the document containing this frame currently has no presentation?
if (lm && lm->GetCompositorBridgeChild() && lm != mLayerManager) {
mLayersConnected =
lm->GetCompositorBridgeChild()->SendAdoptChild(mLayersId);
FrameLayerBuilder::InvalidateAllLayers(lm);
}
mLayerManager = lm.forget();
return mLayerManager;
}
void RenderFrame::OwnerContentChanged() { Unused << AttachLayerManager(); }
void RenderFrame::GetTextureFactoryIdentifier(
TextureFactoryIdentifier* aTextureFactoryIdentifier) const {
RefPtr<LayerManager> lm = mTabParent ? GetLayerManager(mTabParent) : nullptr;
// Perhaps the document containing this frame currently has no presentation?
if (lm) {
*aTextureFactoryIdentifier = lm->GetTextureFactoryIdentifier();
} else {
*aTextureFactoryIdentifier = TextureFactoryIdentifier();
}
}
} // namespace layout
} // namespace mozilla
/**
* Gets the layer-pixel offset of aContainerFrame's content rect top-left
* from the nearest display item reference frame (which we assume will be
* inducing a ContainerLayer).
*/
static mozilla::LayoutDeviceIntPoint GetContentRectLayerOffset(
nsIFrame* aContainerFrame, nsDisplayListBuilder* aBuilder) {
nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
// Offset to the content rect in case we have borders or padding
// Note that aContainerFrame could be a reference frame itself, so
// we need to be careful here to ensure that we call ToReferenceFrame
// on aContainerFrame and not its parent.
nsPoint frameOffset =
aBuilder->ToReferenceFrame(aContainerFrame) +
aContainerFrame->GetContentRectRelativeToSelf().TopLeft();
return mozilla::LayoutDeviceIntPoint::FromAppUnitsToNearest(frameOffset,
auPerDevPixel);
}
// Return true iff |aManager| is a "temporary layer manager". They're
// used for small software rendering tasks, like drawWindow. That's
// currently implemented by a BasicLayerManager without a backing
// widget, and hence in non-retained mode.
inline static bool IsTempLayerManager(mozilla::layers::LayerManager* aManager) {
return (mozilla::layers::LayersBackend::LAYERS_BASIC ==
aManager->GetBackendType() &&
!static_cast<BasicLayerManager*>(aManager)->IsRetained());
}
nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
nsSubDocumentFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame),
mTabId{0},
mEventRegionsOverride(EventRegionsOverride::NoOverride) {
bool frameIsPointerEventsNone = aFrame->StyleUI()->GetEffectivePointerEvents(
aFrame) == NS_STYLE_POINTER_EVENTS_NONE;
if (aBuilder->IsInsidePointerEventsNoneDoc() || frameIsPointerEventsNone) {
mEventRegionsOverride |= EventRegionsOverride::ForceEmptyHitRegion;
}
if (nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(
aFrame->PresShell())) {
mEventRegionsOverride |= EventRegionsOverride::ForceDispatchToContent;
}
nsFrameLoader* frameLoader = GetFrameLoader();
MOZ_ASSERT(frameLoader && frameLoader->IsRemoteFrame());
mLayersId = frameLoader->GetLayersId();
if (nsFrameLoader* frameLoader = GetFrameLoader()) {
// TODO: We need to handle acquiring a TabId in the remote sub-frame case
// for fission.
if (TabParent* browser = TabParent::GetFrom(frameLoader)) {
mTabId = browser->GetTabId();
}
}
}
mozilla::LayerState nsDisplayRemote::GetLayerState(
nsDisplayListBuilder* aBuilder, LayerManager* aManager,
const ContainerLayerParameters& aParameters) {
if (IsTempLayerManager(aManager)) {
return mozilla::LAYER_NONE;
}
return mozilla::LAYER_ACTIVE_FORCE;
}
bool nsDisplayRemote::HasDeletedFrame() const {
// RenderFrame might change without invalidating nsSubDocumentFrame.
return !GetFrameLoader() || nsDisplayItem::HasDeletedFrame();
}
already_AddRefed<Layer> nsDisplayRemote::BuildLayer(
nsDisplayListBuilder* aBuilder, LayerManager* aManager,
const ContainerLayerParameters& aContainerParameters) {
MOZ_ASSERT(mFrame, "Makes no sense to have a shadow tree without a frame");
if (IsTempLayerManager(aManager)) {
// This can happen if aManager is a "temporary" manager, or if the
// widget's layer manager changed out from under us. We need to
// FIXME handle the former case somehow, probably with an API to
// draw a manager's subtree. The latter is bad bad bad, but the the
// MOZ_ASSERT() above will flag it. Returning nullptr here will just
// cause the shadow subtree not to be rendered.
if (!aContainerParameters.mForEventsAndPluginsOnly) {
NS_WARNING("Remote iframe not rendered");
}
return nullptr;
}
if (!mLayersId.IsValid()) {
return nullptr;
}
RefPtr<Layer> layer =
aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this);
if (!layer) {
layer = aManager->CreateRefLayer();
}
if (!layer) {
// Probably a temporary layer manager that doesn't know how to
// use ref layers.
return nullptr;
}
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);
}
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");
return;
}
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
Rect destRect = mozilla::NSRectToSnappedRect(GetContentRect(),
appUnitsPerDevPixel, *target);
target->DrawDependentSurface(mTabId, destRect);
}
bool nsDisplayRemote::CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) {
if (!mLayersId.IsValid()) {
return true;
}
mOffset = GetContentRectLayerOffset(mFrame, aDisplayListBuilder);
LayoutDeviceRect rect = LayoutDeviceRect::FromAppUnits(
mFrame->GetContentRectRelativeToSelf(),
mFrame->PresContext()->AppUnitsPerDevPixel());
rect += mOffset;
aBuilder.PushIFrame(mozilla::wr::ToRoundedLayoutRect(rect),
!BackfaceIsHidden(), mozilla::wr::AsPipelineId(mLayersId),
/*ignoreMissingPipelines*/ true);
return true;
}
bool nsDisplayRemote::UpdateScrollData(
mozilla::layers::WebRenderScrollData* aData,
mozilla::layers::WebRenderLayerScrollData* aLayerData) {
if (!mLayersId.IsValid()) {
return true;
}
if (aLayerData) {
aLayerData->SetReferentId(mLayersId);
aLayerData->SetTransform(
mozilla::gfx::Matrix4x4::Translation(mOffset.x, mOffset.y, 0.0));
aLayerData->SetEventRegionsOverride(mEventRegionsOverride);
}
return true;
}
nsFrameLoader* nsDisplayRemote::GetFrameLoader() const {
return mFrame ? static_cast<nsSubDocumentFrame*>(mFrame)->FrameLoader()
: nullptr;
}