From 61e96cd44624c9faceb625519c1b29775b161f45 Mon Sep 17 00:00:00 2001 From: "commit-bot@chromium.org" Date: Tue, 11 Feb 2014 18:21:45 +0000 Subject: [PATCH] SkBitmap now really stores SkImageInfo -- config is just a ruse BUG=skia: R=scroggo@google.com Author: reed@google.com Review URL: https://codereview.chromium.org/159653004 git-svn-id: http://skia.googlecode.com/svn/trunk@13411 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkBitmap.h | 114 +++++++------ include/core/SkImageInfo.h | 46 ++++- include/core/SkPathRef.h | 2 +- src/core/SkBitmap.cpp | 289 ++++++++++++++------------------ src/image/SkImagePriv.cpp | 38 ++--- src/image/SkImagePriv.h | 2 +- src/images/SkDecodingImageGenerator.cpp | 5 - tests/ImageDecodingTest.cpp | 5 +- tests/PixelRefTest.cpp | 2 +- 9 files changed, 245 insertions(+), 258 deletions(-) diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index 87d4649..42ef877 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -79,10 +79,42 @@ public: // This method is not exported to java. void swap(SkBitmap& other); + /////////////////////////////////////////////////////////////////////////// + + const SkImageInfo& info() const { return fInfo; } + + int width() const { return fInfo.fWidth; } + int height() const { return fInfo.fHeight; } + SkColorType colorType() const { return fInfo.fColorType; } + SkAlphaType alphaType() const { return fInfo.fAlphaType; } + + /** Return the number of bytes per pixel based on the config. If the config + does not have at least 1 byte per (e.g. kA1_Config) then 0 is returned. + */ + int bytesPerPixel() const { return fInfo.bytesPerPixel(); } + + /** Return the rowbytes expressed as a number of pixels (like width and + height). Note, for 1-byte per pixel configs like kA8_Config, this will + return the same as rowBytes(). Is undefined for configs that are less + than 1-byte per pixel (e.g. kA1_Config) + */ + int rowBytesAsPixels() const { + return fRowBytes >> this->shiftPerPixel(); + } + + /** 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 + or kNo_Config) + */ + int shiftPerPixel() const { return this->bytesPerPixel() >> 1; } + + /////////////////////////////////////////////////////////////////////////// + /** Return true iff the bitmap has empty dimensions. * Hey! Before you use this, see if you really want to know drawsNothing() instead. */ - bool empty() const { return 0 == fWidth || 0 == fHeight; } + bool empty() const { return fInfo.isEmpty(); } /** Return true iff the bitmap has no pixelref. Note: this can return true even if the * dimensions of the bitmap are > 0 (see empty()). @@ -95,41 +127,14 @@ public: bool drawsNothing() const { return this->empty() || this->isNull(); } /** Return the config for the bitmap. */ - Config config() const { return (Config)fConfig; } + Config config() const; SK_ATTR_DEPRECATED("use config()") Config getConfig() const { return this->config(); } - /** Return the bitmap's width, in pixels. */ - int width() const { return fWidth; } - - /** Return the bitmap's height, in pixels. */ - int height() const { return fHeight; } - /** Return the number of bytes between subsequent rows of the bitmap. */ size_t 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 - or kNo_Config) - */ - int shiftPerPixel() const { return fBytesPerPixel >> 1; } - - /** Return the number of bytes per pixel based on the config. If the config - does not have at least 1 byte per (e.g. kA1_Config) then 0 is returned. - */ - int bytesPerPixel() const { return fBytesPerPixel; } - - /** Return the rowbytes expressed as a number of pixels (like width and - height). Note, for 1-byte per pixel configs like kA8_Config, this will - return the same as rowBytes(). Is undefined for configs that are less - than 1-byte per pixel (e.g. kA1_Config) - */ - int rowBytesAsPixels() const { return fRowBytes >> (fBytesPerPixel >> 1); } - - SkAlphaType alphaType() const { return (SkAlphaType)fAlphaType; } - /** * Set the bitmap's alphaType, returning true on success. If false is * returned, then the specified new alphaType is incompatible with the @@ -149,19 +154,19 @@ public: Note this truncates the result to 32bits. Call getSize64() to detect if the real size exceeds 32bits. */ - size_t getSize() const { return fHeight * fRowBytes; } + size_t getSize() const { return fInfo.fHeight * fRowBytes; } /** Return the number of bytes from the pointer returned by getPixels() to the end of the allocated space in the buffer. Required in cases where extractSubset has been called. */ - size_t getSafeSize() const ; + size_t getSafeSize() const { return fInfo.getSafeSize(fRowBytes); } /** * Return the full size of the bitmap, in bytes. */ int64_t computeSize64() const { - return sk_64_mul(fHeight, fRowBytes); + return sk_64_mul(fInfo.fHeight, fRowBytes); } /** @@ -170,7 +175,7 @@ public: * than computeSize64() if there is any rowbytes padding beyond the width. */ int64_t computeSafeSize64() const { - return ComputeSafeSize64((Config)fConfig, fWidth, fHeight, fRowBytes); + return fInfo.getSafeSize64(fRowBytes); } /** Returns true if this bitmap is marked as immutable, meaning that the @@ -304,11 +309,18 @@ public: void* context); /** - * If the bitmap's config can be represented as SkImageInfo, return true, - * and if info is not-null, set it to the bitmap's info. If it cannot be - * represented as SkImageInfo, return false and ignore the info parameter. + * DEPRECATED: call info(). */ - bool asImageInfo(SkImageInfo* info) const; + bool asImageInfo(SkImageInfo* info) const { + // compatibility: return false for kUnknown + if (kUnknown_SkColorType == this->colorType()) { + return false; + } + if (info) { + *info = this->info(); + } + return true; + } /** Use this to assign a new pixel address for an existing bitmap. This will automatically release any pixelref previously installed. Only call @@ -450,8 +462,8 @@ public: */ GrTexture* getTexture() const; - /** Return the bitmap's colortable, if it uses one (i.e. fConfig is - kIndex8_Config) and the pixels are locked. + /** Return the bitmap's colortable, if it uses one (i.e. colorType is + Index_8) and the pixels are locked. Otherwise returns NULL. Does not affect the colortable's reference count. */ @@ -742,13 +754,11 @@ private: #endif }; + SkImageInfo fInfo; + uint32_t fRowBytes; - uint32_t fWidth; - uint32_t fHeight; - uint8_t fConfig; - uint8_t fAlphaType; + uint8_t fFlags; - uint8_t fBytesPerPixel; // based on config void internalErase(const SkIRect&, U8CPU a, U8CPU r, U8CPU g, U8CPU b)const; @@ -860,29 +870,29 @@ private: inline uint32_t* SkBitmap::getAddr32(int x, int y) const { SkASSERT(fPixels); - SkASSERT(fConfig == kARGB_8888_Config); - SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight); + SkASSERT(this->config() == kARGB_8888_Config); + SkASSERT((unsigned)x < (unsigned)this->width() && (unsigned)y < (unsigned)this->height()); return (uint32_t*)((char*)fPixels + y * fRowBytes + (x << 2)); } inline uint16_t* SkBitmap::getAddr16(int x, int y) const { SkASSERT(fPixels); - SkASSERT(fConfig == kRGB_565_Config || fConfig == kARGB_4444_Config); - SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight); + SkASSERT(this->config() == kRGB_565_Config || this->config() == kARGB_4444_Config); + SkASSERT((unsigned)x < (unsigned)this->width() && (unsigned)y < (unsigned)this->height()); return (uint16_t*)((char*)fPixels + y * fRowBytes + (x << 1)); } inline uint8_t* SkBitmap::getAddr8(int x, int y) const { SkASSERT(fPixels); - SkASSERT(fConfig == kA8_Config || fConfig == kIndex8_Config); - SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight); + SkASSERT(this->config() == kA8_Config || this->config() == kIndex8_Config); + SkASSERT((unsigned)x < (unsigned)this->width() && (unsigned)y < (unsigned)this->height()); return (uint8_t*)fPixels + y * fRowBytes + x; } inline SkPMColor SkBitmap::getIndex8Color(int x, int y) const { SkASSERT(fPixels); - SkASSERT(fConfig == kIndex8_Config); - SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight); + SkASSERT(this->config() == kIndex8_Config); + SkASSERT((unsigned)x < (unsigned)this->width() && (unsigned)y < (unsigned)this->height()); SkASSERT(fColorTable); return (*fColorTable)[*((const uint8_t*)fPixels + y * fRowBytes + x)]; } diff --git a/include/core/SkImageInfo.h b/include/core/SkImageInfo.h index 722ff27..8ca87eb 100644 --- a/include/core/SkImageInfo.h +++ b/include/core/SkImageInfo.h @@ -8,7 +8,7 @@ #ifndef SkImageInfo_DEFINED #define SkImageInfo_DEFINED -#include "SkTypes.h" +#include "SkMath.h" #include "SkSize.h" class SkWriteBuffer; @@ -59,12 +59,17 @@ static inline bool SkAlphaTypeIsOpaque(SkAlphaType at) { return (unsigned)at <= kOpaque_SkAlphaType; } +static inline bool SkAlphaTypeIsValid(unsigned value) { + return value <= kLastEnum_SkAlphaType; +} + /////////////////////////////////////////////////////////////////////////////// /** * Describes how to interpret the components of a pixel. */ enum SkColorType { + kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType, @@ -85,6 +90,7 @@ enum SkColorType { static int SkColorTypeBytesPerPixel(SkColorType ct) { static const uint8_t gSize[] = { + 0, // Unknown 1, // Alpha_8 2, // RGB_565 2, // ARGB_4444 @@ -99,6 +105,14 @@ static int SkColorTypeBytesPerPixel(SkColorType ct) { return gSize[ct]; } +static inline size_t SkColorTypeMinRowBytes(SkColorType ct, int width) { + return width * SkColorTypeBytesPerPixel(ct); +} + +static inline bool SkColorTypeIsValid(unsigned value) { + return value <= kLastEnum_SkColorType; +} + /////////////////////////////////////////////////////////////////////////////// /** @@ -159,16 +173,29 @@ struct SkImageInfo { return info; } + int width() const { return fWidth; } + int height() const { return fHeight; } + SkColorType colorType() const { return fColorType; } + SkAlphaType alphaType() const { return fAlphaType; } + + bool isEmpty() const { return fWidth <= 0 || fHeight <= 0; } + bool isOpaque() const { return SkAlphaTypeIsOpaque(fAlphaType); } + SkISize dimensions() const { return SkISize::Make(fWidth, fHeight); } + int bytesPerPixel() const { return SkColorTypeBytesPerPixel(fColorType); } + uint64_t minRowBytes64() const { + return sk_64_mul(fWidth, this->bytesPerPixel()); + } + size_t minRowBytes() const { - return fWidth * this->bytesPerPixel(); + return (size_t)this->minRowBytes64(); } bool operator==(const SkImageInfo& other) const { @@ -181,12 +208,23 @@ struct SkImageInfo { void unflatten(SkReadBuffer&); void flatten(SkWriteBuffer&) const; - size_t getSafeSize(size_t rowBytes) const { + int64_t getSafeSize64(size_t rowBytes) const { if (0 == fHeight) { return 0; } - return (fHeight - 1) * rowBytes + fWidth * this->bytesPerPixel(); + return sk_64_mul(fHeight - 1, rowBytes) + fWidth * this->bytesPerPixel(); } + + size_t getSafeSize(size_t rowBytes) const { + return (size_t)this->getSafeSize64(rowBytes); + } + + bool validRowBytes(size_t rowBytes) const { + uint64_t rb = sk_64_mul(fWidth, this->bytesPerPixel()); + return rowBytes >= rb; + } + + SkDEBUGCODE(void validate() const;) }; #endif diff --git a/include/core/SkPathRef.h b/include/core/SkPathRef.h index 3c663f7..2e8c547 100644 --- a/include/core/SkPathRef.h +++ b/include/core/SkPathRef.h @@ -106,7 +106,7 @@ public: // In some cases we need to inject a leading moveTo before we add points // for lineTo, quadTo, conicTo, cubicTo - // + // // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0) // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo) void injectMoveToIfNeeded() { fPathRef->injectMoveToIfNeeded(); } diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index 6a70c1e..96d683c 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -24,6 +24,11 @@ #include "SkPackBits.h" #include +static bool reset_return_false(SkBitmap* bm) { + bm->reset(); + return false; +} + struct MipLevel { void* fPixels; uint32_t fRowBytes; @@ -125,13 +130,9 @@ void SkBitmap::swap(SkBitmap& other) { SkTSwap(fPixelLockCount, other.fPixelLockCount); SkTSwap(fMipMap, other.fMipMap); SkTSwap(fPixels, other.fPixels); + SkTSwap(fInfo, other.fInfo); SkTSwap(fRowBytes, other.fRowBytes); - SkTSwap(fWidth, other.fWidth); - SkTSwap(fHeight, other.fHeight); - SkTSwap(fConfig, other.fConfig); - SkTSwap(fAlphaType, other.fAlphaType); SkTSwap(fFlags, other.fFlags); - SkTSwap(fBytesPerPixel, other.fBytesPerPixel); SkDEBUGCODE(this->validate();) } @@ -141,6 +142,10 @@ void SkBitmap::reset() { sk_bzero(this, sizeof(*this)); } +SkBitmap::Config SkBitmap::config() const { + return SkColorTypeToBitmapConfig(fInfo.colorType()); +} + int SkBitmap::ComputeBytesPerPixel(SkBitmap::Config config) { int bpp; switch (config) { @@ -167,39 +172,12 @@ int SkBitmap::ComputeBytesPerPixel(SkBitmap::Config config) { } size_t SkBitmap::ComputeRowBytes(Config c, int width) { - if (width < 0) { - return 0; - } - - int64_t rowBytes = 0; - - switch (c) { - case kNo_Config: - break; - case kA8_Config: - case kIndex8_Config: - rowBytes = width; - break; - case kRGB_565_Config: - case kARGB_4444_Config: - // assign and then shift, so we don't overflow int - rowBytes = width; - rowBytes <<= 1; - break; - case kARGB_8888_Config: - // assign and then shift, so we don't overflow int - rowBytes = width; - rowBytes <<= 2; - break; - default: - SkDEBUGFAIL("unknown config"); - break; - } - return sk_64_isS32(rowBytes) ? sk_64_asS32(rowBytes) : 0; + return SkColorTypeMinRowBytes(SkBitmapConfigToColorType(c), width); } int64_t SkBitmap::ComputeSize64(Config config, int width, int height) { - int64_t rowBytes = sk_64_mul(ComputeBytesPerPixel(config), width); + SkColorType ct = SkBitmapConfigToColorType(config); + int64_t rowBytes = sk_64_mul(SkColorTypeBytesPerPixel(ct), width); return rowBytes * height; } @@ -212,13 +190,10 @@ int64_t SkBitmap::ComputeSafeSize64(Config config, uint32_t width, uint32_t height, size_t rowBytes) { - int64_t safeSize = 0; - if (height > 0) { - int64_t lastRow = sk_64_mul(ComputeBytesPerPixel(config), width); - safeSize = sk_64_mul(height - 1, rowBytes) + lastRow; - } - SkASSERT(safeSize >= 0); - return safeSize; + SkImageInfo info = SkImageInfo::Make(width, height, + SkBitmapConfigToColorType(config), + kPremul_SkAlphaType); + return info.getSafeSize64(rowBytes); } size_t SkBitmap::ComputeSafeSize(Config config, @@ -237,35 +212,36 @@ size_t SkBitmap::ComputeSafeSize(Config config, void SkBitmap::getBounds(SkRect* bounds) const { SkASSERT(bounds); bounds->set(0, 0, - SkIntToScalar(fWidth), SkIntToScalar(fHeight)); + SkIntToScalar(fInfo.fWidth), SkIntToScalar(fInfo.fHeight)); } void SkBitmap::getBounds(SkIRect* bounds) const { SkASSERT(bounds); - bounds->set(0, 0, fWidth, fHeight); + bounds->set(0, 0, fInfo.fWidth, fInfo.fHeight); } /////////////////////////////////////////////////////////////////////////////// -static bool validate_alphaType(SkBitmap::Config config, SkAlphaType alphaType, +static bool validate_alphaType(SkColorType colorType, SkAlphaType alphaType, SkAlphaType* canonical = NULL) { - switch (config) { - case SkBitmap::kNo_Config: + switch (colorType) { + case kUnknown_SkColorType: alphaType = kIgnore_SkAlphaType; break; - case SkBitmap::kA8_Config: + case kAlpha_8_SkColorType: if (kUnpremul_SkAlphaType == alphaType) { alphaType = kPremul_SkAlphaType; } // fall-through - case SkBitmap::kIndex8_Config: - case SkBitmap::kARGB_4444_Config: - case SkBitmap::kARGB_8888_Config: + case kIndex_8_SkColorType: + case kARGB_4444_SkColorType: + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: if (kIgnore_SkAlphaType == alphaType) { return false; } break; - case SkBitmap::kRGB_565_Config: + case kRGB_565_SkColorType: alphaType = kOpaque_SkAlphaType; break; default: @@ -277,52 +253,48 @@ static bool validate_alphaType(SkBitmap::Config config, SkAlphaType alphaType, return true; } -bool SkBitmap::setConfig(Config config, int width, int height, size_t rowBytes, - SkAlphaType alphaType) { - if ((width | height) < 0) { - goto BAD_CONFIG; +bool SkBitmap::setConfig(const SkImageInfo& info, size_t rowBytes) { + // require that rowBytes fit in 31bits + int64_t mrb = info.minRowBytes64(); + if ((int32_t)mrb != mrb) { + return reset_return_false(this); } - if (rowBytes == 0) { - rowBytes = SkBitmap::ComputeRowBytes(config, width); - if (0 == rowBytes && kNo_Config != config && width > 0) { - goto BAD_CONFIG; - } + if ((int64_t)rowBytes != (int32_t)rowBytes) { + return reset_return_false(this); } - if (!validate_alphaType(config, alphaType, &alphaType)) { - goto BAD_CONFIG; + if (info.width() < 0 || info.height() < 0) { + return reset_return_false(this); } - this->freePixels(); - - fConfig = SkToU8(config); - fAlphaType = SkToU8(alphaType); - fWidth = width; - fHeight = height; - fRowBytes = SkToU32(rowBytes); + if (kUnknown_SkColorType == info.colorType()) { + rowBytes = 0; + } else if (0 == rowBytes) { + rowBytes = (size_t)mrb; + } else if (rowBytes < info.minRowBytes()) { + return reset_return_false(this); + } - fBytesPerPixel = (uint8_t)ComputeBytesPerPixel(config); + this->freePixels(); - SkDEBUGCODE(this->validate();) + fInfo = info; + fRowBytes = SkToU32(rowBytes); return true; - - // if we got here, we had an error, so we reset the bitmap to empty -BAD_CONFIG: - this->reset(); - return false; } -bool SkBitmap::setConfig(const SkImageInfo& info, size_t rowBytes) { - return this->setConfig(SkImageInfoToBitmapConfig(info), info.fWidth, - info.fHeight, rowBytes, info.fAlphaType); +bool SkBitmap::setConfig(Config config, int width, int height, size_t rowBytes, + SkAlphaType alphaType) { + SkColorType ct = SkBitmapConfigToColorType(config); + return this->setConfig(SkImageInfo::Make(width, height, ct, alphaType), + rowBytes); } bool SkBitmap::setAlphaType(SkAlphaType alphaType) { - if (!validate_alphaType(this->config(), alphaType, &alphaType)) { + if (!validate_alphaType(fInfo.fColorType, alphaType, &alphaType)) { return false; } - if (fAlphaType != alphaType) { - fAlphaType = SkToU8(alphaType); + if (fInfo.fAlphaType != alphaType) { + fInfo.fAlphaType = alphaType; if (fPixelRef) { fPixelRef->changeAlphaType(alphaType); } @@ -339,7 +311,7 @@ void SkBitmap::updatePixelsFromRef() const { if (NULL != p) { p = (char*)p + fPixelRefOrigin.fY * fRowBytes - + fPixelRefOrigin.fX * fBytesPerPixel; + + fPixelRefOrigin.fX * fInfo.bytesPerPixel(); } fPixels = p; fColorTable = fPixelRef->colorTable(); @@ -379,20 +351,6 @@ static bool config_to_colorType(SkBitmap::Config config, SkColorType* ctOut) { return true; } -bool SkBitmap::asImageInfo(SkImageInfo* info) const { - SkColorType ct; - if (!config_to_colorType(this->config(), &ct)) { - return false; - } - if (info) { - info->fWidth = fWidth; - info->fHeight = fHeight; - info->fAlphaType = this->alphaType(); - info->fColorType = ct; - } - return true; -} - SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) { #ifdef SK_DEBUG if (pr) { @@ -404,7 +362,7 @@ SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, int dx, int dy) { SkASSERT(info.fColorType == prInfo.fColorType); switch (prInfo.fAlphaType) { case kIgnore_SkAlphaType: - SkASSERT(fAlphaType == kIgnore_SkAlphaType); + SkASSERT(fInfo.fAlphaType == kIgnore_SkAlphaType); break; case kOpaque_SkAlphaType: case kPremul_SkAlphaType: @@ -502,11 +460,6 @@ bool SkBitmap::allocPixels(Allocator* allocator, SkColorTable* ctable) { /////////////////////////////////////////////////////////////////////////////// -static bool reset_return_false(SkBitmap* bm) { - bm->reset(); - return false; -} - bool SkBitmap::allocPixels(const SkImageInfo& info, SkPixelRefFactory* factory, SkColorTable* ctable) { if (kIndex_8_SkColorType == info.fColorType && NULL == ctable) { @@ -562,10 +515,6 @@ bool SkBitmap::allocConfigPixels(Config config, int width, int height, } SkAlphaType at = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; - if (!validate_alphaType(config, at, &at)) { - return false; - } - return this->allocPixels(SkImageInfo::Make(width, height, ct, at)); } @@ -637,13 +586,6 @@ bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst, /////////////////////////////////////////////////////////////////////////////// -size_t SkBitmap::getSafeSize() const { - // This is intended to be a size_t version of ComputeSafeSize64(), just - // faster. The computation is meant to be identical. - return (fHeight ? ((fHeight - 1) * fRowBytes) + - ComputeRowBytes(this->config(), fWidth): 0); -} - bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize, size_t dstRowBytes, bool preserveDstPad) const { @@ -651,9 +593,10 @@ bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize, dstRowBytes = fRowBytes; } - if (dstRowBytes < ComputeRowBytes(this->config(), fWidth) || - dst == NULL || (getPixels() == NULL && pixelRef() == NULL)) + if (dstRowBytes < fInfo.minRowBytes() || + dst == NULL || (getPixels() == NULL && pixelRef() == NULL)) { return false; + } if (!preserveDstPad && static_cast(dstRowBytes) == fRowBytes) { size_t safeSize = this->getSafeSize(); @@ -670,16 +613,15 @@ bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize, } } else { // If destination has different stride than us, then copy line by line. - if (ComputeSafeSize(this->config(), fWidth, fHeight, dstRowBytes) > - dstSize) + if (fInfo.getSafeSize(dstRowBytes) > dstSize) { return false; - else { + } else { // Just copy what we need on each line. - size_t rowBytes = ComputeRowBytes(this->config(), fWidth); + size_t rowBytes = fInfo.minRowBytes(); SkAutoLockPixels lock(*this); const uint8_t* srcP = reinterpret_cast(getPixels()); uint8_t* dstP = reinterpret_cast(dst); - for (uint32_t row = 0; row < fHeight; + for (int row = 0; row < fInfo.fHeight; row++, srcP += fRowBytes, dstP += dstRowBytes) { memcpy(dstP, srcP, rowBytes); } @@ -723,19 +665,19 @@ void* SkBitmap::getAddr(int x, int y) const { char* base = (char*)this->getPixels(); if (base) { base += y * this->rowBytes(); - switch (this->config()) { - case SkBitmap::kARGB_8888_Config: + switch (this->colorType()) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: base += x << 2; break; - case SkBitmap::kARGB_4444_Config: - case SkBitmap::kRGB_565_Config: + case kARGB_4444_SkColorType: + case kRGB_565_SkColorType: base += x << 1; break; - case SkBitmap::kA8_Config: - case SkBitmap::kIndex8_Config: + case kAlpha_8_SkColorType: + case kIndex_8_SkColorType: base += x; break; - break; default: SkDEBUGFAIL("Can't return addr for config"); base = NULL; @@ -873,8 +815,12 @@ void SkBitmap::internalErase(const SkIRect& area, } #endif - if (kNo_Config == fConfig || kIndex8_Config == fConfig) { - return; + switch (fInfo.colorType()) { + case kUnknown_SkColorType: + case kIndex_8_SkColorType: + return; // can't erase + default: + break; } SkAutoLockPixels alp(*this); @@ -894,8 +840,8 @@ void SkBitmap::internalErase(const SkIRect& area, b = SkAlphaMul(b, a); } - switch (fConfig) { - case kA8_Config: { + switch (this->colorType()) { + case kAlpha_8_SkColorType: { uint8_t* p = this->getAddr8(area.fLeft, area.fTop); while (--height >= 0) { memset(p, a, width); @@ -903,12 +849,12 @@ void SkBitmap::internalErase(const SkIRect& area, } break; } - case kARGB_4444_Config: - case kRGB_565_Config: { + case kARGB_4444_SkColorType: + case kRGB_565_SkColorType: { uint16_t* p = this->getAddr16(area.fLeft, area.fTop);; uint16_t v; - if (kARGB_4444_Config == fConfig) { + if (kARGB_4444_SkColorType == this->colorType()) { v = pack_8888_to_4444(a, r, g, b); } else { v = SkPackRGB16(r >> (8 - SK_R16_BITS), @@ -921,7 +867,9 @@ void SkBitmap::internalErase(const SkIRect& area, } break; } - case kARGB_8888_Config: { + case kPMColor_SkColorType: { + // what to do about BGRA or RGBA (which ever is != PMColor ? + // for now we don't support them. uint32_t* p = this->getAddr32(area.fLeft, area.fTop); uint32_t v = SkPackARGB32(a, r, g, b); @@ -931,6 +879,8 @@ void SkBitmap::internalErase(const SkIRect& area, } break; } + default: + return; // no change, so don't call notifyPixelsChanged() } this->notifyPixelsChanged(); @@ -1046,7 +996,8 @@ bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const { if (fPixelRef) { SkIRect subset; - subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY, fWidth, fHeight); + subset.setXYWH(fPixelRefOrigin.fX, fPixelRefOrigin.fY, + fInfo.width(), fInfo.height()); if (fPixelRef->readPixels(&tmpSrc, &subset)) { SkASSERT(tmpSrc.width() == this->width()); SkASSERT(tmpSrc.height() == this->height()); @@ -1160,6 +1111,8 @@ bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const { } bool SkBitmap::deepCopyTo(SkBitmap* dst, Config dstConfig) const { + const SkColorType dstCT = SkBitmapConfigToColorType(dstConfig); + if (!this->canCopyTo(dstConfig)) { return false; } @@ -1170,7 +1123,7 @@ bool SkBitmap::deepCopyTo(SkBitmap* dst, Config dstConfig) const { SkPixelRef* pixelRef = fPixelRef->deepCopy(dstConfig); if (pixelRef) { uint32_t rowBytes; - if (dstConfig == fConfig) { + if (this->colorType() == dstCT) { // Since there is no subset to pass to deepCopy, and deepCopy // succeeded, the new pixel ref must be identical. SkASSERT(fPixelRef->info() == pixelRef->info()); @@ -1181,7 +1134,12 @@ bool SkBitmap::deepCopyTo(SkBitmap* dst, Config dstConfig) const { // With the new config, an appropriate fRowBytes will be computed by setConfig. rowBytes = 0; } - dst->setConfig(dstConfig, fWidth, fHeight, rowBytes); + + SkImageInfo info = fInfo; + info.fColorType = dstCT; + if (!dst->setConfig(info, rowBytes)) { + return false; + } dst->setPixelRef(pixelRef, fPixelRefOrigin)->unref(); return true; } @@ -1584,11 +1542,8 @@ enum { }; void SkBitmap::flatten(SkWriteBuffer& buffer) const { - buffer.writeInt(fWidth); - buffer.writeInt(fHeight); + fInfo.flatten(buffer); buffer.writeInt(fRowBytes); - buffer.writeInt(fConfig); - buffer.writeInt(fAlphaType); if (fPixelRef) { if (fPixelRef->getFactory()) { @@ -1608,19 +1563,17 @@ void SkBitmap::flatten(SkWriteBuffer& buffer) const { void SkBitmap::unflatten(SkReadBuffer& buffer) { this->reset(); - int width = buffer.readInt(); - int height = buffer.readInt(); - int rowBytes = buffer.readInt(); - Config config = (Config)buffer.readInt(); - SkAlphaType alphaType = (SkAlphaType)buffer.readInt(); - buffer.validate((width >= 0) && (height >= 0) && (rowBytes >= 0) && - SkIsValidConfig(config) && validate_alphaType(config, alphaType)); + SkImageInfo info; + info.unflatten(buffer); + size_t rowBytes = buffer.readInt(); + buffer.validate((info.width() >= 0) && (info.height() >= 0) && + SkColorTypeIsValid(info.fColorType) && + SkAlphaTypeIsValid(info.fAlphaType) && + validate_alphaType(info.fColorType, info.fAlphaType) && + info.validRowBytes(rowBytes)); - bool configIsValid = this->setConfig(config, width, height, rowBytes, alphaType); - // Note : Using (fRowBytes >= (fWidth * fBytesPerPixel)) in the following test can create false - // positives if the multiplication causes an integer overflow. Use the division instead. - buffer.validate(configIsValid && (fBytesPerPixel > 0) && - ((fRowBytes / fBytesPerPixel) >= fWidth)); + bool configIsValid = this->setConfig(info, rowBytes); + buffer.validate(configIsValid); int reftype = buffer.readInt(); if (buffer.validate((SERIALIZE_PIXELTYPE_REF_DATA == reftype) || @@ -1630,7 +1583,7 @@ void SkBitmap::unflatten(SkReadBuffer& buffer) { SkIPoint origin; origin.fX = buffer.readInt(); origin.fY = buffer.readInt(); - size_t offset = origin.fY * rowBytes + origin.fX * fBytesPerPixel; + size_t offset = origin.fY * rowBytes + origin.fX * info.bytesPerPixel(); SkPixelRef* pr = buffer.readPixelRef(); if (!buffer.validate((NULL == pr) || (pr->getAllocatedSizeInBytes() >= (offset + this->getSafeSize())))) { @@ -1663,15 +1616,14 @@ SkBitmap::RLEPixels::~RLEPixels() { #ifdef SK_DEBUG void SkBitmap::validate() const { - SkASSERT(fConfig < kConfigCount); - SkASSERT(fRowBytes >= (unsigned)ComputeRowBytes((Config)fConfig, fWidth)); + fInfo.validate(); + SkASSERT(fInfo.validRowBytes(fRowBytes)); uint8_t allFlags = kImageIsOpaque_Flag | kImageIsVolatile_Flag | kImageIsImmutable_Flag; #ifdef SK_BUILD_FOR_ANDROID allFlags |= kHasHardwareMipMap_Flag; #endif SkASSERT(fFlags <= allFlags); SkASSERT(fPixelLockCount >= 0); - SkASSERT((uint8_t)ComputeBytesPerPixel((Config)fConfig) == fBytesPerPixel); if (fPixels) { SkASSERT(fPixelRef); @@ -1680,9 +1632,9 @@ void SkBitmap::validate() const { SkASSERT(fPixelRef->rowBytes() == fRowBytes); SkASSERT(fPixelRefOrigin.fX >= 0); SkASSERT(fPixelRefOrigin.fY >= 0); - SkASSERT(fPixelRef->info().fWidth >= (int)fWidth + fPixelRefOrigin.fX); - SkASSERT(fPixelRef->info().fHeight >= (int)fHeight + fPixelRefOrigin.fY); - SkASSERT(fPixelRef->rowBytes() >= fWidth * fBytesPerPixel); + SkASSERT(fPixelRef->info().width() >= (int)this->width() + fPixelRefOrigin.fX); + SkASSERT(fPixelRef->info().fHeight >= (int)this->height() + fPixelRefOrigin.fY); + SkASSERT(fPixelRef->rowBytes() >= fInfo.minRowBytes()); } else { SkASSERT(NULL == fColorTable); } @@ -1728,3 +1680,14 @@ void SkBitmap::toString(SkString* str) const { str->append(")"); } #endif + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_DEBUG +void SkImageInfo::validate() const { + SkASSERT(fWidth >= 0); + SkASSERT(fHeight >= 0); + SkASSERT(SkColorTypeIsValid(fColorType)); + SkASSERT(SkAlphaTypeIsValid(fAlphaType)); +} +#endif diff --git a/src/image/SkImagePriv.cpp b/src/image/SkImagePriv.cpp index 43cc44b..a044aad 100644 --- a/src/image/SkImagePriv.cpp +++ b/src/image/SkImagePriv.cpp @@ -37,35 +37,19 @@ SkBitmap::Config SkImageInfoToBitmapConfig(const SkImageInfo& info) { return SkColorTypeToBitmapConfig(info.fColorType); } -bool SkBitmapConfigToColorType(SkBitmap::Config config, SkColorType* ctOut) { - SkColorType ct; - switch (config) { - case SkBitmap::kA8_Config: - ct = kAlpha_8_SkColorType; - break; - case SkBitmap::kIndex8_Config: - ct = kIndex_8_SkColorType; - break; - case SkBitmap::kRGB_565_Config: - ct = kRGB_565_SkColorType; - break; - case SkBitmap::kARGB_4444_Config: - ct = kARGB_4444_SkColorType; - break; - case SkBitmap::kARGB_8888_Config: - ct = kPMColor_SkColorType; - break; - case SkBitmap::kNo_Config: - default: - return false; - } - if (ctOut) { - *ctOut = ct; - } - return true; +SkColorType SkBitmapConfigToColorType(SkBitmap::Config config) { + static const SkColorType gCT[] = { + kUnknown_SkColorType, // kNo_Config + kAlpha_8_SkColorType, // kA8_Config + kIndex_8_SkColorType, // kIndex8_Config + kRGB_565_SkColorType, // kRGB_565_Config + kARGB_4444_SkColorType, // kARGB_4444_Config + kPMColor_SkColorType, // kARGB_8888_Config + }; + SkASSERT((unsigned)config < SK_ARRAY_COUNT(gCT)); + return gCT[config]; } - SkImage* SkNewImageFromBitmap(const SkBitmap& bm, bool canSharePixelRef) { SkImageInfo info; if (!bm.asImageInfo(&info)) { diff --git a/src/image/SkImagePriv.h b/src/image/SkImagePriv.h index 7c19c73..8883e2c 100644 --- a/src/image/SkImagePriv.h +++ b/src/image/SkImagePriv.h @@ -15,7 +15,7 @@ class SkPicture; extern SkBitmap::Config SkImageInfoToBitmapConfig(const SkImageInfo&); extern SkBitmap::Config SkColorTypeToBitmapConfig(SkColorType); -extern bool SkBitmapConfigToColorType(SkBitmap::Config, SkColorType* ctOut); +extern SkColorType SkBitmapConfigToColorType(SkBitmap::Config); // Call this if you explicitly want to use/share this pixelRef in the image extern SkImage* SkNewImageFromPixelRef(const SkImageInfo&, SkPixelRef*, diff --git a/src/images/SkDecodingImageGenerator.cpp b/src/images/SkDecodingImageGenerator.cpp index 153d1e2..1e28136 100644 --- a/src/images/SkDecodingImageGenerator.cpp +++ b/src/images/SkDecodingImageGenerator.cpp @@ -275,11 +275,6 @@ SkImageGenerator* SkDecodingImageGenerator::Create( info.fHeight = bitmap.height(); info.fColorType = opts.fRequestedColorType; info.fAlphaType = bitmap.alphaType(); - - // Sanity check. - SkDEBUGCODE(SkColorType tmp;) - SkASSERT(SkBitmapConfigToColorType(config, &tmp)); - SkASSERT(tmp == opts.fRequestedColorType); } return SkNEW_ARGS(SkDecodingImageGenerator, (data, autoStream.detach(), info, diff --git a/tests/ImageDecodingTest.cpp b/tests/ImageDecodingTest.cpp index 81f9006..2e0225a 100644 --- a/tests/ImageDecodingTest.cpp +++ b/tests/ImageDecodingTest.cpp @@ -333,10 +333,7 @@ static SkPixelRef* install_pixel_ref(SkBitmap* bitmap, SkASSERT(stream != NULL); SkASSERT(stream->rewind()); SkASSERT(stream->unique()); - SkColorType colorType; - if (!SkBitmapConfigToColorType(bitmap->config(), &colorType)) { - return NULL; - } + SkColorType colorType = bitmap->colorType(); SkDecodingImageGenerator::Options opts(sampleSize, ditherImage, colorType); SkAutoTDelete gen( SkDecodingImageGenerator::Create(stream, opts)); diff --git a/tests/PixelRefTest.cpp b/tests/PixelRefTest.cpp index c0bdf54..aeb3070 100644 --- a/tests/PixelRefTest.cpp +++ b/tests/PixelRefTest.cpp @@ -30,7 +30,7 @@ static void test_info(skiatest::Reporter* reporter) { REPORTER_ASSERT(reporter, success); success = bitmap.asImageInfo(&info); REPORTER_ASSERT(reporter, success == gRec[i].fExpectedSuccess); - if (gRec[i].fExpectedSuccess) { + if (success && gRec[i].fExpectedSuccess) { REPORTER_ASSERT(reporter, info.fAlphaType == gRec[i].fAlphaType); REPORTER_ASSERT(reporter, info.fColorType == gRec[i].fExpectedColorType); } -- 2.7.4