1// Copyright 2013 The Flutter 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#ifndef FLUTTER_FLOW_LAYERS_CONTAINER_LAYER_H_
6#define FLUTTER_FLOW_LAYERS_CONTAINER_LAYER_H_
7
8#include <vector>
9#include "flutter/flow/layers/layer.h"
10
11namespace flutter {
12
13class ContainerLayer : public Layer {
14 public:
15 ContainerLayer();
16
17 virtual void Add(std::shared_ptr<Layer> layer);
18
19 void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
20 void Paint(PaintContext& context) const override;
21#if defined(LEGACY_FUCHSIA_EMBEDDER)
22 void CheckForChildLayerBelow(PrerollContext* context) override;
23 void UpdateScene(SceneUpdateContext& context) override;
24#endif
25
26 const std::vector<std::shared_ptr<Layer>>& layers() const { return layers_; }
27
28 protected:
29 void PrerollChildren(PrerollContext* context,
30 const SkMatrix& child_matrix,
31 SkRect* child_paint_bounds);
32 void PaintChildren(PaintContext& context) const;
33
34#if defined(LEGACY_FUCHSIA_EMBEDDER)
35 void UpdateSceneChildren(SceneUpdateContext& context);
36#endif
37
38 // Try to prepare the raster cache for a given layer.
39 //
40 // The raster cache would fail if either of the followings is true:
41 // 1. The context has a platform view.
42 // 2. The context does not have a valid raster cache.
43 // 3. The layer's paint bounds does not intersect with the cull rect.
44 //
45 // We make this a static function instead of a member function that directy
46 // uses the "this" pointer as the layer because we sometimes need to raster
47 // cache a child layer and one can't access its child's protected method.
48 static void TryToPrepareRasterCache(PrerollContext* context,
49 Layer* layer,
50 const SkMatrix& matrix);
51
52 private:
53 std::vector<std::shared_ptr<Layer>> layers_;
54
55 FML_DISALLOW_COPY_AND_ASSIGN(ContainerLayer);
56};
57
58//------------------------------------------------------------------------------
59/// Some ContainerLayer objects perform a rendering operation or filter on
60/// the rendered output of their children. Often that operation is changed
61/// slightly from frame to frame as part of an animation. During such an
62/// animation, the children can be cached if they are stable to avoid having
63/// to render them on every frame. Even if the children are not stable,
64/// rendering them into the raster cache during a Preroll operation will save
65/// an extra change of rendering surface during the Paint phase as compared
66/// to using the SaveLayer that would otherwise be needed with no caching.
67///
68/// Typically the Flutter Widget objects that lead to the creation of these
69/// layers will try to enforce only a single child Widget by their design.
70/// Unfortunately, the process of turning Widgets eventually into engine
71/// layers is not a 1:1 process so this layer might end up with multiple
72/// child layers even if the Widget only had a single child Widget.
73///
74/// When such a layer goes to cache the output of its children, it will
75/// need to supply a single layer to the cache mechanism since the raster
76/// cache uses a layer unique_id() as part of the cache key. If this layer
77/// ended up with multiple children, then it must first collect them into
78/// one layer for the cache mechanism. In order to provide a single layer
79/// for all of the children, this utility class will implicitly collect
80/// the children into a secondary ContainerLayer called the child container.
81///
82/// A by-product of creating a hidden child container, though, is that the
83/// child container is created new every time this layer is created with
84/// different properties, such as during an animation. In that scenario,
85/// it would be best to cache the single real child of this layer if it
86/// is unique and if it is stable from frame to frame. To facilitate this
87/// optimal caching strategy, this class implements two accessor methods
88/// to be used for different purposes:
89///
90/// When the layer needs to recurse to perform some operation on its children,
91/// it can call GetChildContainer() to return the hidden container containing
92/// all of the real children.
93///
94/// When the layer wants to cache the rendered contents of its children, it
95/// should call GetCacheableChild() for best performance. This method may
96/// end up returning the same layer as GetChildContainer(), but only if the
97/// conditions for optimal caching of a single child are not met.
98///
99class MergedContainerLayer : public ContainerLayer {
100 public:
101 MergedContainerLayer();
102
103 void Add(std::shared_ptr<Layer> layer) override;
104
105 protected:
106 /**
107 * @brief Returns the ContainerLayer used to hold all of the children of the
108 * MergedContainerLayer. Note that this may not be the best layer to use
109 * for caching the children.
110 *
111 * @see GetCacheableChild()
112 * @return the ContainerLayer child used to hold the children
113 */
114 ContainerLayer* GetChildContainer() const;
115
116 /**
117 * @brief Returns the best choice for a Layer object that can be used
118 * in RasterCache operations to cache the children.
119 *
120 * The returned Layer must represent all children and try to remain stable
121 * if the MergedContainerLayer is reconstructed in subsequent frames of
122 * the scene.
123 *
124 * @see GetChildContainer()
125 * @return the best candidate Layer for caching the children
126 */
127 Layer* GetCacheableChild() const;
128
129 private:
130 FML_DISALLOW_COPY_AND_ASSIGN(MergedContainerLayer);
131};
132
133} // namespace flutter
134
135#endif // FLUTTER_FLOW_LAYERS_CONTAINER_LAYER_H_
136