diff options
Diffstat (limited to 'layout/ipc')
-rw-r--r-- | layout/ipc/PRenderFrame.ipdl | 37 | ||||
-rw-r--r-- | layout/ipc/PVsync.ipdl | 42 | ||||
-rw-r--r-- | layout/ipc/RenderFrameChild.cpp | 35 | ||||
-rw-r--r-- | layout/ipc/RenderFrameChild.h | 33 | ||||
-rw-r--r-- | layout/ipc/RenderFrameParent.cpp | 368 | ||||
-rw-r--r-- | layout/ipc/RenderFrameParent.h | 161 | ||||
-rw-r--r-- | layout/ipc/VsyncChild.cpp | 94 | ||||
-rw-r--r-- | layout/ipc/VsyncChild.h | 62 | ||||
-rw-r--r-- | layout/ipc/VsyncParent.cpp | 121 | ||||
-rw-r--r-- | layout/ipc/VsyncParent.h | 56 | ||||
-rw-r--r-- | layout/ipc/moz.build | 41 |
11 files changed, 1050 insertions, 0 deletions
diff --git a/layout/ipc/PRenderFrame.ipdl b/layout/ipc/PRenderFrame.ipdl new file mode 100644 index 000000000..3a1a47fe0 --- /dev/null +++ b/layout/ipc/PRenderFrame.ipdl @@ -0,0 +1,37 @@ +/* -*- 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 protocol PBrowser; +include protocol PLayerTransaction; + + +using class nsRegion from "nsRegion.h"; + +namespace mozilla { +namespace layout { + +/** + * PRenderFrame (in the layout sense of "frame") represents one web + * "page". It's used to graft content processes' layer trees into + * chrome's rendering path. The lifetime of a PRenderFrame is tied to + * its PresShell in the child process. + * + * The child process conceptually "owns" a PRenderFrame, because it + * only makes sense wrt documents loaded by the child. + */ +sync protocol PRenderFrame +{ + manager PBrowser; + +parent: + async NotifyCompositorTransaction(); + + async __delete__(); +}; + +} // namespace layout +} // namespace mozilla diff --git a/layout/ipc/PVsync.ipdl b/layout/ipc/PVsync.ipdl new file mode 100644 index 000000000..5d31e34d4 --- /dev/null +++ b/layout/ipc/PVsync.ipdl @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 protocol PBackground; + +using class mozilla::TimeStamp from "mozilla/TimeStamp.h"; + +namespace mozilla { +namespace layout { + +/* + * The PVsync is a sub-protocol in PBackground and it is used to notify + * the vsync event from chrome to content process. It also provides the + * interfaces for content to observe/unobserve vsync event notifications. + */ +async protocol PVsync +{ + manager PBackground; + +child: + // Send vsync event from chrome to content process. + async Notify(TimeStamp aVsyncTimestamp) compress; + + // Send the vsync rate to the content process. + async VsyncRate(float aVsyncRate); + +parent: + // Content process use these messages to acquire the vsync event. + async Observe(); + async Unobserve(); + async RequestVsyncRate(); + + // This message is never sent. Each PVsync actor will stay alive as long as + // its PBackground manager. + async __delete__(); +}; + +} // namespace layout +} // namespace mozilla + diff --git a/layout/ipc/RenderFrameChild.cpp b/layout/ipc/RenderFrameChild.cpp new file mode 100644 index 000000000..72225abc0 --- /dev/null +++ b/layout/ipc/RenderFrameChild.cpp @@ -0,0 +1,35 @@ +/* -*- 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 "RenderFrameChild.h" +#include "mozilla/layers/LayerTransactionChild.h" + +using mozilla::layers::PLayerTransactionChild; +using mozilla::layers::LayerTransactionChild; + +namespace mozilla { +namespace layout { + +void +RenderFrameChild::ActorDestroy(ActorDestroyReason why) +{ + mWasDestroyed = true; +} + +void +RenderFrameChild::Destroy() +{ + if (mWasDestroyed) { + return; + } + + Send__delete__(this); + // WARNING: |this| is dead, hands off +} + +} // namespace layout +} // namespace mozilla diff --git a/layout/ipc/RenderFrameChild.h b/layout/ipc/RenderFrameChild.h new file mode 100644 index 000000000..059f54a65 --- /dev/null +++ b/layout/ipc/RenderFrameChild.h @@ -0,0 +1,33 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_RenderFrameChild_h +#define mozilla_dom_RenderFrameChild_h + +#include "mozilla/layout/PRenderFrameChild.h" + +namespace mozilla { +namespace layout { + +class RenderFrameChild : public PRenderFrameChild +{ +public: + RenderFrameChild() : mWasDestroyed(false) {} + virtual ~RenderFrameChild() {} + + void ActorDestroy(ActorDestroyReason why) override; + + void Destroy(); + +private: + bool mWasDestroyed; +}; + +} // namespace layout +} // namespace mozilla + +#endif // mozilla_dom_RenderFrameChild_h 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(); +} diff --git a/layout/ipc/RenderFrameParent.h b/layout/ipc/RenderFrameParent.h new file mode 100644 index 000000000..274f8ff6d --- /dev/null +++ b/layout/ipc/RenderFrameParent.h @@ -0,0 +1,161 @@ +/* -*- 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/. */ + +#ifndef mozilla_layout_RenderFrameParent_h +#define mozilla_layout_RenderFrameParent_h + +#include "mozilla/Attributes.h" +#include <map> + +#include "mozilla/layers/APZUtils.h" +#include "mozilla/layers/LayersTypes.h" +#include "mozilla/layout/PRenderFrameParent.h" +#include "nsDisplayList.h" + +class nsFrameLoader; +class nsSubDocumentFrame; + +namespace mozilla { + +class InputEvent; + +namespace layers { +class AsyncDragMetrics; +class TargetConfig; +struct TextureFactoryIdentifier; +struct ScrollableLayerGuid; +} // namespace layers + +namespace layout { + +class RenderFrameParent : public PRenderFrameParent +{ + typedef mozilla::layers::AsyncDragMetrics AsyncDragMetrics; + typedef mozilla::layers::FrameMetrics FrameMetrics; + typedef mozilla::layers::ContainerLayer ContainerLayer; + typedef mozilla::layers::Layer Layer; + typedef mozilla::layers::LayerManager LayerManager; + typedef mozilla::layers::TargetConfig TargetConfig; + typedef mozilla::ContainerLayerParameters ContainerLayerParameters; + typedef mozilla::layers::TextureFactoryIdentifier TextureFactoryIdentifier; + typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid; + typedef mozilla::layers::TouchBehaviorFlags TouchBehaviorFlags; + typedef mozilla::layers::ZoomConstraints ZoomConstraints; + typedef FrameMetrics::ViewID ViewID; + +public: + + + /** + * Select the desired scrolling behavior. If ASYNC_PAN_ZOOM is + * chosen, then RenderFrameParent will watch input events and use + * them to asynchronously pan and zoom. + */ + RenderFrameParent(nsFrameLoader* aFrameLoader, bool* aSuccess); + virtual ~RenderFrameParent(); + + bool Init(nsFrameLoader* aFrameLoader); + bool IsInitted(); + void Destroy(); + + void BuildDisplayList(nsDisplayListBuilder* aBuilder, + nsSubDocumentFrame* aFrame, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists); + + already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, + LayerManager* aManager, + const nsIntRect& aVisibleRect, + nsDisplayItem* aItem, + const ContainerLayerParameters& aContainerParameters); + + void OwnerContentChanged(nsIContent* aContent); + + bool HitTest(const nsRect& aRect); + + void GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier); + + inline uint64_t GetLayersId() { return mLayersId; } + + void TakeFocusForClickFromTap(); + + void EnsureLayersConnected(); + +protected: + void ActorDestroy(ActorDestroyReason why) override; + + virtual bool RecvNotifyCompositorTransaction() override; + +private: + void TriggerRepaint(); + void DispatchEventForPanZoomController(const InputEvent& aEvent); + + uint64_t GetLayerTreeId() const; + + // 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; + + 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. + // It's still OK to *tell* the frame loader that we've painted after + // it's destroyed; it'll just ignore us, and we won't be able to + // find an nsIFrame to invalidate. See ShadowLayersUpdated(). + // + // Prefer the extra bit of state to null'ing out mFrameLoader in + // Destroy() so that less code needs to be special-cased for after + // Destroy(). + // + // It's possible for mFrameLoader==null and + // mFrameLoaderDestroyed==false. + bool mFrameLoaderDestroyed; + + bool mAsyncPanZoomEnabled; + bool mInitted; +}; + +} // namespace layout +} // namespace mozilla + +/** + * A DisplayRemote exists solely to graft a child process's shadow + * layer tree (for a given RenderFrameParent) into its parent + * process's layer tree. + */ +class nsDisplayRemote : public nsDisplayItem +{ + typedef mozilla::layout::RenderFrameParent RenderFrameParent; + +public: + nsDisplayRemote(nsDisplayListBuilder* aBuilder, nsSubDocumentFrame* aFrame, + RenderFrameParent* aRemoteFrame); + + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override + { return mozilla::LAYER_ACTIVE_FORCE; } + + virtual already_AddRefed<Layer> + BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + + NS_DISPLAY_DECL_NAME("Remote", TYPE_REMOTE) + +private: + RenderFrameParent* mRemoteFrame; + mozilla::layers::EventRegionsOverride mEventRegionsOverride; +}; + + +#endif // mozilla_layout_RenderFrameParent_h diff --git a/layout/ipc/VsyncChild.cpp b/layout/ipc/VsyncChild.cpp new file mode 100644 index 000000000..45372b89a --- /dev/null +++ b/layout/ipc/VsyncChild.cpp @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "VsyncChild.h" + +#include "mozilla/VsyncDispatcher.h" +#include "nsThreadUtils.h" + +namespace mozilla { +namespace layout { + +VsyncChild::VsyncChild() + : mObservingVsync(false) + , mIsShutdown(false) + , mVsyncRate(TimeDuration::Forever()) +{ + MOZ_ASSERT(NS_IsMainThread()); +} + +VsyncChild::~VsyncChild() +{ + MOZ_ASSERT(NS_IsMainThread()); +} + +bool +VsyncChild::SendObserve() +{ + MOZ_ASSERT(NS_IsMainThread()); + if (!mObservingVsync && !mIsShutdown) { + mObservingVsync = true; + PVsyncChild::SendObserve(); + } + return true; +} + +bool +VsyncChild::SendUnobserve() +{ + MOZ_ASSERT(NS_IsMainThread()); + if (mObservingVsync && !mIsShutdown) { + mObservingVsync = false; + PVsyncChild::SendUnobserve(); + } + return true; +} + +void +VsyncChild::ActorDestroy(ActorDestroyReason aActorDestroyReason) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mIsShutdown); + mIsShutdown = true; + mObserver = nullptr; +} + +bool +VsyncChild::RecvNotify(const TimeStamp& aVsyncTimestamp) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mIsShutdown); + if (mObservingVsync && mObserver) { + mObserver->NotifyVsync(aVsyncTimestamp); + } + return true; +} + +void +VsyncChild::SetVsyncObserver(VsyncObserver* aVsyncObserver) +{ + MOZ_ASSERT(NS_IsMainThread()); + mObserver = aVsyncObserver; +} + +TimeDuration +VsyncChild::GetVsyncRate() +{ + if (mVsyncRate == TimeDuration::Forever()) { + PVsyncChild::SendRequestVsyncRate(); + } + + return mVsyncRate; +} + +bool +VsyncChild::RecvVsyncRate(const float& aVsyncRate) +{ + mVsyncRate = TimeDuration::FromMilliseconds(aVsyncRate); + return true; +} + +} // namespace layout +} // namespace mozilla diff --git a/layout/ipc/VsyncChild.h b/layout/ipc/VsyncChild.h new file mode 100644 index 000000000..88896d643 --- /dev/null +++ b/layout/ipc/VsyncChild.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#ifndef mozilla_layout_ipc_VsyncChild_h +#define mozilla_layout_ipc_VsyncChild_h + +#include "mozilla/layout/PVsyncChild.h" +#include "nsISupportsImpl.h" +#include "mozilla/RefPtr.h" + +namespace mozilla { + +class VsyncObserver; + +namespace ipc { +class BackgroundChildImpl; +} // namespace ipc + +namespace layout { + +// The PVsyncChild actor receives a vsync event from the main process and +// delivers it to the child process. Currently this is restricted to the main +// thread only. The actor will stay alive until the process dies or its +// PVsyncParent actor dies. +class VsyncChild final : public PVsyncChild +{ + NS_INLINE_DECL_REFCOUNTING(VsyncChild) + + friend class mozilla::ipc::BackgroundChildImpl; + +public: + // Hide the SendObserve/SendUnobserve in PVsyncChild. We add an flag + // mObservingVsync to handle the race problem of unobserving vsync event. + bool SendObserve(); + bool SendUnobserve(); + + // Bind a VsyncObserver into VsyncChild after ipc channel connected. + void SetVsyncObserver(VsyncObserver* aVsyncObserver); + TimeDuration GetVsyncRate(); + +private: + VsyncChild(); + virtual ~VsyncChild(); + + virtual bool RecvNotify(const TimeStamp& aVsyncTimestamp) override; + virtual bool RecvVsyncRate(const float& aVsyncRate) override; + virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) override; + + bool mObservingVsync; + bool mIsShutdown; + + // The content side vsync observer. + RefPtr<VsyncObserver> mObserver; + TimeDuration mVsyncRate; +}; + +} // namespace layout +} // namespace mozilla + +#endif // mozilla_layout_ipc_VsyncChild_h diff --git a/layout/ipc/VsyncParent.cpp b/layout/ipc/VsyncParent.cpp new file mode 100644 index 000000000..8ffe8abc4 --- /dev/null +++ b/layout/ipc/VsyncParent.cpp @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "VsyncParent.h" + +#include "BackgroundParent.h" +#include "BackgroundParentImpl.h" +#include "gfxPlatform.h" +#include "mozilla/Unused.h" +#include "nsIThread.h" +#include "nsThreadUtils.h" +#include "VsyncSource.h" + +namespace mozilla { + +using namespace ipc; + +namespace layout { + +/*static*/ already_AddRefed<VsyncParent> +VsyncParent::Create() +{ + AssertIsOnBackgroundThread(); + RefPtr<gfx::VsyncSource> vsyncSource = gfxPlatform::GetPlatform()->GetHardwareVsync(); + RefPtr<VsyncParent> vsyncParent = new VsyncParent(); + vsyncParent->mVsyncDispatcher = vsyncSource->GetRefreshTimerVsyncDispatcher(); + return vsyncParent.forget(); +} + +VsyncParent::VsyncParent() + : mObservingVsync(false) + , mDestroyed(false) + , mBackgroundThread(NS_GetCurrentThread()) +{ + MOZ_ASSERT(mBackgroundThread); + AssertIsOnBackgroundThread(); +} + +VsyncParent::~VsyncParent() +{ + // Since we use NS_INLINE_DECL_THREADSAFE_REFCOUNTING, we can't make sure + // VsyncParent is always released on the background thread. +} + +bool +VsyncParent::NotifyVsync(TimeStamp aTimeStamp) +{ + // Called on hardware vsync thread. We should post to current ipc thread. + MOZ_ASSERT(!IsOnBackgroundThread()); + nsCOMPtr<nsIRunnable> vsyncEvent = + NewRunnableMethod<TimeStamp>(this, + &VsyncParent::DispatchVsyncEvent, + aTimeStamp); + MOZ_ALWAYS_SUCCEEDS(mBackgroundThread->Dispatch(vsyncEvent, NS_DISPATCH_NORMAL)); + return true; +} + +void +VsyncParent::DispatchVsyncEvent(TimeStamp aTimeStamp) +{ + AssertIsOnBackgroundThread(); + + // If we call NotifyVsync() when we handle ActorDestroy() message, we might + // still call DispatchVsyncEvent(). + // Similarly, we might also receive RecvUnobserveVsync() when call + // NotifyVsync(). We use mObservingVsync and mDestroyed flags to skip this + // notification. + if (mObservingVsync && !mDestroyed) { + Unused << SendNotify(aTimeStamp); + } +} + +bool +VsyncParent::RecvRequestVsyncRate() +{ + AssertIsOnBackgroundThread(); + TimeDuration vsyncRate = gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate(); + Unused << SendVsyncRate(vsyncRate.ToMilliseconds()); + return true; +} + +bool +VsyncParent::RecvObserve() +{ + AssertIsOnBackgroundThread(); + if (!mObservingVsync) { + mVsyncDispatcher->AddChildRefreshTimer(this); + mObservingVsync = true; + return true; + } + return false; +} + +bool +VsyncParent::RecvUnobserve() +{ + AssertIsOnBackgroundThread(); + if (mObservingVsync) { + mVsyncDispatcher->RemoveChildRefreshTimer(this); + mObservingVsync = false; + return true; + } + return false; +} + +void +VsyncParent::ActorDestroy(ActorDestroyReason aReason) +{ + MOZ_ASSERT(!mDestroyed); + AssertIsOnBackgroundThread(); + if (mObservingVsync) { + mVsyncDispatcher->RemoveChildRefreshTimer(this); + } + mVsyncDispatcher = nullptr; + mDestroyed = true; +} + +} // namespace layout +} // namespace mozilla diff --git a/layout/ipc/VsyncParent.h b/layout/ipc/VsyncParent.h new file mode 100644 index 000000000..33e96c4c6 --- /dev/null +++ b/layout/ipc/VsyncParent.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#ifndef mozilla_layout_ipc_VsyncParent_h +#define mozilla_layout_ipc_VsyncParent_h + +#include "mozilla/layout/PVsyncParent.h" +#include "mozilla/VsyncDispatcher.h" +#include "nsCOMPtr.h" +#include "mozilla/RefPtr.h" + +class nsIThread; + +namespace mozilla { + +namespace ipc { +class BackgroundParentImpl; +} // namespace ipc + +namespace layout { + +// Use PBackground thread in the main process to send vsync notifications to +// content process. This actor will be released when its parent protocol calls +// DeallocPVsyncParent(). +class VsyncParent final : public PVsyncParent, + public VsyncObserver +{ + friend class mozilla::ipc::BackgroundParentImpl; + +private: + static already_AddRefed<VsyncParent> Create(); + + VsyncParent(); + virtual ~VsyncParent(); + + virtual bool NotifyVsync(TimeStamp aTimeStamp) override; + virtual bool RecvRequestVsyncRate() override; + + virtual bool RecvObserve() override; + virtual bool RecvUnobserve() override; + virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) override; + + void DispatchVsyncEvent(TimeStamp aTimeStamp); + + bool mObservingVsync; + bool mDestroyed; + nsCOMPtr<nsIThread> mBackgroundThread; + RefPtr<RefreshTimerVsyncDispatcher> mVsyncDispatcher; +}; + +} // namespace layout +} // namespace mozilla + +#endif //mozilla_layout_ipc_VsyncParent_h diff --git a/layout/ipc/moz.build b/layout/ipc/moz.build new file mode 100644 index 000000000..d9cf962ca --- /dev/null +++ b/layout/ipc/moz.build @@ -0,0 +1,41 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +with Files('**'): + BUG_COMPONENT = ('Core', 'Layout: View Rendering') + +EXPORTS.mozilla.layout += [ + 'RenderFrameChild.h', + 'RenderFrameParent.h', + 'VsyncChild.h', + 'VsyncParent.h', +] + +UNIFIED_SOURCES += [ + 'RenderFrameChild.cpp', + 'RenderFrameParent.cpp', +] + +SOURCES += [ + 'VsyncChild.cpp', + 'VsyncParent.cpp', +] + +IPDL_SOURCES = [ + 'PRenderFrame.ipdl', + 'PVsync.ipdl', +] + +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul' + +LOCAL_INCLUDES += [ + '/dom/base', + '/layout/base', + '/layout/generic', + '/layout/xul', +] |