зеркало из https://github.com/mozilla/moz-skia.git
Pipe factory names independently from the flattenables using them.
Avoids an issue where a flattenable written twice might be written differently (the first time the flat data may have a name, whereas the second time it will have an index). Also add a test which confirms that identical flattenables will have the same SkFlatData representation. BUG=https://code.google.com/p/skia/issues/detail?id=721 TEST=FlatDataTest.cpp Review URL: https://codereview.appspot.com/6431057 git-svn-id: http://skia.googlecode.com/svn/trunk@4896 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
4605a3f3ff
Коммит
0c3e5fe728
|
@ -40,6 +40,7 @@
|
||||||
'../tests/DrawTextTest.cpp',
|
'../tests/DrawTextTest.cpp',
|
||||||
'../tests/EmptyPathTest.cpp',
|
'../tests/EmptyPathTest.cpp',
|
||||||
'../tests/FillPathTest.cpp',
|
'../tests/FillPathTest.cpp',
|
||||||
|
'../tests/FlatDataTest.cpp',
|
||||||
'../tests/FlateTest.cpp',
|
'../tests/FlateTest.cpp',
|
||||||
'../tests/FontHostStreamTest.cpp',
|
'../tests/FontHostStreamTest.cpp',
|
||||||
'../tests/FontHostTest.cpp',
|
'../tests/FontHostTest.cpp',
|
||||||
|
|
|
@ -191,8 +191,8 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this with an initially empty array, so the reader can cache each
|
* 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
|
* factory it sees by name. Used by the pipe code in combination with
|
||||||
* the writer's kInlineFactoryNames_Flag.
|
* setNamedFactoryRecorder.
|
||||||
*/
|
*/
|
||||||
void setFactoryArray(SkTDArray<SkFlattenable::Factory>* array) {
|
void setFactoryArray(SkTDArray<SkFlattenable::Factory>* array) {
|
||||||
fFactoryTDArray = array;
|
fFactoryTDArray = array;
|
||||||
|
@ -241,6 +241,33 @@ protected:
|
||||||
|
|
||||||
class SkFactorySet : public SkTPtrSet<SkFlattenable::Factory> {};
|
class SkFactorySet : public SkTPtrSet<SkFlattenable::Factory> {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to SkFactorySet, but only allows Factorys that have registered names.
|
||||||
|
* Also has a function to return the next added Factory's name.
|
||||||
|
*/
|
||||||
|
class SkNamedFactorySet : public SkRefCnt {
|
||||||
|
public:
|
||||||
|
SkNamedFactorySet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the specified Factory in the set. If it is not already in the set,
|
||||||
|
* and has registered its name, add it to the set, and return its index.
|
||||||
|
* If the Factory has no registered name, return 0.
|
||||||
|
*/
|
||||||
|
uint32_t find(SkFlattenable::Factory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If new Factorys have been added to the set, return the name of the first
|
||||||
|
* Factory added after the Factory name returned by the last call to this
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
const char* getNextAddedFactoryName();
|
||||||
|
private:
|
||||||
|
int fNextAddedFactory;
|
||||||
|
SkFactorySet fFactorySet;
|
||||||
|
SkTDArray<const char*> fNames;
|
||||||
|
};
|
||||||
|
|
||||||
class SkFlattenableWriteBuffer {
|
class SkFlattenableWriteBuffer {
|
||||||
public:
|
public:
|
||||||
SkFlattenableWriteBuffer();
|
SkFlattenableWriteBuffer();
|
||||||
|
@ -285,13 +312,11 @@ public:
|
||||||
SkFactorySet* getFactoryRecorder() const { return fFactorySet; }
|
SkFactorySet* getFactoryRecorder() const { return fFactorySet; }
|
||||||
SkFactorySet* setFactoryRecorder(SkFactorySet*);
|
SkFactorySet* setFactoryRecorder(SkFactorySet*);
|
||||||
|
|
||||||
|
SkNamedFactorySet* getNamedFactoryRecorder() const { return fNamedFactorySet; }
|
||||||
|
SkNamedFactorySet* setNamedFactoryRecorder(SkNamedFactorySet*);
|
||||||
|
|
||||||
enum Flags {
|
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,
|
|
||||||
/**
|
/**
|
||||||
* Instructs the writer to always serialize bitmap pixel data.
|
* Instructs the writer to always serialize bitmap pixel data.
|
||||||
*/
|
*/
|
||||||
|
@ -304,9 +329,6 @@ public:
|
||||||
bool isCrossProcess() const {
|
bool isCrossProcess() const {
|
||||||
return SkToBool(fFlags & kCrossProcess_Flag);
|
return SkToBool(fFlags & kCrossProcess_Flag);
|
||||||
}
|
}
|
||||||
bool inlineFactoryNames() const {
|
|
||||||
return SkToBool(fFlags & kInlineFactoryNames_Flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool persistBitmapPixels() const {
|
bool persistBitmapPixels() const {
|
||||||
return (fFlags & (kCrossProcess_Flag | kForceFlattenBitmapPixels_Flag)) != 0;
|
return (fFlags & (kCrossProcess_Flag | kForceFlattenBitmapPixels_Flag)) != 0;
|
||||||
|
@ -326,6 +348,8 @@ protected:
|
||||||
SkRefCntSet* fTFSet;
|
SkRefCntSet* fTFSet;
|
||||||
SkRefCntSet* fRCSet;
|
SkRefCntSet* fRCSet;
|
||||||
SkFactorySet* fFactorySet;
|
SkFactorySet* fFactorySet;
|
||||||
|
SkNamedFactorySet* fNamedFactorySet;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -128,7 +128,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkGPipeCanvas* fCanvas;
|
SkGPipeCanvas* fCanvas;
|
||||||
SkFactorySet* fFactorySet;
|
|
||||||
SkWriter32 fWriter;
|
SkWriter32 fWriter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -46,17 +46,43 @@ SkFlattenableReadBuffer::SkFlattenableReadBuffer() {
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
SkNamedFactorySet::SkNamedFactorySet() : fNextAddedFactory(0) {}
|
||||||
|
|
||||||
|
uint32_t SkNamedFactorySet::find(SkFlattenable::Factory factory) {
|
||||||
|
uint32_t index = fFactorySet.find(factory);
|
||||||
|
if (index > 0) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
const char* name = SkFlattenable::FactoryToName(factory);
|
||||||
|
if (NULL == name) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*fNames.append() = name;
|
||||||
|
return fFactorySet.add(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* SkNamedFactorySet::getNextAddedFactoryName() {
|
||||||
|
if (fNextAddedFactory < fNames.count()) {
|
||||||
|
return fNames[fNextAddedFactory++];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkFlattenableWriteBuffer::SkFlattenableWriteBuffer() {
|
SkFlattenableWriteBuffer::SkFlattenableWriteBuffer() {
|
||||||
fFlags = (Flags)0;
|
fFlags = (Flags)0;
|
||||||
fRCSet = NULL;
|
fRCSet = NULL;
|
||||||
fTFSet = NULL;
|
fTFSet = NULL;
|
||||||
fFactorySet = NULL;
|
fFactorySet = NULL;
|
||||||
|
fNamedFactorySet = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkFlattenableWriteBuffer::~SkFlattenableWriteBuffer() {
|
SkFlattenableWriteBuffer::~SkFlattenableWriteBuffer() {
|
||||||
SkSafeUnref(fRCSet);
|
SkSafeUnref(fRCSet);
|
||||||
SkSafeUnref(fTFSet);
|
SkSafeUnref(fTFSet);
|
||||||
SkSafeUnref(fFactorySet);
|
SkSafeUnref(fFactorySet);
|
||||||
|
SkSafeUnref(fNamedFactorySet);
|
||||||
}
|
}
|
||||||
|
|
||||||
SkRefCntSet* SkFlattenableWriteBuffer::setRefCntRecorder(SkRefCntSet* rec) {
|
SkRefCntSet* SkFlattenableWriteBuffer::setRefCntRecorder(SkRefCntSet* rec) {
|
||||||
|
@ -71,6 +97,20 @@ SkRefCntSet* SkFlattenableWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) {
|
||||||
|
|
||||||
SkFactorySet* SkFlattenableWriteBuffer::setFactoryRecorder(SkFactorySet* rec) {
|
SkFactorySet* SkFlattenableWriteBuffer::setFactoryRecorder(SkFactorySet* rec) {
|
||||||
SkRefCnt_SafeAssign(fFactorySet, rec);
|
SkRefCnt_SafeAssign(fFactorySet, rec);
|
||||||
|
if (fNamedFactorySet != NULL) {
|
||||||
|
fNamedFactorySet->unref();
|
||||||
|
fNamedFactorySet = NULL;
|
||||||
|
}
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkNamedFactorySet* SkFlattenableWriteBuffer::setNamedFactoryRecorder(
|
||||||
|
SkNamedFactorySet* rec) {
|
||||||
|
SkRefCnt_SafeAssign(fNamedFactorySet, rec);
|
||||||
|
if (fFactorySet != NULL) {
|
||||||
|
fFactorySet->unref();
|
||||||
|
fFactorySet = NULL;
|
||||||
|
}
|
||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,32 +45,16 @@ SkFlattenable* SkOrderedReadBuffer::readFlattenable() {
|
||||||
if (0 == index) {
|
if (0 == index) {
|
||||||
return NULL; // writer failed to give us the flattenable
|
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
|
index -= 1; // we stored the index-base-1
|
||||||
SkASSERT(index < fFactoryCount);
|
SkASSERT(index < fFactoryCount);
|
||||||
factory = fFactoryArray[index];
|
factory = fFactoryArray[index];
|
||||||
} else if (fFactoryTDArray) {
|
} else if (fFactoryTDArray) {
|
||||||
const int32_t* peek = (const int32_t*)fReader.peek();
|
|
||||||
if (*peek <= 0) {
|
|
||||||
int32_t index = fReader.readU32();
|
int32_t index = fReader.readU32();
|
||||||
if (0 == index) {
|
if (0 == index) {
|
||||||
return NULL; // writer failed to give us the flattenable
|
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
|
index -= 1; // we stored the index-base-1
|
||||||
factory = (*fFactoryTDArray)[index];
|
factory = (*fFactoryTDArray)[index];
|
||||||
} else {
|
|
||||||
const char* name = fReader.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 {
|
} else {
|
||||||
factory = (SkFlattenable::Factory)readFunctionPtr();
|
factory = (SkFlattenable::Factory)readFunctionPtr();
|
||||||
if (NULL == factory) {
|
if (NULL == factory) {
|
||||||
|
|
|
@ -23,8 +23,7 @@ void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) {
|
||||||
/*
|
/*
|
||||||
* If we have a factoryset, then the first 32bits tell us...
|
* If we have a factoryset, then the first 32bits tell us...
|
||||||
* 0: failure to write the flattenable
|
* 0: failure to write the flattenable
|
||||||
* <0: we store the negative of the (1-based) index
|
* >0: (1-based) index into the SkFactorySet or SkNamedFactorySet
|
||||||
* >0: the length of the name
|
|
||||||
* If we don't have a factoryset, then the first "ptr" is either the
|
* If we don't have a factoryset, then the first "ptr" is either the
|
||||||
* factory, or null for failure.
|
* factory, or null for failure.
|
||||||
*
|
*
|
||||||
|
@ -37,7 +36,7 @@ void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) {
|
||||||
factory = flattenable->getFactory();
|
factory = flattenable->getFactory();
|
||||||
}
|
}
|
||||||
if (NULL == factory) {
|
if (NULL == factory) {
|
||||||
if (fFactorySet) {
|
if (fFactorySet != NULL || fNamedFactorySet != NULL) {
|
||||||
this->write32(0);
|
this->write32(0);
|
||||||
} else {
|
} else {
|
||||||
this->writeFunctionPtr(NULL);
|
this->writeFunctionPtr(NULL);
|
||||||
|
@ -53,32 +52,18 @@ void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) {
|
||||||
* resolve the function-ptrs into strings for its reader. SkPicture
|
* resolve the function-ptrs into strings for its reader. SkPicture
|
||||||
* does exactly this, by writing a table of names (matching the indices)
|
* does exactly this, by writing a table of names (matching the indices)
|
||||||
* up front in its serialized form.
|
* up front in its serialized form.
|
||||||
* 3. names : Reuse fFactorySet to store indices, but only after we've
|
* 3. index into fNamedFactorySet. fNamedFactorySet will also store the
|
||||||
* written the name the first time. SkGPipe uses this technique, as it
|
* name. SkGPipe uses this technique so it can write the name to its
|
||||||
* doesn't require the reader to be told to know the table of names
|
* stream before writing the flattenable.
|
||||||
* up front.
|
|
||||||
*/
|
*/
|
||||||
if (fFactorySet) {
|
if (fFactorySet) {
|
||||||
if (this->inlineFactoryNames()) {
|
this->write32(fFactorySet->add(factory));
|
||||||
int index = fFactorySet->find(factory);
|
} else if (fNamedFactorySet) {
|
||||||
if (index) {
|
int32_t index = fNamedFactorySet->find(factory);
|
||||||
// we write the negative of the index, to distinguish it from
|
this->write32(index);
|
||||||
// the length of a string
|
if (0 == index) {
|
||||||
this->write32(-index);
|
|
||||||
} else {
|
|
||||||
const char* name = SkFlattenable::FactoryToName(factory);
|
|
||||||
if (NULL == name) {
|
|
||||||
this->write32(0);
|
|
||||||
return;
|
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 {
|
} else {
|
||||||
this->writeFunctionPtr((void*)factory);
|
this->writeFunctionPtr((void*)factory);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ SkRefCnt* SkRefCntPlayback::set(int index, SkRefCnt* obj) {
|
||||||
SkFlatData* SkFlatData::Create(SkFlatController* controller, const void* obj,
|
SkFlatData* SkFlatData::Create(SkFlatController* controller, const void* obj,
|
||||||
int index, void (*flattenProc)(SkOrderedWriteBuffer&, const void*),
|
int index, void (*flattenProc)(SkOrderedWriteBuffer&, const void*),
|
||||||
SkRefCntSet* refCntRecorder, SkRefCntSet* faceRecorder,
|
SkRefCntSet* refCntRecorder, SkRefCntSet* faceRecorder,
|
||||||
uint32_t writeBufferflags, SkFactorySet* fset) {
|
uint32_t writeBufferflags, SkNamedFactorySet* fset) {
|
||||||
// a buffer of 256 bytes should be sufficient for most paints, regions,
|
// a buffer of 256 bytes should be sufficient for most paints, regions,
|
||||||
// and matrices.
|
// and matrices.
|
||||||
intptr_t storage[256];
|
intptr_t storage[256];
|
||||||
|
@ -75,7 +75,7 @@ SkFlatData* SkFlatData::Create(SkFlatController* controller, const void* obj,
|
||||||
buffer.setTypefaceRecorder(faceRecorder);
|
buffer.setTypefaceRecorder(faceRecorder);
|
||||||
}
|
}
|
||||||
buffer.setFlags(writeBufferflags);
|
buffer.setFlags(writeBufferflags);
|
||||||
buffer.setFactoryRecorder(fset);
|
buffer.setNamedFactoryRecorder(fset);
|
||||||
|
|
||||||
flattenProc(buffer, obj);
|
flattenProc(buffer, obj);
|
||||||
uint32_t size = buffer.size();
|
uint32_t size = buffer.size();
|
||||||
|
|
|
@ -175,6 +175,7 @@ public:
|
||||||
* provided.
|
* provided.
|
||||||
*/
|
*/
|
||||||
virtual void unalloc(void* ptr) = 0;
|
virtual void unalloc(void* ptr) = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SkFlatData {
|
class SkFlatData {
|
||||||
|
@ -241,7 +242,7 @@ public:
|
||||||
SkRefCntSet* refCntRecorder = NULL,
|
SkRefCntSet* refCntRecorder = NULL,
|
||||||
SkRefCntSet* faceRecorder = NULL,
|
SkRefCntSet* faceRecorder = NULL,
|
||||||
uint32_t writeBufferflags = 0,
|
uint32_t writeBufferflags = 0,
|
||||||
SkFactorySet* fset = NULL);
|
SkNamedFactorySet* fset = NULL);
|
||||||
|
|
||||||
void unflatten(void* result,
|
void unflatten(void* result,
|
||||||
void (*unflattenProc)(SkOrderedReadBuffer&, void*),
|
void (*unflattenProc)(SkOrderedReadBuffer&, void*),
|
||||||
|
@ -291,7 +292,7 @@ class SkFlatDictionary {
|
||||||
public:
|
public:
|
||||||
SkFlatDictionary(SkFlatController* controller, SkRefCntSet* refSet = NULL,
|
SkFlatDictionary(SkFlatController* controller, SkRefCntSet* refSet = NULL,
|
||||||
SkRefCntSet* typeFaceSet = NULL,
|
SkRefCntSet* typeFaceSet = NULL,
|
||||||
SkFactorySet* factorySet = NULL)
|
SkNamedFactorySet* factorySet = NULL)
|
||||||
: fController(controller), fRefSet(refSet), fTypefaceSet(typeFaceSet)
|
: fController(controller), fRefSet(refSet), fTypefaceSet(typeFaceSet)
|
||||||
, fFactorySet(factorySet) {
|
, fFactorySet(factorySet) {
|
||||||
fFlattenProc = NULL;
|
fFlattenProc = NULL;
|
||||||
|
@ -444,7 +445,7 @@ private:
|
||||||
SkTDArray<const SkFlatData*> fData;
|
SkTDArray<const SkFlatData*> fData;
|
||||||
SkRefCntSet* fRefSet;
|
SkRefCntSet* fRefSet;
|
||||||
SkRefCntSet* fTypefaceSet;
|
SkRefCntSet* fTypefaceSet;
|
||||||
SkFactorySet* fFactorySet;
|
SkNamedFactorySet* fFactorySet;
|
||||||
|
|
||||||
const SkFlatData* findAndReturnFlat(const T& element,
|
const SkFlatData* findAndReturnFlat(const T& element,
|
||||||
uint32_t writeBufferflags) {
|
uint32_t writeBufferflags) {
|
||||||
|
@ -540,7 +541,7 @@ class SkBitmapDictionary : public SkFlatDictionary<SkBitmap> {
|
||||||
public:
|
public:
|
||||||
SkBitmapDictionary(SkFlatController* controller, SkRefCntSet* refSet = NULL,
|
SkBitmapDictionary(SkFlatController* controller, SkRefCntSet* refSet = NULL,
|
||||||
SkRefCntSet* typefaceSet = NULL,
|
SkRefCntSet* typefaceSet = NULL,
|
||||||
SkFactorySet* factorySet = NULL)
|
SkNamedFactorySet* factorySet = NULL)
|
||||||
: SkFlatDictionary<SkBitmap>(controller, refSet, typefaceSet, factorySet) {
|
: SkFlatDictionary<SkBitmap>(controller, refSet, typefaceSet, factorySet) {
|
||||||
fFlattenProc = &SkFlattenObjectProc<SkBitmap>;
|
fFlattenProc = &SkFlattenObjectProc<SkBitmap>;
|
||||||
fUnflattenProc = &SkUnflattenObjectProc<SkBitmap>;
|
fUnflattenProc = &SkUnflattenObjectProc<SkBitmap>;
|
||||||
|
|
|
@ -70,6 +70,7 @@ enum DrawOps {
|
||||||
kDef_Typeface_DrawOp,
|
kDef_Typeface_DrawOp,
|
||||||
kDef_Flattenable_DrawOp,
|
kDef_Flattenable_DrawOp,
|
||||||
kDef_Bitmap_DrawOp,
|
kDef_Bitmap_DrawOp,
|
||||||
|
kDef_Factory_DrawOp,
|
||||||
|
|
||||||
// these are signals to playback, not drawing verbs
|
// these are signals to playback, not drawing verbs
|
||||||
kReportFlags_DrawOp,
|
kReportFlags_DrawOp,
|
||||||
|
|
|
@ -104,6 +104,14 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void defFactory(const char* name) {
|
||||||
|
SkFlattenable::Factory factory = SkFlattenable::NameToFactory(name);
|
||||||
|
if (factory) {
|
||||||
|
SkASSERT(fFactoryArray.find(factory) < 0);
|
||||||
|
*fFactoryArray.append() = factory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void addBitmap(int index) {
|
void addBitmap(int index) {
|
||||||
index--;
|
index--;
|
||||||
SkBitmap* bm;
|
SkBitmap* bm;
|
||||||
|
@ -551,6 +559,11 @@ static void def_Bitmap_rp(SkCanvas*, SkReader32*, uint32_t op32,
|
||||||
state->addBitmap(index);
|
state->addBitmap(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void def_Factory_rp(SkCanvas*, SkReader32* reader, uint32_t,
|
||||||
|
SkGPipeState* state) {
|
||||||
|
state->defFactory(reader->readString());
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void skip_rp(SkCanvas*, SkReader32* reader, uint32_t op32, SkGPipeState*) {
|
static void skip_rp(SkCanvas*, SkReader32* reader, uint32_t op32, SkGPipeState*) {
|
||||||
|
@ -605,6 +618,7 @@ static const ReadProc gReadTable[] = {
|
||||||
def_Typeface_rp,
|
def_Typeface_rp,
|
||||||
def_PaintFlat_rp,
|
def_PaintFlat_rp,
|
||||||
def_Bitmap_rp,
|
def_Bitmap_rp,
|
||||||
|
def_Factory_rp,
|
||||||
|
|
||||||
reportflags_rp,
|
reportflags_rp,
|
||||||
done_rp
|
done_rp
|
||||||
|
|
|
@ -28,6 +28,10 @@
|
||||||
#include "SkOrderedWriteBuffer.h"
|
#include "SkOrderedWriteBuffer.h"
|
||||||
#include "SkPictureFlat.h"
|
#include "SkPictureFlat.h"
|
||||||
|
|
||||||
|
static bool isCrossProcess(uint32_t flags) {
|
||||||
|
return SkToBool(flags & SkGPipeWriter::kCrossProcess_Flag);
|
||||||
|
}
|
||||||
|
|
||||||
static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
|
static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
|
||||||
SkASSERT(paintFlat < kCount_PaintFlats);
|
SkASSERT(paintFlat < kCount_PaintFlats);
|
||||||
switch (paintFlat) {
|
switch (paintFlat) {
|
||||||
|
@ -61,7 +65,9 @@ static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
|
||||||
|
|
||||||
class FlattenableHeap : public SkFlatController {
|
class FlattenableHeap : public SkFlatController {
|
||||||
public:
|
public:
|
||||||
FlattenableHeap(int numFlatsToKeep) : fNumFlatsToKeep(numFlatsToKeep) {}
|
FlattenableHeap(int numFlatsToKeep)
|
||||||
|
: fNumFlatsToKeep(numFlatsToKeep) {
|
||||||
|
}
|
||||||
|
|
||||||
~FlattenableHeap() {
|
~FlattenableHeap() {
|
||||||
fPointers.freeAll();
|
fPointers.freeAll();
|
||||||
|
@ -132,7 +138,7 @@ const SkFlatData* FlattenableHeap::flatToReplace() const {
|
||||||
|
|
||||||
class FlatDictionary : public SkFlatDictionary<SkFlattenable> {
|
class FlatDictionary : public SkFlatDictionary<SkFlattenable> {
|
||||||
public:
|
public:
|
||||||
FlatDictionary(FlattenableHeap* heap, SkFactorySet* factorySet)
|
FlatDictionary(FlattenableHeap* heap, SkNamedFactorySet* factorySet)
|
||||||
: SkFlatDictionary<SkFlattenable>(heap, NULL, NULL, factorySet) {
|
: SkFlatDictionary<SkFlattenable>(heap, NULL, NULL, factorySet) {
|
||||||
fFlattenProc = &flattenFlattenableProc;
|
fFlattenProc = &flattenFlattenableProc;
|
||||||
// No need to define fUnflattenProc since the writer will never
|
// No need to define fUnflattenProc since the writer will never
|
||||||
|
@ -365,7 +371,7 @@ BitmapInfo* SharedHeap::bitmapToReplace(const SkBitmap& bm) const {
|
||||||
|
|
||||||
class SkGPipeCanvas : public SkCanvas {
|
class SkGPipeCanvas : public SkCanvas {
|
||||||
public:
|
public:
|
||||||
SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*, uint32_t flags);
|
SkGPipeCanvas(SkGPipeController*, SkWriter32*, uint32_t flags);
|
||||||
virtual ~SkGPipeCanvas();
|
virtual ~SkGPipeCanvas();
|
||||||
|
|
||||||
void finish() {
|
void finish() {
|
||||||
|
@ -439,6 +445,7 @@ private:
|
||||||
enum {
|
enum {
|
||||||
kNoSaveLayer = -1,
|
kNoSaveLayer = -1,
|
||||||
};
|
};
|
||||||
|
SkNamedFactorySet* fFactorySet;
|
||||||
int fFirstSaveLayerStackLevel;
|
int fFirstSaveLayerStackLevel;
|
||||||
SharedHeap fSharedHeap;
|
SharedHeap fSharedHeap;
|
||||||
SkGPipeController* fController;
|
SkGPipeController* fController;
|
||||||
|
@ -472,6 +479,10 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should be called after any calls to an SkFlatDictionary::findAndReplace
|
||||||
|
// if a new SkFlatData was added when in cross process mode
|
||||||
|
void flattenFactoryNames();
|
||||||
|
|
||||||
// These are only used when in cross process, but with no shared address
|
// These are only used when in cross process, but with no shared address
|
||||||
// space, so bitmaps are flattened.
|
// space, so bitmaps are flattened.
|
||||||
FlattenableHeap fBitmapHeap;
|
FlattenableHeap fBitmapHeap;
|
||||||
|
@ -509,18 +520,32 @@ private:
|
||||||
typedef SkCanvas INHERITED;
|
typedef SkCanvas INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void SkGPipeCanvas::flattenFactoryNames() {
|
||||||
|
const char* name;
|
||||||
|
while ((name = fFactorySet->getNextAddedFactoryName()) != NULL) {
|
||||||
|
size_t len = strlen(name);
|
||||||
|
if (this->needOpBytes(len)) {
|
||||||
|
this->writeOp(kDef_Factory_DrawOp);
|
||||||
|
fWriter.writeString(name, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int SkGPipeCanvas::flattenToIndex(const SkBitmap & bitmap) {
|
int SkGPipeCanvas::flattenToIndex(const SkBitmap & bitmap) {
|
||||||
SkASSERT(shouldFlattenBitmaps(fFlags));
|
SkASSERT(shouldFlattenBitmaps(fFlags));
|
||||||
uint32_t flags = SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
|
uint32_t flags = SkFlattenableWriteBuffer::kCrossProcess_Flag;
|
||||||
| SkFlattenableWriteBuffer::kCrossProcess_Flag;
|
|
||||||
bool added, replaced;
|
bool added, replaced;
|
||||||
const SkFlatData* flat = fBitmapDictionary.findAndReplace(
|
const SkFlatData* flat = fBitmapDictionary.findAndReplace(
|
||||||
bitmap, flags, fBitmapHeap.flatToReplace(), &added, &replaced);
|
bitmap, flags, fBitmapHeap.flatToReplace(), &added, &replaced);
|
||||||
|
|
||||||
int index = flat->index();
|
int index = flat->index();
|
||||||
if (added && this->needOpBytes(flat->flatSize())) {
|
if (added) {
|
||||||
|
this->flattenFactoryNames();
|
||||||
|
size_t flatSize = flat->flatSize();
|
||||||
|
if (this->needOpBytes(flatSize)) {
|
||||||
this->writeOp(kDef_Bitmap_DrawOp, 0, index);
|
this->writeOp(kDef_Bitmap_DrawOp, 0, index);
|
||||||
fWriter.write(flat->data(), flat->flatSize());
|
fWriter.write(flat->data(), flatSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
@ -533,9 +558,8 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t writeBufferFlags;
|
uint32_t writeBufferFlags;
|
||||||
if (SkToBool(fFlags & SkGPipeWriter::kCrossProcess_Flag)) {
|
if (isCrossProcess(fFlags)) {
|
||||||
writeBufferFlags = (SkFlattenableWriteBuffer::kInlineFactoryNames_Flag
|
writeBufferFlags = SkFlattenableWriteBuffer::kCrossProcess_Flag;
|
||||||
| SkFlattenableWriteBuffer::kCrossProcess_Flag);
|
|
||||||
} else {
|
} else {
|
||||||
// Needed for bitmap shaders.
|
// Needed for bitmap shaders.
|
||||||
writeBufferFlags = SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag;
|
writeBufferFlags = SkFlattenableWriteBuffer::kForceFlattenBitmapPixels_Flag;
|
||||||
|
@ -545,9 +569,15 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
|
||||||
const SkFlatData* flat = fFlatDictionary.findAndReplace(
|
const SkFlatData* flat = fFlatDictionary.findAndReplace(
|
||||||
*obj, writeBufferFlags, fFlattenableHeap.flatToReplace(), &added, &replaced);
|
*obj, writeBufferFlags, fFlattenableHeap.flatToReplace(), &added, &replaced);
|
||||||
int index = flat->index();
|
int index = flat->index();
|
||||||
if (added && this->needOpBytes(flat->flatSize())) {
|
if (added) {
|
||||||
|
if (isCrossProcess(fFlags)) {
|
||||||
|
this->flattenFactoryNames();
|
||||||
|
}
|
||||||
|
size_t flatSize = flat->flatSize();
|
||||||
|
if (this->needOpBytes(flatSize)) {
|
||||||
this->writeOp(kDef_Flattenable_DrawOp, paintflat, index);
|
this->writeOp(kDef_Flattenable_DrawOp, paintflat, index);
|
||||||
fWriter.write(flat->data(), flat->flatSize());
|
fWriter.write(flat->data(), flatSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (replaced) {
|
if (replaced) {
|
||||||
index = ~index;
|
index = ~index;
|
||||||
|
@ -562,11 +592,15 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
|
||||||
#define FLATTENABLES_TO_KEEP 10
|
#define FLATTENABLES_TO_KEEP 10
|
||||||
|
|
||||||
SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
|
SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
|
||||||
SkWriter32* writer, SkFactorySet* fset, uint32_t flags)
|
SkWriter32* writer, uint32_t flags)
|
||||||
: fSharedHeap(!(flags & SkGPipeWriter::kCrossProcess_Flag), controller->numberOfReaders())
|
: fFactorySet(isCrossProcess(flags) ? SkNEW(SkNamedFactorySet) : NULL)
|
||||||
, fWriter(*writer), fFlags(flags)
|
, fSharedHeap(!isCrossProcess(flags), controller->numberOfReaders())
|
||||||
, fBitmapHeap(BITMAPS_TO_KEEP), fBitmapDictionary(&fBitmapHeap, NULL, NULL, fset)
|
, fWriter(*writer)
|
||||||
, fFlattenableHeap(FLATTENABLES_TO_KEEP), fFlatDictionary(&fFlattenableHeap, fset) {
|
, fFlags(flags)
|
||||||
|
, fBitmapHeap(BITMAPS_TO_KEEP)
|
||||||
|
, fBitmapDictionary(&fBitmapHeap, NULL, NULL, fFactorySet)
|
||||||
|
, fFlattenableHeap(FLATTENABLES_TO_KEEP)
|
||||||
|
, fFlatDictionary(&fFlattenableHeap, fFactorySet) {
|
||||||
fController = controller;
|
fController = controller;
|
||||||
fDone = false;
|
fDone = false;
|
||||||
fBlockSize = 0; // need first block from controller
|
fBlockSize = 0; // need first block from controller
|
||||||
|
@ -589,6 +623,7 @@ SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
|
||||||
|
|
||||||
SkGPipeCanvas::~SkGPipeCanvas() {
|
SkGPipeCanvas::~SkGPipeCanvas() {
|
||||||
this->finish();
|
this->finish();
|
||||||
|
SkSafeUnref(fFactorySet);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkGPipeCanvas::needOpBytes(size_t needed) {
|
bool SkGPipeCanvas::needOpBytes(size_t needed) {
|
||||||
|
@ -1196,7 +1231,7 @@ void SkGPipeCanvas::writePaint(const SkPaint& paint) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
|
if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) {
|
||||||
if (SkToBool(fFlags & SkGPipeWriter::kCrossProcess_Flag)) {
|
if (isCrossProcess(fFlags)) {
|
||||||
uint32_t id = this->getTypefaceID(paint.getTypeface());
|
uint32_t id = this->getTypefaceID(paint.getTypeface());
|
||||||
*ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
|
*ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id);
|
||||||
} else if (this->needOpBytes(sizeof(void*))) {
|
} else if (this->needOpBytes(sizeof(void*))) {
|
||||||
|
@ -1255,23 +1290,18 @@ void SkGPipeController::setCanvas(SkGPipeCanvas* canvas) {
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkGPipeWriter::SkGPipeWriter()
|
SkGPipeWriter::SkGPipeWriter()
|
||||||
: fFactorySet(SkNEW(SkFactorySet))
|
: fWriter(0) {
|
||||||
, fWriter(0) {
|
|
||||||
fCanvas = NULL;
|
fCanvas = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkGPipeWriter::~SkGPipeWriter() {
|
SkGPipeWriter::~SkGPipeWriter() {
|
||||||
this->endRecording();
|
this->endRecording();
|
||||||
fFactorySet->unref();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags) {
|
SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, uint32_t flags) {
|
||||||
if (NULL == fCanvas) {
|
if (NULL == fCanvas) {
|
||||||
fWriter.reset(NULL, 0);
|
fWriter.reset(NULL, 0);
|
||||||
fFactorySet->reset();
|
fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, flags));
|
||||||
fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter,
|
|
||||||
(flags & kCrossProcess_Flag) ?
|
|
||||||
fFactorySet : NULL, flags));
|
|
||||||
}
|
}
|
||||||
controller->setCanvas(fCanvas);
|
controller->setCanvas(fCanvas);
|
||||||
return fCanvas;
|
return fCanvas;
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2012 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SkBitmap.h"
|
||||||
|
#include "SkCanvas.h"
|
||||||
|
#include "SkColor.h"
|
||||||
|
#include "SkColorFilter.h"
|
||||||
|
#include "SkGradientShader.h"
|
||||||
|
#include "SkPaint.h"
|
||||||
|
#include "SkPictureFlat.h"
|
||||||
|
#include "SkShader.h"
|
||||||
|
#include "SkXfermode.h"
|
||||||
|
#include "Test.h"
|
||||||
|
|
||||||
|
static void flattenFlattenableProc(SkOrderedWriteBuffer& buffer,
|
||||||
|
const void* obj) {
|
||||||
|
buffer.writeFlattenable((SkFlattenable*)obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that two SkFlatData objects that created from the same object are
|
||||||
|
* identical when using an SkNamedFactorySet.
|
||||||
|
* @param reporter Object to report failures.
|
||||||
|
* @param obj Flattenable object to be flattened.
|
||||||
|
* @param flattenProc Function that flattens objects with the same type as obj.
|
||||||
|
*/
|
||||||
|
static void testCreate(skiatest::Reporter* reporter, const void* obj,
|
||||||
|
void (*flattenProc)(SkOrderedWriteBuffer&, const void*)) {
|
||||||
|
SkChunkFlatController controller(1024);
|
||||||
|
SkNamedFactorySet factorySet;
|
||||||
|
// No need to delete data because that will be taken care of by the
|
||||||
|
// controller.
|
||||||
|
SkFlatData* data1 = SkFlatData::Create(&controller, obj, 0, flattenProc,
|
||||||
|
NULL, NULL, 0, &factorySet);
|
||||||
|
data1->setSentinelInCache();
|
||||||
|
SkFlatData* data2 = SkFlatData::Create(&controller, obj, 0, flattenProc,
|
||||||
|
NULL, NULL, 0, &factorySet);
|
||||||
|
data2->setSentinelAsCandidate();
|
||||||
|
REPORTER_ASSERT(reporter, SkFlatData::Compare(data1, data2) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Tests(skiatest::Reporter* reporter) {
|
||||||
|
// Test flattening SkShader
|
||||||
|
SkPoint points[2];
|
||||||
|
points[0].set(0, 0);
|
||||||
|
points[1].set(SkIntToScalar(20), SkIntToScalar(20));
|
||||||
|
SkColor colors[2];
|
||||||
|
colors[0] = SK_ColorRED;
|
||||||
|
colors[1] = SK_ColorBLUE;
|
||||||
|
SkShader* shader = SkGradientShader::CreateLinear(points, colors, NULL,
|
||||||
|
2, SkShader::kRepeat_TileMode);
|
||||||
|
SkAutoUnref aur(shader);
|
||||||
|
testCreate(reporter, shader, flattenFlattenableProc);
|
||||||
|
|
||||||
|
// Test SkBitmap
|
||||||
|
{
|
||||||
|
SkBitmap bm;
|
||||||
|
bm.setConfig(SkBitmap::kARGB_8888_Config, 50, 50);
|
||||||
|
bm.allocPixels();
|
||||||
|
SkCanvas canvas(bm);
|
||||||
|
SkPaint paint;
|
||||||
|
paint.setShader(shader);
|
||||||
|
canvas.drawPaint(paint);
|
||||||
|
testCreate(reporter, &bm, &SkFlattenObjectProc<SkBitmap>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test SkColorFilter
|
||||||
|
SkColorFilter* cf = SkColorFilter::CreateLightingFilter(SK_ColorBLUE,
|
||||||
|
SK_ColorRED);
|
||||||
|
SkAutoUnref aurcf(cf);
|
||||||
|
testCreate(reporter, cf, &flattenFlattenableProc);
|
||||||
|
|
||||||
|
// Test SkXfermode
|
||||||
|
SkXfermode* xfer = SkXfermode::Create(SkXfermode::kDstOver_Mode);
|
||||||
|
SkAutoUnref aurxf(xfer);
|
||||||
|
testCreate(reporter, xfer, &flattenFlattenableProc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "TestClassDef.h"
|
||||||
|
DEFINE_TESTCLASS("FlatData", FlatDataClass, Tests)
|
Загрузка…
Ссылка в новой задаче