// 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 #include "base/logging.h" #include "cc/trees/property_tree.h" namespace cc { template PropertyTree::PropertyTree() { nodes_.push_back(T()); back()->id = 0; back()->parent_id = -1; } template PropertyTree::~PropertyTree() { } template int PropertyTree::Insert(const T& tree_node, int parent_id) { DCHECK_GT(nodes_.size(), 0u); nodes_.push_back(tree_node); T& node = nodes_.back(); node.parent_id = parent_id; node.id = static_cast(nodes_.size()) - 1; return node.id; } template class PropertyTree; template class PropertyTree; TransformNodeData::TransformNodeData() : target_id(-1), is_invertible(true), ancestors_are_invertible(true), is_animated(false), to_screen_is_animated(false), flattens(false) { } TransformNodeData::~TransformNodeData() { } ClipNodeData::ClipNodeData() : transform_id(-1), target_id(-1) { } bool TransformTree::ComputeTransform(int source_id, int dest_id, gfx::Transform* transform) const { transform->MakeIdentity(); if (source_id == dest_id) return true; if (source_id > dest_id && IsDescendant(source_id, dest_id)) return CombineTransformsBetween(source_id, dest_id, transform); if (dest_id > source_id && IsDescendant(dest_id, source_id)) return CombineInversesBetween(source_id, dest_id, transform); int lca = LowestCommonAncestor(source_id, dest_id); bool no_singular_matrices_to_lca = CombineTransformsBetween(source_id, lca, transform); bool no_singular_matrices_from_lca = CombineInversesBetween(lca, dest_id, transform); return no_singular_matrices_to_lca && no_singular_matrices_from_lca; } bool TransformTree::Are2DAxisAligned(int source_id, int dest_id) const { gfx::Transform transform; return ComputeTransform(source_id, dest_id, &transform) && transform.Preserves2dAxisAlignment(); } void TransformTree::UpdateScreenSpaceTransform(int id) { TransformNode* current_node = Node(id); TransformNode* parent_node = parent(current_node); TransformNode* target_node = Node(current_node->data.target_id); if (!parent_node) { current_node->data.to_screen = current_node->data.to_parent; current_node->data.ancestors_are_invertible = true; current_node->data.to_screen_is_animated = false; } else if (parent_node->data.flattens) { // Flattening is tricky. Once a layer is drawn into its render target, it // cannot escape, so we only need to consider transforms between the layer // and its target when flattening (i.e., its draw transform). To compute the // screen space transform when flattening is involved we combine three // transforms, A * B * C, where A is the screen space transform of the // target, B is the flattened draw transform of the layer's parent, and C is // the local transform. current_node->data.to_screen = target_node->data.to_screen; gfx::Transform flattened; ComputeTransform(parent_node->id, target_node->id, &flattened); flattened.FlattenTo2d(); current_node->data.to_screen.PreconcatTransform(flattened); current_node->data.to_screen.PreconcatTransform( current_node->data.to_parent); current_node->data.ancestors_are_invertible = parent_node->data.ancestors_are_invertible; } else { current_node->data.to_screen = parent_node->data.to_screen; current_node->data.to_screen.PreconcatTransform( current_node->data.to_parent); current_node->data.ancestors_are_invertible = parent_node->data.ancestors_are_invertible; } if (!current_node->data.to_screen.GetInverse(¤t_node->data.from_screen)) current_node->data.ancestors_are_invertible = false; if (parent_node) { current_node->data.to_screen_is_animated = current_node->data.is_animated || parent_node->data.to_screen_is_animated; } } bool TransformTree::IsDescendant(int desc_id, int source_id) const { while (desc_id != source_id) { if (desc_id < 0) return false; desc_id = Node(desc_id)->parent_id; } return true; } int TransformTree::LowestCommonAncestor(int a, int b) const { std::set chain_a; std::set chain_b; while (a || b) { if (a) { a = Node(a)->parent_id; if (a > -1 && chain_b.find(a) != chain_b.end()) return a; chain_a.insert(a); } if (b) { b = Node(b)->parent_id; if (b > -1 && chain_a.find(b) != chain_a.end()) return b; chain_b.insert(b); } } NOTREACHED(); return 0; } bool TransformTree::CombineTransformsBetween(int source_id, int dest_id, gfx::Transform* transform) const { const TransformNode* current = Node(source_id); const TransformNode* dest = Node(dest_id); if (!dest || dest->data.ancestors_are_invertible) { transform->ConcatTransform(current->data.to_screen); if (dest) transform->ConcatTransform(dest->data.from_screen); return true; } bool all_are_invertible = true; for (; current && current->id > dest_id; current = parent(current)) { transform->ConcatTransform(current->data.to_parent); if (!current->data.is_invertible) all_are_invertible = false; } return all_are_invertible; } bool TransformTree::CombineInversesBetween(int source_id, int dest_id, gfx::Transform* transform) const { const TransformNode* current = Node(dest_id); const TransformNode* dest = Node(source_id); if (current->data.ancestors_are_invertible) { transform->PreconcatTransform(current->data.from_screen); if (dest) transform->PreconcatTransform(dest->data.to_screen); return true; } bool all_are_invertible = true; for (; current && current->id > source_id; current = parent(current)) { transform->PreconcatTransform(current->data.from_parent); if (!current->data.is_invertible) all_are_invertible = false; } return all_are_invertible; } } // namespace cc