blob: a27c31a2979102f6d984c33a10c6aeea53000ca3 [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>
fmalitac3470342015-09-04 11:36:39 -07008#include "SkImageGenerator.h"
robertphillipsdb539902014-07-01 08:47:04 -07009#include "SkPictureData.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000010#include "SkPictureRecord.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000011#include "SkReadBuffer.h"
fmalitab7425172014-08-26 07:56:44 -070012#include "SkTextBlob.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000013#include "SkTypeface.h"
commit-bot@chromium.org8016f792014-03-07 15:53:01 +000014#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
egdaniel12c21982014-06-18 07:34:39 -070016#if SK_SUPPORT_GPU
17#include "GrContext.h"
18#endif
19
reed@google.comf4cc1872012-07-23 15:04:45 +000020template <typename T> int SafeCount(const T* obj) {
21 return obj ? obj->count() : 0;
22}
23
robertphillipsdb539902014-07-01 08:47:04 -070024SkPictureData::SkPictureData(const SkPictInfo& info)
robertphillipse26e65e2014-06-12 05:51:22 -070025 : fInfo(info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000026 this->init();
27}
28
robertphillipsdb539902014-07-01 08:47:04 -070029void SkPictureData::initForPlayback() const {
robertphillipse26e65e2014-06-12 05:51:22 -070030 // ensure that the paths bounds are pre-computed
mtklein703d3c72014-11-12 11:08:20 -080031 for (int i = 0; i < fPaths.count(); i++) {
32 fPaths[i].updateBoundsCache();
robertphillipse26e65e2014-06-12 05:51:22 -070033 }
34}
35
robertphillipsdb539902014-07-01 08:47:04 -070036SkPictureData::SkPictureData(const SkPictureRecord& record,
robertphillips61426092014-07-10 09:35:12 -070037 const SkPictInfo& info,
38 bool deepCopyOps)
robertphillipse26e65e2014-06-12 05:51:22 -070039 : fInfo(info) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000040
commit-bot@chromium.org70512af2014-03-18 17:45:32 +000041 this->init();
robertphillips0bdbea72014-06-11 11:37:55 -070042
43 fOpData = record.opData(deepCopyOps);
reed@google.com82065d62011-02-07 15:30:46 +000044
robertphillips0bdbea72014-06-11 11:37:55 -070045 fContentInfo.set(record.fContentInfo);
rileya@google.com8515e792012-09-13 21:41:51 +000046
mtklein703d3c72014-11-12 11:08:20 -080047 fBitmaps = record.fBitmaps;
48 fPaints = record.fPaints;
mtkleinc2e29772015-10-30 05:24:58 -070049
50 fPaths.reset(record.fPaths.count());
51 record.fPaths.foreach([this](const SkPath& path, int n) {
52 // These indices are logically 1-based, but we need to serialize them
53 // 0-based to keep the deserializing SkPictureData::getPath() working.
54 fPaths[n-1] = path;
55 });
djsollen@google.comc9ab9872012-08-29 18:52:07 +000056
robertphillipse26e65e2014-06-12 05:51:22 -070057 this->initForPlayback();
reed@android.com8a1c16f2008-12-17 15:59:43 +000058
robertphillips9b14f262014-06-04 05:40:44 -070059 const SkTDArray<const SkPicture* >& pictures = record.getPictureRefs();
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 fPictureCount = pictures.count();
61 if (fPictureCount > 0) {
halcanary385fe4d2015-08-26 13:07:48 -070062 fPictureRefs = new const SkPicture* [fPictureCount];
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 for (int i = 0; i < fPictureCount; i++) {
robertphillips6de27122014-06-10 09:23:06 -070064 fPictureRefs[i] = pictures[i];
65 fPictureRefs[i]->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 }
67 }
fmalitab7425172014-08-26 07:56:44 -070068
69 // templatize to consolidate with similar picture logic?
70 const SkTDArray<const SkTextBlob*>& blobs = record.getTextBlobRefs();
71 fTextBlobCount = blobs.count();
72 if (fTextBlobCount > 0) {
halcanary385fe4d2015-08-26 13:07:48 -070073 fTextBlobRefs = new const SkTextBlob* [fTextBlobCount];
fmalitab7425172014-08-26 07:56:44 -070074 for (int i = 0; i < fTextBlobCount; ++i) {
75 fTextBlobRefs[i] = SkRef(blobs[i]);
76 }
77 }
mtklein0c263fa2015-08-18 08:29:59 -070078
reed871872f2015-06-22 12:48:26 -070079 const SkTDArray<const SkImage*>& imgs = record.getImageRefs();
80 fImageCount = imgs.count();
81 if (fImageCount > 0) {
halcanary385fe4d2015-08-26 13:07:48 -070082 fImageRefs = new const SkImage* [fImageCount];
reed871872f2015-06-22 12:48:26 -070083 for (int i = 0; i < fImageCount; ++i) {
84 fImageRefs[i] = SkRef(imgs[i]);
85 }
86 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000087}
88
robertphillipsdb539902014-07-01 08:47:04 -070089void SkPictureData::init() {
halcanary96fcdcc2015-08-27 07:41:13 -070090 fPictureRefs = nullptr;
reed@google.comf4cc1872012-07-23 15:04:45 +000091 fPictureCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -070092 fTextBlobRefs = nullptr;
fmalitab7425172014-08-26 07:56:44 -070093 fTextBlobCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -070094 fImageRefs = nullptr;
reed871872f2015-06-22 12:48:26 -070095 fImageCount = 0;
halcanary96fcdcc2015-08-27 07:41:13 -070096 fFactoryPlayback = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +000097}
98
robertphillipsdb539902014-07-01 08:47:04 -070099SkPictureData::~SkPictureData() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100 for (int i = 0; i < fPictureCount; i++) {
101 fPictureRefs[i]->unref();
102 }
halcanary385fe4d2015-08-26 13:07:48 -0700103 delete[] fPictureRefs;
reed@google.com82065d62011-02-07 15:30:46 +0000104
fmalitab7425172014-08-26 07:56:44 -0700105 for (int i = 0; i < fTextBlobCount; i++) {
106 fTextBlobRefs[i]->unref();
107 }
halcanary385fe4d2015-08-26 13:07:48 -0700108 delete[] fTextBlobRefs;
mtklein0c263fa2015-08-18 08:29:59 -0700109
reed871872f2015-06-22 12:48:26 -0700110 for (int i = 0; i < fImageCount; i++) {
111 fImageRefs[i]->unref();
112 }
halcanary385fe4d2015-08-26 13:07:48 -0700113 delete[] fImageRefs;
mtklein0c263fa2015-08-18 08:29:59 -0700114
halcanary385fe4d2015-08-26 13:07:48 -0700115 delete fFactoryPlayback;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116}
117
robertphillipsdb539902014-07-01 08:47:04 -0700118bool SkPictureData::containsBitmaps() const {
reed871872f2015-06-22 12:48:26 -0700119 if (fBitmaps.count() > 0 || fImageCount > 0) {
tomhudson@google.com381010e2013-10-24 11:12:47 +0000120 return true;
121 }
122 for (int i = 0; i < fPictureCount; ++i) {
123 if (fPictureRefs[i]->willPlayBackBitmaps()) {
124 return true;
125 }
126 }
127 return false;
128}
129
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130///////////////////////////////////////////////////////////////////////////////
131///////////////////////////////////////////////////////////////////////////////
132
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133#include "SkStream.h"
134
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000135static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) {
136 size_t size = 4; // for 'count'
reed@google.com82065d62011-02-07 15:30:46 +0000137
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000138 for (int i = 0; i < count; i++) {
139 const char* name = SkFlattenable::FactoryToName(array[i]);
halcanary96fcdcc2015-08-27 07:41:13 -0700140 if (nullptr == name || 0 == *name) {
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000141 size += SkWStream::SizeOfPackedUInt(0);
142 } else {
143 size_t len = strlen(name);
144 size += SkWStream::SizeOfPackedUInt(len);
145 size += len;
146 }
147 }
148
149 return size;
150}
151
robertphillips61426092014-07-10 09:35:12 -0700152static void write_tag_size(SkWriteBuffer& buffer, uint32_t tag, size_t size) {
153 buffer.writeUInt(tag);
154 buffer.writeUInt(SkToU32(size));
155}
156
157static void write_tag_size(SkWStream* stream, uint32_t tag, size_t size) {
158 stream->write32(tag);
159 stream->write32(SkToU32(size));
160}
161
robertphillipsdb539902014-07-01 08:47:04 -0700162void SkPictureData::WriteFactories(SkWStream* stream, const SkFactorySet& rec) {
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000163 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000164
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count);
166 SkFlattenable::Factory* array = (SkFlattenable::Factory*)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000167 rec.copyToArray(array);
reed@google.com82065d62011-02-07 15:30:46 +0000168
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000169 size_t size = compute_chunk_size(array, count);
170
171 // TODO: write_tag_size should really take a size_t
robertphillips61426092014-07-10 09:35:12 -0700172 write_tag_size(stream, SK_PICT_FACTORY_TAG, (uint32_t) size);
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000173 SkDEBUGCODE(size_t start = stream->bytesWritten());
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000174 stream->write32(count);
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 for (int i = 0; i < count; i++) {
177 const char* name = SkFlattenable::FactoryToName(array[i]);
halcanary96fcdcc2015-08-27 07:41:13 -0700178 if (nullptr == name || 0 == *name) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 stream->writePackedUInt(0);
180 } else {
commit-bot@chromium.org2cfa3202014-04-19 22:00:40 +0000181 size_t len = strlen(name);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 stream->writePackedUInt(len);
183 stream->write(name, len);
184 }
185 }
commit-bot@chromium.orgdcb8e542014-03-05 18:25:20 +0000186
commit-bot@chromium.org06e97522014-03-06 20:53:44 +0000187 SkASSERT(size == (stream->bytesWritten() - start));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188}
189
robertphillipsdb539902014-07-01 08:47:04 -0700190void SkPictureData::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 int count = rec.count();
reed@google.com82065d62011-02-07 15:30:46 +0000192
robertphillips61426092014-07-10 09:35:12 -0700193 write_tag_size(stream, SK_PICT_TYPEFACE_TAG, count);
reed@google.com82065d62011-02-07 15:30:46 +0000194
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195 SkAutoSTMalloc<16, SkTypeface*> storage(count);
196 SkTypeface** array = (SkTypeface**)storage.get();
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000197 rec.copyToArray((SkRefCnt**)array);
reed@google.com82065d62011-02-07 15:30:46 +0000198
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 for (int i = 0; i < count; i++) {
200 array[i]->serialize(stream);
201 }
202}
203
robertphillipsdb539902014-07-01 08:47:04 -0700204void SkPictureData::flattenToBuffer(SkWriteBuffer& buffer) const {
reed@google.comf4cc1872012-07-23 15:04:45 +0000205 int i, n;
reed@google.com82065d62011-02-07 15:30:46 +0000206
mtklein703d3c72014-11-12 11:08:20 -0800207 if ((n = fBitmaps.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700208 write_tag_size(buffer, SK_PICT_BITMAP_BUFFER_TAG, n);
reed@google.comf4cc1872012-07-23 15:04:45 +0000209 for (i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800210 buffer.writeBitmap(fBitmaps[i]);
reed@google.com67562092012-06-22 15:38:39 +0000211 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000213
mtklein703d3c72014-11-12 11:08:20 -0800214 if ((n = fPaints.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700215 write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, n);
reed@google.comf4cc1872012-07-23 15:04:45 +0000216 for (i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800217 buffer.writePaint(fPaints[i]);
reed@google.com67562092012-06-22 15:38:39 +0000218 }
219 }
skia.committer@gmail.coma27096b2012-08-30 14:38:00 +0000220
mtklein703d3c72014-11-12 11:08:20 -0800221 if ((n = fPaths.count()) > 0) {
robertphillips61426092014-07-10 09:35:12 -0700222 write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, n);
mtklein71a23632014-11-12 10:24:55 -0800223 buffer.writeInt(n);
224 for (int i = 0; i < n; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800225 buffer.writePath(fPaths[i]);
mtklein71a23632014-11-12 10:24:55 -0800226 }
robertphillipse26e65e2014-06-12 05:51:22 -0700227 }
fmalitab7425172014-08-26 07:56:44 -0700228
229 if (fTextBlobCount > 0) {
230 write_tag_size(buffer, SK_PICT_TEXTBLOB_BUFFER_TAG, fTextBlobCount);
231 for (i = 0; i < fTextBlobCount; ++i) {
232 fTextBlobRefs[i]->flatten(buffer);
233 }
234 }
mtklein0c263fa2015-08-18 08:29:59 -0700235
reed871872f2015-06-22 12:48:26 -0700236 if (fImageCount > 0) {
237 write_tag_size(buffer, SK_PICT_IMAGE_BUFFER_TAG, fImageCount);
238 for (i = 0; i < fImageCount; ++i) {
239 buffer.writeImage(fImageRefs[i]);
240 }
241 }
reed@google.com67562092012-06-22 15:38:39 +0000242}
reed@google.com82065d62011-02-07 15:30:46 +0000243
robertphillipsdb539902014-07-01 08:47:04 -0700244void SkPictureData::serialize(SkWStream* stream,
mtklein0c263fa2015-08-18 08:29:59 -0700245 SkPixelSerializer* pixelSerializer,
246 SkRefCntSet* topLevelTypeFaceSet) const {
247 // This can happen at pretty much any time, so might as well do it first.
robertphillips61426092014-07-10 09:35:12 -0700248 write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size());
reed@google.comddf98a82012-07-21 20:31:09 +0000249 stream->write(fOpData->bytes(), fOpData->size());
reed@google.com67562092012-06-22 15:38:39 +0000250
mtklein0c263fa2015-08-18 08:29:59 -0700251 // We serialize all typefaces into the typeface section of the top-level picture.
252 SkRefCntSet localTypefaceSet;
253 SkRefCntSet* typefaceSet = topLevelTypeFaceSet ? topLevelTypeFaceSet : &localTypefaceSet;
254
255 // We delay serializing the bulk of our data until after we've serialized
256 // factories and typefaces by first serializing to an in-memory write buffer.
257 SkFactorySet factSet; // buffer refs factSet, so factSet must come first.
258 SkWriteBuffer buffer(SkWriteBuffer::kCrossProcess_Flag);
259 buffer.setFactoryRecorder(&factSet);
260 buffer.setPixelSerializer(pixelSerializer);
261 buffer.setTypefaceRecorder(typefaceSet);
262 this->flattenToBuffer(buffer);
263
264 // Dummy serialize our sub-pictures for the side effect of filling
265 // typefaceSet with typefaces from sub-pictures.
266 struct DevNull: public SkWStream {
267 DevNull() : fBytesWritten(0) {}
268 size_t fBytesWritten;
269 bool write(const void*, size_t size) override { fBytesWritten += size; return true; }
270 size_t bytesWritten() const override { return fBytesWritten; }
271 } devnull;
272 for (int i = 0; i < fPictureCount; i++) {
273 fPictureRefs[i]->serialize(&devnull, pixelSerializer, typefaceSet);
274 }
275
276 // We need to write factories before we write the buffer.
277 // We need to write typefaces before we write the buffer or any sub-picture.
278 WriteFactories(stream, factSet);
279 if (typefaceSet == &localTypefaceSet) {
280 WriteTypefaces(stream, *typefaceSet);
281 }
282
283 // Write the buffer.
284 write_tag_size(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten());
285 buffer.writeToStream(stream);
286
287 // Write sub-pictures by calling serialize again.
reed@google.com67562092012-06-22 15:38:39 +0000288 if (fPictureCount > 0) {
robertphillips61426092014-07-10 09:35:12 -0700289 write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictureCount);
reed@google.com67562092012-06-22 15:38:39 +0000290 for (int i = 0; i < fPictureCount; i++) {
mtklein0c263fa2015-08-18 08:29:59 -0700291 fPictureRefs[i]->serialize(stream, pixelSerializer, typefaceSet);
reed@google.com67562092012-06-22 15:38:39 +0000292 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293 }
reed@google.com82065d62011-02-07 15:30:46 +0000294
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000295 stream->write32(SK_PICT_EOF_TAG);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296}
297
robertphillipsdb539902014-07-01 08:47:04 -0700298void SkPictureData::flatten(SkWriteBuffer& buffer) const {
robertphillips61426092014-07-10 09:35:12 -0700299 write_tag_size(buffer, SK_PICT_READER_TAG, fOpData->size());
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000300 buffer.writeByteArray(fOpData->bytes(), fOpData->size());
301
302 if (fPictureCount > 0) {
robertphillips61426092014-07-10 09:35:12 -0700303 write_tag_size(buffer, SK_PICT_PICTURE_TAG, fPictureCount);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000304 for (int i = 0; i < fPictureCount; i++) {
305 fPictureRefs[i]->flatten(buffer);
306 }
307 }
308
309 // Write this picture playback's data into a writebuffer
310 this->flattenToBuffer(buffer);
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000311 buffer.write32(SK_PICT_EOF_TAG);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000312}
313
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314///////////////////////////////////////////////////////////////////////////////
315
reed@google.com34342f62012-06-25 14:36:28 +0000316/**
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000317 * Return the corresponding SkReadBuffer flags, given a set of
reed@google.com34342f62012-06-25 14:36:28 +0000318 * SkPictInfo flags.
319 */
320static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) {
321 static const struct {
322 uint32_t fSrc;
323 uint32_t fDst;
324 } gSD[] = {
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000325 { SkPictInfo::kCrossProcess_Flag, SkReadBuffer::kCrossProcess_Flag },
326 { SkPictInfo::kScalarIsFloat_Flag, SkReadBuffer::kScalarIsFloat_Flag },
327 { SkPictInfo::kPtrIs64Bit_Flag, SkReadBuffer::kPtrIs64Bit_Flag },
reed@google.com34342f62012-06-25 14:36:28 +0000328 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000329
reed@google.com34342f62012-06-25 14:36:28 +0000330 uint32_t rbMask = 0;
331 for (size_t i = 0; i < SK_ARRAY_COUNT(gSD); ++i) {
332 if (pictInfoFlags & gSD[i].fSrc) {
333 rbMask |= gSD[i].fDst;
334 }
335 }
336 return rbMask;
337}
338
robertphillipsdb539902014-07-01 08:47:04 -0700339bool SkPictureData::parseStreamTag(SkStream* stream,
robertphillipsce4dd3d2014-07-07 13:46:35 -0700340 uint32_t tag,
341 uint32_t size,
mtklein0c263fa2015-08-18 08:29:59 -0700342 SkPicture::InstallPixelRefProc proc,
343 SkTypefacePlayback* topLevelTFPlayback) {
reed@google.com67562092012-06-22 15:38:39 +0000344 /*
345 * By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
346 * its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
347 * but if they are present, they need to have been seen before the buffer.
348 *
349 * We assert that if/when we see either of these, that we have not yet seen
350 * the buffer tag, because if we have, then its too-late to deal with the
351 * factories or typefaces.
352 */
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000353 SkDEBUGCODE(bool haveBuffer = false;)
reed@google.com67562092012-06-22 15:38:39 +0000354
355 switch (tag) {
reed9594da12014-09-12 12:12:27 -0700356 case SK_PICT_READER_TAG:
halcanary96fcdcc2015-08-27 07:41:13 -0700357 SkASSERT(nullptr == fOpData);
reedfde05112016-03-11 13:02:28 -0800358 fOpData = SkData::MakeFromStream(stream, size);
reed9594da12014-09-12 12:12:27 -0700359 if (!fOpData) {
scroggo@google.com12705322013-10-01 15:30:46 +0000360 return false;
361 }
reed9594da12014-09-12 12:12:27 -0700362 break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000363 case SK_PICT_FACTORY_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000364 SkASSERT(!haveBuffer);
mtklein88fd0fb2014-12-01 06:56:38 -0800365 size = stream->readU32();
halcanary385fe4d2015-08-26 13:07:48 -0700366 fFactoryPlayback = new SkFactoryPlayback(size);
reed@google.com67562092012-06-22 15:38:39 +0000367 for (size_t i = 0; i < size; i++) {
368 SkString str;
scroggo@google.com12705322013-10-01 15:30:46 +0000369 const size_t len = stream->readPackedUInt();
reed@google.com67562092012-06-22 15:38:39 +0000370 str.resize(len);
scroggo@google.com12705322013-10-01 15:30:46 +0000371 if (stream->read(str.writable_str(), len) != len) {
372 return false;
373 }
reed@google.com67562092012-06-22 15:38:39 +0000374 fFactoryPlayback->base()[i] = SkFlattenable::NameToFactory(str.c_str());
375 }
376 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000377 case SK_PICT_TYPEFACE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000378 SkASSERT(!haveBuffer);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000379 const int count = SkToInt(size);
380 fTFPlayback.setCount(count);
381 for (int i = 0; i < count; i++) {
reed@google.com73c0abc2013-04-22 13:47:40 +0000382 SkAutoTUnref<SkTypeface> tf(SkTypeface::Deserialize(stream));
383 if (!tf.get()) { // failed to deserialize
384 // fTFPlayback asserts it never has a null, so we plop in
385 // the default here.
386 tf.reset(SkTypeface::RefDefault());
387 }
388 fTFPlayback.set(i, tf);
reed@google.com67562092012-06-22 15:38:39 +0000389 }
390 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000391 case SK_PICT_PICTURE_TAG: {
fmalita5479d3b2015-07-29 14:40:06 -0700392 fPictureCount = 0;
halcanary385fe4d2015-08-26 13:07:48 -0700393 fPictureRefs = new const SkPicture* [size];
fmalita5479d3b2015-07-29 14:40:06 -0700394 for (uint32_t i = 0; i < size; i++) {
mtklein0c263fa2015-08-18 08:29:59 -0700395 fPictureRefs[i] = SkPicture::CreateFromStream(stream, proc, topLevelTFPlayback);
fmalita5479d3b2015-07-29 14:40:06 -0700396 if (!fPictureRefs[i]) {
397 return false;
scroggo@google.com12705322013-10-01 15:30:46 +0000398 }
fmalita5479d3b2015-07-29 14:40:06 -0700399 fPictureCount++;
reed@google.com67562092012-06-22 15:38:39 +0000400 }
401 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000402 case SK_PICT_BUFFER_SIZE_TAG: {
reed@google.com67562092012-06-22 15:38:39 +0000403 SkAutoMalloc storage(size);
scroggo@google.com12705322013-10-01 15:30:46 +0000404 if (stream->read(storage.get(), size) != size) {
405 return false;
406 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000407
reedac6a2f92014-11-12 09:25:25 -0800408 /* Should we use SkValidatingReadBuffer instead? */
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000409 SkReadBuffer buffer(storage.get(), size);
commit-bot@chromium.org0943f5f2014-03-28 18:05:47 +0000410 buffer.setFlags(pictInfoFlagsToReadBufferFlags(fInfo.fFlags));
commit-bot@chromium.org7ed173b2014-05-20 17:31:08 +0000411 buffer.setVersion(fInfo.fVersion);
reed@google.com34342f62012-06-25 14:36:28 +0000412
caryclark46895be2016-01-21 06:54:46 -0800413 if (!fFactoryPlayback) {
414 return false;
415 }
reed@google.com67562092012-06-22 15:38:39 +0000416 fFactoryPlayback->setupBuffer(buffer);
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000417 buffer.setBitmapDecoder(proc);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000418
mtklein0c263fa2015-08-18 08:29:59 -0700419 if (fTFPlayback.count() > 0) {
420 // .skp files <= v43 have typefaces serialized with each sub picture.
421 fTFPlayback.setupBuffer(buffer);
422 } else {
423 // Newer .skp files serialize all typefaces with the top picture.
424 topLevelTFPlayback->setupBuffer(buffer);
425 }
426
reedac6a2f92014-11-12 09:25:25 -0800427 while (!buffer.eof() && buffer.isValid()) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000428 tag = buffer.readUInt();
429 size = buffer.readUInt();
robertphillipse26e65e2014-06-12 05:51:22 -0700430 if (!this->parseBufferTag(buffer, tag, size)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000431 return false;
432 }
reed@google.com67562092012-06-22 15:38:39 +0000433 }
reedac6a2f92014-11-12 09:25:25 -0800434 if (!buffer.isValid()) {
435 return false;
436 }
scroggo@google.comc4dc8312013-02-22 15:46:44 +0000437 SkDEBUGCODE(haveBuffer = true;)
reed@google.com67562092012-06-22 15:38:39 +0000438 } break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439 }
scroggo@google.com12705322013-10-01 15:30:46 +0000440 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441}
442
reed871872f2015-06-22 12:48:26 -0700443static const SkImage* create_image_from_buffer(SkReadBuffer& buffer) {
fmalitacd56f812015-09-14 13:31:18 -0700444 return buffer.readImage();
reed871872f2015-06-22 12:48:26 -0700445}
446
447// Need a shallow wrapper to return const SkPicture* to match the other factories,
448// as SkPicture::CreateFromBuffer() returns SkPicture*
449static const SkPicture* create_picture_from_buffer(SkReadBuffer& buffer) {
450 return SkPicture::CreateFromBuffer(buffer);
451}
452
453template <typename T>
454bool new_array_from_buffer(SkReadBuffer& buffer, uint32_t inCount,
455 const T*** array, int* outCount, const T* (*factory)(SkReadBuffer&)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700456 if (!buffer.validate((0 == *outCount) && (nullptr == *array))) {
reed871872f2015-06-22 12:48:26 -0700457 return false;
458 }
459 if (0 == inCount) {
460 return true;
461 }
462 *outCount = inCount;
halcanary385fe4d2015-08-26 13:07:48 -0700463 *array = new const T* [*outCount];
reed871872f2015-06-22 12:48:26 -0700464 bool success = true;
465 int i = 0;
466 for (; i < *outCount; i++) {
467 (*array)[i] = factory(buffer);
halcanary96fcdcc2015-08-27 07:41:13 -0700468 if (nullptr == (*array)[i]) {
reed871872f2015-06-22 12:48:26 -0700469 success = false;
470 break;
471 }
472 }
473 if (!success) {
474 // Delete all of the blobs that were already created (up to but excluding i):
475 for (int j = 0; j < i; j++) {
476 (*array)[j]->unref();
477 }
478 // Delete the array
halcanary385fe4d2015-08-26 13:07:48 -0700479 delete[] * array;
halcanary96fcdcc2015-08-27 07:41:13 -0700480 *array = nullptr;
reed871872f2015-06-22 12:48:26 -0700481 *outCount = 0;
482 return false;
483 }
484 return true;
485}
486
487bool SkPictureData::parseBufferTag(SkReadBuffer& buffer, uint32_t tag, uint32_t size) {
reed@google.com67562092012-06-22 15:38:39 +0000488 switch (tag) {
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000489 case SK_PICT_BITMAP_BUFFER_TAG: {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000490 const int count = SkToInt(size);
mtklein703d3c72014-11-12 11:08:20 -0800491 fBitmaps.reset(count);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000492 for (int i = 0; i < count; ++i) {
mtklein703d3c72014-11-12 11:08:20 -0800493 SkBitmap* bm = &fBitmaps[i];
reedac6a2f92014-11-12 09:25:25 -0800494 if (buffer.readBitmap(bm)) {
495 bm->setImmutable();
496 } else {
497 return false;
498 }
reed@google.com67562092012-06-22 15:38:39 +0000499 }
500 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000501 case SK_PICT_PAINT_BUFFER_TAG: {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000502 const int count = SkToInt(size);
mtklein703d3c72014-11-12 11:08:20 -0800503 fPaints.reset(count);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000504 for (int i = 0; i < count; ++i) {
mtklein703d3c72014-11-12 11:08:20 -0800505 buffer.readPaint(&fPaints[i]);
reed@google.com67562092012-06-22 15:38:39 +0000506 }
507 } break;
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000508 case SK_PICT_PATH_BUFFER_TAG:
robertphillipse26e65e2014-06-12 05:51:22 -0700509 if (size > 0) {
mtklein71a23632014-11-12 10:24:55 -0800510 const int count = buffer.readInt();
mtklein703d3c72014-11-12 11:08:20 -0800511 fPaths.reset(count);
mtklein71a23632014-11-12 10:24:55 -0800512 for (int i = 0; i < count; i++) {
mtklein703d3c72014-11-12 11:08:20 -0800513 buffer.readPath(&fPaths[i]);
mtklein71a23632014-11-12 10:24:55 -0800514 }
515 } break;
reed871872f2015-06-22 12:48:26 -0700516 case SK_PICT_TEXTBLOB_BUFFER_TAG:
517 if (!new_array_from_buffer(buffer, size, &fTextBlobRefs, &fTextBlobCount,
518 SkTextBlob::CreateFromBuffer)) {
fmalitab7425172014-08-26 07:56:44 -0700519 return false;
520 }
reed871872f2015-06-22 12:48:26 -0700521 break;
522 case SK_PICT_IMAGE_BUFFER_TAG:
523 if (!new_array_from_buffer(buffer, size, &fImageRefs, &fImageCount,
524 create_image_from_buffer)) {
fmalitab7425172014-08-26 07:56:44 -0700525 return false;
526 }
reed871872f2015-06-22 12:48:26 -0700527 break;
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000528 case SK_PICT_READER_TAG: {
reedfde05112016-03-11 13:02:28 -0800529 auto data(SkData::MakeUninitialized(size));
reed9594da12014-09-12 12:12:27 -0700530 if (!buffer.readByteArray(data->writable_data(), size) ||
halcanary96fcdcc2015-08-27 07:41:13 -0700531 !buffer.validate(nullptr == fOpData)) {
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000532 return false;
533 }
halcanary96fcdcc2015-08-27 07:41:13 -0700534 SkASSERT(nullptr == fOpData);
reedfde05112016-03-11 13:02:28 -0800535 fOpData = std::move(data);
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000536 } break;
reed871872f2015-06-22 12:48:26 -0700537 case SK_PICT_PICTURE_TAG:
538 if (!new_array_from_buffer(buffer, size, &fPictureRefs, &fPictureCount,
539 create_picture_from_buffer)) {
commit-bot@chromium.org9e5f85e2014-03-12 14:46:41 +0000540 return false;
541 }
reedc2100352015-06-22 17:03:10 -0700542 break;
scroggo@google.com12705322013-10-01 15:30:46 +0000543 default:
544 // The tag was invalid.
545 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000546 }
scroggo@google.com12705322013-10-01 15:30:46 +0000547 return true; // success
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548}
549
robertphillipsdb539902014-07-01 08:47:04 -0700550SkPictureData* SkPictureData::CreateFromStream(SkStream* stream,
551 const SkPictInfo& info,
mtklein0c263fa2015-08-18 08:29:59 -0700552 SkPicture::InstallPixelRefProc proc,
553 SkTypefacePlayback* topLevelTFPlayback) {
halcanary385fe4d2015-08-26 13:07:48 -0700554 SkAutoTDelete<SkPictureData> data(new SkPictureData(info));
mtklein0c263fa2015-08-18 08:29:59 -0700555 if (!topLevelTFPlayback) {
556 topLevelTFPlayback = &data->fTFPlayback;
557 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000558
mtklein0c263fa2015-08-18 08:29:59 -0700559 if (!data->parseStream(stream, proc, topLevelTFPlayback)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700560 return nullptr;
scroggo@google.com12705322013-10-01 15:30:46 +0000561 }
mtklein18300a32016-03-16 13:53:35 -0700562 return data.release();
scroggo@google.com12705322013-10-01 15:30:46 +0000563}
564
robertphillipsdb539902014-07-01 08:47:04 -0700565SkPictureData* SkPictureData::CreateFromBuffer(SkReadBuffer& buffer,
566 const SkPictInfo& info) {
halcanary385fe4d2015-08-26 13:07:48 -0700567 SkAutoTDelete<SkPictureData> data(new SkPictureData(info));
commit-bot@chromium.org7ed173b2014-05-20 17:31:08 +0000568 buffer.setVersion(info.fVersion);
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000569
robertphillipsdb539902014-07-01 08:47:04 -0700570 if (!data->parseBuffer(buffer)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700571 return nullptr;
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000572 }
mtklein18300a32016-03-16 13:53:35 -0700573 return data.release();
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000574}
575
robertphillipsdb539902014-07-01 08:47:04 -0700576bool SkPictureData::parseStream(SkStream* stream,
mtklein0c263fa2015-08-18 08:29:59 -0700577 SkPicture::InstallPixelRefProc proc,
578 SkTypefacePlayback* topLevelTFPlayback) {
reed@google.com67562092012-06-22 15:38:39 +0000579 for (;;) {
580 uint32_t tag = stream->readU32();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000581 if (SK_PICT_EOF_TAG == tag) {
reed@google.com67562092012-06-22 15:38:39 +0000582 break;
583 }
reed@google.com82065d62011-02-07 15:30:46 +0000584
reed@google.comed384952012-06-22 13:12:17 +0000585 uint32_t size = stream->readU32();
mtklein0c263fa2015-08-18 08:29:59 -0700586 if (!this->parseStreamTag(stream, tag, size, proc, topLevelTFPlayback)) {
scroggo@google.com12705322013-10-01 15:30:46 +0000587 return false; // we're invalid
588 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000589 }
scroggo@google.com12705322013-10-01 15:30:46 +0000590 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000591}
592
robertphillipsdb539902014-07-01 08:47:04 -0700593bool SkPictureData::parseBuffer(SkReadBuffer& buffer) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000594 for (;;) {
595 uint32_t tag = buffer.readUInt();
commit-bot@chromium.org6f4fb0f2014-03-03 19:18:39 +0000596 if (SK_PICT_EOF_TAG == tag) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000597 break;
598 }
599
600 uint32_t size = buffer.readUInt();
robertphillipse26e65e2014-06-12 05:51:22 -0700601 if (!this->parseBufferTag(buffer, tag, size)) {
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000602 return false; // we're invalid
603 }
604 }
605 return true;
606}
607
reed@android.com8a1c16f2008-12-17 15:59:43 +0000608///////////////////////////////////////////////////////////////////////////////
609///////////////////////////////////////////////////////////////////////////////
610
robertphillips0bdbea72014-06-11 11:37:55 -0700611#if SK_SUPPORT_GPU
robertphillipsdb539902014-07-01 08:47:04 -0700612bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
hendrikwafdada22014-08-08 10:44:33 -0700613 int sampleCount) const {
614 return fContentInfo.suitableForGpuRasterization(context, reason, sampleCount);
robertphillips0bdbea72014-06-11 11:37:55 -0700615}
egdaniel12c21982014-06-18 07:34:39 -0700616
robertphillipsdb539902014-07-01 08:47:04 -0700617bool SkPictureData::suitableForGpuRasterization(GrContext* context, const char **reason,
618 GrPixelConfig config, SkScalar dpi) const {
egdaniel12c21982014-06-18 07:34:39 -0700619
halcanary96fcdcc2015-08-27 07:41:13 -0700620 if (context != nullptr) {
egdaniel12c21982014-06-18 07:34:39 -0700621 return this->suitableForGpuRasterization(context, reason,
622 context->getRecommendedSampleCount(config, dpi));
623 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700624 return this->suitableForGpuRasterization(nullptr, reason);
egdaniel12c21982014-06-18 07:34:39 -0700625 }
626}
627
robertphillipsc019ec42014-08-12 05:35:58 -0700628bool SkPictureData::suitableForLayerOptimization() const {
629 return fContentInfo.numLayers() > 0;
630}
robertphillips0bdbea72014-06-11 11:37:55 -0700631#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000632///////////////////////////////////////////////////////////////////////////////
633
reed@android.com8a1c16f2008-12-17 15:59:43 +0000634