diff options
Diffstat (limited to 'layout/ipc/RenderFrameParent.cpp')
-rw-r--r-- | layout/ipc/RenderFrameParent.cpp | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp new file mode 100644 index 000000000..8162d02d7 --- /dev/null +++ b/layout/ipc/RenderFrameParent.cpp @@ -0,0 +1,368 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=8 et : + */ +/* 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 "BasicLayers.h" +#include "gfxPrefs.h" +#ifdef MOZ_ENABLE_D3D9_LAYER +# include "LayerManagerD3D9.h" +#endif //MOZ_ENABLE_D3D9_LAYER +#include "mozilla/BrowserElementParent.h" +#include "mozilla/EventForwards.h" // for Modifiers +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/TabChild.h" +#include "mozilla/dom/TabParent.h" +#include "mozilla/layers/APZCTreeManager.h" +#include "mozilla/layers/APZThreadUtils.h" +#include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/layers/LayerTransactionParent.h" +#include "nsContentUtils.h" +#include "nsFocusManager.h" +#include "nsFrameLoader.h" +#include "nsIObserver.h" +#include "nsStyleStructInlines.h" +#include "nsSubDocumentFrame.h" +#include "nsView.h" +#include "nsViewportFrame.h" +#include "RenderFrameParent.h" +#include "mozilla/gfx/GPUProcessManager.h" +#include "mozilla/layers/LayerManagerComposite.h" +#include "mozilla/layers/CompositorBridgeChild.h" +#include "ClientLayerManager.h" +#include "FrameLayerBuilder.h" + +using namespace mozilla::dom; +using namespace mozilla::gfx; +using namespace mozilla::layers; + +namespace mozilla { +namespace layout { + +typedef FrameMetrics::ViewID ViewID; + +/** + * 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 nsIntPoint +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 frameOffset.ToNearestPixels(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(LayerManager* aManager) +{ + return (mozilla::layers::LayersBackend::LAYERS_BASIC == aManager->GetBackendType() && + !static_cast<BasicLayerManager*>(aManager)->IsRetained()); +} + +already_AddRefed<LayerManager> +GetFrom(nsFrameLoader* aFrameLoader) +{ + nsIDocument* doc = aFrameLoader->GetOwnerDoc(); + if (!doc) { + return nullptr; + } + return nsContentUtils::LayerManagerForDocument(doc); +} + +RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader, bool* aSuccess) + : mLayersId(0) + , mFrameLoader(aFrameLoader) + , mFrameLoaderDestroyed(false) + , mAsyncPanZoomEnabled(false) + , mInitted(false) +{ + mInitted = Init(aFrameLoader); + *aSuccess = mInitted; +} + +RenderFrameParent::~RenderFrameParent() +{} + +bool +RenderFrameParent::Init(nsFrameLoader* aFrameLoader) +{ + if (mInitted || !aFrameLoader) { + return false; + } + + mFrameLoader = aFrameLoader; + + RefPtr<LayerManager> lm = GetFrom(mFrameLoader); + + 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->AsClientLayerManager()) { + if (!lm->AsClientLayerManager()->GetRemoteRenderer()->SendNotifyChildCreated(mLayersId)) { + return false; + } + } + } else if (XRE_IsContentProcess()) { + ContentChild::GetSingleton()->SendAllocateLayerTreeId(browser->Manager()->ChildID(), browser->GetTabId(), &mLayersId); + if (!CompositorBridgeChild::Get()->SendNotifyChildCreated(mLayersId)) { + return false; + } + } + + mInitted = true; + return true; +} + +bool +RenderFrameParent::IsInitted() +{ + return mInitted; +} + +void +RenderFrameParent::Destroy() +{ + mFrameLoaderDestroyed = true; +} + +already_AddRefed<Layer> +RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, + LayerManager* aManager, + const nsIntRect& aVisibleRect, + nsDisplayItem* aItem, + const ContainerLayerParameters& aContainerParameters) +{ + MOZ_ASSERT(aFrame, + "makes no sense to have a shadow tree without a frame"); + MOZ_ASSERT(!mContainer || + IsTempLayerManager(aManager) || + mContainer->Manager() == aManager, + "retaining manager changed out from under us ... HELP!"); + + if (IsTempLayerManager(aManager) || + (mContainer && mContainer->Manager() != 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; + } + + uint64_t id = GetLayerTreeId(); + if (!id) { + return nullptr; + } + + RefPtr<Layer> layer = + (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); + 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(id); + nsIntPoint offset = GetContentRectLayerOffset(aFrame, 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()); + gfx::Matrix4x4 m = gfx::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); + + return layer.forget(); +} + +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->AsClientLayerManager()) { + lm->AsClientLayerManager()->GetRemoteRenderer()->SendAdoptChild(mLayersId); + FrameLayerBuilder::InvalidateAllLayers(lm); + } +} + +void +RenderFrameParent::ActorDestroy(ActorDestroyReason why) +{ + if (mLayersId != 0) { + if (XRE_IsParentProcess()) { + GPUProcessManager::Get()->UnmapLayerTreeId(mLayersId, OtherPid()); + } else if (XRE_IsContentProcess()) { + ContentChild::GetSingleton()->SendDeallocateLayerTreeId(mLayersId); + } + } + + mFrameLoader = nullptr; +} + +bool +RenderFrameParent::RecvNotifyCompositorTransaction() +{ + TriggerRepaint(); + return true; +} + +void +RenderFrameParent::TriggerRepaint() +{ + nsIFrame* docFrame = mFrameLoader->GetPrimaryFrameOfOwningContent(); + if (!docFrame) { + // Bad, but nothing we can do about it (XXX/cjones: or is there? + // maybe bug 589337?). When the new frame is created, we'll + // probably still be the current render frame and will get to draw + // our content then. Or, we're shutting down and this update goes + // to /dev/null. + return; + } + + docFrame->InvalidateLayer(nsDisplayItem::TYPE_REMOTE); +} + +uint64_t +RenderFrameParent::GetLayerTreeId() const +{ + return mLayersId; +} + +void +RenderFrameParent::BuildDisplayList(nsDisplayListBuilder* aBuilder, + nsSubDocumentFrame* aFrame, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) +{ + // We're the subdoc for <browser remote="true"> and it has + // painted content. Display its shadow layer tree. + DisplayListClipState::AutoSaveRestore clipState(aBuilder); + + nsPoint offset = aBuilder->ToReferenceFrame(aFrame); + nsRect bounds = aFrame->EnsureInnerView()->GetBounds() + offset; + clipState.ClipContentDescendants(bounds); + + aLists.Content()->AppendToTop( + new (aBuilder) nsDisplayRemote(aBuilder, aFrame, this)); +} + +void +RenderFrameParent::GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier) +{ + RefPtr<LayerManager> lm = mFrameLoader ? GetFrom(mFrameLoader) : nullptr; + // Perhaps the document containing this frame currently has no presentation? + if (lm && lm->AsClientLayerManager()) { + *aTextureFactoryIdentifier = lm->AsClientLayerManager()->GetTextureFactoryIdentifier(); + } else { + *aTextureFactoryIdentifier = TextureFactoryIdentifier(); + } +} + +void +RenderFrameParent::TakeFocusForClickFromTap() +{ + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); + if (!fm) { + return; + } + nsCOMPtr<nsIContent> owner = mFrameLoader->GetOwnerContent(); + if (!owner) { + return; + } + nsCOMPtr<nsIDOMElement> element = do_QueryInterface(owner); + if (!element) { + return; + } + fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE | + nsIFocusManager::FLAG_BYTOUCH | + nsIFocusManager::FLAG_NOSCROLL); +} + +void +RenderFrameParent::EnsureLayersConnected() +{ + RefPtr<LayerManager> lm = GetFrom(mFrameLoader); + if (!lm) { + return; + } + + ClientLayerManager* client = lm->AsClientLayerManager(); + if (!client) { + return; + } + + client->GetRemoteRenderer()->SendNotifyChildRecreated(mLayersId); +} + +} // namespace layout +} // namespace mozilla + +nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder, + nsSubDocumentFrame* aFrame, + RenderFrameParent* aRemoteFrame) + : nsDisplayItem(aBuilder, aFrame) + , mRemoteFrame(aRemoteFrame) + , mEventRegionsOverride(EventRegionsOverride::NoOverride) +{ + if (aBuilder->IsBuildingLayerEventRegions()) { + bool frameIsPointerEventsNone = + aFrame->StyleUserInterface()->GetEffectivePointerEvents(aFrame) == + NS_STYLE_POINTER_EVENTS_NONE; + if (aBuilder->IsInsidePointerEventsNoneDoc() || frameIsPointerEventsNone) { + mEventRegionsOverride |= EventRegionsOverride::ForceEmptyHitRegion; + } + if (nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(aFrame->PresContext()->PresShell())) { + mEventRegionsOverride |= EventRegionsOverride::ForceDispatchToContent; + } + } +} + +already_AddRefed<Layer> +nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) +{ + int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); + nsIntRect visibleRect = GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel); + visibleRect += aContainerParameters.mOffset; + RefPtr<Layer> layer = mRemoteFrame->BuildLayer(aBuilder, mFrame, aManager, visibleRect, this, aContainerParameters); + if (layer && layer->AsContainerLayer()) { + layer->AsContainerLayer()->SetEventRegionsOverride(mEventRegionsOverride); + } + return layer.forget(); +} |