Bug 1227233: Increase scope of TreeTraversal.h to by-value traversal r=botond

MozReview-Commit-ID: LOw1k792T10

--HG--
extra : rebase_source : a81ac06686bc21ed69693a3a80551e0648a8299a
This commit is contained in:
Kevin Wern 2016-09-22 12:31:26 -04:00
parent 8f2b2148c6
commit 16d7a2302e
6 changed files with 169 additions and 181 deletions

View File

@ -643,7 +643,10 @@ public:
}
void IncreaseIndent() { ++mDepth; }
void DecreaseIndent() { --mDepth; }
void DecreaseIndent() {
MOZ_ASSERT(mDepth > 0);
--mDepth;
}
void ConditionOnPrefFunction(bool(*aPrefFunction)()) {
mConditionedOnPref = true;
@ -681,6 +684,14 @@ public:
explicit TreeAutoIndent(TreeLog& aTreeLog) : mTreeLog(aTreeLog) {
mTreeLog.IncreaseIndent();
}
TreeAutoIndent(const TreeAutoIndent& aTreeAutoIndent) :
TreeAutoIndent(aTreeAutoIndent.mTreeLog) {
mTreeLog.IncreaseIndent();
}
TreeAutoIndent& operator=(const TreeAutoIndent& aTreeAutoIndent) = delete;
~TreeAutoIndent() {
mTreeLog.DecreaseIndent();
}

View File

@ -80,24 +80,20 @@ LayerManager::GetRootScrollableLayerId()
return FrameMetrics::NULL_SCROLL_ID;
}
nsTArray<LayerMetricsWrapper> queue = { LayerMetricsWrapper(mRoot) };
while (queue.Length()) {
LayerMetricsWrapper layer = queue[0];
queue.RemoveElementAt(0);
LayerMetricsWrapper layerMetricsRoot = LayerMetricsWrapper(mRoot);
const FrameMetrics& frameMetrics = layer.Metrics();
if (frameMetrics.IsScrollable()) {
return frameMetrics.GetScrollId();
}
LayerMetricsWrapper rootScrollableLayerMetrics =
BreadthFirstSearch<ForwardIterator>(
layerMetricsRoot,
[](LayerMetricsWrapper aLayerMetrics)
{
return aLayerMetrics.Metrics().IsScrollable();
}
);
LayerMetricsWrapper child = layer.GetFirstChild();
while (child) {
queue.AppendElement(child);
child = child.GetNextSibling();
}
}
return FrameMetrics::NULL_SCROLL_ID;
return rootScrollableLayerMetrics.IsValid() ?
rootScrollableLayerMetrics.Metrics().GetScrollId() :
FrameMetrics::NULL_SCROLL_ID;
}
void
@ -159,23 +155,14 @@ LayerManager::GetRootContentLayer()
return LayerMetricsWrapper();
}
nsTArray<Layer*> queue = { mRoot };
while (!queue.IsEmpty()) {
Layer* layer = queue[0];
queue.RemoveElementAt(0);
LayerMetricsWrapper root(mRoot);
for (uint32_t i = 0; i < layer->GetScrollMetadataCount(); i++) {
if (layer->GetFrameMetrics(i).IsRootContent()) {
return LayerMetricsWrapper(layer, i);
return BreadthFirstSearch<ForwardIterator>(root,
[](LayerMetricsWrapper aLayerMetrics)
{
return aLayerMetrics.Metrics().IsRootContent();
}
}
for (Layer* child = layer->GetFirstChild(); child; child = child->GetNextSibling()) {
queue.AppendElement(child);
}
}
return LayerMetricsWrapper();
);
}
already_AddRefed<DrawTarget>

View File

@ -34,25 +34,41 @@ enum class TraversalFlag { Skip, Continue, Abort };
class ForwardIterator
{
public:
template <typename Node>
static Node* FirstChild(Node* n) {
return n->GetFirstChild();
}
template <typename Node>
static Node* NextSibling(Node* n) {
return n->GetNextSibling();
}
template <typename Node>
static Node* FirstChild(Node* n) {
return n->GetFirstChild();
static Node FirstChild(Node n) {
return n.GetFirstChild();
}
template <typename Node>
static Node NextSibling(Node n) {
return n.GetNextSibling();
}
};
class ReverseIterator
{
public:
template <typename Node>
static Node* FirstChild(Node* n) {
return n->GetLastChild();
}
template <typename Node>
static Node* NextSibling(Node* n) {
return n->GetPrevSibling();
}
template <typename Node>
static Node* FirstChild(Node* n) {
return n->GetLastChild();
static Node FirstChild(Node n) {
return n.GetLastChild();
}
template <typename Node>
static Node NextSibling(Node n) {
return n.GetPrevSibling();
}
};
@ -65,13 +81,13 @@ class ReverseIterator
* is not performed.
*
* |Iterator| should have static methods named NextSibling() and FirstChild()
* that accept an argument of type Node*. For convenience, classes
* that accept an argument of type Node. For convenience, classes
* |ForwardIterator| and |ReverseIterator| are provided which implement these
* methods as GetNextSibling()/GetFirstChild() and GetPrevSibling()/GetLastChild(),
* respectively.
*/
template <typename Iterator, typename Node, typename PreAction, typename PostAction>
static auto ForEachNode(Node* aRoot, const PreAction& aPreAction, const PostAction& aPostAction) ->
static auto ForEachNode(Node aRoot, const PreAction& aPreAction, const PostAction& aPostAction) ->
typename EnableIf<IsSame<decltype(aPreAction(aRoot)), TraversalFlag>::value &&
IsSame<decltype(aPostAction(aRoot)),TraversalFlag>::value, bool>::Type
{
@ -86,7 +102,7 @@ typename EnableIf<IsSame<decltype(aPreAction(aRoot)), TraversalFlag>::value &&
}
if (result == TraversalFlag::Continue) {
for (Node* child = Iterator::FirstChild(aRoot);
for (Node child = Iterator::FirstChild(aRoot);
child;
child = Iterator::NextSibling(child)) {
bool abort = ForEachNode<Iterator>(child, aPreAction, aPostAction);
@ -110,7 +126,7 @@ typename EnableIf<IsSame<decltype(aPreAction(aRoot)), TraversalFlag>::value &&
* |aPreAction| before traversal of children and |aPostAction| after.
*/
template <typename Iterator, typename Node, typename PreAction, typename PostAction>
static auto ForEachNode(Node* aRoot, const PreAction& aPreAction, const PostAction& aPostAction) ->
static auto ForEachNode(Node aRoot, const PreAction& aPreAction, const PostAction& aPostAction) ->
typename EnableIf<IsSame<decltype(aPreAction(aRoot)), void>::value &&
IsSame<decltype(aPostAction(aRoot)),void>::value, void>::Type
{
@ -120,7 +136,7 @@ typename EnableIf<IsSame<decltype(aPreAction(aRoot)), void>::value &&
aPreAction(aRoot);
for (Node* child = Iterator::FirstChild(aRoot);
for (Node child = Iterator::FirstChild(aRoot);
child;
child = Iterator::NextSibling(child)) {
ForEachNode<Iterator>(child, aPreAction, aPostAction);
@ -133,40 +149,40 @@ typename EnableIf<IsSame<decltype(aPreAction(aRoot)), void>::value &&
* ForEachNode pre-order traversal, using TraversalFlag.
*/
template <typename Iterator, typename Node, typename PreAction>
auto ForEachNode(Node* aRoot, const PreAction& aPreAction) ->
auto ForEachNode(Node aRoot, const PreAction& aPreAction) ->
typename EnableIf<IsSame<decltype(aPreAction(aRoot)), TraversalFlag>::value, bool>::Type
{
return ForEachNode<Iterator>(aRoot, aPreAction, [](Node* aNode){ return TraversalFlag::Continue; });
return ForEachNode<Iterator>(aRoot, aPreAction, [](Node aNode){ return TraversalFlag::Continue; });
}
/*
* ForEachNode pre-order, not using TraversalFlag.
*/
template <typename Iterator, typename Node, typename PreAction>
auto ForEachNode(Node* aRoot, const PreAction& aPreAction) ->
auto ForEachNode(Node aRoot, const PreAction& aPreAction) ->
typename EnableIf<IsSame<decltype(aPreAction(aRoot)), void>::value, void>::Type
{
ForEachNode<Iterator>(aRoot, aPreAction, [](Node* aNode){});
ForEachNode<Iterator>(aRoot, aPreAction, [](Node aNode){});
}
/*
* ForEachNode post-order traversal, using TraversalFlag.
*/
template <typename Iterator, typename Node, typename PostAction>
auto ForEachNodePostOrder(Node* aRoot, const PostAction& aPostAction) ->
auto ForEachNodePostOrder(Node aRoot, const PostAction& aPostAction) ->
typename EnableIf<IsSame<decltype(aPostAction(aRoot)), TraversalFlag>::value, bool>::Type
{
return ForEachNode<Iterator>(aRoot, [](Node* aNode){ return TraversalFlag::Continue; }, aPostAction);
return ForEachNode<Iterator>(aRoot, [](Node aNode){ return TraversalFlag::Continue; }, aPostAction);
}
/*
* ForEachNode post-order, not using TraversalFlag.
*/
template <typename Iterator, typename Node, typename PostAction>
auto ForEachNodePostOrder(Node* aRoot, const PostAction& aPostAction) ->
auto ForEachNodePostOrder(Node aRoot, const PostAction& aPostAction) ->
typename EnableIf<IsSame<decltype(aPostAction(aRoot)), void>::value, void>::Type
{
ForEachNode<Iterator>(aRoot, [](Node* aNode){}, aPostAction);
ForEachNode<Iterator>(aRoot, [](Node aNode){}, aPostAction);
}
/*
@ -174,33 +190,35 @@ typename EnableIf<IsSame<decltype(aPostAction(aRoot)), void>::value, void>::Type
* first visited node that satisfies |aCondition|, or nullptr if no such node
* was found.
*
* See ForEachNode() for the requirements on |Iterator| and |Node|
* |Iterator| and |Node| have all the same requirements seen in ForEachNode()'s
* definition, but in addition to those, |Node| must be able to express a null
* value, returned from Node()
*/
template <typename Iterator, typename Node, typename Condition>
Node* BreadthFirstSearch(Node* aRoot, const Condition& aCondition)
Node BreadthFirstSearch(Node aRoot, const Condition& aCondition)
{
if (!aRoot) {
return nullptr;
return Node();
}
std::queue<Node*> queue;
std::queue<Node> queue;
queue.push(aRoot);
while (!queue.empty()) {
Node* node = queue.front();
Node node = queue.front();
queue.pop();
if (aCondition(node)) {
return node;
}
for (Node* child = Iterator::FirstChild(node);
for (Node child = Iterator::FirstChild(node);
child;
child = Iterator::NextSibling(child)) {
queue.push(child);
}
}
return nullptr;
return Node();
}
/*
@ -208,15 +226,17 @@ Node* BreadthFirstSearch(Node* aRoot, const Condition& aCondition)
* return the first visited node that satisfies |aCondition|, or nullptr
* if no such node was found.
*
* See ForEachNode() for the requirements on |Iterator| and |Node|
* |Iterator| and |Node| have all the same requirements seen in ForEachNode()'s
* definition, but in addition to those, |Node| must be able to express a null
* value, returned from Node().
*/
template <typename Iterator, typename Node, typename Condition>
Node* DepthFirstSearch(Node* aRoot, const Condition& aCondition)
Node DepthFirstSearch(Node aRoot, const Condition& aCondition)
{
Node* result = nullptr;
Node result = Node();
ForEachNode<Iterator>(aRoot,
[&aCondition, &result](Node* aNode)
[&aCondition, &result](Node aNode)
{
if (aCondition(aNode)) {
result = aNode;
@ -232,15 +252,17 @@ Node* DepthFirstSearch(Node* aRoot, const Condition& aCondition)
/*
* Perform a post-order, depth-first search starting at aRoot.
*
* See ForEachNode() for the requirements on |Iterator| and |Node|
* |Iterator| and |Node| have all the same requirements seen in ForEachNode()'s
* definition, but in addition to those, |Node| must be able to express a null
* value, returned from Node().
*/
template <typename Iterator, typename Node, typename Condition>
Node* DepthFirstSearchPostOrder(Node* aRoot, const Condition& aCondition)
Node DepthFirstSearchPostOrder(Node aRoot, const Condition& aCondition)
{
Node* result = nullptr;
Node result = Node();
ForEachNodePostOrder<Iterator>(aRoot,
[&aCondition, &result](Node* aNode)
[&aCondition, &result](Node aNode)
{
if (aCondition(aNode)) {
result = aNode;

View File

@ -180,12 +180,65 @@ APZCTreeManager::UpdateHitTestingTree(CompositorBridgeParent* aCompositor,
mRootNode = nullptr;
if (aRoot) {
std::stack<gfx::TreeAutoIndent> indents;
std::stack<gfx::Matrix4x4> ancestorTransforms;
HitTestingTreeNode* parent = nullptr;
HitTestingTreeNode* next = nullptr;
// aCompositor is null in gtest scenarios
uint64_t layersId = aCompositor ? aCompositor->RootLayerTreeId() : 0;
ancestorTransforms.push(Matrix4x4());
mApzcTreeLog << "[start]\n";
LayerMetricsWrapper root(aRoot);
UpdateHitTestingTree(state, root,
// aCompositor is null in gtest scenarios
aCompositor ? aCompositor->RootLayerTreeId() : 0,
Matrix4x4(), nullptr, nullptr);
mTreeLock.AssertCurrentThreadOwns();
ForEachNode<ReverseIterator>(root,
[&](LayerMetricsWrapper aLayerMetrics)
{
mApzcTreeLog << aLayerMetrics.Name() << '\t';
HitTestingTreeNode* node = PrepareNodeForLayer(aLayerMetrics,
aLayerMetrics.Metrics(), layersId, ancestorTransforms.top(),
parent, next, state);
MOZ_ASSERT(node);
AsyncPanZoomController* apzc = node->GetApzc();
aLayerMetrics.SetApzc(apzc);
mApzcTreeLog << '\n';
// Accumulate the CSS transform between layers that have an APZC.
// In the terminology of the big comment above APZCTreeManager::GetScreenToApzcTransform, if
// we are at layer M, then aAncestorTransform is NC * OC * PC, and we left-multiply MC and
// compute ancestorTransform to be MC * NC * OC * PC. This gets passed down as the ancestor
// 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.
// If a transform is a perspective transform, it's ignored for this purpose
// (see bug 1168263).
Matrix4x4 currentTransform = aLayerMetrics.TransformIsPerspective() ? Matrix4x4() : aLayerMetrics.GetTransform();
if (!apzc) {
currentTransform = currentTransform * ancestorTransforms.top();
}
ancestorTransforms.push(currentTransform);
// Note that |node| at this point will not have any children, otherwise we
// we would have to set next to node->GetFirstChild().
MOZ_ASSERT(!node->GetFirstChild());
parent = node;
next = nullptr;
layersId = (aLayerMetrics.AsRefLayer() ? aLayerMetrics.AsRefLayer()->GetReferentId() : layersId);
indents.push(gfx::TreeAutoIndent(mApzcTreeLog));
},
[&](LayerMetricsWrapper aLayerMetrics)
{
next = parent;
parent = parent->GetParent();
layersId = next->GetLayersId();
ancestorTransforms.pop();
indents.pop();
});
mApzcTreeLog << "[end]\n";
}
@ -563,57 +616,6 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer,
return node;
}
HitTestingTreeNode*
APZCTreeManager::UpdateHitTestingTree(TreeBuildingState& aState,
const LayerMetricsWrapper& aLayer,
uint64_t aLayersId,
const gfx::Matrix4x4& aAncestorTransform,
HitTestingTreeNode* aParent,
HitTestingTreeNode* aNextSibling)
{
mTreeLock.AssertCurrentThreadOwns();
mApzcTreeLog << aLayer.Name() << '\t';
HitTestingTreeNode* node = PrepareNodeForLayer(aLayer,
aLayer.Metrics(), aLayersId, aAncestorTransform,
aParent, aNextSibling, aState);
MOZ_ASSERT(node);
AsyncPanZoomController* apzc = node->GetApzc();
aLayer.SetApzc(apzc);
mApzcTreeLog << '\n';
// Accumulate the CSS transform between layers that have an APZC.
// In the terminology of the big comment above APZCTreeManager::GetScreenToApzcTransform, if
// we are at layer M, then aAncestorTransform is NC * OC * PC, and we left-multiply MC and
// compute ancestorTransform to be MC * NC * OC * PC. This gets passed down as the ancestor
// 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.
// If a transform is a perspective transform, it's ignored for this purpose
// (see bug 1168263).
Matrix4x4 ancestorTransform = aLayer.TransformIsPerspective() ? Matrix4x4() : aLayer.GetTransform();
if (!apzc) {
ancestorTransform = ancestorTransform * aAncestorTransform;
}
// Note that |node| at this point will not have any children, otherwise we
// we would have to set next to node->GetFirstChild().
MOZ_ASSERT(!node->GetFirstChild());
aParent = node;
HitTestingTreeNode* next = nullptr;
uint64_t childLayersId = (aLayer.AsRefLayer() ? aLayer.AsRefLayer()->GetReferentId() : aLayersId);
for (LayerMetricsWrapper child = aLayer.GetLastChild(); child; child = child.GetPrevSibling()) {
gfx::TreeAutoIndent indent(mApzcTreeLog);
next = UpdateHitTestingTree(aState, child, childLayersId,
ancestorTransform, aParent, next);
}
return node;
}
template<typename PanGestureOrScrollWheelInput>
static bool
WillHandleInput(const PanGestureOrScrollWheelInput& aPanInput)

View File

@ -474,34 +474,6 @@ private:
HitTestingTreeNode* aNextSibling,
TreeBuildingState& aState);
/**
* Recursive helper function to build the hit-testing tree. See documentation
* in HitTestingTreeNode.h for more details on the shape of the tree.
* This function walks the layer tree backwards through siblings and
* constructs the hit-testing tree also as a last-child-prev-sibling tree
* because that simplifies the hit detection code.
*
* @param aState The current tree building state.
* @param aLayer The (layer, metrics) pair which is the current position in
* the recursive walk of the layer tree. This call builds a
* hit-testing subtree corresponding to the layer subtree rooted
* at aLayer.
* @param aLayersId The layers id of the layer in aLayer.
* @param aAncestorTransform The accumulated CSS transforms of all the
* layers from aLayer up (via the parent chain)
* to the next APZC-bearing layer.
* @param aParent The parent of any node built at this level.
* @param aNextSibling The next sibling of any node built at this level.
* @return The HitTestingTreeNode created at this level. This will always
* be non-null.
*/
HitTestingTreeNode* UpdateHitTestingTree(TreeBuildingState& aState,
const LayerMetricsWrapper& aLayer,
uint64_t aLayersId,
const gfx::Matrix4x4& aAncestorTransform,
HitTestingTreeNode* aParent,
HitTestingTreeNode* aNextSibling);
void PrintAPZCInfo(const LayerMetricsWrapper& aLayer,
const AsyncPanZoomController* apzc);

View File

@ -768,15 +768,16 @@ static bool
SampleAPZAnimations(const LayerMetricsWrapper& aLayer, TimeStamp aSampleTime)
{
bool activeAnimations = false;
for (LayerMetricsWrapper child = aLayer.GetFirstChild(); child;
child = child.GetNextSibling()) {
activeAnimations |= SampleAPZAnimations(child, aSampleTime);
}
if (AsyncPanZoomController* apzc = aLayer.GetApzc()) {
apzc->ReportCheckerboard(aSampleTime);
activeAnimations |= apzc->AdvanceAnimations(aSampleTime);
}
ForEachNodePostOrder<ForwardIterator>(aLayer,
[&activeAnimations, &aSampleTime](LayerMetricsWrapper aLayerMetrics)
{
if (AsyncPanZoomController* apzc = aLayerMetrics.GetApzc()) {
apzc->ReportCheckerboard(aSampleTime);
activeAnimations |= apzc->AdvanceAnimations(aSampleTime);
}
}
);
return activeAnimations;
}
@ -1326,37 +1327,14 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
SetShadowTransform(aScrollbar, transform);
}
static LayerMetricsWrapper
FindScrolledLayerRecursive(Layer* aScrollbar, const LayerMetricsWrapper& aSubtreeRoot)
{
if (LayerIsScrollbarTarget(aSubtreeRoot, aScrollbar)) {
return aSubtreeRoot;
}
for (LayerMetricsWrapper child = aSubtreeRoot.GetFirstChild();
child;
child = child.GetNextSibling())
{
// Do not recurse into RefLayers, since our initial aSubtreeRoot is the
// root (or RefLayer root) of a single layer space to search.
if (child.AsRefLayer()) {
continue;
}
LayerMetricsWrapper target = FindScrolledLayerRecursive(aScrollbar, child);
if (target) {
return target;
}
}
return LayerMetricsWrapper();
}
static LayerMetricsWrapper
FindScrolledLayerForScrollbar(Layer* aScrollbar, bool* aOutIsAncestor)
{
// First check if the scrolled layer is an ancestor of the scrollbar layer.
LayerMetricsWrapper root(aScrollbar->Manager()->GetRoot());
LayerMetricsWrapper prevAncestor(aScrollbar);
LayerMetricsWrapper scrolledLayer;
for (LayerMetricsWrapper ancestor(aScrollbar); ancestor; ancestor = ancestor.GetParent()) {
// Don't walk into remote layer trees; the scrollbar will always be in
// the same layer space.
@ -1373,7 +1351,23 @@ FindScrolledLayerForScrollbar(Layer* aScrollbar, bool* aOutIsAncestor)
}
// Search the entire layer space of the scrollbar.
return FindScrolledLayerRecursive(aScrollbar, root);
ForEachNode<ForwardIterator>(
root,
[&root, &scrolledLayer, &aScrollbar](LayerMetricsWrapper aLayerMetrics)
{
// Do not recurse into RefLayers, since our initial aSubtreeRoot is the
// root (or RefLayer root) of a single layer space to search.
if (root != aLayerMetrics && aLayerMetrics.AsRefLayer()) {
return TraversalFlag::Skip;
}
if (LayerIsScrollbarTarget(aLayerMetrics, aScrollbar)) {
scrolledLayer = aLayerMetrics;
return TraversalFlag::Abort;
}
return TraversalFlag::Continue;
}
);
return scrolledLayer;
}
void