// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef FLUTTER_FLOW_LAYERS_CONTAINER_LAYER_H_ #define FLUTTER_FLOW_LAYERS_CONTAINER_LAYER_H_ #include #include "flutter/flow/layers/layer.h" namespace flutter { class ContainerLayer : public Layer { public: ContainerLayer(); virtual void Add(std::shared_ptr layer); void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; #if defined(LEGACY_FUCHSIA_EMBEDDER) void CheckForChildLayerBelow(PrerollContext* context) override; void UpdateScene(SceneUpdateContext& context) override; #endif const std::vector>& layers() const { return layers_; } protected: void PrerollChildren(PrerollContext* context, const SkMatrix& child_matrix, SkRect* child_paint_bounds); void PaintChildren(PaintContext& context) const; #if defined(LEGACY_FUCHSIA_EMBEDDER) void UpdateSceneChildren(SceneUpdateContext& context); #endif // Try to prepare the raster cache for a given layer. // // The raster cache would fail if either of the followings is true: // 1. The context has a platform view. // 2. The context does not have a valid raster cache. // 3. The layer's paint bounds does not intersect with the cull rect. // // We make this a static function instead of a member function that directy // uses the "this" pointer as the layer because we sometimes need to raster // cache a child layer and one can't access its child's protected method. static void TryToPrepareRasterCache(PrerollContext* context, Layer* layer, const SkMatrix& matrix); private: std::vector> layers_; FML_DISALLOW_COPY_AND_ASSIGN(ContainerLayer); }; //------------------------------------------------------------------------------ /// Some ContainerLayer objects perform a rendering operation or filter on /// the rendered output of their children. Often that operation is changed /// slightly from frame to frame as part of an animation. During such an /// animation, the children can be cached if they are stable to avoid having /// to render them on every frame. Even if the children are not stable, /// rendering them into the raster cache during a Preroll operation will save /// an extra change of rendering surface during the Paint phase as compared /// to using the SaveLayer that would otherwise be needed with no caching. /// /// Typically the Flutter Widget objects that lead to the creation of these /// layers will try to enforce only a single child Widget by their design. /// Unfortunately, the process of turning Widgets eventually into engine /// layers is not a 1:1 process so this layer might end up with multiple /// child layers even if the Widget only had a single child Widget. /// /// When such a layer goes to cache the output of its children, it will /// need to supply a single layer to the cache mechanism since the raster /// cache uses a layer unique_id() as part of the cache key. If this layer /// ended up with multiple children, then it must first collect them into /// one layer for the cache mechanism. In order to provide a single layer /// for all of the children, this utility class will implicitly collect /// the children into a secondary ContainerLayer called the child container. /// /// A by-product of creating a hidden child container, though, is that the /// child container is created new every time this layer is created with /// different properties, such as during an animation. In that scenario, /// it would be best to cache the single real child of this layer if it /// is unique and if it is stable from frame to frame. To facilitate this /// optimal caching strategy, this class implements two accessor methods /// to be used for different purposes: /// /// When the layer needs to recurse to perform some operation on its children, /// it can call GetChildContainer() to return the hidden container containing /// all of the real children. /// /// When the layer wants to cache the rendered contents of its children, it /// should call GetCacheableChild() for best performance. This method may /// end up returning the same layer as GetChildContainer(), but only if the /// conditions for optimal caching of a single child are not met. /// class MergedContainerLayer : public ContainerLayer { public: MergedContainerLayer(); void Add(std::shared_ptr layer) override; protected: /** * @brief Returns the ContainerLayer used to hold all of the children of the * MergedContainerLayer. Note that this may not be the best layer to use * for caching the children. * * @see GetCacheableChild() * @return the ContainerLayer child used to hold the children */ ContainerLayer* GetChildContainer() const; /** * @brief Returns the best choice for a Layer object that can be used * in RasterCache operations to cache the children. * * The returned Layer must represent all children and try to remain stable * if the MergedContainerLayer is reconstructed in subsequent frames of * the scene. * * @see GetChildContainer() * @return the best candidate Layer for caching the children */ Layer* GetCacheableChild() const; private: FML_DISALLOW_COPY_AND_ASSIGN(MergedContainerLayer); }; } // namespace flutter #endif // FLUTTER_FLOW_LAYERS_CONTAINER_LAYER_H_