blob: 9780b7d104060928436d9d9c361f7845464d5682 [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 */
Hal Canary95e3c052017-01-11 12:44:43 -05007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include <new>
Hal Canary95e3c052017-01-11 12:44:43 -05009
10#include "SkAutoMalloc.h"
fmalitac3470342015-09-04 11:36:39 -070011#include "SkImageGenerator.h"
robertphillipsdb539902014-07-01 08:47:04 -070012#include "SkPictureData.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000013#include "SkPictureRecord.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000014#include "SkReadBuffer.h"
fmalitab7425172014-08-26 07:56:44 -070015#include "SkTextBlob.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000016#include "SkTypeface.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000017#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000018
egdaniel12c21982014-06-18 07:34:39 -070019#if SK_SUPPORT_GPU
20#include "GrContext.h"
21#endif
22
reed@google.comf4cc1872012-07-23 15:04:45 +000023template <typename T> int SafeCount(const T* obj) {
24 return obj ? obj->count() : 0;
25}
26
robertphillipsdb539902014-07-01 08:47:04 -070027SkPictureData::SkPictureData(const SkPictInfo& info)
robertphillipse26e65e2014-06-12 05:51:22 -070028 : fInfo(info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 this->init();
30}
31
robertphillipsdb539902014-07-01 08:47:04 -070032void SkPictureData::initForPlayback() const {
robertphillipse26e65e2014-06-12 05:51:22 -070033 // ensure that the paths bounds are pre-computed
mtklein703d3c72014-11-12 11:08:20 -080034 for (int i = 0; i < fPaths.count(); i++) {
35 fPaths[i].updateBoundsCache();
robertphillipse26e65e2014-06-12 05:51:22 -070036 }
37}
38
robertphillipsdb539902014-07-01 08:47:04 -070039SkPictureData::SkPictureData(const SkPictureRecord& record,
mtklein4d9ff622016-04-29 14:45:36 -070040 const SkPictInfo& info)
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
mtklein4d9ff622016-04-29 14:45:36 -070045 fOpData = record.opData();
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 fPaints = record.fPaints;
mtkleinc2e29772015-10-30 05:24:58 -070050
51 fPaths.reset(record.fPaths.count());
52 record.fPaths.foreach([this](const SkPath& path, int n) {
53 // These indices are logically 1-based, but we need to serialize them
54 // 0-based to keep the deserializing SkPictureData::getPath() working.
55 fPaths[n-1] = path;
56 });
djsollen@google.comc9ab9872012-08-29 18:52:07 +000057
robertphillipse26e65e2014-06-12 05:51:22 -070058 this->initForPlayback();
reed@android.com8a1c16f2008-12-17 15:59:43 +000059
robertphillips9b14f262014-06-04 05:40:44 -070060 const SkTDArray<const SkPicture* >& pictures = record.getPictureRefs();
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 fPictureCount = pictures.count();
62 if (fPictureCount > 0) {
halcanary385fe4d2015-08-26 13:07:48 -070063 fPictureRefs = new const SkPicture* [fPictureCount];
reed@android.com8a1c16f2008-12-17 15:59:43 +000064 for (int i = 0; i < fPictureCount; i++) {
robertphillips6de27122014-06-10 09:23:06 -070065 fPictureRefs[i] = pictures[i];
66 fPictureRefs[i]->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 }
68 }
fmalitab7425172014-08-26 07:56:44 -070069
msarett95416f42016-04-27 13:51:20 -070070 const SkTDArray<SkDrawable* >& drawables = record.getDrawableRefs();
71 fDrawableCount = drawables.count();
72 if (fDrawableCount > 0) {
73 fDrawableRefs = new SkDrawable* [fDrawableCount];
74 for (int i = 0; i < fDrawableCount; i++) {
75 fDrawableRefs[i] = drawables[i];
76 fDrawableRefs[i]->ref();
77 }
78 }
79
fmalitab7425172014-08-26 07:56:44 -070080 // templatize to consolidate with similar picture logic?
81 const SkTDArray<const SkTextBlob*>& blobs = record.getTextBlobRefs();
82 fTextBlobCount = blobs.count();
83 if (fTextBlobCount > 0) {
halcanary385fe4d2015-08-26 13:07:48 -070084 fTextBlobRefs = new const SkTextBlob* [fTextBlobCount];
fmalitab7425172014-08-26 07:56:44 -070085 for (int i = 0; i < fTextBlobCount; ++i) {
86 fTextBlobRefs[i] = SkRef(blobs[i]);
87 }
88 }
mtklein0c263fa2015-08-18 08:29:59 -070089
reed871872f2015-06-22 12:48:26 -070090 const SkTDArray<const SkImage*>& imgs = record.getImageRefs();
91 fImageCount = imgs.count();
92 if (fImageCount > 0) {
halcanary385fe4d2015-08-26 13:07:48 -070093 fImageRefs = new const SkImage* [fImageCount];
reed871872f2015-06-22 12:48:26 -070094 for (int i = 0; i < fImageCount; ++i) {
95 fImageRefs[i] = SkRef(imgs[i]);
96 }
97 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000098}
99
robertphillipsdb539902014-07-01 08:47:04 -0700100void SkPictureData::init() {
halcanary96fcdcc2015-08-27 07:41:13 -0700101 fPictureRefs = nullptr;
reed@google.comf4cc1872012-07-23 15:04:45 +0000102 fPictureCount = 0;
msarett95416f42016-04-27 13:51:20 -0700103 fDrawableRefs = nullptr;
104 fDrawableCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700105 fTextBlobRefs = nullptr;
fmalitab7425172014-08-26 07:56:44 -0700106 fTextBlobCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700107 fImageRefs = nullptr;
reed871872f2015-06-22 12:48:26 -0700108 fImageCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700109 fFactoryPlayback = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110}
111
robertphillipsdb539902014-07-01 08:47:04 -0700112SkPictureData::~SkPictureData() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113 for (int i = 0; i < fPictureCount; i++) {
114 fPictureRefs[i]->unref();
115 }
halcanary385fe4d2015-08-26 13:07:48 -0700116 delete[] fPictureRefs;
reed@google.com82065d62011-02-07 15:30:46 +0000117
msarett95416f42016-04-27 13:51:20 -0700118 for (int i = 0; i < fDrawableCount; i++) {
119 fDrawableRefs[i]->unref();
120 }
121 if (fDrawableCount > 0) {
122 SkASSERT(fDrawableRefs);
123 delete[] fDrawableRefs;
124 }
125
fmalitab7425172014-08-26 07:56:44 -0700126 for (int i = 0; i < fTextBlobCount; i++) {
127 fTextBlobRefs[i]->unref();
128 }
halcanary385fe4d2015-08-26 13:07:48 -0700129 delete[] fTextBlobRefs;
mtklein0c263fa2015-08-18 08:29:59 -0700130
reed871872f2015-06-22 12:48:26 -0700131 for (int i = 0; i < fImageCount; i++) {
132 fImageRefs[i]->unref();
133 }
halcanary385fe4d2015-08-26 13:07:48 -0700134 delete[] fImageRefs;
mtklein0c263fa2015-08-18 08:29:59 -0700135
halcanary385fe4d2015-08-26 13:07:48 -0700136 delete fFactoryPlayback;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137}
138
robertphillipsdb539902014-07-01 08:47:04 -0700139bool SkPictureData::containsBitmaps() const {
reeda9ca05c2016-08-11 03:55:15 -0700140 if (fBitmapImageCount > 0 || fImageCount > 0) {
tomhudson@google.com381010e2013-10-24 11:12:47 +0000141 return true;
142 }
143 for (int i = 0; i < fPictureCount; ++i) {
144 if (fPictureRefs[i]->willPlayBackBitmaps()) {
145 return true;
146 }
147 }
148 return false;
149}
150
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151///////////////////////////////////////////////////////////////////////////////
152///////////////////////////////////////////////////////////////////////////////
153
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154#include "SkStream.h"
155
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000156static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) {
157 size_t size = 4; // for 'count'
reed@google.com82065d62011-02-07 15:30:46 +0000158
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000159 for (int i = 0; i < count; i++) {
160 const char* name = SkFlattenable::FactoryToName(array[i]);
halcanary96fcdcc2015-08-27 07:41:13 -0700161 if (nullptr == name || 0 == *name) {
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000162 size += SkWStream::SizeOfPackedUInt(0);
163 } else {
164 size_t len = strlen(name);
165 size += SkWStream::SizeOfPackedUInt(len);
166 size += len;
167 }
168 }
169
170 return size;
171}
172
robertphillips61426092014-07-10 09:35:12 -0700173static void write_tag_size(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
174 buffer.writeUInt(tag);
175 buffer.writeUInt(SkToU32(size));
176}
177
178static void write_tag_size(SkWStream* stream, uint32_t tag, size_t size) {
179 stream->write32(tag);
180 stream->write32(SkToU32(size));
181}
182
robertphillipsdb539902014-07-01 08:47:04 -0700183void SkPictureData::WriteFactories(SkWStream* stream, const SkFactorySet& rec) {
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000184 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000185
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
187 SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000188 rec.copyToArray(array);
reed@google.com82065d62011-02-07 15:30:46 +0000189
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000190 size_t size = compute_chunk_size(array, count);
191
192 // TODO: write_tag_size should really take a size_t
robertphillips61426092014-07-10 09:35:12 -0700193 write_tag_size(stream, SK_PICT_FACTORY_TAG, (uint32_t) size);
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000194 SkDEBUGCODE(size_t start = stream->bytesWritten());
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000195 stream->write32(count);
196
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 for (int i = 0; i < count; i++) {
198 const char* name = SkFlattenable::FactoryToName(array[i]);
halcanary96fcdcc2015-08-27 07:41:13 -0700199 if (nullptr == name || 0 == *name) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 stream->writePackedUInt(0);
201 } else {
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +0000202 size_t len = strlen(name);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 stream->writePackedUInt(len);
204 stream->write(name, len);
205 }
206 }
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000207
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000208 SkASSERT(size == (stream->bytesWritten() - start));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209}
210
robertphillipsdb539902014-07-01 08:47:04 -0700211void SkPictureData::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000213
robertphillips61426092014-07-10 09:35:12 -0700214 write_tag_size(stream, SK_PICT_TYPEFACE_TAG, count);
reed@google.com82065d62011-02-07 15:30:46 +0000215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 SkAutoSTMalloc<16, SkTypeface*> storage(count);
217 SkTypeface** array = (SkTypeface**)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000218 rec.copyToArray((SkRefCnt**)array);
reed@google.com82065d62011-02-07 15:30:46 +0000219
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 for (int i = 0; i < count; i++) {
221 array[i]->serialize(stream);
222 }
223}
224
robertphillipsdb539902014-07-01 08:47:04 -0700225void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const {
reed@google.comf4cc1872012-07-23 15:04:45 +0000226 int i, n;
reed@google.com82065d62011-02-07 15:30:46 +0000227
mtklein703d3c72014-11-12 11:08:20 -0800228 if ((n = fPaints.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700229 write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, n);
reed@google.comf4cc1872012-07-23 15:04:45 +0000230 for (i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800231 buffer.writePaint(fPaints[i]);
reed@google.com67562092012-06-22 15:38:39 +0000232 }
233 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000234
mtklein703d3c72014-11-12 11:08:20 -0800235 if ((n = fPaths.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700236 write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, n);
mtklein71a23632014-11-12 10:24:55 -0800237 buffer.writeInt(n);
238 for (int i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800239 buffer.writePath(fPaths[i]);
mtklein71a23632014-11-12 10:24:55 -0800240 }
robertphillipse26e65e2014-06-12 05:51:22 -0700241 }
fmalitab7425172014-08-26 07:56:44 -0700242
243 if (fTextBlobCount > 0) {
244 write_tag_size(buffer, SK_PICT_TEXTBLOB_BUFFER_TAG, fTextBlobCount);
245 for (i = 0; i < fTextBlobCount; ++i) {
246 fTextBlobRefs[i]->flatten(buffer);
247 }
248 }
mtklein0c263fa2015-08-18 08:29:59 -0700249
reed871872f2015-06-22 12:48:26 -0700250 if (fImageCount > 0) {
251 write_tag_size(buffer, SK_PICT_IMAGE_BUFFER_TAG, fImageCount);
252 for (i = 0; i < fImageCount; ++i) {
253 buffer.writeImage(fImageRefs[i]);
254 }
255 }
reed@google.com67562092012-06-22 15:38:39 +0000256}
reed@google.com82065d62011-02-07 15:30:46 +0000257
robertphillipsdb539902014-07-01 08:47:04 -0700258void SkPictureData::serialize(SkWStream* stream,
mtklein0c263fa2015-08-18 08:29:59 -0700259 SkPixelSerializer* pixelSerializer,
260 SkRefCntSet* topLevelTypeFaceSet) const {
261 // This can happen at pretty much any time, so might as well do it first.
robertphillips61426092014-07-10 09:35:12 -0700262 write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size());
reed@google.comddf98a82012-07-21 20:31:09 +0000263 stream->write(fOpData->bytes(), fOpData->size());
reed@google.com67562092012-06-22 15:38:39 +0000264
mtklein0c263fa2015-08-18 08:29:59 -0700265 // We serialize all typefaces into the typeface section of the top-level picture.
266 SkRefCntSet localTypefaceSet;
267 SkRefCntSet* typefaceSet = topLevelTypeFaceSet ? topLevelTypeFaceSet : &localTypefaceSet;
268
269 // We delay serializing the bulk of our data until after we've serialized
270 // factories and typefaces by first serializing to an in-memory write buffer.
271 SkFactorySet factSet; // buffer refs factSet, so factSet must come first.
brianosmanfad98562016-05-04 11:06:28 -0700272 SkBinaryWriteBuffer buffer(SkBinaryWriteBuffer::kCrossProcess_Flag);
mtklein0c263fa2015-08-18 08:29:59 -0700273 buffer.setFactoryRecorder(&factSet);
bungeman6bd52842016-10-27 09:30:08 -0700274 buffer.setPixelSerializer(sk_ref_sp(pixelSerializer));
mtklein0c263fa2015-08-18 08:29:59 -0700275 buffer.setTypefaceRecorder(typefaceSet);
276 this->flattenToBuffer(buffer);
277
278 // Dummy serialize our sub-pictures for the side effect of filling
279 // typefaceSet with typefaces from sub-pictures.
280 struct DevNull: public SkWStream {
281 DevNull() : fBytesWritten(0) {}
282 size_t fBytesWritten;
283 bool write(const void*, size_t size) override { fBytesWritten += size; return true; }
284 size_t bytesWritten() const override { return fBytesWritten; }
285 } devnull;
286 for (int i = 0; i < fPictureCount; i++) {
287 fPictureRefs[i]->serialize(&devnull, pixelSerializer, typefaceSet);
288 }
289
290 // We need to write factories before we write the buffer.
291 // We need to write typefaces before we write the buffer or any sub-picture.
292 WriteFactories(stream, factSet);
293 if (typefaceSet == &localTypefaceSet) {
294 WriteTypefaces(stream, *typefaceSet);
295 }
296
297 // Write the buffer.
298 write_tag_size(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten());
299 buffer.writeToStream(stream);
300
301 // Write sub-pictures by calling serialize again.
reed@google.com67562092012-06-22 15:38:39 +0000302 if (fPictureCount > 0) {
robertphillips61426092014-07-10 09:35:12 -0700303 write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictureCount);
reed@google.com67562092012-06-22 15:38:39 +0000304 for (int i = 0; i < fPictureCount; i++) {
mtklein0c263fa2015-08-18 08:29:59 -0700305 fPictureRefs[i]->serialize(stream, pixelSerializer, typefaceSet);
reed@google.com67562092012-06-22 15:38:39 +0000306 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000307 }
reed@google.com82065d62011-02-07 15:30:46 +0000308
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000309 stream->write32(SK_PICT_EOF_TAG);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310}
311
robertphillipsdb539902014-07-01 08:47:04 -0700312void SkPictureData::flatten(SkWriteBuffer& buffer) const {
robertphillips61426092014-07-10 09:35:12 -0700313 write_tag_size(buffer, SK_PICT_READER_TAG, fOpData->size());
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000314 buffer.writeByteArray(fOpData->bytes(), fOpData->size());
315
316 if (fPictureCount > 0) {
robertphillips61426092014-07-10 09:35:12 -0700317 write_tag_size(buffer, SK_PICT_PICTURE_TAG, fPictureCount);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000318 for (int i = 0; i < fPictureCount; i++) {
319 fPictureRefs[i]->flatten(buffer);
320 }
321 }
322
msarett95416f42016-04-27 13:51:20 -0700323 if (fDrawableCount > 0) {
324 write_tag_size(buffer, SK_PICT_DRAWABLE_TAG, fDrawableCount);
325 for (int i = 0; i < fDrawableCount; i++) {
326 buffer.writeFlattenable(fDrawableRefs[i]);
327 }
328 }
329
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000330 // Write this picture playback's data into a writebuffer
331 this->flattenToBuffer(buffer);
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000332 buffer.write32(SK_PICT_EOF_TAG);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000333}
334
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335///////////////////////////////////////////////////////////////////////////////
336
reed@google.com34342f62012-06-25 14:36:28 +0000337/**
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000338 * Return the corresponding SkReadBuffer flags, given a set of
reed@google.com34342f62012-06-25 14:36:28 +0000339 * SkPictInfo flags.
340 */
341static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
342 static const struct {
343 uint32_t fSrc;
344 uint32_t fDst;
345 } gSD[] = {
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000346 { SkPictInfo::kCrossProcess_Flag, SkReadBuffer::kCrossProcess_Flag },
347 { SkPictInfo::kScalarIsFloat_Flag, SkReadBuffer::kScalarIsFloat_Flag },
348 { SkPictInfo::kPtrIs64Bit_Flag, SkReadBuffer::kPtrIs64Bit_Flag },
reed@google.com34342f62012-06-25 14:36:28 +0000349 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000350
reed@google.com34342f62012-06-25 14:36:28 +0000351 uint32_t rbMask = 0;
352 for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
353 if (pictInfoFlags & gSD[i].fSrc) {
354 rbMask |= gSD[i].fDst;
355 }
356 }
357 return rbMask;
358}
359
robertphillipsdb539902014-07-01 08:47:04 -0700360bool SkPictureData::parseStreamTag(SkStream* stream,
robertphillipsce4dd3d2014-07-07 13:46:35 -0700361 uint32_t tag,
362 uint32_t size,
reeda9ca05c2016-08-11 03:55:15 -0700363 SkImageDeserializer* factory,
mtklein0c263fa2015-08-18 08:29:59 -0700364 SkTypefacePlayback* topLevelTFPlayback) {
reed@google.com67562092012-06-22 15:38:39 +0000365 /*
366 * By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
367 * its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
368 * but if they are present, they need to have been seen before the buffer.
369 *
370 * We assert that if/when we see either of these, that we have not yet seen
371 * the buffer tag, because if we have, then its too-late to deal with the
372 * factories or typefaces.
373 */
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000374 SkDEBUGCODE(bool haveBuffer = false;)
reed@google.com67562092012-06-22 15:38:39 +0000375
376 switch (tag) {
reed9594da12014-09-12 12:12:27 -0700377 case SK_PICT_READER_TAG:
halcanary96fcdcc2015-08-27 07:41:13 -0700378 SkASSERT(nullptr == fOpData);
reedfde05112016-03-11 13:02:28 -0800379 fOpData = SkData::MakeFromStream(stream, size);
reed9594da12014-09-12 12:12:27 -0700380 if (!fOpData) {
scroggo@google.com12705322013-10-01 15:30:46 +0000381 return false;
382 }
reed9594da12014-09-12 12:12:27 -0700383 break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000384 case SK_PICT_FACTORY_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000385 SkASSERT(!haveBuffer);
mtklein88fd0fb2014-12-01 06:56:38 -0800386 size = stream->readU32();
halcanary385fe4d2015-08-26 13:07:48 -0700387 fFactoryPlayback = new SkFactoryPlayback(size);
reed@google.com67562092012-06-22 15:38:39 +0000388 for (size_t i = 0; i < size; i++) {
389 SkString str;
scroggo@google.com12705322013-10-01 15:30:46 +0000390 const size_t len = stream->readPackedUInt();
reed@google.com67562092012-06-22 15:38:39 +0000391 str.resize(len);
scroggo@google.com12705322013-10-01 15:30:46 +0000392 if (stream->read(str.writable_str(), len) != len) {
393 return false;
394 }
reed@google.com67562092012-06-22 15:38:39 +0000395 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
396 }
397 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000398 case SK_PICT_TYPEFACE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000399 SkASSERT(!haveBuffer);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000400 const int count = SkToInt(size);
401 fTFPlayback.setCount(count);
402 for (int i = 0; i < count; i++) {
bungeman13b9c952016-05-12 10:09:30 -0700403 sk_sp<SkTypeface> tf(SkTypeface::MakeDeserialize(stream));
reed@google.com73c0abc2013-04-22 13:47:40 +0000404 if (!tf.get()) { // failed to deserialize
405 // fTFPlayback asserts it never has a null, so we plop in
406 // the default here.
bungeman13b9c952016-05-12 10:09:30 -0700407 tf = SkTypeface::MakeDefault();
reed@google.com73c0abc2013-04-22 13:47:40 +0000408 }
bungeman13b9c952016-05-12 10:09:30 -0700409 fTFPlayback.set(i, tf.get());
reed@google.com67562092012-06-22 15:38:39 +0000410 }
411 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000412 case SK_PICT_PICTURE_TAG: {
fmalita5479d3b2015-07-29 14:40:06 -0700413 fPictureCount = 0;
halcanary385fe4d2015-08-26 13:07:48 -0700414 fPictureRefs = new const SkPicture* [size];
fmalita5479d3b2015-07-29 14:40:06 -0700415 for (uint32_t i = 0; i < size; i++) {
reeda9ca05c2016-08-11 03:55:15 -0700416 fPictureRefs[i] = SkPicture::MakeFromStream(stream, factory, topLevelTFPlayback).release();
fmalita5479d3b2015-07-29 14:40:06 -0700417 if (!fPictureRefs[i]) {
418 return false;
scroggo@google.com12705322013-10-01 15:30:46 +0000419 }
fmalita5479d3b2015-07-29 14:40:06 -0700420 fPictureCount++;
reed@google.com67562092012-06-22 15:38:39 +0000421 }
422 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000423 case SK_PICT_BUFFER_SIZE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000424 SkAutoMalloc storage(size);
scroggo@google.com12705322013-10-01 15:30:46 +0000425 if (stream->read(storage.get(), size) != size) {
426 return false;
427 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000428
reedac6a2f92014-11-12 09:25:25 -0800429 /* Should we use SkValidatingReadBuffer instead? */
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000430 SkReadBuffer buffer(storage.get(), size);
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000431 buffer.setFlags(pictInfoFlagsToReadBufferFlags(fInfo.fFlags));
Mike Reedb3f543d2016-10-04 15:12:01 -0400432 buffer.setVersion(fInfo.getVersion());
reed@google.com34342f62012-06-25 14:36:28 +0000433
caryclark46895be2016-01-21 06:54:46 -0800434 if (!fFactoryPlayback) {
435 return false;
436 }
reed@google.com67562092012-06-22 15:38:39 +0000437 fFactoryPlayback->setupBuffer(buffer);
reeda9ca05c2016-08-11 03:55:15 -0700438 buffer.setImageDeserializer(factory);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000439
mtklein0c263fa2015-08-18 08:29:59 -0700440 if (fTFPlayback.count() > 0) {
441 // .skp files <= v43 have typefaces serialized with each sub picture.
442 fTFPlayback.setupBuffer(buffer);
443 } else {
444 // Newer .skp files serialize all typefaces with the top picture.
445 topLevelTFPlayback->setupBuffer(buffer);
446 }
447
reedac6a2f92014-11-12 09:25:25 -0800448 while (!buffer.eof() && buffer.isValid()) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000449 tag = buffer.readUInt();
450 size = buffer.readUInt();
robertphillipse26e65e2014-06-12 05:51:22 -0700451 if (!this->parseBufferTag(buffer, tag, size)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000452 return false;
453 }
reed@google.com67562092012-06-22 15:38:39 +0000454 }
reedac6a2f92014-11-12 09:25:25 -0800455 if (!buffer.isValid()) {
456 return false;
457 }
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000458 SkDEBUGCODE(haveBuffer = true;)
reed@google.com67562092012-06-22 15:38:39 +0000459 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460 }
scroggo@google.com12705322013-10-01 15:30:46 +0000461 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000462}
463
reed871872f2015-06-22 12:48:26 -0700464static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) {
reeda9ca05c2016-08-11 03:55:15 -0700465 return buffer.readImage().release();
466}
467
468static const SkImage* create_bitmap_image_from_buffer(SkReadBuffer& buffer) {
469 return buffer.readBitmapAsImage().release();
reed871872f2015-06-22 12:48:26 -0700470}
471
472// Need a shallow wrapper to return const SkPicture* to match the other factories,
473// as SkPicture::CreateFromBuffer() returns SkPicture*
474static const SkPicture* create_picture_from_buffer(SkReadBuffer& buffer) {
reedca2622b2016-03-18 07:25:55 -0700475 return SkPicture::MakeFromBuffer(buffer).release();
reed871872f2015-06-22 12:48:26 -0700476}
477
msarett95416f42016-04-27 13:51:20 -0700478static const SkDrawable* create_drawable_from_buffer(SkReadBuffer& buffer) {
479 return (SkDrawable*) buffer.readFlattenable(SkFlattenable::kSkDrawable_Type);
480}
481
reed871872f2015-06-22 12:48:26 -0700482template <typename T>
483bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount,
484 const T*** array, int* outCount, const T* (*factory)(SkReadBuffer&)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700485 if (!buffer.validate((0 == *outCount) && (nullptr == *array))) {
reed871872f2015-06-22 12:48:26 -0700486 return false;
487 }
488 if (0 == inCount) {
489 return true;
490 }
Robert Phillips20dd31f2016-12-19 12:58:14 -0500491 if (!buffer.validate(SkTFitsIn<int>(inCount))) {
492 return false;
493 }
494
reed871872f2015-06-22 12:48:26 -0700495 *outCount = inCount;
halcanary385fe4d2015-08-26 13:07:48 -0700496 *array = new const T* [*outCount];
reed871872f2015-06-22 12:48:26 -0700497 bool success = true;
498 int i = 0;
499 for (; i < *outCount; i++) {
500 (*array)[i] = factory(buffer);
halcanary96fcdcc2015-08-27 07:41:13 -0700501 if (nullptr == (*array)[i]) {
reed871872f2015-06-22 12:48:26 -0700502 success = false;
503 break;
504 }
505 }
506 if (!success) {
507 // Delete all of the blobs that were already created (up to but excluding i):
508 for (int j = 0; j < i; j++) {
509 (*array)[j]->unref();
510 }
511 // Delete the array
halcanary385fe4d2015-08-26 13:07:48 -0700512 delete[] * array;
halcanary96fcdcc2015-08-27 07:41:13 -0700513 *array = nullptr;
reed871872f2015-06-22 12:48:26 -0700514 *outCount = 0;
515 return false;
516 }
517 return true;
518}
519
520bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) {
reed@google.com67562092012-06-22 15:38:39 +0000521 switch (tag) {
reeda9ca05c2016-08-11 03:55:15 -0700522 case SK_PICT_BITMAP_BUFFER_TAG:
523 if (!new_array_from_buffer(buffer, size, &fBitmapImageRefs, &fBitmapImageCount,
524 create_bitmap_image_from_buffer)) {
525 return false;
reed@google.com67562092012-06-22 15:38:39 +0000526 }
reeda9ca05c2016-08-11 03:55:15 -0700527 break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000528 case SK_PICT_PAINT_BUFFER_TAG: {
Robert Phillips20dd31f2016-12-19 12:58:14 -0500529 if (!buffer.validate(SkTFitsIn<int>(size))) {
530 return false;
531 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000532 const int count = SkToInt(size);
mtklein703d3c72014-11-12 11:08:20 -0800533 fPaints.reset(count);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000534 for (int i = 0; i < count; ++i) {
mtklein703d3c72014-11-12 11:08:20 -0800535 buffer.readPaint(&fPaints[i]);
reed@google.com67562092012-06-22 15:38:39 +0000536 }
537 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000538 case SK_PICT_PATH_BUFFER_TAG:
robertphillipse26e65e2014-06-12 05:51:22 -0700539 if (size > 0) {
mtklein71a23632014-11-12 10:24:55 -0800540 const int count = buffer.readInt();
mtklein703d3c72014-11-12 11:08:20 -0800541 fPaths.reset(count);
mtklein71a23632014-11-12 10:24:55 -0800542 for (int i = 0; i < count; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800543 buffer.readPath(&fPaths[i]);
mtklein71a23632014-11-12 10:24:55 -0800544 }
545 } break;
reed871872f2015-06-22 12:48:26 -0700546 case SK_PICT_TEXTBLOB_BUFFER_TAG:
547 if (!new_array_from_buffer(buffer, size, &fTextBlobRefs, &fTextBlobCount,
548 SkTextBlob::CreateFromBuffer)) {
fmalitab7425172014-08-26 07:56:44 -0700549 return false;
550 }
reed871872f2015-06-22 12:48:26 -0700551 break;
552 case SK_PICT_IMAGE_BUFFER_TAG:
553 if (!new_array_from_buffer(buffer, size, &fImageRefs, &fImageCount,
554 create_image_from_buffer)) {
fmalitab7425172014-08-26 07:56:44 -0700555 return false;
556 }
reed871872f2015-06-22 12:48:26 -0700557 break;
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000558 case SK_PICT_READER_TAG: {
reedfde05112016-03-11 13:02:28 -0800559 auto data(SkData::MakeUninitialized(size));
reed9594da12014-09-12 12:12:27 -0700560 if (!buffer.readByteArray(data->writable_data(), size) ||
halcanary96fcdcc2015-08-27 07:41:13 -0700561 !buffer.validate(nullptr == fOpData)) {
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000562 return false;
563 }
halcanary96fcdcc2015-08-27 07:41:13 -0700564 SkASSERT(nullptr == fOpData);
reedfde05112016-03-11 13:02:28 -0800565 fOpData = std::move(data);
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000566 } break;
reed871872f2015-06-22 12:48:26 -0700567 case SK_PICT_PICTURE_TAG:
568 if (!new_array_from_buffer(buffer, size, &fPictureRefs, &fPictureCount,
569 create_picture_from_buffer)) {
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000570 return false;
571 }
reedc2100352015-06-22 17:03:10 -0700572 break;
msarett95416f42016-04-27 13:51:20 -0700573 case SK_PICT_DRAWABLE_TAG:
574 if (!new_array_from_buffer(buffer, size, (const SkDrawable***)&fDrawableRefs,
575 &fDrawableCount, create_drawable_from_buffer)) {
576 return false;
577 }
578 break;
scroggo@google.com12705322013-10-01 15:30:46 +0000579 default:
580 // The tag was invalid.
581 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000582 }
scroggo@google.com12705322013-10-01 15:30:46 +0000583 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000584}
585
robertphillipsdb539902014-07-01 08:47:04 -0700586SkPictureData* SkPictureData::CreateFromStream(SkStream* stream,
587 const SkPictInfo& info,
reeda9ca05c2016-08-11 03:55:15 -0700588 SkImageDeserializer* factory,
mtklein0c263fa2015-08-18 08:29:59 -0700589 SkTypefacePlayback* topLevelTFPlayback) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400590 std::unique_ptr<SkPictureData> data(new SkPictureData(info));
mtklein0c263fa2015-08-18 08:29:59 -0700591 if (!topLevelTFPlayback) {
592 topLevelTFPlayback = &data->fTFPlayback;
593 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000594
reeda9ca05c2016-08-11 03:55:15 -0700595 if (!data->parseStream(stream, factory, topLevelTFPlayback)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700596 return nullptr;
scroggo@google.com12705322013-10-01 15:30:46 +0000597 }
mtklein18300a32016-03-16 13:53:35 -0700598 return data.release();
scroggo@google.com12705322013-10-01 15:30:46 +0000599}
600
robertphillipsdb539902014-07-01 08:47:04 -0700601SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer,
602 const SkPictInfo& info) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400603 std::unique_ptr<SkPictureData> data(new SkPictureData(info));
Mike Reedb3f543d2016-10-04 15:12:01 -0400604 buffer.setVersion(info.getVersion());
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000605
robertphillipsdb539902014-07-01 08:47:04 -0700606 if (!data->parseBuffer(buffer)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700607 return nullptr;
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000608 }
mtklein18300a32016-03-16 13:53:35 -0700609 return data.release();
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000610}
611
robertphillipsdb539902014-07-01 08:47:04 -0700612bool SkPictureData::parseStream(SkStream* stream,
reeda9ca05c2016-08-11 03:55:15 -0700613 SkImageDeserializer* factory,
mtklein0c263fa2015-08-18 08:29:59 -0700614 SkTypefacePlayback* topLevelTFPlayback) {
reed@google.com67562092012-06-22 15:38:39 +0000615 for (;;) {
616 uint32_t tag = stream->readU32();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000617 if (SK_PICT_EOF_TAG == tag) {
reed@google.com67562092012-06-22 15:38:39 +0000618 break;
619 }
reed@google.com82065d62011-02-07 15:30:46 +0000620
reed@google.comed384952012-06-22 13:12:17 +0000621 uint32_t size = stream->readU32();
reeda9ca05c2016-08-11 03:55:15 -0700622 if (!this->parseStreamTag(stream, tag, size, factory, topLevelTFPlayback)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000623 return false; // we're invalid
624 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625 }
scroggo@google.com12705322013-10-01 15:30:46 +0000626 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000627}
628
robertphillipsdb539902014-07-01 08:47:04 -0700629bool SkPictureData::parseBuffer(SkReadBuffer& buffer) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000630 for (;;) {
631 uint32_t tag = buffer.readUInt();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000632 if (SK_PICT_EOF_TAG == tag) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000633 break;
634 }
635
636 uint32_t size = buffer.readUInt();
robertphillipse26e65e2014-06-12 05:51:22 -0700637 if (!this->parseBufferTag(buffer, tag, size)) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000638 return false; // we're invalid
639 }
640 }
641 return true;
642}
643
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644///////////////////////////////////////////////////////////////////////////////
645///////////////////////////////////////////////////////////////////////////////
646
robertphillips0bdbea72014-06-11 11:37:55 -0700647#if SK_SUPPORT_GPU
robertphillipsdb539902014-07-01 08:47:04 -0700648bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
hendrikwafdada22014-08-08 10:44:33 -0700649 int sampleCount) const {
650 return fContentInfo.suitableForGpuRasterization(context, reason, sampleCount);
robertphillips0bdbea72014-06-11 11:37:55 -0700651}
egdaniel12c21982014-06-18 07:34:39 -0700652
robertphillipsdb539902014-07-01 08:47:04 -0700653bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
654 GrPixelConfig config, SkScalar dpi) const {
egdaniel12c21982014-06-18 07:34:39 -0700655
halcanary96fcdcc2015-08-27 07:41:13 -0700656 if (context != nullptr) {
egdaniel12c21982014-06-18 07:34:39 -0700657 return this->suitableForGpuRasterization(context, reason,
658 context->getRecommendedSampleCount(config, dpi));
659 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700660 return this->suitableForGpuRasterization(nullptr, reason);
egdaniel12c21982014-06-18 07:34:39 -0700661 }
662}
663
robertphillipsc019ec42014-08-12 05:35:58 -0700664bool SkPictureData::suitableForLayerOptimization() const {
665 return fContentInfo.numLayers() > 0;
666}
robertphillips0bdbea72014-06-11 11:37:55 -0700667#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668///////////////////////////////////////////////////////////////////////////////