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
13namespace SkRecords {
14
15// A list of all the types of canvas calls we can record.
16// Each of these is reified into a struct below.
17//
18// (We're using the macro-of-macro trick here to do several different things with the same list.)
19//
20// We leave this SK_RECORD_TYPES macro defined for use by code that wants to operate on SkRecords
21// types polymorphically.  (See SkRecord::Record::{visit,mutate} for an example.)
22//
23// Order doesn't technically matter here, but the compiler can generally generate better code if
24// you keep them semantically grouped, especially the Draws.  It's also nice to leave NoOp at 0.
25#define SK_RECORD_TYPES(M)                                          \
26    M(NoOp)                                                         \
27    M(Restore)                                                      \
28    M(Save)                                                         \
29    M(SaveLayer)                                                    \
30    M(PushCull)                                                     \
31    M(PopCull)                                                      \
32    M(PairedPushCull)         /*From SkRecordAnnotateCullingPairs*/ \
33    M(Concat)                                                       \
34    M(SetMatrix)                                                    \
35    M(ClipPath)                                                     \
36    M(ClipRRect)                                                    \
37    M(ClipRect)                                                     \
38    M(ClipRegion)                                                   \
39    M(Clear)                                                        \
40    M(DrawBitmap)                                                   \
41    M(DrawBitmapMatrix)                                             \
42    M(DrawBitmapNine)                                               \
43    M(DrawBitmapRectToRect)                                         \
44    M(DrawDRRect)                                                   \
45    M(DrawOval)                                                     \
46    M(DrawPaint)                                                    \
47    M(DrawPath)                                                     \
48    M(DrawPoints)                                                   \
49    M(DrawPosText)                                                  \
50    M(DrawPosTextH)                                                 \
51    M(DrawRRect)                                                    \
52    M(DrawRect)                                                     \
53    M(DrawSprite)                                                   \
54    M(DrawText)                                                     \
55    M(DrawTextOnPath)                                               \
56    M(DrawVertices)                                                 \
57    M(BoundedDrawPosTextH)    /*From SkRecordBoundDrawPosTextH*/
58
59// Defines SkRecords::Type, an enum of all record types.
60#define ENUM(T) T##_Type,
61enum Type { SK_RECORD_TYPES(ENUM) };
62#undef ENUM
63
64// Macros to make it easier to define a record for a draw call with 0 args, 1 args, 2 args, etc.
65// These should be clearer when you look at their use below.
66#define RECORD0(T)                      \
67struct T {                              \
68    static const Type kType = T##_Type; \
69};
70
71// We try to be flexible about the types the constructors take.  Instead of requring the exact type
72// A here, we take any type Z which implicitly casts to A.  This allows the delay_copy() trick to
73// work, allowing the caller to decide whether to pass by value or by const&.
74
75#define RECORD1(T, A, a)                \
76struct T {                              \
77    static const Type kType = T##_Type; \
78    template <typename Z>               \
79    T(Z a) : a(a) {}                    \
80    A a;                                \
81};
82
83#define RECORD2(T, A, a, B, b)          \
84struct T {                              \
85    static const Type kType = T##_Type; \
86    template <typename Z, typename Y>   \
87    T(Z a, Y b) : a(a), b(b) {}         \
88    A a; B b;                           \
89};
90
91#define RECORD3(T, A, a, B, b, C, c)              \
92struct T {                                        \
93    static const Type kType = T##_Type;           \
94    template <typename Z, typename Y, typename X> \
95    T(Z a, Y b, X c) : a(a), b(b), c(c) {}        \
96    A a; B b; C c;                                \
97};
98
99#define RECORD4(T, A, a, B, b, C, c, D, d)                    \
100struct T {                                                    \
101    static const Type kType = T##_Type;                       \
102    template <typename Z, typename Y, typename X, typename W> \
103    T(Z a, Y b, X c, W d) : a(a), b(b), c(c), d(d) {}         \
104    A a; B b; C c; D d;                                       \
105};
106
107#define RECORD5(T, A, a, B, b, C, c, D, d, E, e)                          \
108struct T {                                                                \
109    static const Type kType = T##_Type;                                   \
110    template <typename Z, typename Y, typename X, typename W, typename V> \
111    T(Z a, Y b, X c, W d, V e) : a(a), b(b), c(c), d(d), e(e) {}          \
112    A a; B b; C c; D d; E e;                                              \
113};
114
115#define ACT_AS_PTR(ptr)                       \
116    operator T*() { return ptr; }             \
117    operator const T*() const { return ptr; } \
118    T* operator->() { return ptr; }           \
119    const T* operator->() const { return ptr; }
120
121// An Optional doesn't own the pointer's memory, but may need to destroy non-POD data.
122template <typename T>
123class Optional : SkNoncopyable {
124public:
125    Optional(T* ptr) : fPtr(ptr) {}
126    ~Optional() { if (fPtr) fPtr->~T(); }
127
128    ACT_AS_PTR(fPtr);
129private:
130    T* fPtr;
131};
132
133// Like Optional, but ptr must not be NULL.
134template <typename T>
135class Adopted : SkNoncopyable {
136public:
137    Adopted(T* ptr) : fPtr(ptr) { SkASSERT(fPtr); }
138    Adopted(Adopted* source) {
139        // Transfer ownership from source to this.
140        fPtr = source->fPtr;
141        source->fPtr = NULL;
142    }
143    ~Adopted() { if (fPtr) fPtr->~T(); }
144
145    ACT_AS_PTR(fPtr);
146private:
147    T* fPtr;
148};
149
150// PODArray doesn't own the pointer's memory, and we assume the data is POD.
151template <typename T>
152class PODArray {
153public:
154    PODArray(T* ptr) : fPtr(ptr) {}
155    // Default copy and assign.
156
157    ACT_AS_PTR(fPtr);
158private:
159    T* fPtr;
160};
161
162#undef ACT_AS_PTR
163
164// Like SkBitmap, but deep copies pixels if they're not immutable.
165// Using this, we guarantee the immutability of all bitmaps we record.
166class ImmutableBitmap {
167public:
168    explicit ImmutableBitmap(const SkBitmap& bitmap) {
169        if (bitmap.isImmutable()) {
170            fBitmap = bitmap;
171        } else {
172            bitmap.copyTo(&fBitmap);
173        }
174        fBitmap.setImmutable();
175    }
176
177    operator const SkBitmap& () const { return fBitmap; }
178
179private:
180    SkBitmap fBitmap;
181};
182
183RECORD0(NoOp);
184
185RECORD0(Restore);
186RECORD1(Save, SkCanvas::SaveFlags, flags);
187RECORD3(SaveLayer, Optional<SkRect>, bounds, Optional<SkPaint>, paint, SkCanvas::SaveFlags, flags);
188
189RECORD1(PushCull, SkRect, rect);
190RECORD0(PopCull);
191
192RECORD1(Concat, SkMatrix, matrix);
193RECORD1(SetMatrix, SkMatrix, matrix);
194
195RECORD3(ClipPath, SkPath, path, SkRegion::Op, op, bool, doAA);
196RECORD3(ClipRRect, SkRRect, rrect, SkRegion::Op, op, bool, doAA);
197RECORD3(ClipRect, SkRect, rect, SkRegion::Op, op, bool, doAA);
198RECORD2(ClipRegion, SkRegion, region, SkRegion::Op, op);
199
200RECORD1(Clear, SkColor, color);
201// While not strictly required, if you have an SkPaint, it's fastest to put it first.
202RECORD4(DrawBitmap, Optional<SkPaint>, paint,
203                    ImmutableBitmap, bitmap,
204                    SkScalar, left,
205                    SkScalar, top);
206RECORD3(DrawBitmapMatrix, Optional<SkPaint>, paint, ImmutableBitmap, bitmap, SkMatrix, matrix);
207RECORD4(DrawBitmapNine, Optional<SkPaint>, paint,
208                        ImmutableBitmap, bitmap,
209                        SkIRect, center,
210                        SkRect, dst);
211RECORD5(DrawBitmapRectToRect, Optional<SkPaint>, paint,
212                              ImmutableBitmap, bitmap,
213                              Optional<SkRect>, src,
214                              SkRect, dst,
215                              SkCanvas::DrawBitmapRectFlags, flags);
216RECORD3(DrawDRRect, SkPaint, paint, SkRRect, outer, SkRRect, inner);
217RECORD2(DrawOval, SkPaint, paint, SkRect, oval);
218RECORD1(DrawPaint, SkPaint, paint);
219RECORD2(DrawPath, SkPaint, paint, SkPath, path);
220RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, size_t, count, SkPoint*, pts);
221RECORD4(DrawPosText, SkPaint, paint,
222                     PODArray<char>, text,
223                     size_t, byteLength,
224                     PODArray<SkPoint>, pos);
225RECORD5(DrawPosTextH, SkPaint, paint,
226                      PODArray<char>, text,
227                      size_t, byteLength,
228                      PODArray<SkScalar>, xpos,
229                      SkScalar, y);
230RECORD2(DrawRRect, SkPaint, paint, SkRRect, rrect);
231RECORD2(DrawRect, SkPaint, paint, SkRect, rect);
232RECORD4(DrawSprite, Optional<SkPaint>, paint, ImmutableBitmap, bitmap, int, left, int, top);
233RECORD5(DrawText, SkPaint, paint,
234                  PODArray<char>, text,
235                  size_t, byteLength,
236                  SkScalar, x,
237                  SkScalar, y);
238RECORD5(DrawTextOnPath, SkPaint, paint,
239                        PODArray<char>, text,
240                        size_t, byteLength,
241                        SkPath, path,
242                        Optional<SkMatrix>, matrix);
243
244// This guy is so ugly we just write it manually.
245struct DrawVertices {
246    static const Type kType = DrawVertices_Type;
247
248    DrawVertices(const SkPaint& paint,
249                 SkCanvas::VertexMode vmode,
250                 int vertexCount,
251                 SkPoint* vertices,
252                 SkPoint* texs,
253                 SkColor* colors,
254                 SkXfermode* xmode,
255                 uint16_t* indices,
256                 int indexCount)
257        : paint(paint)
258        , vmode(vmode)
259        , vertexCount(vertexCount)
260        , vertices(vertices)
261        , texs(texs)
262        , colors(colors)
263        , xmode(SkSafeRef(xmode))
264        , indices(indices)
265        , indexCount(indexCount) {}
266
267    SkPaint paint;
268    SkCanvas::VertexMode vmode;
269    int vertexCount;
270    PODArray<SkPoint> vertices;
271    PODArray<SkPoint> texs;
272    PODArray<SkColor> colors;
273    SkAutoTUnref<SkXfermode> xmode;
274    PODArray<uint16_t> indices;
275    int indexCount;
276};
277
278// Records added by optimizations.
279RECORD2(PairedPushCull, Adopted<PushCull>, base, unsigned, skip);
280RECORD3(BoundedDrawPosTextH, Adopted<DrawPosTextH>, base, SkScalar, minY, SkScalar, maxY);
281
282#undef RECORD0
283#undef RECORD1
284#undef RECORD2
285#undef RECORD3
286#undef RECORD4
287#undef RECORD5
288
289}  // namespace SkRecords
290
291#endif//SkRecords_DEFINED
292