add new copyTo version to SkBitmap, which takes SkColorType

BUG=skia:
R=scroggo@google.com, halcanary@google.com, bsalomon@google.com

Author: reed@google.com

Review URL: https://codereview.chromium.org/171723007

git-svn-id: http://skia.googlecode.com/svn/trunk@13553 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 520ccd3..32cb7b2 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -982,32 +982,43 @@
 #include "SkCanvas.h"
 #include "SkPaint.h"
 
-bool SkBitmap::canCopyTo(Config dstConfig) const {
-    if (this->config() == kNo_Config) {
+#ifdef SK_SUPPORT_LEGACY_COPYTO_CONFIG
+bool SkBitmap::copyTo(SkBitmap* dst, Config c, Allocator* allocator) const {
+    return this->copyTo(dst, SkBitmapConfigToSkColorType(c), allocator);
+}
+
+bool SkBitmap::canCopyTo(Config newConfig) const {
+    return this->canCopyTo(SkBitmapConfigToSkColorType(c));
+}
+#endif
+
+bool SkBitmap::canCopyTo(SkColorType dstColorType) const {
+    if (this->colorType() == kUnknown_SkColorType) {
         return false;
     }
 
-    bool sameConfigs = (this->config() == dstConfig);
-    switch (dstConfig) {
-        case kA8_Config:
-        case kRGB_565_Config:
-        case kARGB_8888_Config:
+    bool sameConfigs = (this->colorType() == dstColorType);
+    switch (dstColorType) {
+        case kAlpha_8_SkColorType:
+        case kRGB_565_SkColorType:
+        case kPMColor_SkColorType:
             break;
-        case kIndex8_Config:
+        case kIndex_8_SkColorType:
             if (!sameConfigs) {
                 return false;
             }
             break;
-        case kARGB_4444_Config:
-            return sameConfigs || kARGB_8888_Config == this->config();
+        case kARGB_4444_SkColorType:
+            return sameConfigs || kPMColor_SkColorType == this->colorType();
         default:
             return false;
     }
     return true;
 }
 
-bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const {
-    if (!this->canCopyTo(dstConfig)) {
+bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType,
+                      Allocator* alloc) const {
+    if (!this->canCopyTo(dstColorType)) {
         return false;
     }
 
@@ -1024,7 +1035,7 @@
             SkASSERT(tmpSrc.height() == this->height());
 
             // did we get lucky and we can just return tmpSrc?
-            if (tmpSrc.config() == dstConfig && NULL == alloc) {
+            if (tmpSrc.colorType() == dstColorType && NULL == alloc) {
                 dst->swap(tmpSrc);
                 // If the result is an exact copy, clone the gen ID.
                 if (dst->pixelRef() && dst->pixelRef()->info() == fPixelRef->info()) {
@@ -1047,14 +1058,20 @@
     // The only way to be readyToDraw is if fPixelRef is non NULL.
     SkASSERT(fPixelRef != NULL);
 
+    SkImageInfo dstInfo = src->info();
+    dstInfo.fColorType = dstColorType;
+
     SkBitmap tmpDst;
-    tmpDst.setConfig(dstConfig, src->width(), src->height(), 0,
-                     src->alphaType());
+    if (!tmpDst.setConfig(dstInfo)) {
+        return false;
+    }
 
     // allocate colortable if srcConfig == kIndex8_Config
-    SkColorTable* ctable = (dstConfig == kIndex8_Config) ?
-    new SkColorTable(*src->getColorTable()) : NULL;
-    SkAutoUnref au(ctable);
+    SkAutoTUnref<SkColorTable> ctable;
+    if (dstColorType == kIndex_8_SkColorType) {
+        // TODO: can we just ref() the src colortable? Is it reentrant-safe?
+        ctable.reset(SkNEW_ARGS(SkColorTable, (*src->getColorTable())));
+    }
     if (!tmpDst.allocPixels(alloc, ctable)) {
         return false;
     }
@@ -1070,7 +1087,7 @@
 
     /* do memcpy for the same configs cases, else use drawing
     */
-    if (src->config() == dstConfig) {
+    if (src->colorType() == dstColorType) {
         if (tmpDst.getSize() == src->getSize()) {
             memcpy(tmpDst.getPixels(), src->getPixels(), src->getSafeSize());
             SkPixelRef* pixelRef = tmpDst.pixelRef();
@@ -1102,8 +1119,8 @@
                 dstP += tmpDst.rowBytes();
             }
         }
-    } else if (SkBitmap::kARGB_4444_Config == dstConfig
-               && SkBitmap::kARGB_8888_Config == src->config()) {
+    } else if (kARGB_4444_SkColorType == dstColorType
+               && kPMColor_SkColorType == src->colorType()) {
         SkASSERT(src->height() == tmpDst.height());
         SkASSERT(src->width() == tmpDst.width());
         for (int y = 0; y < src->height(); ++y) {
@@ -1134,7 +1151,7 @@
 bool SkBitmap::deepCopyTo(SkBitmap* dst, Config dstConfig) const {
     const SkColorType dstCT = SkBitmapConfigToColorType(dstConfig);
 
-    if (!this->canCopyTo(dstConfig)) {
+    if (!this->canCopyTo(dstCT)) {
         return false;
     }
 
@@ -1169,7 +1186,7 @@
     if (this->getTexture()) {
         return false;
     } else {
-        return this->copyTo(dst, dstConfig, NULL);
+        return this->copyTo(dst, dstCT, NULL);
     }
 }
 
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 07ae3df..7ed8058 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -189,9 +189,9 @@
     if (!src.extractSubset(&subset, srcRect)) {
         return false;
     }
-    if (SkBitmap::kARGB_8888_Config != subset.config()) {
+    if (kPMColor_SkColorType != subset.colorType()) {
         // It'd be preferable to do this directly to bitmap.
-        subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
+        subset.copyTo(&subset, kPMColor_SkColorType);
     }
     SkAutoLockPixels alp(bitmap);
     uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
index f946f87..4d23658 100644
--- a/src/effects/SkBlurImageFilter.cpp
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -178,7 +178,7 @@
     }
 
     if (kernelSizeX == 0 && kernelSizeY == 0) {
-        src.copyTo(dst, dst->config());
+        src.copyTo(dst, dst->colorType());
         offset->fX = srcBounds.fLeft;
         offset->fY = srcBounds.fTop;
         return true;
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index c053e8b..94e4c8c 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -155,7 +155,7 @@
                 return result;
             }
         } else {
-            origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config);
+            origBitmap.copyTo(&tmpBitmap, kPMColor_SkColorType);
             // now bitmap points to our temp, which has been promoted to 32bits
             bitmap = &tmpBitmap;
             desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap->config());
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 0d8ddaa..475f50e 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -59,7 +59,7 @@
 }
 
 bool SkImage_Gpu::getROPixels(SkBitmap* dst) const {
-    return fBitmap.copyTo(dst, SkBitmap::kARGB_8888_Config);
+    return fBitmap.copyTo(dst, kPMColor_SkColorType);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index 504943e..abf6dc8 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -127,7 +127,7 @@
         if (!fBitmap.extractSubset(&src, subset)) {
             return false;
         }
-        return src.copyTo(dst, src.config());
+        return src.copyTo(dst, src.colorType());
     }
 }
 
diff --git a/src/images/SkDecodingImageGenerator.cpp b/src/images/SkDecodingImageGenerator.cpp
index 1e28136..7e3bb9b 100644
--- a/src/images/SkDecodingImageGenerator.cpp
+++ b/src/images/SkDecodingImageGenerator.cpp
@@ -14,60 +14,50 @@
 #include "SkStream.h"
 #include "SkUtils.h"
 
+static bool equal_modulo_alpha(const SkImageInfo& a, const SkImageInfo& b) {
+    return a.width() == b.width() && a.height() == b.height() &&
+           a.colorType() == b.colorType();
+}
+
 namespace {
 /**
  *  Special allocator used by getPixels(). Uses preallocated memory
- *  provided.
+ *  provided if possible, else fall-back on the default allocator
  */
 class TargetAllocator : public SkBitmap::Allocator {
 public:
-    TargetAllocator(void* target,
-                    size_t rowBytes,
-                    int width,
-                    int height,
-                    SkBitmap::Config config)
-        : fTarget(target)
+    TargetAllocator(const SkImageInfo& info,
+                    void* target,
+                    size_t rowBytes)
+        : fInfo(info)
+        , fTarget(target)
         , fRowBytes(rowBytes)
-        , fWidth(width)
-        , fHeight(height)
-        , fConfig(config) { }
+    {}
 
     bool isReady() { return (fTarget != NULL); }
 
     virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) {
-        if ((NULL == fTarget)
-            || (fConfig != bm->config())
-            || (fWidth != bm->width())
-            || (fHeight != bm->height())
-            || (ct != NULL)) {
+        if (NULL == fTarget || !equal_modulo_alpha(fInfo, bm->info())) {
             // Call default allocator.
             return bm->allocPixels(NULL, ct);
         }
-        // make sure fRowBytes is correct.
-        bm->setConfig(fConfig, fWidth, fHeight, fRowBytes, bm->alphaType());
+        
         // TODO(halcanary): verify that all callers of this function
         // will respect new RowBytes.  Will be moot once rowbytes belongs
         // to PixelRef.
-        bm->setPixels(fTarget, NULL);
+        bm->installPixels(fInfo, fTarget, fRowBytes, NULL, NULL);
+
         fTarget = NULL;  // never alloc same pixels twice!
         return true;
     }
 
 private:
+    const SkImageInfo fInfo;
     void* fTarget;  // Block of memory to be supplied as pixel memory
                     // in allocPixelRef.  Must be large enough to hold
-                    // a bitmap described by fWidth, fHeight, and
-                    // fRowBytes.
-    size_t fRowBytes;  // rowbytes for the destination bitmap
-    int fWidth;   // Along with fHeight and fConfig, the information
-    int fHeight;  // about the bitmap whose pixels this allocator is
-                  // expected to allocate. If they do not match the
-                  // bitmap passed to allocPixelRef, it is assumed
-                  // that the bitmap will be copied to a bitmap with
-                  // the correct info using this allocator, so the
-                  // default allocator will be used instead of
-                  // fTarget.
-    SkBitmap::Config fConfig;
+                    // a bitmap described by fInfo and fRowBytes
+    const size_t fRowBytes;  // rowbytes for the destination bitmap
+
     typedef SkBitmap::Allocator INHERITED;
 };
 
@@ -94,14 +84,13 @@
         SkStreamRewindable* stream,
         const SkImageInfo& info,
         int sampleSize,
-        bool ditherImage,
-        SkBitmap::Config requestedConfig)
+        bool ditherImage)
     : fData(data)
     , fStream(stream)
     , fInfo(info)
     , fSampleSize(sampleSize)
     , fDitherImage(ditherImage)
-    , fRequestedConfig(requestedConfig) {
+{
     SkASSERT(stream != NULL);
     SkSafeRef(fData);  // may be NULL.
 }
@@ -151,8 +140,7 @@
         // to change the settings.
         return false;
     }
-    int bpp = SkBitmap::ComputeBytesPerPixel(fRequestedConfig);
-    if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) {
+    if (info.minRowBytes() > rowBytes) {
         // The caller has specified a bad rowBytes.
         return false;
     }
@@ -166,10 +154,11 @@
     decoder->setSampleSize(fSampleSize);
 
     SkBitmap bitmap;
-    TargetAllocator allocator(pixels, rowBytes, info.fWidth,
-                              info.fHeight, fRequestedConfig);
+    TargetAllocator allocator(fInfo, pixels, rowBytes);
     decoder->setAllocator(&allocator);
-    bool success = decoder->decode(fStream, &bitmap, fRequestedConfig,
+    // TODO: need to be able to pass colortype directly to decoder
+    SkBitmap::Config legacyConfig = SkColorTypeToBitmapConfig(info.colorType());
+    bool success = decoder->decode(fStream, &bitmap, legacyConfig,
                                    SkImageDecoder::kDecodePixels_Mode);
     decoder->setAllocator(NULL);
     if (!success) {
@@ -177,16 +166,16 @@
     }
     if (allocator.isReady()) {  // Did not use pixels!
         SkBitmap bm;
-        SkASSERT(bitmap.canCopyTo(fRequestedConfig));
-        if (!bitmap.copyTo(&bm, fRequestedConfig, &allocator)
-            || allocator.isReady()) {
+        SkASSERT(bitmap.canCopyTo(info.colorType()));
+        bool copySuccess = bitmap.copyTo(&bm, info.colorType(), &allocator);
+        if (!copySuccess || allocator.isReady()) {
             SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed.");
             // Earlier we checked canCopyto(); we expect consistency.
             return false;
         }
-        SkASSERT(check_alpha(fInfo.fAlphaType, bm.alphaType()));
+        SkASSERT(check_alpha(info.alphaType(), bm.alphaType()));
     } else {
-        SkASSERT(check_alpha(fInfo.fAlphaType, bitmap.alphaType()));
+        SkASSERT(check_alpha(info.alphaType(), bitmap.alphaType()));
     }
     return true;
 }
@@ -245,38 +234,23 @@
         return NULL;
     }
 
-    SkImageInfo info;
-    SkBitmap::Config config;
+    SkImageInfo info = bitmap.info();
 
     if (!opts.fUseRequestedColorType) {
-        // Use default config.
-        if (SkBitmap::kIndex8_Config == bitmap.config()) {
+        // Use default
+        if (kIndex_8_SkColorType == bitmap.colorType()) {
             // We don't support kIndex8 because we don't support
             // colortables in this workflow.
-            config = SkBitmap::kARGB_8888_Config;
-            info.fWidth = bitmap.width();
-            info.fHeight = bitmap.height();
             info.fColorType = kPMColor_SkColorType;
-            info.fAlphaType = bitmap.alphaType();
-        } else {
-            config = bitmap.config();  // Save for later!
-            if (!bitmap.asImageInfo(&info)) {
-                SkDEBUGFAIL("Getting SkImageInfo from bitmap failed.");
-                return NULL;
-            }
         }
     } else {
-        config = SkColorTypeToBitmapConfig(opts.fRequestedColorType);
-        if (!bitmap.canCopyTo(config)) {
-            SkASSERT(bitmap.config() != config);
+        if (!bitmap.canCopyTo(opts.fRequestedColorType)) {
+            SkASSERT(bitmap.colorType() != opts.fRequestedColorType);
             return NULL;  // Can not translate to needed config.
         }
-        info.fWidth = bitmap.width();
-        info.fHeight = bitmap.height();
         info.fColorType = opts.fRequestedColorType;
-        info.fAlphaType = bitmap.alphaType();
     }
     return SkNEW_ARGS(SkDecodingImageGenerator,
                       (data, autoStream.detach(), info,
-                       opts.fSampleSize, opts.fDitherImage, config));
+                       opts.fSampleSize, opts.fDitherImage));
 }
diff --git a/src/images/SkDecodingImageGenerator.h b/src/images/SkDecodingImageGenerator.h
index 12a49d5..fef7c6c 100644
--- a/src/images/SkDecodingImageGenerator.h
+++ b/src/images/SkDecodingImageGenerator.h
@@ -113,13 +113,12 @@
     const SkImageInfo      fInfo;
     const int              fSampleSize;
     const bool             fDitherImage;
-    const SkBitmap::Config fRequestedConfig;
+
     SkDecodingImageGenerator(SkData* data,
                              SkStreamRewindable* stream,
                              const SkImageInfo& info,
                              int sampleSize,
-                             bool ditherImage,
-                             SkBitmap::Config requestedConfig);
+                             bool ditherImage);
     static SkImageGenerator* Create(SkData*, SkStreamRewindable*,
                                     const Options&);
     typedef SkImageGenerator INHERITED;
diff --git a/src/ports/SkImageDecoder_CG.cpp b/src/ports/SkImageDecoder_CG.cpp
index 90c282d..c61ce98 100644
--- a/src/ports/SkImageDecoder_CG.cpp
+++ b/src/ports/SkImageDecoder_CG.cpp
@@ -208,8 +208,8 @@
             // format.
             // <Error>: CGImageDestinationFinalize image destination does not have enough images
             // So instead we copy to 8888.
-            if (bm.config() == SkBitmap::kARGB_4444_Config) {
-                bm.copyTo(&bitmap8888, SkBitmap::kARGB_8888_Config);
+            if (bm.colorType() == kARGB_4444_SkColorType) {
+                bm.copyTo(&bitmap8888, kPMColor_SkColorType);
                 bmPtr = &bitmap8888;
             }
             type = kUTTypePNG;
diff --git a/src/utils/SkBitmapHasher.cpp b/src/utils/SkBitmapHasher.cpp
index 9f0affd..6c861cd 100644
--- a/src/utils/SkBitmapHasher.cpp
+++ b/src/utils/SkBitmapHasher.cpp
@@ -57,7 +57,7 @@
     // Hmm, that didn't work. Maybe if we create a new
     // kARGB_8888_Config version of the bitmap it will work better?
     SkBitmap copyBitmap;
-    if (!bitmap.copyTo(&copyBitmap, SkBitmap::kARGB_8888_Config)) {
+    if (!bitmap.copyTo(&copyBitmap, kPMColor_SkColorType)) {
         return false;
     }
     return ComputeDigestInternal(copyBitmap, result);
diff --git a/src/utils/mac/SkCreateCGImageRef.cpp b/src/utils/mac/SkCreateCGImageRef.cpp
index 01f2dac..7687c3c 100644
--- a/src/utils/mac/SkCreateCGImageRef.cpp
+++ b/src/utils/mac/SkCreateCGImageRef.cpp
@@ -94,7 +94,7 @@
         copy = new SkBitmap;
         // here we make a ceep copy of the pixels, since CG won't take our
         // 565 directly
-        bm.copyTo(copy, SkBitmap::kARGB_8888_Config);
+        bm.copyTo(copy, kPMColor_SkColorType);
     } else {
         copy = new SkBitmap(bm);
     }