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 15 bool HasAnimationThatInflatesBounds(const LayerImpl& layer) { 16 return layer.layer_animation_controller()->HasAnimationThatInflatesBounds(); 17 } 18 19 bool HasFilterAnimationThatInflatesBounds(const LayerImpl& layer) { 20 return layer.layer_animation_controller() 21 ->HasFilterAnimationThatInflatesBounds(); 22 } 23 24 bool HasTransformAnimationThatInflatesBounds(const LayerImpl& layer) { 25 return layer.layer_animation_controller() 26 ->HasTransformAnimationThatInflatesBounds(); 27 } 28 29 inline bool HasAncestorTransformAnimation(const LayerImpl& layer) { 30 return layer.screen_space_transform_is_animating(); 31 } 32 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 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