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 "SkBBHFactory.h"
15#include "SkBitmapDevice.h"
16#include "SkCanvas.h"
17#include "SkChunkAlloc.h"
18#include "SkPaintPriv.h"
19#include "SkPicture.h"
20#include "SkRegion.h"
21#include "SkStream.h"
22#include "SkTDArray.h"
23#include "SkTSearch.h"
24#include "SkTime.h"
25
26#include "SkReader32.h"
27#include "SkWriter32.h"
28#include "SkRTree.h"
29#include "SkBBoxHierarchyRecord.h"
30
31#if SK_SUPPORT_GPU
32#include "GrContext.h"
33#endif
34
35template <typename T> int SafeCount(const T* obj) {
36    return obj ? obj->count() : 0;
37}
38
39#define DUMP_BUFFER_SIZE 65536
40
41//#define ENABLE_TIME_DRAW    // dumps milliseconds for each draw
42
43
44#ifdef SK_DEBUG
45// enable SK_DEBUG_TRACE to trace DrawType elements when
46//     recorded and played back
47// #define SK_DEBUG_TRACE
48// enable SK_DEBUG_SIZE to see the size of picture components
49// #define SK_DEBUG_SIZE
50// enable SK_DEBUG_DUMP to see the contents of recorded elements
51// #define SK_DEBUG_DUMP
52// enable SK_DEBUG_VALIDATE to check internal structures for consistency
53// #define SK_DEBUG_VALIDATE
54#endif
55
56#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
57const char* DrawTypeToString(DrawType drawType) {
58    switch (drawType) {
59        case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
60        case CLIP_PATH: return "CLIP_PATH";
61        case CLIP_REGION: return "CLIP_REGION";
62        case CLIP_RECT: return "CLIP_RECT";
63        case CLIP_RRECT: return "CLIP_RRECT";
64        case CONCAT: return "CONCAT";
65        case DRAW_BITMAP: return "DRAW_BITMAP";
66        case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
67        case DRAW_BITMAP_NINE: return "DRAW_BITMAP_NINE";
68        case DRAW_BITMAP_RECT_TO_RECT: return "DRAW_BITMAP_RECT_TO_RECT";
69        case DRAW_CLEAR: return "DRAW_CLEAR";
70        case DRAW_DATA: return "DRAW_DATA";
71        case DRAW_OVAL: return "DRAW_OVAL";
72        case DRAW_PAINT: return "DRAW_PAINT";
73        case DRAW_PATH: return "DRAW_PATH";
74        case DRAW_PICTURE: return "DRAW_PICTURE";
75        case DRAW_POINTS: return "DRAW_POINTS";
76        case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
77        case DRAW_POS_TEXT_TOP_BOTTOM: return "DRAW_POS_TEXT_TOP_BOTTOM";
78        case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
79        case DRAW_POS_TEXT_H_TOP_BOTTOM: return "DRAW_POS_TEXT_H_TOP_BOTTOM";
80        case DRAW_RECT: return "DRAW_RECT";
81        case DRAW_RRECT: return "DRAW_RRECT";
82        case DRAW_SPRITE: return "DRAW_SPRITE";
83        case DRAW_TEXT: return "DRAW_TEXT";
84        case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
85        case DRAW_TEXT_TOP_BOTTOM: return "DRAW_TEXT_TOP_BOTTOM";
86        case DRAW_VERTICES: return "DRAW_VERTICES";
87        case RESTORE: return "RESTORE";
88        case ROTATE: return "ROTATE";
89        case SAVE: return "SAVE";
90        case SAVE_LAYER: return "SAVE_LAYER";
91        case SCALE: return "SCALE";
92        case SET_MATRIX: return "SET_MATRIX";
93        case SKEW: return "SKEW";
94        case TRANSLATE: return "TRANSLATE";
95        case NOOP: return "NOOP";
96        default:
97            SkDebugf("DrawType error 0x%08x\n", drawType);
98            SkASSERT(0);
99            break;
100    }
101    SkASSERT(0);
102    return NULL;
103}
104#endif
105
106#ifdef SK_DEBUG_VALIDATE
107static void validateMatrix(const SkMatrix* matrix) {
108    SkScalar scaleX = matrix->getScaleX();
109    SkScalar scaleY = matrix->getScaleY();
110    SkScalar skewX = matrix->getSkewX();
111    SkScalar skewY = matrix->getSkewY();
112    SkScalar perspX = matrix->getPerspX();
113    SkScalar perspY = matrix->getPerspY();
114    if (scaleX != 0 && skewX != 0)
115        SkDebugf("scaleX != 0 && skewX != 0\n");
116    SkASSERT(scaleX == 0 || skewX == 0);
117    SkASSERT(scaleY == 0 || skewY == 0);
118    SkASSERT(perspX == 0);
119    SkASSERT(perspY == 0);
120}
121#endif
122
123
124///////////////////////////////////////////////////////////////////////////////
125
126SkPicture::SkPicture()
127    : fAccelData(NULL) {
128    this->needsNewGenID();
129    fPlayback = NULL;
130    fWidth = fHeight = 0;
131}
132
133SkPicture::SkPicture(int width, int height,
134                     const SkPictureRecord& record,
135                     bool deepCopyOps)
136    : fWidth(width)
137    , fHeight(height)
138    , fAccelData(NULL) {
139    this->needsNewGenID();
140
141    SkPictInfo info;
142    this->createHeader(&info);
143    fPlayback = SkNEW_ARGS(SkPicturePlayback, (record, info, deepCopyOps));
144}
145
146SkPicture::SkPicture(const SkPicture& src)
147    : INHERITED()
148    , fAccelData(NULL) {
149    this->needsNewGenID();
150    fWidth = src.fWidth;
151    fHeight = src.fHeight;
152
153    if (src.fPlayback) {
154        fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
155        fUniqueID = src.uniqueID();     // need to call method to ensure != 0
156    } else {
157        fPlayback = NULL;
158    }
159}
160
161SkPicture::~SkPicture() {
162    SkDELETE(fPlayback);
163    SkSafeUnref(fAccelData);
164}
165
166void SkPicture::swap(SkPicture& other) {
167    SkTSwap(fUniqueID, other.fUniqueID);
168    SkTSwap(fPlayback, other.fPlayback);
169    SkTSwap(fAccelData, other.fAccelData);
170    SkTSwap(fWidth, other.fWidth);
171    SkTSwap(fHeight, other.fHeight);
172}
173
174SkPicture* SkPicture::clone() const {
175    SkPicture* clonedPicture = SkNEW(SkPicture);
176    this->clone(clonedPicture, 1);
177    return clonedPicture;
178}
179
180void SkPicture::clone(SkPicture* pictures, int count) const {
181    SkPictCopyInfo copyInfo;
182
183    for (int i = 0; i < count; i++) {
184        SkPicture* clone = &pictures[i];
185
186        clone->needsNewGenID();
187        clone->fWidth = fWidth;
188        clone->fHeight = fHeight;
189        SkDELETE(clone->fPlayback);
190
191        /*  We want to copy the src's playback. However, if that hasn't been built
192            yet, we need to fake a call to endRecording() without actually calling
193            it (since it is destructive, and we don't want to change src).
194         */
195        if (fPlayback) {
196            if (!copyInfo.initialized) {
197                int paintCount = SafeCount(fPlayback->fPaints);
198
199                /* The alternative to doing this is to have a clone method on the paint and have it
200                 * make the deep copy of its internal structures as needed. The holdup to doing
201                 * that is at this point we would need to pass the SkBitmapHeap so that we don't
202                 * unnecessarily flatten the pixels in a bitmap shader.
203                 */
204                copyInfo.paintData.setCount(paintCount);
205
206                /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is
207                 * one, use it. If this SkPicturePlayback was created from a stream, fBitmapHeap
208                 * will be NULL, so create a new one.
209                 */
210                if (fPlayback->fBitmapHeap.get() == NULL) {
211                    // FIXME: Put this on the stack inside SkPicture::clone.
212                    SkBitmapHeap* heap = SkNEW(SkBitmapHeap);
213                    copyInfo.controller.setBitmapStorage(heap);
214                    heap->unref();
215                } else {
216                    copyInfo.controller.setBitmapStorage(fPlayback->fBitmapHeap);
217                }
218
219                SkDEBUGCODE(int heapSize = SafeCount(fPlayback->fBitmapHeap.get());)
220                for (int i = 0; i < paintCount; i++) {
221                    if (NeedsDeepCopy(fPlayback->fPaints->at(i))) {
222                        copyInfo.paintData[i] =
223                            SkFlatData::Create<SkPaint::FlatteningTraits>(&copyInfo.controller,
224                                                              fPlayback->fPaints->at(i), 0);
225
226                    } else {
227                        // this is our sentinel, which we use in the unflatten loop
228                        copyInfo.paintData[i] = NULL;
229                    }
230                }
231                SkASSERT(SafeCount(fPlayback->fBitmapHeap.get()) == heapSize);
232
233                // needed to create typeface playback
234                copyInfo.controller.setupPlaybacks();
235                copyInfo.initialized = true;
236            }
237
238            clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, &copyInfo));
239            clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0
240        } else {
241            clone->fPlayback = NULL;
242        }
243    }
244}
245
246SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
247    static int32_t gNextID = 0;
248
249    int32_t id = sk_atomic_inc(&gNextID);
250    if (id >= 1 << (8 * sizeof(Domain))) {
251        SK_CRASH();
252    }
253
254    return static_cast<Domain>(id);
255}
256
257///////////////////////////////////////////////////////////////////////////////
258
259const SkPicture::OperationList& SkPicture::OperationList::InvalidList() {
260    static OperationList gInvalid;
261    return gInvalid;
262}
263
264const SkPicture::OperationList& SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const {
265    SkASSERT(NULL != fPlayback);
266    if (NULL != fPlayback) {
267        return fPlayback->getActiveOps(queryRect);
268    }
269    return OperationList::InvalidList();
270}
271
272size_t SkPicture::EXPERIMENTAL_curOpID() const {
273    if (NULL != fPlayback) {
274        return fPlayback->curOpID();
275    }
276    return 0;
277}
278
279void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) const {
280    SkASSERT(NULL != fPlayback);
281    if (NULL != fPlayback) {
282        fPlayback->draw(*surface, callback);
283    }
284}
285
286///////////////////////////////////////////////////////////////////////////////
287
288#include "SkStream.h"
289
290static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
291
292bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
293    if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
294        return false;
295    }
296
297    if (info.fVersion < MIN_PICTURE_VERSION ||
298        info.fVersion > CURRENT_PICTURE_VERSION) {
299        return false;
300    }
301
302    return true;
303}
304
305bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
306    if (NULL == stream) {
307        return false;
308    }
309
310    // Check magic bytes.
311    SkPictInfo info;
312    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
313    if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) {
314        return false;
315    }
316
317    if (pInfo != NULL) {
318        *pInfo = info;
319    }
320    return true;
321}
322
323bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) {
324    // Check magic bytes.
325    SkPictInfo info;
326    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
327    if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) {
328        return false;
329    }
330
331    if (pInfo != NULL) {
332        *pInfo = info;
333    }
334    return true;
335}
336
337SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height)
338    : fPlayback(playback)
339    , fWidth(width)
340    , fHeight(height)
341    , fAccelData(NULL) {
342    this->needsNewGenID();
343}
344
345SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
346    SkPictInfo info;
347
348    if (!InternalOnly_StreamIsSKP(stream, &info)) {
349        return NULL;
350    }
351
352    // Check to see if there is a playback to recreate.
353    if (stream->readBool()) {
354        SkPicturePlayback* playback = SkPicturePlayback::CreateFromStream(stream, info, proc);
355        if (NULL == playback) {
356            return NULL;
357        }
358
359        return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight));
360    }
361
362    return NULL;
363}
364
365SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
366    SkPictInfo info;
367
368    if (!InternalOnly_BufferIsSKP(buffer, &info)) {
369        return NULL;
370    }
371
372    // Check to see if there is a playback to recreate.
373    if (buffer.readBool()) {
374        SkPicturePlayback* playback = SkPicturePlayback::CreateFromBuffer(buffer, info);
375        if (NULL == playback) {
376            return NULL;
377        }
378
379        return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight));
380    }
381
382    return NULL;
383}
384
385void SkPicture::createHeader(SkPictInfo* info) const {
386    // Copy magic bytes at the beginning of the header
387    SkASSERT(sizeof(kMagic) == 8);
388    SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
389    memcpy(info->fMagic, kMagic, sizeof(kMagic));
390
391    // Set picture info after magic bytes in the header
392    info->fVersion = CURRENT_PICTURE_VERSION;
393    info->fWidth = fWidth;
394    info->fHeight = fHeight;
395    info->fFlags = SkPictInfo::kCrossProcess_Flag;
396    // TODO: remove this flag, since we're always float (now)
397    info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
398
399    if (8 == sizeof(void*)) {
400        info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
401    }
402}
403
404void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
405    SkPicturePlayback* playback = fPlayback;
406
407    SkPictInfo info;
408    this->createHeader(&info);
409    stream->write(&info, sizeof(info));
410    if (playback) {
411        stream->writeBool(true);
412        playback->serialize(stream, encoder);
413        // delete playback if it is a local version (i.e. cons'd up just now)
414        if (playback != fPlayback) {
415            SkDELETE(playback);
416        }
417    } else {
418        stream->writeBool(false);
419    }
420}
421
422void SkPicture::WriteTagSize(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
423    buffer.writeUInt(tag);
424    buffer.writeUInt(SkToU32(size));
425}
426
427void SkPicture::WriteTagSize(SkWStream* stream, uint32_t tag,  size_t size) {
428    stream->write32(tag);
429    stream->write32(SkToU32(size));
430}
431
432void SkPicture::flatten(SkWriteBuffer& buffer) const {
433    SkPicturePlayback* playback = fPlayback;
434
435    SkPictInfo info;
436    this->createHeader(&info);
437    buffer.writeByteArray(&info, sizeof(info));
438    if (playback) {
439        buffer.writeBool(true);
440        playback->flatten(buffer);
441        // delete playback if it is a local version (i.e. cons'd up just now)
442        if (playback != fPlayback) {
443            SkDELETE(playback);
444        }
445    } else {
446        buffer.writeBool(false);
447    }
448}
449
450#if SK_SUPPORT_GPU
451bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const {
452    if (NULL == fPlayback) {
453        if (NULL != reason) {
454            *reason = "Missing playback object.";
455        }
456        return false;
457    }
458
459    return fPlayback->suitableForGpuRasterization(context, reason);
460}
461#endif
462
463bool SkPicture::willPlayBackBitmaps() const {
464    if (!fPlayback) {
465        return false;
466    }
467    return fPlayback->containsBitmaps();
468}
469
470#ifdef SK_BUILD_FOR_ANDROID
471void SkPicture::abortPlayback() {
472    if (NULL == fPlayback) {
473        return;
474    }
475    fPlayback->abort();
476}
477#endif
478
479static int32_t next_picture_generation_id() {
480    static int32_t  gPictureGenerationID = 0;
481    // do a loop in case our global wraps around, as we never want to
482    // return a 0
483    int32_t genID;
484    do {
485        genID = sk_atomic_inc(&gPictureGenerationID) + 1;
486    } while (SK_InvalidGenID == genID);
487    return genID;
488}
489
490uint32_t SkPicture::uniqueID() const {
491    if (SK_InvalidGenID == fUniqueID) {
492        fUniqueID = next_picture_generation_id();
493    }
494    return fUniqueID;
495}
496