Both shader and gradient_shader write matrices to the flatten stream. However, they were
just calling write(&matrix, sizeof(SkMatrix)) and the matrix can contain lazily-computed
function ptrs as part of its internal cache. Thus two matrices that are logically the
same may write different bytes.
This is a problem because picture relies on flattening objects and then using the
flatten stream as a key into its cache. This matrix-write bug effectively kills the
effectiveness of the cache for shaders.
The fix is to write proper read/write functions for matrix (and region btw). These
call through to the existing low-level flatten routines (which just write into a
memory ptr).
git-svn-id: http://skia.googlecode.com/svn/trunk@1290
2bbb7eff-a529-9590-31e7-
b0007b416f81
SkFlattenable(SkFlattenableReadBuffer&) {}
};
+// helpers for matrix and region
+
+class SkMatrix;
+extern void SkReadMatrix(SkReader32*, SkMatrix*);
+extern void SkWriteMatrix(SkWriter32*, const SkMatrix&);
+
+class SkRegion;
+extern void SkReadRegion(SkReader32*, SkRegion*);
+extern void SkWriteRegion(SkWriter32*, const SkRegion&);
+
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#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
: INHERITED(buffer), fLocalMatrix(NULL) {
if (buffer.readBool()) {
SkMatrix matrix;
- buffer.read(&matrix, sizeof(matrix));
+ SkReadMatrix(&buffer, &matrix);
setLocalMatrix(matrix);
}
SkDEBUGCODE(fInSession = false;)
this->INHERITED::flatten(buffer);
buffer.writeBool(fLocalMatrix != NULL);
if (fLocalMatrix) {
- buffer.writeMul4(fLocalMatrix, sizeof(SkMatrix));
+ SkWriteMatrix(&buffer, *fLocalMatrix);
}
}
recs[i].fScale = buffer.readU32();
}
}
- buffer.read(&fPtsToUnit, sizeof(SkMatrix));
+ SkReadMatrix(&buffer, &fPtsToUnit);
fFlags = 0;
}
buffer.write32(recs[i].fScale);
}
}
- buffer.writeMul4(&fPtsToUnit, sizeof(SkMatrix));
+ SkWriteMatrix(&buffer, fPtsToUnit);
}
bool Gradient_Shader::setContext(const SkBitmap& device,