/*
* 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;
}