3 * Copyright 2007 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "SkPictureFlat.h"
11 #include "SkPictureData.h"
12 #include "SkPicturePlayback.h"
13 #include "SkPictureRecord.h"
14 #include "SkPictureRecorder.h"
15 #include "SkPictureStateTree.h"
17 #include "SkBitmapDevice.h"
19 #include "SkChunkAlloc.h"
20 #include "SkDrawPictureCallback.h"
21 #include "SkPaintPriv.h"
22 #include "SkPicture.h"
23 #include "SkRecordAnalysis.h"
26 #include "SkTDArray.h"
27 #include "SkTSearch.h"
30 #include "SkReader32.h"
31 #include "SkWriter32.h"
33 #include "SkBBoxHierarchyRecord.h"
36 #include "GrContext.h"
40 #include "SkRecordDraw.h"
41 #include "SkRecorder.h"
43 template <typename T> int SafeCount(const T* obj) {
44 return obj ? obj->count() : 0;
47 ///////////////////////////////////////////////////////////////////////////////
49 #ifdef SK_SUPPORT_LEGACY_DEFAULT_PICTURE_CTOR
51 SkPicture::SkPicture()
54 , fRecordWillPlayBackBitmaps(false) {
55 this->needsNewGenID();
60 SkPicture::SkPicture(int width, int height,
61 const SkPictureRecord& record,
65 , fRecordWillPlayBackBitmaps(false) {
66 this->needsNewGenID();
69 this->createHeader(&info);
70 fData.reset(SkNEW_ARGS(SkPictureData, (record, info, deepCopyOps)));
73 // Create an SkPictureData-backed SkPicture from an SkRecord.
74 // This for compatibility with serialization code only. This is not cheap.
75 static SkPicture* backport(const SkRecord& src, int width, int height) {
76 SkPictureRecorder recorder;
77 SkRecordDraw(src, recorder.beginRecording(width, height), NULL/*bbh*/, NULL/*callback*/);
78 return recorder.endRecording();
82 SkPicture::~SkPicture() {
83 this->callDeletionListeners();
86 #ifdef SK_SUPPORT_LEGACY_PICTURE_CLONE
87 // fRecord TODO, fix by deleting this method
88 SkPicture* SkPicture::clone() const {
89 #ifdef SK_PICTURE_CLONE_NOOP
90 return SkRef(const_cast<SkPicture*>(this));
92 SkAutoTDelete<SkPictureData> newData;
95 SkPictCopyInfo copyInfo;
97 int paintCount = SafeCount(fData->fPaints);
99 /* The alternative to doing this is to have a clone method on the paint and have it
100 * make the deep copy of its internal structures as needed. The holdup to doing
101 * that is at this point we would need to pass the SkBitmapHeap so that we don't
102 * unnecessarily flatten the pixels in a bitmap shader.
104 copyInfo.paintData.setCount(paintCount);
106 /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is
107 * one, use it. If this SkPictureData was created from a stream, fBitmapHeap
108 * will be NULL, so create a new one.
110 if (fData->fBitmapHeap.get() == NULL) {
111 // FIXME: Put this on the stack inside SkPicture::clone.
112 SkBitmapHeap* heap = SkNEW(SkBitmapHeap);
113 copyInfo.controller.setBitmapStorage(heap);
116 copyInfo.controller.setBitmapStorage(fData->fBitmapHeap);
119 SkDEBUGCODE(int heapSize = SafeCount(fData->fBitmapHeap.get());)
120 for (int i = 0; i < paintCount; i++) {
121 if (NeedsDeepCopy(fData->fPaints->at(i))) {
122 copyInfo.paintData[i] =
123 SkFlatData::Create<SkPaint::FlatteningTraits>(©Info.controller,
124 fData->fPaints->at(i), 0);
127 // this is our sentinel, which we use in the unflatten loop
128 copyInfo.paintData[i] = NULL;
131 SkASSERT(SafeCount(fData->fBitmapHeap.get()) == heapSize);
133 // needed to create typeface playback
134 copyInfo.controller.setupPlaybacks();
136 newData.reset(SkNEW_ARGS(SkPictureData, (*fData, ©Info)));
139 SkPicture* clone = SkNEW_ARGS(SkPicture, (newData.detach(), fWidth, fHeight));
140 clone->fRecordWillPlayBackBitmaps = fRecordWillPlayBackBitmaps;
141 clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0
146 #endif//SK_SUPPORT_LEGACY_PICTURE_CLONE
149 void SkPicture::EXPERIMENTAL_addAccelData(const SkPicture::AccelData* data) const {
150 fAccelData.reset(SkRef(data));
154 const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData(
155 SkPicture::AccelData::Key key) const {
156 if (NULL != fAccelData.get() && fAccelData->getKey() == key) {
157 return fAccelData.get();
163 SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
164 static int32_t gNextID = 0;
166 int32_t id = sk_atomic_inc(&gNextID);
167 if (id >= 1 << (8 * sizeof(Domain))) {
171 return static_cast<Domain>(id);
174 ///////////////////////////////////////////////////////////////////////////////
176 uint32_t SkPicture::OperationList::offset(int index) const {
177 SkASSERT(index < fOps.count());
178 return ((SkPictureStateTree::Draw*)fOps[index])->fOffset;
181 const SkMatrix& SkPicture::OperationList::matrix(int index) const {
182 SkASSERT(index < fOps.count());
183 return *((SkPictureStateTree::Draw*)fOps[index])->fMatrix;
187 const SkPicture::OperationList* SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const {
188 SkASSERT(NULL != fData.get());
189 if (NULL != fData.get()) {
190 return fData->getActiveOps(queryRect);
196 void SkPicture::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) const {
197 SkASSERT(NULL != canvas);
198 SkASSERT(NULL != fData.get() || NULL != fRecord.get());
200 if (NULL != fData.get()) {
201 SkPicturePlayback playback(this);
202 playback.draw(canvas, callback);
204 if (NULL != fRecord.get()) {
205 SkRecordDraw(*fRecord, canvas, fBBH.get(), callback);
209 ///////////////////////////////////////////////////////////////////////////////
211 #include "SkStream.h"
213 static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
216 bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
217 if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
221 if (info.fVersion < MIN_PICTURE_VERSION ||
222 info.fVersion > CURRENT_PICTURE_VERSION) {
230 bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
231 if (NULL == stream) {
235 // Check magic bytes.
237 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
238 if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) {
249 bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) {
250 // Check magic bytes.
252 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
253 if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) {
264 SkPicture::SkPicture(SkPictureData* data, int width, int height)
268 , fRecordWillPlayBackBitmaps(false) {
269 this->needsNewGenID();
273 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
276 if (!InternalOnly_StreamIsSKP(stream, &info)) {
280 // Check to see if there is a playback to recreate.
281 if (stream->readBool()) {
282 SkPictureData* data = SkPictureData::CreateFromStream(stream, info, proc);
287 return SkNEW_ARGS(SkPicture, (data, info.fWidth, info.fHeight));
294 SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
297 if (!InternalOnly_BufferIsSKP(buffer, &info)) {
301 // Check to see if there is a playback to recreate.
302 if (buffer.readBool()) {
303 SkPictureData* data = SkPictureData::CreateFromBuffer(buffer, info);
308 return SkNEW_ARGS(SkPicture, (data, info.fWidth, info.fHeight));
315 void SkPicture::createHeader(SkPictInfo* info) const {
316 // Copy magic bytes at the beginning of the header
317 SkASSERT(sizeof(kMagic) == 8);
318 SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
319 memcpy(info->fMagic, kMagic, sizeof(kMagic));
321 // Set picture info after magic bytes in the header
322 info->fVersion = CURRENT_PICTURE_VERSION;
323 info->fWidth = fWidth;
324 info->fHeight = fHeight;
325 info->fFlags = SkPictInfo::kCrossProcess_Flag;
326 // TODO: remove this flag, since we're always float (now)
327 info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
329 if (8 == sizeof(void*)) {
330 info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
335 void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
336 const SkPictureData* data = fData.get();
338 // If we're a new-format picture, backport to old format for serialization.
339 SkAutoTDelete<SkPicture> oldFormat;
340 if (NULL == data && NULL != fRecord.get()) {
341 oldFormat.reset(backport(*fRecord, fWidth, fHeight));
342 data = oldFormat->fData.get();
343 SkASSERT(NULL != data);
347 this->createHeader(&info);
348 stream->write(&info, sizeof(info));
351 stream->writeBool(true);
352 data->serialize(stream, encoder);
354 stream->writeBool(false);
359 void SkPicture::flatten(SkWriteBuffer& buffer) const {
360 const SkPictureData* data = fData.get();
362 // If we're a new-format picture, backport to old format for serialization.
363 SkAutoTDelete<SkPicture> oldFormat;
364 if (NULL == data && NULL != fRecord.get()) {
365 oldFormat.reset(backport(*fRecord, fWidth, fHeight));
366 data = oldFormat->fData.get();
367 SkASSERT(NULL != data);
371 this->createHeader(&info);
372 buffer.writeByteArray(&info, sizeof(info));
375 buffer.writeBool(true);
376 data->flatten(buffer);
378 buffer.writeBool(false);
384 bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const {
385 if (NULL == fData.get()) {
386 if (NULL != reason) {
387 *reason = "Missing internal data.";
392 return fData->suitableForGpuRasterization(context, reason);
397 bool SkPicture::willPlayBackBitmaps() const {
399 return fRecordWillPlayBackBitmaps;
404 return fData->containsBitmaps();
408 static int32_t next_picture_generation_id() {
409 static int32_t gPictureGenerationID = 0;
410 // do a loop in case our global wraps around, as we never want to
414 genID = sk_atomic_inc(&gPictureGenerationID) + 1;
415 } while (SK_InvalidGenID == genID);
420 uint32_t SkPicture::uniqueID() const {
421 if (SK_InvalidGenID == fUniqueID) {
422 fUniqueID = next_picture_generation_id();
428 SkPicture::SkPicture(int width, int height, SkRecord* record, SkBBoxHierarchy* bbh)
432 , fBBH(SkSafeRef(bbh))
433 , fRecordWillPlayBackBitmaps(SkRecordWillPlaybackBitmaps(*record)) {
434 // TODO: delay as much of this work until just before first playback?
436 SkRecordFillBounds(*record, fBBH.get());
438 this->needsNewGenID();
441 // Note that we are assuming that this entry point will only be called from
442 // one thread. Currently the only client of this method is
443 // SkGpuDevice::EXPERIMENTAL_optimize which should be only called from a single
445 void SkPicture::addDeletionListener(DeletionListener* listener) const {
446 SkASSERT(NULL != listener);
448 *fDeletionListeners.append() = SkRef(listener);
451 void SkPicture::callDeletionListeners() {
452 for (int i = 0; i < fDeletionListeners.count(); ++i) {
453 fDeletionListeners[i]->onDeletion(this->uniqueID());
456 fDeletionListeners.unrefAll();
460 int SkPicture::approximateOpCount() const {
461 SkASSERT(fRecord.get() || fData.get());
463 return fRecord->count();
466 return fData->opCount();