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_DISPLAY_LIST_DISPATCHER_H_ |

6 | #define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_DISPATCHER_H_ |

7 | |

8 | #include "flutter/display_list/display_list.h" |

9 | #include "flutter/display_list/dl_blend_mode.h" |

10 | #include "flutter/display_list/dl_canvas.h" |

11 | #include "flutter/display_list/dl_paint.h" |

12 | #include "flutter/display_list/dl_sampling_options.h" |

13 | #include "flutter/display_list/dl_vertices.h" |

14 | #include "flutter/display_list/effects/dl_color_filter.h" |

15 | #include "flutter/display_list/effects/dl_color_source.h" |

16 | #include "flutter/display_list/effects/dl_image_filter.h" |

17 | #include "flutter/display_list/effects/dl_mask_filter.h" |

18 | #include "flutter/display_list/effects/dl_path_effect.h" |

19 | #include "flutter/display_list/image/dl_image.h" |

20 | |

21 | namespace flutter { |

22 | |

23 | class DisplayList; |

24 | |

25 | //------------------------------------------------------------------------------ |

26 | /// @brief The pure virtual interface for interacting with a display list. |

27 | /// This interface represents the methods used to build a list |

28 | /// through the DisplayListBuilder and also the methods that will be |

29 | /// invoked through the DisplayList::dispatch() method. |

30 | /// |

31 | class DlOpReceiver { |

32 | protected: |

33 | using ClipOp = DlCanvas::ClipOp; |

34 | using PointMode = DlCanvas::PointMode; |

35 | using SrcRectConstraint = DlCanvas::SrcRectConstraint; |

36 | |

37 | public: |

38 | // MaxDrawPointsCount * sizeof(SkPoint) must be less than 1 << 32 |

39 | static constexpr int kMaxDrawPointsCount = ((1 << 29) - 1); |

40 | |

41 | // The following methods are nearly 1:1 with the methods on DlPaint and |

42 | // carry the same meanings. Each method sets a persistent value for the |

43 | // attribute for the rest of the display list or until it is reset by |

44 | // another method that changes the same attribute. The current set of |

45 | // attributes is not affected by |save| and |restore|. |

46 | virtual void setAntiAlias(bool aa) = 0; |

47 | virtual void setDither(bool dither) = 0; |

48 | virtual void setDrawStyle(DlDrawStyle style) = 0; |

49 | virtual void setColor(DlColor color) = 0; |

50 | virtual void setStrokeWidth(float width) = 0; |

51 | virtual void setStrokeMiter(float limit) = 0; |

52 | virtual void setStrokeCap(DlStrokeCap cap) = 0; |

53 | virtual void setStrokeJoin(DlStrokeJoin join) = 0; |

54 | virtual void setColorSource(const DlColorSource* source) = 0; |

55 | virtual void setColorFilter(const DlColorFilter* filter) = 0; |

56 | // setInvertColors is a quick way to set a ColorFilter that inverts the |

57 | // rgb values of all rendered colors. |

58 | // It is not reset by |setColorFilter|, but instead composed with that |

59 | // filter so that the color inversion happens after the ColorFilter. |

60 | virtual void setInvertColors(bool invert) = 0; |

61 | virtual void setBlendMode(DlBlendMode mode) = 0; |

62 | virtual void setPathEffect(const DlPathEffect* effect) = 0; |

63 | virtual void setMaskFilter(const DlMaskFilter* filter) = 0; |

64 | virtual void setImageFilter(const DlImageFilter* filter) = 0; |

65 | |

66 | // All of the following methods are nearly 1:1 with their counterparts |

67 | // in |SkCanvas| and have the same behavior and output. |

68 | virtual void save() = 0; |

69 | // The |options| parameter can specify whether the existing rendering |

70 | // attributes will be applied to the save layer surface while rendering |

71 | // it back to the current surface. If the flag is false then this method |

72 | // is equivalent to |SkCanvas::saveLayer| with a null paint object. |

73 | // The |options| parameter may contain other options that indicate some |

74 | // specific optimizations may be made by the underlying implementation |

75 | // to avoid creating a temporary layer, these optimization options will |

76 | // be determined as the |DisplayList| is constructed and should not be |

77 | // specified in calling a |DisplayListBuilder| as they will be ignored. |

78 | // The |backdrop| filter, if not null, is used to initialize the new |

79 | // layer before further rendering happens. |

80 | virtual void saveLayer(const SkRect* bounds, |

81 | const SaveLayerOptions options, |

82 | const DlImageFilter* backdrop = nullptr) = 0; |

83 | virtual void restore() = 0; |

84 | |

85 | virtual void translate(SkScalar tx, SkScalar ty) = 0; |

86 | virtual void scale(SkScalar sx, SkScalar sy) = 0; |

87 | virtual void rotate(SkScalar degrees) = 0; |

88 | virtual void skew(SkScalar sx, SkScalar sy) = 0; |

89 | |

90 | // The transform methods all assume the following math for transforming |

91 | // an arbitrary 3D homogenous point (x, y, z, w). |

92 | // All coordinates in the rendering methods (and SkPoint and SkRect objects) |

93 | // represent a simplified coordinate (x, y, 0, 1). |

94 | // x' = x * mxx + y * mxy + z * mxz + w * mxt |

95 | // y' = x * myx + y * myy + z * myz + w * myt |

96 | // z' = x * mzx + y * mzy + z * mzz + w * mzt |

97 | // w' = x * mwx + y * mwy + z * mwz + w * mwt |

98 | // Note that for non-homogenous 2D coordinates, the last column in those |

99 | // equations is multiplied by 1 and is simply adding a translation and |

100 | // so is referred to with the final letter "t" here instead of "w". |

101 | // |

102 | // In 2D coordinates, z=0 and so the 3rd column always evaluates to 0. |

103 | // |

104 | // In non-perspective transforms, the 4th row has identity values |

105 | // and so w` = w. (i.e. w'=1 for 2d points transformed by a matrix |

106 | // with identity values in the last row). |

107 | // |

108 | // In affine 2D transforms, the 3rd and 4th row and 3rd column are all |

109 | // identity values and so z` = z (which is 0 for 2D coordinates) and |

110 | // the x` and y` equations don't see a contribution from a z coordinate |

111 | // and the w' ends up being the same as the w from the source coordinate |

112 | // (which is 1 for a 2D coordinate). |

113 | // |

114 | // Here is the math for transforming a 2D source coordinate and |

115 | // looking for the destination 2D coordinate (for a surface that |

116 | // does not have a Z buffer or track the Z coordinates in any way) |

117 | // Source coordinate = (x, y, 0, 1) |

118 | // x' = x * mxx + y * mxy + 0 * mxz + 1 * mxt |

119 | // y' = x * myx + y * myy + 0 * myz + 1 * myt |

120 | // z' = x * mzx + y * mzy + 0 * mzz + 1 * mzt |

121 | // w' = x * mwx + y * mwy + 0 * mwz + 1 * mwt |

122 | // Destination coordinate does not need z', so this reduces to: |

123 | // x' = x * mxx + y * mxy + mxt |

124 | // y' = x * myx + y * myy + myt |

125 | // w' = x * mwx + y * mwy + mwt |

126 | // Destination coordinate is (x' / w', y' / w', 0, 1) |

127 | // Note that these are the matrix values in SkMatrix which means that |

128 | // an SkMatrix contains enough data to transform a 2D source coordinate |

129 | // and place it on a 2D surface, but is otherwise not enough to continue |

130 | // concatenating with further matrices as its missing elements will not |

131 | // be able to model the interplay between the rows and columns that |

132 | // happens during a full 4x4 by 4x4 matrix multiplication. |

133 | // |

134 | // If the transform doesn't have any perspective parts (the last |

135 | // row is identity - 0, 0, 0, 1), then this further simplifies to: |

136 | // x' = x * mxx + y * mxy + mxt |

137 | // y' = x * myx + y * myy + myt |

138 | // w' = x * 0 + y * 0 + 1 = 1 |

139 | // |

140 | // In short, while the full 4x4 set of matrix entries needs to be |

141 | // maintained for accumulating transform mutations accurately, the |

142 | // actual end work of transforming a single 2D coordinate (or, in |

143 | // the case of bounds transformations, 4 of them) can be accomplished |

144 | // with the 9 values from transform3x3 or SkMatrix. |

145 | // |

146 | // The only need for the w value here is for homogenous coordinates |

147 | // which only come up if the perspective elements (the 4th row) of |

148 | // a transform are non-identity. Otherwise the w always ends up |

149 | // being 1 in all calculations. If the matrix has perspecitve elements |

150 | // then the final transformed coordinates will have a w that is not 1 |

151 | // and the actual coordinates are determined by dividing out that w |

152 | // factor resulting in a real-world point expressed as (x, y, z, 1). |

153 | // |

154 | // Because of the predominance of 2D affine transforms the |

155 | // 2x3 subset of the 4x4 transform matrix is special cased with |

156 | // its own dispatch method that omits the last 2 rows and the 3rd |

157 | // column. Even though a 3x3 subset is enough for transforming |

158 | // leaf coordinates as shown above, no method is provided for |

159 | // representing a 3x3 transform in the DisplayList since if there |

160 | // is perspective involved then a full 4x4 matrix should be provided |

161 | // for accurate concatenations. Providing a 3x3 method or record |

162 | // in the stream would encourage developers to prematurely subset |

163 | // a full perspective matrix. |

164 | |

165 | // clang-format off |

166 | |

167 | // |transform2DAffine| is equivalent to concatenating the internal |

168 | // 4x4 transform with the following row major transform matrix: |

169 | // [ mxx mxy 0 mxt ] |

170 | // [ myx myy 0 myt ] |

171 | // [ 0 0 1 0 ] |

172 | // [ 0 0 0 1 ] |

173 | virtual void transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt, |

174 | SkScalar myx, SkScalar myy, SkScalar myt) = 0; |

175 | // |transformFullPerspective| is equivalent to concatenating the internal |

176 | // 4x4 transform with the following row major transform matrix: |

177 | // [ mxx mxy mxz mxt ] |

178 | // [ myx myy myz myt ] |

179 | // [ mzx mzy mzz mzt ] |

180 | // [ mwx mwy mwz mwt ] |

181 | virtual void transformFullPerspective( |

182 | SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt, |

183 | SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt, |

184 | SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt, |

185 | SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) = 0; |

186 | // clang-format on |

187 | |

188 | // Clears the transformation stack. |

189 | virtual void transformReset() = 0; |

190 | |

191 | virtual void clipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) = 0; |

192 | virtual void clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) = 0; |

193 | virtual void clipPath(const SkPath& path, ClipOp clip_op, bool is_aa) = 0; |

194 | |

195 | // The following rendering methods all take their rendering attributes |

196 | // from the last value set by the attribute methods above (regardless |

197 | // of any |save| or |restore| operations which do not affect attributes). |

198 | // In cases where a paint object may have been optional in the SkCanvas |

199 | // method, the methods here will generally offer a boolean parameter |

200 | // which specifies whether to honor the attributes of the display list |

201 | // stream, or assume default attributes. |

202 | virtual void drawColor(DlColor color, DlBlendMode mode) = 0; |

203 | virtual void drawPaint() = 0; |

204 | virtual void drawLine(const SkPoint& p0, const SkPoint& p1) = 0; |

205 | virtual void drawRect(const SkRect& rect) = 0; |

206 | virtual void drawOval(const SkRect& bounds) = 0; |

207 | virtual void drawCircle(const SkPoint& center, SkScalar radius) = 0; |

208 | virtual void drawRRect(const SkRRect& rrect) = 0; |

209 | virtual void drawDRRect(const SkRRect& outer, const SkRRect& inner) = 0; |

210 | virtual void drawPath(const SkPath& path) = 0; |

211 | virtual void drawArc(const SkRect& oval_bounds, |

212 | SkScalar start_degrees, |

213 | SkScalar sweep_degrees, |

214 | bool use_center) = 0; |

215 | virtual void drawPoints(PointMode mode, |

216 | uint32_t count, |

217 | const SkPoint points[]) = 0; |

218 | virtual void drawVertices(const DlVertices* vertices, DlBlendMode mode) = 0; |

219 | virtual void drawImage(const sk_sp<DlImage> image, |

220 | const SkPoint point, |

221 | DlImageSampling sampling, |

222 | bool render_with_attributes) = 0; |

223 | virtual void drawImageRect( |

224 | const sk_sp<DlImage> image, |

225 | const SkRect& src, |

226 | const SkRect& dst, |

227 | DlImageSampling sampling, |

228 | bool render_with_attributes, |

229 | SrcRectConstraint constraint = SrcRectConstraint::kFast) = 0; |

230 | virtual void drawImageNine(const sk_sp<DlImage> image, |

231 | const SkIRect& center, |

232 | const SkRect& dst, |

233 | DlFilterMode filter, |

234 | bool render_with_attributes) = 0; |

235 | virtual void drawAtlas(const sk_sp<DlImage> atlas, |

236 | const SkRSXform xform[], |

237 | const SkRect tex[], |

238 | const DlColor colors[], |

239 | int count, |

240 | DlBlendMode mode, |

241 | DlImageSampling sampling, |

242 | const SkRect* cull_rect, |

243 | bool render_with_attributes) = 0; |

244 | virtual void drawDisplayList(const sk_sp<DisplayList> display_list, |

245 | SkScalar opacity = SK_Scalar1) = 0; |

246 | virtual void drawTextBlob(const sk_sp<SkTextBlob> blob, |

247 | SkScalar x, |

248 | SkScalar y) = 0; |

249 | virtual void drawShadow(const SkPath& path, |

250 | const DlColor color, |

251 | const SkScalar elevation, |

252 | bool transparent_occluder, |

253 | SkScalar dpr) = 0; |

254 | }; |

255 | |

256 | } // namespace flutter |

257 | |

258 | #endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_DISPATCHER_H_ |

259 |