1/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkRecords_DEFINED
9#define SkRecords_DEFINED
10
11#include "include/core/SkCanvas.h"
12#include "include/core/SkData.h"
13#include "include/core/SkDrawable.h"
14#include "include/core/SkImage.h"
15#include "include/core/SkImageFilter.h"
16#include "include/core/SkM44.h"
17#include "include/core/SkMatrix.h"
18#include "include/core/SkPath.h"
19#include "include/core/SkPicture.h"
20#include "include/core/SkRRect.h"
21#include "include/core/SkRSXform.h"
22#include "include/core/SkRect.h"
23#include "include/core/SkRegion.h"
24#include "include/core/SkString.h"
25#include "include/core/SkTextBlob.h"
26#include "include/core/SkVertices.h"
27#include "src/core/SkDrawShadowInfo.h"
28
29namespace SkRecords {
30
31// A list of all the types of canvas calls we can record.
32// Each of these is reified into a struct below.
33//
34// (We're using the macro-of-macro trick here to do several different things with the same list.)
35//
36// We leave this SK_RECORD_TYPES macro defined for use by code that wants to operate on SkRecords
37// types polymorphically. (See SkRecord::Record::{visit,mutate} for an example.)
38//
39// Order doesn't technically matter here, but the compiler can generally generate better code if
40// you keep them semantically grouped, especially the Draws. It's also nice to leave NoOp at 0.
41#define SK_RECORD_TYPES(M) \
42 M(NoOp) \
43 M(Flush) \
44 M(Restore) \
45 M(Save) \
46 M(SaveLayer) \
47 M(SaveBehind) \
48 M(MarkCTM) \
49 M(SetMatrix) \
50 M(Translate) \
51 M(Scale) \
52 M(Concat) \
53 M(Concat44) \
54 M(ClipPath) \
55 M(ClipRRect) \
56 M(ClipRect) \
57 M(ClipRegion) \
58 M(ClipShader) \
59 M(DrawArc) \
60 M(DrawDrawable) \
61 M(DrawImage) \
62 M(DrawImageLattice) \
63 M(DrawImageRect) \
64 M(DrawImageNine) \
65 M(DrawDRRect) \
66 M(DrawOval) \
67 M(DrawBehind) \
68 M(DrawPaint) \
69 M(DrawPath) \
70 M(DrawPatch) \
71 M(DrawPicture) \
72 M(DrawPoints) \
73 M(DrawRRect) \
74 M(DrawRect) \
75 M(DrawRegion) \
76 M(DrawTextBlob) \
77 M(DrawAtlas) \
78 M(DrawVertices) \
79 M(DrawShadowRec) \
80 M(DrawAnnotation) \
81 M(DrawEdgeAAQuad) \
82 M(DrawEdgeAAImageSet)
83
84
85// Defines SkRecords::Type, an enum of all record types.
86#define ENUM(T) T##_Type,
87enum Type { SK_RECORD_TYPES(ENUM) };
88#undef ENUM
89
90#define ACT_AS_PTR(ptr) \
91 operator T*() const { return ptr; } \
92 T* operator->() const { return ptr; }
93
94// An Optional doesn't own the pointer's memory, but may need to destroy non-POD data.
95template <typename T>
96class Optional {
97public:
98 Optional() : fPtr(nullptr) {}
99 Optional(T* ptr) : fPtr(ptr) {}
100 Optional(Optional&& o) : fPtr(o.fPtr) {
101 o.fPtr = nullptr;
102 }
103 ~Optional() { if (fPtr) fPtr->~T(); }
104
105 ACT_AS_PTR(fPtr)
106private:
107 T* fPtr;
108 Optional(const Optional&) = delete;
109 Optional& operator=(const Optional&) = delete;
110};
111
112// Like Optional, but ptr must not be NULL.
113template <typename T>
114class Adopted {
115public:
116 Adopted(T* ptr) : fPtr(ptr) { SkASSERT(fPtr); }
117 Adopted(Adopted* source) {
118 // Transfer ownership from source to this.
119 fPtr = source->fPtr;
120 source->fPtr = NULL;
121 }
122 ~Adopted() { if (fPtr) fPtr->~T(); }
123
124 ACT_AS_PTR(fPtr)
125private:
126 T* fPtr;
127 Adopted(const Adopted&) = delete;
128 Adopted& operator=(const Adopted&) = delete;
129};
130
131// PODArray doesn't own the pointer's memory, and we assume the data is POD.
132template <typename T>
133class PODArray {
134public:
135 PODArray() {}
136 PODArray(T* ptr) : fPtr(ptr) {}
137 // Default copy and assign.
138
139 ACT_AS_PTR(fPtr)
140private:
141 T* fPtr;
142};
143
144#undef ACT_AS_PTR
145
146// SkPath::getBounds() isn't thread safe unless we precache the bounds in a singlethreaded context.
147// SkPath::cheapComputeDirection() is similar.
148// Recording is a convenient time to cache these, or we can delay it to between record and playback.
149struct PreCachedPath : public SkPath {
150 PreCachedPath() {}
151 PreCachedPath(const SkPath& path);
152};
153
154// Like SkPath::getBounds(), SkMatrix::getType() isn't thread safe unless we precache it.
155// This may not cover all SkMatrices used by the picture (e.g. some could be hiding in a shader).
156struct TypedMatrix : public SkMatrix {
157 TypedMatrix() {}
158 TypedMatrix(const SkMatrix& matrix);
159};
160
161enum Tags {
162 kDraw_Tag = 1, // May draw something (usually named DrawFoo).
163 kHasImage_Tag = 2, // Contains an SkImage or SkBitmap.
164 kHasText_Tag = 4, // Contains text.
165 kHasPaint_Tag = 8, // May have an SkPaint field, at least optionally.
166
167 kDrawWithPaint_Tag = kDraw_Tag | kHasPaint_Tag,
168};
169
170// A macro to make it a little easier to define a struct that can be stored in SkRecord.
171#define RECORD(T, tags, ...) \
172struct T { \
173 static const Type kType = T##_Type; \
174 static const int kTags = tags; \
175 __VA_ARGS__; \
176};
177
178RECORD(NoOp, 0);
179RECORD(Flush, 0);
180RECORD(Restore, 0,
181 TypedMatrix matrix);
182RECORD(Save, 0);
183
184RECORD(SaveLayer, kHasPaint_Tag,
185 Optional<SkRect> bounds;
186 Optional<SkPaint> paint;
187 sk_sp<const SkImageFilter> backdrop;
188 sk_sp<const SkImage> clipMask;
189 Optional<SkMatrix> clipMatrix;
190 SkCanvas::SaveLayerFlags saveLayerFlags);
191
192RECORD(SaveBehind, 0,
193 Optional<SkRect> subset);
194
195RECORD(MarkCTM, 0,
196 uint32_t id);
197RECORD(SetMatrix, 0,
198 TypedMatrix matrix);
199RECORD(Concat, 0,
200 TypedMatrix matrix);
201RECORD(Concat44, 0,
202 SkM44 matrix);
203
204RECORD(Translate, 0,
205 SkScalar dx;
206 SkScalar dy);
207
208RECORD(Scale, 0,
209 SkScalar sx;
210 SkScalar sy);
211
212struct ClipOpAndAA {
213 ClipOpAndAA() {}
214 ClipOpAndAA(SkClipOp op, bool aa) : fOp(static_cast<unsigned>(op)), fAA(aa) {}
215
216 SkClipOp op() const { return static_cast<SkClipOp>(fOp); }
217 bool aa() const { return fAA != 0; }
218
219private:
220 unsigned fOp : 31; // This really only needs to be 3, but there's no win today to do so.
221 unsigned fAA : 1; // MSVC won't pack an enum with an bool, so we call this an unsigned.
222};
223static_assert(sizeof(ClipOpAndAA) == 4, "ClipOpAndAASize");
224
225RECORD(ClipPath, 0,
226 PreCachedPath path;
227 ClipOpAndAA opAA);
228RECORD(ClipRRect, 0,
229 SkRRect rrect;
230 ClipOpAndAA opAA);
231RECORD(ClipRect, 0,
232 SkRect rect;
233 ClipOpAndAA opAA);
234RECORD(ClipRegion, 0,
235 SkRegion region;
236 SkClipOp op);
237RECORD(ClipShader, 0,
238 sk_sp<SkShader> shader;
239 SkClipOp op);
240
241// While not strictly required, if you have an SkPaint, it's fastest to put it first.
242RECORD(DrawArc, kDraw_Tag|kHasPaint_Tag,
243 SkPaint paint;
244 SkRect oval;
245 SkScalar startAngle;
246 SkScalar sweepAngle;
247 unsigned useCenter);
248RECORD(DrawDRRect, kDraw_Tag|kHasPaint_Tag,
249 SkPaint paint;
250 SkRRect outer;
251 SkRRect inner);
252RECORD(DrawDrawable, kDraw_Tag,
253 Optional<SkMatrix> matrix;
254 SkRect worstCaseBounds;
255 int32_t index);
256RECORD(DrawImage, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
257 Optional<SkPaint> paint;
258 sk_sp<const SkImage> image;
259 SkScalar left;
260 SkScalar top);
261RECORD(DrawImageLattice, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
262 Optional<SkPaint> paint;
263 sk_sp<const SkImage> image;
264 int xCount;
265 PODArray<int> xDivs;
266 int yCount;
267 PODArray<int> yDivs;
268 int flagCount;
269 PODArray<SkCanvas::Lattice::RectType> flags;
270 PODArray<SkColor> colors;
271 SkIRect src;
272 SkRect dst);
273RECORD(DrawImageRect, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
274 Optional<SkPaint> paint;
275 sk_sp<const SkImage> image;
276 Optional<SkRect> src;
277 SkRect dst;
278 SkCanvas::SrcRectConstraint constraint);
279RECORD(DrawImageNine, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
280 Optional<SkPaint> paint;
281 sk_sp<const SkImage> image;
282 SkIRect center;
283 SkRect dst);
284RECORD(DrawOval, kDraw_Tag|kHasPaint_Tag,
285 SkPaint paint;
286 SkRect oval);
287RECORD(DrawPaint, kDraw_Tag|kHasPaint_Tag,
288 SkPaint paint);
289RECORD(DrawBehind, kDraw_Tag|kHasPaint_Tag,
290 SkPaint paint);
291RECORD(DrawPath, kDraw_Tag|kHasPaint_Tag,
292 SkPaint paint;
293 PreCachedPath path);
294RECORD(DrawPicture, kDraw_Tag|kHasPaint_Tag,
295 Optional<SkPaint> paint;
296 sk_sp<const SkPicture> picture;
297 TypedMatrix matrix);
298RECORD(DrawPoints, kDraw_Tag|kHasPaint_Tag,
299 SkPaint paint;
300 SkCanvas::PointMode mode;
301 unsigned count;
302 SkPoint* pts);
303RECORD(DrawRRect, kDraw_Tag|kHasPaint_Tag,
304 SkPaint paint;
305 SkRRect rrect);
306RECORD(DrawRect, kDraw_Tag|kHasPaint_Tag,
307 SkPaint paint;
308 SkRect rect);
309RECORD(DrawRegion, kDraw_Tag|kHasPaint_Tag,
310 SkPaint paint;
311 SkRegion region);
312RECORD(DrawTextBlob, kDraw_Tag|kHasText_Tag|kHasPaint_Tag,
313 SkPaint paint;
314 sk_sp<const SkTextBlob> blob;
315 SkScalar x;
316 SkScalar y);
317RECORD(DrawPatch, kDraw_Tag|kHasPaint_Tag,
318 SkPaint paint;
319 PODArray<SkPoint> cubics;
320 PODArray<SkColor> colors;
321 PODArray<SkPoint> texCoords;
322 SkBlendMode bmode);
323RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
324 Optional<SkPaint> paint;
325 sk_sp<const SkImage> atlas;
326 PODArray<SkRSXform> xforms;
327 PODArray<SkRect> texs;
328 PODArray<SkColor> colors;
329 int count;
330 SkBlendMode mode;
331 Optional<SkRect> cull);
332RECORD(DrawVertices, kDraw_Tag|kHasPaint_Tag,
333 SkPaint paint;
334 sk_sp<SkVertices> vertices;
335 SkBlendMode bmode);
336RECORD(DrawShadowRec, kDraw_Tag,
337 PreCachedPath path;
338 SkDrawShadowRec rec);
339RECORD(DrawAnnotation, 0, // TODO: kDraw_Tag, skia:5548
340 SkRect rect;
341 SkString key;
342 sk_sp<SkData> value);
343RECORD(DrawEdgeAAQuad, kDraw_Tag,
344 SkRect rect;
345 PODArray<SkPoint> clip;
346 SkCanvas::QuadAAFlags aa;
347 SkColor4f color;
348 SkBlendMode mode);
349RECORD(DrawEdgeAAImageSet, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
350 Optional<SkPaint> paint;
351 SkAutoTArray<SkCanvas::ImageSetEntry> set;
352 int count;
353 PODArray<SkPoint> dstClips;
354 PODArray<SkMatrix> preViewMatrices;
355 SkCanvas::SrcRectConstraint constraint);
356#undef RECORD
357
358} // namespace SkRecords
359
360#endif//SkRecords_DEFINED
361