blob: 0b7a1dbcc592702ec3cf9185f3bfcded0b32bf79 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * 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
scroggo@google.com2983ddd2013-05-07 14:45:40 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkPictureFlat.h"
robertphillipsdb539902014-07-01 08:47:04 -070011#include "SkPictureData.h"
robertphillipsce4dd3d2014-07-07 13:46:35 -070012#include "SkPicturePlayback.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkPictureRecord.h"
mtklein73734562014-06-24 12:28:34 -070014#include "SkPictureRecorder.h"
robertphillips3afef1f2014-07-08 06:12:22 -070015#include "SkPictureStateTree.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
robertphillips@google.com770963f2014-04-18 18:04:41 +000017#include "SkBBHFactory.h"
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000018#include "SkBitmapDevice.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000019#include "SkCanvas.h"
20#include "SkChunkAlloc.h"
Mike Kleinc11530e2014-06-24 11:29:06 -040021#include "SkDrawPictureCallback.h"
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000022#include "SkPaintPriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000023#include "SkPicture.h"
tomhudsond9305112014-07-05 13:37:53 -070024#include "SkRecordAnalysis.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000025#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"
rileya@google.com8515e792012-09-13 21:41:51 +000033#include "SkRTree.h"
34#include "SkBBoxHierarchyRecord.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000035
commit-bot@chromium.orgeb9547c2014-03-19 21:24:25 +000036#if SK_SUPPORT_GPU
37#include "GrContext.h"
38#endif
39
Mike Klein744fb732014-06-23 15:13:26 -040040#include "SkRecord.h"
41#include "SkRecordDraw.h"
Mike Kleinc11530e2014-06-24 11:29:06 -040042#include "SkRecorder.h"
Mike Klein744fb732014-06-23 15:13:26 -040043
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +000044template <typename T> int SafeCount(const T* obj) {
45 return obj ? obj->count() : 0;
46}
47
reed@android.com8a1c16f2008-12-17 15:59:43 +000048#define DUMP_BUFFER_SIZE 65536
49
reed@android.com8a1c16f2008-12-17 15:59:43 +000050#ifdef SK_DEBUG
reed@google.com82065d62011-02-07 15:30:46 +000051// enable SK_DEBUG_TRACE to trace DrawType elements when
reed@android.com8a1c16f2008-12-17 15:59:43 +000052// 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";
robertphillips@google.come4ce5b82013-02-15 17:19:15 +000069 case CLIP_RRECT: return "CLIP_RRECT";
reed@android.com8a1c16f2008-12-17 15:59:43 +000070 case CONCAT: return "CONCAT";
71 case DRAW_BITMAP: return "DRAW_BITMAP";
72 case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
robertphillips@google.come4ce5b82013-02-15 17:19:15 +000073 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";
reed@android.com8a1c16f2008-12-17 15:59:43 +000078 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";
robertphillips@google.come4ce5b82013-02-15 17:19:15 +000083 case DRAW_POS_TEXT_TOP_BOTTOM: return "DRAW_POS_TEXT_TOP_BOTTOM";
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
robertphillips@google.come4ce5b82013-02-15 17:19:15 +000085 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";
reed@android.com8a1c16f2008-12-17 15:59:43 +000088 case DRAW_SPRITE: return "DRAW_SPRITE";
89 case DRAW_TEXT: return "DRAW_TEXT";
90 case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
robertphillips@google.come4ce5b82013-02-15 17:19:15 +000091 case DRAW_TEXT_TOP_BOTTOM: return "DRAW_TEXT_TOP_BOTTOM";
92 case DRAW_VERTICES: return "DRAW_VERTICES";
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 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";
robertphillips@google.come4ce5b82013-02-15 17:19:15 +000098 case SET_MATRIX: return "SET_MATRIX";
reed@android.com8a1c16f2008-12-17 15:59:43 +000099 case SKEW: return "SKEW";
100 case TRANSLATE: return "TRANSLATE";
robertphillips@google.come4ce5b82013-02-15 17:19:15 +0000101 case NOOP: return "NOOP";
reed@google.com82065d62011-02-07 15:30:46 +0000102 default:
103 SkDebugf("DrawType error 0x%08x\n", drawType);
104 SkASSERT(0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105 break;
106 }
reed@google.com82065d62011-02-07 15:30:46 +0000107 SkASSERT(0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108 return NULL;
109}
110#endif
111
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112///////////////////////////////////////////////////////////////////////////////
113
Robert Phillipscfaeec42014-07-13 12:00:50 -0400114#ifdef SK_SUPPORT_LEGACY_DEFAULT_PICTURE_CTOR
Mike Klein744fb732014-06-23 15:13:26 -0400115// fRecord OK
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000116SkPicture::SkPicture()
Mike Klein744fb732014-06-23 15:13:26 -0400117 : fWidth(0)
tomhudsond9305112014-07-05 13:37:53 -0700118 , fHeight(0)
119 , fRecordWillPlayBackBitmaps(false) {
robertphillips@google.comd5500882014-04-02 23:51:13 +0000120 this->needsNewGenID();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121}
Robert Phillipscfaeec42014-07-13 12:00:50 -0400122#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123
Mike Klein744fb732014-06-23 15:13:26 -0400124// fRecord OK
robertphillips0bdbea72014-06-11 11:37:55 -0700125SkPicture::SkPicture(int width, int height,
robertphillipse26e65e2014-06-12 05:51:22 -0700126 const SkPictureRecord& record,
robertphillips0bdbea72014-06-11 11:37:55 -0700127 bool deepCopyOps)
128 : fWidth(width)
tomhudsond9305112014-07-05 13:37:53 -0700129 , fHeight(height)
130 , fRecordWillPlayBackBitmaps(false) {
robertphillips0bdbea72014-06-11 11:37:55 -0700131 this->needsNewGenID();
robertphillips9058d602014-06-10 11:45:46 -0700132
robertphillips0bdbea72014-06-11 11:37:55 -0700133 SkPictInfo info;
134 this->createHeader(&info);
robertphillipsdb539902014-07-01 08:47:04 -0700135 fData.reset(SkNEW_ARGS(SkPictureData, (record, info, deepCopyOps)));
commit-bot@chromium.org2ee3c2c2014-05-19 12:36:15 +0000136}
137
robertphillipsdb539902014-07-01 08:47:04 -0700138// Create an SkPictureData-backed SkPicture from an SkRecord.
mtklein73734562014-06-24 12:28:34 -0700139// 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
Mike Kleinc11530e2014-06-24 11:29:06 -0400146// fRecord OK
robertphillipsd771f6b2014-07-22 10:18:06 -0700147SkPicture::~SkPicture() {
148 this->callDeletionListeners();
149}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150
mtkleind3e474e2014-06-27 12:34:44 -0700151#ifdef SK_SUPPORT_LEGACY_PICTURE_CLONE
Mike Kleinc11530e2014-06-24 11:29:06 -0400152// fRecord TODO, fix by deleting this method
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000153SkPicture* SkPicture::clone() const {
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000154
Robert Phillipscfaeec42014-07-13 12:00:50 -0400155 SkAutoTDelete<SkPictureData> newData;
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000156
Robert Phillipscfaeec42014-07-13 12:00:50 -0400157 if (fData.get()) {
158 SkPictCopyInfo copyInfo;
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000159
Robert Phillipscfaeec42014-07-13 12:00:50 -0400160 int paintCount = SafeCount(fData->fPaints);
scroggo@google.comde1390d2012-11-02 20:51:19 +0000161
Robert Phillipscfaeec42014-07-13 12:00:50 -0400162 /* The alternative to doing this is to have a clone method on the paint and have it
163 * make the deep copy of its internal structures as needed. The holdup to doing
164 * that is at this point we would need to pass the SkBitmapHeap so that we don't
165 * unnecessarily flatten the pixels in a bitmap shader.
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000166 */
Robert Phillipscfaeec42014-07-13 12:00:50 -0400167 copyInfo.paintData.setCount(paintCount);
commit-bot@chromium.org66ec1e42014-04-29 17:22:54 +0000168
Robert Phillipscfaeec42014-07-13 12:00:50 -0400169 /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is
170 * one, use it. If this SkPictureData was created from a stream, fBitmapHeap
171 * will be NULL, so create a new one.
172 */
173 if (fData->fBitmapHeap.get() == NULL) {
174 // FIXME: Put this on the stack inside SkPicture::clone.
175 SkBitmapHeap* heap = SkNEW(SkBitmapHeap);
176 copyInfo.controller.setBitmapStorage(heap);
177 heap->unref();
178 } else {
179 copyInfo.controller.setBitmapStorage(fData->fBitmapHeap);
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000180 }
Robert Phillipscfaeec42014-07-13 12:00:50 -0400181
182 SkDEBUGCODE(int heapSize = SafeCount(fData->fBitmapHeap.get());)
183 for (int i = 0; i < paintCount; i++) {
184 if (NeedsDeepCopy(fData->fPaints->at(i))) {
185 copyInfo.paintData[i] =
186 SkFlatData::Create<SkPaint::FlatteningTraits>(&copyInfo.controller,
187 fData->fPaints->at(i), 0);
188
189 } else {
190 // this is our sentinel, which we use in the unflatten loop
191 copyInfo.paintData[i] = NULL;
192 }
193 }
194 SkASSERT(SafeCount(fData->fBitmapHeap.get()) == heapSize);
195
196 // needed to create typeface playback
197 copyInfo.controller.setupPlaybacks();
198
199 newData.reset(SkNEW_ARGS(SkPictureData, (*fData, &copyInfo)));
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000200 }
Robert Phillipscfaeec42014-07-13 12:00:50 -0400201
202 SkPicture* clone = SkNEW_ARGS(SkPicture, (newData.detach(), fWidth, fHeight));
203 clone->fRecordWillPlayBackBitmaps = fRecordWillPlayBackBitmaps;
204 clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0
205
206 return clone;
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000207}
mtkleind3e474e2014-06-27 12:34:44 -0700208#endif//SK_SUPPORT_LEGACY_PICTURE_CLONE
djsollen@google.comc9ab9872012-08-29 18:52:07 +0000209
Mike Klein744fb732014-06-23 15:13:26 -0400210// fRecord OK
211void SkPicture::EXPERIMENTAL_addAccelData(const SkPicture::AccelData* data) const {
212 fAccelData.reset(SkRef(data));
213}
214
215// fRecord OK
216const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData(
217 SkPicture::AccelData::Key key) const {
218 if (NULL != fAccelData.get() && fAccelData->getKey() == key) {
219 return fAccelData.get();
220 }
221 return NULL;
222}
223
224// fRecord OK
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +0000225SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
226 static int32_t gNextID = 0;
227
228 int32_t id = sk_atomic_inc(&gNextID);
229 if (id >= 1 << (8 * sizeof(Domain))) {
230 SK_CRASH();
231 }
232
233 return static_cast<Domain>(id);
234}
235
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236///////////////////////////////////////////////////////////////////////////////
237
robertphillips3afef1f2014-07-08 06:12:22 -0700238uint32_t SkPicture::OperationList::offset(int index) const {
239 SkASSERT(index < fOps.count());
240 return ((SkPictureStateTree::Draw*)fOps[index])->fOffset;
241}
242
243const SkMatrix& SkPicture::OperationList::matrix(int index) const {
244 SkASSERT(index < fOps.count());
245 return *((SkPictureStateTree::Draw*)fOps[index])->fMatrix;
246}
247
Mike Klein744fb732014-06-23 15:13:26 -0400248// fRecord TODO
robertphillipsce4dd3d2014-07-07 13:46:35 -0700249const SkPicture::OperationList* SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const {
robertphillipsdb539902014-07-01 08:47:04 -0700250 SkASSERT(NULL != fData.get());
251 if (NULL != fData.get()) {
252 return fData->getActiveOps(queryRect);
commit-bot@chromium.org70512af2014-03-18 17:45:32 +0000253 }
robertphillipsce4dd3d2014-07-07 13:46:35 -0700254 return NULL;
commit-bot@chromium.org75cf29b2014-03-24 19:40:49 +0000255}
256
Mike Klein744fb732014-06-23 15:13:26 -0400257// fRecord OK
258void SkPicture::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) const {
259 SkASSERT(NULL != canvas);
robertphillipsdb539902014-07-01 08:47:04 -0700260 SkASSERT(NULL != fData.get() || NULL != fRecord.get());
Mike Klein744fb732014-06-23 15:13:26 -0400261
robertphillipsdb539902014-07-01 08:47:04 -0700262 if (NULL != fData.get()) {
robertphillipsce4dd3d2014-07-07 13:46:35 -0700263 SkPicturePlayback playback(this);
264 playback.draw(canvas, callback);
Mike Klein744fb732014-06-23 15:13:26 -0400265 }
266 if (NULL != fRecord.get()) {
Mike Kleinc11530e2014-06-24 11:29:06 -0400267 SkRecordDraw(*fRecord, canvas, callback);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 }
269}
270
271///////////////////////////////////////////////////////////////////////////////
272
273#include "SkStream.h"
274
rmistry@google.comd6bab022013-12-02 13:50:38 +0000275static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000276
Mike Klein744fb732014-06-23 15:13:26 -0400277// fRecord OK
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000278bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
279 if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
280 return false;
281 }
282
283 if (info.fVersion < MIN_PICTURE_VERSION ||
284 info.fVersion > CURRENT_PICTURE_VERSION) {
285 return false;
286 }
287
288 return true;
289}
rmistry@google.comd6bab022013-12-02 13:50:38 +0000290
Mike Klein744fb732014-06-23 15:13:26 -0400291// fRecord OK
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000292bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
scroggo@google.comf1754ec2013-06-28 21:32:00 +0000293 if (NULL == stream) {
294 return false;
borenet@google.com66bcbd12012-09-17 18:26:06 +0000295 }
reed@google.com67562092012-06-22 15:38:39 +0000296
rmistry@google.comd6bab022013-12-02 13:50:38 +0000297 // Check magic bytes.
reed@google.com67562092012-06-22 15:38:39 +0000298 SkPictInfo info;
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000299 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
300 if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) {
scroggo@google.comf1754ec2013-06-28 21:32:00 +0000301 return false;
reed@google.com67562092012-06-22 15:38:39 +0000302 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303
scroggo@google.comf1754ec2013-06-28 21:32:00 +0000304 if (pInfo != NULL) {
305 *pInfo = info;
306 }
307 return true;
308}
309
Mike Klein744fb732014-06-23 15:13:26 -0400310// fRecord OK
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000311bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000312 // Check magic bytes.
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000313 SkPictInfo info;
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000314 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
315 if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000316 return false;
317 }
318
319 if (pInfo != NULL) {
320 *pInfo = info;
321 }
322 return true;
323}
324
Mike Klein744fb732014-06-23 15:13:26 -0400325// fRecord OK
robertphillipsdb539902014-07-01 08:47:04 -0700326SkPicture::SkPicture(SkPictureData* data, int width, int height)
327 : fData(data)
scroggo@google.comf1754ec2013-06-28 21:32:00 +0000328 , fWidth(width)
tomhudsond9305112014-07-05 13:37:53 -0700329 , fHeight(height)
330 , fRecordWillPlayBackBitmaps(false) {
robertphillips@google.comd5500882014-04-02 23:51:13 +0000331 this->needsNewGenID();
332}
scroggo@google.comf1754ec2013-06-28 21:32:00 +0000333
Mike Klein744fb732014-06-23 15:13:26 -0400334// fRecord OK
scroggo@google.comf1754ec2013-06-28 21:32:00 +0000335SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
336 SkPictInfo info;
337
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000338 if (!InternalOnly_StreamIsSKP(stream, &info)) {
scroggo@google.comf1754ec2013-06-28 21:32:00 +0000339 return NULL;
340 }
341
scroggo@google.comf1754ec2013-06-28 21:32:00 +0000342 // Check to see if there is a playback to recreate.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 if (stream->readBool()) {
robertphillipsdb539902014-07-01 08:47:04 -0700344 SkPictureData* data = SkPictureData::CreateFromStream(stream, info, proc);
345 if (NULL == data) {
scroggo@google.com12705322013-10-01 15:30:46 +0000346 return NULL;
347 }
robertphillipse26e65e2014-06-12 05:51:22 -0700348
robertphillipsdb539902014-07-01 08:47:04 -0700349 return SkNEW_ARGS(SkPicture, (data, info.fWidth, info.fHeight));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 }
reed@google.com67562092012-06-22 15:38:39 +0000351
robertphillipse26e65e2014-06-12 05:51:22 -0700352 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353}
354
Mike Klein744fb732014-06-23 15:13:26 -0400355// fRecord OK
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000356SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
357 SkPictInfo info;
358
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000359 if (!InternalOnly_BufferIsSKP(buffer, &info)) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000360 return NULL;
361 }
362
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000363 // Check to see if there is a playback to recreate.
364 if (buffer.readBool()) {
robertphillipsdb539902014-07-01 08:47:04 -0700365 SkPictureData* data = SkPictureData::CreateFromBuffer(buffer, info);
366 if (NULL == data) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000367 return NULL;
368 }
robertphillipse26e65e2014-06-12 05:51:22 -0700369
robertphillipsdb539902014-07-01 08:47:04 -0700370 return SkNEW_ARGS(SkPicture, (data, info.fWidth, info.fHeight));
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000371 }
372
robertphillipse26e65e2014-06-12 05:51:22 -0700373 return NULL;
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000374}
375
Mike Klein744fb732014-06-23 15:13:26 -0400376// fRecord OK
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000377void SkPicture::createHeader(SkPictInfo* info) const {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000378 // Copy magic bytes at the beginning of the header
379 SkASSERT(sizeof(kMagic) == 8);
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000380 SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
381 memcpy(info->fMagic, kMagic, sizeof(kMagic));
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000382
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000383 // Set picture info after magic bytes in the header
commit-bot@chromium.orge8d96142014-02-25 02:16:10 +0000384 info->fVersion = CURRENT_PICTURE_VERSION;
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000385 info->fWidth = fWidth;
386 info->fHeight = fHeight;
387 info->fFlags = SkPictInfo::kCrossProcess_Flag;
388 // TODO: remove this flag, since we're always float (now)
389 info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
390
391 if (8 == sizeof(void*)) {
392 info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
393 }
394}
395
mtklein73734562014-06-24 12:28:34 -0700396// fRecord OK
scroggo@google.com32ef1312013-02-22 22:04:19 +0000397void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
robertphillipsdb539902014-07-01 08:47:04 -0700398 const SkPictureData* data = fData.get();
mtklein73734562014-06-24 12:28:34 -0700399
400 // If we're a new-format picture, backport to old format for serialization.
401 SkAutoTDelete<SkPicture> oldFormat;
robertphillipsdb539902014-07-01 08:47:04 -0700402 if (NULL == data && NULL != fRecord.get()) {
mtklein73734562014-06-24 12:28:34 -0700403 oldFormat.reset(backport(*fRecord, fWidth, fHeight));
robertphillipsdb539902014-07-01 08:47:04 -0700404 data = oldFormat->fData.get();
405 SkASSERT(NULL != data);
mtklein73734562014-06-24 12:28:34 -0700406 }
407
commit-bot@chromium.org2ee3c2c2014-05-19 12:36:15 +0000408 SkPictInfo info;
409 this->createHeader(&info);
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000410 stream->write(&info, sizeof(info));
mtklein40684ba2014-06-24 10:12:39 -0700411
robertphillipsdb539902014-07-01 08:47:04 -0700412 if (NULL != data) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000413 stream->writeBool(true);
robertphillipsdb539902014-07-01 08:47:04 -0700414 data->serialize(stream, encoder);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415 } else {
416 stream->writeBool(false);
417 }
418}
419
Mike Klein744fb732014-06-23 15:13:26 -0400420// fRecord OK
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000421void SkPicture::flatten(SkWriteBuffer& buffer) const {
robertphillipsdb539902014-07-01 08:47:04 -0700422 const SkPictureData* data = fData.get();
mtklein73734562014-06-24 12:28:34 -0700423
424 // If we're a new-format picture, backport to old format for serialization.
425 SkAutoTDelete<SkPicture> oldFormat;
robertphillipsdb539902014-07-01 08:47:04 -0700426 if (NULL == data && NULL != fRecord.get()) {
mtklein73734562014-06-24 12:28:34 -0700427 oldFormat.reset(backport(*fRecord, fWidth, fHeight));
robertphillipsdb539902014-07-01 08:47:04 -0700428 data = oldFormat->fData.get();
429 SkASSERT(NULL != data);
mtklein73734562014-06-24 12:28:34 -0700430 }
431
commit-bot@chromium.org2ee3c2c2014-05-19 12:36:15 +0000432 SkPictInfo info;
433 this->createHeader(&info);
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000434 buffer.writeByteArray(&info, sizeof(info));
mtklein40684ba2014-06-24 10:12:39 -0700435
robertphillipsdb539902014-07-01 08:47:04 -0700436 if (NULL != data) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000437 buffer.writeBool(true);
robertphillipsdb539902014-07-01 08:47:04 -0700438 data->flatten(buffer);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000439 } else {
440 buffer.writeBool(false);
441 }
442}
443
commit-bot@chromium.org1c308182014-03-19 22:54:40 +0000444#if SK_SUPPORT_GPU
Mike Klein744fb732014-06-23 15:13:26 -0400445// fRecord TODO
commit-bot@chromium.orga1ff26a2014-05-30 21:52:52 +0000446bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const {
robertphillipsdb539902014-07-01 08:47:04 -0700447 if (NULL == fData.get()) {
robertphillips0bdbea72014-06-11 11:37:55 -0700448 if (NULL != reason) {
robertphillipsdb539902014-07-01 08:47:04 -0700449 *reason = "Missing internal data.";
robertphillips0bdbea72014-06-11 11:37:55 -0700450 }
451 return false;
commit-bot@chromium.orga1ff26a2014-05-30 21:52:52 +0000452 }
robertphillips0bdbea72014-06-11 11:37:55 -0700453
robertphillipsdb539902014-07-01 08:47:04 -0700454 return fData->suitableForGpuRasterization(context, reason);
commit-bot@chromium.orgeb9547c2014-03-19 21:24:25 +0000455}
commit-bot@chromium.org1c308182014-03-19 22:54:40 +0000456#endif
commit-bot@chromium.orgeb9547c2014-03-19 21:24:25 +0000457
tomhudsond9305112014-07-05 13:37:53 -0700458// fRecord OK
tomhudson@google.com381010e2013-10-24 11:12:47 +0000459bool SkPicture::willPlayBackBitmaps() const {
tomhudsond9305112014-07-05 13:37:53 -0700460 if (fRecord.get()) {
461 return fRecordWillPlayBackBitmaps;
462 }
robertphillipsdb539902014-07-01 08:47:04 -0700463 if (!fData.get()) {
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +0000464 return false;
465 }
robertphillipsdb539902014-07-01 08:47:04 -0700466 return fData->containsBitmaps();
tomhudson@google.com381010e2013-10-24 11:12:47 +0000467}
468
Mike Klein744fb732014-06-23 15:13:26 -0400469// fRecord OK
robertphillips@google.comd5500882014-04-02 23:51:13 +0000470static int32_t next_picture_generation_id() {
471 static int32_t gPictureGenerationID = 0;
472 // do a loop in case our global wraps around, as we never want to
473 // return a 0
474 int32_t genID;
475 do {
476 genID = sk_atomic_inc(&gPictureGenerationID) + 1;
commit-bot@chromium.org2b4e3702014-04-07 18:26:22 +0000477 } while (SK_InvalidGenID == genID);
robertphillips@google.comd5500882014-04-02 23:51:13 +0000478 return genID;
479}
480
Mike Klein744fb732014-06-23 15:13:26 -0400481// fRecord OK
commit-bot@chromium.org2b4e3702014-04-07 18:26:22 +0000482uint32_t SkPicture::uniqueID() const {
commit-bot@chromium.org2b4e3702014-04-07 18:26:22 +0000483 if (SK_InvalidGenID == fUniqueID) {
484 fUniqueID = next_picture_generation_id();
robertphillips@google.comd5500882014-04-02 23:51:13 +0000485 }
commit-bot@chromium.org2b4e3702014-04-07 18:26:22 +0000486 return fUniqueID;
robertphillips@google.comd5500882014-04-02 23:51:13 +0000487}
Mike Klein744fb732014-06-23 15:13:26 -0400488
489// fRecord OK
490SkPicture::SkPicture(int width, int height, SkRecord* record)
491 : fWidth(width)
492 , fHeight(height)
tomhudsond9305112014-07-05 13:37:53 -0700493 , fRecord(record)
494 , fRecordWillPlayBackBitmaps(SkRecordWillPlaybackBitmaps(*record)) {
Mike Klein744fb732014-06-23 15:13:26 -0400495 this->needsNewGenID();
496}
robertphillipsd771f6b2014-07-22 10:18:06 -0700497
498// Note that we are assuming that this entry point will only be called from
499// one thread. Currently the only client of this method is
500// SkGpuDevice::EXPERIMENTAL_optimize which should be only called from a single
501// thread.
502void SkPicture::addDeletionListener(DeletionListener* listener) const {
503 SkASSERT(NULL != listener);
504
505 *fDeletionListeners.append() = SkRef(listener);
506}
507
508void SkPicture::callDeletionListeners() {
509 for (int i = 0; i < fDeletionListeners.count(); ++i) {
510 fDeletionListeners[i]->onDeletion(this->uniqueID());
511 }
512
513 fDeletionListeners.unrefAll();
514}