Index: src/core/SkBitmapConfig.cpp |
diff --git a/src/core/SkBitmapConfig.cpp b/src/core/SkBitmapConfig.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f3ff9240a7ca38ac440cf3799194152e9304f57c |
--- /dev/null |
+++ b/src/core/SkBitmapConfig.cpp |
@@ -0,0 +1,273 @@ |
+/* |
+ * Copyright 2014 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "SkBitmap.h" |
+#include "SkCanvas.h" |
+#include "SkColorPriv.h" |
+#include "SkDither.h" |
+#include "SkImagePriv.h" |
+#include "SkPixelRef.h" |
+ |
+#ifdef SK_SUPPORT_LEGACY_BITMAP_COMPUTESIZE |
+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; |
+} |
+ |
+int64_t SkBitmap::ComputeSafeSize64(Config config, |
+ uint32_t width, |
+ uint32_t height, |
+ size_t rowBytes) { |
+ SkImageInfo info = SkImageInfo::Make(width, height, |
+ SkBitmapConfigToColorType(config), |
+ kPremul_SkAlphaType); |
+ return info.getSafeSize64(rowBytes); |
+} |
+ |
+size_t SkBitmap::ComputeSafeSize(Config config, |
+ uint32_t width, |
+ uint32_t height, |
+ size_t rowBytes) { |
+ int64_t safeSize = ComputeSafeSize64(config, width, height, rowBytes); |
+ int32_t safeSize32 = (int32_t)safeSize; |
+ |
+ if (safeSize32 != safeSize) { |
+ safeSize32 = 0; |
+ } |
+ return safeSize32; |
+} |
+#endif |
+ |
+#ifdef SK_SUPPORT_LEGACY_BITMAPCONFIG |
+ |
+SkBitmap::Config SkBitmap::config() const { |
+ return SkColorTypeToBitmapConfig(fInfo.colorType()); |
+} |
+ |
+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::allocConfigPixels(Config config, int width, int height, |
+ bool isOpaque) { |
+ SkColorType ct = SkBitmapConfigToColorType(config); |
+ SkAlphaType at = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; |
+ return this->allocPixels(SkImageInfo::Make(width, height, ct, at)); |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+bool SkBitmap::canCopyTo(Config dstConfig) const { |
+ return this->canCopyTo(SkBitmapConfigToColorType(dstConfig)); |
+} |
+ |
+bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const { |
+ if (!this->canCopyTo(dstConfig)) { |
+ return false; |
+ } |
+ |
+ // if we have a texture, first get those pixels |
+ SkBitmap tmpSrc; |
+ const SkBitmap* src = this; |
+ |
+ if (fPixelRef) { |
+ SkIRect subset; |
+ 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()); |
+ |
+ // did we get lucky and we can just return tmpSrc? |
+ if (tmpSrc.config() == dstConfig && NULL == alloc) { |
+ dst->swap(tmpSrc); |
+ // If the result is an exact copy, clone the gen ID. |
+ if (dst->pixelRef() && dst->pixelRef()->info() == fPixelRef->info()) { |
+ dst->pixelRef()->cloneGenID(*fPixelRef); |
+ } |
+ return true; |
+ } |
+ |
+ // fall through to the raster case |
+ src = &tmpSrc; |
+ } |
+ } |
+ |
+ // we lock this now, since we may need its colortable |
+ SkAutoLockPixels srclock(*src); |
+ if (!src->readyToDraw()) { |
+ return false; |
+ } |
+ |
+ // The only way to be readyToDraw is if fPixelRef is non NULL. |
+ SkASSERT(fPixelRef != NULL); |
+ |
+ SkBitmap tmpDst; |
+ tmpDst.setConfig(dstConfig, src->width(), src->height(), 0, |
+ src->alphaType()); |
+ |
+ // allocate colortable if srcConfig == kIndex8_Config |
+ SkColorTable* ctable = (dstConfig == kIndex8_Config) ? |
+ new SkColorTable(*src->getColorTable()) : NULL; |
+ SkAutoUnref au(ctable); |
+ if (!tmpDst.allocPixels(alloc, ctable)) { |
+ return false; |
+ } |
+ |
+ if (!tmpDst.readyToDraw()) { |
+ // allocator/lock failed |
+ return false; |
+ } |
+ |
+ // pixelRef must be non NULL or tmpDst.readyToDraw() would have |
+ // returned false. |
+ SkASSERT(tmpDst.pixelRef() != NULL); |
+ |
+ /* do memcpy for the same configs cases, else use drawing |
+ */ |
+ if (src->config() == dstConfig) { |
+ if (tmpDst.getSize() == src->getSize()) { |
+ memcpy(tmpDst.getPixels(), src->getPixels(), src->getSafeSize()); |
+ SkPixelRef* pixelRef = tmpDst.pixelRef(); |
+ |
+ // In order to reach this point, we know that the width, config and |
+ // rowbytes of the SkPixelRefs are the same, but it is possible for |
+ // the heights to differ, if this SkBitmap's height is a subset of |
+ // fPixelRef. Only if the SkPixelRefs' heights match are we |
+ // guaranteed that this is an exact copy, meaning we should clone |
+ // the genID. |
+ if (pixelRef->info().fHeight == fPixelRef->info().fHeight) { |
+ // TODO: what to do if the two infos match, BUT |
+ // fPixelRef is premul and pixelRef is opaque? |
+ // skipping assert for now |
+ // https://code.google.com/p/skia/issues/detail?id=2012 |
+ // SkASSERT(pixelRef->info() == fPixelRef->info()); |
+ SkASSERT(pixelRef->info().fWidth == fPixelRef->info().fWidth); |
+ SkASSERT(pixelRef->info().fColorType == fPixelRef->info().fColorType); |
+ pixelRef->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 (SkBitmap::kARGB_4444_Config == dstConfig |
+ && SkBitmap::kARGB_8888_Config == src->config()) { |
+ 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 { |
+ // 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); |
+ return true; |
+} |
+ |
+bool SkBitmap::deepCopyTo(SkBitmap* dst, Config dstConfig) const { |
+ const SkColorType dstCT = SkBitmapConfigToColorType(dstConfig); |
+ |
+ if (!this->canCopyTo(dstConfig)) { |
+ return false; |
+ } |
+ |
+ // If we have a PixelRef, and it supports deep copy, use it. |
+ // Currently supported only by texture-backed bitmaps. |
+ if (fPixelRef) { |
+ SkPixelRef* pixelRef = fPixelRef->deepCopy(dstConfig); |
+ if (pixelRef) { |
+ uint32_t rowBytes; |
+ 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()); |
+ pixelRef->cloneGenID(*fPixelRef); |
+ // Use the same rowBytes as the original. |
+ rowBytes = fRowBytes; |
+ } else { |
+ // With the new config, an appropriate fRowBytes will be computed by setConfig. |
+ rowBytes = 0; |
+ } |
+ |
+ SkImageInfo info = fInfo; |
+ info.fColorType = dstCT; |
+ if (!dst->setConfig(info, rowBytes)) { |
+ return false; |
+ } |
+ dst->setPixelRef(pixelRef, fPixelRefOrigin)->unref(); |
+ return true; |
+ } |
+ } |
+ |
+ if (this->getTexture()) { |
+ return false; |
+ } else { |
+ return this->copyTo(dst, dstConfig, NULL); |
+ } |
+} |
+ |
+#endif |