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/geometry/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.
67 gfx::BoxF
box(layer_in
.bounds().width(), layer_in
.bounds().height(), 0.f
);
69 // We want to inflate/transform the box as few times as possible. Each time
70 // we do this, we have to make the box axis aligned again, so if we make many
71 // small adjustments to the box by transforming it repeatedly rather than
72 // once by the product of all these matrices, we will accumulate a bunch of
73 // unnecessary inflation because of the the many axis-alignment fixes. This
74 // matrix stores said product.
75 gfx::Transform coalesced_transform
;
77 for (const LayerImpl
* layer
= &layer_in
; layer
; layer
= layer
->parent()) {
78 int transform_origin_x
= layer
->transform_origin().x();
79 int transform_origin_y
= layer
->transform_origin().y();
80 int transform_origin_z
= layer
->transform_origin().z();
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 composite_layer_transform
.Translate3d(transform_origin_x
+ position
.x(),
91 transform_origin_y
+ position
.y(),
93 composite_layer_transform
.PreconcatTransform(layer
->transform());
94 composite_layer_transform
.Translate3d(
95 -transform_origin_x
, -transform_origin_y
, -transform_origin_z
);
97 // Add this layer's contributions to the |coalesced_transform|.
98 coalesced_transform
.ConcatTransform(composite_layer_transform
);
102 // First, apply coalesced transform we've been building and reset it.
103 coalesced_transform
.TransformBox(&box
);
104 coalesced_transform
.MakeIdentity();
106 // We need to apply the inflation about the layer's anchor point. Rather
107 // than doing this via transforms, we'll just shift the box directly.
108 box
.set_origin(box
.origin() + gfx::Vector3dF(-transform_origin_x
,
110 -transform_origin_z
));
112 // Perform the inflation
113 if (HasFilterAnimationThatInflatesBounds(*layer
)) {
115 if (!layer
->layer_animation_controller()->FilterAnimationBoundsForBox(
121 if (HasTransformAnimationThatInflatesBounds(*layer
)) {
123 if (!layer
->layer_animation_controller()->TransformAnimationBoundsForBox(
129 // Apply step 3) mentioned above.
130 box
.set_origin(box
.origin() +
131 gfx::Vector3dF(transform_origin_x
+ position
.x(),
132 transform_origin_y
+ position
.y(),
133 transform_origin_z
));
136 // If we've got an unapplied coalesced transform at this point, it must still
138 if (!coalesced_transform
.IsIdentity())
139 coalesced_transform
.TransformBox(&box
);