aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar weita@google.com <weita@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2009-05-03 18:23:30 +0000
committerGravatar weita@google.com <weita@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2009-05-03 18:23:30 +0000
commitf9ab99aaade8c451c0e9309b4c61a448373019e3 (patch)
tree0d9bc4974227cff2f3fa8f5ecd79a57382b01595
parent4226396806f99fea03fcc4f95f6367402bd5fa3d (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.h54
-rw-r--r--src/core/SkBitmap.cpp113
-rw-r--r--src/core/SkColorTable.cpp36
-rw-r--r--tests/BitmapCopyTest.cpp15
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());