fTFArray = array;
fTFCount = count;
}
-
+
+ /**
+ * Call this with a pre-loaded array of Factories, in the same order as
+ * were created/written by the writer. SkPicture uses this.
+ */
void setFactoryPlayback(SkFlattenable::Factory array[], int count) {
+ fFactoryTDArray = NULL;
fFactoryArray = array;
fFactoryCount = count;
}
+
+ /**
+ * Call this with an initially empty array, so the reader can cache each
+ * factory it sees by name. Used by the pipe code in conjunction with
+ * the writer's kInlineFactoryNames_Flag.
+ */
+ void setFactoryArray(SkTDArray<SkFlattenable::Factory>* array) {
+ fFactoryTDArray = array;
+ fFactoryArray = NULL;
+ fFactoryCount = 0;
+ }
SkTypeface* readTypeface();
SkRefCnt* readRefCnt();
SkTypeface** fTFArray;
int fTFCount;
+ SkTDArray<SkFlattenable::Factory>* fFactoryTDArray;
SkFlattenable::Factory* fFactoryArray;
int fFactoryCount;
SkFactorySet* setFactoryRecorder(SkFactorySet*);
enum Flags {
- kCrossProcess_Flag = 0x01
+ kCrossProcess_Flag = 0x01,
+ /**
+ * Instructs the writer to inline Factory names as there are seen the
+ * first time (after that we store an index). The pipe code uses this.
+ */
+ kInlineFactoryNames_Flag = 0x02,
};
- Flags getFlags() const { return fFlags; }
+ Flags getFlags() const { return (Flags)fFlags; }
void setFlags(Flags flags) { fFlags = flags; }
- bool isCrossProcess() const { return (fFlags & kCrossProcess_Flag) != 0; }
+ bool isCrossProcess() const {
+ return SkToBool(fFlags & kCrossProcess_Flag);
+ }
+ bool inlineFactoryNames() const {
+ return SkToBool(fFlags & kInlineFactoryNames_Flag);
+ }
bool persistBitmapPixels() const {
return (fFlags & kCrossProcess_Flag) != 0;
bool persistTypeface() const { return (fFlags & kCrossProcess_Flag) != 0; }
private:
- Flags fFlags;
- SkRefCntSet* fTFSet;
- SkRefCntSet* fRCSet;
- SkFactorySet* fFactorySet;
+ uint32_t fFlags;
+ SkRefCntSet* fTFSet;
+ SkRefCntSet* fRCSet;
+ SkFactorySet* fFactorySet;
typedef SkWriter32 INHERITED;
};
friend class SkTextToPathIter;
};
-//////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
#include "SkPathEffect.h"
SkPaint::Cap, SkScalar miterLimit = -1);
// overrides
- // This method is not exported to java.
virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
// overrides for SkFlattenable
- // This method is not exported to java.
virtual void flatten(SkFlattenableWriteBuffer&);
- // This method is not exported to java.
virtual Factory getFactory();
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
private:
SkScalar fWidth, fMiter;
uint8_t fStyle, fJoin, fCap;
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
SkStrokePathEffect(SkFlattenableReadBuffer&);
typedef SkPathEffect INHERITED;
*/
class SK_API SkPathEffect : public SkFlattenable {
public:
- // This method is not exported to java.
SkPathEffect() {}
/** Given a src path and a width value, return true if the patheffect
// overrides
- // This method is not exported to java.
virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkComposePathEffect, (buffer));
+ }
+
protected:
virtual Factory getFactory() { return CreateProc; }
private:
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
- return SkNEW_ARGS(SkComposePathEffect, (buffer));
- }
SkComposePathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
// illegal
: INHERITED(first, second) {}
// overrides
- // This method is not exported to java.
virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkSumPathEffect, (buffer));
+ }
+
protected:
virtual Factory getFactory() { return CreateProc; }
private:
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
- return SkNEW_ARGS(SkSumPathEffect, (buffer));
- }
SkSumPathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
// illegal
*/
template <typename T> class SkTPtrSet : public SkPtrSet {
public:
+ uint32_t find(T ptr) {
+ return this->INHERITED::find((void*)ptr);
+ }
uint32_t add(T ptr) {
return this->INHERITED::add((void*)ptr);
}
-
+
void copyToArray(T* array) const {
this->INHERITED::copyToArray((void**)array);
}
// This method is not exported to java.
virtual void flatten(SkFlattenableWriteBuffer&);
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
protected:
SkCornerPathEffect(SkFlattenableReadBuffer&);
private:
SkScalar fRadius;
-
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
-
- // illegal
- SkCornerPathEffect(const SkCornerPathEffect&);
- SkCornerPathEffect& operator=(const SkCornerPathEffect&);
typedef SkPathEffect INHERITED;
};
// This method is not exported to java.
virtual void flatten(SkFlattenableWriteBuffer&);
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
protected:
SkDashPathEffect(SkFlattenableReadBuffer&);
SkScalar fIntervalLength;
bool fScaleToFit;
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
-
typedef SkPathEffect INHERITED;
};
// This method is not exported to java.
virtual void flatten(SkFlattenableWriteBuffer&);
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
protected:
SkDiscretePathEffect(SkFlattenableReadBuffer&);
private:
SkScalar fSegLength, fPerterb;
-
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
typedef SkPathEffect INHERITED;
};
fTFArray = NULL;
fTFCount = 0;
+ fFactoryTDArray = NULL;
fFactoryArray = NULL;
fFactoryCount = 0;
}
fTFArray = NULL;
fTFCount = 0;
+ fFactoryTDArray = NULL;
fFactoryArray = NULL;
fFactoryCount = 0;
}
fTFArray = NULL;
fTFCount = 0;
+ fFactoryTDArray = NULL;
fFactoryArray = NULL;
fFactoryCount = 0;
}
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
+ 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 < (unsigned)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 sizeRecorded = this->readU32();
uint32_t offset = this->offset();
obj = (*factory)(*this);
// check that we read the amount we expected
// we could try to fix up the offset...
sk_throw();
}
+ } else {
+ // we must skip the remaining data
+ this->skip(sizeRecorded);
}
return 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) {
- this->write32(fFactorySet->add(factory));
+ 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(-fFactorySet->add(factory));
+ }
} else {
this->writeFunctionPtr((void*)factory);
}
- if (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;
- }
+ // 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) {
}
SkPairPathEffect::~SkPairPathEffect() {
- fPE0->unref();
- fPE1->unref();
+ SkSafeUnref(fPE0);
+ SkSafeUnref(fPE1);
}
/*
SkPairPathEffect::SkPairPathEffect(SkFlattenableReadBuffer& buffer) {
fPE0 = (SkPathEffect*)buffer.readFlattenable();
fPE1 = (SkPathEffect*)buffer.readFlattenable();
+ // either of these may fail, so we have to check for nulls later on
}
///////////////////////////////////////////////////////////////////////////////
bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src,
SkScalar* width) {
+ // we may have failed to unflatten these, so we have to check
+ if (!fPE0 || !fPE1) {
+ return false;
+ }
+
SkPath tmp;
const SkPath* ptr = &src;
fCap = buffer.readU8();
}
+///////////////////////////////////////////////////////////////////////////////
+
+static SkFlattenable::Registrar gComposePathEffectReg("SkComposePathEffect",
+ SkComposePathEffect::CreateProc);
+
+static SkFlattenable::Registrar gSumPathEffectReg("SkSumPathEffect",
+ SkSumPathEffect::CreateProc);
+
+static SkFlattenable::Registrar gStrokePathEffectReg("SkStrokePathEffect",
+ SkStrokePathEffect::CreateProc);
+
*/
const char* SkReader32::readString(size_t* outLen) {
- // we need to read at least 1-4 bytes
- SkASSERT(this->isAvailable(4));
size_t len = this->readInt();
const void* ptr = this->peek();
}
}
-SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer) {
+SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer)
+: INHERITED(buffer) {
+
fDx = buffer.readScalar();
fDy = buffer.readScalar();
fBlurColor = buffer.readU32();
fRadius = buffer.readScalar();
}
+///////////////////////////////////////////////////////////////////////////////
+
+static SkFlattenable::Registrar gReg("SkCornerPathEffect",
+ SkCornerPathEffect::CreateProc);
+
buffer.read(fIntervals, fCount * sizeof(fIntervals[0]));
}
+///////////////////////////////////////////////////////////////////////////////
+
+static SkFlattenable::Registrar gReg("SkDashPathEffect",
+ SkDashPathEffect::CreateProc);
fPerterb = buffer.readScalar();
}
+///////////////////////////////////////////////////////////////////////////////
+
+static SkFlattenable::Registrar gReg("SkDiscretePathEffect",
+ SkDiscretePathEffect::CreateProc);
+
kDef_Typeface_DrawOp,
kDef_Flattenable_DrawOp,
- kName_Flattenable_DrawOp, // index <--> name
-
// these are signals to playback, not drawing verbs
kDone_DrawOp,
};
void setReader(SkFlattenableReadBuffer* reader) {
fReader = reader;
- fReader->setFactoryPlayback(fFactoryArray.begin(), fFactoryArray.count());
+ fReader->setFactoryArray(&fFactoryArray);
}
const SkPaint& paint() const { return fPaint; }
*fFlatArray.append() = obj;
}
- void nameFlattenable(PaintFlats pf, unsigned index) {
- SkASSERT(index == fFactoryArray.count() + 1);
- const char* name = fReader->readString();
- SkFlattenable::Factory fact = SkFlattenable::NameToFactory(name);
- *fFactoryArray.append() = fact;
-
- // update this each time we grow the array
- fReader->setFactoryPlayback(fFactoryArray.begin(), fFactoryArray.count());
- }
-
void addTypeface() {
size_t size = fReader->readU32();
const void* data = fReader->skip(SkAlign4(size));
state->defFlattenable(pf, index);
}
-static void name_PaintFlat_rp(SkCanvas*, SkReader32*, uint32_t op32,
- SkGPipeState* state) {
- PaintFlats pf = (PaintFlats)DrawOp_unpackFlags(op32);
- unsigned index = DrawOp_unpackData(op32);
- state->nameFlattenable(pf, index);
-}
-
///////////////////////////////////////////////////////////////////////////////
static void skip_rp(SkCanvas*, SkReader32* reader, uint32_t op32, SkGPipeState*) {
paintOp_rp,
def_Typeface_rp,
def_PaintFlat_rp,
- name_PaintFlat_rp,
done_rp
};
SkGPipeState::SkGPipeState() {}
SkGPipeState::~SkGPipeState() {
- fTypefaces.unrefAll();
- fFlatArray.unrefAll();
+ fTypefaces.safeUnrefAll();
+ fFlatArray.safeUnrefAll();
}
///////////////////////////////////////////////////////////////////////////////
if (readAtom &&
(table[op] != paintOp_rp &&
table[op] != def_Typeface_rp &&
- table[op] != def_PaintFlat_rp &&
- table[op] != name_PaintFlat_rp
+ table[op] != def_PaintFlat_rp
)) {
status = kReadAtom_Status;
break;
if (NULL == obj) {
return 0;
}
-
- SkFlattenable::Factory fact = obj->getFactory();
- if (NULL == fact) {
- return 0;
- }
- if (fFactorySet) {
- uint32_t id = fFactorySet->find((void*)fact);
- if (0 == id) {
- const char* name = SkFlattenable::FactoryToName(fact);
- if (NULL == name) {
- return 0;
- }
- size_t len = strlen(name);
- size_t size = SkWriter32::WriteStringSize(name, len);
- if (!this->needOpBytes(size)) {
- return 0;
- }
- unsigned id = fFactorySet->add(fact);
- this->writeOp(kName_Flattenable_DrawOp, paintflat, id);
- fWriter.writeString(name, len);
- }
- }
-
SkFlattenableWriteBuffer tmpWriter(1024);
+ tmpWriter.setFlags(SkFlattenableWriteBuffer::kInlineFactoryNames_Flag);
tmpWriter.setFactoryRecorder(fFactorySet);
tmpWriter.writeFlattenable(obj);