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