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 "SkCanvas.h"
12#include "SkDrawable.h"
13#include "SkPicture.h"
14#include "SkTextBlob.h"
15
16namespace SkRecords {
17
18// A list of all the types of canvas calls we can record.
19// Each of these is reified into a struct below.
20//
21// (We're using the macro-of-macro trick here to do several different things with the same list.)
22//
23// We leave this SK_RECORD_TYPES macro defined for use by code that wants to operate on SkRecords
24// types polymorphically.  (See SkRecord::Record::{visit,mutate} for an example.)
25//
26// Order doesn't technically matter here, but the compiler can generally generate better code if
27// you keep them semantically grouped, especially the Draws.  It's also nice to leave NoOp at 0.
28#define SK_RECORD_TYPES(M)                                          \
29    M(NoOp)                                                         \
30    M(Restore)                                                      \
31    M(Save)                                                         \
32    M(SaveLayer)                                                    \
33    M(SetMatrix)                                                    \
34    M(ClipPath)                                                     \
35    M(ClipRRect)                                                    \
36    M(ClipRect)                                                     \
37    M(ClipRegion)                                                   \
38    M(BeginCommentGroup)                                            \
39    M(AddComment)                                                   \
40    M(EndCommentGroup)                                              \
41    M(DrawBitmap)                                                   \
42    M(DrawBitmapNine)                                               \
43    M(DrawBitmapRectToRect)                                         \
44    M(DrawBitmapRectToRectBleed)                                    \
45    M(DrawDrawable)                                                 \
46    M(DrawImage)                                                    \
47    M(DrawImageRect)                                                \
48    M(DrawDRRect)                                                   \
49    M(DrawOval)                                                     \
50    M(DrawPaint)                                                    \
51    M(DrawPath)                                                     \
52    M(DrawPatch)                                                    \
53    M(DrawPicture)                                                  \
54    M(DrawPoints)                                                   \
55    M(DrawPosText)                                                  \
56    M(DrawPosTextH)                                                 \
57    M(DrawText)                                                     \
58    M(DrawTextOnPath)                                               \
59    M(DrawRRect)                                                    \
60    M(DrawRect)                                                     \
61    M(DrawSprite)                                                   \
62    M(DrawTextBlob)                                                 \
63    M(DrawVertices)
64
65// Defines SkRecords::Type, an enum of all record types.
66#define ENUM(T) T##_Type,
67enum Type { SK_RECORD_TYPES(ENUM) };
68#undef ENUM
69
70// Macros to make it easier to define a record for a draw call with 0 args, 1 args, 2 args, etc.
71// These should be clearer when you look at their use below.
72#define RECORD0(T)                      \
73struct T {                              \
74    static const Type kType = T##_Type; \
75};
76
77// We try to be flexible about the types the constructors take.  Instead of requring the exact type
78// A here, we take any type Z which implicitly casts to A.  This allows the delay_copy() trick to
79// work, allowing the caller to decide whether to pass by value or by const&.
80
81#define RECORD1(T, A, a)                \
82struct T {                              \
83    static const Type kType = T##_Type; \
84    template <typename Z>               \
85    T(Z a) : a(a) {}                    \
86    A a;                                \
87};
88
89#define RECORD2(T, A, a, B, b)          \
90struct T {                              \
91    static const Type kType = T##_Type; \
92    template <typename Z, typename Y>   \
93    T(Z a, Y b) : a(a), b(b) {}         \
94    A a; B b;                           \
95};
96
97#define RECORD3(T, A, a, B, b, C, c)              \
98struct T {                                        \
99    static const Type kType = T##_Type;           \
100    template <typename Z, typename Y, typename X> \
101    T(Z a, Y b, X c) : a(a), b(b), c(c) {}        \
102    A a; B b; C c;                                \
103};
104
105#define RECORD4(T, A, a, B, b, C, c, D, d)                    \
106struct T {                                                    \
107    static const Type kType = T##_Type;                       \
108    template <typename Z, typename Y, typename X, typename W> \
109    T(Z a, Y b, X c, W d) : a(a), b(b), c(c), d(d) {}         \
110    A a; B b; C c; D d;                                       \
111};
112
113#define RECORD5(T, A, a, B, b, C, c, D, d, E, e)                          \
114struct T {                                                                \
115    static const Type kType = T##_Type;                                   \
116    template <typename Z, typename Y, typename X, typename W, typename V> \
117    T(Z a, Y b, X c, W d, V e) : a(a), b(b), c(c), d(d), e(e) {}          \
118    A a; B b; C c; D d; E e;                                              \
119};
120
121#define ACT_AS_PTR(ptr)                 \
122    operator T*() const { return ptr; } \
123    T* operator->() const { return ptr; }
124
125template <typename T>
126class RefBox : SkNoncopyable {
127public:
128    RefBox(T* obj) : fObj(SkSafeRef(obj)) {}
129    ~RefBox() { SkSafeUnref(fObj); }
130
131    ACT_AS_PTR(fObj);
132
133private:
134    T* fObj;
135};
136
137// An Optional doesn't own the pointer's memory, but may need to destroy non-POD data.
138template <typename T>
139class Optional : SkNoncopyable {
140public:
141    Optional(T* ptr) : fPtr(ptr) {}
142    ~Optional() { if (fPtr) fPtr->~T(); }
143
144    ACT_AS_PTR(fPtr);
145private:
146    T* fPtr;
147};
148
149// Like Optional, but ptr must not be NULL.
150template <typename T>
151class Adopted : SkNoncopyable {
152public:
153    Adopted(T* ptr) : fPtr(ptr) { SkASSERT(fPtr); }
154    Adopted(Adopted* source) {
155        // Transfer ownership from source to this.
156        fPtr = source->fPtr;
157        source->fPtr = NULL;
158    }
159    ~Adopted() { if (fPtr) fPtr->~T(); }
160
161    ACT_AS_PTR(fPtr);
162private:
163    T* fPtr;
164};
165
166// PODArray doesn't own the pointer's memory, and we assume the data is POD.
167template <typename T>
168class PODArray {
169public:
170    PODArray(T* ptr) : fPtr(ptr) {}
171    // Default copy and assign.
172
173    ACT_AS_PTR(fPtr);
174private:
175    T* fPtr;
176};
177
178#undef ACT_AS_PTR
179
180// Like SkBitmap, but deep copies pixels if they're not immutable.
181// Using this, we guarantee the immutability of all bitmaps we record.
182class ImmutableBitmap : SkNoncopyable {
183public:
184    explicit ImmutableBitmap(const SkBitmap& bitmap) {
185        if (bitmap.isImmutable()) {
186            fBitmap = bitmap;
187        } else {
188            bitmap.copyTo(&fBitmap);
189        }
190        fBitmap.setImmutable();
191    }
192
193    int width()  const { return fBitmap.width();  }
194    int height() const { return fBitmap.height(); }
195
196    // While the pixels are immutable, SkBitmap itself is not thread-safe, so return a copy.
197    SkBitmap shallowCopy() const { return fBitmap; }
198private:
199    SkBitmap fBitmap;
200};
201
202// SkPath::getBounds() isn't thread safe unless we precache the bounds in a singlethreaded context.
203// SkPath::cheapComputeDirection() is similar.
204// Recording is a convenient time to cache these, or we can delay it to between record and playback.
205struct PreCachedPath : public SkPath {
206    explicit PreCachedPath(const SkPath& path) : SkPath(path) {
207        this->updateBoundsCache();
208        SkPath::Direction junk;
209        (void)this->cheapComputeDirection(&junk);
210    }
211};
212
213// Like SkPath::getBounds(), SkMatrix::getType() isn't thread safe unless we precache it.
214// This may not cover all SkMatrices used by the picture (e.g. some could be hiding in a shader).
215struct TypedMatrix : public SkMatrix {
216    explicit TypedMatrix(const SkMatrix& matrix) : SkMatrix(matrix) {
217        (void)this->getType();
218    }
219};
220
221RECORD0(NoOp);
222
223RECORD2(Restore, SkIRect, devBounds, TypedMatrix, matrix);
224RECORD0(Save);
225RECORD3(SaveLayer, Optional<SkRect>, bounds, Optional<SkPaint>, paint, SkCanvas::SaveFlags, flags);
226
227RECORD1(SetMatrix, TypedMatrix, matrix);
228
229struct RegionOpAndAA {
230    RegionOpAndAA(SkRegion::Op op, bool aa) : op(op), aa(aa) {}
231    SkRegion::Op op : 31;  // This really only needs to be 3, but there's no win today to do so.
232    unsigned     aa :  1;  // MSVC won't pack an enum with an bool, so we call this an unsigned.
233};
234SK_COMPILE_ASSERT(sizeof(RegionOpAndAA) == 4, RegionOpAndAASize);
235
236RECORD3(ClipPath,   SkIRect, devBounds, PreCachedPath,  path, RegionOpAndAA, opAA);
237RECORD3(ClipRRect,  SkIRect, devBounds, SkRRect,       rrect, RegionOpAndAA, opAA);
238RECORD3(ClipRect,   SkIRect, devBounds, SkRect,         rect, RegionOpAndAA, opAA);
239RECORD3(ClipRegion, SkIRect, devBounds, SkRegion,     region, SkRegion::Op,    op);
240
241RECORD1(BeginCommentGroup, PODArray<char>, description);
242RECORD2(AddComment, PODArray<char>, key, PODArray<char>, value);
243RECORD0(EndCommentGroup);
244
245// While not strictly required, if you have an SkPaint, it's fastest to put it first.
246RECORD4(DrawBitmap, Optional<SkPaint>, paint,
247                    ImmutableBitmap, bitmap,
248                    SkScalar, left,
249                    SkScalar, top);
250RECORD4(DrawBitmapNine, Optional<SkPaint>, paint,
251                        ImmutableBitmap, bitmap,
252                        SkIRect, center,
253                        SkRect, dst);
254RECORD4(DrawBitmapRectToRect, Optional<SkPaint>, paint,
255                              ImmutableBitmap, bitmap,
256                              Optional<SkRect>, src,
257                              SkRect, dst);
258RECORD4(DrawBitmapRectToRectBleed, Optional<SkPaint>, paint,
259                                   ImmutableBitmap, bitmap,
260                                   Optional<SkRect>, src,
261                                   SkRect, dst);
262RECORD3(DrawDRRect, SkPaint, paint, SkRRect, outer, SkRRect, inner);
263RECORD2(DrawDrawable, SkRect, worstCaseBounds, int32_t, index);
264RECORD4(DrawImage, Optional<SkPaint>, paint,
265                   RefBox<const SkImage>, image,
266                   SkScalar, left,
267                   SkScalar, top);
268RECORD4(DrawImageRect, Optional<SkPaint>, paint,
269                       RefBox<const SkImage>, image,
270                       Optional<SkRect>, src,
271                       SkRect, dst);
272RECORD2(DrawOval, SkPaint, paint, SkRect, oval);
273RECORD1(DrawPaint, SkPaint, paint);
274RECORD2(DrawPath, SkPaint, paint, PreCachedPath, path);
275RECORD3(DrawPicture, Optional<SkPaint>, paint,
276                     RefBox<const SkPicture>, picture,
277                     TypedMatrix, matrix);
278RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, unsigned, count, SkPoint*, pts);
279RECORD4(DrawPosText, SkPaint, paint,
280                     PODArray<char>, text,
281                     size_t, byteLength,
282                     PODArray<SkPoint>, pos);
283RECORD5(DrawPosTextH, SkPaint, paint,
284                      PODArray<char>, text,
285                      unsigned, byteLength,
286                      SkScalar, y,
287                      PODArray<SkScalar>, xpos);
288RECORD2(DrawRRect, SkPaint, paint, SkRRect, rrect);
289RECORD2(DrawRect, SkPaint, paint, SkRect, rect);
290RECORD4(DrawSprite, Optional<SkPaint>, paint, ImmutableBitmap, bitmap, int, left, int, top);
291RECORD5(DrawText, SkPaint, paint,
292                  PODArray<char>, text,
293                  size_t, byteLength,
294                  SkScalar, x,
295                  SkScalar, y);
296RECORD4(DrawTextBlob, SkPaint, paint,
297                      RefBox<const SkTextBlob>, blob,
298                      SkScalar, x,
299                      SkScalar, y);
300RECORD5(DrawTextOnPath, SkPaint, paint,
301                        PODArray<char>, text,
302                        size_t, byteLength,
303                        PreCachedPath, path,
304                        TypedMatrix, matrix);
305
306RECORD5(DrawPatch, SkPaint, paint,
307                   PODArray<SkPoint>, cubics,
308                   PODArray<SkColor>, colors,
309                   PODArray<SkPoint>, texCoords,
310                   RefBox<SkXfermode>, xmode);
311
312// This guy is so ugly we just write it manually.
313struct DrawVertices {
314    static const Type kType = DrawVertices_Type;
315
316    DrawVertices(const SkPaint& paint,
317                 SkCanvas::VertexMode vmode,
318                 int vertexCount,
319                 SkPoint* vertices,
320                 SkPoint* texs,
321                 SkColor* colors,
322                 SkXfermode* xmode,
323                 uint16_t* indices,
324                 int indexCount)
325        : paint(paint)
326        , vmode(vmode)
327        , vertexCount(vertexCount)
328        , vertices(vertices)
329        , texs(texs)
330        , colors(colors)
331        , xmode(SkSafeRef(xmode))
332        , indices(indices)
333        , indexCount(indexCount) {}
334
335    SkPaint paint;
336    SkCanvas::VertexMode vmode;
337    int vertexCount;
338    PODArray<SkPoint> vertices;
339    PODArray<SkPoint> texs;
340    PODArray<SkColor> colors;
341    SkAutoTUnref<SkXfermode> xmode;
342    PODArray<uint16_t> indices;
343    int indexCount;
344};
345
346#undef RECORD0
347#undef RECORD1
348#undef RECORD2
349#undef RECORD3
350#undef RECORD4
351#undef RECORD5
352
353}  // namespace SkRecords
354
355#endif//SkRecords_DEFINED
356