blob: 4f3ac37066f9197c362d9b0f7b6ac533306d070e [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>
robertphillipsdb539902014-07-01 08:47:04 -07008#include "SkPictureData.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +00009#include "SkPictureRecord.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000010#include "SkReadBuffer.h"
fmalitab7425172014-08-26 07:56:44 -070011#include "SkTextBlob.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000012#include "SkTypeface.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000013#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
egdaniel12c21982014-06-18 07:34:39 -070015#if SK_SUPPORT_GPU
16#include "GrContext.h"
17#endif
18
reed@google.comf4cc1872012-07-23 15:04:45 +000019template <typename T> int SafeCount(const T* obj) {
20 return obj ? obj->count() : 0;
21}
22
robertphillipsdb539902014-07-01 08:47:04 -070023SkPictureData::SkPictureData(const SkPictInfo& info)
robertphillipse26e65e2014-06-12 05:51:22 -070024 : fInfo(info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000025 this->init();
26}
27
robertphillipsdb539902014-07-01 08:47:04 -070028void SkPictureData::initForPlayback() const {
robertphillipse26e65e2014-06-12 05:51:22 -070029 // ensure that the paths bounds are pre-computed
mtklein703d3c72014-11-12 11:08:20 -080030 for (int i = 0; i < fPaths.count(); i++) {
31 fPaths[i].updateBoundsCache();
robertphillipse26e65e2014-06-12 05:51:22 -070032 }
33}
34
robertphillipsdb539902014-07-01 08:47:04 -070035SkPictureData::SkPictureData(const SkPictureRecord& record,
robertphillips61426092014-07-10 09:35:12 -070036 const SkPictInfo& info,
37 bool deepCopyOps)
robertphillipse26e65e2014-06-12 05:51:22 -070038 : fInfo(info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000039
commit-bot@chromium.org70512af2014-03-18 17:45:32 +000040 this->init();
robertphillips0bdbea72014-06-11 11:37:55 -070041
42 fOpData = record.opData(deepCopyOps);
reed@google.com82065d62011-02-07 15:30:46 +000043
robertphillips0bdbea72014-06-11 11:37:55 -070044 fContentInfo.set(record.fContentInfo);
rileya@google.com8515e792012-09-13 21:41:51 +000045
mtklein703d3c72014-11-12 11:08:20 -080046 fBitmaps = record.fBitmaps;
47 fPaints = record.fPaints;
48 fPaths = record.fPaths;
djsollen@google.comc9ab9872012-08-29 18:52:07 +000049
robertphillipse26e65e2014-06-12 05:51:22 -070050 this->initForPlayback();
reed@android.com8a1c16f2008-12-17 15:59:43 +000051
robertphillips9b14f262014-06-04 05:40:44 -070052 const SkTDArray<const SkPicture* >& pictures = record.getPictureRefs();
reed@android.com8a1c16f2008-12-17 15:59:43 +000053 fPictureCount = pictures.count();
54 if (fPictureCount > 0) {
robertphillips9b14f262014-06-04 05:40:44 -070055 fPictureRefs = SkNEW_ARRAY(const SkPicture*, fPictureCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 for (int i = 0; i < fPictureCount; i++) {
robertphillips6de27122014-06-10 09:23:06 -070057 fPictureRefs[i] = pictures[i];
58 fPictureRefs[i]->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 }
60 }
fmalitab7425172014-08-26 07:56:44 -070061
62 // templatize to consolidate with similar picture logic?
63 const SkTDArray<const SkTextBlob*>& blobs = record.getTextBlobRefs();
64 fTextBlobCount = blobs.count();
65 if (fTextBlobCount > 0) {
66 fTextBlobRefs = SkNEW_ARRAY(const SkTextBlob*, fTextBlobCount);
67 for (int i = 0; i < fTextBlobCount; ++i) {
68 fTextBlobRefs[i] = SkRef(blobs[i]);
69 }
70 }
reed871872f2015-06-22 12:48:26 -070071
72 const SkTDArray<const SkImage*>& imgs = record.getImageRefs();
73 fImageCount = imgs.count();
74 if (fImageCount > 0) {
75 fImageRefs = SkNEW_ARRAY(const SkImage*, fImageCount);
76 for (int i = 0; i < fImageCount; ++i) {
77 fImageRefs[i] = SkRef(imgs[i]);
78 }
79 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000080}
81
robertphillipsdb539902014-07-01 08:47:04 -070082void SkPictureData::init() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000083 fPictureRefs = NULL;
reed@google.comf4cc1872012-07-23 15:04:45 +000084 fPictureCount = 0;
fmalitab7425172014-08-26 07:56:44 -070085 fTextBlobRefs = NULL;
86 fTextBlobCount = 0;
reed871872f2015-06-22 12:48:26 -070087 fImageRefs = NULL;
88 fImageCount = 0;
reed@google.comddf98a82012-07-21 20:31:09 +000089 fOpData = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 fFactoryPlayback = NULL;
91}
92
robertphillipsdb539902014-07-01 08:47:04 -070093SkPictureData::~SkPictureData() {
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +000094 SkSafeUnref(fOpData);
reed@android.com8a1c16f2008-12-17 15:59:43 +000095
reed@android.com8a1c16f2008-12-17 15:59:43 +000096 for (int i = 0; i < fPictureCount; i++) {
97 fPictureRefs[i]->unref();
98 }
99 SkDELETE_ARRAY(fPictureRefs);
reed@google.com82065d62011-02-07 15:30:46 +0000100
fmalitab7425172014-08-26 07:56:44 -0700101 for (int i = 0; i < fTextBlobCount; i++) {
102 fTextBlobRefs[i]->unref();
103 }
104 SkDELETE_ARRAY(fTextBlobRefs);
reed871872f2015-06-22 12:48:26 -0700105
106 for (int i = 0; i < fImageCount; i++) {
107 fImageRefs[i]->unref();
108 }
109 SkDELETE_ARRAY(fImageRefs);
110
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111 SkDELETE(fFactoryPlayback);
112}
113
robertphillipsdb539902014-07-01 08:47:04 -0700114bool SkPictureData::containsBitmaps() const {
reed871872f2015-06-22 12:48:26 -0700115 if (fBitmaps.count() > 0 || fImageCount > 0) {
tomhudson@google.com381010e2013-10-24 11:12:47 +0000116 return true;
117 }
118 for (int i = 0; i < fPictureCount; ++i) {
119 if (fPictureRefs[i]->willPlayBackBitmaps()) {
120 return true;
121 }
122 }
123 return false;
124}
125
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126///////////////////////////////////////////////////////////////////////////////
127///////////////////////////////////////////////////////////////////////////////
128
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129#include "SkStream.h"
130
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000131static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) {
132 size_t size = 4; // for 'count'
reed@google.com82065d62011-02-07 15:30:46 +0000133
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000134 for (int i = 0; i < count; i++) {
135 const char* name = SkFlattenable::FactoryToName(array[i]);
136 if (NULL == name || 0 == *name) {
137 size += SkWStream::SizeOfPackedUInt(0);
138 } else {
139 size_t len = strlen(name);
140 size += SkWStream::SizeOfPackedUInt(len);
141 size += len;
142 }
143 }
144
145 return size;
146}
147
robertphillips61426092014-07-10 09:35:12 -0700148static void write_tag_size(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
149 buffer.writeUInt(tag);
150 buffer.writeUInt(SkToU32(size));
151}
152
153static void write_tag_size(SkWStream* stream, uint32_t tag, size_t size) {
154 stream->write32(tag);
155 stream->write32(SkToU32(size));
156}
157
robertphillipsdb539902014-07-01 08:47:04 -0700158void SkPictureData::WriteFactories(SkWStream* stream, const SkFactorySet& rec) {
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000159 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000160
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
162 SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000163 rec.copyToArray(array);
reed@google.com82065d62011-02-07 15:30:46 +0000164
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000165 size_t size = compute_chunk_size(array, count);
166
167 // TODO: write_tag_size should really take a size_t
robertphillips61426092014-07-10 09:35:12 -0700168 write_tag_size(stream, SK_PICT_FACTORY_TAG, (uint32_t) size);
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000169 SkDEBUGCODE(size_t start = stream->bytesWritten());
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000170 stream->write32(count);
171
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 for (int i = 0; i < count; i++) {
173 const char* name = SkFlattenable::FactoryToName(array[i]);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174 if (NULL == name || 0 == *name) {
175 stream->writePackedUInt(0);
176 } else {
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +0000177 size_t len = strlen(name);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 stream->writePackedUInt(len);
179 stream->write(name, len);
180 }
181 }
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000182
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000183 SkASSERT(size == (stream->bytesWritten() - start));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184}
185
robertphillipsdb539902014-07-01 08:47:04 -0700186void SkPictureData::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000188
robertphillips61426092014-07-10 09:35:12 -0700189 write_tag_size(stream, SK_PICT_TYPEFACE_TAG, count);
reed@google.com82065d62011-02-07 15:30:46 +0000190
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 SkAutoSTMalloc<16, SkTypeface*> storage(count);
192 SkTypeface** array = (SkTypeface**)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000193 rec.copyToArray((SkRefCnt**)array);
reed@google.com82065d62011-02-07 15:30:46 +0000194
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195 for (int i = 0; i < count; i++) {
mtkleind9591bb2015-02-10 11:48:55 -0800196#ifdef SK_PICTURE_FORCE_FONT_EMBEDDING
mtklein1a4900e2014-12-11 11:06:00 -0800197 array[i]->serializeForcingEmbedding(stream);
198#else
mtkleind9591bb2015-02-10 11:48:55 -0800199 // TODO: if (embedFonts) { array[i]->serializeForcingEmbedding(stream) } else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 array[i]->serialize(stream);
mtklein1a4900e2014-12-11 11:06:00 -0800201#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 }
203}
204
robertphillipsdb539902014-07-01 08:47:04 -0700205void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const {
reed@google.comf4cc1872012-07-23 15:04:45 +0000206 int i, n;
reed@google.com82065d62011-02-07 15:30:46 +0000207
mtklein703d3c72014-11-12 11:08:20 -0800208 if ((n = fBitmaps.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700209 write_tag_size(buffer, SK_PICT_BITMAP_BUFFER_TAG, n);
reed@google.comf4cc1872012-07-23 15:04:45 +0000210 for (i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800211 buffer.writeBitmap(fBitmaps[i]);
reed@google.com67562092012-06-22 15:38:39 +0000212 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000214
mtklein703d3c72014-11-12 11:08:20 -0800215 if ((n = fPaints.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700216 write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, n);
reed@google.comf4cc1872012-07-23 15:04:45 +0000217 for (i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800218 buffer.writePaint(fPaints[i]);
reed@google.com67562092012-06-22 15:38:39 +0000219 }
220 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000221
mtklein703d3c72014-11-12 11:08:20 -0800222 if ((n = fPaths.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700223 write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, n);
mtklein71a23632014-11-12 10:24:55 -0800224 buffer.writeInt(n);
225 for (int i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800226 buffer.writePath(fPaths[i]);
mtklein71a23632014-11-12 10:24:55 -0800227 }
robertphillipse26e65e2014-06-12 05:51:22 -0700228 }
fmalitab7425172014-08-26 07:56:44 -0700229
230 if (fTextBlobCount > 0) {
231 write_tag_size(buffer, SK_PICT_TEXTBLOB_BUFFER_TAG, fTextBlobCount);
232 for (i = 0; i < fTextBlobCount; ++i) {
233 fTextBlobRefs[i]->flatten(buffer);
234 }
235 }
reed871872f2015-06-22 12:48:26 -0700236
237 if (fImageCount > 0) {
238 write_tag_size(buffer, SK_PICT_IMAGE_BUFFER_TAG, fImageCount);
239 for (i = 0; i < fImageCount; ++i) {
240 buffer.writeImage(fImageRefs[i]);
241 }
242 }
reed@google.com67562092012-06-22 15:38:39 +0000243}
reed@google.com82065d62011-02-07 15:30:46 +0000244
robertphillipsdb539902014-07-01 08:47:04 -0700245void SkPictureData::serialize(SkWStream* stream,
scroggo895c43b2014-12-11 10:53:58 -0800246 SkPixelSerializer* pixelSerializer) const {
robertphillips61426092014-07-10 09:35:12 -0700247 write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size());
reed@google.comddf98a82012-07-21 20:31:09 +0000248 stream->write(fOpData->bytes(), fOpData->size());
reed@google.com67562092012-06-22 15:38:39 +0000249
250 if (fPictureCount > 0) {
robertphillips61426092014-07-10 09:35:12 -0700251 write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictureCount);
reed@google.com67562092012-06-22 15:38:39 +0000252 for (int i = 0; i < fPictureCount; i++) {
scroggo895c43b2014-12-11 10:53:58 -0800253 fPictureRefs[i]->serialize(stream, pixelSerializer);
reed@google.com67562092012-06-22 15:38:39 +0000254 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000255 }
reed@google.com82065d62011-02-07 15:30:46 +0000256
reed@google.com67562092012-06-22 15:38:39 +0000257 // Write some of our data into a writebuffer, and then serialize that
258 // into our stream
259 {
260 SkRefCntSet typefaceSet;
261 SkFactorySet factSet;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262
commit-bot@chromium.orga2bd2d12014-01-30 22:16:32 +0000263 SkWriteBuffer buffer(SkWriteBuffer::kCrossProcess_Flag);
reed@google.com67562092012-06-22 15:38:39 +0000264 buffer.setTypefaceRecorder(&typefaceSet);
265 buffer.setFactoryRecorder(&factSet);
scroggo895c43b2014-12-11 10:53:58 -0800266 buffer.setPixelSerializer(pixelSerializer);
reed@google.com34342f62012-06-25 14:36:28 +0000267
reed@google.com67562092012-06-22 15:38:39 +0000268 this->flattenToBuffer(buffer);
269
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000270 // We have to write these two sets into the stream *before* we write
reed@google.com67562092012-06-22 15:38:39 +0000271 // the buffer, since parsing that buffer will require that we already
272 // have these sets available to use.
commit-bot@chromium.org8f831f22014-04-23 22:35:42 +0000273 WriteFactories(stream, factSet);
274 WriteTypefaces(stream, typefaceSet);
reed@google.com67562092012-06-22 15:38:39 +0000275
robertphillips61426092014-07-10 09:35:12 -0700276 write_tag_size(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten());
reed@google.com67562092012-06-22 15:38:39 +0000277 buffer.writeToStream(stream);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 }
reed@google.com82065d62011-02-07 15:30:46 +0000279
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000280 stream->write32(SK_PICT_EOF_TAG);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281}
282
robertphillipsdb539902014-07-01 08:47:04 -0700283void SkPictureData::flatten(SkWriteBuffer& buffer) const {
robertphillips61426092014-07-10 09:35:12 -0700284 write_tag_size(buffer, SK_PICT_READER_TAG, fOpData->size());
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000285 buffer.writeByteArray(fOpData->bytes(), fOpData->size());
286
287 if (fPictureCount > 0) {
robertphillips61426092014-07-10 09:35:12 -0700288 write_tag_size(buffer, SK_PICT_PICTURE_TAG, fPictureCount);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000289 for (int i = 0; i < fPictureCount; i++) {
290 fPictureRefs[i]->flatten(buffer);
291 }
292 }
293
294 // Write this picture playback's data into a writebuffer
295 this->flattenToBuffer(buffer);
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000296 buffer.write32(SK_PICT_EOF_TAG);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000297}
298
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299///////////////////////////////////////////////////////////////////////////////
300
reed@google.com34342f62012-06-25 14:36:28 +0000301/**
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000302 * Return the corresponding SkReadBuffer flags, given a set of
reed@google.com34342f62012-06-25 14:36:28 +0000303 * SkPictInfo flags.
304 */
305static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
306 static const struct {
307 uint32_t fSrc;
308 uint32_t fDst;
309 } gSD[] = {
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000310 { SkPictInfo::kCrossProcess_Flag, SkReadBuffer::kCrossProcess_Flag },
311 { SkPictInfo::kScalarIsFloat_Flag, SkReadBuffer::kScalarIsFloat_Flag },
312 { SkPictInfo::kPtrIs64Bit_Flag, SkReadBuffer::kPtrIs64Bit_Flag },
reed@google.com34342f62012-06-25 14:36:28 +0000313 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000314
reed@google.com34342f62012-06-25 14:36:28 +0000315 uint32_t rbMask = 0;
316 for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
317 if (pictInfoFlags & gSD[i].fSrc) {
318 rbMask |= gSD[i].fDst;
319 }
320 }
321 return rbMask;
322}
323
robertphillipsdb539902014-07-01 08:47:04 -0700324bool SkPictureData::parseStreamTag(SkStream* stream,
robertphillipsce4dd3d2014-07-07 13:46:35 -0700325 uint32_t tag,
326 uint32_t size,
327 SkPicture::InstallPixelRefProc proc) {
reed@google.com67562092012-06-22 15:38:39 +0000328 /*
329 * By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
330 * its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
331 * but if they are present, they need to have been seen before the buffer.
332 *
333 * We assert that if/when we see either of these, that we have not yet seen
334 * the buffer tag, because if we have, then its too-late to deal with the
335 * factories or typefaces.
336 */
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000337 SkDEBUGCODE(bool haveBuffer = false;)
reed@google.com67562092012-06-22 15:38:39 +0000338
339 switch (tag) {
reed9594da12014-09-12 12:12:27 -0700340 case SK_PICT_READER_TAG:
341 SkASSERT(NULL == fOpData);
342 fOpData = SkData::NewFromStream(stream, size);
343 if (!fOpData) {
scroggo@google.com12705322013-10-01 15:30:46 +0000344 return false;
345 }
reed9594da12014-09-12 12:12:27 -0700346 break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000347 case SK_PICT_FACTORY_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000348 SkASSERT(!haveBuffer);
mtklein88fd0fb2014-12-01 06:56:38 -0800349 size = stream->readU32();
reed@google.com67562092012-06-22 15:38:39 +0000350 fFactoryPlayback = SkNEW_ARGS(SkFactoryPlayback, (size));
351 for (size_t i = 0; i < size; i++) {
352 SkString str;
scroggo@google.com12705322013-10-01 15:30:46 +0000353 const size_t len = stream->readPackedUInt();
reed@google.com67562092012-06-22 15:38:39 +0000354 str.resize(len);
scroggo@google.com12705322013-10-01 15:30:46 +0000355 if (stream->read(str.writable_str(), len) != len) {
356 return false;
357 }
reed@google.com67562092012-06-22 15:38:39 +0000358 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
359 }
360 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000361 case SK_PICT_TYPEFACE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000362 SkASSERT(!haveBuffer);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000363 const int count = SkToInt(size);
364 fTFPlayback.setCount(count);
365 for (int i = 0; i < count; i++) {
reed@google.com73c0abc2013-04-22 13:47:40 +0000366 SkAutoTUnref<SkTypeface> tf(SkTypeface::Deserialize(stream));
367 if (!tf.get()) { // failed to deserialize
368 // fTFPlayback asserts it never has a null, so we plop in
369 // the default here.
370 tf.reset(SkTypeface::RefDefault());
371 }
372 fTFPlayback.set(i, tf);
reed@google.com67562092012-06-22 15:38:39 +0000373 }
374 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000375 case SK_PICT_PICTURE_TAG: {
fmalita5479d3b2015-07-29 14:40:06 -0700376 fPictureCount = 0;
377 fPictureRefs = SkNEW_ARRAY(const SkPicture*, size);
378 for (uint32_t i = 0; i < size; i++) {
scroggo@google.comf1754ec2013-06-28 21:32:00 +0000379 fPictureRefs[i] = SkPicture::CreateFromStream(stream, proc);
fmalita5479d3b2015-07-29 14:40:06 -0700380 if (!fPictureRefs[i]) {
381 return false;
scroggo@google.com12705322013-10-01 15:30:46 +0000382 }
fmalita5479d3b2015-07-29 14:40:06 -0700383 fPictureCount++;
reed@google.com67562092012-06-22 15:38:39 +0000384 }
385 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000386 case SK_PICT_BUFFER_SIZE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000387 SkAutoMalloc storage(size);
scroggo@google.com12705322013-10-01 15:30:46 +0000388 if (stream->read(storage.get(), size) != size) {
389 return false;
390 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000391
reedac6a2f92014-11-12 09:25:25 -0800392 /* Should we use SkValidatingReadBuffer instead? */
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000393 SkReadBuffer buffer(storage.get(), size);
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000394 buffer.setFlags(pictInfoFlagsToReadBufferFlags(fInfo.fFlags));
commit-bot@chromium.org7ed173b2014-05-20 17:31:08 +0000395 buffer.setVersion(fInfo.fVersion);
reed@google.com34342f62012-06-25 14:36:28 +0000396
reed@google.com67562092012-06-22 15:38:39 +0000397 fFactoryPlayback->setupBuffer(buffer);
398 fTFPlayback.setupBuffer(buffer);
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000399 buffer.setBitmapDecoder(proc);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000400
reedac6a2f92014-11-12 09:25:25 -0800401 while (!buffer.eof() && buffer.isValid()) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000402 tag = buffer.readUInt();
403 size = buffer.readUInt();
robertphillipse26e65e2014-06-12 05:51:22 -0700404 if (!this->parseBufferTag(buffer, tag, size)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000405 return false;
406 }
reed@google.com67562092012-06-22 15:38:39 +0000407 }
reedac6a2f92014-11-12 09:25:25 -0800408 if (!buffer.isValid()) {
409 return false;
410 }
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000411 SkDEBUGCODE(haveBuffer = true;)
reed@google.com67562092012-06-22 15:38:39 +0000412 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000413 }
scroggo@google.com12705322013-10-01 15:30:46 +0000414 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415}
416
reed871872f2015-06-22 12:48:26 -0700417static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) {
418 int width = buffer.read32();
419 int height = buffer.read32();
420 if (width <= 0 || height <= 0) { // SkImage never has a zero dimension
421 buffer.validate(false);
422 return NULL;
423 }
424
425 SkAutoTUnref<SkData> encoded(buffer.readByteArrayAsData());
426 int originX = buffer.read32();
427 int originY = buffer.read32();
428 if (0 == encoded->size() || originX < 0 || originY < 0) {
429 buffer.validate(false);
430 return NULL;
431 }
432
433 const SkIRect subset = SkIRect::MakeXYWH(originX, originY, width, height);
434 return SkImage::NewFromEncoded(encoded, &subset);
435}
436
437// Need a shallow wrapper to return const SkPicture* to match the other factories,
438// as SkPicture::CreateFromBuffer() returns SkPicture*
439static const SkPicture* create_picture_from_buffer(SkReadBuffer& buffer) {
440 return SkPicture::CreateFromBuffer(buffer);
441}
442
443template <typename T>
444bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount,
445 const T*** array, int* outCount, const T* (*factory)(SkReadBuffer&)) {
446 if (!buffer.validate((0 == *outCount) && (NULL == *array))) {
447 return false;
448 }
449 if (0 == inCount) {
450 return true;
451 }
452 *outCount = inCount;
453 *array = SkNEW_ARRAY(const T*, *outCount);
454 bool success = true;
455 int i = 0;
456 for (; i < *outCount; i++) {
457 (*array)[i] = factory(buffer);
458 if (NULL == (*array)[i]) {
459 success = false;
460 break;
461 }
462 }
463 if (!success) {
464 // Delete all of the blobs that were already created (up to but excluding i):
465 for (int j = 0; j < i; j++) {
466 (*array)[j]->unref();
467 }
468 // Delete the array
469 SkDELETE_ARRAY(*array);
470 *array = NULL;
471 *outCount = 0;
472 return false;
473 }
474 return true;
475}
476
477bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) {
reed@google.com67562092012-06-22 15:38:39 +0000478 switch (tag) {
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000479 case SK_PICT_BITMAP_BUFFER_TAG: {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000480 const int count = SkToInt(size);
mtklein703d3c72014-11-12 11:08:20 -0800481 fBitmaps.reset(count);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000482 for (int i = 0; i < count; ++i) {
mtklein703d3c72014-11-12 11:08:20 -0800483 SkBitmap* bm = &fBitmaps[i];
reedac6a2f92014-11-12 09:25:25 -0800484 if (buffer.readBitmap(bm)) {
485 bm->setImmutable();
486 } else {
487 return false;
488 }
reed@google.com67562092012-06-22 15:38:39 +0000489 }
490 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000491 case SK_PICT_PAINT_BUFFER_TAG: {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000492 const int count = SkToInt(size);
mtklein703d3c72014-11-12 11:08:20 -0800493 fPaints.reset(count);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000494 for (int i = 0; i < count; ++i) {
mtklein703d3c72014-11-12 11:08:20 -0800495 buffer.readPaint(&fPaints[i]);
reed@google.com67562092012-06-22 15:38:39 +0000496 }
497 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000498 case SK_PICT_PATH_BUFFER_TAG:
robertphillipse26e65e2014-06-12 05:51:22 -0700499 if (size > 0) {
mtklein71a23632014-11-12 10:24:55 -0800500 const int count = buffer.readInt();
mtklein703d3c72014-11-12 11:08:20 -0800501 fPaths.reset(count);
mtklein71a23632014-11-12 10:24:55 -0800502 for (int i = 0; i < count; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800503 buffer.readPath(&fPaths[i]);
mtklein71a23632014-11-12 10:24:55 -0800504 }
505 } break;
reed871872f2015-06-22 12:48:26 -0700506 case SK_PICT_TEXTBLOB_BUFFER_TAG:
507 if (!new_array_from_buffer(buffer, size, &fTextBlobRefs, &fTextBlobCount,
508 SkTextBlob::CreateFromBuffer)) {
fmalitab7425172014-08-26 07:56:44 -0700509 return false;
510 }
reed871872f2015-06-22 12:48:26 -0700511 break;
512 case SK_PICT_IMAGE_BUFFER_TAG:
513 if (!new_array_from_buffer(buffer, size, &fImageRefs, &fImageCount,
514 create_image_from_buffer)) {
fmalitab7425172014-08-26 07:56:44 -0700515 return false;
516 }
reed871872f2015-06-22 12:48:26 -0700517 break;
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000518 case SK_PICT_READER_TAG: {
reed9594da12014-09-12 12:12:27 -0700519 SkAutoDataUnref data(SkData::NewUninitialized(size));
520 if (!buffer.readByteArray(data->writable_data(), size) ||
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000521 !buffer.validate(NULL == fOpData)) {
522 return false;
523 }
524 SkASSERT(NULL == fOpData);
reed9594da12014-09-12 12:12:27 -0700525 fOpData = data.detach();
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000526 } break;
reed871872f2015-06-22 12:48:26 -0700527 case SK_PICT_PICTURE_TAG:
528 if (!new_array_from_buffer(buffer, size, &fPictureRefs, &fPictureCount,
529 create_picture_from_buffer)) {
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000530 return false;
531 }
reedc2100352015-06-22 17:03:10 -0700532 break;
scroggo@google.com12705322013-10-01 15:30:46 +0000533 default:
534 // The tag was invalid.
535 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536 }
scroggo@google.com12705322013-10-01 15:30:46 +0000537 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538}
539
robertphillipsdb539902014-07-01 08:47:04 -0700540SkPictureData* SkPictureData::CreateFromStream(SkStream* stream,
541 const SkPictInfo& info,
542 SkPicture::InstallPixelRefProc proc) {
543 SkAutoTDelete<SkPictureData> data(SkNEW_ARGS(SkPictureData, (info)));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544
robertphillipsdb539902014-07-01 08:47:04 -0700545 if (!data->parseStream(stream, proc)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000546 return NULL;
547 }
robertphillipsdb539902014-07-01 08:47:04 -0700548 return data.detach();
scroggo@google.com12705322013-10-01 15:30:46 +0000549}
550
robertphillipsdb539902014-07-01 08:47:04 -0700551SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer,
552 const SkPictInfo& info) {
553 SkAutoTDelete<SkPictureData> data(SkNEW_ARGS(SkPictureData, (info)));
commit-bot@chromium.org7ed173b2014-05-20 17:31:08 +0000554 buffer.setVersion(info.fVersion);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000555
robertphillipsdb539902014-07-01 08:47:04 -0700556 if (!data->parseBuffer(buffer)) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000557 return NULL;
558 }
robertphillipsdb539902014-07-01 08:47:04 -0700559 return data.detach();
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000560}
561
robertphillipsdb539902014-07-01 08:47:04 -0700562bool SkPictureData::parseStream(SkStream* stream,
563 SkPicture::InstallPixelRefProc proc) {
reed@google.com67562092012-06-22 15:38:39 +0000564 for (;;) {
565 uint32_t tag = stream->readU32();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000566 if (SK_PICT_EOF_TAG == tag) {
reed@google.com67562092012-06-22 15:38:39 +0000567 break;
568 }
reed@google.com82065d62011-02-07 15:30:46 +0000569
reed@google.comed384952012-06-22 13:12:17 +0000570 uint32_t size = stream->readU32();
robertphillipse26e65e2014-06-12 05:51:22 -0700571 if (!this->parseStreamTag(stream, tag, size, proc)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000572 return false; // we're invalid
573 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574 }
scroggo@google.com12705322013-10-01 15:30:46 +0000575 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576}
577
robertphillipsdb539902014-07-01 08:47:04 -0700578bool SkPictureData::parseBuffer(SkReadBuffer& buffer) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000579 for (;;) {
580 uint32_t tag = buffer.readUInt();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000581 if (SK_PICT_EOF_TAG == tag) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000582 break;
583 }
584
585 uint32_t size = buffer.readUInt();
robertphillipse26e65e2014-06-12 05:51:22 -0700586 if (!this->parseBufferTag(buffer, tag, size)) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000587 return false; // we're invalid
588 }
589 }
590 return true;
591}
592
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593///////////////////////////////////////////////////////////////////////////////
594///////////////////////////////////////////////////////////////////////////////
595
robertphillips0bdbea72014-06-11 11:37:55 -0700596#if SK_SUPPORT_GPU
robertphillipsdb539902014-07-01 08:47:04 -0700597bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
hendrikwafdada22014-08-08 10:44:33 -0700598 int sampleCount) const {
599 return fContentInfo.suitableForGpuRasterization(context, reason, sampleCount);
robertphillips0bdbea72014-06-11 11:37:55 -0700600}
egdaniel12c21982014-06-18 07:34:39 -0700601
robertphillipsdb539902014-07-01 08:47:04 -0700602bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
603 GrPixelConfig config, SkScalar dpi) const {
egdaniel12c21982014-06-18 07:34:39 -0700604
605 if (context != NULL) {
606 return this->suitableForGpuRasterization(context, reason,
607 context->getRecommendedSampleCount(config, dpi));
608 } else {
609 return this->suitableForGpuRasterization(NULL, reason);
610 }
611}
612
robertphillipsc019ec42014-08-12 05:35:58 -0700613bool SkPictureData::suitableForLayerOptimization() const {
614 return fContentInfo.numLayers() > 0;
615}
robertphillips0bdbea72014-06-11 11:37:55 -0700616#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000617///////////////////////////////////////////////////////////////////////////////
618
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619