blob: 9d8c215a8c9d745975d899406503bb3016d90c28 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkFlattenable.h"
9#include "SkTypeface.h"
10
reed@google.comf2eb5ab2011-05-10 22:56:42 +000011#include "SkMatrix.h"
12#include "SkRegion.h"
13
14void SkReadMatrix(SkReader32* reader, SkMatrix* matrix) {
15 size_t size = matrix->unflatten(reader->peek());
16 SkASSERT(SkAlign4(size) == size);
17 (void)reader->skip(size);
18}
19
20void SkWriteMatrix(SkWriter32* writer, const SkMatrix& matrix) {
21 size_t size = matrix.flatten(NULL);
22 SkASSERT(SkAlign4(size) == size);
23 matrix.flatten(writer->reserve(size));
24}
25
26void SkReadRegion(SkReader32* reader, SkRegion* rgn) {
27 size_t size = rgn->unflatten(reader->peek());
28 SkASSERT(SkAlign4(size) == size);
29 (void)reader->skip(size);
30}
31
32void SkWriteRegion(SkWriter32* writer, const SkRegion& rgn) {
33 size_t size = rgn.flatten(NULL);
34 SkASSERT(SkAlign4(size) == size);
35 rgn.flatten(writer->reserve(size));
36}
37
38///////////////////////////////////////////////////////////////////////////////
39
reed@android.com8a1c16f2008-12-17 15:59:43 +000040void SkFlattenable::flatten(SkFlattenableWriteBuffer&)
41{
42 /* we don't write anything at the moment, but this allows our subclasses
43 to not know that, since we want them to always call INHERITED::flatten()
44 in their code.
45 */
46}
47
48///////////////////////////////////////////////////////////////////////////////
49///////////////////////////////////////////////////////////////////////////////
50
51SkFlattenableReadBuffer::SkFlattenableReadBuffer() {
52 fRCArray = NULL;
53 fRCCount = 0;
reed@google.com82065d62011-02-07 15:30:46 +000054
reed@android.com8a1c16f2008-12-17 15:59:43 +000055 fTFArray = NULL;
56 fTFCount = 0;
reed@google.com82065d62011-02-07 15:30:46 +000057
reed@google.com6bac9472011-06-21 19:24:00 +000058 fFactoryTDArray = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 fFactoryArray = NULL;
60 fFactoryCount = 0;
61}
62
63SkFlattenableReadBuffer::SkFlattenableReadBuffer(const void* data) :
64 INHERITED(data, 1024 * 1024) {
65 fRCArray = NULL;
66 fRCCount = 0;
reed@google.com82065d62011-02-07 15:30:46 +000067
reed@android.com8a1c16f2008-12-17 15:59:43 +000068 fTFArray = NULL;
69 fTFCount = 0;
reed@google.com82065d62011-02-07 15:30:46 +000070
reed@google.com6bac9472011-06-21 19:24:00 +000071 fFactoryTDArray = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000072 fFactoryArray = NULL;
73 fFactoryCount = 0;
74}
75
76SkFlattenableReadBuffer::SkFlattenableReadBuffer(const void* data, size_t size)
77 : INHERITED(data, size) {
78 fRCArray = NULL;
79 fRCCount = 0;
reed@google.com82065d62011-02-07 15:30:46 +000080
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 fTFArray = NULL;
82 fTFCount = 0;
reed@google.com82065d62011-02-07 15:30:46 +000083
reed@google.com6bac9472011-06-21 19:24:00 +000084 fFactoryTDArray = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000085 fFactoryArray = NULL;
86 fFactoryCount = 0;
87}
88
89SkTypeface* SkFlattenableReadBuffer::readTypeface() {
90 uint32_t index = this->readU32();
91 if (0 == index || index > (unsigned)fTFCount) {
92 if (index) {
93 SkDebugf("====== typeface index %d\n", index);
94 }
95 return NULL;
96 } else {
97 SkASSERT(fTFArray);
98 return fTFArray[index - 1];
99 }
100}
101
102SkRefCnt* SkFlattenableReadBuffer::readRefCnt() {
103 uint32_t index = this->readU32();
104 if (0 == index || index > (unsigned)fRCCount) {
105 return NULL;
106 } else {
107 SkASSERT(fRCArray);
108 return fRCArray[index - 1];
109 }
110}
111
112SkFlattenable* SkFlattenableReadBuffer::readFlattenable() {
113 SkFlattenable::Factory factory = NULL;
reed@google.com82065d62011-02-07 15:30:46 +0000114
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115 if (fFactoryCount > 0) {
reed@google.com6bac9472011-06-21 19:24:00 +0000116 int32_t index = this->readU32();
117 if (0 == index) {
118 return NULL; // writer failed to give us the flattenable
119 }
120 index = -index; // we stored the negative of the index
121 index -= 1; // we stored the index-base-1
reed@google.com13649ce2011-06-28 12:02:58 +0000122 SkASSERT(index < fFactoryCount);
reed@google.com6bac9472011-06-21 19:24:00 +0000123 factory = fFactoryArray[index];
124 } else if (fFactoryTDArray) {
125 const int32_t* peek = (const int32_t*)this->peek();
126 if (*peek <= 0) {
127 int32_t index = this->readU32();
128 if (0 == index) {
129 return NULL; // writer failed to give us the flattenable
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 }
reed@google.com6bac9472011-06-21 19:24:00 +0000131 index = -index; // we stored the negative of the index
132 index -= 1; // we stored the index-base-1
133 factory = (*fFactoryTDArray)[index];
134 } else {
135 const char* name = this->readString();
136 factory = SkFlattenable::NameToFactory(name);
137 if (factory) {
138 SkASSERT(fFactoryTDArray->find(factory) < 0);
139 *fFactoryTDArray->append() = factory;
140 } else {
141// SkDebugf("can't find factory for [%s]\n", name);
142 }
143 // if we didn't find a factory, that's our failure, not the writer's,
144 // so we fall through, so we can skip the sizeRecorded data.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 }
146 } else {
147 factory = (SkFlattenable::Factory)readFunctionPtr();
reed@google.com6bac9472011-06-21 19:24:00 +0000148 if (NULL == factory) {
149 return NULL; // writer failed to give us the flattenable
150 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151 }
152
reed@google.com6bac9472011-06-21 19:24:00 +0000153 // if we get here, factory may still be null, but if that is the case, the
154 // failure was ours, not the writer.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155 SkFlattenable* obj = NULL;
reed@google.com6bac9472011-06-21 19:24:00 +0000156 uint32_t sizeRecorded = this->readU32();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 if (factory) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158 uint32_t offset = this->offset();
159 obj = (*factory)(*this);
160 // check that we read the amount we expected
161 uint32_t sizeRead = this->offset() - offset;
162 if (sizeRecorded != sizeRead) {
163 // we could try to fix up the offset...
164 sk_throw();
165 }
reed@google.com6bac9472011-06-21 19:24:00 +0000166 } else {
167 // we must skip the remaining data
168 this->skip(sizeRecorded);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 }
170 return obj;
171}
172
173void* SkFlattenableReadBuffer::readFunctionPtr() {
174 void* proc;
175 this->read(&proc, sizeof(proc));
176 return proc;
177}
178
179///////////////////////////////////////////////////////////////////////////////
180
181SkFlattenableWriteBuffer::SkFlattenableWriteBuffer(size_t minSize) :
182 INHERITED(minSize) {
183 fFlags = (Flags)0;
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000184 fRCSet = NULL;
185 fTFSet = NULL;
186 fFactorySet = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187}
188
189SkFlattenableWriteBuffer::~SkFlattenableWriteBuffer() {
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000190 SkSafeUnref(fRCSet);
191 SkSafeUnref(fTFSet);
192 SkSafeUnref(fFactorySet);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193}
194
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000195SkRefCntSet* SkFlattenableWriteBuffer::setRefCntRecorder(SkRefCntSet* rec) {
196 SkRefCnt_SafeAssign(fRCSet, rec);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 return rec;
198}
199
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000200SkRefCntSet* SkFlattenableWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) {
201 SkRefCnt_SafeAssign(fTFSet, rec);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 return rec;
203}
204
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000205SkFactorySet* SkFlattenableWriteBuffer::setFactoryRecorder(SkFactorySet* rec) {
206 SkRefCnt_SafeAssign(fFactorySet, rec);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 return rec;
208}
209
210void SkFlattenableWriteBuffer::writeTypeface(SkTypeface* obj) {
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000211 if (NULL == obj || NULL == fTFSet) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 this->write32(0);
213 } else {
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000214 this->write32(fTFSet->add(obj));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215 }
216}
217
218void SkFlattenableWriteBuffer::writeRefCnt(SkRefCnt* obj) {
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000219 if (NULL == obj || NULL == fRCSet) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 this->write32(0);
221 } else {
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000222 this->write32(fRCSet->add(obj));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 }
224}
225
226void SkFlattenableWriteBuffer::writeFlattenable(SkFlattenable* flattenable) {
reed@google.com6bac9472011-06-21 19:24:00 +0000227 /*
228 * If we have a factoryset, then the first 32bits tell us...
229 * 0: failure to write the flattenable
230 * <0: we store the negative of the (1-based) index
231 * >0: the length of the name
232 * If we don't have a factoryset, then the first "ptr" is either the
233 * factory, or null for failure.
234 *
235 * The distinction is important, since 0-index is 32bits (always), but a
236 * 0-functionptr might be 32 or 64 bits.
237 */
238
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 SkFlattenable::Factory factory = NULL;
240 if (flattenable) {
241 factory = flattenable->getFactory();
242 }
reed@google.com6bac9472011-06-21 19:24:00 +0000243 if (NULL == factory) {
244 if (fFactorySet) {
245 this->write32(0);
246 } else {
247 this->writeFunctionPtr(NULL);
248 }
249 return;
250 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251
reed@google.com6bac9472011-06-21 19:24:00 +0000252 /*
253 * We can write 1 of 3 versions of the flattenable:
254 * 1. function-ptr : this is the fastest for the reader, but assumes that
255 * the writer and reader are in the same process.
256 * 2. index into fFactorySet : This is assumes the writer will later
257 * resolve the function-ptrs into strings for its reader. SkPicture
258 * does exactly this, by writing a table of names (matching the indices)
259 * up front in its serialized form.
260 * 3. names : Reuse fFactorySet to store indices, but only after we've
261 * written the name the first time. SkGPipe uses this technique, as it
262 * doesn't require the reader to be told to know the table of names
263 * up front.
264 */
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000265 if (fFactorySet) {
reed@google.com6bac9472011-06-21 19:24:00 +0000266 if (this->inlineFactoryNames()) {
267 int index = fFactorySet->find(factory);
268 if (index) {
269 // we write the negative of the index, to distinguish it from
270 // the length of a string
271 this->write32(-index);
272 } else {
273 const char* name = SkFlattenable::FactoryToName(factory);
274 if (NULL == name) {
275 this->write32(0);
276 return;
277 }
278 this->writeString(name);
279 index = fFactorySet->add(factory);
280 }
281 } else {
282 // we write the negative of the index, to distinguish it from
283 // the length of a string
reed@google.com13649ce2011-06-28 12:02:58 +0000284 this->write32(-(int)fFactorySet->add(factory));
reed@google.com6bac9472011-06-21 19:24:00 +0000285 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000286 } else {
287 this->writeFunctionPtr((void*)factory);
288 }
reed@google.com82065d62011-02-07 15:30:46 +0000289
reed@google.com6bac9472011-06-21 19:24:00 +0000290 // make room for the size of the flatttened object
291 (void)this->reserve(sizeof(uint32_t));
292 // record the current size, so we can subtract after the object writes.
293 uint32_t offset = this->size();
294 // now flatten the object
295 flattenable->flatten(*this);
296 uint32_t objSize = this->size() - offset;
297 // record the obj's size
298 *this->peek32(offset - sizeof(uint32_t)) = objSize;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299}
300
301void SkFlattenableWriteBuffer::writeFunctionPtr(void* proc) {
302 *(void**)this->reserve(sizeof(void*)) = proc;
303}
304
305///////////////////////////////////////////////////////////////////////////////
306
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000307SkRefCntSet::~SkRefCntSet() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000308 // call this now, while our decPtr() is sill in scope
309 this->reset();
310}
311
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000312void SkRefCntSet::incPtr(void* ptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 ((SkRefCnt*)ptr)->ref();
314}
315
mike@reedtribe.orge9e08cc2011-04-29 01:44:52 +0000316void SkRefCntSet::decPtr(void* ptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317 ((SkRefCnt*)ptr)->unref();
318}
319
320///////////////////////////////////////////////////////////////////////////////
321///////////////////////////////////////////////////////////////////////////////
322///////////////////////////////////////////////////////////////////////////////
323
324#define MAX_PAIR_COUNT 64
325
326struct Pair {
327 const char* fName;
328 SkFlattenable::Factory fFactory;
329};
330
331static int gCount;
332static Pair gPairs[MAX_PAIR_COUNT];
333
334void SkFlattenable::Register(const char name[], Factory factory) {
335 SkASSERT(name);
336 SkASSERT(factory);
reed@google.com82065d62011-02-07 15:30:46 +0000337
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 static bool gOnce;
339 if (!gOnce) {
340 gCount = 0;
341 gOnce = true;
342 }
reed@google.com82065d62011-02-07 15:30:46 +0000343
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 SkASSERT(gCount < MAX_PAIR_COUNT);
reed@google.com82065d62011-02-07 15:30:46 +0000345
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346 gPairs[gCount].fName = name;
347 gPairs[gCount].fFactory = factory;
348 gCount += 1;
349}
350
caryclark@google.comd26147a2011-12-15 14:16:43 +0000351#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
352static void report_no_entries(const char* functionName) {
353 if (!gCount) {
354 SkDebugf("%s has no registered name/factory pairs."
caryclark@google.com92454982011-12-16 16:54:07 +0000355 " Call SkGraphics::Init() at process initialization time.",
356 functionName);
caryclark@google.comd26147a2011-12-15 14:16:43 +0000357 }
358}
359#endif
360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361SkFlattenable::Factory SkFlattenable::NameToFactory(const char name[]) {
caryclark@google.comd26147a2011-12-15 14:16:43 +0000362#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
363 report_no_entries(__FUNCTION__);
364#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365 const Pair* pairs = gPairs;
366 for (int i = gCount - 1; i >= 0; --i) {
367 if (strcmp(pairs[i].fName, name) == 0) {
368 return pairs[i].fFactory;
369 }
370 }
371 return NULL;
372}
373
374const char* SkFlattenable::FactoryToName(Factory fact) {
caryclark@google.comd26147a2011-12-15 14:16:43 +0000375#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
376 report_no_entries(__FUNCTION__);
377#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 const Pair* pairs = gPairs;
379 for (int i = gCount - 1; i >= 0; --i) {
380 if (pairs[i].fFactory == fact) {
381 return pairs[i].fName;
382 }
383 }
384 return NULL;
385}