SkPicture.cpp revision 3ba15ae3e13a6da0a9735fcc04166ed4d3ddcd67
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///////////////////////////////////////////////////////////////////////////////
113
114#ifdef SK_SUPPORT_LEGACY_DEFAULT_PICTURE_CTOR
115// fRecord OK
116SkPicture::SkPicture()
117    : fWidth(0)
118    , fHeight(0)
119    , fRecordWillPlayBackBitmaps(false) {
120    this->needsNewGenID();
121}
122#endif
123
124// fRecord OK
125SkPicture::SkPicture(int width, int height,
126                     const SkPictureRecord& record,
127                     bool deepCopyOps)
128    : fWidth(width)
129    , fHeight(height)
130    , fRecordWillPlayBackBitmaps(false) {
131    this->needsNewGenID();
132
133    SkPictInfo info;
134    this->createHeader(&info);
135    fData.reset(SkNEW_ARGS(SkPictureData, (record, info, deepCopyOps)));
136}
137
138// Create an SkPictureData-backed SkPicture from an SkRecord.
139// This for compatibility with serialization code only.  This is not cheap.
140static SkPicture* backport(const SkRecord& src, int width, int height) {
141    SkPictureRecorder recorder;
142    SkRecordDraw(src, recorder.beginRecording(width, height));
143    return recorder.endRecording();
144}
145
146// fRecord OK
147SkPicture::~SkPicture() {
148    this->callDeletionListeners();
149}
150
151#ifdef SK_SUPPORT_LEGACY_PICTURE_CLONE
152// fRecord TODO, fix by deleting this method
153SkPicture* SkPicture::clone() const {
154#ifdef SK_PICTURE_CLONE_NOOP
155    return SkRef(const_cast<SkPicture*>(this));
156#else
157    SkAutoTDelete<SkPictureData> newData;
158
159    if (fData.get()) {
160        SkPictCopyInfo copyInfo;
161
162        int paintCount = SafeCount(fData->fPaints);
163
164        /* The alternative to doing this is to have a clone method on the paint and have it
165         * make the deep copy of its internal structures as needed. The holdup to doing
166         * that is at this point we would need to pass the SkBitmapHeap so that we don't
167         * unnecessarily flatten the pixels in a bitmap shader.
168         */
169        copyInfo.paintData.setCount(paintCount);
170
171        /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is
172         * one, use it. If this SkPictureData was created from a stream, fBitmapHeap
173         * will be NULL, so create a new one.
174         */
175        if (fData->fBitmapHeap.get() == NULL) {
176            // FIXME: Put this on the stack inside SkPicture::clone.
177            SkBitmapHeap* heap = SkNEW(SkBitmapHeap);
178            copyInfo.controller.setBitmapStorage(heap);
179            heap->unref();
180        } else {
181            copyInfo.controller.setBitmapStorage(fData->fBitmapHeap);
182        }
183
184        SkDEBUGCODE(int heapSize = SafeCount(fData->fBitmapHeap.get());)
185        for (int i = 0; i < paintCount; i++) {
186            if (NeedsDeepCopy(fData->fPaints->at(i))) {
187                copyInfo.paintData[i] =
188                    SkFlatData::Create<SkPaint::FlatteningTraits>(&copyInfo.controller,
189                    fData->fPaints->at(i), 0);
190
191            } else {
192                // this is our sentinel, which we use in the unflatten loop
193                copyInfo.paintData[i] = NULL;
194            }
195        }
196        SkASSERT(SafeCount(fData->fBitmapHeap.get()) == heapSize);
197
198        // needed to create typeface playback
199        copyInfo.controller.setupPlaybacks();
200
201        newData.reset(SkNEW_ARGS(SkPictureData, (*fData, &copyInfo)));
202    }
203
204    SkPicture* clone = SkNEW_ARGS(SkPicture, (newData.detach(), fWidth, fHeight));
205    clone->fRecordWillPlayBackBitmaps = fRecordWillPlayBackBitmaps;
206    clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0
207
208    return clone;
209#endif
210}
211#endif//SK_SUPPORT_LEGACY_PICTURE_CLONE
212
213// fRecord OK
214void SkPicture::EXPERIMENTAL_addAccelData(const SkPicture::AccelData* data) const {
215    fAccelData.reset(SkRef(data));
216}
217
218// fRecord OK
219const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData(
220        SkPicture::AccelData::Key key) const {
221    if (NULL != fAccelData.get() && fAccelData->getKey() == key) {
222        return fAccelData.get();
223    }
224    return NULL;
225}
226
227// fRecord OK
228SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
229    static int32_t gNextID = 0;
230
231    int32_t id = sk_atomic_inc(&gNextID);
232    if (id >= 1 << (8 * sizeof(Domain))) {
233        SK_CRASH();
234    }
235
236    return static_cast<Domain>(id);
237}
238
239///////////////////////////////////////////////////////////////////////////////
240
241uint32_t SkPicture::OperationList::offset(int index) const {
242    SkASSERT(index < fOps.count());
243    return ((SkPictureStateTree::Draw*)fOps[index])->fOffset;
244}
245
246const SkMatrix& SkPicture::OperationList::matrix(int index) const {
247    SkASSERT(index < fOps.count());
248    return *((SkPictureStateTree::Draw*)fOps[index])->fMatrix;
249}
250
251// fRecord TODO
252const SkPicture::OperationList* SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const {
253    SkASSERT(NULL != fData.get());
254    if (NULL != fData.get()) {
255        return fData->getActiveOps(queryRect);
256    }
257    return NULL;
258}
259
260// fRecord OK
261void SkPicture::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) const {
262    SkASSERT(NULL != canvas);
263    SkASSERT(NULL != fData.get() || NULL != fRecord.get());
264
265    if (NULL != fData.get()) {
266        SkPicturePlayback playback(this);
267        playback.draw(canvas, callback);
268    }
269    if (NULL != fRecord.get()) {
270        SkRecordDraw(*fRecord, canvas, callback);
271    }
272}
273
274///////////////////////////////////////////////////////////////////////////////
275
276#include "SkStream.h"
277
278static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
279
280// fRecord OK
281bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
282    if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
283        return false;
284    }
285
286    if (info.fVersion < MIN_PICTURE_VERSION ||
287        info.fVersion > CURRENT_PICTURE_VERSION) {
288        return false;
289    }
290
291    return true;
292}
293
294// fRecord OK
295bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
296    if (NULL == stream) {
297        return false;
298    }
299
300    // Check magic bytes.
301    SkPictInfo info;
302    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
303    if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) {
304        return false;
305    }
306
307    if (pInfo != NULL) {
308        *pInfo = info;
309    }
310    return true;
311}
312
313// fRecord OK
314bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) {
315    // Check magic bytes.
316    SkPictInfo info;
317    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
318    if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) {
319        return false;
320    }
321
322    if (pInfo != NULL) {
323        *pInfo = info;
324    }
325    return true;
326}
327
328// fRecord OK
329SkPicture::SkPicture(SkPictureData* data, int width, int height)
330    : fData(data)
331    , fWidth(width)
332    , fHeight(height)
333    , fRecordWillPlayBackBitmaps(false) {
334    this->needsNewGenID();
335}
336
337// fRecord OK
338SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
339    SkPictInfo info;
340
341    if (!InternalOnly_StreamIsSKP(stream, &info)) {
342        return NULL;
343    }
344
345    // Check to see if there is a playback to recreate.
346    if (stream->readBool()) {
347        SkPictureData* data = SkPictureData::CreateFromStream(stream, info, proc);
348        if (NULL == data) {
349            return NULL;
350        }
351
352        return SkNEW_ARGS(SkPicture, (data, info.fWidth, info.fHeight));
353    }
354
355    return NULL;
356}
357
358// fRecord OK
359SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
360    SkPictInfo info;
361
362    if (!InternalOnly_BufferIsSKP(buffer, &info)) {
363        return NULL;
364    }
365
366    // Check to see if there is a playback to recreate.
367    if (buffer.readBool()) {
368        SkPictureData* data = SkPictureData::CreateFromBuffer(buffer, info);
369        if (NULL == data) {
370            return NULL;
371        }
372
373        return SkNEW_ARGS(SkPicture, (data, info.fWidth, info.fHeight));
374    }
375
376    return NULL;
377}
378
379// fRecord OK
380void SkPicture::createHeader(SkPictInfo* info) const {
381    // Copy magic bytes at the beginning of the header
382    SkASSERT(sizeof(kMagic) == 8);
383    SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
384    memcpy(info->fMagic, kMagic, sizeof(kMagic));
385
386    // Set picture info after magic bytes in the header
387    info->fVersion = CURRENT_PICTURE_VERSION;
388    info->fWidth = fWidth;
389    info->fHeight = fHeight;
390    info->fFlags = SkPictInfo::kCrossProcess_Flag;
391    // TODO: remove this flag, since we're always float (now)
392    info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
393
394    if (8 == sizeof(void*)) {
395        info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
396    }
397}
398
399// fRecord OK
400void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
401    const SkPictureData* data = fData.get();
402
403    // If we're a new-format picture, backport to old format for serialization.
404    SkAutoTDelete<SkPicture> oldFormat;
405    if (NULL == data && NULL != fRecord.get()) {
406        oldFormat.reset(backport(*fRecord, fWidth, fHeight));
407        data = oldFormat->fData.get();
408        SkASSERT(NULL != data);
409    }
410
411    SkPictInfo info;
412    this->createHeader(&info);
413    stream->write(&info, sizeof(info));
414
415    if (NULL != data) {
416        stream->writeBool(true);
417        data->serialize(stream, encoder);
418    } else {
419        stream->writeBool(false);
420    }
421}
422
423// fRecord OK
424void SkPicture::flatten(SkWriteBuffer& buffer) const {
425    const SkPictureData* data = fData.get();
426
427    // If we're a new-format picture, backport to old format for serialization.
428    SkAutoTDelete<SkPicture> oldFormat;
429    if (NULL == data && NULL != fRecord.get()) {
430        oldFormat.reset(backport(*fRecord, fWidth, fHeight));
431        data = oldFormat->fData.get();
432        SkASSERT(NULL != data);
433    }
434
435    SkPictInfo info;
436    this->createHeader(&info);
437    buffer.writeByteArray(&info, sizeof(info));
438
439    if (NULL != data) {
440        buffer.writeBool(true);
441        data->flatten(buffer);
442    } else {
443        buffer.writeBool(false);
444    }
445}
446
447#if SK_SUPPORT_GPU
448// fRecord TODO
449bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const {
450    if (NULL == fData.get()) {
451        if (NULL != reason) {
452            *reason = "Missing internal data.";
453        }
454        return false;
455    }
456
457    return fData->suitableForGpuRasterization(context, reason);
458}
459#endif
460
461// fRecord OK
462bool SkPicture::willPlayBackBitmaps() const {
463    if (fRecord.get()) {
464        return fRecordWillPlayBackBitmaps;
465    }
466    if (!fData.get()) {
467        return false;
468    }
469    return fData->containsBitmaps();
470}
471
472// fRecord OK
473static int32_t next_picture_generation_id() {
474    static int32_t  gPictureGenerationID = 0;
475    // do a loop in case our global wraps around, as we never want to
476    // return a 0
477    int32_t genID;
478    do {
479        genID = sk_atomic_inc(&gPictureGenerationID) + 1;
480    } while (SK_InvalidGenID == genID);
481    return genID;
482}
483
484// fRecord OK
485uint32_t SkPicture::uniqueID() const {
486    if (SK_InvalidGenID == fUniqueID) {
487        fUniqueID = next_picture_generation_id();
488    }
489    return fUniqueID;
490}
491
492// fRecord OK
493SkPicture::SkPicture(int width, int height, SkRecord* record)
494    : fWidth(width)
495    , fHeight(height)
496    , fRecord(record)
497    , fRecordWillPlayBackBitmaps(SkRecordWillPlaybackBitmaps(*record)) {
498    this->needsNewGenID();
499}
500
501// Note that we are assuming that this entry point will only be called from
502// one thread. Currently the only client of this method is
503// SkGpuDevice::EXPERIMENTAL_optimize which should be only called from a single
504// thread.
505void SkPicture::addDeletionListener(DeletionListener* listener) const {
506    SkASSERT(NULL != listener);
507
508    *fDeletionListeners.append() = SkRef(listener);
509}
510
511void SkPicture::callDeletionListeners() {
512    for (int i = 0; i < fDeletionListeners.count(); ++i) {
513        fDeletionListeners[i]->onDeletion(this->uniqueID());
514    }
515
516    fDeletionListeners.unrefAll();
517}
518