aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-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());