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 TESTING_MOCK_CANVAS_H_
6#define TESTING_MOCK_CANVAS_H_
7
8#include <ostream>
9#include <variant>
10#include <vector>
11
12#include "flutter/testing/assertions_skia.h"
13#include "gtest/gtest.h"
14#include "third_party/skia/include/core/SkCanvas.h"
15#include "third_party/skia/include/core/SkCanvasVirtualEnforcer.h"
16#include "third_party/skia/include/core/SkClipOp.h"
17#include "third_party/skia/include/core/SkData.h"
18#include "third_party/skia/include/core/SkImageFilter.h"
19#include "third_party/skia/include/core/SkM44.h"
20#include "third_party/skia/include/core/SkPath.h"
21#include "third_party/skia/include/core/SkRRect.h"
22#include "third_party/skia/include/core/SkRect.h"
23#include "third_party/skia/include/utils/SkNWayCanvas.h"
24
25namespace flutter {
26namespace testing {
27
28static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
29
30// Mock |SkCanvas|, useful for writing tests that use Skia but do not interact
31// with the GPU.
32//
33// The |MockCanvas| stores a list of |DrawCall| that the test can later verify
34// against the expected list of primitives to be drawn.
35class MockCanvas : public SkCanvasVirtualEnforcer<SkCanvas> {
36 public:
37 using SkCanvas::kHard_ClipEdgeStyle;
38 using SkCanvas::kSoft_ClipEdgeStyle;
39
40 struct SaveData {
41 int save_to_layer;
42 };
43
44 struct SaveLayerData {
45 SkRect save_bounds;
46 SkPaint restore_paint;
47 sk_sp<SkImageFilter> backdrop_filter;
48 int save_to_layer;
49 };
50
51 struct RestoreData {
52 int restore_to_layer;
53 };
54
55 struct ConcatMatrixData {
56 SkMatrix matrix;
57 };
58
59 struct ConcatMatrix44Data {
60 SkM44 matrix;
61 };
62
63 struct SetMatrixData {
64 SkMatrix matrix;
65 };
66
67 struct DrawRectData {
68 SkRect rect;
69 SkPaint paint;
70 };
71
72 struct DrawPathData {
73 SkPath path;
74 SkPaint paint;
75 };
76
77 struct DrawTextData {
78 sk_sp<SkData> serialized_text;
79 SkPaint paint;
80 SkPoint offset;
81 };
82
83 struct DrawPictureData {
84 sk_sp<SkData> serialized_picture;
85 SkPaint paint;
86 SkMatrix matrix;
87 };
88
89 struct DrawShadowData {
90 SkPath path;
91 };
92
93 struct ClipRectData {
94 SkRect rect;
95 SkClipOp clip_op;
96 ClipEdgeStyle style;
97 };
98
99 struct ClipRRectData {
100 SkRRect rrect;
101 SkClipOp clip_op;
102 ClipEdgeStyle style;
103 };
104
105 struct ClipPathData {
106 SkPath path;
107 SkClipOp clip_op;
108 ClipEdgeStyle style;
109 };
110
111 // Discriminated union of all the different |DrawCall| types. It is roughly
112 // equivalent to the different methods in |SkCanvas|' public API.
113 using DrawCallData = std::variant<SaveData,
114 SaveLayerData,
115 RestoreData,
116 ConcatMatrixData,
117 ConcatMatrix44Data,
118 SetMatrixData,
119 DrawRectData,
120 DrawPathData,
121 DrawTextData,
122 DrawPictureData,
123 DrawShadowData,
124 ClipRectData,
125 ClipRRectData,
126 ClipPathData>;
127
128 // A single call made against this canvas.
129 struct DrawCall {
130 int layer;
131 DrawCallData data;
132 };
133
134 MockCanvas();
135 ~MockCanvas() override;
136
137 SkNWayCanvas* internal_canvas() { return &internal_canvas_; }
138
139 const std::vector<DrawCall>& draw_calls() const { return draw_calls_; }
140
141 protected:
142 // Save/restore/set operations that we track.
143 void willSave() override;
144 SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override;
145 void willRestore() override;
146 void didRestore() override {}
147 void didConcat(const SkMatrix& matrix) override;
148 void didConcat44(const SkM44&) override;
149 void didScale(SkScalar x, SkScalar y) override;
150 void didTranslate(SkScalar x, SkScalar y) override;
151 void didSetMatrix(const SkMatrix& matrix) override;
152
153 // Draw and clip operations that we track.
154 void onDrawRect(const SkRect& rect, const SkPaint& paint) override;
155 void onDrawPath(const SkPath& path, const SkPaint& paint) override;
156 void onDrawTextBlob(const SkTextBlob* text,
157 SkScalar x,
158 SkScalar y,
159 const SkPaint& paint) override;
160 void onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) override;
161 void onDrawPicture(const SkPicture* picture,
162 const SkMatrix* matrix,
163 const SkPaint* paint) override;
164 void onClipRect(const SkRect& rect,
165 SkClipOp op,
166 ClipEdgeStyle style) override;
167 void onClipRRect(const SkRRect& rrect,
168 SkClipOp op,
169 ClipEdgeStyle style) override;
170 void onClipPath(const SkPath& path,
171 SkClipOp op,
172 ClipEdgeStyle style) override;
173
174 // Operations that we don't track.
175 bool onDoSaveBehind(const SkRect*) override;
176 void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
177 void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
178 void onDrawDrawable(SkDrawable*, const SkMatrix*) override;
179 void onDrawPatch(const SkPoint[12],
180 const SkColor[4],
181 const SkPoint[4],
182 SkBlendMode,
183 const SkPaint&) override;
184 void onDrawPaint(const SkPaint&) override;
185 void onDrawBehind(const SkPaint&) override;
186 void onDrawPoints(PointMode,
187 size_t,
188 const SkPoint[],
189 const SkPaint&) override;
190 void onDrawRegion(const SkRegion&, const SkPaint&) override;
191 void onDrawOval(const SkRect&, const SkPaint&) override;
192 void onDrawArc(const SkRect&,
193 SkScalar,
194 SkScalar,
195 bool,
196 const SkPaint&) override;
197 void onDrawRRect(const SkRRect&, const SkPaint&) override;
198 void onDrawImage(const SkImage* image,
199 SkScalar x,
200 SkScalar y,
201 const SkPaint* paint) override;
202 void onDrawImageRect(const SkImage*,
203 const SkRect*,
204 const SkRect&,
205 const SkPaint*,
206 SrcRectConstraint) override;
207 void onDrawImageNine(const SkImage*,
208 const SkIRect&,
209 const SkRect&,
210 const SkPaint*) override;
211 void onDrawImageLattice(const SkImage*,
212 const Lattice&,
213 const SkRect&,
214 const SkPaint*) override;
215 void onDrawVerticesObject(const SkVertices*,
216 SkBlendMode,
217 const SkPaint&) override;
218 void onDrawAtlas(const SkImage*,
219 const SkRSXform[],
220 const SkRect[],
221 const SkColor[],
222 int,
223 SkBlendMode,
224 const SkRect*,
225 const SkPaint*) override;
226 void onDrawEdgeAAQuad(const SkRect&,
227 const SkPoint[4],
228 QuadAAFlags,
229 const SkColor4f&,
230 SkBlendMode) override;
231 void onDrawEdgeAAImageSet(const ImageSetEntry[],
232 int,
233 const SkPoint[],
234 const SkMatrix[],
235 const SkPaint*,
236 SrcRectConstraint) override;
237 void onClipRegion(const SkRegion&, SkClipOp) override;
238
239 private:
240 SkNWayCanvas internal_canvas_;
241
242 std::vector<DrawCall> draw_calls_;
243 int current_layer_;
244};
245
246extern bool operator==(const MockCanvas::SaveData& a,
247 const MockCanvas::SaveData& b);
248extern std::ostream& operator<<(std::ostream& os,
249 const MockCanvas::SaveData& data);
250extern bool operator==(const MockCanvas::SaveLayerData& a,
251 const MockCanvas::SaveLayerData& b);
252extern std::ostream& operator<<(std::ostream& os,
253 const MockCanvas::SaveLayerData& data);
254extern bool operator==(const MockCanvas::RestoreData& a,
255 const MockCanvas::RestoreData& b);
256extern std::ostream& operator<<(std::ostream& os,
257 const MockCanvas::RestoreData& data);
258extern bool operator==(const MockCanvas::ConcatMatrixData& a,
259 const MockCanvas::ConcatMatrixData& b);
260extern std::ostream& operator<<(std::ostream& os,
261 const MockCanvas::ConcatMatrixData& data);
262extern bool operator==(const MockCanvas::ConcatMatrix44Data& a,
263 const MockCanvas::ConcatMatrix44Data& b);
264extern std::ostream& operator<<(std::ostream& os,
265 const MockCanvas::ConcatMatrix44Data& data);
266extern bool operator==(const MockCanvas::SetMatrixData& a,
267 const MockCanvas::SetMatrixData& b);
268extern std::ostream& operator<<(std::ostream& os,
269 const MockCanvas::SetMatrixData& data);
270extern bool operator==(const MockCanvas::DrawRectData& a,
271 const MockCanvas::DrawRectData& b);
272extern std::ostream& operator<<(std::ostream& os,
273 const MockCanvas::DrawRectData& data);
274extern bool operator==(const MockCanvas::DrawPathData& a,
275 const MockCanvas::DrawPathData& b);
276extern std::ostream& operator<<(std::ostream& os,
277 const MockCanvas::DrawPathData& data);
278extern bool operator==(const MockCanvas::DrawTextData& a,
279 const MockCanvas::DrawTextData& b);
280extern std::ostream& operator<<(std::ostream& os,
281 const MockCanvas::DrawTextData& data);
282extern bool operator==(const MockCanvas::DrawPictureData& a,
283 const MockCanvas::DrawPictureData& b);
284extern std::ostream& operator<<(std::ostream& os,
285 const MockCanvas::DrawPictureData& data);
286extern bool operator==(const MockCanvas::DrawShadowData& a,
287 const MockCanvas::DrawShadowData& b);
288extern std::ostream& operator<<(std::ostream& os,
289 const MockCanvas::DrawShadowData& data);
290extern bool operator==(const MockCanvas::ClipRectData& a,
291 const MockCanvas::ClipRectData& b);
292extern std::ostream& operator<<(std::ostream& os,
293 const MockCanvas::ClipRectData& data);
294extern bool operator==(const MockCanvas::ClipRRectData& a,
295 const MockCanvas::ClipRRectData& b);
296extern std::ostream& operator<<(std::ostream& os,
297 const MockCanvas::ClipRRectData& data);
298extern bool operator==(const MockCanvas::ClipPathData& a,
299 const MockCanvas::ClipPathData& b);
300extern std::ostream& operator<<(std::ostream& os,
301 const MockCanvas::ClipPathData& data);
302extern std::ostream& operator<<(std::ostream& os,
303 const MockCanvas::DrawCallData& data);
304extern bool operator==(const MockCanvas::DrawCall& a,
305 const MockCanvas::DrawCall& b);
306extern std::ostream& operator<<(std::ostream& os,
307 const MockCanvas::DrawCall& draw);
308
309} // namespace testing
310} // namespace flutter
311
312#endif // TESTING_MOCK_CANVAS_H_
313