diff --git a/include/core/SkChunkAlloc.h b/include/core/SkChunkAlloc.h index 0e9ad189cd..810e7b627a 100644 --- a/include/core/SkChunkAlloc.h +++ b/include/core/SkChunkAlloc.h @@ -46,6 +46,14 @@ public: return this->alloc(bytes, kThrow_AllocFailType); } + /** Call this to unalloc the most-recently allocated ptr by alloc(). On + success, the number of bytes freed is returned, or 0 if the block could + not be unallocated. This is a hint to the underlying allocator that + the previous allocation may be reused, but the implementation is free + to ignore this call (and return 0). + */ + size_t unalloc(void* ptr); + size_t totalCapacity() const { return fTotalCapacity; } private: diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp index 3a819029d0..635fde1dc0 100644 --- a/samplecode/SampleApp.cpp +++ b/samplecode/SampleApp.cpp @@ -299,12 +299,12 @@ void SampleWindow::afterChildren(SkCanvas* orig) { case kRaster_CanvasType: break; case kPicture_CanvasType: - if (false) { + if (true) { SkPicture* pict = new SkPicture(*fPicture); fPicture->unref(); orig->drawPicture(*pict); pict->unref(); - } if (true) { + } else if (true) { SkDynamicMemoryWStream ostream; fPicture->serialize(&ostream); fPicture->unref(); diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 00461b0de2..16c94c28c0 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -943,8 +943,8 @@ bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const { return true; } - SkScalarCompareType userT = SkScalarAs2sCompliment(top); - SkScalarCompareType userB = SkScalarAs2sCompliment(bottom); + SkScalarCompareType userT = SkScalarToCompareType(top); + SkScalarCompareType userB = SkScalarToCompareType(bottom); // check for invalid user Y coordinates (i.e. empty) if (userT >= userB) { diff --git a/src/core/SkChunkAlloc.cpp b/src/core/SkChunkAlloc.cpp index ae37ec0839..83272c58eb 100644 --- a/src/core/SkChunkAlloc.cpp +++ b/src/core/SkChunkAlloc.cpp @@ -23,6 +23,10 @@ struct SkChunkAlloc::Block { char* fFreePtr; // data[] follows + char* startOfData() { + return reinterpret_cast(this + 1); + } + void freeChain() { // this can be null Block* block = this; while (block) { @@ -89,7 +93,7 @@ SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) { if (block) { // block->fNext = fBlock; block->fFreeSize = size; - block->fFreePtr = (char*)block + sizeof(Block); + block->fFreePtr = block->startOfData(); fTotalCapacity += size; } @@ -118,3 +122,18 @@ void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) { return ptr; } +size_t SkChunkAlloc::unalloc(void* ptr) { + size_t bytes = 0; + Block* block = fBlock; + if (block) { + char* cPtr = reinterpret_cast(ptr); + char* start = block->startOfData(); + if (start <= cPtr && cPtr < block->fFreePtr) { + bytes = block->fFreePtr - cPtr; + block->fFreeSize += bytes; + block->fFreePtr = cPtr; + } + } + return bytes; +} + diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 691da41980..da70c74fe5 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -1278,50 +1278,143 @@ SkGlyphCache* SkPaint::detachCache(const SkMatrix* deviceMatrix) const #include "SkStream.h" +static uintptr_t asint(const void* p) { + return reinterpret_cast(p); +} + +union Scalar32 { + SkScalar fScalar; + uint32_t f32; +}; + +static uint32_t* write_scalar(uint32_t* ptr, SkScalar value) { + SkASSERT(sizeof(SkScalar) == sizeof(uint32_t)); + Scalar32 tmp; + tmp.fScalar = value; + *ptr = tmp.f32; + return ptr + 1; +} + +static SkScalar read_scalar(const uint32_t*& ptr) { + SkASSERT(sizeof(SkScalar) == sizeof(uint32_t)); + Scalar32 tmp; + tmp.f32 = *ptr++; + return tmp.fScalar; +} + +static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) { + SkASSERT(a == (uint8_t)a); + SkASSERT(b == (uint8_t)b); + SkASSERT(c == (uint8_t)c); + SkASSERT(d == (uint8_t)d); + return (a << 24) | (b << 16) | (c << 8) | d; +} + +enum FlatFlags { + kHasTypeface_FlatFlag = 0x01, + kHasEffects_FlatFlag = 0x02 +}; + +// The size of a flat paint's POD fields +static const uint32_t kPODPaintSize = 5 * sizeof(SkScalar) + + 1 * sizeof(SkColor) + + 1 * sizeof(uint16_t) + + 6 * sizeof(uint8_t); + +/* To save space/time, we analyze the paint, and write a truncated version of + it if there are not tricky elements like shaders, etc. + */ void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const { - buffer.writeTypeface(this->getTypeface()); - buffer.writeScalar(this->getTextSize()); - buffer.writeScalar(this->getTextScaleX()); - buffer.writeScalar(this->getTextSkewX()); - buffer.writeFlattenable(this->getPathEffect()); - buffer.writeFlattenable(this->getShader()); - buffer.writeFlattenable(this->getXfermode()); - buffer.writeFlattenable(this->getMaskFilter()); - buffer.writeFlattenable(this->getColorFilter()); - buffer.writeFlattenable(this->getRasterizer()); - buffer.writeFlattenable(this->getLooper()); - buffer.write32(this->getColor()); - buffer.writeScalar(this->getStrokeWidth()); - buffer.writeScalar(this->getStrokeMiter()); - buffer.write16(this->getFlags()); - buffer.write8(this->getTextAlign()); - buffer.write8(this->getStrokeCap()); - buffer.write8(this->getStrokeJoin()); - buffer.write8(this->getStyle()); - buffer.write8(this->getTextEncoding()); + uint8_t flatFlags = 0; + if (this->getTypeface()) { + flatFlags |= kHasTypeface_FlatFlag; + } + if (asint(this->getPathEffect()) | + asint(this->getShader()) | + asint(this->getXfermode()) | + asint(this->getMaskFilter()) | + asint(this->getColorFilter()) | + asint(this->getRasterizer()) | + asint(this->getLooper())) { + flatFlags |= kHasEffects_FlatFlag; + } + + SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize); + uint32_t* ptr = buffer.reserve(kPODPaintSize); + + ptr = write_scalar(ptr, this->getTextSize()); + ptr = write_scalar(ptr, this->getTextScaleX()); + ptr = write_scalar(ptr, this->getTextSkewX()); + ptr = write_scalar(ptr, this->getStrokeWidth()); + ptr = write_scalar(ptr, this->getStrokeMiter()); + *ptr++ = this->getColor(); + *ptr++ = (this->getFlags() << 16) | (this->getTextAlign() << 8) | flatFlags; + *ptr++ = pack_4(this->getStrokeCap(), this->getStrokeJoin(), + this->getStyle(), this->getTextEncoding()); + + // now we're done with ptr and the (pre)reserved space. If we need to write + // additional fields, use the buffer directly + if (flatFlags & kHasTypeface_FlatFlag) { + buffer.writeTypeface(this->getTypeface()); + } + if (flatFlags & kHasEffects_FlatFlag) { + buffer.writeFlattenable(this->getPathEffect()); + buffer.writeFlattenable(this->getShader()); + buffer.writeFlattenable(this->getXfermode()); + buffer.writeFlattenable(this->getMaskFilter()); + buffer.writeFlattenable(this->getColorFilter()); + buffer.writeFlattenable(this->getRasterizer()); + buffer.writeFlattenable(this->getLooper()); + } } void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) { - this->setTypeface(buffer.readTypeface()); - this->setTextSize(buffer.readScalar()); - this->setTextScaleX(buffer.readScalar()); - this->setTextSkewX(buffer.readScalar()); - this->setPathEffect((SkPathEffect*) buffer.readFlattenable())->safeUnref(); - this->setShader((SkShader*) buffer.readFlattenable())->safeUnref(); - this->setXfermode((SkXfermode*) buffer.readFlattenable())->safeUnref(); - this->setMaskFilter((SkMaskFilter*) buffer.readFlattenable())->safeUnref(); - this->setColorFilter((SkColorFilter*) buffer.readFlattenable())->safeUnref(); - this->setRasterizer((SkRasterizer*) buffer.readFlattenable())->safeUnref(); - this->setLooper((SkDrawLooper*) buffer.readFlattenable())->safeUnref(); - this->setColor(buffer.readU32()); - this->setStrokeWidth(buffer.readScalar()); - this->setStrokeMiter(buffer.readScalar()); - this->setFlags(buffer.readU16()); - this->setTextAlign((SkPaint::Align) buffer.readU8()); - this->setStrokeCap((SkPaint::Cap) buffer.readU8()); - this->setStrokeJoin((SkPaint::Join) buffer.readU8()); - this->setStyle((SkPaint::Style) buffer.readU8()); - this->setTextEncoding((SkPaint::TextEncoding) buffer.readU8()); + SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize); + const void* podData = buffer.skip(kPODPaintSize); + const uint32_t* pod = reinterpret_cast(podData); + + // the order we read must match the order we wrote in flatten() + this->setTextSize(read_scalar(pod)); + this->setTextScaleX(read_scalar(pod)); + this->setTextSkewX(read_scalar(pod)); + this->setStrokeWidth(read_scalar(pod)); + this->setStrokeMiter(read_scalar(pod)); + this->setColor(*pod++); + + uint32_t tmp = *pod++; + this->setFlags(tmp >> 16); + this->setTextAlign(static_cast((tmp >> 8) & 0xFF)); + uint8_t flatFlags = tmp & 0xFF; + + tmp = *pod++; + this->setStrokeCap(static_cast((tmp >> 24) & 0xFF)); + this->setStrokeJoin(static_cast((tmp >> 16) & 0xFF)); + this->setStyle(static_cast