/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkChunkAlloc.h"
#include "SkPackBits.h"
#include "SkBitmap.h"
#include "SkPixelRef.h"
class RLEPixelRef : public SkPixelRef {
public:
RLEPixelRef(SkBitmap::RLEPixels* rlep, SkColorTable* ctable);
virtual ~RLEPixelRef();
protected:
// overrides from SkPixelRef
virtual void* onLockPixels(SkColorTable**);
virtual void onUnlockPixels();
private:
SkBitmap::RLEPixels* fRLEPixels;
SkColorTable* fCTable;
};
RLEPixelRef::RLEPixelRef(SkBitmap::RLEPixels* rlep, SkColorTable* ctable)
: SkPixelRef(NULL) {
fRLEPixels = rlep; // we now own this ptr
fCTable = ctable;
SkSafeRef(ctable);
}
RLEPixelRef::~RLEPixelRef() {
SkDELETE(fRLEPixels);
SkSafeUnref(fCTable);
}
void* RLEPixelRef::onLockPixels(SkColorTable** ct) {
*ct = fCTable;
return fRLEPixels;
}
void RLEPixelRef::onUnlockPixels() {
// nothing to do
}
/////////////////////////////////////////////////////////////////////////////
class ChunkRLEPixels : public SkBitmap::RLEPixels {
public:
ChunkRLEPixels(int width, int height, size_t chunkSize)
: SkBitmap::RLEPixels(width, height), fStorage(chunkSize) {
}
SkChunkAlloc fStorage;
};
SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src);
SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src) {
if (SkBitmap::kIndex8_Config != src.config() &&
SkBitmap::kA8_Config != src.config()) {
return NULL;
}
size_t maxPacked = SkPackBits::ComputeMaxSize8(src.width());
// estimate the rle size based on the original size
size_t size = src.getSize() >> 3;
if (size < maxPacked) {
size = maxPacked;
}
ChunkRLEPixels* rlePixels = SkNEW_ARGS(ChunkRLEPixels,
(src.width(), src.height(), size));
uint8_t* dstRow = NULL;
size_t free = 0;
size_t totalPacked = 0;
for (int y = 0; y < src.height(); y++) {
const uint8_t* srcRow = src.getAddr8(0, y);
if (free < maxPacked) {
dstRow = (uint8_t*)rlePixels->fStorage.allocThrow(size);
free = size;
}
size_t packedSize = SkPackBits::Pack8(srcRow, src.width(), dstRow);
SkASSERT(packedSize <= free);
rlePixels->setPackedAtY(y, dstRow);
dstRow += packedSize;
free -= packedSize;
totalPacked += packedSize;
}
//#ifdef SK_DEBUG
#if 0
// test
uint8_t* buffer = new uint8_t[src.width()];
for (int y = 0; y < src.height(); y++) {
const uint8_t* srcRow = src.getAddr8(0, y);
SkPackBits::Unpack8(buffer, 0, src.width(), rlePixels->packedAtY(y));
int n = memcmp(buffer, srcRow, src.width());
if (n) {
SkDebugf("----- memcmp returned %d on line %d\n", n, y);
}
SkASSERT(n == 0);
}
delete[] buffer;
size_t totalAlloc = src.height() * sizeof(uint8_t*) + totalPacked;
SkDebugf("--- RLE: orig [%d %d] %d, rle %d %d savings %g\n",
src.width(), src.height(), src.getSize(),
src.height() * sizeof(uint8_t*), totalPacked,
(float)totalAlloc / src.getSize());
#endif
// transfer ownership of rlePixels to our pixelref
return SkNEW_ARGS(RLEPixelRef, (rlePixels, src.getColorTable()));
}