Home | History | Annotate | Download | only in layers
      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