• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "cc/layers/layer_utils.h"
6 
7 #include "cc/layers/layer_impl.h"
8 #include "cc/trees/layer_tree_host_common.h"
9 #include "ui/gfx/box_f.h"
10 
11 namespace cc {
12 
13 namespace {
14 
HasAnimationThatInflatesBounds(const LayerImpl & layer)15 bool HasAnimationThatInflatesBounds(const LayerImpl& layer) {
16   return layer.layer_animation_controller()->HasAnimationThatInflatesBounds();
17 }
18 
HasFilterAnimationThatInflatesBounds(const LayerImpl & layer)19 bool HasFilterAnimationThatInflatesBounds(const LayerImpl& layer) {
20   return layer.layer_animation_controller()
21       ->HasFilterAnimationThatInflatesBounds();
22 }
23 
HasTransformAnimationThatInflatesBounds(const LayerImpl & layer)24 bool HasTransformAnimationThatInflatesBounds(const LayerImpl& layer) {
25   return layer.layer_animation_controller()
26       ->HasTransformAnimationThatInflatesBounds();
27 }
28 
HasAncestorTransformAnimation(const LayerImpl & layer)29 inline bool HasAncestorTransformAnimation(const LayerImpl& layer) {
30   return layer.screen_space_transform_is_animating();
31 }
32 
HasAncestorFilterAnimation(const LayerImpl & layer)33 inline bool HasAncestorFilterAnimation(const LayerImpl& layer) {
34   for (const LayerImpl* current = &layer; current;
35        current = current->parent()) {
36     if (HasFilterAnimationThatInflatesBounds(*current))
37         return true;
38   }
39 
40   return false;
41 }
42 
43 }  // namespace
44 
GetAnimationBounds(const LayerImpl & layer_in,gfx::BoxF * out)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())
48     return false;
49 
50   // We also don't care for layers that are not animated or a child of an
51   // animated layer.
52   if (!HasAncestorTransformAnimation(layer_in) &&
53       !HasAncestorFilterAnimation(layer_in))
54     return false;
55 
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.
59   //
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   //
67   gfx::BoxF box(layer_in.bounds().width(), layer_in.bounds().height(), 0.f);
68 
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;
76 
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();
81 
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;
89 
90       composite_layer_transform.Translate3d(transform_origin_x + position.x(),
91                                             transform_origin_y + position.y(),
92                                             transform_origin_z);
93       composite_layer_transform.PreconcatTransform(layer->transform());
94       composite_layer_transform.Translate3d(
95           -transform_origin_x, -transform_origin_y, -transform_origin_z);
96 
97       // Add this layer's contributions to the |coalesced_transform|.
98       coalesced_transform.ConcatTransform(composite_layer_transform);
99       continue;
100     }
101 
102     // First, apply coalesced transform we've been building and reset it.
103     coalesced_transform.TransformBox(&box);
104     coalesced_transform.MakeIdentity();
105 
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,
109                                                  -transform_origin_y,
110                                                  -transform_origin_z));
111 
112     // Perform the inflation
113     if (HasFilterAnimationThatInflatesBounds(*layer)) {
114       gfx::BoxF inflated;
115       if (!layer->layer_animation_controller()->FilterAnimationBoundsForBox(
116               box, &inflated))
117         return false;
118       box = inflated;
119     }
120 
121     if (HasTransformAnimationThatInflatesBounds(*layer)) {
122       gfx::BoxF inflated;
123       if (!layer->layer_animation_controller()->TransformAnimationBoundsForBox(
124               box, &inflated))
125         return false;
126       box = inflated;
127     }
128 
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));
134   }
135 
136   // If we've got an unapplied coalesced transform at this point, it must still
137   // be applied.
138   if (!coalesced_transform.IsIdentity())
139     coalesced_transform.TransformBox(&box);
140 
141   *out = box;
142 
143   return true;
144 }
145 
146 }  // namespace cc
147