1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/layers/layer_utils.h"
7 #include "cc/layers/layer_impl.h"
8 #include "cc/trees/layer_tree_host_common.h"
9 #include "ui/gfx/box_f.h"
15 bool HasAnimationThatInflatesBounds(const LayerImpl& layer) {
16 return layer.layer_animation_controller()->HasAnimationThatInflatesBounds();
19 bool HasFilterAnimationThatInflatesBounds(const LayerImpl& layer) {
20 return layer.layer_animation_controller()
21 ->HasFilterAnimationThatInflatesBounds();
24 bool HasTransformAnimationThatInflatesBounds(const LayerImpl& layer) {
25 return layer.layer_animation_controller()
26 ->HasTransformAnimationThatInflatesBounds();
29 inline bool HasAncestorTransformAnimation(const LayerImpl& layer) {
30 return layer.screen_space_transform_is_animating();
33 inline bool HasAncestorFilterAnimation(const LayerImpl& layer) {
34 for (const LayerImpl* current = &layer; current;
35 current = current->parent()) {
36 if (HasFilterAnimationThatInflatesBounds(*current))
45 bool LayerUtils::GetAnimationBounds(const LayerImpl& layer_in, gfx::BoxF* out) {
46 // We don't care about animated bounds for invisible layers.
47 if (!layer_in.DrawsContent())
50 // We also don't care for layers that are not animated or a child of an
52 if (!HasAncestorTransformAnimation(layer_in) &&
53 !HasAncestorFilterAnimation(layer_in))
56 // To compute the inflated bounds for a layer, we start by taking its bounds
57 // and converting it to a 3d box, and then we transform or inflate it
58 // repeatedly as we walk up the layer tree to the root.
60 // At each layer we apply the following transformations to the box:
61 // 1) We translate so that the anchor point is the origin.
62 // 2) We either apply the layer's transform or inflate if the layer's
63 // transform is animated.
64 // 3) We undo the translation from step 1 and apply a second translation
65 // to account for the layer's position.
66 // 4) We apply the sublayer transform from our parent (about the parent's
69 gfx::BoxF box(layer_in.bounds().width(), layer_in.bounds().height(), 0.f);
71 // We want to inflate/transform the box as few times as possible. Each time
72 // we do this, we have to make the box axis aligned again, so if we make many
73 // small adjustments to the box by transforming it repeatedly rather than
74 // once by the product of all these matrices, we will accumulate a bunch of
75 // unnecessary inflation because of the the many axis-alignment fixes. This
76 // matrix stores said product.
77 gfx::Transform coalesced_transform;
79 for (const LayerImpl* layer = &layer_in; layer; layer = layer->parent()) {
80 int anchor_x = layer->anchor_point().x() * layer->bounds().width();
81 int anchor_y = layer->anchor_point().y() * layer->bounds().height();
82 gfx::PointF position = layer->position();
83 if (layer->parent() && !HasAnimationThatInflatesBounds(*layer)) {
84 // |composite_layer_transform| contains 1 - 4 mentioned above. We compute
85 // it separately and apply afterwards because it's a bit more efficient
86 // because post-multiplication appears a bit more expensive, so we want
87 // to do it only once.
88 gfx::Transform composite_layer_transform;
90 if (!layer->parent()->sublayer_transform().IsIdentity()) {
91 LayerTreeHostCommon::ApplySublayerTransformAboutAnchor(
93 layer->parent()->bounds(),
94 &composite_layer_transform);
97 composite_layer_transform.Translate3d(anchor_x + position.x(),
98 anchor_y + position.y(),
99 layer->anchor_point_z());
100 composite_layer_transform.PreconcatTransform(layer->transform());
101 composite_layer_transform.Translate3d(
102 -anchor_x, -anchor_y, -layer->anchor_point_z());
104 // Add this layer's contributions to the |coalesced_transform|.
105 coalesced_transform.ConcatTransform(composite_layer_transform);
109 // First, apply coalesced transform we've been building and reset it.
110 coalesced_transform.TransformBox(&box);
111 coalesced_transform.MakeIdentity();
113 // We need to apply the inflation about the layer's anchor point. Rather
114 // than doing this via transforms, we'll just shift the box directly.
115 box.set_origin(box.origin() + gfx::Vector3dF(-anchor_x,
117 -layer->anchor_point_z()));
119 // Perform the inflation
120 if (HasFilterAnimationThatInflatesBounds(*layer)) {
122 if (!layer->layer_animation_controller()->FilterAnimationBoundsForBox(
128 if (HasTransformAnimationThatInflatesBounds(*layer)) {
130 if (!layer->layer_animation_controller()->TransformAnimationBoundsForBox(
136 // Apply step 3) mentioned above.
137 box.set_origin(box.origin() + gfx::Vector3dF(anchor_x + position.x(),
138 anchor_y + position.y(),
139 layer->anchor_point_z()));
141 // Even for layers with animations, we have to tack in the sublayer
142 // transform of our parent. *Every* layer is repsonsible for including the
143 // sublayer transform of its parent (see step 4 above).
144 if (layer->parent()) {
145 LayerTreeHostCommon::ApplySublayerTransformAboutAnchor(
146 *layer->parent(), layer->parent()->bounds(), &coalesced_transform);
150 // If we've got an unapplied coalesced transform at this point, it must still
152 if (!coalesced_transform.IsIdentity())
153 coalesced_transform.TransformBox(&box);