blob: e43a111ddc7bc7a0ec2be490b4f3b6cc0e390b6f [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
9#include "SkOrderedWriteBuffer.h"
junov@chromium.orgce65f382012-10-17 19:36:09 +000010#include "SkBitmap.h"
mike@reedtribe.org227b5162012-08-12 19:25:08 +000011#include "SkPtrRecorder.h"
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000012#include "SkStream.h"
djsollen@google.com2b2ede32012-04-12 13:24:04 +000013#include "SkTypeface.h"
14
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000015SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize)
16 : INHERITED()
17 , fFactorySet(NULL)
18 , fNamedFactorySet(NULL)
19 , fWriter(minSize)
djsollen@google.com21830d92012-08-07 19:49:41 +000020 , fBitmapHeap(NULL)
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000021 , fTFSet(NULL)
22 , fBitmapEncoder(NULL) {
djsollen@google.com2b2ede32012-04-12 13:24:04 +000023}
24
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000025SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize, void* storage, size_t storageSize)
26 : INHERITED()
27 , fFactorySet(NULL)
28 , fNamedFactorySet(NULL)
29 , fWriter(minSize, storage, storageSize)
djsollen@google.com21830d92012-08-07 19:49:41 +000030 , fBitmapHeap(NULL)
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000031 , fTFSet(NULL)
32 , fBitmapEncoder(NULL) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000033}
34
35SkOrderedWriteBuffer::~SkOrderedWriteBuffer() {
36 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
42void SkOrderedWriteBuffer::writeByteArray(const void* data, size_t size) {
43 fWriter.write32(size);
44 fWriter.writePad(data, size);
45}
46
47void SkOrderedWriteBuffer::writeBool(bool value) {
48 fWriter.writeBool(value);
49}
50
51void SkOrderedWriteBuffer::writeFixed(SkFixed value) {
52 fWriter.write32(value);
53}
54
55void SkOrderedWriteBuffer::writeScalar(SkScalar value) {
56 fWriter.writeScalar(value);
57}
58
59void SkOrderedWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) {
60 fWriter.write32(count);
61 fWriter.write(value, count * sizeof(SkScalar));
62}
63
64void SkOrderedWriteBuffer::writeInt(int32_t value) {
65 fWriter.write32(value);
66}
67
68void SkOrderedWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) {
69 fWriter.write32(count);
70 fWriter.write(value, count * sizeof(int32_t));
71}
72
73void SkOrderedWriteBuffer::writeUInt(uint32_t value) {
74 fWriter.write32(value);
75}
76
77void SkOrderedWriteBuffer::write32(int32_t value) {
78 fWriter.write32(value);
79}
80
81void SkOrderedWriteBuffer::writeString(const char* value) {
82 fWriter.writeString(value);
83}
84
85void SkOrderedWriteBuffer::writeEncodedString(const void* value, size_t byteLength,
86 SkPaint::TextEncoding encoding) {
87 fWriter.writeInt(encoding);
88 fWriter.writeInt(byteLength);
89 fWriter.write(value, byteLength);
90}
91
92
93void SkOrderedWriteBuffer::writeColor(const SkColor& color) {
94 fWriter.write32(color);
95}
96
97void SkOrderedWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) {
98 fWriter.write32(count);
99 fWriter.write(color, count * sizeof(SkColor));
100}
101
102void SkOrderedWriteBuffer::writePoint(const SkPoint& point) {
103 fWriter.writeScalar(point.fX);
104 fWriter.writeScalar(point.fY);
105}
106
107void SkOrderedWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) {
108 fWriter.write32(count);
109 fWriter.write(point, count * sizeof(SkPoint));
110}
111
112void SkOrderedWriteBuffer::writeMatrix(const SkMatrix& matrix) {
113 fWriter.writeMatrix(matrix);
114}
115
116void SkOrderedWriteBuffer::writeIRect(const SkIRect& rect) {
117 fWriter.write(&rect, sizeof(SkIRect));
118}
119
120void SkOrderedWriteBuffer::writeRect(const SkRect& rect) {
121 fWriter.writeRect(rect);
122}
123
124void SkOrderedWriteBuffer::writeRegion(const SkRegion& region) {
125 fWriter.writeRegion(region);
126}
127
128void SkOrderedWriteBuffer::writePath(const SkPath& path) {
129 fWriter.writePath(path);
130}
131
132size_t SkOrderedWriteBuffer::writeStream(SkStream* stream, size_t length) {
133 return fWriter.readFromStream(stream, length);
134}
135
136bool SkOrderedWriteBuffer::writeToStream(SkWStream* stream) {
137 return fWriter.writeToStream(stream);
138}
139
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000140void SkOrderedWriteBuffer::writeBitmap(const SkBitmap& bitmap) {
scroggo@google.com5a7c6be2012-10-04 21:46:08 +0000141 bool encoded = false;
142 if (fBitmapEncoder != NULL) {
143 SkDynamicMemoryWStream pngStream;
144 if (fBitmapEncoder(&pngStream, bitmap)) {
145 encoded = true;
146 if (encoded) {
147 uint32_t offset = fWriter.bytesWritten();
148 // Write the length to indicate that the bitmap was encoded successfully.
149 size_t length = pngStream.getOffset();
150 this->writeUInt(length);
151 // Now write the stream.
152 if (pngStream.read(fWriter.reservePad(length), 0, length)) {
153 // Write the width and height in case the reader does not have a decoder.
154 this->writeInt(bitmap.width());
155 this->writeInt(bitmap.height());
156 } else {
157 // Writing the stream failed, so go back to original state to store another way.
158 fWriter.rewindToOffset(offset);
159 encoded = false;
160 }
161 }
162 }
163 }
164 if (!encoded) {
165 // Bitmap was not encoded. Record a zero, implying that the reader need not decode.
166 this->writeUInt(0);
167 if (fBitmapHeap) {
junov@chromium.orgce65f382012-10-17 19:36:09 +0000168 int32_t slot = fBitmapHeap->insert(bitmap);
169 fWriter.write32(slot);
170 // crbug.com/155875
171 // The generation ID is not required information. We write it to prevent collisions
172 // in SkFlatDictionary. It is possible to get a collision when a previously
173 // unflattened (i.e. stale) instance of a similar flattenable is in the dictionary
174 // and the instance currently being written is re-using the same slot from the
175 // bitmap heap.
176 fWriter.write32(bitmap.getGenerationID());
scroggo@google.com5a7c6be2012-10-04 21:46:08 +0000177 } else {
178 bitmap.flatten(*this);
179 }
djsollen@google.com21830d92012-08-07 19:49:41 +0000180 }
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000181}
182
183void SkOrderedWriteBuffer::writeTypeface(SkTypeface* obj) {
184 if (NULL == obj || NULL == fTFSet) {
185 fWriter.write32(0);
186 } else {
187 fWriter.write32(fTFSet->add(obj));
188 }
189}
190
191SkFactorySet* SkOrderedWriteBuffer::setFactoryRecorder(SkFactorySet* rec) {
192 SkRefCnt_SafeAssign(fFactorySet, rec);
193 if (fNamedFactorySet != NULL) {
194 fNamedFactorySet->unref();
195 fNamedFactorySet = NULL;
196 }
197 return rec;
198}
199
200SkNamedFactorySet* SkOrderedWriteBuffer::setNamedFactoryRecorder(SkNamedFactorySet* rec) {
201 SkRefCnt_SafeAssign(fNamedFactorySet, rec);
202 if (fFactorySet != NULL) {
203 fFactorySet->unref();
204 fFactorySet = NULL;
205 }
206 return rec;
207}
208
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000209SkRefCntSet* SkOrderedWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) {
210 SkRefCnt_SafeAssign(fTFSet, rec);
211 return rec;
reed@google.come49aca92012-04-24 21:12:39 +0000212}
213
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000214void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) {
215 /*
216 * If we have a factoryset, then the first 32bits tell us...
217 * 0: failure to write the flattenable
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000218 * >0: (1-based) index into the SkFactorySet or SkNamedFactorySet
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000219 * If we don't have a factoryset, then the first "ptr" is either the
220 * factory, or null for failure.
221 *
222 * The distinction is important, since 0-index is 32bits (always), but a
223 * 0-functionptr might be 32 or 64 bits.
224 */
225
226 SkFlattenable::Factory factory = NULL;
227 if (flattenable) {
228 factory = flattenable->getFactory();
229 }
230 if (NULL == factory) {
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000231 if (fFactorySet != NULL || fNamedFactorySet != NULL) {
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000232 this->write32(0);
233 } else {
234 this->writeFunctionPtr(NULL);
235 }
236 return;
237 }
238
239 /*
240 * We can write 1 of 3 versions of the flattenable:
241 * 1. function-ptr : this is the fastest for the reader, but assumes that
242 * the writer and reader are in the same process.
243 * 2. index into fFactorySet : This is assumes the writer will later
244 * resolve the function-ptrs into strings for its reader. SkPicture
245 * does exactly this, by writing a table of names (matching the indices)
246 * up front in its serialized form.
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000247 * 3. index into fNamedFactorySet. fNamedFactorySet will also store the
248 * name. SkGPipe uses this technique so it can write the name to its
249 * stream before writing the flattenable.
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000250 */
251 if (fFactorySet) {
scroggo@google.com0c3e5fe2012-08-01 19:34:20 +0000252 this->write32(fFactorySet->add(factory));
253 } else if (fNamedFactorySet) {
254 int32_t index = fNamedFactorySet->find(factory);
255 this->write32(index);
256 if (0 == index) {
257 return;
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000258 }
259 } else {
260 this->writeFunctionPtr((void*)factory);
261 }
262
scroggo@google.comd8a6cc82012-09-12 18:53:49 +0000263 // make room for the size of the flattened object
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000264 (void)fWriter.reserve(sizeof(uint32_t));
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000265 // record the current size, so we can subtract after the object writes.
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000266 uint32_t offset = fWriter.size();
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000267 // now flatten the object
268 flattenObject(flattenable, *this);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000269 uint32_t objSize = fWriter.size() - offset;
djsollen@google.com2b2ede32012-04-12 13:24:04 +0000270 // record the obj's size
271 *fWriter.peek32(offset - sizeof(uint32_t)) = objSize;
272}