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