| // 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_DISPLAY_LIST_H_ |
| #define FLUTTER_FLOW_DISPLAY_LIST_H_ |
| |
| #include "third_party/skia/include/core/SkBlender.h" |
| #include "third_party/skia/include/core/SkBlurTypes.h" |
| #include "third_party/skia/include/core/SkCanvas.h" |
| #include "third_party/skia/include/core/SkColorFilter.h" |
| #include "third_party/skia/include/core/SkImage.h" |
| #include "third_party/skia/include/core/SkImageFilter.h" |
| #include "third_party/skia/include/core/SkPathEffect.h" |
| #include "third_party/skia/include/core/SkPicture.h" |
| #include "third_party/skia/include/core/SkShader.h" |
| #include "third_party/skia/include/core/SkVertices.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 Dispatcher |
| // Dispatcher: 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 the same |
| // calls defined in the Dispatcher |
| // |
| // Other files include various class definitions for dealing with display |
| // lists, such as: |
| // display_list_canvas.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 Dispatcher, 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 Dispatcher can inherit from |
| // these utility classes to simplify its creation |
| // |
| // The Flutter DisplayList mechanism can be used in place of the Skia |
| // SkPicture mechanism. The primary means of communication into and out |
| // of the DisplayList is through the Dispatcher virtual class which |
| // provides a nearly 1:1 translation between the records of the DisplayList |
| // to method calls. |
| // |
| // A DisplayList can be created directly using a DisplayListBuilder and |
| // the Dispatcher methods that it implements, or it can be created from |
| // a sequence of SkCanvas calls using the DisplayListCanvasRecorder class. |
| // |
| // A DisplayList can be read back by implementing the Dispatcher 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 DisplayListCanvasDispatcher or simply by passing an |
| // SkCanvas pointer to its renderTo() method. |
| // |
| // 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(SetDither) \ |
| V(SetInvertColors) \ |
| \ |
| V(SetStrokeCap) \ |
| V(SetStrokeJoin) \ |
| \ |
| V(SetStyle) \ |
| V(SetStrokeWidth) \ |
| V(SetStrokeMiter) \ |
| \ |
| V(SetColor) \ |
| V(SetBlendMode) \ |
| \ |
| V(SetBlender) \ |
| V(ClearBlender) \ |
| V(SetShader) \ |
| V(ClearShader) \ |
| V(SetColorFilter) \ |
| V(ClearColorFilter) \ |
| V(SetImageFilter) \ |
| V(ClearImageFilter) \ |
| V(SetPathEffect) \ |
| V(ClearPathEffect) \ |
| \ |
| V(ClearMaskFilter) \ |
| V(SetMaskFilter) \ |
| V(SetMaskBlurFilterNormal) \ |
| V(SetMaskBlurFilterSolid) \ |
| V(SetMaskBlurFilterOuter) \ |
| V(SetMaskBlurFilterInner) \ |
| \ |
| V(Save) \ |
| V(SaveLayer) \ |
| V(SaveLayerBounds) \ |
| V(Restore) \ |
| \ |
| V(Translate) \ |
| V(Scale) \ |
| V(Rotate) \ |
| V(Skew) \ |
| V(Transform2DAffine) \ |
| V(TransformFullPerspective) \ |
| \ |
| V(ClipIntersectRect) \ |
| V(ClipIntersectRRect) \ |
| V(ClipIntersectPath) \ |
| V(ClipDifferenceRect) \ |
| V(ClipDifferenceRRect) \ |
| V(ClipDifferencePath) \ |
| \ |
| V(DrawPaint) \ |
| V(DrawColor) \ |
| \ |
| V(DrawLine) \ |
| 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(DrawImageLattice) \ |
| V(DrawAtlas) \ |
| V(DrawAtlasCulled) \ |
| \ |
| V(DrawSkPicture) \ |
| V(DrawSkPictureMatrix) \ |
| V(DrawDisplayList) \ |
| V(DrawTextBlob) \ |
| \ |
| 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) }; |
| #undef DL_OP_TO_ENUM_VALUE |
| |
| class Dispatcher; |
| class DisplayListBuilder; |
| |
| // The base class that contains a sequence of rendering operations |
| // for dispatch to a Dispatcher. These objects must be instantiated |
| // through an instance of DisplayListBuilder::build(). |
| class DisplayList : public SkRefCnt { |
| public: |
| static const SkSamplingOptions NearestSampling; |
| static const SkSamplingOptions LinearSampling; |
| static const SkSamplingOptions MipmapSampling; |
| static const SkSamplingOptions CubicSampling; |
| |
| DisplayList() |
| : byte_count_(0), |
| op_count_(0), |
| nested_byte_count_(0), |
| nested_op_count_(0), |
| unique_id_(0), |
| bounds_({0, 0, 0, 0}), |
| bounds_cull_({0, 0, 0, 0}) {} |
| |
| ~DisplayList(); |
| |
| void Dispatch(Dispatcher& ctx) const { |
| uint8_t* ptr = storage_.get(); |
| Dispatch(ctx, ptr, ptr + byte_count_); |
| } |
| |
| void RenderTo(SkCanvas* canvas) const; |
| |
| // SkPicture always includes 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); |
| } |
| int op_count(bool nested = false) const { |
| return op_count_ + (nested ? nested_op_count_ : 0); |
| } |
| uint32_t unique_id() const { return unique_id_; } |
| |
| const SkRect& bounds() { |
| if (bounds_.width() < 0.0) { |
| // ComputeBounds() will leave the variable with a |
| // non-negative width and height |
| ComputeBounds(); |
| } |
| return bounds_; |
| } |
| |
| bool Equals(const DisplayList& other) const; |
| |
| private: |
| DisplayList(uint8_t* ptr, |
| size_t byte_count, |
| int op_count, |
| size_t nested_byte_count, |
| int nested_op_count, |
| const SkRect& cull_rect); |
| |
| std::unique_ptr<uint8_t, SkFunctionWrapper<void(void*), sk_free>> storage_; |
| size_t byte_count_; |
| int op_count_; |
| |
| size_t nested_byte_count_; |
| int nested_op_count_; |
| |
| uint32_t unique_id_; |
| SkRect bounds_; |
| |
| // Only used for drawPaint() and drawColor() |
| SkRect bounds_cull_; |
| |
| void ComputeBounds(); |
| void Dispatch(Dispatcher& ctx, uint8_t* ptr, uint8_t* end) const; |
| |
| friend class DisplayListBuilder; |
| }; |
| |
| // The pure virtual interface for interacting with a display list. |
| // This interface represents the methods used to build a list |
| // through the DisplayListBuilder and also the methods that will |
| // be invoked through the DisplayList::dispatch() method. |
| class Dispatcher { |
| public: |
| // MaxDrawPointsCount * sizeof(SkPoint) must be less than 1 << 32 |
| static constexpr int kMaxDrawPointsCount = ((1 << 29) - 1); |
| |
| // The following methods are nearly 1:1 with the methods on SkPaint and |
| // carry the same meanings. Each method sets a persistent value for the |
| // attribute for the rest of the display list or until it is reset by |
| // another method that changes the same attribute. The current set of |
| // attributes is not affected by |save| and |restore|. |
| virtual void setAntiAlias(bool aa) = 0; |
| virtual void setDither(bool dither) = 0; |
| virtual void setStyle(SkPaint::Style style) = 0; |
| virtual void setColor(SkColor color) = 0; |
| virtual void setStrokeWidth(SkScalar width) = 0; |
| virtual void setStrokeMiter(SkScalar limit) = 0; |
| virtual void setStrokeCap(SkPaint::Cap cap) = 0; |
| virtual void setStrokeJoin(SkPaint::Join join) = 0; |
| virtual void setShader(sk_sp<SkShader> shader) = 0; |
| virtual void setColorFilter(sk_sp<SkColorFilter> filter) = 0; |
| // setInvertColors does not exist in SkPaint, but is a quick way to set |
| // a ColorFilter that inverts the rgb values of all rendered colors. |
| // It is not reset by |setColorFilter|, but instead composed with that |
| // filter so that the color inversion happens after the ColorFilter. |
| virtual void setInvertColors(bool invert) = 0; |
| virtual void setBlendMode(SkBlendMode mode) = 0; |
| virtual void setBlender(sk_sp<SkBlender> blender) = 0; |
| virtual void setPathEffect(sk_sp<SkPathEffect> effect) = 0; |
| virtual void setMaskFilter(sk_sp<SkMaskFilter> filter) = 0; |
| // setMaskBlurFilter is a quick way to set the parameters for a |
| // mask blur filter without constructing an SkMaskFilter object. |
| // It is equivalent to setMaskFilter(SkMaskFilter::MakeBlur(style, sigma)). |
| // To reset the filter use setMaskFilter(nullptr). |
| virtual void setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) = 0; |
| virtual void setImageFilter(sk_sp<SkImageFilter> filter) = 0; |
| |
| // All of the following methods are nearly 1:1 with their counterparts |
| // in |SkCanvas| and have the same behavior and output. |
| virtual void save() = 0; |
| // The |restore_with_paint| parameter determines whether the existing |
| // rendering attributes will be applied to the save layer surface while |
| // rendering it back to the current surface. If the parameter is false |
| // then this method is equivalent to |SkCanvas::saveLayer| with a null |
| // paint object. |
| virtual void saveLayer(const SkRect* bounds, bool restore_with_paint) = 0; |
| virtual void restore() = 0; |
| |
| virtual void translate(SkScalar tx, SkScalar ty) = 0; |
| virtual void scale(SkScalar sx, SkScalar sy) = 0; |
| virtual void rotate(SkScalar degrees) = 0; |
| virtual void skew(SkScalar sx, SkScalar sy) = 0; |
| |
| // The transform methods all assume the following math for transforming |
| // an arbitrary 3D homogenous point (x, y, z, w). |
| // All coordinates in the rendering methods (and SkPoint and SkRect objects) |
| // represent a simplified coordinate (x, y, 0, 1). |
| // x' = x * mxx + y * mxy + z * mxz + w * mxt |
| // y' = x * myx + y * myy + z * myz + w * myt |
| // z' = x * mzx + y * mzy + z * mzz + w * mzt |
| // w' = x * mwx + y * mwy + z * mwz + w * mwt |
| // Note that for non-homogenous 2D coordinates, the last column in those |
| // equations is multiplied by 1 and is simply adding a translation and |
| // so is referred to with the final letter "t" here instead of "w". |
| // |
| // In 2D coordinates, z=0 and so the 3rd column always evaluates to 0. |
| // |
| // In non-perspective transforms, the 4th row has identity values |
| // and so w` = w. (i.e. w'=1 for 2d points transformed by a matrix |
| // with identity values in the last row). |
| // |
| // In affine 2D transforms, the 3rd and 4th row and 3rd column are all |
| // identity values and so z` = z (which is 0 for 2D coordinates) and |
| // the x` and y` equations don't see a contribution from a z coordinate |
| // and the w' ends up being the same as the w from the source coordinate |
| // (which is 1 for a 2D coordinate). |
| // |
| // Here is the math for transforming a 2D source coordinate and |
| // looking for the destination 2D coordinate (for a surface that |
| // does not have a Z buffer or track the Z coordinates in any way) |
| // Source coordinate = (x, y, 0, 1) |
| // x' = x * mxx + y * mxy + 0 * mxz + 1 * mxt |
| // y' = x * myx + y * myy + 0 * myz + 1 * myt |
| // z' = x * mzx + y * mzy + 0 * mzz + 1 * mzt |
| // w' = x * mwx + y * mwy + 0 * mwz + 1 * mwt |
| // Destination coordinate does not need z', so this reduces to: |
| // x' = x * mxx + y * mxy + mxt |
| // y' = x * myx + y * myy + myt |
| // w' = x * mwx + y * mwy + mwt |
| // Destination coordinate is (x' / w', y' / w', 0, 1) |
| // Note that these are the matrix values in SkMatrix which means that |
| // an SkMatrix contains enough data to transform a 2D source coordinate |
| // and place it on a 2D surface, but is otherwise not enough to continue |
| // concatenating with further matrices as its missing elements will not |
| // be able to model the interplay between the rows and columns that |
| // happens during a full 4x4 by 4x4 matrix multiplication. |
| // |
| // If the transform doesn't have any perspective parts (the last |
| // row is identity - 0, 0, 0, 1), then this further simplifies to: |
| // x' = x * mxx + y * mxy + mxt |
| // y' = x * myx + y * myy + myt |
| // w' = x * 0 + y * 0 + 1 = 1 |
| // |
| // In short, while the full 4x4 set of matrix entries needs to be |
| // maintained for accumulating transform mutations accurately, the |
| // actual end work of transforming a single 2D coordinate (or, in |
| // the case of bounds transformations, 4 of them) can be accomplished |
| // with the 9 values from transform3x3 or SkMatrix. |
| // |
| // The only need for the w value here is for homogenous coordinates |
| // which only come up if the perspective elements (the 4th row) of |
| // a transform are non-identity. Otherwise the w always ends up |
| // being 1 in all calculations. If the matrix has perspecitve elements |
| // then the final transformed coordinates will have a w that is not 1 |
| // and the actual coordinates are determined by dividing out that w |
| // factor resulting in a real-world point expressed as (x, y, z, 1). |
| // |
| // Because of the predominance of 2D affine transforms the |
| // 2x3 subset of the 4x4 transform matrix is special cased with |
| // its own dispatch method that omits the last 2 rows and the 3rd |
| // column. Even though a 3x3 subset is enough for transforming |
| // leaf coordinates as shown above, no method is provided for |
| // representing a 3x3 transform in the DisplayList since if there |
| // is perspective involved then a full 4x4 matrix should be provided |
| // for accurate concatenations. Providing a 3x3 method or record |
| // in the stream would encourage developers to prematurely subset |
| // a full perspective matrix. |
| |
| // clang-format off |
| |
| // |transform2DAffine| is equivalent to concatenating the internal |
| // 4x4 transform with the following row major transform matrix: |
| // [ mxx mxy 0 mxt ] |
| // [ myx myy 0 myt ] |
| // [ 0 0 1 0 ] |
| // [ 0 0 0 1 ] |
| virtual void transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt, |
| SkScalar myx, SkScalar myy, SkScalar myt) = 0; |
| // |transformFullPerspective| is equivalent to concatenating the internal |
| // 4x4 transform with the following row major transform matrix: |
| // [ mxx mxy mxz mxt ] |
| // [ myx myy myz myt ] |
| // [ mzx mzy mzz mzt ] |
| // [ mwx mwy mwz mwt ] |
| virtual void transformFullPerspective( |
| SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt, |
| SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt, |
| SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt, |
| SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) = 0; |
| |
| // clang-format on |
| |
| virtual void clipRect(const SkRect& rect, SkClipOp clip_op, bool is_aa) = 0; |
| virtual void clipRRect(const SkRRect& rrect, |
| SkClipOp clip_op, |
| bool is_aa) = 0; |
| virtual void clipPath(const SkPath& path, SkClipOp clip_op, bool is_aa) = 0; |
| |
| // The following rendering methods all take their rendering attributes |
| // from the last value set by the attribute methods above (regardless |
| // of any |save| or |restore| operations which do not affect attributes). |
| // In cases where a paint object may have been optional in the SkCanvas |
| // method, the methods here will generally offer a boolean parameter |
| // which specifies whether to honor the attributes of the display list |
| // stream, or assume default attributes. |
| virtual void drawColor(SkColor color, SkBlendMode mode) = 0; |
| virtual void drawPaint() = 0; |
| virtual void drawLine(const SkPoint& p0, const SkPoint& p1) = 0; |
| virtual void drawRect(const SkRect& rect) = 0; |
| virtual void drawOval(const SkRect& bounds) = 0; |
| virtual void drawCircle(const SkPoint& center, SkScalar radius) = 0; |
| virtual void drawRRect(const SkRRect& rrect) = 0; |
| virtual void drawDRRect(const SkRRect& outer, const SkRRect& inner) = 0; |
| virtual void drawPath(const SkPath& path) = 0; |
| virtual void drawArc(const SkRect& oval_bounds, |
| SkScalar start_degrees, |
| SkScalar sweep_degrees, |
| bool use_center) = 0; |
| virtual void drawPoints(SkCanvas::PointMode mode, |
| uint32_t count, |
| const SkPoint points[]) = 0; |
| virtual void drawVertices(const sk_sp<SkVertices> vertices, |
| SkBlendMode mode) = 0; |
| virtual void drawImage(const sk_sp<SkImage> image, |
| const SkPoint point, |
| const SkSamplingOptions& sampling, |
| bool render_with_attributes) = 0; |
| virtual void drawImageRect(const sk_sp<SkImage> image, |
| const SkRect& src, |
| const SkRect& dst, |
| const SkSamplingOptions& sampling, |
| bool render_with_attributes, |
| SkCanvas::SrcRectConstraint constraint) = 0; |
| virtual void drawImageNine(const sk_sp<SkImage> image, |
| const SkIRect& center, |
| const SkRect& dst, |
| SkFilterMode filter, |
| bool render_with_attributes) = 0; |
| virtual void drawImageLattice(const sk_sp<SkImage> image, |
| const SkCanvas::Lattice& lattice, |
| const SkRect& dst, |
| SkFilterMode filter, |
| bool render_with_attributes) = 0; |
| virtual void drawAtlas(const sk_sp<SkImage> atlas, |
| const SkRSXform xform[], |
| const SkRect tex[], |
| const SkColor colors[], |
| int count, |
| SkBlendMode mode, |
| const SkSamplingOptions& sampling, |
| const SkRect* cull_rect, |
| bool render_with_attributes) = 0; |
| virtual void drawPicture(const sk_sp<SkPicture> picture, |
| const SkMatrix* matrix, |
| bool render_with_attributes) = 0; |
| virtual void drawDisplayList(const sk_sp<DisplayList> display_list) = 0; |
| virtual void drawTextBlob(const sk_sp<SkTextBlob> blob, |
| SkScalar x, |
| SkScalar y) = 0; |
| virtual void drawShadow(const SkPath& path, |
| const SkColor color, |
| const SkScalar elevation, |
| bool transparent_occluder, |
| SkScalar dpr) = 0; |
| }; |
| |
| // The primary class used to build a display list. The list of methods |
| // here matches the list of methods invoked on a |Dispatcher|. |
| // If there is some code that already renders to an SkCanvas object, |
| // those rendering commands can be captured into a DisplayList using |
| // the DisplayListCanvasRecorder class. |
| class DisplayListBuilder final : public virtual Dispatcher, public SkRefCnt { |
| public: |
| DisplayListBuilder(const SkRect& cull_rect = kMaxCullRect_); |
| ~DisplayListBuilder(); |
| |
| void setAntiAlias(bool aa) override; |
| void setDither(bool dither) override; |
| void setInvertColors(bool invert) override; |
| void setStrokeCap(SkPaint::Cap cap) override; |
| void setStrokeJoin(SkPaint::Join join) override; |
| void setStyle(SkPaint::Style style) override; |
| void setStrokeWidth(SkScalar width) override; |
| void setStrokeMiter(SkScalar limit) override; |
| void setColor(SkColor color) override; |
| void setBlendMode(SkBlendMode mode) override; |
| void setBlender(sk_sp<SkBlender> blender) override; |
| void setShader(sk_sp<SkShader> shader) override; |
| void setImageFilter(sk_sp<SkImageFilter> filter) override; |
| void setColorFilter(sk_sp<SkColorFilter> filter) override; |
| void setPathEffect(sk_sp<SkPathEffect> effect) override; |
| void setMaskFilter(sk_sp<SkMaskFilter> filter) override; |
| void setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) override; |
| |
| void save() override; |
| void saveLayer(const SkRect* bounds, bool restoreWithPaint) override; |
| void restore() override; |
| |
| void translate(SkScalar tx, SkScalar ty) override; |
| void scale(SkScalar sx, SkScalar sy) override; |
| void rotate(SkScalar degrees) override; |
| void skew(SkScalar sx, SkScalar sy) override; |
| |
| // clang-format off |
| |
| // 2x3 2D affine subset of a 4x4 transform in row major order |
| void transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt, |
| SkScalar myx, SkScalar myy, SkScalar myt) override; |
| // full 4x4 transform in row major order |
| void transformFullPerspective( |
| SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt, |
| SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt, |
| SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt, |
| SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) override; |
| |
| // clang-format on |
| |
| void clipRect(const SkRect& rect, SkClipOp clip_op, bool isAA) override; |
| void clipRRect(const SkRRect& rrect, SkClipOp clip_op, bool isAA) override; |
| void clipPath(const SkPath& path, SkClipOp clip_op, bool isAA) override; |
| |
| void drawPaint() override; |
| void drawColor(SkColor color, SkBlendMode mode) override; |
| void drawLine(const SkPoint& p0, const SkPoint& p1) override; |
| void drawRect(const SkRect& rect) override; |
| void drawOval(const SkRect& bounds) override; |
| void drawCircle(const SkPoint& center, SkScalar radius) override; |
| void drawRRect(const SkRRect& rrect) override; |
| void drawDRRect(const SkRRect& outer, const SkRRect& inner) override; |
| void drawPath(const SkPath& path) override; |
| void drawArc(const SkRect& bounds, |
| SkScalar start, |
| SkScalar sweep, |
| bool useCenter) override; |
| void drawPoints(SkCanvas::PointMode mode, |
| uint32_t count, |
| const SkPoint pts[]) override; |
| void drawVertices(const sk_sp<SkVertices> vertices, |
| SkBlendMode mode) override; |
| void drawImage(const sk_sp<SkImage> image, |
| const SkPoint point, |
| const SkSamplingOptions& sampling, |
| bool render_with_attributes) override; |
| void drawImageRect( |
| const sk_sp<SkImage> image, |
| const SkRect& src, |
| const SkRect& dst, |
| const SkSamplingOptions& sampling, |
| bool render_with_attributes, |
| SkCanvas::SrcRectConstraint constraint = |
| SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint) override; |
| void drawImageNine(const sk_sp<SkImage> image, |
| const SkIRect& center, |
| const SkRect& dst, |
| SkFilterMode filter, |
| bool render_with_attributes) override; |
| void drawImageLattice(const sk_sp<SkImage> image, |
| const SkCanvas::Lattice& lattice, |
| const SkRect& dst, |
| SkFilterMode filter, |
| bool render_with_attributes) override; |
| void drawAtlas(const sk_sp<SkImage> atlas, |
| const SkRSXform xform[], |
| const SkRect tex[], |
| const SkColor colors[], |
| int count, |
| SkBlendMode mode, |
| const SkSamplingOptions& sampling, |
| const SkRect* cullRect, |
| bool render_with_attributes) override; |
| void drawPicture(const sk_sp<SkPicture> picture, |
| const SkMatrix* matrix, |
| bool render_with_attributes) override; |
| void drawDisplayList(const sk_sp<DisplayList> display_list) override; |
| void drawTextBlob(const sk_sp<SkTextBlob> blob, |
| SkScalar x, |
| SkScalar y) override; |
| void drawShadow(const SkPath& path, |
| const SkColor color, |
| const SkScalar elevation, |
| bool transparent_occluder, |
| SkScalar dpr) override; |
| |
| sk_sp<DisplayList> Build(); |
| |
| private: |
| SkAutoTMalloc<uint8_t> storage_; |
| size_t used_ = 0; |
| size_t allocated_ = 0; |
| int op_count_ = 0; |
| int save_level_ = 0; |
| |
| // bytes and ops from |drawPicture| and |drawDisplayList| |
| size_t nested_bytes_ = 0; |
| int nested_op_count_ = 0; |
| |
| SkRect cull_rect_; |
| static constexpr SkRect kMaxCullRect_ = |
| SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F); |
| |
| template <typename T, typename... Args> |
| void* Push(size_t extra, int op_inc, Args&&... args); |
| }; |
| |
| } // namespace flutter |
| |
| #endif // FLUTTER_FLOW_DISPLAY_LIST_H_ |