// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "cc/layers/layer_utils.h" #include "cc/layers/layer_impl.h" #include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_impl.h" #include "ui/gfx/geometry/box_f.h" namespace cc { namespace { bool HasTransformAnimationThatInflatesBounds(const LayerImpl& layer) { return layer.HasTransformAnimationThatInflatesBounds(); } inline bool HasAncestorTransformAnimation(const TransformNode* transform_node) { return transform_node->data.to_screen_is_animated; } inline bool HasAncestorFilterAnimation(const LayerImpl& layer) { // This function returns false, it should use the effect tree once filters // and filter animations are known by the tree. return false; } } // namespace bool LayerUtils::GetAnimationBounds(const LayerImpl& layer_in, gfx::BoxF* out) { // We don't care about animated bounds for invisible layers. if (!layer_in.DrawsContent()) return false; TransformTree& transform_tree = layer_in.layer_tree_impl()->property_trees()->transform_tree; // We also don't care for layers that are not animated or a child of an // animated layer. if (!HasAncestorTransformAnimation( transform_tree.Node(layer_in.transform_tree_index())) && !HasAncestorFilterAnimation(layer_in)) return false; // To compute the inflated bounds for a layer, we start by taking its bounds // and converting it to a 3d box, and then we transform or inflate it // repeatedly as we walk up the transform tree to the root. // // At each transform_node without transform animation that inflates bounds: // // 1) We concat transform_node->data.to_parent to the coalesced_transform. // // At each transform_node with a transform animation that inflates bounds: // // 1) We concat transform_node->data.pre_local to the coalesced_transform. // This is to translate the box so that the anchor point is the origin. // 2) We apply coalesced_transform to the 3d box and make the transform // identity. This is apply the accumulated transform to the box to inflate // it. // 3) We inflate the 3d box for animation as the node has a animated // transform. // 4) We concat transform_node->data.post_local to the coalesced_transform. // This step undoes the translation in step (1), accounts for the layer's // position and the 2d translation to the space of the parent transform // node. gfx::BoxF box(layer_in.bounds().width(), layer_in.bounds().height(), 0.f); // We want to inflate/transform the box as few times as possible. Each time // we do this, we have to make the box axis aligned again, so if we make many // small adjustments to the box by transforming it repeatedly rather than // once by the product of all these matrices, we will accumulate a bunch of // unnecessary inflation because of the the many axis-alignment fixes. This // matrix stores said product. gfx::Transform coalesced_transform; const TransformNode* transform_node = transform_tree.Node(layer_in.transform_tree_index()); // If layer_in has a transform node, the offset_to_transform_parent() is 0 coalesced_transform.Translate(layer_in.offset_to_transform_parent().x(), layer_in.offset_to_transform_parent().y()); for (; transform_tree.parent(transform_node); transform_node = transform_tree.parent(transform_node)) { LayerImpl* layer = layer_in.layer_tree_impl()->LayerById(transform_node->owner_id); // Filter animation bounds are unimplemented, see function // HasAncestorFilterAnimation() for reference. if (HasTransformAnimationThatInflatesBounds(*layer)) { coalesced_transform.ConcatTransform(transform_node->data.pre_local); coalesced_transform.TransformBox(&box); coalesced_transform.MakeIdentity(); gfx::BoxF inflated; if (!layer->TransformAnimationBoundsForBox(box, &inflated)) return false; box = inflated; coalesced_transform.ConcatTransform(transform_node->data.post_local); } else { coalesced_transform.ConcatTransform(transform_node->data.to_parent); } } // If we've got an unapplied coalesced transform at this point, it must still // be applied. if (!coalesced_transform.IsIdentity()) coalesced_transform.TransformBox(&box); *out = box; return true; } } // namespace cc