| 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
|
|
|