1
2/*
3 * Copyright 2007 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkPictureFlat.h"
11#include "SkPicturePlayback.h"
12#include "SkPictureRecord.h"
13
14#include "SkBitmapDevice.h"
15#include "SkCanvas.h"
16#include "SkChunkAlloc.h"
17#include "SkPicture.h"
18#include "SkRegion.h"
19#include "SkStream.h"
20#include "SkTDArray.h"
21#include "SkTSearch.h"
22#include "SkTime.h"
23
24#include "SkReader32.h"
25#include "SkWriter32.h"
26#include "SkRTree.h"
27#include "SkBBoxHierarchyRecord.h"
28
29#define DUMP_BUFFER_SIZE 65536
30
31//#define ENABLE_TIME_DRAW    // dumps milliseconds for each draw
32
33
34#ifdef SK_DEBUG
35// enable SK_DEBUG_TRACE to trace DrawType elements when
36//     recorded and played back
37// #define SK_DEBUG_TRACE
38// enable SK_DEBUG_SIZE to see the size of picture components
39// #define SK_DEBUG_SIZE
40// enable SK_DEBUG_DUMP to see the contents of recorded elements
41// #define SK_DEBUG_DUMP
42// enable SK_DEBUG_VALIDATE to check internal structures for consistency
43// #define SK_DEBUG_VALIDATE
44#endif
45
46#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
47const char* DrawTypeToString(DrawType drawType) {
48    switch (drawType) {
49        case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
50        case CLIP_PATH: return "CLIP_PATH";
51        case CLIP_REGION: return "CLIP_REGION";
52        case CLIP_RECT: return "CLIP_RECT";
53        case CLIP_RRECT: return "CLIP_RRECT";
54        case CONCAT: return "CONCAT";
55        case DRAW_BITMAP: return "DRAW_BITMAP";
56        case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
57        case DRAW_BITMAP_NINE: return "DRAW_BITMAP_NINE";
58        case DRAW_BITMAP_RECT_TO_RECT: return "DRAW_BITMAP_RECT_TO_RECT";
59        case DRAW_CLEAR: return "DRAW_CLEAR";
60        case DRAW_DATA: return "DRAW_DATA";
61        case DRAW_OVAL: return "DRAW_OVAL";
62        case DRAW_PAINT: return "DRAW_PAINT";
63        case DRAW_PATH: return "DRAW_PATH";
64        case DRAW_PICTURE: return "DRAW_PICTURE";
65        case DRAW_POINTS: return "DRAW_POINTS";
66        case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
67        case DRAW_POS_TEXT_TOP_BOTTOM: return "DRAW_POS_TEXT_TOP_BOTTOM";
68        case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
69        case DRAW_POS_TEXT_H_TOP_BOTTOM: return "DRAW_POS_TEXT_H_TOP_BOTTOM";
70        case DRAW_RECT: return "DRAW_RECT";
71        case DRAW_RRECT: return "DRAW_RRECT";
72        case DRAW_SPRITE: return "DRAW_SPRITE";
73        case DRAW_TEXT: return "DRAW_TEXT";
74        case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
75        case DRAW_TEXT_TOP_BOTTOM: return "DRAW_TEXT_TOP_BOTTOM";
76        case DRAW_VERTICES: return "DRAW_VERTICES";
77        case RESTORE: return "RESTORE";
78        case ROTATE: return "ROTATE";
79        case SAVE: return "SAVE";
80        case SAVE_LAYER: return "SAVE_LAYER";
81        case SCALE: return "SCALE";
82        case SET_MATRIX: return "SET_MATRIX";
83        case SKEW: return "SKEW";
84        case TRANSLATE: return "TRANSLATE";
85        case NOOP: return "NOOP";
86        default:
87            SkDebugf("DrawType error 0x%08x\n", drawType);
88            SkASSERT(0);
89            break;
90    }
91    SkASSERT(0);
92    return NULL;
93}
94#endif
95
96#ifdef SK_DEBUG_VALIDATE
97static void validateMatrix(const SkMatrix* matrix) {
98    SkScalar scaleX = matrix->getScaleX();
99    SkScalar scaleY = matrix->getScaleY();
100    SkScalar skewX = matrix->getSkewX();
101    SkScalar skewY = matrix->getSkewY();
102    SkScalar perspX = matrix->getPerspX();
103    SkScalar perspY = matrix->getPerspY();
104    if (scaleX != 0 && skewX != 0)
105        SkDebugf("scaleX != 0 && skewX != 0\n");
106    SkASSERT(scaleX == 0 || skewX == 0);
107    SkASSERT(scaleY == 0 || skewY == 0);
108    SkASSERT(perspX == 0);
109    SkASSERT(perspY == 0);
110}
111#endif
112
113
114///////////////////////////////////////////////////////////////////////////////
115
116SkPicture::SkPicture() {
117    fRecord = NULL;
118    fPlayback = NULL;
119    fWidth = fHeight = 0;
120}
121
122SkPicture::SkPicture(const SkPicture& src) : INHERITED() {
123    fWidth = src.fWidth;
124    fHeight = src.fHeight;
125    fRecord = NULL;
126
127    /*  We want to copy the src's playback. However, if that hasn't been built
128        yet, we need to fake a call to endRecording() without actually calling
129        it (since it is destructive, and we don't want to change src).
130     */
131    if (src.fPlayback) {
132        fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
133    } else if (src.fRecord) {
134        // here we do a fake src.endRecording()
135        fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord));
136    } else {
137        fPlayback = NULL;
138    }
139}
140
141SkPicture::~SkPicture() {
142    SkSafeUnref(fRecord);
143    SkDELETE(fPlayback);
144}
145
146void SkPicture::swap(SkPicture& other) {
147    SkTSwap(fRecord, other.fRecord);
148    SkTSwap(fPlayback, other.fPlayback);
149    SkTSwap(fWidth, other.fWidth);
150    SkTSwap(fHeight, other.fHeight);
151}
152
153SkPicture* SkPicture::clone() const {
154    SkPicture* clonedPicture = SkNEW(SkPicture);
155    clone(clonedPicture, 1);
156    return clonedPicture;
157}
158
159void SkPicture::clone(SkPicture* pictures, int count) const {
160    SkPictCopyInfo copyInfo;
161
162    for (int i = 0; i < count; i++) {
163        SkPicture* clone = &pictures[i];
164
165        clone->fWidth = fWidth;
166        clone->fHeight = fHeight;
167        clone->fRecord = NULL;
168
169        if (NULL != clone->fRecord) {
170            clone->fRecord->unref();
171            clone->fRecord = NULL;
172        }
173        SkDELETE(clone->fPlayback);
174
175        /*  We want to copy the src's playback. However, if that hasn't been built
176            yet, we need to fake a call to endRecording() without actually calling
177            it (since it is destructive, and we don't want to change src).
178         */
179        if (fPlayback) {
180            clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, &copyInfo));
181        } else if (fRecord) {
182            // here we do a fake src.endRecording()
183            clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, true));
184        } else {
185            clone->fPlayback = NULL;
186        }
187    }
188}
189
190///////////////////////////////////////////////////////////////////////////////
191
192SkCanvas* SkPicture::beginRecording(int width, int height,
193                                    uint32_t recordingFlags) {
194    if (fPlayback) {
195        SkDELETE(fPlayback);
196        fPlayback = NULL;
197    }
198
199    if (NULL != fRecord) {
200        fRecord->unref();
201        fRecord = NULL;
202    }
203
204    SkBitmap bm;
205    bm.setConfig(SkBitmap::kNo_Config, width, height);
206    SkAutoTUnref<SkBaseDevice> dev(SkNEW_ARGS(SkBitmapDevice, (bm)));
207
208    // Must be set before calling createBBoxHierarchy
209    fWidth = width;
210    fHeight = height;
211
212    if (recordingFlags & kOptimizeForClippedPlayback_RecordingFlag) {
213        SkBBoxHierarchy* tree = this->createBBoxHierarchy();
214        SkASSERT(NULL != tree);
215        fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (recordingFlags, tree, dev));
216        tree->unref();
217    } else {
218        fRecord = SkNEW_ARGS(SkPictureRecord, (recordingFlags, dev));
219    }
220    fRecord->beginRecording();
221
222    return fRecord;
223}
224
225SkBBoxHierarchy* SkPicture::createBBoxHierarchy() const {
226    // These values were empirically determined to produce reasonable
227    // performance in most cases.
228    static const int kRTreeMinChildren = 6;
229    static const int kRTreeMaxChildren = 11;
230
231    SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth),
232                                       SkIntToScalar(fHeight));
233    bool sortDraws = false;  // Do not sort draw calls when bulk loading.
234
235    return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren,
236                           aspectRatio, sortDraws);
237}
238
239SkCanvas* SkPicture::getRecordingCanvas() const {
240    // will be null if we are not recording
241    return fRecord;
242}
243
244void SkPicture::endRecording() {
245    if (NULL == fPlayback) {
246        if (NULL != fRecord) {
247            fRecord->endRecording();
248            fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
249            fRecord->unref();
250            fRecord = NULL;
251        }
252    }
253    SkASSERT(NULL == fRecord);
254}
255
256void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) {
257    this->endRecording();
258    if (fPlayback) {
259        fPlayback->draw(*surface, callback);
260    }
261}
262
263///////////////////////////////////////////////////////////////////////////////
264
265#include "SkStream.h"
266
267static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
268
269bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
270    if (NULL == stream) {
271        return false;
272    }
273
274    // Check magic bytes.
275    char magic[sizeof(kMagic)];
276    stream->read(magic, sizeof(kMagic));
277    if (0 != memcmp(magic, kMagic, sizeof(kMagic))) {
278        return false;
279    }
280
281    SkPictInfo info;
282    if (!stream->read(&info, sizeof(SkPictInfo))) {
283        return false;
284    }
285
286    if (PICTURE_VERSION != info.fVersion
287#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
288        // V16 is backwards compatible with V15
289        && PRIOR_PICTURE_VERSION != info.fVersion  // TODO: remove when .skps regenerated
290#endif
291        ) {
292        return false;
293    }
294
295    if (pInfo != NULL) {
296        *pInfo = info;
297    }
298    return true;
299}
300
301SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height)
302    : fPlayback(playback)
303    , fRecord(NULL)
304    , fWidth(width)
305    , fHeight(height) {}
306
307SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
308    SkPictInfo info;
309
310    if (!StreamIsSKP(stream, &info)) {
311        return NULL;
312    }
313
314    SkPicturePlayback* playback;
315    // Check to see if there is a playback to recreate.
316    if (stream->readBool()) {
317        playback = SkPicturePlayback::CreateFromStream(stream, info, proc);
318        if (NULL == playback) {
319            return NULL;
320        }
321    } else {
322        playback = NULL;
323    }
324
325    return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight));
326}
327
328void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
329    SkPicturePlayback* playback = fPlayback;
330
331    if (NULL == playback && fRecord) {
332        playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord));
333    }
334
335    SkPictInfo info;
336
337    info.fVersion = PICTURE_VERSION;
338    info.fWidth = fWidth;
339    info.fHeight = fHeight;
340    info.fFlags = SkPictInfo::kCrossProcess_Flag;
341#ifdef SK_SCALAR_IS_FLOAT
342    info.fFlags |= SkPictInfo::kScalarIsFloat_Flag;
343#endif
344    if (8 == sizeof(void*)) {
345        info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
346    }
347
348    // Write 8 magic bytes to ID this file format.
349    SkASSERT(sizeof(kMagic) == 8);
350    stream->write(kMagic, sizeof(kMagic));
351
352    stream->write(&info, sizeof(info));
353    if (playback) {
354        stream->writeBool(true);
355        playback->serialize(stream, encoder);
356        // delete playback if it is a local version (i.e. cons'd up just now)
357        if (playback != fPlayback) {
358            SkDELETE(playback);
359        }
360    } else {
361        stream->writeBool(false);
362    }
363}
364
365bool SkPicture::willPlayBackBitmaps() const {
366    if (!fPlayback) return false;
367    return fPlayback->containsBitmaps();
368}
369
370#ifdef SK_BUILD_FOR_ANDROID
371void SkPicture::abortPlayback() {
372    if (NULL == fPlayback) {
373        return;
374    }
375    fPlayback->abort();
376}
377#endif
378