SkRecorder.cpp revision 3fcc125c776c837aa858598ce385f5c6f8f01795
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#include "SkRecorder.h"
9#include "SkPatchUtils.h"
10#include "SkPicture.h"
11
12SkCanvasDrawableList::~SkCanvasDrawableList() {
13    fArray.unrefAll();
14}
15
16SkPicture::SnapshotArray* SkCanvasDrawableList::newDrawableSnapshot() {
17    const int count = fArray.count();
18    if (0 == count) {
19        return NULL;
20    }
21    SkAutoTMalloc<const SkPicture*> pics(count);
22    for (int i = 0; i < count; ++i) {
23        pics[i] = fArray[i]->newPictureSnapshot();
24    }
25    return SkNEW_ARGS(SkPicture::SnapshotArray, (pics.detach(), count));
26}
27
28void SkCanvasDrawableList::append(SkCanvasDrawable* drawable) {
29    *fArray.append() = SkRef(drawable);
30}
31
32///////////////////////////////////////////////////////////////////////////////////////////////
33
34SkRecorder::SkRecorder(SkRecord* record, int width, int height)
35    : SkCanvas(SkIRect::MakeWH(width, height), SkCanvas::kConservativeRasterClip_InitFlag)
36    , fRecord(record) {}
37
38SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds)
39    : SkCanvas(bounds.roundOut(), SkCanvas::kConservativeRasterClip_InitFlag)
40    , fRecord(record) {}
41
42void SkRecorder::forgetRecord() {
43    fDrawableList.reset(NULL);
44    fRecord = NULL;
45}
46
47// To make appending to fRecord a little less verbose.
48#define APPEND(T, ...) \
49        SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__))
50
51// For methods which must call back into SkCanvas.
52#define INHERITED(method, ...) this->SkCanvas::method(__VA_ARGS__)
53
54// The structs we're creating all copy their constructor arguments.  Given the way the SkRecords
55// framework works, sometimes they happen to technically be copied twice, which is fine and elided
56// into a single copy unless the class has a non-trivial copy constructor.  For classes with
57// non-trivial copy constructors, we skip the first copy (and its destruction) by wrapping the value
58// with delay_copy(), forcing the argument to be passed by const&.
59//
60// This is used below for SkBitmap, SkPaint, SkPath, and SkRegion, which all have non-trivial copy
61// constructors and destructors.  You'll know you've got a good candidate T if you see ~T() show up
62// unexpectedly on a profile of record time.  Otherwise don't bother.
63template <typename T>
64class Reference {
65public:
66    Reference(const T& x) : fX(x) {}
67    operator const T&() const { return fX; }
68private:
69    const T& fX;
70};
71
72template <typename T>
73static Reference<T> delay_copy(const T& x) { return Reference<T>(x); }
74
75// Use copy() only for optional arguments, to be copied if present or skipped if not.
76// (For most types we just pass by value and let copy constructors do their thing.)
77template <typename T>
78T* SkRecorder::copy(const T* src) {
79    if (NULL == src) {
80        return NULL;
81    }
82    return SkNEW_PLACEMENT_ARGS(fRecord->alloc<T>(), T, (*src));
83}
84
85// This copy() is for arrays.
86// It will work with POD or non-POD, though currently we only use it for POD.
87template <typename T>
88T* SkRecorder::copy(const T src[], size_t count) {
89    if (NULL == src) {
90        return NULL;
91    }
92    T* dst = fRecord->alloc<T>(count);
93    for (size_t i = 0; i < count; i++) {
94        SkNEW_PLACEMENT_ARGS(dst + i, T, (src[i]));
95    }
96    return dst;
97}
98
99// Specialization for copying strings, using memcpy.
100// This measured around 2x faster for copying code points,
101// but I found no corresponding speedup for other arrays.
102template <>
103char* SkRecorder::copy(const char src[], size_t count) {
104    if (NULL == src) {
105        return NULL;
106    }
107    char* dst = fRecord->alloc<char>(count);
108    memcpy(dst, src, count);
109    return dst;
110}
111
112// As above, assuming and copying a terminating \0.
113template <>
114char* SkRecorder::copy(const char* src) {
115    return this->copy(src, strlen(src)+1);
116}
117
118
119void SkRecorder::drawPaint(const SkPaint& paint) {
120    APPEND(DrawPaint, delay_copy(paint));
121}
122
123void SkRecorder::drawPoints(PointMode mode,
124                            size_t count,
125                            const SkPoint pts[],
126                            const SkPaint& paint) {
127    APPEND(DrawPoints, delay_copy(paint), mode, SkToUInt(count), this->copy(pts, count));
128}
129
130void SkRecorder::drawRect(const SkRect& rect, const SkPaint& paint) {
131    APPEND(DrawRect, delay_copy(paint), rect);
132}
133
134void SkRecorder::drawOval(const SkRect& oval, const SkPaint& paint) {
135    APPEND(DrawOval, delay_copy(paint), oval);
136}
137
138void SkRecorder::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
139    APPEND(DrawRRect, delay_copy(paint), rrect);
140}
141
142void SkRecorder::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
143    APPEND(DrawDRRect, delay_copy(paint), outer, inner);
144}
145
146void SkRecorder::onDrawDrawable(SkCanvasDrawable* drawable) {
147    if (!fDrawableList) {
148        fDrawableList.reset(SkNEW(SkCanvasDrawableList));
149    }
150    fDrawableList->append(drawable);
151    APPEND(DrawDrawable, drawable->getBounds(), fDrawableList->count() - 1);
152}
153
154void SkRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
155    APPEND(DrawPath, delay_copy(paint), delay_copy(path));
156}
157
158void SkRecorder::drawBitmap(const SkBitmap& bitmap,
159                            SkScalar left,
160                            SkScalar top,
161                            const SkPaint* paint) {
162    APPEND(DrawBitmap, this->copy(paint), delay_copy(bitmap), left, top);
163}
164
165void SkRecorder::drawBitmapRectToRect(const SkBitmap& bitmap,
166                                      const SkRect* src,
167                                      const SkRect& dst,
168                                      const SkPaint* paint,
169                                      DrawBitmapRectFlags flags) {
170    if (kBleed_DrawBitmapRectFlag == flags) {
171        APPEND(DrawBitmapRectToRectBleed,
172               this->copy(paint), delay_copy(bitmap), this->copy(src), dst);
173        return;
174    }
175    SkASSERT(kNone_DrawBitmapRectFlag == flags);
176    APPEND(DrawBitmapRectToRect,
177           this->copy(paint), delay_copy(bitmap), this->copy(src), dst);
178}
179
180void SkRecorder::drawBitmapNine(const SkBitmap& bitmap,
181                                const SkIRect& center,
182                                const SkRect& dst,
183                                const SkPaint* paint) {
184    APPEND(DrawBitmapNine, this->copy(paint), delay_copy(bitmap), center, dst);
185}
186
187void SkRecorder::drawImage(const SkImage* image, SkScalar left, SkScalar top,
188                           const SkPaint* paint) {
189    APPEND(DrawImage, this->copy(paint), image, left, top);
190}
191
192void SkRecorder::drawImageRect(const SkImage* image, const SkRect* src,
193                               const SkRect& dst,
194                               const SkPaint* paint) {
195    APPEND(DrawImageRect, this->copy(paint), image, this->copy(src), dst);
196}
197
198void SkRecorder::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
199    APPEND(DrawSprite, this->copy(paint), delay_copy(bitmap), left, top);
200}
201
202void SkRecorder::onDrawText(const void* text, size_t byteLength,
203                            SkScalar x, SkScalar y, const SkPaint& paint) {
204    APPEND(DrawText,
205           delay_copy(paint), this->copy((const char*)text, byteLength), byteLength, x, y);
206}
207
208void SkRecorder::onDrawPosText(const void* text, size_t byteLength,
209                               const SkPoint pos[], const SkPaint& paint) {
210    const unsigned points = paint.countText(text, byteLength);
211    APPEND(DrawPosText,
212           delay_copy(paint),
213           this->copy((const char*)text, byteLength),
214           byteLength,
215           this->copy(pos, points));
216}
217
218void SkRecorder::onDrawPosTextH(const void* text, size_t byteLength,
219                                const SkScalar xpos[], SkScalar constY, const SkPaint& paint) {
220    const unsigned points = paint.countText(text, byteLength);
221    APPEND(DrawPosTextH,
222           delay_copy(paint),
223           this->copy((const char*)text, byteLength),
224           SkToUInt(byteLength),
225           constY,
226           this->copy(xpos, points));
227}
228
229void SkRecorder::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
230                                  const SkMatrix* matrix, const SkPaint& paint) {
231    APPEND(DrawTextOnPath,
232           delay_copy(paint),
233           this->copy((const char*)text, byteLength),
234           byteLength,
235           delay_copy(path),
236           matrix ? *matrix : SkMatrix::I());
237}
238
239void SkRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
240                                const SkPaint& paint) {
241    APPEND(DrawTextBlob, delay_copy(paint), blob, x, y);
242}
243
244void SkRecorder::onDrawPicture(const SkPicture* pic, const SkMatrix* matrix, const SkPaint* paint) {
245    APPEND(DrawPicture, this->copy(paint), pic, matrix ? *matrix : SkMatrix::I());
246}
247
248void SkRecorder::drawVertices(VertexMode vmode,
249                              int vertexCount, const SkPoint vertices[],
250                              const SkPoint texs[], const SkColor colors[],
251                              SkXfermode* xmode,
252                              const uint16_t indices[], int indexCount, const SkPaint& paint) {
253    APPEND(DrawVertices, delay_copy(paint),
254                         vmode,
255                         vertexCount,
256                         this->copy(vertices, vertexCount),
257                         texs ? this->copy(texs, vertexCount) : NULL,
258                         colors ? this->copy(colors, vertexCount) : NULL,
259                         xmode,
260                         this->copy(indices, indexCount),
261                         indexCount);
262}
263
264void SkRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
265                             const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
266    APPEND(DrawPatch, delay_copy(paint),
267           cubics ? this->copy(cubics, SkPatchUtils::kNumCtrlPts) : NULL,
268           colors ? this->copy(colors, SkPatchUtils::kNumCorners) : NULL,
269           texCoords ? this->copy(texCoords, SkPatchUtils::kNumCorners) : NULL,
270           xmode);
271}
272
273void SkRecorder::willSave() {
274    APPEND(Save);
275}
276
277SkCanvas::SaveLayerStrategy SkRecorder::willSaveLayer(const SkRect* bounds,
278                                                      const SkPaint* paint,
279                                                      SkCanvas::SaveFlags flags) {
280    APPEND(SaveLayer, this->copy(bounds), this->copy(paint), flags);
281    return SkCanvas::kNoLayer_SaveLayerStrategy;
282}
283
284void SkRecorder::didRestore() {
285    APPEND(Restore, this->devBounds(), this->getTotalMatrix());
286}
287
288void SkRecorder::didConcat(const SkMatrix& matrix) {
289    this->didSetMatrix(this->getTotalMatrix());
290}
291
292void SkRecorder::didSetMatrix(const SkMatrix& matrix) {
293    SkDEVCODE(if (matrix != this->getTotalMatrix()) {
294        matrix.dump();
295        this->getTotalMatrix().dump();
296        SkASSERT(matrix == this->getTotalMatrix());
297    })
298    APPEND(SetMatrix, matrix);
299}
300
301void SkRecorder::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
302    INHERITED(onClipRect, rect, op, edgeStyle);
303    SkRecords::RegionOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle);
304    APPEND(ClipRect, this->devBounds(), rect, opAA);
305}
306
307void SkRecorder::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
308    INHERITED(onClipRRect, rrect, op, edgeStyle);
309    SkRecords::RegionOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle);
310    APPEND(ClipRRect, this->devBounds(), rrect, opAA);
311}
312
313void SkRecorder::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
314    INHERITED(onClipPath, path, op, edgeStyle);
315    SkRecords::RegionOpAndAA opAA(op, kSoft_ClipEdgeStyle == edgeStyle);
316    APPEND(ClipPath, this->devBounds(), delay_copy(path), opAA);
317}
318
319void SkRecorder::onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
320    INHERITED(onClipRegion, deviceRgn, op);
321    APPEND(ClipRegion, this->devBounds(), delay_copy(deviceRgn), op);
322}
323
324void SkRecorder::beginCommentGroup(const char* description) {
325    APPEND(BeginCommentGroup, this->copy(description));
326}
327
328void SkRecorder::addComment(const char* key, const char* value) {
329    APPEND(AddComment, this->copy(key), this->copy(value));
330}
331
332void SkRecorder::endCommentGroup() {
333    APPEND(EndCommentGroup);
334}
335
336void SkRecorder::drawData(const void* data, size_t length) {
337    APPEND(DrawData, copy((const char*)data), length);
338}
339