blob: 7fc165d219d2962ffebce0ad2f677a5e7e5415ee [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00007#include <new>
rileya@google.com8515e792012-09-13 21:41:51 +00008#include "SkBBoxHierarchy.h"
Mike Kleinc11530e2014-06-24 11:29:06 -04009#include "SkDrawPictureCallback.h"
robertphillipsdb539902014-07-01 08:47:04 -070010#include "SkPictureData.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000011#include "SkPictureRecord.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000012#include "SkReadBuffer.h"
fmalitab7425172014-08-26 07:56:44 -070013#include "SkTextBlob.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000014#include "SkTypeface.h"
rileya@google.com8515e792012-09-13 21:41:51 +000015#include "SkTSort.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000016#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
egdaniel12c21982014-06-18 07:34:39 -070018#if SK_SUPPORT_GPU
19#include "GrContext.h"
20#endif
21
reed@google.comf4cc1872012-07-23 15:04:45 +000022template <typename T> int SafeCount(const T* obj) {
23 return obj ? obj->count() : 0;
24}
25
robertphillipsdb539902014-07-01 08:47:04 -070026SkPictureData::SkPictureData(const SkPictInfo& info)
robertphillipse26e65e2014-06-12 05:51:22 -070027 : fInfo(info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000028 this->init();
29}
30
robertphillipsdb539902014-07-01 08:47:04 -070031void SkPictureData::initForPlayback() const {
robertphillipse26e65e2014-06-12 05:51:22 -070032 // ensure that the paths bounds are pre-computed
mtklein703d3c72014-11-12 11:08:20 -080033 for (int i = 0; i < fPaths.count(); i++) {
34 fPaths[i].updateBoundsCache();
robertphillipse26e65e2014-06-12 05:51:22 -070035 }
36}
37
robertphillipsdb539902014-07-01 08:47:04 -070038SkPictureData::SkPictureData(const SkPictureRecord& record,
robertphillips61426092014-07-10 09:35:12 -070039 const SkPictInfo& info,
40 bool deepCopyOps)
robertphillipse26e65e2014-06-12 05:51:22 -070041 : fInfo(info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000042
commit-bot@chromium.org70512af2014-03-18 17:45:32 +000043 this->init();
robertphillips0bdbea72014-06-11 11:37:55 -070044
45 fOpData = record.opData(deepCopyOps);
reed@google.com82065d62011-02-07 15:30:46 +000046
robertphillips0bdbea72014-06-11 11:37:55 -070047 fContentInfo.set(record.fContentInfo);
rileya@google.com8515e792012-09-13 21:41:51 +000048
mtklein703d3c72014-11-12 11:08:20 -080049 fBitmaps = record.fBitmaps;
50 fPaints = record.fPaints;
51 fPaths = record.fPaths;
djsollen@google.comc9ab9872012-08-29 18:52:07 +000052
robertphillipse26e65e2014-06-12 05:51:22 -070053 this->initForPlayback();
reed@android.com8a1c16f2008-12-17 15:59:43 +000054
robertphillips9b14f262014-06-04 05:40:44 -070055 const SkTDArray<const SkPicture* >& pictures = record.getPictureRefs();
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 fPictureCount = pictures.count();
57 if (fPictureCount > 0) {
robertphillips9b14f262014-06-04 05:40:44 -070058 fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 for (int i = 0; i < fPictureCount; i++) {
robertphillips6de27122014-06-10 09:23:06 -070060 fPictureRefs[i] = pictures[i];
61 fPictureRefs[i]->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +000062 }
63 }
fmalitab7425172014-08-26 07:56:44 -070064
65 // templatize to consolidate with similar picture logic?
66 const SkTDArray<const SkTextBlob*>& blobs = record.getTextBlobRefs();
67 fTextBlobCount = blobs.count();
68 if (fTextBlobCount > 0) {
69 fTextBlobRefs = SkNEW_ARRAY(const SkTextBlob*, fTextBlobCount);
70 for (int i = 0; i < fTextBlobCount; ++i) {
71 fTextBlobRefs[i] = SkRef(blobs[i]);
72 }
73 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000074}
75
robertphillipsdb539902014-07-01 08:47:04 -070076void SkPictureData::init() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000077 fPictureRefs = NULL;
reed@google.comf4cc1872012-07-23 15:04:45 +000078 fPictureCount = 0;
fmalitab7425172014-08-26 07:56:44 -070079 fTextBlobRefs = NULL;
80 fTextBlobCount = 0;
reed@google.comddf98a82012-07-21 20:31:09 +000081 fOpData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000082 fFactoryPlayback = NULL;
83}
84
robertphillipsdb539902014-07-01 08:47:04 -070085SkPictureData::~SkPictureData() {
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +000086 SkSafeUnref(fOpData);
reed@android.com8a1c16f2008-12-17 15:59:43 +000087
reed@android.com8a1c16f2008-12-17 15:59:43 +000088 for (int i = 0; i < fPictureCount; i++) {
89 fPictureRefs[i]->unref();
90 }
91 SkDELETE_ARRAY(fPictureRefs);
reed@google.com82065d62011-02-07 15:30:46 +000092
fmalitab7425172014-08-26 07:56:44 -070093 for (int i = 0; i < fTextBlobCount; i++) {
94 fTextBlobRefs[i]->unref();
95 }
96 SkDELETE_ARRAY(fTextBlobRefs);
97
reed@android.com8a1c16f2008-12-17 15:59:43 +000098 SkDELETE(fFactoryPlayback);
99}
100
robertphillipsdb539902014-07-01 08:47:04 -0700101bool SkPictureData::containsBitmaps() const {
mtklein703d3c72014-11-12 11:08:20 -0800102 if (fBitmaps.count() > 0) {
tomhudson@google.com381010e2013-10-24 11:12:47 +0000103 return true;
104 }
105 for (int i = 0; i < fPictureCount; ++i) {
106 if (fPictureRefs[i]->willPlayBackBitmaps()) {
107 return true;
108 }
109 }
110 return false;
111}
112
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113///////////////////////////////////////////////////////////////////////////////
114///////////////////////////////////////////////////////////////////////////////
115
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116#include "SkStream.h"
117
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000118static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) {
119 size_t size = 4; // for 'count'
reed@google.com82065d62011-02-07 15:30:46 +0000120
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000121 for (int i = 0; i < count; i++) {
122 const char* name = SkFlattenable::FactoryToName(array[i]);
123 if (NULL == name || 0 == *name) {
124 size += SkWStream::SizeOfPackedUInt(0);
125 } else {
126 size_t len = strlen(name);
127 size += SkWStream::SizeOfPackedUInt(len);
128 size += len;
129 }
130 }
131
132 return size;
133}
134
robertphillips61426092014-07-10 09:35:12 -0700135static void write_tag_size(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
136 buffer.writeUInt(tag);
137 buffer.writeUInt(SkToU32(size));
138}
139
140static void write_tag_size(SkWStream* stream, uint32_t tag, size_t size) {
141 stream->write32(tag);
142 stream->write32(SkToU32(size));
143}
144
robertphillipsdb539902014-07-01 08:47:04 -0700145void SkPictureData::WriteFactories(SkWStream* stream, const SkFactorySet& rec) {
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000146 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000147
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148 SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
149 SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000150 rec.copyToArray(array);
reed@google.com82065d62011-02-07 15:30:46 +0000151
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000152 size_t size = compute_chunk_size(array, count);
153
154 // TODO: write_tag_size should really take a size_t
robertphillips61426092014-07-10 09:35:12 -0700155 write_tag_size(stream, SK_PICT_FACTORY_TAG, (uint32_t) size);
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000156 SkDEBUGCODE(size_t start = stream->bytesWritten());
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000157 stream->write32(count);
158
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 for (int i = 0; i < count; i++) {
160 const char* name = SkFlattenable::FactoryToName(array[i]);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 if (NULL == name || 0 == *name) {
162 stream->writePackedUInt(0);
163 } else {
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +0000164 size_t len = strlen(name);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 stream->writePackedUInt(len);
166 stream->write(name, len);
167 }
168 }
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000169
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000170 SkASSERT(size == (stream->bytesWritten() - start));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171}
172
robertphillipsdb539902014-07-01 08:47:04 -0700173void SkPictureData::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000175
robertphillips61426092014-07-10 09:35:12 -0700176 write_tag_size(stream, SK_PICT_TYPEFACE_TAG, count);
reed@google.com82065d62011-02-07 15:30:46 +0000177
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 SkAutoSTMalloc<16, SkTypeface*> storage(count);
179 SkTypeface** array = (SkTypeface**)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000180 rec.copyToArray((SkRefCnt**)array);
reed@google.com82065d62011-02-07 15:30:46 +0000181
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 for (int i = 0; i < count; i++) {
mtklein1a4900e2014-12-11 11:06:00 -0800183#ifdef SK_BUILD_FOR_UNIX
184 array[i]->serializeForcingEmbedding(stream);
185#else
186 // FIXME: Macs and Windows don't draw pixel-perfect if we embed fonts in the SKP.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 array[i]->serialize(stream);
mtklein1a4900e2014-12-11 11:06:00 -0800188#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 }
190}
191
robertphillipsdb539902014-07-01 08:47:04 -0700192void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const {
reed@google.comf4cc1872012-07-23 15:04:45 +0000193 int i, n;
reed@google.com82065d62011-02-07 15:30:46 +0000194
mtklein703d3c72014-11-12 11:08:20 -0800195 if ((n = fBitmaps.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700196 write_tag_size(buffer, SK_PICT_BITMAP_BUFFER_TAG, n);
reed@google.comf4cc1872012-07-23 15:04:45 +0000197 for (i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800198 buffer.writeBitmap(fBitmaps[i]);
reed@google.com67562092012-06-22 15:38:39 +0000199 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000201
mtklein703d3c72014-11-12 11:08:20 -0800202 if ((n = fPaints.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700203 write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, n);
reed@google.comf4cc1872012-07-23 15:04:45 +0000204 for (i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800205 buffer.writePaint(fPaints[i]);
reed@google.com67562092012-06-22 15:38:39 +0000206 }
207 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000208
mtklein703d3c72014-11-12 11:08:20 -0800209 if ((n = fPaths.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700210 write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, n);
mtklein71a23632014-11-12 10:24:55 -0800211 buffer.writeInt(n);
212 for (int i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800213 buffer.writePath(fPaths[i]);
mtklein71a23632014-11-12 10:24:55 -0800214 }
robertphillipse26e65e2014-06-12 05:51:22 -0700215 }
fmalitab7425172014-08-26 07:56:44 -0700216
217 if (fTextBlobCount > 0) {
218 write_tag_size(buffer, SK_PICT_TEXTBLOB_BUFFER_TAG, fTextBlobCount);
219 for (i = 0; i < fTextBlobCount; ++i) {
220 fTextBlobRefs[i]->flatten(buffer);
221 }
222 }
reed@google.com67562092012-06-22 15:38:39 +0000223}
reed@google.com82065d62011-02-07 15:30:46 +0000224
robertphillipsdb539902014-07-01 08:47:04 -0700225void SkPictureData::serialize(SkWStream* stream,
scroggo895c43b2014-12-11 10:53:58 -0800226 SkPixelSerializer* pixelSerializer) const {
robertphillips61426092014-07-10 09:35:12 -0700227 write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size());
reed@google.comddf98a82012-07-21 20:31:09 +0000228 stream->write(fOpData->bytes(), fOpData->size());
reed@google.com67562092012-06-22 15:38:39 +0000229
230 if (fPictureCount > 0) {
robertphillips61426092014-07-10 09:35:12 -0700231 write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictureCount);
reed@google.com67562092012-06-22 15:38:39 +0000232 for (int i = 0; i < fPictureCount; i++) {
scroggo895c43b2014-12-11 10:53:58 -0800233 fPictureRefs[i]->serialize(stream, pixelSerializer);
reed@google.com67562092012-06-22 15:38:39 +0000234 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235 }
reed@google.com82065d62011-02-07 15:30:46 +0000236
reed@google.com67562092012-06-22 15:38:39 +0000237 // Write some of our data into a writebuffer, and then serialize that
238 // into our stream
239 {
240 SkRefCntSet typefaceSet;
241 SkFactorySet factSet;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242
commit-bot@chromium.orga2bd2d12014-01-30 22:16:32 +0000243 SkWriteBuffer buffer(SkWriteBuffer::kCrossProcess_Flag);
reed@google.com67562092012-06-22 15:38:39 +0000244 buffer.setTypefaceRecorder(&typefaceSet);
245 buffer.setFactoryRecorder(&factSet);
scroggo895c43b2014-12-11 10:53:58 -0800246 buffer.setPixelSerializer(pixelSerializer);
reed@google.com34342f62012-06-25 14:36:28 +0000247
reed@google.com67562092012-06-22 15:38:39 +0000248 this->flattenToBuffer(buffer);
249
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000250 // We have to write these two sets into the stream *before* we write
reed@google.com67562092012-06-22 15:38:39 +0000251 // the buffer, since parsing that buffer will require that we already
252 // have these sets available to use.
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000253 WriteFactories(stream, factSet);
254 WriteTypefaces(stream, typefaceSet);
reed@google.com67562092012-06-22 15:38:39 +0000255
robertphillips61426092014-07-10 09:35:12 -0700256 write_tag_size(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten());
reed@google.com67562092012-06-22 15:38:39 +0000257 buffer.writeToStream(stream);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 }
reed@google.com82065d62011-02-07 15:30:46 +0000259
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000260 stream->write32(SK_PICT_EOF_TAG);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261}
262
robertphillipsdb539902014-07-01 08:47:04 -0700263void SkPictureData::flatten(SkWriteBuffer& buffer) const {
robertphillips61426092014-07-10 09:35:12 -0700264 write_tag_size(buffer, SK_PICT_READER_TAG, fOpData->size());
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000265 buffer.writeByteArray(fOpData->bytes(), fOpData->size());
266
267 if (fPictureCount > 0) {
robertphillips61426092014-07-10 09:35:12 -0700268 write_tag_size(buffer, SK_PICT_PICTURE_TAG, fPictureCount);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000269 for (int i = 0; i < fPictureCount; i++) {
270 fPictureRefs[i]->flatten(buffer);
271 }
272 }
273
274 // Write this picture playback's data into a writebuffer
275 this->flattenToBuffer(buffer);
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000276 buffer.write32(SK_PICT_EOF_TAG);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000277}
278
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279///////////////////////////////////////////////////////////////////////////////
280
reed@google.com34342f62012-06-25 14:36:28 +0000281/**
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000282 * Return the corresponding SkReadBuffer flags, given a set of
reed@google.com34342f62012-06-25 14:36:28 +0000283 * SkPictInfo flags.
284 */
285static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
286 static const struct {
287 uint32_t fSrc;
288 uint32_t fDst;
289 } gSD[] = {
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000290 { SkPictInfo::kCrossProcess_Flag, SkReadBuffer::kCrossProcess_Flag },
291 { SkPictInfo::kScalarIsFloat_Flag, SkReadBuffer::kScalarIsFloat_Flag },
292 { SkPictInfo::kPtrIs64Bit_Flag, SkReadBuffer::kPtrIs64Bit_Flag },
reed@google.com34342f62012-06-25 14:36:28 +0000293 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000294
reed@google.com34342f62012-06-25 14:36:28 +0000295 uint32_t rbMask = 0;
296 for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
297 if (pictInfoFlags & gSD[i].fSrc) {
298 rbMask |= gSD[i].fDst;
299 }
300 }
301 return rbMask;
302}
303
robertphillipsdb539902014-07-01 08:47:04 -0700304bool SkPictureData::parseStreamTag(SkStream* stream,
robertphillipsce4dd3d2014-07-07 13:46:35 -0700305 uint32_t tag,
306 uint32_t size,
307 SkPicture::InstallPixelRefProc proc) {
reed@google.com67562092012-06-22 15:38:39 +0000308 /*
309 * By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
310 * its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
311 * but if they are present, they need to have been seen before the buffer.
312 *
313 * We assert that if/when we see either of these, that we have not yet seen
314 * the buffer tag, because if we have, then its too-late to deal with the
315 * factories or typefaces.
316 */
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000317 SkDEBUGCODE(bool haveBuffer = false;)
reed@google.com67562092012-06-22 15:38:39 +0000318
319 switch (tag) {
reed9594da12014-09-12 12:12:27 -0700320 case SK_PICT_READER_TAG:
321 SkASSERT(NULL == fOpData);
322 fOpData = SkData::NewFromStream(stream, size);
323 if (!fOpData) {
scroggo@google.com12705322013-10-01 15:30:46 +0000324 return false;
325 }
reed9594da12014-09-12 12:12:27 -0700326 break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000327 case SK_PICT_FACTORY_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000328 SkASSERT(!haveBuffer);
mtklein88fd0fb2014-12-01 06:56:38 -0800329 size = stream->readU32();
reed@google.com67562092012-06-22 15:38:39 +0000330 fFactoryPlayback = SkNEW_ARGS(SkFactoryPlayback, (size));
331 for (size_t i = 0; i < size; i++) {
332 SkString str;
scroggo@google.com12705322013-10-01 15:30:46 +0000333 const size_t len = stream->readPackedUInt();
reed@google.com67562092012-06-22 15:38:39 +0000334 str.resize(len);
scroggo@google.com12705322013-10-01 15:30:46 +0000335 if (stream->read(str.writable_str(), len) != len) {
336 return false;
337 }
reed@google.com67562092012-06-22 15:38:39 +0000338 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
339 }
340 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000341 case SK_PICT_TYPEFACE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000342 SkASSERT(!haveBuffer);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000343 const int count = SkToInt(size);
344 fTFPlayback.setCount(count);
345 for (int i = 0; i < count; i++) {
reed@google.com73c0abc2013-04-22 13:47:40 +0000346 SkAutoTUnref<SkTypeface> tf(SkTypeface::Deserialize(stream));
347 if (!tf.get()) { // failed to deserialize
348 // fTFPlayback asserts it never has a null, so we plop in
349 // the default here.
350 tf.reset(SkTypeface::RefDefault());
351 }
352 fTFPlayback.set(i, tf);
reed@google.com67562092012-06-22 15:38:39 +0000353 }
354 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000355 case SK_PICT_PICTURE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000356 fPictureCount = size;
robertphillips9b14f262014-06-04 05:40:44 -0700357 fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
scroggo@google.com12705322013-10-01 15:30:46 +0000358 bool success = true;
359 int i = 0;
360 for ( ; i < fPictureCount; i++) {
scroggo@google.comf1754ec2013-06-28 21:32:00 +0000361 fPictureRefs[i] = SkPicture::CreateFromStream(stream, proc);
scroggo@google.com12705322013-10-01 15:30:46 +0000362 if (NULL == fPictureRefs[i]) {
363 success = false;
364 break;
365 }
366 }
367 if (!success) {
368 // Delete all of the pictures that were already created (up to but excluding i):
369 for (int j = 0; j < i; j++) {
370 fPictureRefs[j]->unref();
371 }
372 // Delete the array
373 SkDELETE_ARRAY(fPictureRefs);
374 fPictureCount = 0;
375 return false;
reed@google.com67562092012-06-22 15:38:39 +0000376 }
377 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000378 case SK_PICT_BUFFER_SIZE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000379 SkAutoMalloc storage(size);
scroggo@google.com12705322013-10-01 15:30:46 +0000380 if (stream->read(storage.get(), size) != size) {
381 return false;
382 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000383
reedac6a2f92014-11-12 09:25:25 -0800384 /* Should we use SkValidatingReadBuffer instead? */
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000385 SkReadBuffer buffer(storage.get(), size);
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000386 buffer.setFlags(pictInfoFlagsToReadBufferFlags(fInfo.fFlags));
commit-bot@chromium.org7ed173b2014-05-20 17:31:08 +0000387 buffer.setVersion(fInfo.fVersion);
reed@google.com34342f62012-06-25 14:36:28 +0000388
reed@google.com67562092012-06-22 15:38:39 +0000389 fFactoryPlayback->setupBuffer(buffer);
390 fTFPlayback.setupBuffer(buffer);
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000391 buffer.setBitmapDecoder(proc);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000392
reedac6a2f92014-11-12 09:25:25 -0800393 while (!buffer.eof() && buffer.isValid()) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000394 tag = buffer.readUInt();
395 size = buffer.readUInt();
robertphillipse26e65e2014-06-12 05:51:22 -0700396 if (!this->parseBufferTag(buffer, tag, size)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000397 return false;
398 }
reed@google.com67562092012-06-22 15:38:39 +0000399 }
reedac6a2f92014-11-12 09:25:25 -0800400 if (!buffer.isValid()) {
401 return false;
402 }
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000403 SkDEBUGCODE(haveBuffer = true;)
reed@google.com67562092012-06-22 15:38:39 +0000404 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000405 }
scroggo@google.com12705322013-10-01 15:30:46 +0000406 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407}
408
robertphillipsdb539902014-07-01 08:47:04 -0700409bool SkPictureData::parseBufferTag(SkReadBuffer& buffer,
robertphillipsce4dd3d2014-07-07 13:46:35 -0700410 uint32_t tag, uint32_t size) {
reed@google.com67562092012-06-22 15:38:39 +0000411 switch (tag) {
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000412 case SK_PICT_BITMAP_BUFFER_TAG: {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000413 const int count = SkToInt(size);
mtklein703d3c72014-11-12 11:08:20 -0800414 fBitmaps.reset(count);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000415 for (int i = 0; i < count; ++i) {
mtklein703d3c72014-11-12 11:08:20 -0800416 SkBitmap* bm = &fBitmaps[i];
reedac6a2f92014-11-12 09:25:25 -0800417 if (buffer.readBitmap(bm)) {
418 bm->setImmutable();
419 } else {
420 return false;
421 }
reed@google.com67562092012-06-22 15:38:39 +0000422 }
423 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000424 case SK_PICT_PAINT_BUFFER_TAG: {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000425 const int count = SkToInt(size);
mtklein703d3c72014-11-12 11:08:20 -0800426 fPaints.reset(count);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000427 for (int i = 0; i < count; ++i) {
mtklein703d3c72014-11-12 11:08:20 -0800428 buffer.readPaint(&fPaints[i]);
reed@google.com67562092012-06-22 15:38:39 +0000429 }
430 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000431 case SK_PICT_PATH_BUFFER_TAG:
robertphillipse26e65e2014-06-12 05:51:22 -0700432 if (size > 0) {
mtklein71a23632014-11-12 10:24:55 -0800433 const int count = buffer.readInt();
mtklein703d3c72014-11-12 11:08:20 -0800434 fPaths.reset(count);
mtklein71a23632014-11-12 10:24:55 -0800435 for (int i = 0; i < count; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800436 buffer.readPath(&fPaths[i]);
mtklein71a23632014-11-12 10:24:55 -0800437 }
438 } break;
fmalitab7425172014-08-26 07:56:44 -0700439 case SK_PICT_TEXTBLOB_BUFFER_TAG: {
440 if (!buffer.validate((0 == fTextBlobCount) && (NULL == fTextBlobRefs))) {
441 return false;
442 }
443 fTextBlobCount = size;
444 fTextBlobRefs = SkNEW_ARRAY(const SkTextBlob*, fTextBlobCount);
445 bool success = true;
446 int i = 0;
447 for ( ; i < fTextBlobCount; i++) {
448 fTextBlobRefs[i] = SkTextBlob::CreateFromBuffer(buffer);
449 if (NULL == fTextBlobRefs[i]) {
450 success = false;
451 break;
452 }
453 }
454 if (!success) {
455 // Delete all of the blobs that were already created (up to but excluding i):
456 for (int j = 0; j < i; j++) {
457 fTextBlobRefs[j]->unref();
458 }
459 // Delete the array
460 SkDELETE_ARRAY(fTextBlobRefs);
461 fTextBlobRefs = NULL;
462 fTextBlobCount = 0;
463 return false;
464 }
465 } break;
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000466 case SK_PICT_READER_TAG: {
reed9594da12014-09-12 12:12:27 -0700467 SkAutoDataUnref data(SkData::NewUninitialized(size));
468 if (!buffer.readByteArray(data->writable_data(), size) ||
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000469 !buffer.validate(NULL == fOpData)) {
470 return false;
471 }
472 SkASSERT(NULL == fOpData);
reed9594da12014-09-12 12:12:27 -0700473 fOpData = data.detach();
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000474 } break;
475 case SK_PICT_PICTURE_TAG: {
476 if (!buffer.validate((0 == fPictureCount) && (NULL == fPictureRefs))) {
477 return false;
478 }
479 fPictureCount = size;
robertphillips9b14f262014-06-04 05:40:44 -0700480 fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000481 bool success = true;
482 int i = 0;
483 for ( ; i < fPictureCount; i++) {
484 fPictureRefs[i] = SkPicture::CreateFromBuffer(buffer);
485 if (NULL == fPictureRefs[i]) {
486 success = false;
487 break;
488 }
489 }
490 if (!success) {
491 // Delete all of the pictures that were already created (up to but excluding i):
492 for (int j = 0; j < i; j++) {
493 fPictureRefs[j]->unref();
494 }
495 // Delete the array
496 SkDELETE_ARRAY(fPictureRefs);
497 fPictureCount = 0;
498 return false;
499 }
500 } break;
scroggo@google.com12705322013-10-01 15:30:46 +0000501 default:
502 // The tag was invalid.
503 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000504 }
scroggo@google.com12705322013-10-01 15:30:46 +0000505 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506}
507
robertphillipsdb539902014-07-01 08:47:04 -0700508SkPictureData* SkPictureData::CreateFromStream(SkStream* stream,
509 const SkPictInfo& info,
510 SkPicture::InstallPixelRefProc proc) {
511 SkAutoTDelete<SkPictureData> data(SkNEW_ARGS(SkPictureData, (info)));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000512
robertphillipsdb539902014-07-01 08:47:04 -0700513 if (!data->parseStream(stream, proc)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000514 return NULL;
515 }
robertphillipsdb539902014-07-01 08:47:04 -0700516 return data.detach();
scroggo@google.com12705322013-10-01 15:30:46 +0000517}
518
robertphillipsdb539902014-07-01 08:47:04 -0700519SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer,
520 const SkPictInfo& info) {
521 SkAutoTDelete<SkPictureData> data(SkNEW_ARGS(SkPictureData, (info)));
commit-bot@chromium.org7ed173b2014-05-20 17:31:08 +0000522 buffer.setVersion(info.fVersion);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000523
robertphillipsdb539902014-07-01 08:47:04 -0700524 if (!data->parseBuffer(buffer)) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000525 return NULL;
526 }
robertphillipsdb539902014-07-01 08:47:04 -0700527 return data.detach();
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000528}
529
robertphillipsdb539902014-07-01 08:47:04 -0700530bool SkPictureData::parseStream(SkStream* stream,
531 SkPicture::InstallPixelRefProc proc) {
reed@google.com67562092012-06-22 15:38:39 +0000532 for (;;) {
533 uint32_t tag = stream->readU32();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000534 if (SK_PICT_EOF_TAG == tag) {
reed@google.com67562092012-06-22 15:38:39 +0000535 break;
536 }
reed@google.com82065d62011-02-07 15:30:46 +0000537
reed@google.comed384952012-06-22 13:12:17 +0000538 uint32_t size = stream->readU32();
robertphillipse26e65e2014-06-12 05:51:22 -0700539 if (!this->parseStreamTag(stream, tag, size, proc)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000540 return false; // we're invalid
541 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000542 }
scroggo@google.com12705322013-10-01 15:30:46 +0000543 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544}
545
robertphillipsdb539902014-07-01 08:47:04 -0700546bool SkPictureData::parseBuffer(SkReadBuffer& buffer) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000547 for (;;) {
548 uint32_t tag = buffer.readUInt();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000549 if (SK_PICT_EOF_TAG == tag) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000550 break;
551 }
552
553 uint32_t size = buffer.readUInt();
robertphillipse26e65e2014-06-12 05:51:22 -0700554 if (!this->parseBufferTag(buffer, tag, size)) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000555 return false; // we're invalid
556 }
557 }
558 return true;
559}
560
reed@android.com8a1c16f2008-12-17 15:59:43 +0000561///////////////////////////////////////////////////////////////////////////////
562///////////////////////////////////////////////////////////////////////////////
563
robertphillips0bdbea72014-06-11 11:37:55 -0700564#if SK_SUPPORT_GPU
robertphillipsdb539902014-07-01 08:47:04 -0700565bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
hendrikwafdada22014-08-08 10:44:33 -0700566 int sampleCount) const {
567 return fContentInfo.suitableForGpuRasterization(context, reason, sampleCount);
robertphillips0bdbea72014-06-11 11:37:55 -0700568}
egdaniel12c21982014-06-18 07:34:39 -0700569
robertphillipsdb539902014-07-01 08:47:04 -0700570bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
571 GrPixelConfig config, SkScalar dpi) const {
egdaniel12c21982014-06-18 07:34:39 -0700572
573 if (context != NULL) {
574 return this->suitableForGpuRasterization(context, reason,
575 context->getRecommendedSampleCount(config, dpi));
576 } else {
577 return this->suitableForGpuRasterization(NULL, reason);
578 }
579}
580
robertphillipsc019ec42014-08-12 05:35:58 -0700581bool SkPictureData::suitableForLayerOptimization() const {
582 return fContentInfo.numLayers() > 0;
583}
robertphillips0bdbea72014-06-11 11:37:55 -0700584#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000585///////////////////////////////////////////////////////////////////////////////
586
reed@android.com8a1c16f2008-12-17 15:59:43 +0000587