| |
| /* |
| * Copyright 2011 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #include "SkFlattenable.h" |
| #include "SkTypeface.h" |
| |
| #include "SkMatrix.h" |
| #include "SkRegion.h" |
| |
| void SkReadMatrix(SkReader32* reader, SkMatrix* matrix) { |
| size_t size = matrix->unflatten(reader->peek()); |
| SkASSERT(SkAlign4(size) == size); |
| (void)reader->skip(size); |
| } |
| |
| void SkWriteMatrix(SkWriter32* writer, const SkMatrix& matrix) { |
| size_t size = matrix.flatten(NULL); |
| SkASSERT(SkAlign4(size) == size); |
| matrix.flatten(writer->reserve(size)); |
| } |
| |
| void SkReadRegion(SkReader32* reader, SkRegion* rgn) { |
| size_t size = rgn->unflatten(reader->peek()); |
| SkASSERT(SkAlign4(size) == size); |
| (void)reader->skip(size); |
| } |
| |
| void SkWriteRegion(SkWriter32* writer, const SkRegion& rgn) { |
| size_t size = rgn.flatten(NULL); |
| SkASSERT(SkAlign4(size) == size); |
| rgn.flatten(writer->reserve(size)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| void SkFlattenable::flatten(SkFlattenableWriteBuffer&) |
| { |
| /* we don't write anything at the moment, but this allows our subclasses |
| to not know that, since we want them to always call INHERITED::flatten() |
| in their code. |
| */ |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| SkFlattenableReadBuffer::SkFlattenableReadBuffer() { |
| fRCArray = NULL; |
| fRCCount = 0; |
| |
| fTFArray = NULL; |
| fTFCount = 0; |
| |
| fFactoryTDArray = NULL; |
| fFactoryArray = NULL; |
| fFactoryCount = 0; |
| fPictureVersion = PICTURE_VERSION_JB; |
| } |
| |
| SkFlattenableReadBuffer::SkFlattenableReadBuffer(const void* data) : |
| INHERITED(data, 1024 * 1024) { |
| fRCArray = NULL; |
| fRCCount = 0; |
| |
| fTFArray = NULL; |
| fTFCount = 0; |
| |
| fFactoryTDArray = NULL; |
| fFactoryArray = NULL; |
| fFactoryCount = 0; |
| fPictureVersion = PICTURE_VERSION_JB; |
| } |
| |
| SkFlattenableReadBuffer::SkFlattenableReadBuffer(const void* data, size_t size) |
| : INHERITED(data, size) { |
| fRCArray = NULL; |
| fRCCount = 0; |
| |
| fTFArray = NULL; |
| fTFCount = 0; |
| |
| fFactoryTDArray = NULL; |
| fFactoryArray = NULL; |
| fFactoryCount = 0; |
| fPictureVersion = PICTURE_VERSION_JB; |
| } |
| |
| SkTypeface* SkFlattenableReadBuffer::readTypeface() { |
| uint32_t index = this->readU32(); |
| if (0 == index || index > (unsigned)fTFCount) { |
| if (index) { |
| SkDebugf("====== typeface index %d\n", index); |
| } |
| return NULL; |
| } else { |
| SkASSERT(fTFArray); |
| return fTFArray[index - 1]; |
| } |
| } |
| |
| SkRefCnt* SkFlattenableReadBuffer::readRefCnt() { |
| uint32_t index = this->readU32(); |
| if (0 == index || index > (unsigned)fRCCount) { |
| return NULL; |
| } else { |
| SkASSERT(fRCArray); |
| return fRCArray[index - 1]; |
| } |
| } |
| |
| SkFlattenable* SkFlattenableReadBuffer::readFlattenable() { |
| |
| if(fPictureVersion == PICTURE_VERSION_ICS) { |
| SkFlattenable::Factory factory = NULL; |
| |
| if (fFactoryCount > 0) { |
| uint32_t index = this->readU32(); |
| if (index > 0) { |
| index -= 1; |
| SkASSERT(index < (unsigned)fFactoryCount); |
| factory = fFactoryArray[index]; |
| // if we recorded an index, but failed to get a factory, we need |
| // to skip the flattened data in the buffer |
| if (NULL == factory) { |
| uint32_t size = this->readU32(); |
| this->skip(size); |
| // fall through and return NULL for the object |
| } |
| } |
| } else { |
| factory = (SkFlattenable::Factory)readFunctionPtr(); |
| } |
| |
| SkFlattenable* obj = NULL; |
| if (factory) { |
| uint32_t sizeRecorded = this->readU32(); |
| uint32_t offset = this->offset(); |
| obj = (*factory)(*this); |
| // check that we read the amount we expected |
| uint32_t sizeRead = this->offset() - offset; |
| if (sizeRecorded != sizeRead) { |
| // we could try to fix up the offset... |
| sk_throw(); |
| } |
| } |
| return obj; |
| } |
| |
| SkFlattenable::Factory factory = NULL; |
| |
| if (fFactoryCount > 0) { |
| int32_t index = this->readU32(); |
| if (0 == index) { |
| return NULL; // writer failed to give us the flattenable |
| } |
| index = -index; // we stored the negative of the index |
| index -= 1; // we stored the index-base-1 |
| SkASSERT(index < fFactoryCount); |
| factory = fFactoryArray[index]; |
| } else if (fFactoryTDArray) { |
| const int32_t* peek = (const int32_t*)this->peek(); |
| if (*peek <= 0) { |
| int32_t index = this->readU32(); |
| if (0 == index) { |
| return NULL; // writer failed to give us the flattenable |
| } |
| index = -index; // we stored the negative of the index |
| index -= 1; // we stored the index-base-1 |
| factory = (*fFactoryTDArray)[index]; |
| } else { |
| const char* name = this->readString(); |
| factory = SkFlattenable::NameToFactory(name); |
| if (factory) { |
| SkASSERT(fFactoryTDArray->find(factory) < 0); |
| *fFactoryTDArray->append() = factory; |
| } else { |
| // SkDebugf("can't find factory for [%s]\n", name); |
| } |
| // if we didn't find a factory, that's our failure, not the writer's, |
| // so we fall through, so we can skip the sizeRecorded data. |
| } |
| } else { |
| factory = (SkFlattenable::Factory)readFunctionPtr(); |
| if (NULL == factory) { |
| return NULL; // writer failed to give us the flattenable |
| } |
| } |
| |
| // if we get here, factory may still be null, but if that is the case, the |
| // failure was ours, not the writer. |
| SkFlattenable* obj = NULL; |
| uint32_t sizeRecorded = this->readU32(); |
| if (factory) { |
| uint32_t offset = this->offset(); |
| obj = (*factory)(*this); |
| // check that we read the amount we expected |
| uint32_t sizeRead = this->offset() - offset; |
| if (sizeRecorded != sizeRead) { |
| // we could try to fix up the offset... |
| sk_throw(); |
| } |
| } else { |
| // we must skip the remaining data |
| this->skip(sizeRecorded); |
| } |
| return obj; |
| } |
| |
| void* SkFlattenableReadBuffer::readFunctionPtr() { |
| void* proc; |
| this->read(&proc, sizeof(proc)); |
| return proc; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| SkFlattenableWriteBuffer::SkFlattenableWriteBuffer(size_t minSize) : |
| INHERITED(minSize) { |
| fFlags = (Flags)0; |
| fRCSet = NULL; |
| fTFSet = NULL; |
| fFactorySet = NULL; |
| } |
| |
| SkFlattenableWriteBuffer::~SkFlattenableWriteBuffer() { |
| SkSafeUnref(fRCSet); |
| SkSafeUnref(fTFSet); |
| SkSafeUnref(fFactorySet); |
| } |
| |
| SkRefCntSet* SkFlattenableWriteBuffer::setRefCntRecorder(SkRefCntSet* rec) { |
| SkRefCnt_SafeAssign(fRCSet, rec); |
| return rec; |
| } |
| |
| SkRefCntSet* SkFlattenableWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) { |
| SkRefCnt_SafeAssign(fTFSet, rec); |
| return rec; |
| } |
| |
| SkFactorySet* SkFlattenableWriteBuffer::setFactoryRecorder(SkFactorySet* rec) { |
| SkRefCnt_SafeAssign(fFactorySet, rec); |
| return rec; |
| } |
| |
| void SkFlattenableWriteBuffer::writeTypeface(SkTypeface* obj) { |
| if (NULL == obj || NULL == fTFSet) { |
| this->write32(0); |
| } else { |
| this->write32(fTFSet->add(obj)); |
| } |
| } |
| |
| void SkFlattenableWriteBuffer::writeRefCnt(SkRefCnt* obj) { |
| if (NULL == obj || NULL == fRCSet) { |
| this->write32(0); |
| } else { |
| this->write32(fRCSet->add(obj)); |
| } |
| } |
| |
| void SkFlattenableWriteBuffer::writeFlattenable(SkFlattenable* flattenable) { |
| /* |
| * If we have a factoryset, then the first 32bits tell us... |
| * 0: failure to write the flattenable |
| * <0: we store the negative of the (1-based) index |
| * >0: the length of the name |
| * If we don't have a factoryset, then the first "ptr" is either the |
| * factory, or null for failure. |
| * |
| * The distinction is important, since 0-index is 32bits (always), but a |
| * 0-functionptr might be 32 or 64 bits. |
| */ |
| |
| SkFlattenable::Factory factory = NULL; |
| if (flattenable) { |
| factory = flattenable->getFactory(); |
| } |
| if (NULL == factory) { |
| if (fFactorySet) { |
| this->write32(0); |
| } else { |
| this->writeFunctionPtr(NULL); |
| } |
| return; |
| } |
| |
| /* |
| * We can write 1 of 3 versions of the flattenable: |
| * 1. function-ptr : this is the fastest for the reader, but assumes that |
| * the writer and reader are in the same process. |
| * 2. index into fFactorySet : This is assumes the writer will later |
| * resolve the function-ptrs into strings for its reader. SkPicture |
| * does exactly this, by writing a table of names (matching the indices) |
| * up front in its serialized form. |
| * 3. names : Reuse fFactorySet to store indices, but only after we've |
| * written the name the first time. SkGPipe uses this technique, as it |
| * doesn't require the reader to be told to know the table of names |
| * up front. |
| */ |
| if (fFactorySet) { |
| if (this->inlineFactoryNames()) { |
| int index = fFactorySet->find(factory); |
| if (index) { |
| // we write the negative of the index, to distinguish it from |
| // the length of a string |
| this->write32(-index); |
| } else { |
| const char* name = SkFlattenable::FactoryToName(factory); |
| if (NULL == name) { |
| this->write32(0); |
| return; |
| } |
| this->writeString(name); |
| index = fFactorySet->add(factory); |
| } |
| } else { |
| // we write the negative of the index, to distinguish it from |
| // the length of a string |
| this->write32(-(int)fFactorySet->add(factory)); |
| } |
| } else { |
| this->writeFunctionPtr((void*)factory); |
| } |
| |
| // make room for the size of the flatttened object |
| (void)this->reserve(sizeof(uint32_t)); |
| // record the current size, so we can subtract after the object writes. |
| uint32_t offset = this->size(); |
| // now flatten the object |
| flattenable->flatten(*this); |
| uint32_t objSize = this->size() - offset; |
| // record the obj's size |
| *this->peek32(offset - sizeof(uint32_t)) = objSize; |
| } |
| |
| void SkFlattenableWriteBuffer::writeFunctionPtr(void* proc) { |
| *(void**)this->reserve(sizeof(void*)) = proc; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| SkRefCntSet::~SkRefCntSet() { |
| // call this now, while our decPtr() is sill in scope |
| this->reset(); |
| } |
| |
| void SkRefCntSet::incPtr(void* ptr) { |
| ((SkRefCnt*)ptr)->ref(); |
| } |
| |
| void SkRefCntSet::decPtr(void* ptr) { |
| ((SkRefCnt*)ptr)->unref(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #define MAX_PAIR_COUNT 64 |
| |
| struct Pair { |
| const char* fName; |
| SkFlattenable::Factory fFactory; |
| }; |
| |
| static int gCount; |
| static Pair gPairs[MAX_PAIR_COUNT]; |
| |
| void SkFlattenable::Register(const char name[], Factory factory) { |
| SkASSERT(name); |
| SkASSERT(factory); |
| |
| static bool gOnce; |
| if (!gOnce) { |
| gCount = 0; |
| gOnce = true; |
| } |
| |
| SkASSERT(gCount < MAX_PAIR_COUNT); |
| |
| gPairs[gCount].fName = name; |
| gPairs[gCount].fFactory = factory; |
| gCount += 1; |
| } |
| |
| #if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG) |
| static void report_no_entries(const char* functionName) { |
| if (!gCount) { |
| SkDebugf("%s has no registered name/factory pairs." |
| " Call SkGraphics::Init() at process initialization time.", |
| functionName); |
| } |
| } |
| #endif |
| |
| SkFlattenable::Factory SkFlattenable::NameToFactory(const char name[]) { |
| #if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG) |
| report_no_entries(__FUNCTION__); |
| #endif |
| const Pair* pairs = gPairs; |
| for (int i = gCount - 1; i >= 0; --i) { |
| if (strcmp(pairs[i].fName, name) == 0) { |
| return pairs[i].fFactory; |
| } |
| } |
| return NULL; |
| } |
| |
| const char* SkFlattenable::FactoryToName(Factory fact) { |
| #if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG) |
| report_no_entries(__FUNCTION__); |
| #endif |
| const Pair* pairs = gPairs; |
| for (int i = gCount - 1; i >= 0; --i) { |
| if (pairs[i].fFactory == fact) { |
| return pairs[i].fName; |
| } |
| } |
| return NULL; |
| } |
| |
| bool SkFlattenable::toDumpString(SkString* str) const { |
| return false; |
| } |