store SkAlphaType inside SkBitmap, on road to support unpremul

BUG=
R=bsalomon@google.com, scroggo@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@11877 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 63a760c..bad63ba 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -143,6 +143,7 @@
     SkTSwap(fWidth, other.fWidth);
     SkTSwap(fHeight, other.fHeight);
     SkTSwap(fConfig, other.fConfig);
+    SkTSwap(fAlphaType, other.fAlphaType);
     SkTSwap(fFlags, other.fFlags);
     SkTSwap(fBytesPerPixel, other.fBytesPerPixel);
 
@@ -266,33 +267,76 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void SkBitmap::setConfig(Config c, int width, int height, size_t rowBytes) {
-    this->freePixels();
-
-    if ((width | height) < 0) {
-        goto err;
+static bool validate_alphaType(SkBitmap::Config config, SkAlphaType alphaType,
+                               SkAlphaType* canonical) {
+    switch (config) {
+        case SkBitmap::kNo_Config:
+            alphaType = kIgnore_SkAlphaType;
+            break;
+        case SkBitmap::kA1_Config:
+        case SkBitmap::kA8_Config:
+            if (kUnpremul_SkAlphaType == alphaType) {
+                alphaType = kPremul_SkAlphaType;
+            }
+            // fall-through
+        case SkBitmap::kIndex8_Config:
+        case SkBitmap::kARGB_4444_Config:
+        case SkBitmap::kARGB_8888_Config:
+            if (kIgnore_SkAlphaType == alphaType) {
+                return false;
+            }
+            break;
+        case SkBitmap::kRGB_565_Config:
+            alphaType = kOpaque_SkAlphaType;
+            break;
     }
+    if (canonical) {
+        *canonical = alphaType;
+    }
+    return true;
+}
 
+bool SkBitmap::setConfig(Config config, int width, int height, size_t rowBytes,
+                         SkAlphaType alphaType) {
+    if ((width | height) < 0) {
+        goto ERROR;
+    }
     if (rowBytes == 0) {
-        rowBytes = SkBitmap::ComputeRowBytes(c, width);
-        if (0 == rowBytes && kNo_Config != c) {
-            goto err;
+        rowBytes = SkBitmap::ComputeRowBytes(config, width);
+        if (0 == rowBytes && kNo_Config != config) {
+            goto ERROR;
         }
     }
 
-    fConfig     = SkToU8(c);
+    if (!validate_alphaType(config, alphaType, &alphaType)) {
+        goto ERROR;
+    }
+
+    this->freePixels();
+
+    fConfig     = SkToU8(config);
+    fAlphaType  = SkToU8(alphaType);
     fWidth      = width;
     fHeight     = height;
     fRowBytes   = SkToU32(rowBytes);
 
-    fBytesPerPixel = (uint8_t)ComputeBytesPerPixel(c);
+    fBytesPerPixel = (uint8_t)ComputeBytesPerPixel(config);
 
     SkDEBUGCODE(this->validate();)
-    return;
+    return true;
 
     // if we got here, we had an error, so we reset the bitmap to empty
-err:
+ERROR:
     this->reset();
+    return false;
+}
+
+bool SkBitmap::setAlphaType(SkAlphaType alphaType) {
+    if (!validate_alphaType(this->config(), alphaType, &alphaType)) {
+        return false;
+    }
+    fAlphaType = SkToU8(alphaType);
+    return true;
 }
 
 void SkBitmap::updatePixelsFromRef() const {
@@ -524,46 +568,6 @@
     }
 }
 
-bool SkBitmap::isOpaque() const {
-    switch (fConfig) {
-        case kNo_Config:
-            return true;
-
-        case kA1_Config:
-        case kA8_Config:
-        case kARGB_4444_Config:
-        case kARGB_8888_Config:
-            return (fFlags & kImageIsOpaque_Flag) != 0;
-
-        case kIndex8_Config: {
-            bool isOpaque;
-
-            this->lockPixels();
-            isOpaque = fColorTable && fColorTable->isOpaque();
-            this->unlockPixels();
-            return isOpaque;
-        }
-
-        case kRGB_565_Config:
-            return true;
-
-        default:
-            SkDEBUGFAIL("unknown bitmap config pased to isOpaque");
-            return false;
-    }
-}
-
-void SkBitmap::setIsOpaque(bool isOpaque) {
-    /*  we record this regardless of fConfig, though it is ignored in
-        isOpaque() for configs that can't support per-pixel alpha.
-    */
-    if (isOpaque) {
-        fFlags |= kImageIsOpaque_Flag;
-    } else {
-        fFlags &= ~kImageIsOpaque_Flag;
-    }
-}
-
 bool SkBitmap::isVolatile() const {
     return (fFlags & kImageIsVolatile_Flag) != 0;
 }
@@ -958,9 +962,9 @@
         SkPixelRef* pixelRef = fPixelRef->deepCopy(this->config(), &subset);
         if (pixelRef != NULL) {
             SkBitmap dst;
-            dst.setConfig(this->config(), subset.width(), subset.height());
+            dst.setConfig(this->config(), subset.width(), subset.height(), 0,
+                          this->alphaType());
             dst.setIsVolatile(this->isVolatile());
-            dst.setIsOpaque(this->isOpaque());
             dst.setPixelRef(pixelRef)->unref();
             SkDEBUGCODE(dst.validate());
             result->swap(dst);
@@ -979,9 +983,9 @@
     }
 
     SkBitmap dst;
-    dst.setConfig(this->config(), r.width(), r.height(), this->rowBytes());
+    dst.setConfig(this->config(), r.width(), r.height(), this->rowBytes(),
+                  this->alphaType());
     dst.setIsVolatile(this->isVolatile());
-    dst.setIsOpaque(this->isOpaque());
 
     if (fPixelRef) {
         // share the pixelref with a custom offset
@@ -1070,7 +1074,8 @@
     }
 
     SkBitmap tmpDst;
-    tmpDst.setConfig(dstConfig, src->width(), src->height());
+    tmpDst.setConfig(dstConfig, src->width(), src->height(), 0,
+                     src->alphaType());
 
     // allocate colortable if srcConfig == kIndex8_Config
     SkColorTable* ctable = (dstConfig == kIndex8_Config) ?
@@ -1130,8 +1135,6 @@
         canvas.drawBitmap(*src, 0, 0, &paint);
     }
 
-    tmpDst.setIsOpaque(src->isOpaque());
-
     dst->swap(tmpDst);
     return true;
 }
@@ -1579,7 +1582,7 @@
     buffer.writeInt(fHeight);
     buffer.writeInt(fRowBytes);
     buffer.writeInt(fConfig);
-    buffer.writeBool(this->isOpaque());
+    buffer.writeInt(fAlphaType);
 
     if (fPixelRef) {
         if (fPixelRef->getFactory()) {
@@ -1602,9 +1605,9 @@
     int height = buffer.readInt();
     int rowBytes = buffer.readInt();
     int config = buffer.readInt();
+    int alphaType = buffer.readInt();
 
-    this->setConfig((Config)config, width, height, rowBytes);
-    this->setIsOpaque(buffer.readBool());
+    this->setConfig((Config)config, width, height, rowBytes, (SkAlphaType)alphaType);
 
     int reftype = buffer.readInt();
     switch (reftype) {
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index eee2018..ff68481 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -27,9 +27,9 @@
 }
 
 SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
-    fBitmap.setConfig(config, width, height);
+    fBitmap.setConfig(config, width, height, 0, isOpaque ?
+                      kOpaque_SkAlphaType : kPremul_SkAlphaType);
     fBitmap.allocPixels();
-    fBitmap.setIsOpaque(isOpaque);
     if (!isOpaque) {
         fBitmap.eraseColor(SK_ColorTRANSPARENT);
     }
@@ -39,9 +39,9 @@
                                const SkDeviceProperties& deviceProperties)
     : SkBaseDevice(deviceProperties) {
 
-    fBitmap.setConfig(config, width, height);
+    fBitmap.setConfig(config, width, height, 0, isOpaque ?
+                      kOpaque_SkAlphaType : kPremul_SkAlphaType);
     fBitmap.allocPixels();
-    fBitmap.setIsOpaque(isOpaque);
     if (!isOpaque) {
         fBitmap.eraseColor(SK_ColorTRANSPARENT);
     }
diff --git a/src/core/SkBitmapScaler.cpp b/src/core/SkBitmapScaler.cpp
index 114836d..c28d477 100644
--- a/src/core/SkBitmapScaler.cpp
+++ b/src/core/SkBitmapScaler.cpp
@@ -287,7 +287,8 @@
     // Convolve into the result.
     SkBitmap result;
     result.setConfig(SkBitmap::kARGB_8888_Config,
-        destSubset.width(), destSubset.height());
+                     destSubset.width(), destSubset.height(), 0,
+                     source.alphaType());
     result.allocPixels(allocator, NULL);
     if (!result.readyToDraw()) {
         return false;
@@ -299,8 +300,6 @@
         static_cast<unsigned char*>(result.getPixels()),
         convolveProcs, true);
 
-    // Preserve the "opaque" flag for use as an optimization later.
-    result.setIsOpaque(source.isOpaque());
     *resultPtr = result;
     return true;
 }
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 3c91101..1498fc4 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -137,14 +137,17 @@
     }
 }
 
+/*
+ * GrRenderTarget does not know its opaqueness, only its config, so we have
+ * to make conservative guesses when we return an "equivalent" bitmap.
+ */
 static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
-    GrPixelConfig config = renderTarget->config();
-
     bool isOpaque;
+    SkBitmap::Config config = grConfig2skConfig(renderTarget->config(), &isOpaque);
+
     SkBitmap bitmap;
-    bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
-                     renderTarget->width(), renderTarget->height());
-    bitmap.setIsOpaque(isOpaque);
+    bitmap.setConfig(config, renderTarget->width(), renderTarget->height(), 0,
+                     isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
     return bitmap;
 }
 
diff --git a/src/image/SkImagePriv.cpp b/src/image/SkImagePriv.cpp
index f707543..eeeb9d8 100644
--- a/src/image/SkImagePriv.cpp
+++ b/src/image/SkImagePriv.cpp
@@ -9,45 +9,16 @@
 #include "SkCanvas.h"
 #include "SkPicture.h"
 
-SkBitmap::Config SkImageInfoToBitmapConfig(const SkImage::Info& info,
-                                           bool* isOpaque) {
+SkBitmap::Config SkImageInfoToBitmapConfig(const SkImage::Info& info) {
     switch (info.fColorType) {
         case SkImage::kAlpha_8_ColorType:
-            switch (info.fAlphaType) {
-                case kIgnore_SkAlphaType:
-                    // makes no sense
-                    return SkBitmap::kNo_Config;
-
-                case kOpaque_SkAlphaType:
-                    *isOpaque = true;
-                    return SkBitmap::kA8_Config;
-
-                case kPremul_SkAlphaType:
-                case kUnpremul_SkAlphaType:
-                    *isOpaque = false;
-                    return SkBitmap::kA8_Config;
-            }
-            break;
+            return SkBitmap::kA8_Config;
 
         case SkImage::kRGB_565_ColorType:
-            // we ignore fAlpahType, though some would not make sense
-            *isOpaque = true;
             return SkBitmap::kRGB_565_Config;
 
         case SkImage::kPMColor_ColorType:
-            switch (info.fAlphaType) {
-                case kIgnore_SkAlphaType:
-                case kUnpremul_SkAlphaType:
-                    // not supported yet
-                    return SkBitmap::kNo_Config;
-                case kOpaque_SkAlphaType:
-                    *isOpaque = true;
-                    return SkBitmap::kARGB_8888_Config;
-                case kPremul_SkAlphaType:
-                    *isOpaque = false;
-                    return SkBitmap::kARGB_8888_Config;
-            }
-            break;
+            return SkBitmap::kARGB_8888_Config;
 
         default:
             // break for unsupported colortypes
diff --git a/src/image/SkImagePriv.h b/src/image/SkImagePriv.h
index 2af8bbe..5d93605 100644
--- a/src/image/SkImagePriv.h
+++ b/src/image/SkImagePriv.h
@@ -13,8 +13,7 @@
 
 class SkPicture;
 
-extern SkBitmap::Config SkImageInfoToBitmapConfig(const SkImage::Info&,
-                                                  bool* isOpaque);
+extern SkBitmap::Config SkImageInfoToBitmapConfig(const SkImage::Info&);
 
 extern int SkImageBytesPerPixel(SkImage::ColorType);
 
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index cd9b70f..a208d83 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -31,8 +31,7 @@
             return false;
         }
 
-        bool isOpaque;
-        if (SkImageInfoToBitmapConfig(info, &isOpaque) == SkBitmap::kNo_Config) {
+        if (SkImageInfoToBitmapConfig(info) == SkBitmap::kNo_Config) {
             return false;
         }
 
@@ -85,23 +84,19 @@
 
 SkImage_Raster::SkImage_Raster(const Info& info, SkData* data, size_t rowBytes)
         : INHERITED(info.fWidth, info.fHeight) {
-    bool isOpaque;
-    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+    SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
 
-    fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes);
+    fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes, info.fAlphaType);
     fBitmap.setPixelRef(SkNEW_ARGS(SkDataPixelRef, (data)))->unref();
-    fBitmap.setIsOpaque(isOpaque);
     fBitmap.setImmutable();
 }
 
 SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, size_t rowBytes)
 : INHERITED(info.fWidth, info.fHeight) {
-    bool isOpaque;
-    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+    SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
 
-    fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes);
+    fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes, info.fAlphaType);
     fBitmap.setPixelRef(pr);
-    fBitmap.setIsOpaque(isOpaque);
 }
 
 SkImage_Raster::~SkImage_Raster() {}
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index e5b7bd4..7b3a643 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -38,12 +38,11 @@
 SkSurface_Gpu::SkSurface_Gpu(GrContext* ctx, const SkImage::Info& info,
                              int sampleCount)
         : INHERITED(info.fWidth, info.fHeight) {
-    bool isOpaque;
-    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+    SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
 
     fDevice = SkNEW_ARGS(SkGpuDevice, (ctx, config, info.fWidth, info.fHeight, sampleCount));
 
-    if (!isOpaque) {
+    if (!SkAlphaTypeIsOpaque(info.fAlphaType)) {
         fDevice->clear(0x0);
     }
 }
@@ -119,8 +118,7 @@
         return NULL;
     }
 
-    bool isOpaque;
-    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+    SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
 
     GrTextureDesc desc;
     desc.fFlags = kRenderTarget_GrTextureFlagBit | kCheckAllocation_GrTextureFlagBit;
@@ -136,3 +134,4 @@
 
     return SkNEW_ARGS(SkSurface_Gpu, (ctx, tex->asRenderTarget()));
 }
+
diff --git a/src/image/SkSurface_Raster.cpp b/src/image/SkSurface_Raster.cpp
index ccfdd27..5beabf7 100644
--- a/src/image/SkSurface_Raster.cpp
+++ b/src/image/SkSurface_Raster.cpp
@@ -39,8 +39,7 @@
 bool SkSurface_Raster::Valid(const SkImage::Info& info, size_t rowBytes) {
     static const size_t kMaxTotalSize = SK_MaxS32;
 
-    bool isOpaque;
-    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+    SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
 
     int shift = 0;
     switch (config) {
@@ -83,26 +82,20 @@
 
 SkSurface_Raster::SkSurface_Raster(const SkImage::Info& info, void* pixels, size_t rb)
         : INHERITED(info.fWidth, info.fHeight) {
-    bool isOpaque;
-    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
-
-    fBitmap.setConfig(config, info.fWidth, info.fHeight, rb);
+    SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
+    fBitmap.setConfig(config, info.fWidth, info.fHeight, rb, info.fAlphaType);
     fBitmap.setPixels(pixels);
-    fBitmap.setIsOpaque(isOpaque);
     fWeOwnThePixels = false;    // We are "Direct"
 }
 
 SkSurface_Raster::SkSurface_Raster(const SkImage::Info& info, SkPixelRef* pr, size_t rb)
         : INHERITED(info.fWidth, info.fHeight) {
-    bool isOpaque;
-    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
-
-    fBitmap.setConfig(config, info.fWidth, info.fHeight, rb);
+    SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
+    fBitmap.setConfig(config, info.fWidth, info.fHeight, rb, info.fAlphaType);
     fBitmap.setPixelRef(pr);
-    fBitmap.setIsOpaque(isOpaque);
     fWeOwnThePixels = true;
 
-    if (!isOpaque) {
+    if (!SkAlphaTypeIsOpaque(info.fAlphaType)) {
         fBitmap.eraseColor(SK_ColorTRANSPARENT);
     }
 }
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index 15cd1a6..3ee4112 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -245,8 +245,7 @@
     }
     // if the destination has no pixels then we must allocate them.
     if (dst->isNull()) {
-        dst->setConfig(src->getConfig(), w, h);
-        dst->setIsOpaque(src->isOpaque());
+        dst->setConfig(src->getConfig(), w, h, 0, src->alphaType());
 
         if (!this->allocPixelRef(dst, NULL)) {
             SkDEBUGF(("failed to allocate pixels needed to crop the bitmap"));
diff --git a/src/images/SkImageDecoder_libbmp.cpp b/src/images/SkImageDecoder_libbmp.cpp
index 2283dbf..34a88ac 100644
--- a/src/images/SkImageDecoder_libbmp.cpp
+++ b/src/images/SkImageDecoder_libbmp.cpp
@@ -133,8 +133,8 @@
 
     SkScaledBitmapSampler sampler(width, height, getSampleSize());
 
-    bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
-    bm->setIsOpaque(true);
+    bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0,
+                  kOpaque_SkAlphaType);
 
     if (justBounds) {
         return true;
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index 52c7483..67b1782 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -543,9 +543,9 @@
 #endif
 
     if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) {
-        bm->setConfig(config, cinfo.image_width, cinfo.image_height);
-        bm->setIsOpaque(config != SkBitmap::kA8_Config);
-        return true;
+        return bm->setConfig(config, cinfo.image_width, cinfo.image_height, 0,
+                             SkBitmap::kA8_Config == config ?
+                                kPremul_SkAlphaType : kOpaque_SkAlphaType);
     }
 
     /*  image_width and image_height are the original dimensions, available
@@ -565,9 +565,9 @@
         if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) {
             SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
                                        recompute_sampleSize(sampleSize, cinfo));
-            bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight());
-            bm->setIsOpaque(config != SkBitmap::kA8_Config);
-            return true;
+            return bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight(),
+                                 0, SkBitmap::kA8_Config == config ?
+                                    kPremul_SkAlphaType : kOpaque_SkAlphaType);
         } else {
             return return_false(cinfo, *bm, "start_decompress");
         }
@@ -580,8 +580,8 @@
     }
 
     SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize);
-    bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
-    bm->setIsOpaque(config != SkBitmap::kA8_Config);
+    bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0,
+                  SkBitmap::kA8_Config != config ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
         return true;
     }
@@ -801,8 +801,8 @@
     SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
 
     SkBitmap bitmap;
-    bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
-    bitmap.setIsOpaque(true);
+    bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0,
+                     kOpaque_SkAlphaType);
 
     // Check ahead of time if the swap(dest, src) is possible or not.
     // If yes, then we will stick to AllocPixelRef since it's cheaper with the
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index 5fc9350..e54387a 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -466,7 +466,16 @@
     if (SkBitmap::kA8_Config == decodedBitmap->config()) {
         reallyHasAlpha = true;
     }
-    decodedBitmap->setIsOpaque(!reallyHasAlpha);
+    
+    SkAlphaType alphaType = kOpaque_SkAlphaType;
+    if (reallyHasAlpha) {
+        if (this->getRequireUnpremultipliedColors()) {
+            alphaType = kUnpremul_SkAlphaType;
+        } else {
+            alphaType = kPremul_SkAlphaType;
+        }
+    }
+    decodedBitmap->setAlphaType(alphaType);
     return true;
 }
 
@@ -939,7 +948,15 @@
     if (SkBitmap::kA8_Config == decodedBitmap.config()) {
         reallyHasAlpha = true;
     }
-    decodedBitmap.setIsOpaque(!reallyHasAlpha);
+    SkAlphaType alphaType = kOpaque_SkAlphaType;
+    if (reallyHasAlpha) {
+        if (this->getRequireUnpremultipliedColors()) {
+            alphaType = kUnpremul_SkAlphaType;
+        } else {
+            alphaType = kPremul_SkAlphaType;
+        }
+    }
+    decodedBitmap.setAlphaType(alphaType);
 
     if (swapOnly) {
         bm->swap(decodedBitmap);
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index 8bb716b..68014dd 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -293,11 +293,8 @@
         return false;
     }
 
-    decodedBitmap->setConfig(config, width, height, 0);
-
-    decodedBitmap->setIsOpaque(!fHasAlpha);
-
-    return true;
+    return decodedBitmap->setConfig(config, width, height, 0,
+                                    fHasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType);
 }
 
 bool SkWEBPImageDecoder::onBuildTileIndex(SkStreamRewindable* stream,
diff --git a/src/images/SkImageDecoder_wbmp.cpp b/src/images/SkImageDecoder_wbmp.cpp
index 4a9944d..8dce62c 100644
--- a/src/images/SkImageDecoder_wbmp.cpp
+++ b/src/images/SkImageDecoder_wbmp.cpp
@@ -111,8 +111,8 @@
     int width = head.fWidth;
     int height = head.fHeight;
 
-    decodedBitmap->setConfig(SkBitmap::kIndex8_Config, width, height);
-    decodedBitmap->setIsOpaque(true);
+    decodedBitmap->setConfig(SkBitmap::kIndex8_Config, width, height, 0,
+                             kOpaque_SkAlphaType);
 
     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
         return true;
diff --git a/src/images/SkImageRef.cpp b/src/images/SkImageRef.cpp
index 9093b05..ead835f 100644
--- a/src/images/SkImageRef.cpp
+++ b/src/images/SkImageRef.cpp
@@ -64,7 +64,8 @@
 bool SkImageRef::isOpaque(SkBitmap* bitmap) {
     if (bitmap && bitmap->pixelRef() == this) {
         bitmap->lockPixels();
-        bitmap->setIsOpaque(fBitmap.isOpaque());
+        // what about colortables??????
+        bitmap->setAlphaType(fBitmap.alphaType());
         bitmap->unlockPixels();
         return true;
     }
diff --git a/src/lazy/SkBitmapFactory.cpp b/src/lazy/SkBitmapFactory.cpp
index 0ff4ee2..5464851 100644
--- a/src/lazy/SkBitmapFactory.cpp
+++ b/src/lazy/SkBitmapFactory.cpp
@@ -53,16 +53,13 @@
         return false;
     }
 
-    bool isOpaque = false;
-    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+    SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
 
     Target target;
     // FIMXE: There will be a problem if this rowbytes is calculated differently from
     // in SkLazyPixelRef.
     target.fRowBytes = SkImageMinRowBytes(info);
-
-    dst->setConfig(config, info.fWidth, info.fHeight, target.fRowBytes);
-    dst->setIsOpaque(isOpaque);
+    dst->setConfig(config, info.fWidth, info.fHeight, target.fRowBytes, info.fAlphaType);
 
     // fImageCache and fCacheSelector are mutually exclusive.
     SkASSERT(NULL == fImageCache || NULL == fCacheSelector);
diff --git a/src/lazy/SkLazyPixelRef.cpp b/src/lazy/SkLazyPixelRef.cpp
index 9e023c4..22d4b11 100644
--- a/src/lazy/SkLazyPixelRef.cpp
+++ b/src/lazy/SkLazyPixelRef.cpp
@@ -150,15 +150,14 @@
 
 static bool init_from_info(SkBitmap* bm, const SkImage::Info& info,
                            size_t rowBytes) {
-    bool isOpaque;
-    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+    SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
     if (SkBitmap::kNo_Config == config) {
         return false;
     }
 
-    bm->setConfig(config, info.fWidth, info.fHeight, rowBytes);
-    bm->setIsOpaque(isOpaque);
-    return bm->allocPixels();
+    return bm->setConfig(config, info.fWidth, info.fHeight, rowBytes, info.fAlphaType)
+           &&
+           bm->allocPixels();
 }
 
 bool SkLazyPixelRef::onImplementsDecodeInto() {
diff --git a/src/ports/SkImageDecoder_CG.cpp b/src/ports/SkImageDecoder_CG.cpp
index 8956aca..3f850b5 100644
--- a/src/ports/SkImageDecoder_CG.cpp
+++ b/src/ports/SkImageDecoder_CG.cpp
@@ -104,11 +104,13 @@
         case kCGImageAlphaNoneSkipLast:
         case kCGImageAlphaNoneSkipFirst:
             SkASSERT(SkBitmap::ComputeIsOpaque(*bm));
-            bm->setIsOpaque(true);
+            bm->setAlphaType(kOpaque_SkAlphaType);
             break;
         default:
             // we don't know if we're opaque or not, so compute it.
-            bm->computeAndSetOpaquePredicate();
+            if (SkBitmap::ComputeIsOpaque(*bm)) {
+                bm->setAlphaType(kOpaque_SkAlphaType);
+            }
     }
     if (!bm->isOpaque() && this->getRequireUnpremultipliedColors()) {
         // CGBitmapContext does not support unpremultiplied, so the image has been premultiplied.
@@ -119,6 +121,7 @@
                 *addr = unpremultiply_pmcolor(*addr);
             }
         }
+        bm->setAlphaType(kUnpremul_SkAlphaType);
     }
     bm->unlockPixels();
     return true;
diff --git a/src/ports/SkImageDecoder_WIC.cpp b/src/ports/SkImageDecoder_WIC.cpp
index c3666ac..1bda67f 100644
--- a/src/ports/SkImageDecoder_WIC.cpp
+++ b/src/ports/SkImageDecoder_WIC.cpp
@@ -240,7 +240,9 @@
         );
 
         // Note: we don't need to premultiply here since we specified PBGRA
-        bm->computeAndSetOpaquePredicate();
+        if (ComputeIsOpaque(*bm)) {
+            bm->setAlphaType(kOpaque_SkAlphaType);
+        }
     }
 
     return SUCCEEDED(hr);
diff --git a/src/views/SkWindow.cpp b/src/views/SkWindow.cpp
index f25eb12..d6fe32b 100644
--- a/src/views/SkWindow.cpp
+++ b/src/views/SkWindow.cpp
@@ -102,9 +102,8 @@
     if (width != fBitmap.width() || height != fBitmap.height() || config != fConfig)
     {
         fConfig = config;
-        fBitmap.setConfig(config, width, height);
+        fBitmap.setConfig(config, width, height, 0, kOpaque_SkAlphaType);
         fBitmap.allocPixels();
-        fBitmap.setIsOpaque(true);
 
         this->setSize(SkIntToScalar(width), SkIntToScalar(height));
         this->inval(NULL);