SkPicture.cpp revision 9b14f26d0f3a974f3dd626c8354e1db1cfcd322f
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    fRecord = NULL;
130    fPlayback = NULL;
131    fWidth = fHeight = 0;
132}
133
134// This method makes a SkPicturePlayback object from an in-progress recording.
135// Unfortunately, it does not include the restoreToCount of a real endRecording
136// call.
137SkPicturePlayback* SkPicture::FakeEndRecording(const SkPicture* resourceSrc,
138                                               const SkPictureRecord& record,
139                                               bool deepCopy) {
140    SkPictInfo info;
141    resourceSrc->createHeader(&info);
142    return SkNEW_ARGS(SkPicturePlayback, (resourceSrc, record, info, deepCopy));
143}
144
145SkPicture::SkPicture(const SkPicture& src)
146    : INHERITED()
147    , fAccelData(NULL)
148    , fContentInfo(src.fContentInfo) {
149    this->needsNewGenID();
150    fWidth = src.fWidth;
151    fHeight = src.fHeight;
152    fRecord = NULL;
153
154    /*  We want to copy the src's playback. However, if that hasn't been built
155        yet, we need to fake a call to endRecording() without actually calling
156        it (since it is destructive, and we don't want to change src).
157     */
158    if (src.fPlayback) {
159        fPlayback = SkNEW_ARGS(SkPicturePlayback, (this, *src.fPlayback));
160        SkASSERT(NULL == src.fRecord);
161        fUniqueID = src.uniqueID();     // need to call method to ensure != 0
162    } else if (src.fRecord) {
163        fPlayback = FakeEndRecording(this, *src.fRecord, false);
164    } else {
165        fPlayback = NULL;
166    }
167
168    fPathHeap.reset(SkSafeRef(src.fPathHeap.get()));
169}
170
171const SkPath& SkPicture::getPath(int index) const {
172    return (*fPathHeap.get())[index];
173}
174
175int SkPicture::addPathToHeap(const SkPath& path) {
176    if (NULL == fPathHeap) {
177        fPathHeap.reset(SkNEW(SkPathHeap));
178    }
179#ifdef SK_DEDUP_PICTURE_PATHS
180    return fPathHeap->insert(path);
181#else
182    return fPathHeap->append(path);
183#endif
184}
185
186void SkPicture::initForPlayback() const {
187    // ensure that the paths bounds are pre-computed
188    if (NULL != fPathHeap.get()) {
189        for (int i = 0; i < fPathHeap->count(); i++) {
190            (*fPathHeap.get())[i].updateBoundsCache();
191        }
192    }
193}
194
195void SkPicture::dumpSize() const {
196    SkDebugf("--- picture size: paths=%d\n",
197             SafeCount(fPathHeap.get()));
198}
199
200SkPicture::~SkPicture() {
201    SkSafeUnref(fRecord);
202    SkDELETE(fPlayback);
203    SkSafeUnref(fAccelData);
204}
205
206void SkPicture::internalOnly_EnableOpts(bool enableOpts) {
207    if (NULL != fRecord) {
208        fRecord->internalOnly_EnableOpts(enableOpts);
209    }
210}
211
212void SkPicture::swap(SkPicture& other) {
213    SkTSwap(fUniqueID, other.fUniqueID);
214    SkTSwap(fRecord, other.fRecord);
215    SkTSwap(fPlayback, other.fPlayback);
216    SkTSwap(fAccelData, other.fAccelData);
217    SkTSwap(fWidth, other.fWidth);
218    SkTSwap(fHeight, other.fHeight);
219    fPathHeap.swap(&other.fPathHeap);
220    fContentInfo.swap(&other.fContentInfo);
221}
222
223SkPicture* SkPicture::clone() const {
224    SkPicture* clonedPicture = SkNEW(SkPicture);
225    this->clone(clonedPicture, 1);
226    return clonedPicture;
227}
228
229void SkPicture::clone(SkPicture* pictures, int count) const {
230    SkPictCopyInfo copyInfo;
231
232    for (int i = 0; i < count; i++) {
233        SkPicture* clone = &pictures[i];
234
235        clone->needsNewGenID();
236        clone->fWidth = fWidth;
237        clone->fHeight = fHeight;
238        SkSafeSetNull(clone->fRecord);
239        SkDELETE(clone->fPlayback);
240        clone->fContentInfo.set(fContentInfo);
241
242        /*  We want to copy the src's playback. However, if that hasn't been built
243            yet, we need to fake a call to endRecording() without actually calling
244            it (since it is destructive, and we don't want to change src).
245         */
246        if (fPlayback) {
247            if (!copyInfo.initialized) {
248                int paintCount = SafeCount(fPlayback->fPaints);
249
250                /* The alternative to doing this is to have a clone method on the paint and have it
251                 * make the deep copy of its internal structures as needed. The holdup to doing
252                 * that is at this point we would need to pass the SkBitmapHeap so that we don't
253                 * unnecessarily flatten the pixels in a bitmap shader.
254                 */
255                copyInfo.paintData.setCount(paintCount);
256
257                /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is
258                 * one, use it. If this SkPicturePlayback was created from a stream, fBitmapHeap
259                 * will be NULL, so create a new one.
260                 */
261                if (fPlayback->fBitmapHeap.get() == NULL) {
262                    // FIXME: Put this on the stack inside SkPicture::clone.
263                    SkBitmapHeap* heap = SkNEW(SkBitmapHeap);
264                    copyInfo.controller.setBitmapStorage(heap);
265                    heap->unref();
266                } else {
267                    copyInfo.controller.setBitmapStorage(fPlayback->fBitmapHeap);
268                }
269
270                SkDEBUGCODE(int heapSize = SafeCount(fPlayback->fBitmapHeap.get());)
271                for (int i = 0; i < paintCount; i++) {
272                    if (NeedsDeepCopy(fPlayback->fPaints->at(i))) {
273                        copyInfo.paintData[i] =
274                            SkFlatData::Create<SkPaint::FlatteningTraits>(&copyInfo.controller,
275                                                              fPlayback->fPaints->at(i), 0);
276
277                    } else {
278                        // this is our sentinel, which we use in the unflatten loop
279                        copyInfo.paintData[i] = NULL;
280                    }
281                }
282                SkASSERT(SafeCount(fPlayback->fBitmapHeap.get()) == heapSize);
283
284                // needed to create typeface playback
285                copyInfo.controller.setupPlaybacks();
286                copyInfo.initialized = true;
287            }
288
289            clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (clone, *fPlayback, &copyInfo));
290            SkASSERT(NULL == fRecord);
291            clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0
292        } else if (fRecord) {
293            clone->fPlayback = FakeEndRecording(clone, *fRecord, true);
294        } else {
295            clone->fPlayback = NULL;
296        }
297
298        clone->fPathHeap.reset(SkSafeRef(fPathHeap.get()));
299    }
300}
301
302SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
303    static int32_t gNextID = 0;
304
305    int32_t id = sk_atomic_inc(&gNextID);
306    if (id >= 1 << (8 * sizeof(Domain))) {
307        SK_CRASH();
308    }
309
310    return static_cast<Domain>(id);
311}
312
313///////////////////////////////////////////////////////////////////////////////
314
315SkCanvas* SkPicture::beginRecording(int width, int height,
316                                    SkBBHFactory* bbhFactory,
317                                    uint32_t recordingFlags) {
318    if (fPlayback) {
319        SkDELETE(fPlayback);
320        fPlayback = NULL;
321    }
322    SkSafeUnref(fAccelData);
323    SkSafeSetNull(fRecord);
324    SkASSERT(NULL == fPathHeap);
325    fContentInfo.reset();
326
327    this->needsNewGenID();
328
329    fWidth = width;
330    fHeight = height;
331
332    const SkISize size = SkISize::Make(width, height);
333
334    if (NULL != bbhFactory) {
335        SkAutoTUnref<SkBBoxHierarchy> tree((*bbhFactory)(width, height));
336        SkASSERT(NULL != tree);
337        fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (this, size, recordingFlags, tree.get()));
338    } else {
339        fRecord = SkNEW_ARGS(SkPictureRecord, (this, size, recordingFlags));
340    }
341    fRecord->beginRecording();
342
343    return fRecord;
344}
345
346SkCanvas* SkPicture::getRecordingCanvas() const {
347    // will be null if we are not recording
348    return fRecord;
349}
350
351void SkPicture::endRecording() {
352    if (NULL == fPlayback) {
353        if (NULL != fRecord) {
354            fRecord->endRecording();
355            SkPictInfo info;
356            this->createHeader(&info);
357            fPlayback = SkNEW_ARGS(SkPicturePlayback, (this, *fRecord, info));
358            SkSafeSetNull(fRecord);
359        }
360    }
361    SkASSERT(NULL == fRecord);
362}
363
364const SkPicture::OperationList& SkPicture::OperationList::InvalidList() {
365    static OperationList gInvalid;
366    return gInvalid;
367}
368
369const SkPicture::OperationList& SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const {
370    SkASSERT(NULL != fPlayback && NULL == fRecord);
371    if (NULL != fPlayback) {
372        return fPlayback->getActiveOps(queryRect);
373    }
374    return OperationList::InvalidList();
375}
376
377size_t SkPicture::EXPERIMENTAL_curOpID() const {
378    if (NULL != fPlayback) {
379        return fPlayback->curOpID();
380    }
381    return 0;
382}
383
384void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) const {
385    SkASSERT(NULL != fPlayback && NULL == fRecord);
386    if (NULL != fPlayback) {
387        fPlayback->draw(*surface, callback);
388    }
389}
390
391///////////////////////////////////////////////////////////////////////////////
392
393#include "SkStream.h"
394
395static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
396
397bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
398    if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
399        return false;
400    }
401
402    if (info.fVersion < MIN_PICTURE_VERSION ||
403        info.fVersion > CURRENT_PICTURE_VERSION) {
404        return false;
405    }
406
407    return true;
408}
409
410bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
411    if (NULL == stream) {
412        return false;
413    }
414
415    // Check magic bytes.
416    SkPictInfo info;
417    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
418    if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) {
419        return false;
420    }
421
422    if (pInfo != NULL) {
423        *pInfo = info;
424    }
425    return true;
426}
427
428bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) {
429    // Check magic bytes.
430    SkPictInfo info;
431    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
432    if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) {
433        return false;
434    }
435
436    if (pInfo != NULL) {
437        *pInfo = info;
438    }
439    return true;
440}
441
442SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height)
443    : fPlayback(playback)
444    , fRecord(NULL)
445    , fWidth(width)
446    , fHeight(height)
447    , fAccelData(NULL) {
448    this->needsNewGenID();
449}
450
451SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
452    SkPictInfo info;
453
454    if (!InternalOnly_StreamIsSKP(stream, &info)) {
455        return NULL;
456    }
457
458    SkPicture* newPict = SkNEW_ARGS(SkPicture, (NULL, info.fWidth, info.fHeight));
459
460    // Check to see if there is a playback to recreate.
461    if (stream->readBool()) {
462        SkPicturePlayback* playback = SkPicturePlayback::CreateFromStream(newPict, stream,
463                                                                          info, proc);
464        if (NULL == playback) {
465            SkDELETE(newPict);
466            return NULL;
467        }
468        newPict->fPlayback = playback;
469    }
470
471    return newPict;
472}
473
474SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
475    SkPictInfo info;
476
477    if (!InternalOnly_BufferIsSKP(buffer, &info)) {
478        return NULL;
479    }
480
481    SkPicture* newPict = SkNEW_ARGS(SkPicture, (NULL, info.fWidth, info.fHeight));
482
483    // Check to see if there is a playback to recreate.
484    if (buffer.readBool()) {
485        SkPicturePlayback* playback = SkPicturePlayback::CreateFromBuffer(newPict, buffer, info);
486        if (NULL == playback) {
487            SkDELETE(newPict);
488            return NULL;
489        }
490        newPict->fPlayback = playback;
491    }
492
493    return newPict;
494}
495
496void SkPicture::createHeader(SkPictInfo* info) const {
497    // Copy magic bytes at the beginning of the header
498    SkASSERT(sizeof(kMagic) == 8);
499    SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
500    memcpy(info->fMagic, kMagic, sizeof(kMagic));
501
502    // Set picture info after magic bytes in the header
503    info->fVersion = CURRENT_PICTURE_VERSION;
504    info->fWidth = fWidth;
505    info->fHeight = fHeight;
506    info->fFlags = SkPictInfo::kCrossProcess_Flag;
507    // TODO: remove this flag, since we're always float (now)
508    info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
509
510    if (8 == sizeof(void*)) {
511        info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
512    }
513}
514
515void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
516    SkPicturePlayback* playback = fPlayback;
517
518    if (NULL == playback && fRecord) {
519        playback = FakeEndRecording(this, *fRecord, false);
520    }
521
522    SkPictInfo info;
523    this->createHeader(&info);
524    stream->write(&info, sizeof(info));
525    if (playback) {
526        stream->writeBool(true);
527        playback->serialize(stream, encoder);
528        // delete playback if it is a local version (i.e. cons'd up just now)
529        if (playback != fPlayback) {
530            SkDELETE(playback);
531        }
532    } else {
533        stream->writeBool(false);
534    }
535}
536
537void SkPicture::WriteTagSize(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
538    buffer.writeUInt(tag);
539    buffer.writeUInt(SkToU32(size));
540}
541
542void SkPicture::WriteTagSize(SkWStream* stream, uint32_t tag,  size_t size) {
543    stream->write32(tag);
544    stream->write32(SkToU32(size));
545}
546
547bool SkPicture::parseBufferTag(SkReadBuffer& buffer,
548                               uint32_t tag,
549                               uint32_t size) {
550    switch (tag) {
551        case SK_PICT_PATH_BUFFER_TAG:
552            if (size > 0) {
553                fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer)));
554            }
555            break;
556        default:
557            // The tag was invalid.
558            return false;
559    }
560
561    return true;    // success
562}
563
564void SkPicture::flattenToBuffer(SkWriteBuffer& buffer) const {
565    int n;
566
567    if ((n = SafeCount(fPathHeap.get())) > 0) {
568        WriteTagSize(buffer, SK_PICT_PATH_BUFFER_TAG, n);
569        fPathHeap->flatten(buffer);
570    }
571}
572
573void SkPicture::flatten(SkWriteBuffer& buffer) const {
574    SkPicturePlayback* playback = fPlayback;
575
576    if (NULL == playback && fRecord) {
577        playback = FakeEndRecording(this, *fRecord, false);
578    }
579
580    SkPictInfo info;
581    this->createHeader(&info);
582    buffer.writeByteArray(&info, sizeof(info));
583    if (playback) {
584        buffer.writeBool(true);
585        playback->flatten(buffer);
586        // delete playback if it is a local version (i.e. cons'd up just now)
587        if (playback != fPlayback) {
588            SkDELETE(playback);
589        }
590    } else {
591        buffer.writeBool(false);
592    }
593}
594
595#if SK_SUPPORT_GPU
596bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const {
597    // TODO: the heuristic used here needs to be refined
598    static const int kNumPaintWithPathEffectUsesTol = 1;
599    static const int kNumAAConcavePaths = 5;
600
601    SkASSERT(this->numAAHairlineConcavePaths() <= this->numAAConcavePaths());
602
603    bool ret = this->numPaintWithPathEffectUses() < kNumPaintWithPathEffectUsesTol &&
604               (this->numAAConcavePaths()-this->numAAHairlineConcavePaths()) < kNumAAConcavePaths;
605    if (!ret && reason) {
606        if (this->numPaintWithPathEffectUses() >= kNumPaintWithPathEffectUsesTol)
607            *reason = "Too many path effects.";
608        else if ((this->numAAConcavePaths()-this->numAAHairlineConcavePaths()) >= kNumAAConcavePaths)
609            *reason = "Too many anti-aliased concave paths.";
610        else
611            *reason = "Unknown reason for GPU unsuitability.";
612    }
613    return ret;
614}
615#endif
616
617bool SkPicture::willPlayBackBitmaps() const {
618    if (!fPlayback) {
619        return false;
620    }
621    return fPlayback->containsBitmaps();
622}
623
624#ifdef SK_BUILD_FOR_ANDROID
625void SkPicture::abortPlayback() {
626    if (NULL == fPlayback) {
627        return;
628    }
629    fPlayback->abort();
630}
631#endif
632
633static int32_t next_picture_generation_id() {
634    static int32_t  gPictureGenerationID = 0;
635    // do a loop in case our global wraps around, as we never want to
636    // return a 0
637    int32_t genID;
638    do {
639        genID = sk_atomic_inc(&gPictureGenerationID) + 1;
640    } while (SK_InvalidGenID == genID);
641    return genID;
642}
643
644uint32_t SkPicture::uniqueID() const {
645    if (NULL != fRecord) {
646        SkASSERT(NULL == fPlayback);
647        return SK_InvalidGenID;
648    }
649
650    if (SK_InvalidGenID == fUniqueID) {
651        fUniqueID = next_picture_generation_id();
652    }
653    return fUniqueID;
654}
655