diff options
author | weita@google.com <weita@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-05-03 18:23:30 +0000 |
---|---|---|
committer | weita@google.com <weita@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-05-03 18:23:30 +0000 |
commit | f9ab99aaade8c451c0e9309b4c61a448373019e3 (patch) | |
tree | 0d9bc4974227cff2f3fa8f5ecd79a57382b01595 | |
parent | 4226396806f99fea03fcc4f95f6367402bd5fa3d (diff) |
Allow copying an Index8 bitmap when srcConfig and dstConfig are both
Index8.
Also, change the logic of SkBitmap.copyTo() to do memcpy() if srcConfig
and dstConfig are the same.
git-svn-id: http://skia.googlecode.com/svn/trunk@164 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | include/core/SkBitmap.h | 54 | ||||
-rw-r--r-- | src/core/SkBitmap.cpp | 113 | ||||
-rw-r--r-- | src/core/SkColorTable.cpp | 36 | ||||
-rw-r--r-- | tests/BitmapCopyTest.cpp | 15 |
4 files changed, 129 insertions, 89 deletions
diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index 5e7c44eee5..48055d0c7a 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -74,11 +74,11 @@ public: */ // This method is not exported to java. void swap(SkBitmap& other); - + /** Return true iff the bitmap has empty dimensions. */ bool empty() const { return 0 == fWidth || 0 == fHeight; } - + /** Return true iff the bitmap has no pixels nor a pixelref. Note: this can return true even if the dimensions of the bitmap are > 0 (see empty()). */ @@ -99,7 +99,7 @@ public: /** Return the number of bytes between subsequent rows of the bitmap. */ int rowBytes() const { return fRowBytes; } - + /** Return the shift amount per pixel (i.e. 0 for 1-byte per pixel, 1 for 2-bytes per pixel configs, 2 for 4-bytes per pixel configs). Return 0 for configs that are not at least 1-byte per pixel (e.g. kA1_Config @@ -128,7 +128,7 @@ public: if the real size exceeds 32bits. */ size_t getSize() const { return fHeight * fRowBytes; } - + /** Return the byte size of the pixels, based on the height and rowBytes. This routine is slightly slower than getSize(), but does not truncate the answer to 32bits. @@ -138,7 +138,7 @@ public: size.setMul(fHeight, fRowBytes); return size; } - + /** Returns true if the bitmap is opaque (has no translucent/transparent pixels). */ bool isOpaque() const; @@ -168,7 +168,7 @@ public: static int ComputeShiftPerPixel(Config c) { return ComputeBytesPerPixel(c) >> 1; } - + static Sk64 ComputeSize64(Config, int width, int height); static size_t ComputeSize(Config, int width, int height); @@ -180,7 +180,7 @@ public: /** Use this to assign a new pixel address for an existing bitmap. This will automatically release any pixelref previously installed. Only call this if you are handling ownership/lifetime of the pixel memory. - + If the bitmap retains a reference to the colortable (assuming it is not null) it will take care of incrementing the reference count. @@ -193,7 +193,7 @@ public: pixel memory. It will be sized based on the current width/height/config. If this is called multiple times, a new pixelref object will be created each time. - + If the bitmap retains a reference to the colortable (assuming it is not null) it will take care of incrementing the reference count. @@ -205,15 +205,15 @@ public: bool allocPixels(SkColorTable* ctable = NULL) { return this->allocPixels(NULL, ctable); } - + /** Use the specified Allocator to create the pixelref that manages the pixel memory. It will be sized based on the current width/height/config. If this is called multiple times, a new pixelref object will be created each time. - + If the bitmap retains a reference to the colortable (assuming it is not null) it will take care of incrementing the reference count. - + @param allocator The Allocator to use to create a pixelref that can manage the pixel memory for the current width/height/config. If allocator is NULL, the standard @@ -226,7 +226,7 @@ public: the bitmap will be unchanged. */ bool allocPixels(Allocator* allocator, SkColorTable* ctable); - + /** Return the current pixelref object, of any */ SkPixelRef* pixelRef() const { return fPixelRef; } @@ -239,7 +239,7 @@ public: ref'd. */ SkPixelRef* setPixelRef(SkPixelRef* pr, size_t offset = 0); - + /** Call this to ensure that the bitmap points to the current pixel address in the pixelref. Balance it with a call to unlockPixels(). These calls are harmless if there is no pixelref. @@ -251,7 +251,7 @@ public: a given image. */ void unlockPixels() const; - + /** Call this to be sure that the bitmap is valid enough to be drawn (i.e. it has non-null pixels, and if required by its config, it has a non-null colortable. Returns true if all of the above are met. @@ -273,7 +273,7 @@ public: will be returned. */ uint32_t getGenerationID() const; - + /** Call this if you have changed the contents of the pixels. This will in- turn cause a different generation ID value to be returned from getGenerationID(). @@ -301,7 +301,7 @@ public: this->eraseARGB(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c)); } - + /** Scroll (a subset of) the contents of this bitmap by dx/dy. If there are no pixels allocated (i.e. getPixels() returns null) the method will still update the inval region (if present). @@ -397,7 +397,7 @@ public: void extractAlpha(SkBitmap* dst, const SkPaint* paint, SkIPoint* offset) const; - + void flatten(SkFlattenableWriteBuffer&) const; void unflatten(SkFlattenableReadBuffer&); @@ -428,23 +428,23 @@ public: public: RLEPixels(int width, int height); virtual ~RLEPixels(); - + uint8_t* packedAtY(int y) const { SkASSERT((unsigned)y < (unsigned)fHeight); return fYPtrs[y]; } - + // called by subclasses during creation void setPackedAtY(int y, uint8_t* addr) { SkASSERT((unsigned)y < (unsigned)fHeight); fYPtrs[y] = addr; } - + private: uint8_t** fYPtrs; int fHeight; }; - + private: #ifdef SK_SUPPORT_MIPMAP struct MipMap; @@ -474,7 +474,7 @@ private: */ void freePixels(); void updatePixelsFromRef() const; - + static SkFixed ComputeMipLevel(SkFixed sx, SkFixed dy); }; @@ -485,7 +485,11 @@ private: */ class SkColorTable : public SkRefCnt { public: - /** Constructs an empty color table (zero colors). + /** Makes a deep copy of colors. + */ + SkColorTable(const SkColorTable& src); + /** Preallocates the colortable to have 'count' colors, which + * are initially set to 0. */ explicit SkColorTable(int count); explicit SkColorTable(SkFlattenableReadBuffer&); @@ -599,12 +603,12 @@ public: fCTable->unlockColors(false); } } - + /** Return the currently locked colors, or NULL if no bitmap's colortable is currently locked. */ const SkPMColor* colors() const { return fColors; } - + /** If a previous bitmap has been locked by this object, unlock its colors first. If the specified bitmap has a colortable, lock its colors and return them. diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index c5d0edaade..3debd81dc7 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -38,7 +38,7 @@ struct SkBitmap::MipMap : SkNoncopyable { int fLevelCount; // MipLevel fLevel[fLevelCount]; // Pixels[] - + static MipMap* Alloc(int levelCount, size_t pixelSize) { MipMap* mm = (MipMap*)sk_malloc_throw(sizeof(MipMap) + levelCount * sizeof(MipLevel) + @@ -53,7 +53,7 @@ struct SkBitmap::MipMap : SkNoncopyable { const void* pixels() const { return levels() + fLevelCount; } void* pixels() { return levels() + fLevelCount; } - + void safeRef() { if (this) { SkASSERT(fRefCnt > 0); @@ -103,7 +103,7 @@ SkBitmap& SkBitmap::operator=(const SkBitmap& src) { // we reset our locks if we get blown away fPixelLockCount = 0; - + /* The src could be in 3 states 1. no pixelref, in which case we just copy/ref the pixels/ctable 2. unlocked pixelref, pixels/ctable should be null @@ -238,7 +238,7 @@ void SkBitmap::updatePixelsFromRef() const { if (NULL != fPixelRef) { if (fPixelLockCount > 0) { SkASSERT(fPixelRef->getLockCount() > 0); - + void* p = fPixelRef->pixels(); if (NULL != p) { p = (char*)p + fPixelRefOffset; @@ -264,7 +264,7 @@ SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, size_t offset) { if (fPixelRef != pr) { this->freePixels(); SkASSERT(NULL == fPixelRef); - + pr->safeRef(); fPixelRef = pr; } @@ -374,7 +374,7 @@ void SkMallocPixelRef::onUnlockPixels() { void SkMallocPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); - + buffer.write32(fSize); buffer.writePad(fStorage, fSize); if (fCTable) { @@ -408,12 +408,12 @@ bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst, if (size.isNeg() || !size.is32()) { return false; } - + void* addr = sk_malloc_flags(size.get32(), 0); // returns NULL on failure if (NULL == addr) { return false; } - + dst->setPixelRef(new SkMallocPixelRef(addr, size.get32(), ctable))->unref(); // since we're already allocated, we lockPixels right away dst->lockPixels(); @@ -554,7 +554,7 @@ void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { case kRGB_565_Config: { uint16_t* p = (uint16_t*)fPixels; uint16_t v; - + if (kARGB_4444_Config == fConfig) { v = SkPackARGB4444(a >> 4, r >> 4, g >> 4, b >> 4); } else { // kRGB_565_Config @@ -578,7 +578,7 @@ void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { break; } } - + this->notifyPixelsChanged(); } @@ -590,7 +590,7 @@ void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const { static size_t getSubOffset(const SkBitmap& bm, int x, int y) { SkASSERT((unsigned)x < (unsigned)bm.width()); SkASSERT((unsigned)y < (unsigned)bm.height()); - + switch (bm.getConfig()) { case SkBitmap::kA8_Config: case SkBitmap:: kIndex8_Config: @@ -635,18 +635,18 @@ bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { return false; } SkBitmap bm; - + bm.setConfig(kIndex8_Config, r.width(), r.height()); bm.allocPixels(this->getColorTable()); if (NULL == bm.getPixels()) { return false; } - + const RLEPixels* rle = (const RLEPixels*)this->getPixels(); uint8_t* dst = bm.getAddr8(0, 0); const int width = bm.width(); const int rowBytes = bm.rowBytes(); - + for (int y = r.fTop; y < r.fBottom; y++) { SkPackBits::Unpack8(dst, r.fLeft, width, rle->packedAtY(y)); dst += rowBytes; @@ -683,47 +683,70 @@ bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { #include "SkPaint.h" bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const { - if (NULL == dst || this->width() == 0 || this->height() == 0) { + if (NULL == dst || this->getConfig() == kNo_Config + || this->width() == 0 || this->height() == 0) { return false; } + bool sameConfigs = (dstConfig == this->config()); switch (dstConfig) { case kA8_Config: case kARGB_4444_Config: case kRGB_565_Config: case kARGB_8888_Config: break; + case kA1_Config: + case kIndex8_Config: + if (!sameConfigs) { + return false; + } + break; default: return false; } - - SkBitmap tmp; - + + // do not copy src if srcConfig == kA1_Config while dstConfig != kA1_Config + if (this->getConfig() == kA1_Config && !sameConfigs) { + return false; + } + + SkBitmap tmp; tmp.setConfig(dstConfig, this->width(), this->height()); - // pass null for colortable, since we don't support Index8 config for dst - if (!tmp.allocPixels(alloc, NULL)) { + + // allocate colortable if srcConfig == kIndex8_Config + SkColorTable* ctable = (dstConfig == kIndex8_Config) ? + new SkColorTable(*this->getColorTable()) : NULL; + SkAutoUnref au(ctable); + if (!tmp.allocPixels(alloc, ctable)) { return false; } - + SkAutoLockPixels srclock(*this); SkAutoLockPixels dstlock(tmp); - + if (!this->readyToDraw() || !tmp.readyToDraw()) { // allocator/lock failed return false; } - // if the src has alpha, we have to clear the dst first - if (!this->isOpaque()) { - tmp.eraseColor(0); + /* do memcpy for the sameConfigs cases and + re-draw for the !sameConfigs cases + */ + if (sameConfigs) { + memcpy(tmp.getPixels(), this->getPixels(), this->getSize()); + } else { + // if the src has alpha, we have to clear the dst first + if (!this->isOpaque()) { + tmp.eraseColor(0); + } + + SkCanvas canvas(tmp); + SkPaint paint; + + paint.setDither(true); + canvas.drawBitmap(*this, 0, 0, &paint); } - SkCanvas canvas(tmp); - SkPaint paint; - - paint.setDither(true); - canvas.drawBitmap(*this, 0, 0, &paint); - dst->swap(tmp); return true; } @@ -773,13 +796,13 @@ static void downsampleby2_proc16(SkBitmap* dst, int x, int y, y <<= 1; const uint16_t* p = src.getAddr16(x, y); SkPMColor c; - + c = expand16(*p); if (x < (int)src.width() - 1) { p += 1; } c += expand16(*p); - + if (y < (int)src.height() - 1) { p = src.getAddr16(x, y + 1); } @@ -788,7 +811,7 @@ static void downsampleby2_proc16(SkBitmap* dst, int x, int y, p += 1; } c += expand16(*p); - + *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)pack16(c >> 2); } @@ -806,13 +829,13 @@ static void downsampleby2_proc4444(SkBitmap* dst, int x, int y, y <<= 1; const uint16_t* p = src.getAddr16(x, y); uint32_t c; - + c = expand4444(*p); if (x < src.width() - 1) { p += 1; } c += expand4444(*p); - + if (y < src.height() - 1) { p = src.getAddr16(x, y + 1); } @@ -821,7 +844,7 @@ static void downsampleby2_proc4444(SkBitmap* dst, int x, int y, p += 1; } c += expand4444(*p); - + *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)collaps4444(c >> 2); } @@ -897,7 +920,7 @@ void SkBitmap::buildMipMap(bool forceRebuild) { dstBM.setConfig(config, width, height, rowBytes); dstBM.setPixels(addr); - + for (unsigned y = 0; y < height; y++) { for (unsigned x = 0; x < width; x++) { proc(&dstBM, x, y, srcBM); @@ -924,7 +947,7 @@ int SkBitmap::extractMipLevel(SkBitmap* dst, SkFixed sx, SkFixed sy) { #ifdef SK_SUPPORT_MIPMAP if (NULL == fMipMap) return 0; - + int level = ComputeMipLevel(sx, sy) >> 16; SkASSERT(level >= 0); if (level <= 0) { @@ -1049,7 +1072,7 @@ void SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint, NO_FILTER_CASE: dst->setConfig(SkBitmap::kA8_Config, this->width(), this->height(), srcM.fRowBytes); - dst->allocPixels(); + dst->allocPixels(); GetBitmapAlpha(*this, dst->getAddr8(0, 0), srcM.fRowBytes); if (offset) { offset->set(0, 0); @@ -1105,7 +1128,7 @@ static SkPixelRef::Factory deserialize_factory(SkFlattenableReadBuffer& buffer) It is tricky to know how much to flatten. If we don't have a pixelref (i.e. we just have pixels, then we can only flatten the pixels, or write out an empty bitmap. - + With a pixelref, we still have the question of recognizing when two sitings of the same pixelref are the same, and when they are different. Perhaps we should look at the generationID and keep a record of that in some dictionary @@ -1118,7 +1141,7 @@ void SkBitmap::flatten(SkFlattenableWriteBuffer& buffer) const { buffer.write32(fRowBytes); buffer.write8(fConfig); buffer.writeBool(this->isOpaque()); - + /* If we are called in this mode, then it is up to the caller to manage the owner-counts on the pixelref, as we just record the ptr itself. */ @@ -1168,15 +1191,15 @@ void SkBitmap::flatten(SkFlattenableWriteBuffer& buffer) const { void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) { this->reset(); - + int width = buffer.readInt(); int height = buffer.readInt(); int rowBytes = buffer.readInt(); int config = buffer.readU8(); - + this->setConfig((Config)config, width, height, rowBytes); this->setIsOpaque(buffer.readBool()); - + size_t size = this->getSize(); int reftype = buffer.readU8(); switch (reftype) { diff --git a/src/core/SkColorTable.cpp b/src/core/SkColorTable.cpp index f991da3bc0..1f92caf669 100644 --- a/src/core/SkColorTable.cpp +++ b/src/core/SkColorTable.cpp @@ -2,16 +2,16 @@ ** ** Copyright 2006, The Android Open Source Project ** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** http://www.apache.org/licenses/LICENSE-2.0 +** http://www.apache.org/licenses/LICENSE-2.0 ** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and ** limitations under the License. */ @@ -31,7 +31,19 @@ SkColorTable::SkColorTable(int count) fCount = SkToU16(count); fColors = (SkPMColor*)sk_malloc_throw(count * sizeof(SkPMColor)); memset(fColors, 0, count * sizeof(SkPMColor)); - + + SkDEBUGCODE(fColorLockCount = 0;) + SkDEBUGCODE(f16BitCacheLockCount = 0;) +} + +SkColorTable::SkColorTable(const SkColorTable& src) { + f16BitCache = NULL; + fFlags = src.fFlags; + int count = src.count(); + fCount = SkToU16(count); + fColors = (SkPMColor*)sk_malloc_throw(count * sizeof(SkPMColor)); + memcpy(fColors, src.fColors, count * sizeof(SkPMColor)); + SkDEBUGCODE(fColorLockCount = 0;) SkDEBUGCODE(f16BitCacheLockCount = 0;) } @@ -43,13 +55,13 @@ SkColorTable::SkColorTable(const SkPMColor colors[], int count) count = 0; else if (count > 256) count = 256; - + fCount = SkToU16(count); fColors = (SkPMColor*)sk_malloc_throw(count * sizeof(SkPMColor)); - + if (colors) memcpy(fColors, colors, count * sizeof(SkPMColor)); - + SkDEBUGCODE(fColorLockCount = 0;) SkDEBUGCODE(f16BitCacheLockCount = 0;) } diff --git a/tests/BitmapCopyTest.cpp b/tests/BitmapCopyTest.cpp index 5ec64cfc03..f904859156 100644 --- a/tests/BitmapCopyTest.cpp +++ b/tests/BitmapCopyTest.cpp @@ -11,7 +11,7 @@ static const char* gConfigName[] = { }; static void init_src(const SkBitmap& bitmap) { - SkAutoLockPixels lock(bitmap); + SkAutoLockPixels lock(bitmap); if (bitmap.getPixels()) { memset(bitmap.getPixels(), 4, bitmap.getSize()); } @@ -32,7 +32,7 @@ struct Pair { static void TestBitmapCopy(skiatest::Reporter* reporter) { static const Pair gPairs[] = { { SkBitmap::kNo_Config, "00000000" }, - { SkBitmap::kA1_Config, "01101110" }, + { SkBitmap::kA1_Config, "01000000" }, { SkBitmap::kA8_Config, "00101110" }, { SkBitmap::kIndex8_Config, "00111110" }, { SkBitmap::kRGB_565_Config, "00101110" }, @@ -40,15 +40,15 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) { { SkBitmap::kARGB_8888_Config, "00101110" }, { SkBitmap::kRLE_Index8_Config, "00000000" } }; - + const int W = 20; const int H = 33; - + for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) { SkBitmap src, dst; SkColorTable* ct = NULL; - + src.setConfig(gPairs[i].fConfig, W, H); if (SkBitmap::kIndex8_Config == src.config()) { ct = init_ctable(); @@ -66,12 +66,13 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) { boolStr(success)); reporter->reportFailed(str); } - + if (success) { REPORTER_ASSERT(reporter, src.width() == dst.width()); REPORTER_ASSERT(reporter, src.height() == dst.height()); + REPORTER_ASSERT(reporter, dst.config() == gPairs[j].fConfig); if (src.config() == dst.config()) { - SkAutoLockPixels srcLock(src); + SkAutoLockPixels srcLock(src); SkAutoLockPixels dstLock(dst); REPORTER_ASSERT(reporter, src.readyToDraw()); REPORTER_ASSERT(reporter, dst.readyToDraw()); |