| /* |
| * Copyright 2016 Google Inc. All Rights Reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef COBALT_RENDER_TREE_ANIMATIONS_ANIMATE_NODE_H_ |
| #define COBALT_RENDER_TREE_ANIMATIONS_ANIMATE_NODE_H_ |
| |
| #include <map> |
| #include <vector> |
| |
| #include "base/containers/small_map.h" |
| #include "base/memory/ref_counted.h" |
| #include "cobalt/math/rect_f.h" |
| #include "cobalt/render_tree/animations/animation_list.h" |
| #include "cobalt/render_tree/movable.h" |
| #include "cobalt/render_tree/node.h" |
| #include "cobalt/render_tree/node_visitor.h" |
| |
| namespace cobalt { |
| namespace render_tree { |
| namespace animations { |
| |
| // An AnimateNode describes a set of animations that affect the subtree attached |
| // to the AnimateNode. In order to create an AnimateNode, one must first |
| // populate an AnimateNode::Builder with a mapping of render tree node |
| // references to corresponding animations that should be applied to them. |
| // Construction of an AnimateNode object requires a populated |
| // AnimateNode::Builder instance as well as the sub-tree that the animations |
| // apply to. Upon construction, AnimateNode will compile the set of animated |
| // nodes into a format specialized to the associated subtree such that it is |
| // much faster to apply the animations. Once an AnimateNode is constructed, |
| // it can generate static render trees representing frames of animation via |
| // calls to AnimateNode::Apply(), which returns a static render tree. |
| // When AnimateNodes are constructed they maintain an invariant that |
| // AnimateNodes never have other AnimateNodes as descendants. It does this |
| // by traversing the subtree on construction and if another AnimateNode is |
| // encountered, its information is merged into this root AnimateNode, and the |
| // sub-AnimateNode is removed from the tree. |
| class AnimateNode : public Node { |
| public: |
| // Manages a mapping of render tree nodes to corresponding animations. Users |
| // of AnimateNode should populate the Builder with animations and then use |
| // that to construct the AnimateNode. |
| class Builder { |
| public: |
| DECLARE_AS_MOVABLE(Builder); |
| |
| Builder() {} |
| explicit Builder(Moved moved) { |
| node_animation_map_ = moved->node_animation_map_; |
| node_refs_.swap(moved->node_refs_); |
| } |
| |
| // This method is a template so that we can ensure that animations are not |
| // mismatched with render tree nodes of the wrong type. |
| template <typename T> |
| void Add(const scoped_refptr<T>& target_node, |
| const scoped_refptr<AnimationList<T> >& animation_list) { |
| AddInternal(target_node, animation_list); |
| } |
| |
| // Convenience method to attach a single animation to a target node. |
| template <typename T> |
| void Add(const scoped_refptr<T>& target_node, |
| const typename Animation<T>::Function& single_animation, |
| base::TimeDelta expiry) { |
| AddInternal(target_node, |
| scoped_refptr<AnimationListBase>( |
| new AnimationList<T>(single_animation, expiry))); |
| } |
| |
| template <typename T> |
| void Add(const scoped_refptr<T>& target_node, |
| const typename Animation<T>::Function& single_animation) { |
| AddInternal(target_node, |
| scoped_refptr<AnimationListBase>(new AnimationList<T>( |
| single_animation, base::TimeDelta::Max()))); |
| } |
| |
| // Merge all mappings from another AnimateNode::Builder into this one. |
| // There cannot be any keys that are in both the merge target and source. |
| void Merge(const Builder& other); |
| |
| // Returns true if there are no animations added to this |
| // AnimateNode::Builder. |
| bool empty() const { return node_animation_map_.empty(); } |
| |
| private: |
| // A non-template function that contains the logic for storing a target |
| // node and animation list pair. |
| void AddInternal(const scoped_refptr<Node>& target_node, |
| const scoped_refptr<AnimationListBase>& animation_list); |
| |
| // The primary internal data structure used to organize and store the |
| // mapping between target render tree node and animation list. |
| // In many cases there are not many active animations, and so we use a |
| // base::SmallMap for this. std::map was found to be more performant than |
| // base::hash_map, so it is used as the fallback map. |
| typedef base::SmallMap<std::map<Node*, scoped_refptr<AnimationListBase> >, |
| 4> InternalMap; |
| InternalMap node_animation_map_; |
| std::vector<scoped_refptr<Node> > node_refs_; |
| |
| friend class AnimateNode; |
| }; |
| |
| AnimateNode(const Builder& builder, const scoped_refptr<Node>& source); |
| |
| // This will create an AnimateNode with no animations. It is useful because |
| // construction of AnimateNodes maintain an invariant that there are no |
| // sub-AnimateNodes underneath them. Thus, adding a AnimateNode, even if it |
| // has no animations, to an existing tree will result in existing AnimateNodes |
| // being merged into the new root AnimateNode, which can simplify the |
| // underlying tree. |
| explicit AnimateNode(const scoped_refptr<Node>& source); |
| |
| // Cannot visit this node. |
| void Accept(NodeVisitor* visitor) OVERRIDE { visitor->Visit(this); } |
| |
| // Since we don't have any bounds on the animations contained in this tree, |
| // we cannot know the bounds of the tree over all time. Indeed animations |
| // may not have any bounds as time goes to infinity. Despite this, we return |
| // the bounds of the initial render tree to enable AnimateNodes to be setup |
| // as children of CompositionNodes. |
| math::RectF GetBounds() const OVERRIDE { return source_->GetBounds(); } |
| |
| base::TypeId GetTypeId() const OVERRIDE { |
| return base::GetTypeId<AnimateNode>(); |
| } |
| |
| struct AnimateResults { |
| // The animated render tree, which is guaranteed to not contain any |
| // AnimateNodes. |
| scoped_refptr<Node> animated; |
| |
| // Can be called in order to return a bounding rectangle around all |
| // nodes that are actively animated. The parameter specifies a "since" |
| // time. Any animations that had already expired *before* the "since" time |
| // will not be included in the returned bounding box. |
| // This information is likely to be used to enable optimizations where only |
| // regions of the screen that have changed are rendered. |
| base::Callback<math::RectF(base::TimeDelta)> get_animation_bounds_since; |
| }; |
| // Apply the animations to the sub render tree with the given |time_offset|. |
| AnimateResults Apply(base::TimeDelta time_offset); |
| |
| // Returns the sub-tree for which the animations apply to. |
| const scoped_refptr<Node> source() const { return source_; } |
| |
| // Returns the time at which all animations will have completed, or |
| // base::TimeDelta::Max() if they will never complete. |
| // It will be true that AnimateNode::Apply(x) == AnimateNode::Apply(y) for |
| // all x, y >= expiry(). |
| const base::TimeDelta& expiry() const { return expiry_; } |
| |
| private: |
| // The compiled node animation list is a sequence of nodes that are either |
| // animated themselves, or on the path to an animated node. Only nodes in |
| // this sequence need to be traversed. TraverseListEntry is an entry in this |
| // list, complete with animations to be applied to the given node, if any. |
| struct TraverseListEntry { |
| TraverseListEntry(Node* node, |
| const scoped_refptr<AnimationListBase>& animations) |
| : node(node), animations(animations) {} |
| explicit TraverseListEntry(Node* node) : node(node) {} |
| |
| Node* node; |
| scoped_refptr<AnimationListBase> animations; |
| }; |
| typedef std::vector<TraverseListEntry> TraverseList; |
| |
| class RefCountedTraversalList; |
| |
| // A helper render tree visitor class used to compile sub render-tree |
| // animations. |
| class TraverseListBuilder; |
| // A helper render tree visitor class used to apply compiled sub render-tree |
| // animations. This class follows the traversal generated by |
| // TraverseListBuilder. |
| class ApplyVisitor; |
| // A helper class to traverse an animated tree, and compute a bounding |
| // rectangle for all active animations. |
| class BoundsVisitor; |
| |
| void CommonInit(const Builder::InternalMap& node_animation_map, |
| const scoped_refptr<Node>& source); |
| |
| static math::RectF GetAnimationBoundsSince( |
| const scoped_refptr<RefCountedTraversalList>& traverse_list, |
| base::TimeDelta time_offset, const scoped_refptr<Node>& animated, |
| base::TimeDelta since); |
| |
| // The compiled traversal list through the sub-tree represented by |source_| |
| // that guides us towards all nodes that need to be animated. |
| TraverseList traverse_list_; |
| scoped_refptr<Node> source_; |
| base::TimeDelta expiry_; |
| }; |
| |
| } // namespace animations |
| } // namespace render_tree |
| } // namespace cobalt |
| |
| #endif // COBALT_RENDER_TREE_ANIMATIONS_ANIMATE_NODE_H_ |