}
#endif
-#ifdef SK_SUPPORT_LEGACY_COMPUTE_CONFIG_SIZE
-int SkBitmap::ComputeBytesPerPixel(SkBitmap::Config config) {
- int bpp;
- switch (config) {
- case kNo_Config:
- bpp = 0; // not applicable
- break;
- case kA8_Config:
- case kIndex8_Config:
- bpp = 1;
- break;
- case kRGB_565_Config:
- case kARGB_4444_Config:
- bpp = 2;
- break;
- case kARGB_8888_Config:
- bpp = 4;
- break;
- default:
- SkDEBUGFAIL("unknown config");
- bpp = 0; // error
- break;
- }
- return bpp;
-}
-
-size_t SkBitmap::ComputeRowBytes(Config c, int width) {
- return SkColorTypeMinRowBytes(SkBitmapConfigToColorType(c), width);
-}
-
-int64_t SkBitmap::ComputeSize64(Config config, int width, int height) {
- SkColorType ct = SkBitmapConfigToColorType(config);
- int64_t rowBytes = sk_64_mul(SkColorTypeBytesPerPixel(ct), width);
- return rowBytes * height;
-}
-
-size_t SkBitmap::ComputeSize(Config c, int width, int height) {
- int64_t size = SkBitmap::ComputeSize64(c, width, height);
- return sk_64_isS32(size) ? sk_64_asS32(size) : 0;
-}
-#endif
-
void SkBitmap::getBounds(SkRect* bounds) const {
SkASSERT(bounds);
bounds->set(0, 0,
///////////////////////////////////////////////////////////////////////////////
-static bool validate_alphaType(SkColorType colorType, SkAlphaType alphaType,
- SkAlphaType* canonical = NULL) {
- switch (colorType) {
- case kUnknown_SkColorType:
- alphaType = kIgnore_SkAlphaType;
- break;
- case kAlpha_8_SkColorType:
- if (kUnpremul_SkAlphaType == alphaType) {
- alphaType = kPremul_SkAlphaType;
- }
- // fall-through
- case kIndex_8_SkColorType:
- case kARGB_4444_SkColorType:
- case kRGBA_8888_SkColorType:
- case kBGRA_8888_SkColorType:
- if (kIgnore_SkAlphaType == alphaType) {
- return false;
- }
- break;
- case kRGB_565_SkColorType:
- alphaType = kOpaque_SkAlphaType;
- break;
- default:
- return false;
- }
- if (canonical) {
- *canonical = alphaType;
- }
- return true;
-}
-
bool SkBitmap::setInfo(const SkImageInfo& origInfo, size_t rowBytes) {
SkImageInfo info = origInfo;
- if (!validate_alphaType(info.fColorType, info.fAlphaType,
- &info.fAlphaType)) {
+ if (!SkColorTypeValidateAlphaType(info.fColorType, info.fAlphaType,
+ &info.fAlphaType)) {
return reset_return_false(this);
}
rowBytes = 0;
} else if (0 == rowBytes) {
rowBytes = (size_t)mrb;
- } else if (rowBytes < info.minRowBytes()) {
+ } else if (!info.validRowBytes(rowBytes)) {
return reset_return_false(this);
}
return true;
}
-#ifdef SK_SUPPORT_LEGACY_SETCONFIG
-bool SkBitmap::setConfig(Config config, int width, int height, size_t rowBytes,
- SkAlphaType alphaType) {
- SkColorType ct = SkBitmapConfigToColorType(config);
- return this->setInfo(SkImageInfo::Make(width, height, ct, alphaType), rowBytes);
-}
-#endif
-
bool SkBitmap::setAlphaType(SkAlphaType alphaType) {
- if (!validate_alphaType(fInfo.fColorType, alphaType, &alphaType)) {
+ if (!SkColorTypeValidateAlphaType(fInfo.fColorType, alphaType, &alphaType)) {
return false;
}
if (fInfo.fAlphaType != alphaType) {
///////////////////////////////////////////////////////////////////////////////
+bool SkBitmap::allocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
+ if (kIndex_8_SkColorType == requestedInfo.colorType()) {
+ return reset_return_false(this);
+ }
+ if (!this->setInfo(requestedInfo, rowBytes)) {
+ return reset_return_false(this);
+ }
+
+ // setInfo may have corrected info (e.g. 565 is always opaque).
+ const SkImageInfo& correctedInfo = this->info();
+ // setInfo may have computed a valid rowbytes if 0 were passed in
+ rowBytes = this->rowBytes();
+
+ SkMallocPixelRef::PRFactory defaultFactory;
+
+ SkPixelRef* pr = defaultFactory.create(correctedInfo, rowBytes, NULL);
+ if (NULL == pr) {
+ return reset_return_false(this);
+ }
+ this->setPixelRef(pr)->unref();
+
+ // TODO: lockPixels could/should return bool or void*/NULL
+ this->lockPixels();
+ if (NULL == this->getPixels()) {
+ return reset_return_false(this);
+ }
+ return true;
+}
+
bool SkBitmap::allocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactory* factory,
SkColorTable* ctable) {
if (kIndex_8_SkColorType == requestedInfo.fColorType && NULL == ctable) {
factory = &defaultFactory;
}
- SkPixelRef* pr = factory->create(correctedInfo, ctable);
+ SkPixelRef* pr = factory->create(correctedInfo, correctedInfo.minRowBytes(), ctable);
if (NULL == pr) {
return reset_return_false(this);
}
///////////////////////////////////////////////////////////////////////////////
bool SkBitmap::isImmutable() const {
- return fPixelRef ? fPixelRef->isImmutable() :
- fFlags & kImageIsImmutable_Flag;
+ return fPixelRef ? fPixelRef->isImmutable() : false;
}
void SkBitmap::setImmutable() {
if (fPixelRef) {
fPixelRef->setImmutable();
- } else {
- fFlags |= kImageIsImmutable_Flag;
}
}
#include "SkPaint.h"
bool SkBitmap::canCopyTo(SkColorType dstColorType) const {
- if (this->colorType() == kUnknown_SkColorType) {
+ const SkColorType srcCT = this->colorType();
+
+ if (srcCT == kUnknown_SkColorType) {
return false;
}
- bool sameConfigs = (this->colorType() == dstColorType);
+ bool sameConfigs = (srcCT == dstColorType);
switch (dstColorType) {
case kAlpha_8_SkColorType:
case kRGB_565_SkColorType:
}
break;
case kARGB_4444_SkColorType:
- return sameConfigs || kN32_SkColorType == this->colorType();
+ return sameConfigs || kN32_SkColorType == srcCT || kIndex_8_SkColorType == srcCT;
default:
return false;
}
return true;
}
-bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType,
- Allocator* alloc) const {
+#include "SkConfig8888.h"
+
+bool SkBitmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB,
+ int x, int y) const {
+ if (kUnknown_SkColorType == requestedDstInfo.colorType()) {
+ return false;
+ }
+ if (NULL == dstPixels || dstRB < requestedDstInfo.minRowBytes()) {
+ return false;
+ }
+ if (0 == requestedDstInfo.width() || 0 == requestedDstInfo.height()) {
+ return false;
+ }
+
+ SkIRect srcR = SkIRect::MakeXYWH(x, y, requestedDstInfo.width(), requestedDstInfo.height());
+ if (!srcR.intersect(0, 0, this->width(), this->height())) {
+ return false;
+ }
+
+ SkImageInfo dstInfo = requestedDstInfo;
+ // the intersect may have shrunk info's logical size
+ dstInfo.fWidth = srcR.width();
+ dstInfo.fHeight = srcR.height();
+
+ // if x or y are negative, then we have to adjust pixels
+ if (x > 0) {
+ x = 0;
+ }
+ if (y > 0) {
+ y = 0;
+ }
+ // here x,y are either 0 or negative
+ dstPixels = ((char*)dstPixels - y * dstRB - x * dstInfo.bytesPerPixel());
+
+ //////////////
+
+ SkAutoLockPixels alp(*this);
+
+ // since we don't stop creating un-pixeled devices yet, check for no pixels here
+ if (NULL == this->getPixels()) {
+ return false;
+ }
+
+ SkImageInfo srcInfo = this->info();
+ srcInfo.fWidth = dstInfo.width();
+ srcInfo.fHeight = dstInfo.height();
+
+ const void* srcPixels = this->getAddr(srcR.x(), srcR.y());
+ return SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, this->rowBytes(),
+ this->getColorTable());
+}
+
+bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) const {
if (!this->canCopyTo(dstColorType)) {
return false;
}
// returned false.
SkASSERT(tmpDst.pixelRef() != NULL);
- /* do memcpy for the same configs cases, else use drawing
- */
- if (src->colorType() == dstColorType) {
- if (tmpDst.getSize() == src->getSize()) {
- memcpy(tmpDst.getPixels(), src->getPixels(), src->getSafeSize());
+ if (!src->readPixels(tmpDst.info(), tmpDst.getPixels(), tmpDst.rowBytes(), 0, 0)) {
+ return false;
+ }
- SkPixelRef* dstPixelRef = tmpDst.pixelRef();
- if (dstPixelRef->info() == fPixelRef->info()) {
- dstPixelRef->cloneGenID(*fPixelRef);
- }
- } else {
- const char* srcP = reinterpret_cast<const char*>(src->getPixels());
- char* dstP = reinterpret_cast<char*>(tmpDst.getPixels());
- // to be sure we don't read too much, only copy our logical pixels
- size_t bytesToCopy = tmpDst.width() * tmpDst.bytesPerPixel();
- for (int y = 0; y < tmpDst.height(); y++) {
- memcpy(dstP, srcP, bytesToCopy);
- srcP += src->rowBytes();
- dstP += tmpDst.rowBytes();
- }
- }
- } else if (kARGB_4444_SkColorType == dstColorType
- && kN32_SkColorType == src->colorType()) {
- if (src->alphaType() == kUnpremul_SkAlphaType) {
- // Our method for converting to 4444 assumes premultiplied.
- return false;
+ // (for BitmapHeap) Clone the pixelref genID even though we have a new pixelref.
+ // The old copyTo impl did this, so we continue it for now.
+ //
+ // TODO: should we ignore rowbytes (i.e. getSize)? Then it could just be
+ // if (src_pixelref->info == dst_pixelref->info)
+ //
+ if (src->colorType() == dstColorType && tmpDst.getSize() == src->getSize()) {
+ SkPixelRef* dstPixelRef = tmpDst.pixelRef();
+ if (dstPixelRef->info() == fPixelRef->info()) {
+ dstPixelRef->cloneGenID(*fPixelRef);
}
- SkASSERT(src->height() == tmpDst.height());
- SkASSERT(src->width() == tmpDst.width());
- for (int y = 0; y < src->height(); ++y) {
- SkPMColor16* SK_RESTRICT dstRow = (SkPMColor16*) tmpDst.getAddr16(0, y);
- SkPMColor* SK_RESTRICT srcRow = (SkPMColor*) src->getAddr32(0, y);
- DITHER_4444_SCAN(y);
- for (int x = 0; x < src->width(); ++x) {
- dstRow[x] = SkDitherARGB32To4444(srcRow[x],
- DITHER_VALUE(x));
- }
- }
- } else {
- if (tmpDst.alphaType() == kUnpremul_SkAlphaType) {
- // We do not support drawing to unpremultiplied bitmaps.
- return false;
- }
-
- // Always clear the dest in case one of the blitters accesses it
- // TODO: switch the allocation of tmpDst to call sk_calloc_throw
- tmpDst.eraseColor(SK_ColorTRANSPARENT);
-
- SkCanvas canvas(tmpDst);
- SkPaint paint;
-
- paint.setDither(true);
- canvas.drawBitmap(*src, 0, 0, &paint);
}
dst->swap(tmpDst);
SkImageInfo info;
info.unflatten(*buffer);
+ // If there was an error reading "info", don't use it to compute minRowBytes()
+ if (!buffer->validate(true)) {
+ return false;
+ }
+
const size_t ramRB = info.minRowBytes();
const int height = info.height();
const size_t snugSize = snugRB * height;
};
void SkBitmap::legacyUnflatten(SkReadBuffer& buffer) {
+#ifdef SK_SUPPORT_LEGACY_PIXELREF_UNFLATTENABLE
this->reset();
SkImageInfo info;
if (!buffer.validate((info.width() >= 0) && (info.height() >= 0) &&
SkColorTypeIsValid(info.fColorType) &&
SkAlphaTypeIsValid(info.fAlphaType) &&
- validate_alphaType(info.fColorType, info.fAlphaType) &&
+ SkColorTypeValidateAlphaType(info.fColorType, info.fAlphaType) &&
info.validRowBytes(rowBytes))) {
return;
}
origin.fX = buffer.readInt();
origin.fY = buffer.readInt();
size_t offset = origin.fY * rowBytes + origin.fX * info.bytesPerPixel();
- SkPixelRef* pr = buffer.readPixelRef();
+ SkPixelRef* pr = buffer.readFlattenable<SkPixelRef>();
if (!buffer.validate((NULL == pr) ||
(pr->getAllocatedSizeInBytes() >= (offset + this->getSafeSize())))) {
origin.setZero();
sk_throw();
}
}
+#else
+ sk_throw();
+#endif
}
///////////////////////////////////////////////////////////////////////////////
}
SkASSERT(fInfo.validRowBytes(fRowBytes));
- uint8_t allFlags = kImageIsOpaque_Flag | kImageIsVolatile_Flag | kImageIsImmutable_Flag;
+ uint8_t allFlags = kImageIsVolatile_Flag;
#ifdef SK_BUILD_FOR_ANDROID
allFlags |= kHasHardwareMipMap_Flag;
#endif
- SkASSERT(fFlags <= allFlags);
+ SkASSERT((~allFlags & fFlags) == 0);
SkASSERT(fPixelLockCount >= 0);
if (fPixels) {