blob: 6a590ed6942aeff37f46eb1b9eeea68afe1c35bb [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();
djsollen@google.com21830d92012-08-07 19:49:41 +000028 fMemoryPtr = NULL;
djsollen@google.com2b2ede32012-04-12 13:24:04 +000029
djsollen@google.com21830d92012-08-07 19:49:41 +000030 fBitmapStorage = NULL;
31 fTFArray = NULL;
32 fTFCount = 0;
33
34 fFactoryTDArray = NULL;
35 fFactoryArray = NULL;
36 fFactoryCount = 0;
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000037 fBitmapDecoder = NULL;
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +000038#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
39 fDecodedBitmapIndex = -1;
40#endif // DEBUG_NON_DETERMINISTIC_ASSERT
djsollen@google.com21830d92012-08-07 19:49:41 +000041}
42
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000043SkReadBuffer::SkReadBuffer(const void* data, size_t size) {
44 fFlags = default_flags();
djsollen@google.com2b2ede32012-04-12 13:24:04 +000045 fReader.setMemory(data, size);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000046 fMemoryPtr = NULL;
47
djsollen@google.com21830d92012-08-07 19:49:41 +000048 fBitmapStorage = NULL;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000049 fTFArray = NULL;
50 fTFCount = 0;
51
52 fFactoryTDArray = NULL;
53 fFactoryArray = NULL;
54 fFactoryCount = 0;
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000055 fBitmapDecoder = NULL;
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +000056#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
57 fDecodedBitmapIndex = -1;
58#endif // DEBUG_NON_DETERMINISTIC_ASSERT
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000059}
60
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000061SkReadBuffer::SkReadBuffer(SkStream* stream) {
62 fFlags = default_flags();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000063 const size_t length = stream->getLength();
64 fMemoryPtr = sk_malloc_throw(length);
65 stream->read(fMemoryPtr, length);
66 fReader.setMemory(fMemoryPtr, length);
djsollen@google.com21830d92012-08-07 19:49:41 +000067
68 fBitmapStorage = NULL;
69 fTFArray = NULL;
70 fTFCount = 0;
71
72 fFactoryTDArray = NULL;
73 fFactoryArray = NULL;
74 fFactoryCount = 0;
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000075 fBitmapDecoder = NULL;
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +000076#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
77 fDecodedBitmapIndex = -1;
78#endif // DEBUG_NON_DETERMINISTIC_ASSERT
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000079}
80
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000081SkReadBuffer::~SkReadBuffer() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000082 sk_free(fMemoryPtr);
djsollen@google.com21830d92012-08-07 19:49:41 +000083 SkSafeUnref(fBitmapStorage);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000084}
85
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000086bool SkReadBuffer::readBool() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000087 return fReader.readBool();
88}
89
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000090SkColor SkReadBuffer::readColor() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000091 return fReader.readInt();
92}
93
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000094SkFixed SkReadBuffer::readFixed() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000095 return fReader.readS32();
96}
97
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000098int32_t SkReadBuffer::readInt() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000099 return fReader.readInt();
100}
101
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000102SkScalar SkReadBuffer::readScalar() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000103 return fReader.readScalar();
104}
105
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000106uint32_t SkReadBuffer::readUInt() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000107 return fReader.readU32();
108}
109
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000110int32_t SkReadBuffer::read32() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000111 return fReader.readInt();
112}
113
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000114void SkReadBuffer::readString(SkString* string) {
djsollen@google.com77687512013-05-21 16:17:14 +0000115 size_t len;
116 const char* strContents = fReader.readString(&len);
117 string->set(strContents, len);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000118}
119
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000120void* SkReadBuffer::readEncodedString(size_t* length, SkPaint::TextEncoding encoding) {
humper@google.com0e515772013-01-07 19:54:40 +0000121 SkDEBUGCODE(int32_t encodingType = ) fReader.readInt();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000122 SkASSERT(encodingType == encoding);
123 *length = fReader.readInt();
124 void* data = sk_malloc_throw(*length);
125 memcpy(data, fReader.skip(SkAlign4(*length)), *length);
126 return data;
127}
128
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000129void SkReadBuffer::readPoint(SkPoint* point) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000130 point->fX = fReader.readScalar();
131 point->fY = fReader.readScalar();
132}
133
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000134void SkReadBuffer::readMatrix(SkMatrix* matrix) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000135 fReader.readMatrix(matrix);
136}
137
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000138void SkReadBuffer::readIRect(SkIRect* rect) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000139 memcpy(rect, fReader.skip(sizeof(SkIRect)), sizeof(SkIRect));
140}
141
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000142void SkReadBuffer::readRect(SkRect* rect) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000143 memcpy(rect, fReader.skip(sizeof(SkRect)), sizeof(SkRect));
144}
145
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000146void SkReadBuffer::readRegion(SkRegion* region) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000147 fReader.readRegion(region);
148}
149
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000150void SkReadBuffer::readPath(SkPath* path) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000151 fReader.readPath(path);
152}
153
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000154bool SkReadBuffer::readArray(void* value, size_t size, size_t elementSize) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000155 const size_t count = this->getArrayCount();
156 if (count == size) {
157 (void)fReader.skip(sizeof(uint32_t)); // Skip array count
158 const size_t byteLength = count * elementSize;
159 memcpy(value, fReader.skip(SkAlign4(byteLength)), byteLength);
160 return true;
161 }
162 SkASSERT(false);
163 fReader.skip(fReader.available());
164 return false;
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000165}
166
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000167bool SkReadBuffer::readByteArray(void* value, size_t size) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000168 return readArray(static_cast<unsigned char*>(value), size, sizeof(unsigned char));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000169}
170
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000171bool SkReadBuffer::readColorArray(SkColor* colors, size_t size) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000172 return readArray(colors, size, sizeof(SkColor));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000173}
174
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000175bool SkReadBuffer::readIntArray(int32_t* values, size_t size) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000176 return readArray(values, size, sizeof(int32_t));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000177}
178
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000179bool SkReadBuffer::readPointArray(SkPoint* points, size_t size) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000180 return readArray(points, size, sizeof(SkPoint));
181}
182
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000183bool SkReadBuffer::readScalarArray(SkScalar* values, size_t size) {
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000184 return readArray(values, size, sizeof(SkScalar));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000185}
186
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000187uint32_t SkReadBuffer::getArrayCount() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000188 return *(uint32_t*)fReader.peek();
189}
190
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000191void SkReadBuffer::readBitmap(SkBitmap* bitmap) {
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000192 const int width = this->readInt();
193 const int height = this->readInt();
194 // The writer stored a boolean value to determine whether an SkBitmapHeap was used during
195 // writing.
196 if (this->readBool()) {
197 // An SkBitmapHeap was used for writing. Read the index from the stream and find the
198 // corresponding SkBitmap in fBitmapStorage.
199 const uint32_t index = fReader.readU32();
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000200 fReader.readU32(); // bitmap generation ID (see SkWriteBuffer::writeBitmap)
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000201 if (fBitmapStorage) {
202 *bitmap = *fBitmapStorage->getBitmap(index);
203 fBitmapStorage->releaseRef(index);
204 return;
scroggo@google.com0cb7df92013-04-30 02:37:56 +0000205 } else {
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000206 // The bitmap was stored in a heap, but there is no way to access it. Set an error and
207 // fall through to use a place holder bitmap.
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000208 SkErrorInternals::SetError(kParseError_SkError, "SkWriteBuffer::writeBitmap "
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000209 "stored the SkBitmap in an SkBitmapHeap, but "
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000210 "SkReadBuffer has no SkBitmapHeapReader to "
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000211 "retrieve the SkBitmap.");
scroggo@google.com0cb7df92013-04-30 02:37:56 +0000212 }
213 } else {
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000214 // The writer stored false, meaning the SkBitmap was not stored in an SkBitmapHeap.
215 const size_t length = this->readUInt();
216 if (length > 0) {
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +0000217#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
218 fDecodedBitmapIndex++;
219#endif // DEBUG_NON_DETERMINISTIC_ASSERT
scroggo@google.com2d76d932013-05-31 14:39:54 +0000220 // A non-zero size means the SkBitmap was encoded. Read the data and pixel
221 // offset.
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000222 const void* data = this->skip(length);
scroggo@google.com2d76d932013-05-31 14:39:54 +0000223 const int32_t xOffset = fReader.readS32();
224 const int32_t yOffset = fReader.readS32();
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000225 if (fBitmapDecoder != NULL && fBitmapDecoder(data, length, bitmap)) {
scroggo@google.com719a3732013-05-16 19:35:39 +0000226 if (bitmap->width() == width && bitmap->height() == height) {
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +0000227#ifdef DEBUG_NON_DETERMINISTIC_ASSERT
228 if (0 != xOffset || 0 != yOffset) {
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000229 SkDebugf("SkReadBuffer::readBitmap: heights match,"
scroggo@google.comc6e5fcb2013-07-08 22:00:17 +0000230 " but offset is not zero. \nInfo about the bitmap:"
231 "\n\tIndex: %d\n\tDimensions: [%d %d]\n\tEncoded"
232 " data size: %d\n\tOffset: (%d, %d)\n",
233 fDecodedBitmapIndex, width, height, length, xOffset,
234 yOffset);
235 }
236#endif // DEBUG_NON_DETERMINISTIC_ASSERT
scroggo@google.com2d76d932013-05-31 14:39:54 +0000237 // If the width and height match, there should be no offset.
238 SkASSERT(0 == xOffset && 0 == yOffset);
scroggo@google.com719a3732013-05-16 19:35:39 +0000239 return;
240 }
241
242 // This case can only be reached if extractSubset was called, so
scroggo@google.com02076832013-12-16 20:02:03 +0000243 // the recorded width and height must be smaller than or equal to
scroggo@google.com719a3732013-05-16 19:35:39 +0000244 // the encoded width and height.
scroggo@google.com02076832013-12-16 20:02:03 +0000245 // FIXME (scroggo): This assert assumes that our decoder and the
246 // sources encoder agree on the width and height which may not
247 // always be the case. Removing until it can be investigated
248 // further.
249 //SkASSERT(width <= bitmap->width() && height <= bitmap->height());
scroggo@google.com719a3732013-05-16 19:35:39 +0000250
scroggo@google.com719a3732013-05-16 19:35:39 +0000251 SkBitmap subsetBm;
scroggo@google.com2d76d932013-05-31 14:39:54 +0000252 SkIRect subset = SkIRect::MakeXYWH(xOffset, yOffset, width, height);
scroggo@google.com719a3732013-05-16 19:35:39 +0000253 if (bitmap->extractSubset(&subsetBm, subset)) {
254 bitmap->swap(subsetBm);
255 return;
256 }
scroggo@google.com0cb7df92013-04-30 02:37:56 +0000257 }
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000258 // This bitmap was encoded when written, but we are unable to decode, possibly due to
259 // not having a decoder.
260 SkErrorInternals::SetError(kParseError_SkError,
261 "Could not decode bitmap. Resulting bitmap will be red.");
scroggo@google.com0cb7df92013-04-30 02:37:56 +0000262 } else {
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000263 // A size of zero means the SkBitmap was simply flattened.
264 bitmap->unflatten(*this);
265 return;
scroggo@google.com5a7c6be2012-10-04 21:46:08 +0000266 }
djsollen@google.com21830d92012-08-07 19:49:41 +0000267 }
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000268 // Could not read the SkBitmap. Use a placeholder bitmap.
reed@google.com9ebcac52014-01-24 18:53:42 +0000269 bitmap->allocPixels(SkImageInfo::MakeN32Premul(width, height));
scroggo@google.com2983ddd2013-05-07 14:45:40 +0000270 bitmap->eraseColor(SK_ColorRED);
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000271}
272
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000273SkTypeface* SkReadBuffer::readTypeface() {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000274
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000275 uint32_t index = fReader.readU32();
276 if (0 == index || index > (unsigned)fTFCount) {
277 if (index) {
278 SkDebugf("====== typeface index %d\n", index);
279 }
280 return NULL;
281 } else {
282 SkASSERT(fTFArray);
283 return fTFArray[index - 1];
284 }
285}
286
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000287SkFlattenable* SkReadBuffer::readFlattenable(SkFlattenable::Type ft) {
reed@google.com35348222013-10-16 13:05:06 +0000288 //
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000289 // TODO: confirm that ft matches the factory we decide to use
reed@google.com35348222013-10-16 13:05:06 +0000290 //
291
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000292 SkFlattenable::Factory factory = NULL;
293
294 if (fFactoryCount > 0) {
295 int32_t index = fReader.readU32();
296 if (0 == index) {
297 return NULL; // writer failed to give us the flattenable
298 }
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000299 index -= 1; // we stored the index-base-1
300 SkASSERT(index < fFactoryCount);
301 factory = fFactoryArray[index];
302 } else if (fFactoryTDArray) {
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000303 int32_t index = fReader.readU32();
304 if (0 == index) {
305 return NULL; // writer failed to give us the flattenable
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000306 }
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000307 index -= 1; // we stored the index-base-1
308 factory = (*fFactoryTDArray)[index];
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000309 } else {
310 factory = (SkFlattenable::Factory)readFunctionPtr();
311 if (NULL == factory) {
312 return NULL; // writer failed to give us the flattenable
313 }
314 }
315
316 // if we get here, factory may still be null, but if that is the case, the
317 // failure was ours, not the writer.
318 SkFlattenable* obj = NULL;
319 uint32_t sizeRecorded = fReader.readU32();
320 if (factory) {
321 uint32_t offset = fReader.offset();
322 obj = (*factory)(*this);
323 // check that we read the amount we expected
324 uint32_t sizeRead = fReader.offset() - offset;
325 if (sizeRecorded != sizeRead) {
326 // we could try to fix up the offset...
327 sk_throw();
328 }
329 } else {
330 // we must skip the remaining data
331 fReader.skip(sizeRecorded);
332 }
333 return obj;
334}