diff --git a/include/core/SkFlattenable.h b/include/core/SkFlattenable.h index 03bcab86e2..fddda551cd 100644 --- a/include/core/SkFlattenable.h +++ b/include/core/SkFlattenable.h @@ -100,11 +100,27 @@ public: 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* array) { + fFactoryTDArray = array; + fFactoryArray = NULL; + fFactoryCount = 0; + } SkTypeface* readTypeface(); SkRefCnt* readRefCnt(); @@ -118,6 +134,7 @@ private: SkTypeface** fTFArray; int fTFCount; + SkTDArray* fFactoryTDArray; SkFlattenable::Factory* fFactoryArray; int fFactoryCount; @@ -165,12 +182,22 @@ public: 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; @@ -179,10 +206,10 @@ public: 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; }; diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index f4b325fea5..4e83651927 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -876,7 +876,7 @@ private: friend class SkTextToPathIter; }; -////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// #include "SkPathEffect.h" @@ -894,20 +894,18 @@ public: 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; diff --git a/include/core/SkPathEffect.h b/include/core/SkPathEffect.h index eb1cc23833..f84e1d1b12 100644 --- a/include/core/SkPathEffect.h +++ b/include/core/SkPathEffect.h @@ -31,7 +31,6 @@ class SkPath; */ 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 @@ -86,16 +85,16 @@ public: // 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 @@ -121,16 +120,16 @@ public: : 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 diff --git a/include/core/SkPtrRecorder.h b/include/core/SkPtrRecorder.h index db6c64dfdf..fa87243e52 100644 --- a/include/core/SkPtrRecorder.h +++ b/include/core/SkPtrRecorder.h @@ -89,10 +89,13 @@ private: */ template 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); } diff --git a/include/effects/SkCornerPathEffect.h b/include/effects/SkCornerPathEffect.h index 823de3f6a3..a44df0a1a8 100644 --- a/include/effects/SkCornerPathEffect.h +++ b/include/effects/SkCornerPathEffect.h @@ -42,17 +42,13 @@ public: // 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; }; diff --git a/include/effects/SkDashPathEffect.h b/include/effects/SkDashPathEffect.h index 145f67d592..4eb5c1e69c 100644 --- a/include/effects/SkDashPathEffect.h +++ b/include/effects/SkDashPathEffect.h @@ -44,6 +44,8 @@ public: // This method is not exported to java. virtual void flatten(SkFlattenableWriteBuffer&); + static SkFlattenable* CreateProc(SkFlattenableReadBuffer&); + protected: SkDashPathEffect(SkFlattenableReadBuffer&); @@ -56,8 +58,6 @@ private: SkScalar fIntervalLength; bool fScaleToFit; - static SkFlattenable* CreateProc(SkFlattenableReadBuffer&); - typedef SkPathEffect INHERITED; }; diff --git a/include/effects/SkDiscretePathEffect.h b/include/effects/SkDiscretePathEffect.h index 2950950aad..19b107e77f 100644 --- a/include/effects/SkDiscretePathEffect.h +++ b/include/effects/SkDiscretePathEffect.h @@ -41,13 +41,13 @@ public: // 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; }; diff --git a/src/core/SkFlattenable.cpp b/src/core/SkFlattenable.cpp index 99dd856471..9222759ce3 100644 --- a/src/core/SkFlattenable.cpp +++ b/src/core/SkFlattenable.cpp @@ -48,6 +48,7 @@ SkFlattenableReadBuffer::SkFlattenableReadBuffer() { fTFArray = NULL; fTFCount = 0; + fFactoryTDArray = NULL; fFactoryArray = NULL; fFactoryCount = 0; } @@ -60,6 +61,7 @@ SkFlattenableReadBuffer::SkFlattenableReadBuffer(const void* data) : fTFArray = NULL; fTFCount = 0; + fFactoryTDArray = NULL; fFactoryArray = NULL; fFactoryCount = 0; } @@ -72,6 +74,7 @@ SkFlattenableReadBuffer::SkFlattenableReadBuffer(const void* data, size_t size) fTFArray = NULL; fTFCount = 0; + fFactoryTDArray = NULL; fFactoryArray = NULL; fFactoryCount = 0; } @@ -103,26 +106,48 @@ SkFlattenable* SkFlattenableReadBuffer::readFlattenable() { 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 @@ -131,6 +156,9 @@ SkFlattenable* SkFlattenableReadBuffer::readFlattenable() { // we could try to fix up the offset... sk_throw(); } + } else { + // we must skip the remaining data + this->skip(sizeRecorded); } return obj; } @@ -189,28 +217,78 @@ void SkFlattenableWriteBuffer::writeRefCnt(SkRefCnt* 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) { diff --git a/src/core/SkPathEffect.cpp b/src/core/SkPathEffect.cpp index c3a24fc049..b8880bb4c3 100644 --- a/src/core/SkPathEffect.cpp +++ b/src/core/SkPathEffect.cpp @@ -30,8 +30,8 @@ SkPairPathEffect::SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1) } SkPairPathEffect::~SkPairPathEffect() { - fPE0->unref(); - fPE1->unref(); + SkSafeUnref(fPE0); + SkSafeUnref(fPE1); } /* @@ -45,12 +45,18 @@ void SkPairPathEffect::flatten(SkFlattenableWriteBuffer& buffer) { 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; @@ -134,3 +140,14 @@ SkStrokePathEffect::SkStrokePathEffect(SkFlattenableReadBuffer& buffer) { fCap = buffer.readU8(); } +/////////////////////////////////////////////////////////////////////////////// + +static SkFlattenable::Registrar gComposePathEffectReg("SkComposePathEffect", + SkComposePathEffect::CreateProc); + +static SkFlattenable::Registrar gSumPathEffectReg("SkSumPathEffect", + SkSumPathEffect::CreateProc); + +static SkFlattenable::Registrar gStrokePathEffectReg("SkStrokePathEffect", + SkStrokePathEffect::CreateProc); + diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp index 8842086fd8..9f873b8c80 100644 --- a/src/core/SkWriter32.cpp +++ b/src/core/SkWriter32.cpp @@ -195,8 +195,6 @@ bool SkWriter32::writeToStream(SkWStream* stream) { */ 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(); diff --git a/src/effects/SkBlurDrawLooper.cpp b/src/effects/SkBlurDrawLooper.cpp index bde04edf50..0672f1bf7c 100644 --- a/src/effects/SkBlurDrawLooper.cpp +++ b/src/effects/SkBlurDrawLooper.cpp @@ -38,7 +38,9 @@ SkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy, } } -SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer) { +SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer) +: INHERITED(buffer) { + fDx = buffer.readScalar(); fDy = buffer.readScalar(); fBlurColor = buffer.readU32(); diff --git a/src/effects/SkCornerPathEffect.cpp b/src/effects/SkCornerPathEffect.cpp index 158cefaf5e..4c2cd4c0cd 100644 --- a/src/effects/SkCornerPathEffect.cpp +++ b/src/effects/SkCornerPathEffect.cpp @@ -153,3 +153,8 @@ SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) { fRadius = buffer.readScalar(); } +/////////////////////////////////////////////////////////////////////////////// + +static SkFlattenable::Registrar gReg("SkCornerPathEffect", + SkCornerPathEffect::CreateProc); + diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp index 82f357c7c5..b1f58e6825 100644 --- a/src/effects/SkDashPathEffect.cpp +++ b/src/effects/SkDashPathEffect.cpp @@ -168,4 +168,8 @@ SkDashPathEffect::SkDashPathEffect(SkFlattenableReadBuffer& buffer) { buffer.read(fIntervals, fCount * sizeof(fIntervals[0])); } +/////////////////////////////////////////////////////////////////////////////// + +static SkFlattenable::Registrar gReg("SkDashPathEffect", + SkDashPathEffect::CreateProc); diff --git a/src/effects/SkDiscretePathEffect.cpp b/src/effects/SkDiscretePathEffect.cpp index 3b8d48e7b5..9ffce896af 100644 --- a/src/effects/SkDiscretePathEffect.cpp +++ b/src/effects/SkDiscretePathEffect.cpp @@ -93,3 +93,8 @@ SkDiscretePathEffect::SkDiscretePathEffect(SkFlattenableReadBuffer& buffer) { fPerterb = buffer.readScalar(); } +/////////////////////////////////////////////////////////////////////////////// + +static SkFlattenable::Registrar gReg("SkDiscretePathEffect", + SkDiscretePathEffect::CreateProc); + diff --git a/src/pipe/SkGPipePriv.h b/src/pipe/SkGPipePriv.h index fb1553693d..06ba7b6aaa 100644 --- a/src/pipe/SkGPipePriv.h +++ b/src/pipe/SkGPipePriv.h @@ -75,8 +75,6 @@ enum DrawOps { kDef_Typeface_DrawOp, kDef_Flattenable_DrawOp, - kName_Flattenable_DrawOp, // index <--> name - // these are signals to playback, not drawing verbs kDone_DrawOp, }; diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp index 6665abb3ff..fb0fbc497e 100644 --- a/src/pipe/SkGPipeRead.cpp +++ b/src/pipe/SkGPipeRead.cpp @@ -72,7 +72,7 @@ public: void setReader(SkFlattenableReadBuffer* reader) { fReader = reader; - fReader->setFactoryPlayback(fFactoryArray.begin(), fFactoryArray.count()); + fReader->setFactoryArray(&fFactoryArray); } const SkPaint& paint() const { return fPaint; } @@ -91,16 +91,6 @@ public: *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)); @@ -444,13 +434,6 @@ static void def_PaintFlat_rp(SkCanvas*, SkReader32*, uint32_t op32, 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*) { @@ -497,7 +480,6 @@ static const ReadProc gReadTable[] = { paintOp_rp, def_Typeface_rp, def_PaintFlat_rp, - name_PaintFlat_rp, done_rp }; @@ -507,8 +489,8 @@ static const ReadProc gReadTable[] = { SkGPipeState::SkGPipeState() {} SkGPipeState::~SkGPipeState() { - fTypefaces.unrefAll(); - fFlatArray.unrefAll(); + fTypefaces.safeUnrefAll(); + fFlatArray.safeUnrefAll(); } /////////////////////////////////////////////////////////////////////////////// @@ -562,8 +544,7 @@ SkGPipeReader::Status SkGPipeReader::playback(const void* data, size_t length, 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; diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp index 5f928d7de3..18c3e60c9f 100644 --- a/src/pipe/SkGPipeWrite.cpp +++ b/src/pipe/SkGPipeWrite.cpp @@ -197,31 +197,9 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) { 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);