blob: c32c7bd658672b3531900f3484363251223f91e1 [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
scroggo@google.comf8d7d272013-02-22 21:38:35 +00009#include "SkBitmap.h"
scroggo@google.com49ce11b2013-04-25 18:29:32 +000010#include "SkErrorInternals.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000011#include "SkReadBuffer.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000012#include "SkStream.h"
djsollen@google.com2b2ede32012-04-12 13:24:04 +000013#include "SkTypeface.h"
14
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000015static uint32_t default_flags() {
16 uint32_t flags = 0;
17#ifdef SK_SCALAR_IS_FLOAT
18 flags |= SkReadBuffer::kScalarIsFloat_Flag;
19#endif
20 if (8 == sizeof(void*)) {
21 flags |= SkReadBuffer::kPtrIs64Bit_Flag;
22 }
23 return flags;
24}
25
26SkReadBuffer::SkReadBuffer() {
27 fFlags = default_flags();
commit-bot@chromium.org7ed173b2014-05-20 17:31:08 +000028 fVersion = 0;
djsollen@google.com21830d92012-08-07 19:49:41 +000029 fMemoryPtr = NULL;
djsollen@google.com2b2ede32012-04-12 13:24:04 +000030
djsollen@google.com21830d92012-08-07 19:49:41 +000031 fBitmapStorage = NULL;
32 fTFArray = NULL;
33 fTFCount = 0;
34
35 fFactoryTDArray = NULL;
36 fFactoryArray = NULL;
37 fFactoryCount = 0;
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000038 fBitmapDecoder = NULL;
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +000039#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
40 fDecodedBitmapIndex = -1;
41#endif // DEBUG_NON_DETERMINISTIC_ASSERT
djsollen@google.com21830d92012-08-07 19:49:41 +000042}
43
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000044SkReadBuffer::SkReadBuffer(const void* data, size_t size) {
45 fFlags = default_flags();
commit-bot@chromium.org7ed173b2014-05-20 17:31:08 +000046 fVersion = 0;
djsollen@google.com2b2ede32012-04-12 13:24:04 +000047 fReader.setMemory(data, size);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000048 fMemoryPtr = NULL;
49
djsollen@google.com21830d92012-08-07 19:49:41 +000050 fBitmapStorage = NULL;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000051 fTFArray = NULL;
52 fTFCount = 0;
53
54 fFactoryTDArray = NULL;
55 fFactoryArray = NULL;
56 fFactoryCount = 0;
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000057 fBitmapDecoder = NULL;
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +000058#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
59 fDecodedBitmapIndex = -1;
60#endif // DEBUG_NON_DETERMINISTIC_ASSERT
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000061}
62
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000063SkReadBuffer::SkReadBuffer(SkStream* stream) {
64 fFlags = default_flags();
commit-bot@chromium.org7ed173b2014-05-20 17:31:08 +000065 fVersion = 0;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000066 const size_t length = stream->getLength();
67 fMemoryPtr = sk_malloc_throw(length);
68 stream->read(fMemoryPtr, length);
69 fReader.setMemory(fMemoryPtr, length);
djsollen@google.com21830d92012-08-07 19:49:41 +000070
71 fBitmapStorage = NULL;
72 fTFArray = NULL;
73 fTFCount = 0;
74
75 fFactoryTDArray = NULL;
76 fFactoryArray = NULL;
77 fFactoryCount = 0;
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000078 fBitmapDecoder = NULL;
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +000079#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
80 fDecodedBitmapIndex = -1;
81#endif // DEBUG_NON_DETERMINISTIC_ASSERT
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000082}
83
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000084SkReadBuffer::~SkReadBuffer() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000085 sk_free(fMemoryPtr);
djsollen@google.com21830d92012-08-07 19:49:41 +000086 SkSafeUnref(fBitmapStorage);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000087}
88
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000089bool SkReadBuffer::readBool() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000090 return fReader.readBool();
91}
92
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000093SkColor SkReadBuffer::readColor() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000094 return fReader.readInt();
95}
96
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000097SkFixed SkReadBuffer::readFixed() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000098 return fReader.readS32();
99}
100
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000101int32_t SkReadBuffer::readInt() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000102 return fReader.readInt();
103}
104
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000105SkScalar SkReadBuffer::readScalar() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000106 return fReader.readScalar();
107}
108
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000109uint32_t SkReadBuffer::readUInt() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000110 return fReader.readU32();
111}
112
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000113int32_t SkReadBuffer::read32() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000114 return fReader.readInt();
115}
116
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000117void SkReadBuffer::readString(SkString* string) {
djsollen@google.com77687512013-05-21 16:17:14 +0000118 size_t len;
119 const char* strContents = fReader.readString(&len);
120 string->set(strContents, len);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000121}
122
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000123void* SkReadBuffer::readEncodedString(size_t* length, SkPaint::TextEncoding encoding) {
humper@google.com0e515772013-01-07 19:54:40 +0000124 SkDEBUGCODE(int32_t encodingType = ) fReader.readInt();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000125 SkASSERT(encodingType == encoding);
126 *length = fReader.readInt();
127 void* data = sk_malloc_throw(*length);
128 memcpy(data, fReader.skip(SkAlign4(*length)), *length);
129 return data;
130}
131
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000132void SkReadBuffer::readPoint(SkPoint* point) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000133 point->fX = fReader.readScalar();
134 point->fY = fReader.readScalar();
135}
136
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000137void SkReadBuffer::readMatrix(SkMatrix* matrix) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000138 fReader.readMatrix(matrix);
139}
140
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000141void SkReadBuffer::readIRect(SkIRect* rect) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000142 memcpy(rect, fReader.skip(sizeof(SkIRect)), sizeof(SkIRect));
143}
144
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000145void SkReadBuffer::readRect(SkRect* rect) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000146 memcpy(rect, fReader.skip(sizeof(SkRect)), sizeof(SkRect));
147}
148
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000149void SkReadBuffer::readRegion(SkRegion* region) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000150 fReader.readRegion(region);
151}
152
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000153void SkReadBuffer::readPath(SkPath* path) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000154 fReader.readPath(path);
155}
156
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000157bool SkReadBuffer::readArray(void* value, size_t size, size_t elementSize) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000158 const size_t count = this->getArrayCount();
159 if (count == size) {
160 (void)fReader.skip(sizeof(uint32_t)); // Skip array count
161 const size_t byteLength = count * elementSize;
162 memcpy(value, fReader.skip(SkAlign4(byteLength)), byteLength);
163 return true;
164 }
165 SkASSERT(false);
166 fReader.skip(fReader.available());
167 return false;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000168}
169
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000170bool SkReadBuffer::readByteArray(void* value, size_t size) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000171 return readArray(static_cast<unsigned char*>(value), size, sizeof(unsigned char));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000172}
173
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000174bool SkReadBuffer::readColorArray(SkColor* colors, size_t size) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000175 return readArray(colors, size, sizeof(SkColor));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000176}
177
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000178bool SkReadBuffer::readIntArray(int32_t* values, size_t size) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000179 return readArray(values, size, sizeof(int32_t));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000180}
181
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000182bool SkReadBuffer::readPointArray(SkPoint* points, size_t size) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000183 return readArray(points, size, sizeof(SkPoint));
184}
185
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000186bool SkReadBuffer::readScalarArray(SkScalar* values, size_t size) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000187 return readArray(values, size, sizeof(SkScalar));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000188}
189
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000190uint32_t SkReadBuffer::getArrayCount() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000191 return *(uint32_t*)fReader.peek();
192}
193
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000194void SkReadBuffer::readBitmap(SkBitmap* bitmap) {
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000195 const int width = this->readInt();
196 const int height = this->readInt();
197 // The writer stored a boolean value to determine whether an SkBitmapHeap was used during
198 // writing.
199 if (this->readBool()) {
200 // An SkBitmapHeap was used for writing. Read the index from the stream and find the
201 // corresponding SkBitmap in fBitmapStorage.
202 const uint32_t index = fReader.readU32();
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000203 fReader.readU32(); // bitmap generation ID (see SkWriteBuffer::writeBitmap)
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000204 if (fBitmapStorage) {
205 *bitmap = *fBitmapStorage->getBitmap(index);
206 fBitmapStorage->releaseRef(index);
207 return;
scroggo@google.com0cb7df92013-04-30 02:37:56 +0000208 } else {
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000209 // The bitmap was stored in a heap, but there is no way to access it. Set an error and
210 // fall through to use a place holder bitmap.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000211 SkErrorInternals::SetError(kParseError_SkError, "SkWriteBuffer::writeBitmap "
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000212 "stored the SkBitmap in an SkBitmapHeap, but "
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000213 "SkReadBuffer has no SkBitmapHeapReader to "
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000214 "retrieve the SkBitmap.");
scroggo@google.com0cb7df92013-04-30 02:37:56 +0000215 }
216 } else {
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000217 // The writer stored false, meaning the SkBitmap was not stored in an SkBitmapHeap.
218 const size_t length = this->readUInt();
219 if (length > 0) {
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +0000220#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
221 fDecodedBitmapIndex++;
222#endif // DEBUG_NON_DETERMINISTIC_ASSERT
scroggo@google.com2d76d932013-05-31 14:39:54 +0000223 // A non-zero size means the SkBitmap was encoded. Read the data and pixel
224 // offset.
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000225 const void* data = this->skip(length);
scroggo@google.com2d76d932013-05-31 14:39:54 +0000226 const int32_t xOffset = fReader.readS32();
227 const int32_t yOffset = fReader.readS32();
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000228 if (fBitmapDecoder != NULL && fBitmapDecoder(data, length, bitmap)) {
scroggo@google.com719a3732013-05-16 19:35:39 +0000229 if (bitmap->width() == width && bitmap->height() == height) {
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +0000230#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
231 if (0 != xOffset || 0 != yOffset) {
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000232 SkDebugf("SkReadBuffer::readBitmap: heights match,"
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +0000233 " but offset is not zero. \nInfo about the bitmap:"
234 "\n\tIndex: %d\n\tDimensions: [%d %d]\n\tEncoded"
235 " data size: %d\n\tOffset: (%d, %d)\n",
236 fDecodedBitmapIndex, width, height, length, xOffset,
237 yOffset);
238 }
239#endif // DEBUG_NON_DETERMINISTIC_ASSERT
scroggo@google.com2d76d932013-05-31 14:39:54 +0000240 // If the width and height match, there should be no offset.
241 SkASSERT(0 == xOffset && 0 == yOffset);
scroggo@google.com719a3732013-05-16 19:35:39 +0000242 return;
243 }
244
245 // This case can only be reached if extractSubset was called, so
scroggo@google.com02076832013-12-16 20:02:03 +0000246 // the recorded width and height must be smaller than or equal to
scroggo@google.com719a3732013-05-16 19:35:39 +0000247 // the encoded width and height.
scroggo@google.com02076832013-12-16 20:02:03 +0000248 // FIXME (scroggo): This assert assumes that our decoder and the
249 // sources encoder agree on the width and height which may not
250 // always be the case. Removing until it can be investigated
251 // further.
252 //SkASSERT(width <= bitmap->width() && height <= bitmap->height());
scroggo@google.com719a3732013-05-16 19:35:39 +0000253
scroggo@google.com719a3732013-05-16 19:35:39 +0000254 SkBitmap subsetBm;
scroggo@google.com2d76d932013-05-31 14:39:54 +0000255 SkIRect subset = SkIRect::MakeXYWH(xOffset, yOffset, width, height);
scroggo@google.com719a3732013-05-16 19:35:39 +0000256 if (bitmap->extractSubset(&subsetBm, subset)) {
257 bitmap->swap(subsetBm);
258 return;
259 }
scroggo@google.com0cb7df92013-04-30 02:37:56 +0000260 }
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000261 // This bitmap was encoded when written, but we are unable to decode, possibly due to
262 // not having a decoder.
263 SkErrorInternals::SetError(kParseError_SkError,
264 "Could not decode bitmap. Resulting bitmap will be red.");
scroggo@google.com0cb7df92013-04-30 02:37:56 +0000265 } else {
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000266 // A size of zero means the SkBitmap was simply flattened.
267 bitmap->unflatten(*this);
268 return;
scroggo@google.com5a7c6be2012-10-04 21:46:08 +0000269 }
djsollen@google.com21830d92012-08-07 19:49:41 +0000270 }
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000271 // Could not read the SkBitmap. Use a placeholder bitmap.
reed@google.com9ebcac52014-01-24 18:53:42 +0000272 bitmap->allocPixels(SkImageInfo::MakeN32Premul(width, height));
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000273 bitmap->eraseColor(SK_ColorRED);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000274}
275
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000276SkTypeface* SkReadBuffer::readTypeface() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000277
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000278 uint32_t index = fReader.readU32();
279 if (0 == index || index > (unsigned)fTFCount) {
280 if (index) {
281 SkDebugf("====== typeface index %d\n", index);
282 }
283 return NULL;
284 } else {
285 SkASSERT(fTFArray);
286 return fTFArray[index - 1];
287 }
288}
289
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000290SkFlattenable* SkReadBuffer::readFlattenable(SkFlattenable::Type ft) {
reed@google.com35348222013-10-16 13:05:06 +0000291 //
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000292 // TODO: confirm that ft matches the factory we decide to use
reed@google.com35348222013-10-16 13:05:06 +0000293 //
294
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000295 SkFlattenable::Factory factory = NULL;
296
297 if (fFactoryCount > 0) {
298 int32_t index = fReader.readU32();
299 if (0 == index) {
300 return NULL; // writer failed to give us the flattenable
301 }
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000302 index -= 1; // we stored the index-base-1
303 SkASSERT(index < fFactoryCount);
304 factory = fFactoryArray[index];
305 } else if (fFactoryTDArray) {
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000306 int32_t index = fReader.readU32();
307 if (0 == index) {
308 return NULL; // writer failed to give us the flattenable
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000309 }
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000310 index -= 1; // we stored the index-base-1
311 factory = (*fFactoryTDArray)[index];
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000312 } else {
313 factory = (SkFlattenable::Factory)readFunctionPtr();
314 if (NULL == factory) {
315 return NULL; // writer failed to give us the flattenable
316 }
317 }
318
319 // if we get here, factory may still be null, but if that is the case, the
320 // failure was ours, not the writer.
321 SkFlattenable* obj = NULL;
322 uint32_t sizeRecorded = fReader.readU32();
323 if (factory) {
commit-bot@chromium.orgf1177812014-04-23 19:19:44 +0000324 size_t offset = fReader.offset();
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000325 obj = (*factory)(*this);
326 // check that we read the amount we expected
commit-bot@chromium.orgf1177812014-04-23 19:19:44 +0000327 size_t sizeRead = fReader.offset() - offset;
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000328 if (sizeRecorded != sizeRead) {
329 // we could try to fix up the offset...
330 sk_throw();
331 }
332 } else {
333 // we must skip the remaining data
334 fReader.skip(sizeRecorded);
335 }
336 return obj;
337}
commit-bot@chromium.org4b8f8022014-05-21 19:56:46 +0000338
339/**
340 * Needs to follow the same pattern as readFlattenable(), but explicitly skip whatever data
341 * has been written.
342 */
343void SkReadBuffer::skipFlattenable() {
344 if (fFactoryCount > 0) {
345 if (0 == fReader.readU32()) {
346 return;
347 }
348 } else if (fFactoryTDArray) {
349 if (0 == fReader.readU32()) {
350 return;
351 }
352 } else {
353 if (NULL == this->readFunctionPtr()) {
354 return;
355 }
356 }
357 uint32_t sizeRecorded = fReader.readU32();
358 fReader.skip(sizeRecorded);
359}