blob: b3b6d53c5599afa3bfe0eba2fb2b580e103f3d51 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/layers/layer_utils.h"
#include "cc/layers/layer_impl.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/transform_node.h"
#include "ui/gfx/geometry/box_f.h"
namespace cc {
namespace {
bool HasTransformAnimationThatInflatesBounds(const LayerImpl& layer) {
return layer.HasTransformAnimationThatInflatesBounds();
}
inline bool HasAncestorTransformAnimation(const TransformNode* transform_node) {
return transform_node->to_screen_is_potentially_animated;
}
inline bool HasAncestorFilterAnimation(const LayerImpl& layer) {
// This function returns false, it should use the effect tree once filters
// and filter animations are known by the tree.
return false;
}
} // namespace
bool LayerUtils::GetAnimationBounds(const LayerImpl& layer_in, gfx::BoxF* out) {
// We don't care about animated bounds for invisible layers.
if (!layer_in.DrawsContent())
return false;
TransformTree& transform_tree =
layer_in.layer_tree_impl()->property_trees()->transform_tree;
// We also don't care for layers that are not animated or a child of an
// animated layer.
if (!HasAncestorTransformAnimation(
transform_tree.Node(layer_in.transform_tree_index())) &&
!HasAncestorFilterAnimation(layer_in))
return false;
// To compute the inflated bounds for a layer, we start by taking its bounds
// and converting it to a 3d box, and then we transform or inflate it
// repeatedly as we walk up the transform tree to the root.
//
// At each transform_node without transform animation that inflates bounds:
//
// 1) We concat transform_node->data.to_parent to the coalesced_transform.
//
// At each transform_node with a transform animation that inflates bounds:
//
// 1) We concat transform_node->data.pre_local to the coalesced_transform.
// This is to translate the box so that the anchor point is the origin.
// 2) We apply coalesced_transform to the 3d box and make the transform
// identity. This is apply the accumulated transform to the box to inflate
// it.
// 3) We inflate the 3d box for animation as the node has a animated
// transform.
// 4) We concat transform_node->data.post_local to the coalesced_transform.
// This step undoes the translation in step (1), accounts for the layer's
// position and the 2d translation to the space of the parent transform
// node.
gfx::BoxF box(layer_in.bounds().width(), layer_in.bounds().height(), 0.f);
// We want to inflate/transform the box as few times as possible. Each time
// we do this, we have to make the box axis aligned again, so if we make many
// small adjustments to the box by transforming it repeatedly rather than
// once by the product of all these matrices, we will accumulate a bunch of
// unnecessary inflation because of the the many axis-alignment fixes. This
// matrix stores said product.
gfx::Transform coalesced_transform;
const TransformNode* transform_node =
transform_tree.Node(layer_in.transform_tree_index());
// If layer_in has a transform node, the offset_to_transform_parent() is 0
coalesced_transform.Translate(layer_in.offset_to_transform_parent().x(),
layer_in.offset_to_transform_parent().y());
for (; transform_tree.parent(transform_node);
transform_node = transform_tree.parent(transform_node)) {
LayerImpl* layer =
layer_in.layer_tree_impl()->LayerById(transform_node->owner_id);
// Filter animation bounds are unimplemented, see function
// HasAncestorFilterAnimation() for reference.
if (HasTransformAnimationThatInflatesBounds(*layer)) {
coalesced_transform.ConcatTransform(transform_node->pre_local);
coalesced_transform.TransformBox(&box);
coalesced_transform.MakeIdentity();
gfx::BoxF inflated;
if (!layer->TransformAnimationBoundsForBox(box, &inflated))
return false;
box = inflated;
coalesced_transform.ConcatTransform(transform_node->post_local);
} else {
coalesced_transform.ConcatTransform(transform_node->to_parent);
}
}
// If we've got an unapplied coalesced transform at this point, it must still
// be applied.
if (!coalesced_transform.IsIdentity())
coalesced_transform.TransformBox(&box);
*out = box;
return true;
}
} // namespace cc