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