blob: 7ddc77f93beffab298ca8ac183a1b1570c9cff3e [file] [log] [blame]
djsollen@google.com2b2ede32012-04-12 13:24:04 +00001
2/*
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00003 * Copyright 2012 Google Inc.
djsollen@google.com2b2ede32012-04-12 13:24:04 +00004 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00009#include "SkWriteBuffer.h"
junov@chromium.orgce65f382012-10-17 19:36:09 +000010#include "SkBitmap.h"
djsollen0b17d6c2014-11-13 12:52:35 -080011#include "SkBitmapHeap.h"
scroggo@google.com7c9d5392012-12-10 15:40:55 +000012#include "SkData.h"
reed@google.com672588b2014-01-08 15:42:01 +000013#include "SkPixelRef.h"
mike@reedtribe.org227b5162012-08-12 19:25:08 +000014#include "SkPtrRecorder.h"
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000015#include "SkStream.h"
djsollen@google.com2b2ede32012-04-12 13:24:04 +000016#include "SkTypeface.h"
17
commit-bot@chromium.orga2bd2d12014-01-30 22:16:32 +000018SkWriteBuffer::SkWriteBuffer(uint32_t flags)
19 : fFlags(flags)
halcanary96fcdcc2015-08-27 07:41:13 -070020 , fFactorySet(nullptr)
21 , fNamedFactorySet(nullptr)
22 , fBitmapHeap(nullptr)
23 , fTFSet(nullptr) {
djsollen@google.com2b2ede32012-04-12 13:24:04 +000024}
25
commit-bot@chromium.orga2bd2d12014-01-30 22:16:32 +000026SkWriteBuffer::SkWriteBuffer(void* storage, size_t storageSize, uint32_t flags)
27 : fFlags(flags)
halcanary96fcdcc2015-08-27 07:41:13 -070028 , fFactorySet(nullptr)
29 , fNamedFactorySet(nullptr)
commit-bot@chromium.org19382422014-01-14 20:51:26 +000030 , fWriter(storage, storageSize)
halcanary96fcdcc2015-08-27 07:41:13 -070031 , fBitmapHeap(nullptr)
32 , fTFSet(nullptr) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000033}
34
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000035SkWriteBuffer::~SkWriteBuffer() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000036 SkSafeUnref(fFactorySet);
37 SkSafeUnref(fNamedFactorySet);
djsollen@google.com21830d92012-08-07 19:49:41 +000038 SkSafeUnref(fBitmapHeap);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000039 SkSafeUnref(fTFSet);
40}
41
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000042void SkWriteBuffer::writeByteArray(const void* data, size_t size) {
reed@google.com6fcd28b2014-02-04 16:03:51 +000043 fWriter.write32(SkToU32(size));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000044 fWriter.writePad(data, size);
45}
46
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000047void SkWriteBuffer::writeBool(bool value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000048 fWriter.writeBool(value);
49}
50
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000051void SkWriteBuffer::writeFixed(SkFixed value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000052 fWriter.write32(value);
53}
54
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000055void SkWriteBuffer::writeScalar(SkScalar value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000056 fWriter.writeScalar(value);
57}
58
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000059void SkWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000060 fWriter.write32(count);
61 fWriter.write(value, count * sizeof(SkScalar));
62}
63
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000064void SkWriteBuffer::writeInt(int32_t value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000065 fWriter.write32(value);
66}
67
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000068void SkWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000069 fWriter.write32(count);
70 fWriter.write(value, count * sizeof(int32_t));
71}
72
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000073void SkWriteBuffer::writeUInt(uint32_t value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000074 fWriter.write32(value);
75}
76
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000077void SkWriteBuffer::write32(int32_t value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000078 fWriter.write32(value);
79}
80
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000081void SkWriteBuffer::writeString(const char* value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000082 fWriter.writeString(value);
83}
84
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000085void SkWriteBuffer::writeEncodedString(const void* value, size_t byteLength,
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000086 SkPaint::TextEncoding encoding) {
87 fWriter.writeInt(encoding);
reed@google.com6fcd28b2014-02-04 16:03:51 +000088 fWriter.writeInt(SkToU32(byteLength));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000089 fWriter.write(value, byteLength);
90}
91
92
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000093void SkWriteBuffer::writeColor(const SkColor& color) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000094 fWriter.write32(color);
95}
96
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000097void SkWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000098 fWriter.write32(count);
99 fWriter.write(color, count * sizeof(SkColor));
100}
101
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000102void SkWriteBuffer::writePoint(const SkPoint& point) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000103 fWriter.writeScalar(point.fX);
104 fWriter.writeScalar(point.fY);
105}
106
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000107void SkWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000108 fWriter.write32(count);
109 fWriter.write(point, count * sizeof(SkPoint));
110}
111
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000112void SkWriteBuffer::writeMatrix(const SkMatrix& matrix) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000113 fWriter.writeMatrix(matrix);
114}
115
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000116void SkWriteBuffer::writeIRect(const SkIRect& rect) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000117 fWriter.write(&rect, sizeof(SkIRect));
118}
119
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000120void SkWriteBuffer::writeRect(const SkRect& rect) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000121 fWriter.writeRect(rect);
122}
123
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000124void SkWriteBuffer::writeRegion(const SkRegion& region) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000125 fWriter.writeRegion(region);
126}
127
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000128void SkWriteBuffer::writePath(const SkPath& path) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000129 fWriter.writePath(path);
130}
131
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000132size_t SkWriteBuffer::writeStream(SkStream* stream, size_t length) {
reed@google.com6fcd28b2014-02-04 16:03:51 +0000133 fWriter.write32(SkToU32(length));
djsollen@google.come782f5e2013-01-23 13:40:40 +0000134 size_t bytesWritten = fWriter.readFromStream(stream, length);
135 if (bytesWritten < length) {
136 fWriter.reservePad(length - bytesWritten);
137 }
138 return bytesWritten;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000139}
140
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000141bool SkWriteBuffer::writeToStream(SkWStream* stream) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000142 return fWriter.writeToStream(stream);
143}
144
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000145static void write_encoded_bitmap(SkWriteBuffer* buffer, SkData* data,
reed@google.com672588b2014-01-08 15:42:01 +0000146 const SkIPoint& origin) {
147 buffer->writeUInt(SkToU32(data->size()));
148 buffer->getWriter32()->writePad(data->data(), data->size());
149 buffer->write32(origin.fX);
150 buffer->write32(origin.fY);
151}
scroggo@google.com1b1bcc32013-05-21 20:31:23 +0000152
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000153void SkWriteBuffer::writeBitmap(const SkBitmap& bitmap) {
scroggo@google.com74b7ffd2013-04-30 02:32:41 +0000154 // Record the width and height. This way if readBitmap fails a dummy bitmap can be drawn at the
155 // right size.
156 this->writeInt(bitmap.width());
157 this->writeInt(bitmap.height());
158
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000159 // Record information about the bitmap in one of three ways, in order of priority:
160 // 1. If there is an SkBitmapHeap, store it in the heap. The client can avoid serializing the
scroggo@google.com74b7ffd2013-04-30 02:32:41 +0000161 // bitmap entirely or serialize it later as desired. A boolean value of true will be written
162 // to the stream to signify that a heap was used.
scroggo@google.com1b1bcc32013-05-21 20:31:23 +0000163 // 2. If there is a function for encoding bitmaps, use it to write an encoded version of the
164 // bitmap. After writing a boolean value of false, signifying that a heap was not used, write
165 // the size of the encoded data. A non-zero size signifies that encoded data was written.
scroggo@google.com74b7ffd2013-04-30 02:32:41 +0000166 // 3. Call SkBitmap::flatten. After writing a boolean value of false, signifying that a heap was
167 // not used, write a zero to signify that the data was not encoded.
halcanary96fcdcc2015-08-27 07:41:13 -0700168 bool useBitmapHeap = fBitmapHeap != nullptr;
scroggo@google.com74b7ffd2013-04-30 02:32:41 +0000169 // Write a bool: true if the SkBitmapHeap is to be used, in which case the reader must use an
170 // SkBitmapHeapReader to read the SkBitmap. False if the bitmap was serialized another way.
171 this->writeBool(useBitmapHeap);
172 if (useBitmapHeap) {
halcanary96fcdcc2015-08-27 07:41:13 -0700173 SkASSERT(nullptr == fPixelSerializer);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000174 int32_t slot = fBitmapHeap->insert(bitmap);
175 fWriter.write32(slot);
176 // crbug.com/155875
177 // The generation ID is not required information. We write it to prevent collisions
178 // in SkFlatDictionary. It is possible to get a collision when a previously
179 // unflattened (i.e. stale) instance of a similar flattenable is in the dictionary
180 // and the instance currently being written is re-using the same slot from the
181 // bitmap heap.
182 fWriter.write32(bitmap.getGenerationID());
183 return;
184 }
reed@google.com672588b2014-01-08 15:42:01 +0000185
scroggo895c43b2014-12-11 10:53:58 -0800186 SkPixelRef* pixelRef = bitmap.pixelRef();
187 if (pixelRef) {
188 // see if the pixelref already has an encoded version
189 SkAutoDataUnref existingData(pixelRef->refEncodedData());
halcanary96fcdcc2015-08-27 07:41:13 -0700190 if (existingData.get() != nullptr) {
scroggo895c43b2014-12-11 10:53:58 -0800191 // Assumes that if the client did not set a serializer, they are
192 // happy to get the encoded data.
193 if (!fPixelSerializer || fPixelSerializer->useEncodedData(existingData->data(),
194 existingData->size())) {
195 write_encoded_bitmap(this, existingData, bitmap.pixelRefOrigin());
196 return;
197 }
scroggo@google.com5a7c6be2012-10-04 21:46:08 +0000198 }
reed@google.com672588b2014-01-08 15:42:01 +0000199
scroggo895c43b2014-12-11 10:53:58 -0800200 // see if the caller wants to manually encode
reed92fc2ae2015-05-22 08:06:21 -0700201 SkAutoPixmapUnlock result;
202 if (fPixelSerializer && bitmap.requestLock(&result)) {
203 const SkPixmap& pmap = result.pixmap();
halcanary96fcdcc2015-08-27 07:41:13 -0700204 SkASSERT(nullptr == fBitmapHeap);
reed92fc2ae2015-05-22 08:06:21 -0700205 SkAutoDataUnref data(fPixelSerializer->encodePixels(pmap.info(),
206 pmap.addr(),
207 pmap.rowBytes()));
halcanary96fcdcc2015-08-27 07:41:13 -0700208 if (data.get() != nullptr) {
scroggo895c43b2014-12-11 10:53:58 -0800209 // if we have to "encode" the bitmap, then we assume there is no
210 // offset to share, since we are effectively creating a new pixelref
211 write_encoded_bitmap(this, data, SkIPoint::Make(0, 0));
212 return;
213 }
reed@google.com672588b2014-01-08 15:42:01 +0000214 }
215 }
216
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000217 this->writeUInt(0); // signal raw pixels
218 SkBitmap::WriteRawPixels(this, bitmap);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000219}
220
reed871872f2015-06-22 12:48:26 -0700221static bool try_write_encoded(SkWriteBuffer* buffer, SkData* encoded) {
222 SkPixelSerializer* ps = buffer->getPixelSerializer();
223 // Assumes that if the client did not set a serializer, they are
224 // happy to get the encoded data.
225 if (!ps || ps->useEncodedData(encoded->data(), encoded->size())) {
226 write_encoded_bitmap(buffer, encoded, SkIPoint::Make(0, 0));
227 return true;
228 }
229 return false;
230}
231
232void SkWriteBuffer::writeImage(const SkImage* image) {
233 this->writeInt(image->width());
234 this->writeInt(image->height());
235
236 SkAutoTUnref<SkData> encoded(image->refEncoded());
237 if (encoded && try_write_encoded(this, encoded)) {
238 return;
239 }
240
241 encoded.reset(image->encode(SkImageEncoder::kPNG_Type, 100));
242 if (encoded && try_write_encoded(this, encoded)) {
243 return;
244 }
245
246 this->writeUInt(0); // signal no pixels (in place of the size of the encoded data)
247}
248
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000249void SkWriteBuffer::writeTypeface(SkTypeface* obj) {
halcanary96fcdcc2015-08-27 07:41:13 -0700250 if (nullptr == obj || nullptr == fTFSet) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000251 fWriter.write32(0);
252 } else {
253 fWriter.write32(fTFSet->add(obj));
254 }
255}
256
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000257SkFactorySet* SkWriteBuffer::setFactoryRecorder(SkFactorySet* rec) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000258 SkRefCnt_SafeAssign(fFactorySet, rec);
halcanary96fcdcc2015-08-27 07:41:13 -0700259 if (fNamedFactorySet != nullptr) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000260 fNamedFactorySet->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700261 fNamedFactorySet = nullptr;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000262 }
263 return rec;
264}
265
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000266SkNamedFactorySet* SkWriteBuffer::setNamedFactoryRecorder(SkNamedFactorySet* rec) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000267 SkRefCnt_SafeAssign(fNamedFactorySet, rec);
halcanary96fcdcc2015-08-27 07:41:13 -0700268 if (fFactorySet != nullptr) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000269 fFactorySet->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700270 fFactorySet = nullptr;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000271 }
272 return rec;
273}
274
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000275SkRefCntSet* SkWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000276 SkRefCnt_SafeAssign(fTFSet, rec);
277 return rec;
reed@google.come49aca92012-04-24 21:12:39 +0000278}
279
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000280void SkWriteBuffer::setBitmapHeap(SkBitmapHeap* bitmapHeap) {
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000281 SkRefCnt_SafeAssign(fBitmapHeap, bitmapHeap);
halcanary96fcdcc2015-08-27 07:41:13 -0700282 if (bitmapHeap != nullptr) {
283 SkASSERT(nullptr == fPixelSerializer);
284 fPixelSerializer.reset(nullptr);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000285 }
286}
287
scroggo895c43b2014-12-11 10:53:58 -0800288void SkWriteBuffer::setPixelSerializer(SkPixelSerializer* serializer) {
289 fPixelSerializer.reset(serializer);
290 if (serializer) {
291 serializer->ref();
halcanary96fcdcc2015-08-27 07:41:13 -0700292 SkASSERT(nullptr == fBitmapHeap);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000293 SkSafeUnref(fBitmapHeap);
halcanary96fcdcc2015-08-27 07:41:13 -0700294 fBitmapHeap = nullptr;
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000295 }
296}
297
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000298void SkWriteBuffer::writeFlattenable(const SkFlattenable* flattenable) {
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000299 /*
300 * If we have a factoryset, then the first 32bits tell us...
301 * 0: failure to write the flattenable
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000302 * >0: (1-based) index into the SkFactorySet or SkNamedFactorySet
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000303 * If we don't have a factoryset, then the first "ptr" is either the
304 * factory, or null for failure.
305 *
306 * The distinction is important, since 0-index is 32bits (always), but a
307 * 0-functionptr might be 32 or 64 bits.
308 */
halcanary96fcdcc2015-08-27 07:41:13 -0700309 if (nullptr == flattenable) {
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000310 if (this->isValidating()) {
311 this->writeString("");
halcanary96fcdcc2015-08-27 07:41:13 -0700312 } else if (fFactorySet != nullptr || fNamedFactorySet != nullptr) {
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000313 this->write32(0);
314 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700315 this->writeFunctionPtr(nullptr);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000316 }
317 return;
318 }
319
commit-bot@chromium.org210a6aa2014-03-07 14:52:09 +0000320 SkFlattenable::Factory factory = flattenable->getFactory();
halcanary96fcdcc2015-08-27 07:41:13 -0700321 SkASSERT(factory != nullptr);
commit-bot@chromium.org210a6aa2014-03-07 14:52:09 +0000322
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000323 /*
324 * We can write 1 of 3 versions of the flattenable:
325 * 1. function-ptr : this is the fastest for the reader, but assumes that
326 * the writer and reader are in the same process.
327 * 2. index into fFactorySet : This is assumes the writer will later
328 * resolve the function-ptrs into strings for its reader. SkPicture
329 * does exactly this, by writing a table of names (matching the indices)
330 * up front in its serialized form.
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000331 * 3. index into fNamedFactorySet. fNamedFactorySet will also store the
332 * name. SkGPipe uses this technique so it can write the name to its
333 * stream before writing the flattenable.
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000334 */
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000335 if (this->isValidating()) {
336 this->writeString(flattenable->getTypeName());
337 } else if (fFactorySet) {
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000338 this->write32(fFactorySet->add(factory));
339 } else if (fNamedFactorySet) {
340 int32_t index = fNamedFactorySet->find(factory);
341 this->write32(index);
342 if (0 == index) {
343 return;
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000344 }
345 } else {
346 this->writeFunctionPtr((void*)factory);
347 }
348
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000349 // make room for the size of the flattened object
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000350 (void)fWriter.reserve(sizeof(uint32_t));
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000351 // record the current size, so we can subtract after the object writes.
reed@google.com6fcd28b2014-02-04 16:03:51 +0000352 size_t offset = fWriter.bytesWritten();
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000353 // now flatten the object
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000354 flattenable->flatten(*this);
reed@google.com6fcd28b2014-02-04 16:03:51 +0000355 size_t objSize = fWriter.bytesWritten() - offset;
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000356 // record the obj's size
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000357 fWriter.overwriteTAt(offset - sizeof(uint32_t), SkToU32(objSize));
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000358}