[go: nahoru, domu]

blob: 316994a24b8196b5b59ca17a3a37067fd81a608c [file] [log] [blame]
epoger@google.com685cfc02011-07-28 14:26:00 +00001
reed@android.combcd4d5a2008-12-17 15:59:43 +00002/*
epoger@google.com685cfc02011-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.com8b854502013-05-07 14:45:40 +00009
reed@android.combcd4d5a2008-12-17 15:59:43 +000010#include "SkPictureFlat.h"
11#include "SkPicturePlayback.h"
12#include "SkPictureRecord.h"
13
robertphillips@google.com7aefc822014-04-18 18:04:41 +000014#include "SkBBHFactory.h"
robertphillips@google.com2fd23902013-08-29 11:54:56 +000015#include "SkBitmapDevice.h"
reed@android.combcd4d5a2008-12-17 15:59:43 +000016#include "SkCanvas.h"
17#include "SkChunkAlloc.h"
18#include "SkPicture.h"
19#include "SkRegion.h"
20#include "SkStream.h"
21#include "SkTDArray.h"
22#include "SkTSearch.h"
23#include "SkTime.h"
24
25#include "SkReader32.h"
26#include "SkWriter32.h"
rileya@google.com7fb3d2f2012-09-13 21:41:51 +000027#include "SkRTree.h"
28#include "SkBBoxHierarchyRecord.h"
reed@android.combcd4d5a2008-12-17 15:59:43 +000029
commit-bot@chromium.org95cdc162014-03-19 21:24:25 +000030#if SK_SUPPORT_GPU
31#include "GrContext.h"
32#endif
33
reed@android.combcd4d5a2008-12-17 15:59:43 +000034#define DUMP_BUFFER_SIZE 65536
35
36//#define ENABLE_TIME_DRAW // dumps milliseconds for each draw
37
38
39#ifdef SK_DEBUG
reed@google.com91911482011-02-07 15:30:46 +000040// enable SK_DEBUG_TRACE to trace DrawType elements when
reed@android.combcd4d5a2008-12-17 15:59:43 +000041// recorded and played back
42// #define SK_DEBUG_TRACE
43// enable SK_DEBUG_SIZE to see the size of picture components
44// #define SK_DEBUG_SIZE
45// enable SK_DEBUG_DUMP to see the contents of recorded elements
46// #define SK_DEBUG_DUMP
47// enable SK_DEBUG_VALIDATE to check internal structures for consistency
48// #define SK_DEBUG_VALIDATE
49#endif
50
51#if defined SK_DEBUG_TRACE || defined SK_DEBUG_DUMP
52const char* DrawTypeToString(DrawType drawType) {
53 switch (drawType) {
54 case UNUSED: SkDebugf("DrawType UNUSED\n"); SkASSERT(0); break;
55 case CLIP_PATH: return "CLIP_PATH";
56 case CLIP_REGION: return "CLIP_REGION";
57 case CLIP_RECT: return "CLIP_RECT";
robertphillips@google.come7189be2013-02-15 17:19:15 +000058 case CLIP_RRECT: return "CLIP_RRECT";
reed@android.combcd4d5a2008-12-17 15:59:43 +000059 case CONCAT: return "CONCAT";
60 case DRAW_BITMAP: return "DRAW_BITMAP";
61 case DRAW_BITMAP_MATRIX: return "DRAW_BITMAP_MATRIX";
robertphillips@google.come7189be2013-02-15 17:19:15 +000062 case DRAW_BITMAP_NINE: return "DRAW_BITMAP_NINE";
63 case DRAW_BITMAP_RECT_TO_RECT: return "DRAW_BITMAP_RECT_TO_RECT";
64 case DRAW_CLEAR: return "DRAW_CLEAR";
65 case DRAW_DATA: return "DRAW_DATA";
66 case DRAW_OVAL: return "DRAW_OVAL";
reed@android.combcd4d5a2008-12-17 15:59:43 +000067 case DRAW_PAINT: return "DRAW_PAINT";
68 case DRAW_PATH: return "DRAW_PATH";
69 case DRAW_PICTURE: return "DRAW_PICTURE";
70 case DRAW_POINTS: return "DRAW_POINTS";
71 case DRAW_POS_TEXT: return "DRAW_POS_TEXT";
robertphillips@google.come7189be2013-02-15 17:19:15 +000072 case DRAW_POS_TEXT_TOP_BOTTOM: return "DRAW_POS_TEXT_TOP_BOTTOM";
reed@android.combcd4d5a2008-12-17 15:59:43 +000073 case DRAW_POS_TEXT_H: return "DRAW_POS_TEXT_H";
robertphillips@google.come7189be2013-02-15 17:19:15 +000074 case DRAW_POS_TEXT_H_TOP_BOTTOM: return "DRAW_POS_TEXT_H_TOP_BOTTOM";
75 case DRAW_RECT: return "DRAW_RECT";
76 case DRAW_RRECT: return "DRAW_RRECT";
reed@android.combcd4d5a2008-12-17 15:59:43 +000077 case DRAW_SPRITE: return "DRAW_SPRITE";
78 case DRAW_TEXT: return "DRAW_TEXT";
79 case DRAW_TEXT_ON_PATH: return "DRAW_TEXT_ON_PATH";
robertphillips@google.come7189be2013-02-15 17:19:15 +000080 case DRAW_TEXT_TOP_BOTTOM: return "DRAW_TEXT_TOP_BOTTOM";
81 case DRAW_VERTICES: return "DRAW_VERTICES";
reed@android.combcd4d5a2008-12-17 15:59:43 +000082 case RESTORE: return "RESTORE";
83 case ROTATE: return "ROTATE";
84 case SAVE: return "SAVE";
85 case SAVE_LAYER: return "SAVE_LAYER";
86 case SCALE: return "SCALE";
robertphillips@google.come7189be2013-02-15 17:19:15 +000087 case SET_MATRIX: return "SET_MATRIX";
reed@android.combcd4d5a2008-12-17 15:59:43 +000088 case SKEW: return "SKEW";
89 case TRANSLATE: return "TRANSLATE";
robertphillips@google.come7189be2013-02-15 17:19:15 +000090 case NOOP: return "NOOP";
reed@google.com91911482011-02-07 15:30:46 +000091 default:
92 SkDebugf("DrawType error 0x%08x\n", drawType);
93 SkASSERT(0);
reed@android.combcd4d5a2008-12-17 15:59:43 +000094 break;
95 }
reed@google.com91911482011-02-07 15:30:46 +000096 SkASSERT(0);
reed@android.combcd4d5a2008-12-17 15:59:43 +000097 return NULL;
98}
99#endif
100
101#ifdef SK_DEBUG_VALIDATE
102static void validateMatrix(const SkMatrix* matrix) {
103 SkScalar scaleX = matrix->getScaleX();
104 SkScalar scaleY = matrix->getScaleY();
105 SkScalar skewX = matrix->getSkewX();
106 SkScalar skewY = matrix->getSkewY();
107 SkScalar perspX = matrix->getPerspX();
108 SkScalar perspY = matrix->getPerspY();
109 if (scaleX != 0 && skewX != 0)
110 SkDebugf("scaleX != 0 && skewX != 0\n");
111 SkASSERT(scaleX == 0 || skewX == 0);
112 SkASSERT(scaleY == 0 || skewY == 0);
113 SkASSERT(perspX == 0);
114 SkASSERT(perspY == 0);
115}
116#endif
117
118
119///////////////////////////////////////////////////////////////////////////////
120
121SkPicture::SkPicture() {
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000122 this->needsNewGenID();
reed@android.combcd4d5a2008-12-17 15:59:43 +0000123 fRecord = NULL;
124 fPlayback = NULL;
125 fWidth = fHeight = 0;
commit-bot@chromium.org73857a32014-03-16 19:46:36 +0000126 fAccelData = NULL;
reed@android.combcd4d5a2008-12-17 15:59:43 +0000127}
128
skia.committer@gmail.com8b5598b2014-03-17 03:02:17 +0000129SkPicture::SkPicture(const SkPicture& src)
commit-bot@chromium.org73857a32014-03-16 19:46:36 +0000130 : INHERITED()
131 , fAccelData(NULL) {
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000132 this->needsNewGenID();
reed@android.combcd4d5a2008-12-17 15:59:43 +0000133 fWidth = src.fWidth;
134 fHeight = src.fHeight;
135 fRecord = NULL;
136
137 /* We want to copy the src's playback. However, if that hasn't been built
138 yet, we need to fake a call to endRecording() without actually calling
139 it (since it is destructive, and we don't want to change src).
140 */
141 if (src.fPlayback) {
142 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback));
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000143 SkASSERT(NULL == src.fRecord);
commit-bot@chromium.orgb50bcb92014-04-07 18:26:22 +0000144 fUniqueID = src.uniqueID(); // need to call method to ensure != 0
reed@android.combcd4d5a2008-12-17 15:59:43 +0000145 } else if (src.fRecord) {
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000146 SkPictInfo info;
147 this->createHeader(&info);
reed@android.combcd4d5a2008-12-17 15:59:43 +0000148 // here we do a fake src.endRecording()
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000149 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord, info));
reed@android.combcd4d5a2008-12-17 15:59:43 +0000150 } else {
151 fPlayback = NULL;
152 }
153}
154
155SkPicture::~SkPicture() {
reed@google.com91911482011-02-07 15:30:46 +0000156 SkSafeUnref(fRecord);
reed@android.combcd4d5a2008-12-17 15:59:43 +0000157 SkDELETE(fPlayback);
commit-bot@chromium.org73857a32014-03-16 19:46:36 +0000158 SkSafeUnref(fAccelData);
reed@android.combcd4d5a2008-12-17 15:59:43 +0000159}
160
commit-bot@chromium.orge6e785e2014-03-04 19:08:57 +0000161void SkPicture::internalOnly_EnableOpts(bool enableOpts) {
162 if (NULL != fRecord) {
163 fRecord->internalOnly_EnableOpts(enableOpts);
164 }
165}
166
reed@android.combcd4d5a2008-12-17 15:59:43 +0000167void SkPicture::swap(SkPicture& other) {
commit-bot@chromium.orgb50bcb92014-04-07 18:26:22 +0000168 SkTSwap(fUniqueID, other.fUniqueID);
reed@android.combcd4d5a2008-12-17 15:59:43 +0000169 SkTSwap(fRecord, other.fRecord);
170 SkTSwap(fPlayback, other.fPlayback);
commit-bot@chromium.org73857a32014-03-16 19:46:36 +0000171 SkTSwap(fAccelData, other.fAccelData);
reed@android.combcd4d5a2008-12-17 15:59:43 +0000172 SkTSwap(fWidth, other.fWidth);
173 SkTSwap(fHeight, other.fHeight);
174}
175
djsollen@google.com3855f872012-08-29 18:52:07 +0000176SkPicture* SkPicture::clone() const {
177 SkPicture* clonedPicture = SkNEW(SkPicture);
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000178 this->clone(clonedPicture, 1);
djsollen@google.com3855f872012-08-29 18:52:07 +0000179 return clonedPicture;
180}
181
182void SkPicture::clone(SkPicture* pictures, int count) const {
183 SkPictCopyInfo copyInfo;
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000184 SkPictInfo info;
185 this->createHeader(&info);
djsollen@google.com3855f872012-08-29 18:52:07 +0000186
187 for (int i = 0; i < count; i++) {
188 SkPicture* clone = &pictures[i];
189
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000190 clone->needsNewGenID();
djsollen@google.com3855f872012-08-29 18:52:07 +0000191 clone->fWidth = fWidth;
192 clone->fHeight = fHeight;
commit-bot@chromium.orgefea6992014-02-14 17:27:10 +0000193 SkSafeSetNull(clone->fRecord);
scroggo@google.coma0dd4332012-11-02 20:51:19 +0000194 SkDELETE(clone->fPlayback);
195
djsollen@google.com3855f872012-08-29 18:52:07 +0000196 /* We want to copy the src's playback. However, if that hasn't been built
197 yet, we need to fake a call to endRecording() without actually calling
198 it (since it is destructive, and we don't want to change src).
199 */
200 if (fPlayback) {
201 clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, &copyInfo));
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000202 SkASSERT(NULL == fRecord);
commit-bot@chromium.orgb50bcb92014-04-07 18:26:22 +0000203 clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0
djsollen@google.com3855f872012-08-29 18:52:07 +0000204 } else if (fRecord) {
205 // here we do a fake src.endRecording()
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000206 clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, info, true));
djsollen@google.com3855f872012-08-29 18:52:07 +0000207 } else {
208 clone->fPlayback = NULL;
209 }
210 }
211}
212
commit-bot@chromium.org73857a32014-03-16 19:46:36 +0000213SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
214 static int32_t gNextID = 0;
215
216 int32_t id = sk_atomic_inc(&gNextID);
217 if (id >= 1 << (8 * sizeof(Domain))) {
218 SK_CRASH();
219 }
220
221 return static_cast<Domain>(id);
222}
223
reed@android.combcd4d5a2008-12-17 15:59:43 +0000224///////////////////////////////////////////////////////////////////////////////
225
commit-bot@chromium.org48da8612014-04-17 23:35:06 +0000226#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
227
reed@android.comc4a55d72009-02-13 14:56:09 +0000228SkCanvas* SkPicture::beginRecording(int width, int height,
229 uint32_t recordingFlags) {
reed@android.combcd4d5a2008-12-17 15:59:43 +0000230 if (fPlayback) {
231 SkDELETE(fPlayback);
232 fPlayback = NULL;
233 }
commit-bot@chromium.org73857a32014-03-16 19:46:36 +0000234 SkSafeUnref(fAccelData);
commit-bot@chromium.orgefea6992014-02-14 17:27:10 +0000235 SkSafeSetNull(fRecord);
reed@android.combcd4d5a2008-12-17 15:59:43 +0000236
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000237 this->needsNewGenID();
238
junov@chromium.orgbb78c442012-11-01 17:10:32 +0000239 // Must be set before calling createBBoxHierarchy
240 fWidth = width;
241 fHeight = height;
242
commit-bot@chromium.orgca101d62014-02-17 15:28:00 +0000243 const SkISize size = SkISize::Make(width, height);
244
rileya@google.com7fb3d2f2012-09-13 21:41:51 +0000245 if (recordingFlags & kOptimizeForClippedPlayback_RecordingFlag) {
junov@chromium.orgbb78c442012-11-01 17:10:32 +0000246 SkBBoxHierarchy* tree = this->createBBoxHierarchy();
rileya@google.com7fb3d2f2012-09-13 21:41:51 +0000247 SkASSERT(NULL != tree);
commit-bot@chromium.orgca101d62014-02-17 15:28:00 +0000248 fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (size, recordingFlags, tree));
rileya@google.com7fb3d2f2012-09-13 21:41:51 +0000249 tree->unref();
250 } else {
commit-bot@chromium.orgca101d62014-02-17 15:28:00 +0000251 fRecord = SkNEW_ARGS(SkPictureRecord, (size, recordingFlags));
rileya@google.com7fb3d2f2012-09-13 21:41:51 +0000252 }
reed@google.com118a6d02012-09-27 20:31:31 +0000253 fRecord->beginRecording();
reed@android.combcd4d5a2008-12-17 15:59:43 +0000254
reed@android.combcd4d5a2008-12-17 15:59:43 +0000255 return fRecord;
256}
257
commit-bot@chromium.org48da8612014-04-17 23:35:06 +0000258#endif
259
skia.committer@gmail.com0f1b1d62014-04-18 03:03:54 +0000260SkCanvas* SkPicture::beginRecording(int width, int height,
commit-bot@chromium.org48da8612014-04-17 23:35:06 +0000261 SkBBHFactory* bbhFactory,
262 uint32_t recordingFlags) {
263 if (fPlayback) {
264 SkDELETE(fPlayback);
265 fPlayback = NULL;
266 }
267 SkSafeUnref(fAccelData);
268 SkSafeSetNull(fRecord);
269
270 this->needsNewGenID();
271
272 fWidth = width;
273 fHeight = height;
274
275 const SkISize size = SkISize::Make(width, height);
276
277 if (NULL != bbhFactory) {
278 SkAutoTUnref<SkBBoxHierarchy> tree((*bbhFactory)(width, height));
279 SkASSERT(NULL != tree);
skia.committer@gmail.com0f1b1d62014-04-18 03:03:54 +0000280 fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (size,
commit-bot@chromium.org48da8612014-04-17 23:35:06 +0000281 recordingFlags|
282 kOptimizeForClippedPlayback_RecordingFlag,
283 tree.get()));
284 } else {
285 fRecord = SkNEW_ARGS(SkPictureRecord, (size, recordingFlags));
286 }
287 fRecord->beginRecording();
288
289 return fRecord;
290}
291
292
293#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
294
junov@chromium.orgbb78c442012-11-01 17:10:32 +0000295SkBBoxHierarchy* SkPicture::createBBoxHierarchy() const {
commit-bot@chromium.orgfd73c592014-04-16 16:02:10 +0000296 // TODO: this code is now replicated in SkRTreePicture. Once all external
297 // clients have been weaned off of kOptimizeForClippedPlayback_RecordingFlag,
298 // this code can be removed.
299
skia.committer@gmail.com8d230dd2012-11-02 02:01:24 +0000300 // These values were empirically determined to produce reasonable
junov@chromium.orgbb78c442012-11-01 17:10:32 +0000301 // performance in most cases.
302 static const int kRTreeMinChildren = 6;
303 static const int kRTreeMaxChildren = 11;
304
305 SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth),
306 SkIntToScalar(fHeight));
sglez@google.com9baab6f2013-08-30 17:27:47 +0000307 bool sortDraws = false; // Do not sort draw calls when bulk loading.
308
junov@chromium.orgbb78c442012-11-01 17:10:32 +0000309 return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren,
sglez@google.com9baab6f2013-08-30 17:27:47 +0000310 aspectRatio, sortDraws);
junov@chromium.orgbb78c442012-11-01 17:10:32 +0000311}
312
commit-bot@chromium.org48da8612014-04-17 23:35:06 +0000313#endif
314
reed@android.combcd4d5a2008-12-17 15:59:43 +0000315SkCanvas* SkPicture::getRecordingCanvas() const {
316 // will be null if we are not recording
317 return fRecord;
318}
319
320void SkPicture::endRecording() {
321 if (NULL == fPlayback) {
322 if (NULL != fRecord) {
junov@chromium.org9aa18db2012-07-12 17:47:34 +0000323 fRecord->endRecording();
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000324 SkPictInfo info;
325 this->createHeader(&info);
326 fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, info));
commit-bot@chromium.orgefea6992014-02-14 17:27:10 +0000327 SkSafeSetNull(fRecord);
reed@android.combcd4d5a2008-12-17 15:59:43 +0000328 }
329 }
330 SkASSERT(NULL == fRecord);
331}
332
commit-bot@chromium.org4b918972014-03-18 17:45:32 +0000333const SkPicture::OperationList& SkPicture::OperationList::InvalidList() {
334 static OperationList gInvalid;
335 return gInvalid;
336}
337
338const SkPicture::OperationList& SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) {
robertphillips@google.com6dd381b2014-04-13 19:09:42 +0000339 this->endRecording(); // TODO: remove eventually
commit-bot@chromium.org4b918972014-03-18 17:45:32 +0000340 if (NULL != fPlayback) {
341 return fPlayback->getActiveOps(queryRect);
342 }
343 return OperationList::InvalidList();
344}
345
commit-bot@chromium.org0ea71132014-03-24 19:40:49 +0000346size_t SkPicture::EXPERIMENTAL_curOpID() const {
347 if (NULL != fPlayback) {
348 return fPlayback->curOpID();
349 }
350 return 0;
351}
352
reed@google.com2b3a5082013-05-20 17:02:41 +0000353void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) {
robertphillips@google.com6dd381b2014-04-13 19:09:42 +0000354 this->endRecording(); // TODO: remove eventually
commit-bot@chromium.org73857a32014-03-16 19:46:36 +0000355 if (NULL != fPlayback) {
reed@google.com2b3a5082013-05-20 17:02:41 +0000356 fPlayback->draw(*surface, callback);
reed@android.combcd4d5a2008-12-17 15:59:43 +0000357 }
358}
359
360///////////////////////////////////////////////////////////////////////////////
361
362#include "SkStream.h"
363
rmistry@google.com8793ad72013-12-02 13:50:38 +0000364static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
commit-bot@chromium.org060e3a52014-03-12 14:46:41 +0000365
366bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
367 if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
368 return false;
369 }
370
371 if (info.fVersion < MIN_PICTURE_VERSION ||
372 info.fVersion > CURRENT_PICTURE_VERSION) {
373 return false;
374 }
375
376 return true;
377}
rmistry@google.com8793ad72013-12-02 13:50:38 +0000378
commit-bot@chromium.orgabad6d62014-03-03 19:18:39 +0000379bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
scroggo@google.com3b990302013-06-28 21:32:00 +0000380 if (NULL == stream) {
381 return false;
borenet@google.com30dda202012-09-17 18:26:06 +0000382 }
reed@google.com4bca7f62012-06-22 15:38:39 +0000383
rmistry@google.com8793ad72013-12-02 13:50:38 +0000384 // Check magic bytes.
reed@google.com4bca7f62012-06-22 15:38:39 +0000385 SkPictInfo info;
commit-bot@chromium.org060e3a52014-03-12 14:46:41 +0000386 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
387 if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) {
scroggo@google.com3b990302013-06-28 21:32:00 +0000388 return false;
reed@google.com4bca7f62012-06-22 15:38:39 +0000389 }
reed@android.combcd4d5a2008-12-17 15:59:43 +0000390
scroggo@google.com3b990302013-06-28 21:32:00 +0000391 if (pInfo != NULL) {
392 *pInfo = info;
393 }
394 return true;
395}
396
commit-bot@chromium.orgabad6d62014-03-03 19:18:39 +0000397bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) {
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000398 // Check magic bytes.
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000399 SkPictInfo info;
commit-bot@chromium.org060e3a52014-03-12 14:46:41 +0000400 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
401 if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) {
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000402 return false;
403 }
404
405 if (pInfo != NULL) {
406 *pInfo = info;
407 }
408 return true;
409}
410
scroggo@google.com3b990302013-06-28 21:32:00 +0000411SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height)
412 : fPlayback(playback)
413 , fRecord(NULL)
414 , fWidth(width)
commit-bot@chromium.org73857a32014-03-16 19:46:36 +0000415 , fHeight(height)
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000416 , fAccelData(NULL) {
417 this->needsNewGenID();
418}
scroggo@google.com3b990302013-06-28 21:32:00 +0000419
420SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
421 SkPictInfo info;
422
commit-bot@chromium.orgabad6d62014-03-03 19:18:39 +0000423 if (!InternalOnly_StreamIsSKP(stream, &info)) {
scroggo@google.com3b990302013-06-28 21:32:00 +0000424 return NULL;
425 }
426
427 SkPicturePlayback* playback;
428 // Check to see if there is a playback to recreate.
reed@android.combcd4d5a2008-12-17 15:59:43 +0000429 if (stream->readBool()) {
scroggo@google.com3b7431c2013-10-01 15:30:46 +0000430 playback = SkPicturePlayback::CreateFromStream(stream, info, proc);
431 if (NULL == playback) {
432 return NULL;
433 }
scroggo@google.com3b990302013-06-28 21:32:00 +0000434 } else {
435 playback = NULL;
reed@android.combcd4d5a2008-12-17 15:59:43 +0000436 }
reed@google.com4bca7f62012-06-22 15:38:39 +0000437
scroggo@google.com3b990302013-06-28 21:32:00 +0000438 return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight));
reed@android.combcd4d5a2008-12-17 15:59:43 +0000439}
440
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000441SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
442 SkPictInfo info;
443
commit-bot@chromium.orgabad6d62014-03-03 19:18:39 +0000444 if (!InternalOnly_BufferIsSKP(buffer, &info)) {
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000445 return NULL;
446 }
447
448 SkPicturePlayback* playback;
449 // Check to see if there is a playback to recreate.
450 if (buffer.readBool()) {
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000451 playback = SkPicturePlayback::CreateFromBuffer(buffer, info);
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000452 if (NULL == playback) {
453 return NULL;
454 }
455 } else {
456 playback = NULL;
457 }
458
459 return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight));
460}
461
commit-bot@chromium.org060e3a52014-03-12 14:46:41 +0000462void SkPicture::createHeader(SkPictInfo* info) const {
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000463 // Copy magic bytes at the beginning of the header
464 SkASSERT(sizeof(kMagic) == 8);
commit-bot@chromium.org060e3a52014-03-12 14:46:41 +0000465 SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
466 memcpy(info->fMagic, kMagic, sizeof(kMagic));
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000467
commit-bot@chromium.orgabad6d62014-03-03 19:18:39 +0000468 // Set picture info after magic bytes in the header
commit-bot@chromium.org338284f2014-02-25 02:16:10 +0000469 info->fVersion = CURRENT_PICTURE_VERSION;
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000470 info->fWidth = fWidth;
471 info->fHeight = fHeight;
472 info->fFlags = SkPictInfo::kCrossProcess_Flag;
473 // TODO: remove this flag, since we're always float (now)
474 info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
475
476 if (8 == sizeof(void*)) {
477 info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
478 }
479}
480
scroggo@google.com2e727312013-02-22 22:04:19 +0000481void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
reed@android.combcd4d5a2008-12-17 15:59:43 +0000482 SkPicturePlayback* playback = fPlayback;
reed@google.com91911482011-02-07 15:30:46 +0000483
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000484 SkPictInfo info;
485 this->createHeader(&info);
reed@android.combcd4d5a2008-12-17 15:59:43 +0000486 if (NULL == playback && fRecord) {
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000487 playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, info));
reed@android.combcd4d5a2008-12-17 15:59:43 +0000488 }
489
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000490 stream->write(&info, sizeof(info));
reed@android.combcd4d5a2008-12-17 15:59:43 +0000491 if (playback) {
492 stream->writeBool(true);
scroggo@google.com6ff73172012-10-04 21:46:08 +0000493 playback->serialize(stream, encoder);
reed@android.combcd4d5a2008-12-17 15:59:43 +0000494 // delete playback if it is a local version (i.e. cons'd up just now)
495 if (playback != fPlayback) {
496 SkDELETE(playback);
497 }
498 } else {
499 stream->writeBool(false);
500 }
501}
502
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000503void SkPicture::flatten(SkWriteBuffer& buffer) const {
504 SkPicturePlayback* playback = fPlayback;
505
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000506 SkPictInfo info;
507 this->createHeader(&info);
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000508 if (NULL == playback && fRecord) {
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000509 playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, info));
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000510 }
511
commit-bot@chromium.org206dc582014-03-28 18:05:47 +0000512 buffer.writeByteArray(&info, sizeof(info));
commit-bot@chromium.org7183ff62014-02-07 12:20:04 +0000513 if (playback) {
514 buffer.writeBool(true);
515 playback->flatten(buffer);
516 // delete playback if it is a local version (i.e. cons'd up just now)
517 if (playback != fPlayback) {
518 SkDELETE(playback);
519 }
520 } else {
521 buffer.writeBool(false);
522 }
523}
524
commit-bot@chromium.org05937b42014-03-19 22:54:40 +0000525#if SK_SUPPORT_GPU
commit-bot@chromium.org95cdc162014-03-19 21:24:25 +0000526bool SkPicture::suitableForGpuRasterization(GrContext* context) const {
527 // Stub for now; never veto GPu rasterization.
528 return true;
529}
commit-bot@chromium.org05937b42014-03-19 22:54:40 +0000530#endif
commit-bot@chromium.org95cdc162014-03-19 21:24:25 +0000531
tomhudson@google.comc7941702013-10-24 11:12:47 +0000532bool SkPicture::willPlayBackBitmaps() const {
commit-bot@chromium.org73857a32014-03-16 19:46:36 +0000533 if (!fPlayback) {
534 return false;
535 }
tomhudson@google.comc7941702013-10-24 11:12:47 +0000536 return fPlayback->containsBitmaps();
537}
538
djsollen@google.com6789a342013-02-01 16:18:09 +0000539#ifdef SK_BUILD_FOR_ANDROID
reed@android.combcd4d5a2008-12-17 15:59:43 +0000540void SkPicture::abortPlayback() {
541 if (NULL == fPlayback) {
542 return;
543 }
544 fPlayback->abort();
545}
djsollen@google.com6789a342013-02-01 16:18:09 +0000546#endif
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000547
548static int32_t next_picture_generation_id() {
549 static int32_t gPictureGenerationID = 0;
550 // do a loop in case our global wraps around, as we never want to
551 // return a 0
552 int32_t genID;
553 do {
554 genID = sk_atomic_inc(&gPictureGenerationID) + 1;
commit-bot@chromium.orgb50bcb92014-04-07 18:26:22 +0000555 } while (SK_InvalidGenID == genID);
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000556 return genID;
557}
558
commit-bot@chromium.orgb50bcb92014-04-07 18:26:22 +0000559uint32_t SkPicture::uniqueID() const {
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000560 if (NULL != fRecord) {
561 SkASSERT(NULL == fPlayback);
commit-bot@chromium.orgb50bcb92014-04-07 18:26:22 +0000562 return SK_InvalidGenID;
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000563 }
564
commit-bot@chromium.orgb50bcb92014-04-07 18:26:22 +0000565 if (SK_InvalidGenID == fUniqueID) {
566 fUniqueID = next_picture_generation_id();
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000567 }
commit-bot@chromium.orgb50bcb92014-04-07 18:26:22 +0000568 return fUniqueID;
robertphillips@google.com647fe7f2014-04-02 23:51:13 +0000569}