blob: c33a7aec52c7e8d3e06676a95ce0c87b09787b81 [file] [log] [blame]
djsollen@google.com2b2ede32012-04-12 13:24:04 +00001/*
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00002 * Copyright 2012 Google Inc.
djsollen@google.com2b2ede32012-04-12 13:24:04 +00003 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00008#include "SkWriteBuffer.h"
junov@chromium.orgce65f382012-10-17 19:36:09 +00009#include "SkBitmap.h"
djsollen0b17d6c2014-11-13 12:52:35 -080010#include "SkBitmapHeap.h"
scroggo@google.com7c9d5392012-12-10 15:40:55 +000011#include "SkData.h"
reed@google.com672588b2014-01-08 15:42:01 +000012#include "SkPixelRef.h"
mike@reedtribe.org227b5162012-08-12 19:25:08 +000013#include "SkPtrRecorder.h"
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000014#include "SkStream.h"
djsollen@google.com2b2ede32012-04-12 13:24:04 +000015#include "SkTypeface.h"
16
commit-bot@chromium.orga2bd2d12014-01-30 22:16:32 +000017SkWriteBuffer::SkWriteBuffer(uint32_t flags)
18 : fFlags(flags)
halcanary96fcdcc2015-08-27 07:41:13 -070019 , fFactorySet(nullptr)
20 , fNamedFactorySet(nullptr)
21 , fBitmapHeap(nullptr)
22 , fTFSet(nullptr) {
djsollen@google.com2b2ede32012-04-12 13:24:04 +000023}
24
commit-bot@chromium.orga2bd2d12014-01-30 22:16:32 +000025SkWriteBuffer::SkWriteBuffer(void* storage, size_t storageSize, uint32_t flags)
26 : fFlags(flags)
halcanary96fcdcc2015-08-27 07:41:13 -070027 , fFactorySet(nullptr)
28 , fNamedFactorySet(nullptr)
commit-bot@chromium.org19382422014-01-14 20:51:26 +000029 , fWriter(storage, storageSize)
halcanary96fcdcc2015-08-27 07:41:13 -070030 , fBitmapHeap(nullptr)
31 , fTFSet(nullptr) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000032}
33
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000034SkWriteBuffer::~SkWriteBuffer() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000035 SkSafeUnref(fFactorySet);
36 SkSafeUnref(fNamedFactorySet);
djsollen@google.com21830d92012-08-07 19:49:41 +000037 SkSafeUnref(fBitmapHeap);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000038 SkSafeUnref(fTFSet);
39}
40
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000041void SkWriteBuffer::writeByteArray(const void* data, size_t size) {
reed@google.com6fcd28b2014-02-04 16:03:51 +000042 fWriter.write32(SkToU32(size));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000043 fWriter.writePad(data, size);
44}
45
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000046void SkWriteBuffer::writeBool(bool value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000047 fWriter.writeBool(value);
48}
49
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000050void SkWriteBuffer::writeScalar(SkScalar value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000051 fWriter.writeScalar(value);
52}
53
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000054void SkWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000055 fWriter.write32(count);
56 fWriter.write(value, count * sizeof(SkScalar));
57}
58
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000059void SkWriteBuffer::writeInt(int32_t value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000060 fWriter.write32(value);
61}
62
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000063void SkWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000064 fWriter.write32(count);
65 fWriter.write(value, count * sizeof(int32_t));
66}
67
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000068void SkWriteBuffer::writeUInt(uint32_t value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000069 fWriter.write32(value);
70}
71
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000072void SkWriteBuffer::write32(int32_t value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000073 fWriter.write32(value);
74}
75
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000076void SkWriteBuffer::writeString(const char* value) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000077 fWriter.writeString(value);
78}
79
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000080void SkWriteBuffer::writeEncodedString(const void* value, size_t byteLength,
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000081 SkPaint::TextEncoding encoding) {
82 fWriter.writeInt(encoding);
reed@google.com6fcd28b2014-02-04 16:03:51 +000083 fWriter.writeInt(SkToU32(byteLength));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000084 fWriter.write(value, byteLength);
85}
86
87
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000088void SkWriteBuffer::writeColor(const SkColor& color) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000089 fWriter.write32(color);
90}
91
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000092void SkWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000093 fWriter.write32(count);
94 fWriter.write(color, count * sizeof(SkColor));
95}
96
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000097void SkWriteBuffer::writePoint(const SkPoint& point) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000098 fWriter.writeScalar(point.fX);
99 fWriter.writeScalar(point.fY);
100}
101
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000102void SkWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000103 fWriter.write32(count);
104 fWriter.write(point, count * sizeof(SkPoint));
105}
106
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000107void SkWriteBuffer::writeMatrix(const SkMatrix& matrix) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000108 fWriter.writeMatrix(matrix);
109}
110
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000111void SkWriteBuffer::writeIRect(const SkIRect& rect) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000112 fWriter.write(&rect, sizeof(SkIRect));
113}
114
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000115void SkWriteBuffer::writeRect(const SkRect& rect) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000116 fWriter.writeRect(rect);
117}
118
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000119void SkWriteBuffer::writeRegion(const SkRegion& region) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000120 fWriter.writeRegion(region);
121}
122
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000123void SkWriteBuffer::writePath(const SkPath& path) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000124 fWriter.writePath(path);
125}
126
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000127size_t SkWriteBuffer::writeStream(SkStream* stream, size_t length) {
reed@google.com6fcd28b2014-02-04 16:03:51 +0000128 fWriter.write32(SkToU32(length));
djsollen@google.come782f5e2013-01-23 13:40:40 +0000129 size_t bytesWritten = fWriter.readFromStream(stream, length);
130 if (bytesWritten < length) {
131 fWriter.reservePad(length - bytesWritten);
132 }
133 return bytesWritten;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000134}
135
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000136bool SkWriteBuffer::writeToStream(SkWStream* stream) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000137 return fWriter.writeToStream(stream);
138}
139
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000140static void write_encoded_bitmap(SkWriteBuffer* buffer, SkData* data,
reed@google.com672588b2014-01-08 15:42:01 +0000141 const SkIPoint& origin) {
142 buffer->writeUInt(SkToU32(data->size()));
143 buffer->getWriter32()->writePad(data->data(), data->size());
144 buffer->write32(origin.fX);
145 buffer->write32(origin.fY);
146}
scroggo@google.com1b1bcc32013-05-21 20:31:23 +0000147
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000148void SkWriteBuffer::writeBitmap(const SkBitmap& bitmap) {
scroggo@google.com74b7ffd2013-04-30 02:32:41 +0000149 // Record the width and height. This way if readBitmap fails a dummy bitmap can be drawn at the
150 // right size.
151 this->writeInt(bitmap.width());
152 this->writeInt(bitmap.height());
153
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000154 // Record information about the bitmap in one of three ways, in order of priority:
155 // 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 +0000156 // bitmap entirely or serialize it later as desired. A boolean value of true will be written
157 // to the stream to signify that a heap was used.
scroggo@google.com1b1bcc32013-05-21 20:31:23 +0000158 // 2. If there is a function for encoding bitmaps, use it to write an encoded version of the
159 // bitmap. After writing a boolean value of false, signifying that a heap was not used, write
160 // the size of the encoded data. A non-zero size signifies that encoded data was written.
scroggo@google.com74b7ffd2013-04-30 02:32:41 +0000161 // 3. Call SkBitmap::flatten. After writing a boolean value of false, signifying that a heap was
162 // not used, write a zero to signify that the data was not encoded.
halcanary96fcdcc2015-08-27 07:41:13 -0700163 bool useBitmapHeap = fBitmapHeap != nullptr;
scroggo@google.com74b7ffd2013-04-30 02:32:41 +0000164 // Write a bool: true if the SkBitmapHeap is to be used, in which case the reader must use an
165 // SkBitmapHeapReader to read the SkBitmap. False if the bitmap was serialized another way.
166 this->writeBool(useBitmapHeap);
167 if (useBitmapHeap) {
halcanary96fcdcc2015-08-27 07:41:13 -0700168 SkASSERT(nullptr == fPixelSerializer);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000169 int32_t slot = fBitmapHeap->insert(bitmap);
170 fWriter.write32(slot);
171 // crbug.com/155875
172 // The generation ID is not required information. We write it to prevent collisions
173 // in SkFlatDictionary. It is possible to get a collision when a previously
174 // unflattened (i.e. stale) instance of a similar flattenable is in the dictionary
175 // and the instance currently being written is re-using the same slot from the
176 // bitmap heap.
177 fWriter.write32(bitmap.getGenerationID());
178 return;
179 }
reed@google.com672588b2014-01-08 15:42:01 +0000180
scroggo895c43b2014-12-11 10:53:58 -0800181 SkPixelRef* pixelRef = bitmap.pixelRef();
182 if (pixelRef) {
183 // see if the pixelref already has an encoded version
reedc9e190d2015-09-28 09:58:41 -0700184 SkAutoDataUnref existingData(pixelRef->refEncodedData());
185 if (existingData.get() != nullptr) {
scroggo895c43b2014-12-11 10:53:58 -0800186 // Assumes that if the client did not set a serializer, they are
187 // happy to get the encoded data.
reedc9e190d2015-09-28 09:58:41 -0700188 if (!fPixelSerializer || fPixelSerializer->useEncodedData(existingData->data(),
189 existingData->size())) {
190 write_encoded_bitmap(this, existingData, bitmap.pixelRefOrigin());
scroggo895c43b2014-12-11 10:53:58 -0800191 return;
192 }
scroggo@google.com5a7c6be2012-10-04 21:46:08 +0000193 }
reed@google.com672588b2014-01-08 15:42:01 +0000194
scroggo895c43b2014-12-11 10:53:58 -0800195 // see if the caller wants to manually encode
reed92fc2ae2015-05-22 08:06:21 -0700196 SkAutoPixmapUnlock result;
197 if (fPixelSerializer && bitmap.requestLock(&result)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700198 SkASSERT(nullptr == fBitmapHeap);
halcanary6b280172015-12-07 12:42:24 -0800199 SkAutoDataUnref data(fPixelSerializer->encode(result.pixmap()));
reedc9e190d2015-09-28 09:58:41 -0700200 if (data.get() != nullptr) {
scroggo895c43b2014-12-11 10:53:58 -0800201 // if we have to "encode" the bitmap, then we assume there is no
202 // offset to share, since we are effectively creating a new pixelref
203 write_encoded_bitmap(this, data, SkIPoint::Make(0, 0));
204 return;
205 }
reed@google.com672588b2014-01-08 15:42:01 +0000206 }
207 }
208
commit-bot@chromium.org968edca2014-05-23 13:21:55 +0000209 this->writeUInt(0); // signal raw pixels
210 SkBitmap::WriteRawPixels(this, bitmap);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000211}
212
reed871872f2015-06-22 12:48:26 -0700213void SkWriteBuffer::writeImage(const SkImage* image) {
214 this->writeInt(image->width());
215 this->writeInt(image->height());
216
fmalita2be71252015-09-03 07:17:25 -0700217 SkAutoTUnref<SkData> encoded(image->encode(this->getPixelSerializer()));
fmalitac3470342015-09-04 11:36:39 -0700218 if (encoded && encoded->size() > 0) {
fmalita2be71252015-09-03 07:17:25 -0700219 write_encoded_bitmap(this, encoded, SkIPoint::Make(0, 0));
reed871872f2015-06-22 12:48:26 -0700220 return;
221 }
222
reed871872f2015-06-22 12:48:26 -0700223 this->writeUInt(0); // signal no pixels (in place of the size of the encoded data)
224}
225
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000226void SkWriteBuffer::writeTypeface(SkTypeface* obj) {
halcanary96fcdcc2015-08-27 07:41:13 -0700227 if (nullptr == obj || nullptr == fTFSet) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000228 fWriter.write32(0);
229 } else {
230 fWriter.write32(fTFSet->add(obj));
231 }
232}
233
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000234SkFactorySet* SkWriteBuffer::setFactoryRecorder(SkFactorySet* rec) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000235 SkRefCnt_SafeAssign(fFactorySet, rec);
halcanary96fcdcc2015-08-27 07:41:13 -0700236 if (fNamedFactorySet != nullptr) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000237 fNamedFactorySet->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700238 fNamedFactorySet = nullptr;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000239 }
240 return rec;
241}
242
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000243SkNamedFactorySet* SkWriteBuffer::setNamedFactoryRecorder(SkNamedFactorySet* rec) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000244 SkRefCnt_SafeAssign(fNamedFactorySet, rec);
halcanary96fcdcc2015-08-27 07:41:13 -0700245 if (fFactorySet != nullptr) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000246 fFactorySet->unref();
halcanary96fcdcc2015-08-27 07:41:13 -0700247 fFactorySet = nullptr;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000248 }
249 return rec;
250}
251
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000252SkRefCntSet* SkWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000253 SkRefCnt_SafeAssign(fTFSet, rec);
254 return rec;
reed@google.come49aca92012-04-24 21:12:39 +0000255}
256
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000257void SkWriteBuffer::setBitmapHeap(SkBitmapHeap* bitmapHeap) {
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000258 SkRefCnt_SafeAssign(fBitmapHeap, bitmapHeap);
halcanary96fcdcc2015-08-27 07:41:13 -0700259 if (bitmapHeap != nullptr) {
260 SkASSERT(nullptr == fPixelSerializer);
261 fPixelSerializer.reset(nullptr);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000262 }
263}
264
scroggo895c43b2014-12-11 10:53:58 -0800265void SkWriteBuffer::setPixelSerializer(SkPixelSerializer* serializer) {
266 fPixelSerializer.reset(serializer);
267 if (serializer) {
268 serializer->ref();
halcanary96fcdcc2015-08-27 07:41:13 -0700269 SkASSERT(nullptr == fBitmapHeap);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000270 SkSafeUnref(fBitmapHeap);
halcanary96fcdcc2015-08-27 07:41:13 -0700271 fBitmapHeap = nullptr;
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000272 }
273}
274
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000275void SkWriteBuffer::writeFlattenable(const SkFlattenable* flattenable) {
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000276 /*
277 * If we have a factoryset, then the first 32bits tell us...
278 * 0: failure to write the flattenable
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000279 * >0: (1-based) index into the SkFactorySet or SkNamedFactorySet
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000280 * If we don't have a factoryset, then the first "ptr" is either the
281 * factory, or null for failure.
282 *
283 * The distinction is important, since 0-index is 32bits (always), but a
284 * 0-functionptr might be 32 or 64 bits.
285 */
halcanary96fcdcc2015-08-27 07:41:13 -0700286 if (nullptr == flattenable) {
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000287 if (this->isValidating()) {
288 this->writeString("");
halcanary96fcdcc2015-08-27 07:41:13 -0700289 } else if (fFactorySet != nullptr || fNamedFactorySet != nullptr) {
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000290 this->write32(0);
291 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700292 this->writeFunctionPtr(nullptr);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000293 }
294 return;
295 }
296
commit-bot@chromium.org210a6aa2014-03-07 14:52:09 +0000297 SkFlattenable::Factory factory = flattenable->getFactory();
halcanary96fcdcc2015-08-27 07:41:13 -0700298 SkASSERT(factory != nullptr);
commit-bot@chromium.org210a6aa2014-03-07 14:52:09 +0000299
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000300 /*
301 * We can write 1 of 3 versions of the flattenable:
302 * 1. function-ptr : this is the fastest for the reader, but assumes that
303 * the writer and reader are in the same process.
304 * 2. index into fFactorySet : This is assumes the writer will later
305 * resolve the function-ptrs into strings for its reader. SkPicture
306 * does exactly this, by writing a table of names (matching the indices)
307 * up front in its serialized form.
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000308 * 3. index into fNamedFactorySet. fNamedFactorySet will also store the
309 * name. SkGPipe uses this technique so it can write the name to its
310 * stream before writing the flattenable.
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000311 */
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000312 if (this->isValidating()) {
313 this->writeString(flattenable->getTypeName());
314 } else if (fFactorySet) {
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000315 this->write32(fFactorySet->add(factory));
316 } else if (fNamedFactorySet) {
317 int32_t index = fNamedFactorySet->find(factory);
318 this->write32(index);
319 if (0 == index) {
320 return;
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000321 }
322 } else {
323 this->writeFunctionPtr((void*)factory);
324 }
325
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000326 // make room for the size of the flattened object
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000327 (void)fWriter.reserve(sizeof(uint32_t));
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000328 // record the current size, so we can subtract after the object writes.
reed@google.com6fcd28b2014-02-04 16:03:51 +0000329 size_t offset = fWriter.bytesWritten();
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000330 // now flatten the object
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000331 flattenable->flatten(*this);
reed@google.com6fcd28b2014-02-04 16:03:51 +0000332 size_t objSize = fWriter.bytesWritten() - offset;
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000333 // record the obj's size
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000334 fWriter.overwriteTAt(offset - sizeof(uint32_t), SkToU32(objSize));
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000335}