blob: 69ff736fcf867455adbd92b07c2dc359ae77ff31 [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
Mike Reede88a1cb2017-03-17 09:50:46 -040090 const SkTDArray<const SkVertices*>& verts = record.getVerticesRefs();
91 fVerticesCount = verts.count();
92 if (fVerticesCount > 0) {
93 fVerticesRefs = new const SkVertices* [fVerticesCount];
94 for (int i = 0; i < fVerticesCount; ++i) {
95 fVerticesRefs[i] = SkRef(verts[i]);
96 }
97 }
98
reed871872f2015-06-22 12:48:26 -070099 const SkTDArray<const SkImage*>& imgs = record.getImageRefs();
100 fImageCount = imgs.count();
101 if (fImageCount > 0) {
halcanary385fe4d2015-08-26 13:07:48 -0700102 fImageRefs = new const SkImage* [fImageCount];
reed871872f2015-06-22 12:48:26 -0700103 for (int i = 0; i < fImageCount; ++i) {
104 fImageRefs[i] = SkRef(imgs[i]);
105 }
106 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107}
108
robertphillipsdb539902014-07-01 08:47:04 -0700109void SkPictureData::init() {
halcanary96fcdcc2015-08-27 07:41:13 -0700110 fPictureRefs = nullptr;
reed@google.comf4cc1872012-07-23 15:04:45 +0000111 fPictureCount = 0;
msarett95416f42016-04-27 13:51:20 -0700112 fDrawableRefs = nullptr;
113 fDrawableCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700114 fTextBlobRefs = nullptr;
fmalitab7425172014-08-26 07:56:44 -0700115 fTextBlobCount = 0;
Mike Reede88a1cb2017-03-17 09:50:46 -0400116 fVerticesRefs = nullptr;
117 fVerticesCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700118 fImageRefs = nullptr;
reed871872f2015-06-22 12:48:26 -0700119 fImageCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700120 fFactoryPlayback = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121}
122
robertphillipsdb539902014-07-01 08:47:04 -0700123SkPictureData::~SkPictureData() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 for (int i = 0; i < fPictureCount; i++) {
125 fPictureRefs[i]->unref();
126 }
halcanary385fe4d2015-08-26 13:07:48 -0700127 delete[] fPictureRefs;
reed@google.com82065d62011-02-07 15:30:46 +0000128
msarett95416f42016-04-27 13:51:20 -0700129 for (int i = 0; i < fDrawableCount; i++) {
130 fDrawableRefs[i]->unref();
131 }
132 if (fDrawableCount > 0) {
133 SkASSERT(fDrawableRefs);
134 delete[] fDrawableRefs;
135 }
136
fmalitab7425172014-08-26 07:56:44 -0700137 for (int i = 0; i < fTextBlobCount; i++) {
138 fTextBlobRefs[i]->unref();
139 }
halcanary385fe4d2015-08-26 13:07:48 -0700140 delete[] fTextBlobRefs;
mtklein0c263fa2015-08-18 08:29:59 -0700141
Mike Reede88a1cb2017-03-17 09:50:46 -0400142 for (int i = 0; i < fVerticesCount; i++) {
143 fVerticesRefs[i]->unref();
144 }
145 delete[] fVerticesRefs;
146
reed871872f2015-06-22 12:48:26 -0700147 for (int i = 0; i < fImageCount; i++) {
148 fImageRefs[i]->unref();
149 }
halcanary385fe4d2015-08-26 13:07:48 -0700150 delete[] fImageRefs;
mtklein0c263fa2015-08-18 08:29:59 -0700151
halcanary385fe4d2015-08-26 13:07:48 -0700152 delete fFactoryPlayback;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153}
154
robertphillipsdb539902014-07-01 08:47:04 -0700155bool SkPictureData::containsBitmaps() const {
reeda9ca05c2016-08-11 03:55:15 -0700156 if (fBitmapImageCount > 0 || fImageCount > 0) {
tomhudson@google.com381010e2013-10-24 11:12:47 +0000157 return true;
158 }
159 for (int i = 0; i < fPictureCount; ++i) {
160 if (fPictureRefs[i]->willPlayBackBitmaps()) {
161 return true;
162 }
163 }
164 return false;
165}
166
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167///////////////////////////////////////////////////////////////////////////////
168///////////////////////////////////////////////////////////////////////////////
169
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170#include "SkStream.h"
171
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000172static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) {
173 size_t size = 4; // for 'count'
reed@google.com82065d62011-02-07 15:30:46 +0000174
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000175 for (int i = 0; i < count; i++) {
176 const char* name = SkFlattenable::FactoryToName(array[i]);
halcanary96fcdcc2015-08-27 07:41:13 -0700177 if (nullptr == name || 0 == *name) {
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000178 size += SkWStream::SizeOfPackedUInt(0);
179 } else {
180 size_t len = strlen(name);
181 size += SkWStream::SizeOfPackedUInt(len);
182 size += len;
183 }
184 }
185
186 return size;
187}
188
robertphillips61426092014-07-10 09:35:12 -0700189static void write_tag_size(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
190 buffer.writeUInt(tag);
191 buffer.writeUInt(SkToU32(size));
192}
193
194static void write_tag_size(SkWStream* stream, uint32_t tag, size_t size) {
195 stream->write32(tag);
196 stream->write32(SkToU32(size));
197}
198
robertphillipsdb539902014-07-01 08:47:04 -0700199void SkPictureData::WriteFactories(SkWStream* stream, const SkFactorySet& rec) {
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000200 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000201
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
203 SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000204 rec.copyToArray(array);
reed@google.com82065d62011-02-07 15:30:46 +0000205
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000206 size_t size = compute_chunk_size(array, count);
207
208 // TODO: write_tag_size should really take a size_t
robertphillips61426092014-07-10 09:35:12 -0700209 write_tag_size(stream, SK_PICT_FACTORY_TAG, (uint32_t) size);
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000210 SkDEBUGCODE(size_t start = stream->bytesWritten());
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000211 stream->write32(count);
212
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213 for (int i = 0; i < count; i++) {
214 const char* name = SkFlattenable::FactoryToName(array[i]);
halcanary96fcdcc2015-08-27 07:41:13 -0700215 if (nullptr == name || 0 == *name) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 stream->writePackedUInt(0);
217 } else {
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +0000218 size_t len = strlen(name);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 stream->writePackedUInt(len);
220 stream->write(name, len);
221 }
222 }
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000223
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000224 SkASSERT(size == (stream->bytesWritten() - start));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225}
226
robertphillipsdb539902014-07-01 08:47:04 -0700227void SkPictureData::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000229
robertphillips61426092014-07-10 09:35:12 -0700230 write_tag_size(stream, SK_PICT_TYPEFACE_TAG, count);
reed@google.com82065d62011-02-07 15:30:46 +0000231
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 SkAutoSTMalloc<16, SkTypeface*> storage(count);
233 SkTypeface** array = (SkTypeface**)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000234 rec.copyToArray((SkRefCnt**)array);
reed@google.com82065d62011-02-07 15:30:46 +0000235
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 for (int i = 0; i < count; i++) {
237 array[i]->serialize(stream);
238 }
239}
240
robertphillipsdb539902014-07-01 08:47:04 -0700241void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const {
reed@google.comf4cc1872012-07-23 15:04:45 +0000242 int i, n;
reed@google.com82065d62011-02-07 15:30:46 +0000243
mtklein703d3c72014-11-12 11:08:20 -0800244 if ((n = fPaints.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700245 write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, n);
reed@google.comf4cc1872012-07-23 15:04:45 +0000246 for (i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800247 buffer.writePaint(fPaints[i]);
reed@google.com67562092012-06-22 15:38:39 +0000248 }
249 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000250
mtklein703d3c72014-11-12 11:08:20 -0800251 if ((n = fPaths.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700252 write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, n);
mtklein71a23632014-11-12 10:24:55 -0800253 buffer.writeInt(n);
254 for (int i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800255 buffer.writePath(fPaths[i]);
mtklein71a23632014-11-12 10:24:55 -0800256 }
robertphillipse26e65e2014-06-12 05:51:22 -0700257 }
fmalitab7425172014-08-26 07:56:44 -0700258
259 if (fTextBlobCount > 0) {
260 write_tag_size(buffer, SK_PICT_TEXTBLOB_BUFFER_TAG, fTextBlobCount);
261 for (i = 0; i < fTextBlobCount; ++i) {
262 fTextBlobRefs[i]->flatten(buffer);
263 }
264 }
mtklein0c263fa2015-08-18 08:29:59 -0700265
Mike Reede88a1cb2017-03-17 09:50:46 -0400266 if (fVerticesCount > 0) {
267 write_tag_size(buffer, SK_PICT_VERTICES_BUFFER_TAG, fVerticesCount);
268 for (i = 0; i < fVerticesCount; ++i) {
269 buffer.writeDataAsByteArray(fVerticesRefs[i]->encode().get());
270 }
271 }
272
reed871872f2015-06-22 12:48:26 -0700273 if (fImageCount > 0) {
274 write_tag_size(buffer, SK_PICT_IMAGE_BUFFER_TAG, fImageCount);
275 for (i = 0; i < fImageCount; ++i) {
276 buffer.writeImage(fImageRefs[i]);
277 }
278 }
reed@google.com67562092012-06-22 15:38:39 +0000279}
reed@google.com82065d62011-02-07 15:30:46 +0000280
robertphillipsdb539902014-07-01 08:47:04 -0700281void SkPictureData::serialize(SkWStream* stream,
mtklein0c263fa2015-08-18 08:29:59 -0700282 SkPixelSerializer* pixelSerializer,
283 SkRefCntSet* topLevelTypeFaceSet) const {
284 // This can happen at pretty much any time, so might as well do it first.
robertphillips61426092014-07-10 09:35:12 -0700285 write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size());
reed@google.comddf98a82012-07-21 20:31:09 +0000286 stream->write(fOpData->bytes(), fOpData->size());
reed@google.com67562092012-06-22 15:38:39 +0000287
mtklein0c263fa2015-08-18 08:29:59 -0700288 // We serialize all typefaces into the typeface section of the top-level picture.
289 SkRefCntSet localTypefaceSet;
290 SkRefCntSet* typefaceSet = topLevelTypeFaceSet ? topLevelTypeFaceSet : &localTypefaceSet;
291
292 // We delay serializing the bulk of our data until after we've serialized
293 // factories and typefaces by first serializing to an in-memory write buffer.
294 SkFactorySet factSet; // buffer refs factSet, so factSet must come first.
brianosmanfad98562016-05-04 11:06:28 -0700295 SkBinaryWriteBuffer buffer(SkBinaryWriteBuffer::kCrossProcess_Flag);
mtklein0c263fa2015-08-18 08:29:59 -0700296 buffer.setFactoryRecorder(&factSet);
bungeman6bd52842016-10-27 09:30:08 -0700297 buffer.setPixelSerializer(sk_ref_sp(pixelSerializer));
mtklein0c263fa2015-08-18 08:29:59 -0700298 buffer.setTypefaceRecorder(typefaceSet);
299 this->flattenToBuffer(buffer);
300
301 // Dummy serialize our sub-pictures for the side effect of filling
302 // typefaceSet with typefaces from sub-pictures.
303 struct DevNull: public SkWStream {
304 DevNull() : fBytesWritten(0) {}
305 size_t fBytesWritten;
306 bool write(const void*, size_t size) override { fBytesWritten += size; return true; }
307 size_t bytesWritten() const override { return fBytesWritten; }
308 } devnull;
309 for (int i = 0; i < fPictureCount; i++) {
310 fPictureRefs[i]->serialize(&devnull, pixelSerializer, typefaceSet);
311 }
312
313 // We need to write factories before we write the buffer.
314 // We need to write typefaces before we write the buffer or any sub-picture.
315 WriteFactories(stream, factSet);
316 if (typefaceSet == &localTypefaceSet) {
317 WriteTypefaces(stream, *typefaceSet);
318 }
319
320 // Write the buffer.
321 write_tag_size(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten());
322 buffer.writeToStream(stream);
323
324 // Write sub-pictures by calling serialize again.
reed@google.com67562092012-06-22 15:38:39 +0000325 if (fPictureCount > 0) {
robertphillips61426092014-07-10 09:35:12 -0700326 write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictureCount);
reed@google.com67562092012-06-22 15:38:39 +0000327 for (int i = 0; i < fPictureCount; i++) {
mtklein0c263fa2015-08-18 08:29:59 -0700328 fPictureRefs[i]->serialize(stream, pixelSerializer, typefaceSet);
reed@google.com67562092012-06-22 15:38:39 +0000329 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 }
reed@google.com82065d62011-02-07 15:30:46 +0000331
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000332 stream->write32(SK_PICT_EOF_TAG);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333}
334
robertphillipsdb539902014-07-01 08:47:04 -0700335void SkPictureData::flatten(SkWriteBuffer& buffer) const {
robertphillips61426092014-07-10 09:35:12 -0700336 write_tag_size(buffer, SK_PICT_READER_TAG, fOpData->size());
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000337 buffer.writeByteArray(fOpData->bytes(), fOpData->size());
338
339 if (fPictureCount > 0) {
robertphillips61426092014-07-10 09:35:12 -0700340 write_tag_size(buffer, SK_PICT_PICTURE_TAG, fPictureCount);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000341 for (int i = 0; i < fPictureCount; i++) {
342 fPictureRefs[i]->flatten(buffer);
343 }
344 }
345
msarett95416f42016-04-27 13:51:20 -0700346 if (fDrawableCount > 0) {
347 write_tag_size(buffer, SK_PICT_DRAWABLE_TAG, fDrawableCount);
348 for (int i = 0; i < fDrawableCount; i++) {
349 buffer.writeFlattenable(fDrawableRefs[i]);
350 }
351 }
352
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000353 // Write this picture playback's data into a writebuffer
354 this->flattenToBuffer(buffer);
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000355 buffer.write32(SK_PICT_EOF_TAG);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000356}
357
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358///////////////////////////////////////////////////////////////////////////////
359
reed@google.com34342f62012-06-25 14:36:28 +0000360/**
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000361 * Return the corresponding SkReadBuffer flags, given a set of
reed@google.com34342f62012-06-25 14:36:28 +0000362 * SkPictInfo flags.
363 */
364static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
365 static const struct {
366 uint32_t fSrc;
367 uint32_t fDst;
368 } gSD[] = {
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000369 { SkPictInfo::kCrossProcess_Flag, SkReadBuffer::kCrossProcess_Flag },
370 { SkPictInfo::kScalarIsFloat_Flag, SkReadBuffer::kScalarIsFloat_Flag },
371 { SkPictInfo::kPtrIs64Bit_Flag, SkReadBuffer::kPtrIs64Bit_Flag },
reed@google.com34342f62012-06-25 14:36:28 +0000372 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000373
reed@google.com34342f62012-06-25 14:36:28 +0000374 uint32_t rbMask = 0;
375 for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
376 if (pictInfoFlags & gSD[i].fSrc) {
377 rbMask |= gSD[i].fDst;
378 }
379 }
380 return rbMask;
381}
382
robertphillipsdb539902014-07-01 08:47:04 -0700383bool SkPictureData::parseStreamTag(SkStream* stream,
robertphillipsce4dd3d2014-07-07 13:46:35 -0700384 uint32_t tag,
385 uint32_t size,
reeda9ca05c2016-08-11 03:55:15 -0700386 SkImageDeserializer* factory,
mtklein0c263fa2015-08-18 08:29:59 -0700387 SkTypefacePlayback* topLevelTFPlayback) {
reed@google.com67562092012-06-22 15:38:39 +0000388 /*
389 * By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
390 * its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
391 * but if they are present, they need to have been seen before the buffer.
392 *
393 * We assert that if/when we see either of these, that we have not yet seen
394 * the buffer tag, because if we have, then its too-late to deal with the
395 * factories or typefaces.
396 */
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000397 SkDEBUGCODE(bool haveBuffer = false;)
reed@google.com67562092012-06-22 15:38:39 +0000398
399 switch (tag) {
reed9594da12014-09-12 12:12:27 -0700400 case SK_PICT_READER_TAG:
halcanary96fcdcc2015-08-27 07:41:13 -0700401 SkASSERT(nullptr == fOpData);
reedfde05112016-03-11 13:02:28 -0800402 fOpData = SkData::MakeFromStream(stream, size);
reed9594da12014-09-12 12:12:27 -0700403 if (!fOpData) {
scroggo@google.com12705322013-10-01 15:30:46 +0000404 return false;
405 }
reed9594da12014-09-12 12:12:27 -0700406 break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000407 case SK_PICT_FACTORY_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000408 SkASSERT(!haveBuffer);
mtklein88fd0fb2014-12-01 06:56:38 -0800409 size = stream->readU32();
halcanary385fe4d2015-08-26 13:07:48 -0700410 fFactoryPlayback = new SkFactoryPlayback(size);
reed@google.com67562092012-06-22 15:38:39 +0000411 for (size_t i = 0; i < size; i++) {
412 SkString str;
scroggo@google.com12705322013-10-01 15:30:46 +0000413 const size_t len = stream->readPackedUInt();
reed@google.com67562092012-06-22 15:38:39 +0000414 str.resize(len);
scroggo@google.com12705322013-10-01 15:30:46 +0000415 if (stream->read(str.writable_str(), len) != len) {
416 return false;
417 }
reed@google.com67562092012-06-22 15:38:39 +0000418 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
419 }
420 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000421 case SK_PICT_TYPEFACE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000422 SkASSERT(!haveBuffer);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000423 const int count = SkToInt(size);
424 fTFPlayback.setCount(count);
425 for (int i = 0; i < count; i++) {
bungeman13b9c952016-05-12 10:09:30 -0700426 sk_sp<SkTypeface> tf(SkTypeface::MakeDeserialize(stream));
reed@google.com73c0abc2013-04-22 13:47:40 +0000427 if (!tf.get()) { // failed to deserialize
428 // fTFPlayback asserts it never has a null, so we plop in
429 // the default here.
bungeman13b9c952016-05-12 10:09:30 -0700430 tf = SkTypeface::MakeDefault();
reed@google.com73c0abc2013-04-22 13:47:40 +0000431 }
bungeman13b9c952016-05-12 10:09:30 -0700432 fTFPlayback.set(i, tf.get());
reed@google.com67562092012-06-22 15:38:39 +0000433 }
434 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000435 case SK_PICT_PICTURE_TAG: {
fmalita5479d3b2015-07-29 14:40:06 -0700436 fPictureCount = 0;
halcanary385fe4d2015-08-26 13:07:48 -0700437 fPictureRefs = new const SkPicture* [size];
fmalita5479d3b2015-07-29 14:40:06 -0700438 for (uint32_t i = 0; i < size; i++) {
reeda9ca05c2016-08-11 03:55:15 -0700439 fPictureRefs[i] = SkPicture::MakeFromStream(stream, factory, topLevelTFPlayback).release();
fmalita5479d3b2015-07-29 14:40:06 -0700440 if (!fPictureRefs[i]) {
441 return false;
scroggo@google.com12705322013-10-01 15:30:46 +0000442 }
fmalita5479d3b2015-07-29 14:40:06 -0700443 fPictureCount++;
reed@google.com67562092012-06-22 15:38:39 +0000444 }
445 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000446 case SK_PICT_BUFFER_SIZE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000447 SkAutoMalloc storage(size);
scroggo@google.com12705322013-10-01 15:30:46 +0000448 if (stream->read(storage.get(), size) != size) {
449 return false;
450 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000451
reedac6a2f92014-11-12 09:25:25 -0800452 /* Should we use SkValidatingReadBuffer instead? */
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000453 SkReadBuffer buffer(storage.get(), size);
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000454 buffer.setFlags(pictInfoFlagsToReadBufferFlags(fInfo.fFlags));
Mike Reedb3f543d2016-10-04 15:12:01 -0400455 buffer.setVersion(fInfo.getVersion());
reed@google.com34342f62012-06-25 14:36:28 +0000456
caryclark46895be2016-01-21 06:54:46 -0800457 if (!fFactoryPlayback) {
458 return false;
459 }
reed@google.com67562092012-06-22 15:38:39 +0000460 fFactoryPlayback->setupBuffer(buffer);
reeda9ca05c2016-08-11 03:55:15 -0700461 buffer.setImageDeserializer(factory);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000462
mtklein0c263fa2015-08-18 08:29:59 -0700463 if (fTFPlayback.count() > 0) {
464 // .skp files <= v43 have typefaces serialized with each sub picture.
465 fTFPlayback.setupBuffer(buffer);
466 } else {
467 // Newer .skp files serialize all typefaces with the top picture.
468 topLevelTFPlayback->setupBuffer(buffer);
469 }
470
reedac6a2f92014-11-12 09:25:25 -0800471 while (!buffer.eof() && buffer.isValid()) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000472 tag = buffer.readUInt();
473 size = buffer.readUInt();
robertphillipse26e65e2014-06-12 05:51:22 -0700474 if (!this->parseBufferTag(buffer, tag, size)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000475 return false;
476 }
reed@google.com67562092012-06-22 15:38:39 +0000477 }
reedac6a2f92014-11-12 09:25:25 -0800478 if (!buffer.isValid()) {
479 return false;
480 }
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000481 SkDEBUGCODE(haveBuffer = true;)
reed@google.com67562092012-06-22 15:38:39 +0000482 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000483 }
scroggo@google.com12705322013-10-01 15:30:46 +0000484 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000485}
486
reed871872f2015-06-22 12:48:26 -0700487static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) {
reeda9ca05c2016-08-11 03:55:15 -0700488 return buffer.readImage().release();
489}
Mike Reede88a1cb2017-03-17 09:50:46 -0400490static const SkVertices* create_vertices_from_buffer(SkReadBuffer& buffer) {
491 auto data = buffer.readByteArrayAsData();
492 return data ? SkVertices::Decode(data->data(), data->size()).release() : nullptr;
493}
reeda9ca05c2016-08-11 03:55:15 -0700494
495static const SkImage* create_bitmap_image_from_buffer(SkReadBuffer& buffer) {
496 return buffer.readBitmapAsImage().release();
reed871872f2015-06-22 12:48:26 -0700497}
498
499// Need a shallow wrapper to return const SkPicture* to match the other factories,
500// as SkPicture::CreateFromBuffer() returns SkPicture*
501static const SkPicture* create_picture_from_buffer(SkReadBuffer& buffer) {
reedca2622b2016-03-18 07:25:55 -0700502 return SkPicture::MakeFromBuffer(buffer).release();
reed871872f2015-06-22 12:48:26 -0700503}
504
msarett95416f42016-04-27 13:51:20 -0700505static const SkDrawable* create_drawable_from_buffer(SkReadBuffer& buffer) {
506 return (SkDrawable*) buffer.readFlattenable(SkFlattenable::kSkDrawable_Type);
507}
508
reed871872f2015-06-22 12:48:26 -0700509template <typename T>
510bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount,
511 const T*** array, int* outCount, const T* (*factory)(SkReadBuffer&)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700512 if (!buffer.validate((0 == *outCount) && (nullptr == *array))) {
reed871872f2015-06-22 12:48:26 -0700513 return false;
514 }
515 if (0 == inCount) {
516 return true;
517 }
Robert Phillips20dd31f2016-12-19 12:58:14 -0500518 if (!buffer.validate(SkTFitsIn<int>(inCount))) {
519 return false;
520 }
521
reed871872f2015-06-22 12:48:26 -0700522 *outCount = inCount;
halcanary385fe4d2015-08-26 13:07:48 -0700523 *array = new const T* [*outCount];
reed871872f2015-06-22 12:48:26 -0700524 bool success = true;
525 int i = 0;
526 for (; i < *outCount; i++) {
527 (*array)[i] = factory(buffer);
halcanary96fcdcc2015-08-27 07:41:13 -0700528 if (nullptr == (*array)[i]) {
reed871872f2015-06-22 12:48:26 -0700529 success = false;
530 break;
531 }
532 }
533 if (!success) {
534 // Delete all of the blobs that were already created (up to but excluding i):
535 for (int j = 0; j < i; j++) {
536 (*array)[j]->unref();
537 }
538 // Delete the array
halcanary385fe4d2015-08-26 13:07:48 -0700539 delete[] * array;
halcanary96fcdcc2015-08-27 07:41:13 -0700540 *array = nullptr;
reed871872f2015-06-22 12:48:26 -0700541 *outCount = 0;
542 return false;
543 }
544 return true;
545}
546
547bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) {
reed@google.com67562092012-06-22 15:38:39 +0000548 switch (tag) {
reeda9ca05c2016-08-11 03:55:15 -0700549 case SK_PICT_BITMAP_BUFFER_TAG:
550 if (!new_array_from_buffer(buffer, size, &fBitmapImageRefs, &fBitmapImageCount,
551 create_bitmap_image_from_buffer)) {
552 return false;
reed@google.com67562092012-06-22 15:38:39 +0000553 }
reeda9ca05c2016-08-11 03:55:15 -0700554 break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000555 case SK_PICT_PAINT_BUFFER_TAG: {
Robert Phillips20dd31f2016-12-19 12:58:14 -0500556 if (!buffer.validate(SkTFitsIn<int>(size))) {
557 return false;
558 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000559 const int count = SkToInt(size);
mtklein703d3c72014-11-12 11:08:20 -0800560 fPaints.reset(count);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000561 for (int i = 0; i < count; ++i) {
mtklein703d3c72014-11-12 11:08:20 -0800562 buffer.readPaint(&fPaints[i]);
reed@google.com67562092012-06-22 15:38:39 +0000563 }
564 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000565 case SK_PICT_PATH_BUFFER_TAG:
robertphillipse26e65e2014-06-12 05:51:22 -0700566 if (size > 0) {
mtklein71a23632014-11-12 10:24:55 -0800567 const int count = buffer.readInt();
mtklein703d3c72014-11-12 11:08:20 -0800568 fPaths.reset(count);
mtklein71a23632014-11-12 10:24:55 -0800569 for (int i = 0; i < count; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800570 buffer.readPath(&fPaths[i]);
mtklein71a23632014-11-12 10:24:55 -0800571 }
572 } break;
reed871872f2015-06-22 12:48:26 -0700573 case SK_PICT_TEXTBLOB_BUFFER_TAG:
574 if (!new_array_from_buffer(buffer, size, &fTextBlobRefs, &fTextBlobCount,
575 SkTextBlob::CreateFromBuffer)) {
fmalitab7425172014-08-26 07:56:44 -0700576 return false;
577 }
reed871872f2015-06-22 12:48:26 -0700578 break;
Mike Reede88a1cb2017-03-17 09:50:46 -0400579 case SK_PICT_VERTICES_BUFFER_TAG:
580 if (!new_array_from_buffer(buffer, size, &fVerticesRefs, &fVerticesCount,
581 create_vertices_from_buffer)) {
582 return false;
583 }
584 break;
reed871872f2015-06-22 12:48:26 -0700585 case SK_PICT_IMAGE_BUFFER_TAG:
586 if (!new_array_from_buffer(buffer, size, &fImageRefs, &fImageCount,
587 create_image_from_buffer)) {
fmalitab7425172014-08-26 07:56:44 -0700588 return false;
589 }
reed871872f2015-06-22 12:48:26 -0700590 break;
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000591 case SK_PICT_READER_TAG: {
reedfde05112016-03-11 13:02:28 -0800592 auto data(SkData::MakeUninitialized(size));
reed9594da12014-09-12 12:12:27 -0700593 if (!buffer.readByteArray(data->writable_data(), size) ||
halcanary96fcdcc2015-08-27 07:41:13 -0700594 !buffer.validate(nullptr == fOpData)) {
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000595 return false;
596 }
halcanary96fcdcc2015-08-27 07:41:13 -0700597 SkASSERT(nullptr == fOpData);
reedfde05112016-03-11 13:02:28 -0800598 fOpData = std::move(data);
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000599 } break;
reed871872f2015-06-22 12:48:26 -0700600 case SK_PICT_PICTURE_TAG:
601 if (!new_array_from_buffer(buffer, size, &fPictureRefs, &fPictureCount,
602 create_picture_from_buffer)) {
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000603 return false;
604 }
reedc2100352015-06-22 17:03:10 -0700605 break;
msarett95416f42016-04-27 13:51:20 -0700606 case SK_PICT_DRAWABLE_TAG:
607 if (!new_array_from_buffer(buffer, size, (const SkDrawable***)&fDrawableRefs,
608 &fDrawableCount, create_drawable_from_buffer)) {
609 return false;
610 }
611 break;
scroggo@google.com12705322013-10-01 15:30:46 +0000612 default:
613 // The tag was invalid.
614 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615 }
scroggo@google.com12705322013-10-01 15:30:46 +0000616 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000617}
618
robertphillipsdb539902014-07-01 08:47:04 -0700619SkPictureData* SkPictureData::CreateFromStream(SkStream* stream,
620 const SkPictInfo& info,
reeda9ca05c2016-08-11 03:55:15 -0700621 SkImageDeserializer* factory,
mtklein0c263fa2015-08-18 08:29:59 -0700622 SkTypefacePlayback* topLevelTFPlayback) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400623 std::unique_ptr<SkPictureData> data(new SkPictureData(info));
mtklein0c263fa2015-08-18 08:29:59 -0700624 if (!topLevelTFPlayback) {
625 topLevelTFPlayback = &data->fTFPlayback;
626 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000627
reeda9ca05c2016-08-11 03:55:15 -0700628 if (!data->parseStream(stream, factory, topLevelTFPlayback)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700629 return nullptr;
scroggo@google.com12705322013-10-01 15:30:46 +0000630 }
mtklein18300a32016-03-16 13:53:35 -0700631 return data.release();
scroggo@google.com12705322013-10-01 15:30:46 +0000632}
633
robertphillipsdb539902014-07-01 08:47:04 -0700634SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer,
635 const SkPictInfo& info) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400636 std::unique_ptr<SkPictureData> data(new SkPictureData(info));
Mike Reedb3f543d2016-10-04 15:12:01 -0400637 buffer.setVersion(info.getVersion());
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000638
robertphillipsdb539902014-07-01 08:47:04 -0700639 if (!data->parseBuffer(buffer)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700640 return nullptr;
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000641 }
mtklein18300a32016-03-16 13:53:35 -0700642 return data.release();
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000643}
644
robertphillipsdb539902014-07-01 08:47:04 -0700645bool SkPictureData::parseStream(SkStream* stream,
reeda9ca05c2016-08-11 03:55:15 -0700646 SkImageDeserializer* factory,
mtklein0c263fa2015-08-18 08:29:59 -0700647 SkTypefacePlayback* topLevelTFPlayback) {
reed@google.com67562092012-06-22 15:38:39 +0000648 for (;;) {
649 uint32_t tag = stream->readU32();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000650 if (SK_PICT_EOF_TAG == tag) {
reed@google.com67562092012-06-22 15:38:39 +0000651 break;
652 }
reed@google.com82065d62011-02-07 15:30:46 +0000653
reed@google.comed384952012-06-22 13:12:17 +0000654 uint32_t size = stream->readU32();
reeda9ca05c2016-08-11 03:55:15 -0700655 if (!this->parseStreamTag(stream, tag, size, factory, topLevelTFPlayback)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000656 return false; // we're invalid
657 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658 }
scroggo@google.com12705322013-10-01 15:30:46 +0000659 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660}
661
robertphillipsdb539902014-07-01 08:47:04 -0700662bool SkPictureData::parseBuffer(SkReadBuffer& buffer) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000663 for (;;) {
664 uint32_t tag = buffer.readUInt();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000665 if (SK_PICT_EOF_TAG == tag) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000666 break;
667 }
668
669 uint32_t size = buffer.readUInt();
robertphillipse26e65e2014-06-12 05:51:22 -0700670 if (!this->parseBufferTag(buffer, tag, size)) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000671 return false; // we're invalid
672 }
673 }
674 return true;
675}
676
reed@android.com8a1c16f2008-12-17 15:59:43 +0000677///////////////////////////////////////////////////////////////////////////////
678///////////////////////////////////////////////////////////////////////////////
679
robertphillips0bdbea72014-06-11 11:37:55 -0700680#if SK_SUPPORT_GPU
robertphillipsdb539902014-07-01 08:47:04 -0700681bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
hendrikwafdada22014-08-08 10:44:33 -0700682 int sampleCount) const {
683 return fContentInfo.suitableForGpuRasterization(context, reason, sampleCount);
robertphillips0bdbea72014-06-11 11:37:55 -0700684}
egdaniel12c21982014-06-18 07:34:39 -0700685
robertphillipsdb539902014-07-01 08:47:04 -0700686bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
687 GrPixelConfig config, SkScalar dpi) const {
egdaniel12c21982014-06-18 07:34:39 -0700688
halcanary96fcdcc2015-08-27 07:41:13 -0700689 if (context != nullptr) {
egdaniel12c21982014-06-18 07:34:39 -0700690 return this->suitableForGpuRasterization(context, reason,
691 context->getRecommendedSampleCount(config, dpi));
692 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700693 return this->suitableForGpuRasterization(nullptr, reason);
egdaniel12c21982014-06-18 07:34:39 -0700694 }
695}
696
robertphillipsc019ec42014-08-12 05:35:58 -0700697bool SkPictureData::suitableForLayerOptimization() const {
698 return fContentInfo.numLayers() > 0;
699}
robertphillips0bdbea72014-06-11 11:37:55 -0700700#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000701///////////////////////////////////////////////////////////////////////////////