| 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_DISPLAY_LIST_DL_CANVAS_H_ |
| 6 | #define FLUTTER_DISPLAY_LIST_DL_CANVAS_H_ |
| 7 | |
| 8 | #include "flutter/display_list/dl_blend_mode.h" |
| 9 | #include "flutter/display_list/dl_paint.h" |
| 10 | #include "flutter/display_list/dl_vertices.h" |
| 11 | #include "flutter/display_list/image/dl_image.h" |
| 12 | |
| 13 | #include "third_party/skia/include/core/SkM44.h" |
| 14 | #include "third_party/skia/include/core/SkMatrix.h" |
| 15 | #include "third_party/skia/include/core/SkPath.h" |
| 16 | #include "third_party/skia/include/core/SkRRect.h" |
| 17 | #include "third_party/skia/include/core/SkRSXform.h" |
| 18 | #include "third_party/skia/include/core/SkRect.h" |
| 19 | #include "third_party/skia/include/core/SkTextBlob.h" |
| 20 | |
| 21 | namespace flutter { |
| 22 | |
| 23 | // The primary class used to express rendering operations in the |
| 24 | // DisplayList ecosystem. This class is an API-only virtual class and |
| 25 | // can be used to talk to a DisplayListBuilder to record a series of |
| 26 | // rendering operations, or it could be the public facing API of an |
| 27 | // adapter that forwards the calls to another rendering module, like |
| 28 | // Skia. |
| 29 | // |
| 30 | // Developers familiar with Skia's SkCanvas API will be immediately |
| 31 | // familiar with the methods below as they follow that API closely |
| 32 | // but with DisplayList objects and values used as data instead. |
| 33 | class DlCanvas { |
| 34 | public: |
| 35 | enum class ClipOp { |
| 36 | kDifference, |
| 37 | kIntersect, |
| 38 | }; |
| 39 | |
| 40 | enum class PointMode { |
| 41 | kPoints, //!< draw each point separately |
| 42 | kLines, //!< draw each separate pair of points as a line segment |
| 43 | kPolygon, //!< draw each pair of overlapping points as a line segment |
| 44 | }; |
| 45 | |
| 46 | enum class SrcRectConstraint { |
| 47 | kStrict, |
| 48 | kFast, |
| 49 | }; |
| 50 | |
| 51 | virtual ~DlCanvas() = default; |
| 52 | |
| 53 | virtual SkISize GetBaseLayerSize() const = 0; |
| 54 | virtual SkImageInfo GetImageInfo() const = 0; |
| 55 | |
| 56 | virtual void Save() = 0; |
| 57 | virtual void SaveLayer(const SkRect* bounds, |
| 58 | const DlPaint* paint = nullptr, |
| 59 | const DlImageFilter* backdrop = nullptr) = 0; |
| 60 | virtual void Restore() = 0; |
| 61 | virtual int GetSaveCount() const = 0; |
| 62 | virtual void RestoreToCount(int restore_count) = 0; |
| 63 | |
| 64 | virtual void Translate(SkScalar tx, SkScalar ty) = 0; |
| 65 | virtual void Scale(SkScalar sx, SkScalar sy) = 0; |
| 66 | virtual void Rotate(SkScalar degrees) = 0; |
| 67 | virtual void Skew(SkScalar sx, SkScalar sy) = 0; |
| 68 | |
| 69 | // clang-format off |
| 70 | |
| 71 | // 2x3 2D affine subset of a 4x4 transform in row major order |
| 72 | virtual void Transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt, |
| 73 | SkScalar myx, SkScalar myy, SkScalar myt) = 0; |
| 74 | // full 4x4 transform in row major order |
| 75 | virtual void TransformFullPerspective( |
| 76 | SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt, |
| 77 | SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt, |
| 78 | SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt, |
| 79 | SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) = 0; |
| 80 | // clang-format on |
| 81 | virtual void TransformReset() = 0; |
| 82 | virtual void Transform(const SkMatrix* matrix) = 0; |
| 83 | virtual void Transform(const SkM44* matrix44) = 0; |
| 84 | virtual void Transform(const SkMatrix& matrix) { Transform(matrix: &matrix); } |
| 85 | virtual void Transform(const SkM44& matrix44) { Transform(matrix44: &matrix44); } |
| 86 | virtual void SetTransform(const SkMatrix* matrix) = 0; |
| 87 | virtual void SetTransform(const SkM44* matrix44) = 0; |
| 88 | virtual void SetTransform(const SkMatrix& matrix) { SetTransform(&matrix); } |
| 89 | virtual void SetTransform(const SkM44& matrix44) { SetTransform(&matrix44); } |
| 90 | |
| 91 | /// Returns the 4x4 full perspective transform representing all transform |
| 92 | /// operations executed so far in this DisplayList within the enclosing |
| 93 | /// save stack. |
| 94 | virtual SkM44 GetTransformFullPerspective() const = 0; |
| 95 | /// Returns the 3x3 partial perspective transform representing all transform |
| 96 | /// operations executed so far in this DisplayList within the enclosing |
| 97 | /// save stack. |
| 98 | virtual SkMatrix GetTransform() const = 0; |
| 99 | |
| 100 | virtual void ClipRect(const SkRect& rect, |
| 101 | ClipOp clip_op = ClipOp::kIntersect, |
| 102 | bool is_aa = false) = 0; |
| 103 | virtual void ClipRRect(const SkRRect& rrect, |
| 104 | ClipOp clip_op = ClipOp::kIntersect, |
| 105 | bool is_aa = false) = 0; |
| 106 | virtual void ClipPath(const SkPath& path, |
| 107 | ClipOp clip_op = ClipOp::kIntersect, |
| 108 | bool is_aa = false) = 0; |
| 109 | |
| 110 | /// Conservative estimate of the bounds of all outstanding clip operations |
| 111 | /// measured in the coordinate space within which this DisplayList will |
| 112 | /// be rendered. |
| 113 | virtual SkRect GetDestinationClipBounds() const = 0; |
| 114 | /// Conservative estimate of the bounds of all outstanding clip operations |
| 115 | /// transformed into the local coordinate space in which currently |
| 116 | /// recorded rendering operations are interpreted. |
| 117 | virtual SkRect GetLocalClipBounds() const = 0; |
| 118 | |
| 119 | /// Return true iff the supplied bounds are easily shown to be outside |
| 120 | /// of the current clip bounds. This method may conservatively return |
| 121 | /// false if it cannot make the determination. |
| 122 | virtual bool QuickReject(const SkRect& bounds) const = 0; |
| 123 | |
| 124 | virtual void DrawPaint(const DlPaint& paint) = 0; |
| 125 | virtual void DrawColor(DlColor color, |
| 126 | DlBlendMode mode = DlBlendMode::kSrcOver) = 0; |
| 127 | void Clear(DlColor color) { DrawColor(color, mode: DlBlendMode::kSrc); } |
| 128 | virtual void DrawLine(const SkPoint& p0, |
| 129 | const SkPoint& p1, |
| 130 | const DlPaint& paint) = 0; |
| 131 | virtual void DrawRect(const SkRect& rect, const DlPaint& paint) = 0; |
| 132 | virtual void DrawOval(const SkRect& bounds, const DlPaint& paint) = 0; |
| 133 | virtual void DrawCircle(const SkPoint& center, |
| 134 | SkScalar radius, |
| 135 | const DlPaint& paint) = 0; |
| 136 | virtual void DrawRRect(const SkRRect& rrect, const DlPaint& paint) = 0; |
| 137 | virtual void DrawDRRect(const SkRRect& outer, |
| 138 | const SkRRect& inner, |
| 139 | const DlPaint& paint) = 0; |
| 140 | virtual void DrawPath(const SkPath& path, const DlPaint& paint) = 0; |
| 141 | virtual void DrawArc(const SkRect& bounds, |
| 142 | SkScalar start, |
| 143 | SkScalar sweep, |
| 144 | bool useCenter, |
| 145 | const DlPaint& paint) = 0; |
| 146 | virtual void DrawPoints(PointMode mode, |
| 147 | uint32_t count, |
| 148 | const SkPoint pts[], |
| 149 | const DlPaint& paint) = 0; |
| 150 | virtual void DrawVertices(const DlVertices* vertices, |
| 151 | DlBlendMode mode, |
| 152 | const DlPaint& paint) = 0; |
| 153 | void DrawVertices(const std::shared_ptr<const DlVertices> vertices, |
| 154 | DlBlendMode mode, |
| 155 | const DlPaint& paint) { |
| 156 | DrawVertices(vertices: vertices.get(), mode, paint); |
| 157 | } |
| 158 | virtual void DrawImage(const sk_sp<DlImage>& image, |
| 159 | const SkPoint point, |
| 160 | DlImageSampling sampling, |
| 161 | const DlPaint* paint = nullptr) = 0; |
| 162 | virtual void DrawImageRect( |
| 163 | const sk_sp<DlImage>& image, |
| 164 | const SkRect& src, |
| 165 | const SkRect& dst, |
| 166 | DlImageSampling sampling, |
| 167 | const DlPaint* paint = nullptr, |
| 168 | SrcRectConstraint constraint = SrcRectConstraint::kFast) = 0; |
| 169 | virtual void DrawImageRect( |
| 170 | const sk_sp<DlImage>& image, |
| 171 | const SkIRect& src, |
| 172 | const SkRect& dst, |
| 173 | DlImageSampling sampling, |
| 174 | const DlPaint* paint = nullptr, |
| 175 | SrcRectConstraint constraint = SrcRectConstraint::kFast) { |
| 176 | DrawImageRect(image, src: SkRect::Make(irect: src), dst, sampling, paint, constraint); |
| 177 | } |
| 178 | virtual void DrawImageRect( |
| 179 | const sk_sp<DlImage>& image, |
| 180 | const SkRect& dst, |
| 181 | DlImageSampling sampling, |
| 182 | const DlPaint* paint = nullptr, |
| 183 | SrcRectConstraint constraint = SrcRectConstraint::kFast) { |
| 184 | DrawImageRect(image, src: image->bounds(), dst, sampling, paint, constraint); |
| 185 | } |
| 186 | virtual void DrawImageNine(const sk_sp<DlImage>& image, |
| 187 | const SkIRect& center, |
| 188 | const SkRect& dst, |
| 189 | DlFilterMode filter, |
| 190 | const DlPaint* paint = nullptr) = 0; |
| 191 | virtual void DrawAtlas(const sk_sp<DlImage>& atlas, |
| 192 | const SkRSXform xform[], |
| 193 | const SkRect tex[], |
| 194 | const DlColor colors[], |
| 195 | int count, |
| 196 | DlBlendMode mode, |
| 197 | DlImageSampling sampling, |
| 198 | const SkRect* cullRect, |
| 199 | const DlPaint* paint = nullptr) = 0; |
| 200 | virtual void DrawDisplayList(const sk_sp<DisplayList> display_list, |
| 201 | SkScalar opacity = SK_Scalar1) = 0; |
| 202 | virtual void DrawTextBlob(const sk_sp<SkTextBlob>& blob, |
| 203 | SkScalar x, |
| 204 | SkScalar y, |
| 205 | const DlPaint& paint) = 0; |
| 206 | virtual void DrawShadow(const SkPath& path, |
| 207 | const DlColor color, |
| 208 | const SkScalar elevation, |
| 209 | bool transparent_occluder, |
| 210 | SkScalar dpr) = 0; |
| 211 | |
| 212 | virtual void Flush() = 0; |
| 213 | |
| 214 | static constexpr SkScalar kShadowLightHeight = 600; |
| 215 | static constexpr SkScalar kShadowLightRadius = 800; |
| 216 | |
| 217 | static SkRect ComputeShadowBounds(const SkPath& path, |
| 218 | float elevation, |
| 219 | SkScalar dpr, |
| 220 | const SkMatrix& ctm); |
| 221 | }; |
| 222 | |
| 223 | class DlAutoCanvasRestore { |
| 224 | public: |
| 225 | DlAutoCanvasRestore(DlCanvas* canvas, bool do_save) : canvas_(canvas) { |
| 226 | if (canvas) { |
| 227 | canvas_ = canvas; |
| 228 | restore_count_ = canvas->GetSaveCount(); |
| 229 | if (do_save) { |
| 230 | canvas_->Save(); |
| 231 | } |
| 232 | } else { |
| 233 | canvas_ = nullptr; |
| 234 | restore_count_ = 0; |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | ~DlAutoCanvasRestore() { Restore(); } |
| 239 | |
| 240 | void Restore() { |
| 241 | if (canvas_) { |
| 242 | canvas_->RestoreToCount(restore_count: restore_count_); |
| 243 | canvas_ = nullptr; |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | private: |
| 248 | DlCanvas* canvas_; |
| 249 | int restore_count_; |
| 250 | |
| 251 | FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlAutoCanvasRestore); |
| 252 | }; |
| 253 | |
| 254 | } // namespace flutter |
| 255 | |
| 256 | #endif // FLUTTER_DISPLAY_LIST_DL_CANVAS_H_ |
| 257 | |