From 4e8832c9dddfb987b4fb7e2fef4370f2c10df85f Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Wed, 27 Aug 2014 22:13:41 -0400 Subject: [PATCH] Bug 1055760 - Add a LayerMetricsWrapper and fix up APZCTreeManager FrameMetrics accessing. r=botond,BenWa --- gfx/layers/FrameMetrics.h | 1 + gfx/layers/LayerMetricsWrapper.h | 299 +++++++++++++++++++++++++ gfx/layers/Layers.cpp | 1 + gfx/layers/Layers.h | 3 +- gfx/layers/apz/src/APZCTreeManager.cpp | 39 ++-- gfx/layers/apz/src/APZCTreeManager.h | 6 +- gfx/layers/moz.build | 1 + 7 files changed, 329 insertions(+), 21 deletions(-) create mode 100644 gfx/layers/LayerMetricsWrapper.h diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index b1e9813628c6..bcf5e43b73f6 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -71,6 +71,7 @@ public: static const ViewID NULL_SCROLL_ID; // This container layer does not scroll. static const ViewID START_SCROLL_ID = 2; // This is the ID that scrolling subframes // will begin at. + static const FrameMetrics sNullMetrics; // We often need an empty metrics FrameMetrics() : mCompositionBounds(0, 0, 0, 0) diff --git a/gfx/layers/LayerMetricsWrapper.h b/gfx/layers/LayerMetricsWrapper.h new file mode 100644 index 000000000000..7b705b2f0409 --- /dev/null +++ b/gfx/layers/LayerMetricsWrapper.h @@ -0,0 +1,299 @@ +/* -*- 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 GFX_LAYERMETRICSWRAPPER_H +#define GFX_LAYERMETRICSWRAPPER_H + +#include "Layers.h" + +namespace mozilla { +namespace layers { + +/** + * A wrapper class around a target Layer with that allows user code to + * walk through the FrameMetrics objects on the layer the same way it + * would walk through a ContainerLayer hierarchy. Consider the following + * layer tree: + * + * +---+ + * | A | + * +---+ + * / | \ + * / | \ + * / | \ + * +---+ +-----+ +---+ + * | B | | C | | D | + * +---+ +-----+ +---+ + * | FMn | + * | . | + * | . | + * | . | + * | FM1 | + * | FM0 | + * +-----+ + * / \ + * / \ + * +---+ +---+ + * | E | | F | + * +---+ +---+ + * + * In this layer tree, there are six layers with A being the root and B,D,E,F + * being leaf nodes. Layer C is in the middle and has n+1 FrameMetrics, labelled + * FM0...FMn. FM0 is the FrameMetrics you get by calling c->GetFrameMetrics(0) + * and FMn is the FrameMetrics you can obtain by calling + * c->GetFrameMetrics(c->GetFrameMetricsCount() - 1). This layer tree is + * conceptually equivalent to this one below: + * + * +---+ + * | A | + * +---+ + * / | \ + * / | \ + * / | \ + * +---+ +-----+ +---+ + * | B | | Cn | | D | + * +---+ +-----+ +---+ + * | + * . + * . + * . + * | + * +-----+ + * | C1 | + * +-----+ + * | + * +-----+ + * | C0 | + * +-----+ + * / \ + * / \ + * +---+ +---+ + * | E | | F | + * +---+ +---+ + * + * In this layer tree, the layer C has been expanded into a stack of container + * layers C1...Cn, where C1 has FrameMetrics FM1 and Cn has FrameMetrics Fn. + * Although in this example C (in the first layer tree) and C0 (in the second + * layer tree) are both ContainerLayers (because they have children), they + * do not have to be. They may just be ThebesLayers or ColorLayers, for example, + * which do not have any children. However, the type of C will always be the + * same as the type of C0. + * + * The LayerMetricsWrapper class allows client code to treat the first layer + * tree as though it were the second. That is, instead of client code having + * to iterate through the FrameMetrics objects directly, it can use a + * LayerMetricsWrapper to encapsulate that aspect of the layer tree and just + * walk the tree as if it were a stack of ContainerLayers. + * + * The functions on this class do different things depending on which + * simulated ContainerLayer is being wrapped. For example, if the + * LayerMetricsWrapper is pretending to be C0, the GetNextSibling() function + * will return null even though the underlying layer C does actually have + * a next sibling. The LayerMetricsWrapper pretending to be Cn will return + * D as the next sibling. + * + * Implementation notes: + * + * The AtTopLayer() and AtBottomLayer() functions in this class refer to + * Cn and C0 in the second layer tree above; that is, they are predicates + * to test if the LayerMetricsWrapper is simulating the topmost or bottommost + * layer, as those will have special behaviour. + * + * It is possible to wrap a nullptr in a LayerMetricsWrapper, in which case + * the IsValid() function will return false. This is required to allow + * LayerMetricsWrapper to be a MOZ_STACK_CLASS (desirable because it is used + * in loops and recursion). + * + * This class purposely does not expose the wrapped layer directly to avoid + * user code from accidentally calling functions directly on it. Instead + * any necessary functions should be wrapped in this class. It does expose + * the wrapped layer as a void* for printf purposes. + * + * The implementation may look like it special-cases mIndex == 0 and/or + * GetFrameMetricsCount() == 0. This is an artifact of the fact that both + * mIndex and GetFrameMetricsCount() are uint32_t and GetFrameMetricsCount() + * can return 0 but mIndex cannot store -1. This seems better than the + * alternative of making mIndex a int32_t that can store -1, but then having + * to cast to uint32_t all over the place. + */ +class MOZ_STACK_CLASS LayerMetricsWrapper { +public: + LayerMetricsWrapper() + : mLayer(nullptr) + , mIndex(0) + { + } + + explicit LayerMetricsWrapper(Layer* aRoot) + : mLayer(aRoot) + , mIndex(0) + { + if (!mLayer) { + return; + } + + mIndex = mLayer->GetFrameMetricsCount(); + if (mIndex > 0) { + mIndex--; + } + } + + explicit LayerMetricsWrapper(Layer* aLayer, uint32_t aMetricsIndex) + : mLayer(aLayer) + , mIndex(aMetricsIndex) + { + MOZ_ASSERT(mLayer); + MOZ_ASSERT(mIndex == 0 || mIndex < mLayer->GetFrameMetricsCount()); + } + + bool IsValid() const + { + return mLayer != nullptr; + } + + MOZ_EXPLICIT_CONVERSION operator bool() const + { + return IsValid(); + } + + LayerMetricsWrapper GetLastChild() const + { + MOZ_ASSERT(IsValid()); + + if (!AtBottomLayer()) { + return LayerMetricsWrapper(mLayer, mIndex - 1); + } + return LayerMetricsWrapper(mLayer->GetLastChild()); + } + + LayerMetricsWrapper GetPrevSibling() const + { + MOZ_ASSERT(IsValid()); + + if (AtTopLayer()) { + return LayerMetricsWrapper(mLayer->GetPrevSibling()); + } + return LayerMetricsWrapper(nullptr); + } + + const FrameMetrics& Metrics() const + { + MOZ_ASSERT(IsValid()); + + if (mIndex >= mLayer->GetFrameMetricsCount()) { + return FrameMetrics::sNullMetrics; + } + return mLayer->GetFrameMetrics(mIndex); + } + + AsyncPanZoomController* GetApzc() const + { + MOZ_ASSERT(IsValid()); + + if (mIndex >= mLayer->GetFrameMetricsCount()) { + return nullptr; + } + return mLayer->GetAsyncPanZoomController(mIndex); + } + + void SetApzc(AsyncPanZoomController* aApzc) const + { + MOZ_ASSERT(IsValid()); + + if (mLayer->GetFrameMetricsCount() == 0) { + MOZ_ASSERT(mIndex == 0); + MOZ_ASSERT(aApzc == nullptr); + return; + } + MOZ_ASSERT(mIndex < mLayer->GetFrameMetricsCount()); + mLayer->SetAsyncPanZoomController(mIndex, aApzc); + } + + const char* Name() const + { + MOZ_ASSERT(IsValid()); + + if (AtBottomLayer()) { + return mLayer->Name(); + } + return "DummyContainerLayer"; + } + + gfx::Matrix4x4 GetTransform() const + { + MOZ_ASSERT(IsValid()); + + if (AtBottomLayer()) { + return mLayer->GetTransform(); + } + return gfx::Matrix4x4(); + } + + RefLayer* AsRefLayer() const + { + MOZ_ASSERT(IsValid()); + + if (AtBottomLayer()) { + return mLayer->AsRefLayer(); + } + return nullptr; + } + + nsIntRegion GetVisibleRegion() const + { + MOZ_ASSERT(IsValid()); + + if (AtBottomLayer()) { + return mLayer->GetVisibleRegion(); + } + nsIntRegion region = mLayer->GetVisibleRegion(); + region.Transform(gfx::To3DMatrix(mLayer->GetTransform())); + return region; + } + + const nsIntRect* GetClipRect() const + { + MOZ_ASSERT(IsValid()); + + return mLayer->GetClipRect(); + } + + const std::string& GetContentDescription() const + { + MOZ_ASSERT(IsValid()); + + return mLayer->GetContentDescription(); + } + + // Expose an opaque pointer to the layer. Mostly used for printf + // purposes. This is not intended to be a general-purpose accessor + // for the underlying layer. + const void* GetLayer() const + { + MOZ_ASSERT(IsValid()); + + return (void*)mLayer; + } + +private: + bool AtBottomLayer() const + { + return mIndex == 0; + } + + bool AtTopLayer() const + { + return mLayer->GetFrameMetricsCount() == 0 || mIndex == mLayer->GetFrameMetricsCount() - 1; + } + +private: + Layer* mLayer; + uint32_t mIndex; +}; + +} +} + +#endif /* GFX_LAYERMETRICSWRAPPER_H */ diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index c00822baf8d7..dc4e8869d7d5 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -47,6 +47,7 @@ FILEOrDefault(FILE* aFile) typedef FrameMetrics::ViewID ViewID; const ViewID FrameMetrics::NULL_SCROLL_ID = 0; +const FrameMetrics FrameMetrics::sNullMetrics; using namespace mozilla::gfx; diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 36423c2b4aeb..3acd11226bb2 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -841,7 +841,8 @@ public: * nested scrolling subdocuments. In general a Layer having multiple * FrameMetrics objects is conceptually equivalent to having a stack * of ContainerLayers that have been flattened into this Layer. - * (A pointer to additional documentation will arrive in a future patch.) + * See the documentation in LayerMetricsWrapper.h for a more detailed + * explanation of this conceptual equivalence. * * Note also that there is actually a many-to-many relationship between * Layers and FrameMetrics, because multiple Layers may have identical diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 57a687e0cfc1..2d8ca4991613 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -12,6 +12,7 @@ #include "mozilla/gfx/Point.h" // for Point #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform #include "mozilla/layers/AsyncPanZoomController.h" +#include "mozilla/layers/LayerMetricsWrapper.h" #include "mozilla/MouseEvents.h" #include "mozilla/mozalloc.h" // for operator new #include "mozilla/TouchEvents.h" @@ -160,7 +161,8 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor, if (aRoot) { mApzcTreeLog << "[start]\n"; - UpdatePanZoomControllerTree(state, aRoot, + LayerMetricsWrapper root(aRoot); + UpdatePanZoomControllerTree(state, root, // aCompositor is null in gtest scenarios aCompositor ? aCompositor->RootLayerTreeId() : 0, Matrix4x4(), nullptr, nullptr, nsIntRegion()); @@ -205,7 +207,7 @@ ComputeTouchSensitiveRegion(GeckoContentController* aController, } AsyncPanZoomController* -APZCTreeManager::PrepareAPZCForLayer(const Layer* aLayer, +APZCTreeManager::PrepareAPZCForLayer(const LayerMetricsWrapper& aLayer, const FrameMetrics& aMetrics, uint64_t aLayersId, const gfx::Matrix4x4& aAncestorTransform, @@ -237,13 +239,13 @@ APZCTreeManager::PrepareAPZCForLayer(const Layer* aLayer, if (!insertResult.second) { apzc = insertResult.first->second; } - APZCTM_LOG("Found APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer, guid.mLayersId, guid.mScrollId); + APZCTM_LOG("Found APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer.GetLayer(), guid.mLayersId, guid.mScrollId); // If we haven't encountered a layer already with the same metrics, then we need to // do the full reuse-or-make-an-APZC algorithm, which is contained inside the block // below. if (apzc == nullptr) { - apzc = aLayer->GetAsyncPanZoomController(); + apzc = aLayer.GetApzc(); // If the content represented by the scrollable layer has changed (which may // be possible because of DLBI heuristics) then we don't want to keep using @@ -290,7 +292,7 @@ APZCTreeManager::PrepareAPZCForLayer(const Layer* aLayer, apzc->SetPrevSibling(nullptr); apzc->SetLastChild(nullptr); } - APZCTM_LOG("Using APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer, aLayersId, aMetrics.GetScrollId()); + APZCTM_LOG("Using APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer.GetLayer(), aLayersId, aMetrics.GetScrollId()); apzc->NotifyLayersUpdated(aMetrics, aState.mIsFirstPaint && (aLayersId == aState.mOriginatingLayersId)); @@ -303,9 +305,9 @@ APZCTreeManager::PrepareAPZCForLayer(const Layer* aLayer, mApzcTreeLog << "APZC " << guid << "\tcb=" << aMetrics.mCompositionBounds << "\tsr=" << aMetrics.mScrollableRect - << (aLayer->GetVisibleRegion().IsEmpty() ? "\tscrollinfo" : "") + << (aLayer.GetVisibleRegion().IsEmpty() ? "\tscrollinfo" : "") << (apzc->HasScrollgrab() ? "\tscrollgrab" : "") - << "\t" << aLayer->GetContentDescription(); + << "\t" << aLayer.GetContentDescription(); // Bind the APZC instance into the tree of APZCs if (aNextSibling) { @@ -376,7 +378,8 @@ APZCTreeManager::PrepareAPZCForLayer(const Layer* aLayer, AsyncPanZoomController* APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState, - Layer* aLayer, uint64_t aLayersId, + const LayerMetricsWrapper& aLayer, + uint64_t aLayersId, const gfx::Matrix4x4& aAncestorTransform, AsyncPanZoomController* aParent, AsyncPanZoomController* aNextSibling, @@ -384,12 +387,12 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState, { mTreeLock.AssertCurrentThreadOwns(); - mApzcTreeLog << aLayer->Name() << '\t'; + mApzcTreeLog << aLayer.Name() << '\t'; AsyncPanZoomController* apzc = PrepareAPZCForLayer(aLayer, - aLayer->GetFrameMetrics(), aLayersId, aAncestorTransform, + aLayer.Metrics(), aLayersId, aAncestorTransform, aObscured, aParent, aNextSibling, aState); - aLayer->SetAsyncPanZoomController(apzc); + aLayer.SetApzc(apzc); mApzcTreeLog << '\n'; @@ -400,13 +403,13 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState, // transform to layer L when we recurse into the children below. If we are at a layer // with an APZC, such as P, then we reset the ancestorTransform to just PC, to start // the new accumulation as we go down. - Matrix4x4 transform = aLayer->GetTransform(); + Matrix4x4 transform = aLayer.GetTransform(); Matrix4x4 ancestorTransform = transform; if (!apzc) { ancestorTransform = ancestorTransform * aAncestorTransform; } - uint64_t childLayersId = (aLayer->AsRefLayer() ? aLayer->AsRefLayer()->GetReferentId() : aLayersId); + uint64_t childLayersId = (aLayer.AsRefLayer() ? aLayer.AsRefLayer()->GetReferentId() : aLayersId); nsIntRegion obscured; if (aLayersId == childLayersId) { @@ -428,7 +431,7 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState, // If there's no APZC at this level, any APZCs for our child layers will // have our siblings as siblings. AsyncPanZoomController* next = apzc ? nullptr : aNextSibling; - for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) { + for (LayerMetricsWrapper child = aLayer.GetLastChild(); child; child = child.GetPrevSibling()) { gfx::TreeAutoIndent indent(mApzcTreeLog); next = UpdatePanZoomControllerTree(aState, child, childLayersId, ancestorTransform, aParent, next, @@ -436,10 +439,10 @@ APZCTreeManager::UpdatePanZoomControllerTree(TreeBuildingState& aState, // Each layer obscures its previous siblings, so we augment the obscured // region as we loop backwards through the children. - nsIntRegion childRegion = child->GetVisibleRegion(); - childRegion.Transform(gfx::To3DMatrix(child->GetTransform())); - if (child->GetClipRect()) { - childRegion.AndWith(*child->GetClipRect()); + nsIntRegion childRegion = child.GetVisibleRegion(); + childRegion.Transform(gfx::To3DMatrix(child.GetTransform())); + if (child.GetClipRect()) { + childRegion.AndWith(*child.GetClipRect()); } obscured.OrWith(childRegion); diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index a2f3beb25704..01d02410cd2c 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -44,6 +44,7 @@ class AsyncPanZoomController; class CompositorParent; class APZPaintLogHelper; class OverscrollHandoffChain; +class LayerMetricsWrapper; /** * ****************** NOTE ON LOCK ORDERING IN APZ ************************** @@ -378,7 +379,7 @@ private: void UpdateZoomConstraintsRecursively(AsyncPanZoomController* aApzc, const ZoomConstraints& aConstraints); - AsyncPanZoomController* PrepareAPZCForLayer(const Layer* aLayer, + AsyncPanZoomController* PrepareAPZCForLayer(const LayerMetricsWrapper& aLayer, const FrameMetrics& aMetrics, uint64_t aLayersId, const gfx::Matrix4x4& aAncestorTransform, @@ -397,7 +398,8 @@ private: * code. */ AsyncPanZoomController* UpdatePanZoomControllerTree(TreeBuildingState& aState, - Layer* aLayer, uint64_t aLayersId, + const LayerMetricsWrapper& aLayer, + uint64_t aLayersId, const gfx::Matrix4x4& aAncestorTransform, AsyncPanZoomController* aParent, AsyncPanZoomController* aNextSibling, diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 85b25b9a90f4..285c0c050f0c 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -163,6 +163,7 @@ EXPORTS.mozilla.layers += [ 'ipc/SharedBufferManagerParent.h', 'ipc/SharedPlanarYCbCrImage.h', 'ipc/SharedRGBImage.h', + 'LayerMetricsWrapper.h', 'LayersTypes.h', 'opengl/CompositingRenderTargetOGL.h', 'opengl/CompositorOGL.h',