Bug 1055760 - Add a LayerMetricsWrapper and fix up APZCTreeManager FrameMetrics accessing. r=botond,BenWa

This commit is contained in:
Kartikaya Gupta 2014-08-27 22:13:41 -04:00
parent 23cccb3b33
commit 4e8832c9dd
7 changed files with 329 additions and 21 deletions

View File

@ -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)

View File

@ -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 */

View File

@ -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;

View File

@ -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

View File

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

View File

@ -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,

View File

@ -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',