|  | // 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_DISPLAY_LIST_DISPLAY_LIST_H_ | 
|  | #define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_H_ | 
|  |  | 
|  | #include <memory> | 
|  | #include <optional> | 
|  |  | 
|  | #include "flutter/display_list/dl_blend_mode.h" | 
|  | #include "flutter/display_list/dl_sampling_options.h" | 
|  | #include "flutter/display_list/geometry/dl_rtree.h" | 
|  | #include "flutter/fml/logging.h" | 
|  |  | 
|  | // The Flutter DisplayList mechanism encapsulates a persistent sequence of | 
|  | // rendering operations. | 
|  | // | 
|  | // This file contains the definitions for: | 
|  | // DisplayList: the base class that holds the information about the | 
|  | //              sequence of operations and can dispatch them to a DlOpReceiver | 
|  | // DlOpReceiver: a pure virtual interface which can be implemented to field | 
|  | //               the requests for purposes such as sending them to an SkCanvas | 
|  | //               or detecting various rendering optimization scenarios | 
|  | // DisplayListBuilder: a class for constructing a DisplayList from DlCanvas | 
|  | //                     method calls and which can act as a DlOpReceiver as well | 
|  | // | 
|  | // Other files include various class definitions for dealing with display | 
|  | // lists, such as: | 
|  | // skia/dl_sk_*.h: classes to interact between SkCanvas and DisplayList | 
|  | //                 (SkCanvas->DisplayList adapter and vice versa) | 
|  | // | 
|  | // display_list_utils.h: various utility classes to ease implementing | 
|  | //                       a DlOpReceiver, including NOP implementations of | 
|  | //                       the attribute, clip, and transform methods, | 
|  | //                       classes to track attributes, clips, and transforms | 
|  | //                       and a class to compute the bounds of a DisplayList | 
|  | //                       Any class implementing DlOpReceiver can inherit from | 
|  | //                       these utility classes to simplify its creation | 
|  | // | 
|  | // The Flutter DisplayList mechanism is used in a similar manner to the Skia | 
|  | // SkPicture mechanism. | 
|  | // | 
|  | // A DisplayList must be created using a DisplayListBuilder using its stateless | 
|  | // methods inherited from DlCanvas. | 
|  | // | 
|  | // A DisplayList can be read back by implementing the DlOpReceiver virtual | 
|  | // methods (with help from some of the classes in the utils file) and | 
|  | // passing an instance to the Dispatch() method, or it can be rendered | 
|  | // to Skia using a DlSkCanvasDispatcher. | 
|  | // | 
|  | // The mechanism is inspired by the SkLiteDL class that is not directly | 
|  | // supported by Skia, but has been recommended as a basis for custom | 
|  | // display lists for a number of their customers. | 
|  |  | 
|  | namespace flutter { | 
|  |  | 
|  | #define FOR_EACH_DISPLAY_LIST_OP(V) \ | 
|  | V(SetAntiAlias)                   \ | 
|  | V(SetInvertColors)                \ | 
|  | \ | 
|  | V(SetStrokeCap)                   \ | 
|  | V(SetStrokeJoin)                  \ | 
|  | \ | 
|  | V(SetStyle)                       \ | 
|  | V(SetStrokeWidth)                 \ | 
|  | V(SetStrokeMiter)                 \ | 
|  | \ | 
|  | V(SetColor)                       \ | 
|  | V(SetBlendMode)                   \ | 
|  | \ | 
|  | V(SetPodPathEffect)               \ | 
|  | V(ClearPathEffect)                \ | 
|  | \ | 
|  | V(ClearColorFilter)               \ | 
|  | V(SetPodColorFilter)              \ | 
|  | \ | 
|  | V(ClearColorSource)               \ | 
|  | V(SetPodColorSource)              \ | 
|  | V(SetImageColorSource)            \ | 
|  | V(SetRuntimeEffectColorSource)    \ | 
|  | \ | 
|  | V(ClearImageFilter)               \ | 
|  | V(SetPodImageFilter)              \ | 
|  | V(SetSharedImageFilter)           \ | 
|  | \ | 
|  | V(ClearMaskFilter)                \ | 
|  | V(SetPodMaskFilter)               \ | 
|  | \ | 
|  | V(Save)                           \ | 
|  | V(SaveLayer)                      \ | 
|  | V(SaveLayerBackdrop)              \ | 
|  | V(Restore)                        \ | 
|  | \ | 
|  | V(Translate)                      \ | 
|  | V(Scale)                          \ | 
|  | V(Rotate)                         \ | 
|  | V(Skew)                           \ | 
|  | V(Transform2DAffine)              \ | 
|  | V(TransformFullPerspective)       \ | 
|  | V(TransformReset)                 \ | 
|  | \ | 
|  | V(ClipIntersectRect)              \ | 
|  | V(ClipIntersectRRect)             \ | 
|  | V(ClipIntersectPath)              \ | 
|  | V(ClipDifferenceRect)             \ | 
|  | V(ClipDifferenceRRect)            \ | 
|  | V(ClipDifferencePath)             \ | 
|  | \ | 
|  | V(DrawPaint)                      \ | 
|  | V(DrawColor)                      \ | 
|  | \ | 
|  | V(DrawLine)                       \ | 
|  | V(DrawDashedLine)                 \ | 
|  | V(DrawRect)                       \ | 
|  | V(DrawOval)                       \ | 
|  | V(DrawCircle)                     \ | 
|  | V(DrawRRect)                      \ | 
|  | V(DrawDRRect)                     \ | 
|  | V(DrawArc)                        \ | 
|  | V(DrawPath)                       \ | 
|  | \ | 
|  | V(DrawPoints)                     \ | 
|  | V(DrawLines)                      \ | 
|  | V(DrawPolygon)                    \ | 
|  | V(DrawVertices)                   \ | 
|  | \ | 
|  | V(DrawImage)                      \ | 
|  | V(DrawImageWithAttr)              \ | 
|  | V(DrawImageRect)                  \ | 
|  | V(DrawImageNine)                  \ | 
|  | V(DrawImageNineWithAttr)          \ | 
|  | V(DrawAtlas)                      \ | 
|  | V(DrawAtlasCulled)                \ | 
|  | \ | 
|  | V(DrawDisplayList)                \ | 
|  | V(DrawTextBlob)                   \ | 
|  | V(DrawTextFrame)                  \ | 
|  | \ | 
|  | V(DrawShadow)                     \ | 
|  | V(DrawShadowTransparentOccluder) | 
|  |  | 
|  | #define DL_OP_TO_ENUM_VALUE(name) k##name, | 
|  | enum class DisplayListOpType { | 
|  | FOR_EACH_DISPLAY_LIST_OP(DL_OP_TO_ENUM_VALUE) | 
|  | #ifdef IMPELLER_ENABLE_3D | 
|  | DL_OP_TO_ENUM_VALUE(SetSceneColorSource) | 
|  | #endif  // IMPELLER_ENABLE_3D | 
|  | }; | 
|  | #undef DL_OP_TO_ENUM_VALUE | 
|  |  | 
|  | class DlOpReceiver; | 
|  | class DisplayListBuilder; | 
|  |  | 
|  | class SaveLayerOptions { | 
|  | public: | 
|  | static const SaveLayerOptions kWithAttributes; | 
|  | static const SaveLayerOptions kNoAttributes; | 
|  |  | 
|  | SaveLayerOptions() : flags_(0) {} | 
|  | SaveLayerOptions(const SaveLayerOptions& options) : flags_(options.flags_) {} | 
|  | explicit SaveLayerOptions(const SaveLayerOptions* options) | 
|  | : flags_(options->flags_) {} | 
|  |  | 
|  | SaveLayerOptions without_optimizations() const { | 
|  | SaveLayerOptions options; | 
|  | options.fRendersWithAttributes = fRendersWithAttributes; | 
|  | options.fBoundsFromCaller = fBoundsFromCaller; | 
|  | return options; | 
|  | } | 
|  |  | 
|  | bool renders_with_attributes() const { return fRendersWithAttributes; } | 
|  | SaveLayerOptions with_renders_with_attributes() const { | 
|  | SaveLayerOptions options(this); | 
|  | options.fRendersWithAttributes = true; | 
|  | return options; | 
|  | } | 
|  |  | 
|  | bool can_distribute_opacity() const { return fCanDistributeOpacity; } | 
|  | SaveLayerOptions with_can_distribute_opacity() const { | 
|  | SaveLayerOptions options(this); | 
|  | options.fCanDistributeOpacity = true; | 
|  | return options; | 
|  | } | 
|  |  | 
|  | // Returns true iff the bounds for the saveLayer operation were provided | 
|  | // by the caller, otherwise the bounds will have been computed by the | 
|  | // DisplayListBuilder and provided for reference. | 
|  | bool bounds_from_caller() const { return fBoundsFromCaller; } | 
|  | SaveLayerOptions with_bounds_from_caller() const { | 
|  | SaveLayerOptions options(this); | 
|  | options.fBoundsFromCaller = true; | 
|  | return options; | 
|  | } | 
|  | SaveLayerOptions without_bounds_from_caller() const { | 
|  | SaveLayerOptions options(this); | 
|  | options.fBoundsFromCaller = false; | 
|  | return options; | 
|  | } | 
|  | bool bounds_were_calculated() const { return !fBoundsFromCaller; } | 
|  |  | 
|  | // Returns true iff the bounds for the saveLayer do not fully cover the | 
|  | // contained rendering operations. This will only occur if the original | 
|  | // caller supplied bounds and those bounds were not a strict superset | 
|  | // of the content bounds computed by the DisplayListBuilder. | 
|  | bool content_is_clipped() const { return fContentIsClipped; } | 
|  | SaveLayerOptions with_content_is_clipped() const { | 
|  | SaveLayerOptions options(this); | 
|  | options.fContentIsClipped = true; | 
|  | return options; | 
|  | } | 
|  |  | 
|  | bool contains_backdrop_filter() const { return fHasBackdropFilter; } | 
|  | SaveLayerOptions with_contains_backdrop_filter() const { | 
|  | SaveLayerOptions options(this); | 
|  | options.fHasBackdropFilter = true; | 
|  | return options; | 
|  | } | 
|  |  | 
|  | SaveLayerOptions& operator=(const SaveLayerOptions& other) { | 
|  | flags_ = other.flags_; | 
|  | return *this; | 
|  | } | 
|  | bool operator==(const SaveLayerOptions& other) const { | 
|  | return flags_ == other.flags_; | 
|  | } | 
|  | bool operator!=(const SaveLayerOptions& other) const { | 
|  | return flags_ != other.flags_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | union { | 
|  | struct { | 
|  | unsigned fRendersWithAttributes : 1; | 
|  | unsigned fCanDistributeOpacity : 1; | 
|  | unsigned fBoundsFromCaller : 1; | 
|  | unsigned fContentIsClipped : 1; | 
|  | unsigned fHasBackdropFilter : 1; | 
|  | }; | 
|  | uint32_t flags_; | 
|  | }; | 
|  | }; | 
|  |  | 
|  | // Manages a buffer allocated with malloc. | 
|  | class DisplayListStorage { | 
|  | public: | 
|  | DisplayListStorage() = default; | 
|  | DisplayListStorage(DisplayListStorage&&) = default; | 
|  |  | 
|  | uint8_t* get() { return ptr_.get(); } | 
|  |  | 
|  | const uint8_t* get() const { return ptr_.get(); } | 
|  |  | 
|  | void realloc(size_t count) { | 
|  | ptr_.reset(static_cast<uint8_t*>(std::realloc(ptr_.release(), count))); | 
|  | FML_CHECK(ptr_); | 
|  | } | 
|  |  | 
|  | private: | 
|  | struct FreeDeleter { | 
|  | void operator()(uint8_t* p) { std::free(p); } | 
|  | }; | 
|  | std::unique_ptr<uint8_t, FreeDeleter> ptr_; | 
|  | }; | 
|  |  | 
|  | class Culler; | 
|  |  | 
|  | // The base class that contains a sequence of rendering operations | 
|  | // for dispatch to a DlOpReceiver. These objects must be instantiated | 
|  | // through an instance of DisplayListBuilder::build(). | 
|  | class DisplayList : public SkRefCnt { | 
|  | public: | 
|  | DisplayList(); | 
|  |  | 
|  | ~DisplayList(); | 
|  |  | 
|  | void Dispatch(DlOpReceiver& ctx) const; | 
|  | void Dispatch(DlOpReceiver& ctx, const SkRect& cull_rect) const; | 
|  | void Dispatch(DlOpReceiver& ctx, const SkIRect& cull_rect) const; | 
|  |  | 
|  | // From historical behavior, SkPicture always included nested bytes, | 
|  | // but nested ops are only included if requested. The defaults used | 
|  | // here for these accessors follow that pattern. | 
|  | size_t bytes(bool nested = true) const { | 
|  | return sizeof(DisplayList) + byte_count_ + | 
|  | (nested ? nested_byte_count_ : 0); | 
|  | } | 
|  |  | 
|  | uint32_t op_count(bool nested = false) const { | 
|  | return op_count_ + (nested ? nested_op_count_ : 0); | 
|  | } | 
|  |  | 
|  | uint32_t total_depth() const { return total_depth_; } | 
|  |  | 
|  | uint32_t unique_id() const { return unique_id_; } | 
|  |  | 
|  | const SkRect& bounds() const { return bounds_; } | 
|  |  | 
|  | bool has_rtree() const { return rtree_ != nullptr; } | 
|  | sk_sp<const DlRTree> rtree() const { return rtree_; } | 
|  |  | 
|  | bool Equals(const DisplayList* other) const; | 
|  | bool Equals(const DisplayList& other) const { return Equals(&other); } | 
|  | bool Equals(const sk_sp<const DisplayList>& other) const { | 
|  | return Equals(other.get()); | 
|  | } | 
|  |  | 
|  | bool can_apply_group_opacity() const { return can_apply_group_opacity_; } | 
|  | bool isUIThreadSafe() const { return is_ui_thread_safe_; } | 
|  |  | 
|  | /// @brief     Indicates if there are any rendering operations in this | 
|  | ///            DisplayList that will modify a surface of transparent black | 
|  | ///            pixels. | 
|  | /// | 
|  | /// This condition can be used to determine whether to create a cleared | 
|  | /// surface, render a DisplayList into it, and then composite the | 
|  | /// result into a scene. It is not uncommon for code in the engine to | 
|  | /// come across such degenerate DisplayList objects when slicing up a | 
|  | /// frame between platform views. | 
|  | bool modifies_transparent_black() const { | 
|  | return modifies_transparent_black_; | 
|  | } | 
|  |  | 
|  | const DisplayListStorage& GetStorage() const { return storage_; } | 
|  |  | 
|  | /// @brief    Indicates if there are any saveLayer operations at the root | 
|  | ///           surface level of the DisplayList that use a backdrop filter. | 
|  | /// | 
|  | /// This condition can be used to determine what kind of surface to create | 
|  | /// for the root layer into which to render the DisplayList as some GPUs | 
|  | /// can support surfaces that do or do not support the readback that would | 
|  | /// be required for the backdrop filter to do its work. | 
|  | bool root_has_backdrop_filter() const { return root_has_backdrop_filter_; } | 
|  |  | 
|  | /// @brief    Indicates the maximum DlBlendMode used on any rendering op | 
|  | ///           in the root surface of the DisplayList. | 
|  | /// | 
|  | /// This condition can be used to determine what kind of surface to create | 
|  | /// for the root layer into which to render the DisplayList as some GPUs | 
|  | /// can support surfaces that do or do not support the readback that would | 
|  | /// be required for the indicated blend mode to do its work. | 
|  | DlBlendMode max_root_blend_mode() const { return max_root_blend_mode_; } | 
|  |  | 
|  | private: | 
|  | DisplayList(DisplayListStorage&& ptr, | 
|  | size_t byte_count, | 
|  | uint32_t op_count, | 
|  | size_t nested_byte_count, | 
|  | uint32_t nested_op_count, | 
|  | uint32_t total_depth, | 
|  | const SkRect& bounds, | 
|  | bool can_apply_group_opacity, | 
|  | bool is_ui_thread_safe, | 
|  | bool modifies_transparent_black, | 
|  | DlBlendMode max_root_blend_mode, | 
|  | bool root_has_backdrop_filter, | 
|  | sk_sp<const DlRTree> rtree); | 
|  |  | 
|  | static uint32_t next_unique_id(); | 
|  |  | 
|  | static void DisposeOps(const uint8_t* ptr, const uint8_t* end); | 
|  |  | 
|  | const DisplayListStorage storage_; | 
|  | const size_t byte_count_; | 
|  | const uint32_t op_count_; | 
|  |  | 
|  | const size_t nested_byte_count_; | 
|  | const uint32_t nested_op_count_; | 
|  |  | 
|  | const uint32_t total_depth_; | 
|  |  | 
|  | const uint32_t unique_id_; | 
|  | const SkRect bounds_; | 
|  |  | 
|  | const bool can_apply_group_opacity_; | 
|  | const bool is_ui_thread_safe_; | 
|  | const bool modifies_transparent_black_; | 
|  | const bool root_has_backdrop_filter_; | 
|  | const DlBlendMode max_root_blend_mode_; | 
|  |  | 
|  | const sk_sp<const DlRTree> rtree_; | 
|  |  | 
|  | void Dispatch(DlOpReceiver& ctx, | 
|  | const uint8_t* ptr, | 
|  | const uint8_t* end, | 
|  | Culler& culler) const; | 
|  |  | 
|  | friend class DisplayListBuilder; | 
|  | }; | 
|  |  | 
|  | }  // namespace flutter | 
|  |  | 
|  | #endif  // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_H_ |