change SkColorTable to be immutable

BUG=
R=scroggo@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk/src@11676 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/core/SkBitmap.cpp b/core/SkBitmap.cpp
index 128726c..561f747 100644
--- a/core/SkBitmap.cpp
+++ b/core/SkBitmap.cpp
@@ -536,16 +536,12 @@
             return (fFlags & kImageIsOpaque_Flag) != 0;
 
         case kIndex8_Config: {
-            uint32_t flags = 0;
+            bool isOpaque;
 
             this->lockPixels();
-            // if lockPixels failed, we may not have a ctable ptr
-            if (fColorTable) {
-                flags = fColorTable->getFlags();
-            }
+            isOpaque = fColorTable && fColorTable->isOpaque();
             this->unlockPixels();
-
-            return (flags & SkColorTable::kColorsAreOpaque_Flag) != 0;
+            return isOpaque;
         }
 
         case kRGB_565_Config:
@@ -1494,7 +1490,7 @@
                 s += rb;
                 alpha += alphaRowBytes;
             }
-            ct->unlockColors(false);
+            ct->unlockColors();
         }
     } else {    // src is opaque, so just fill alpha[] with 0xFF
         memset(alpha, 0xFF, h * alphaRowBytes);
diff --git a/core/SkBitmapProcState_procs.h b/core/SkBitmapProcState_procs.h
index da9ca89..68c7983 100644
--- a/core/SkBitmapProcState_procs.h
+++ b/core/SkBitmapProcState_procs.h
@@ -157,7 +157,7 @@
 #define PREAMBLE(state)         const SkPMColor* SK_RESTRICT table = state.fBitmap->getColorTable()->lockColors()
 #define RETURNDST(src)          table[src]
 #define SRC_TO_FILTER(src)      table[src]
-#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlockColors(false)
+#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlockColors()
 #include "SkBitmapProcState_sample.h"
 
 #undef FILTER_PROC
@@ -172,7 +172,7 @@
                                 const SkPMColor* SK_RESTRICT table = state.fBitmap->getColorTable()->lockColors()
 #define RETURNDST(src)          SkAlphaMulQ(table[src], alphaScale)
 #define SRC_TO_FILTER(src)      table[src]
-#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlockColors(false)
+#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlockColors()
 #include "SkBitmapProcState_sample.h"
 
 // SRC == 4444
@@ -337,7 +337,7 @@
 #define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kIndex8_Config)
 #define PREAMBLE(state)         const SkPMColor* SK_RESTRICT table = state.fBitmap->getColorTable()->lockColors()
 #define SRC_TO_FILTER(src)      table[src]
-#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlockColors(false)
+#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlockColors()
 #include "SkBitmapProcState_shaderproc.h"
 
 #undef NAME_WRAP
diff --git a/core/SkColorTable.cpp b/core/SkColorTable.cpp
index e1ebf92..c117443 100644
--- a/core/SkColorTable.cpp
+++ b/core/SkColorTable.cpp
@@ -14,27 +14,11 @@
 
 SK_DEFINE_INST_COUNT(SkColorTable)
 
-SkColorTable::SkColorTable(int count)
-    : f16BitCache(NULL), fFlags(0)
-{
-    if (count < 0)
-        count = 0;
-    else if (count > 256)
-        count = 256;
-
-    fCount = SkToU16(count);
-    fColors = (SkPMColor*)sk_malloc_throw(count * sizeof(SkPMColor));
-    memset(fColors, 0, count * sizeof(SkPMColor));
-
-    SkDEBUGCODE(fColorLockCount = 0;)
-    SkDEBUGCODE(f16BitCacheLockCount = 0;)
-}
-
 // As copy constructor is hidden in the class hierarchy, we need to call
 // default constructor explicitly to suppress a compiler warning.
 SkColorTable::SkColorTable(const SkColorTable& src) : INHERITED() {
     f16BitCache = NULL;
-    fFlags = src.fFlags;
+    fAlphaType = src.fAlphaType;
     int count = src.count();
     fCount = SkToU16(count);
     fColors = reinterpret_cast<SkPMColor*>(
@@ -45,20 +29,22 @@
     SkDEBUGCODE(f16BitCacheLockCount = 0;)
 }
 
-SkColorTable::SkColorTable(const SkPMColor colors[], int count)
-    : f16BitCache(NULL), fFlags(0)
+SkColorTable::SkColorTable(const SkPMColor colors[], int count, SkAlphaType at)
+    : f16BitCache(NULL), fAlphaType(SkToU8(at))
 {
-    if (count < 0)
+    SkASSERT(0 == count || NULL != colors);
+
+    if (count < 0) {
         count = 0;
-    else if (count > 256)
+    } else if (count > 256) {
         count = 256;
+    }
 
     fCount = SkToU16(count);
     fColors = reinterpret_cast<SkPMColor*>(
                                     sk_malloc_throw(count * sizeof(SkPMColor)));
 
-    if (colors)
-        memcpy(fColors, colors, count * sizeof(SkPMColor));
+    memcpy(fColors, colors, count * sizeof(SkPMColor));
 
     SkDEBUGCODE(fColorLockCount = 0;)
     SkDEBUGCODE(f16BitCacheLockCount = 0;)
@@ -73,69 +59,30 @@
     sk_free(f16BitCache);
 }
 
-void SkColorTable::setFlags(unsigned flags)
-{
-    fFlags = SkToU8(flags);
-}
-
-void SkColorTable::unlockColors(bool changed)
-{
+void SkColorTable::unlockColors() {
     SkASSERT(fColorLockCount != 0);
     SkDEBUGCODE(sk_atomic_dec(&fColorLockCount);)
-    if (changed)
-        this->inval16BitCache();
-}
-
-void SkColorTable::inval16BitCache()
-{
-    SkASSERT(f16BitCacheLockCount == 0);
-    if (f16BitCache)
-    {
-        sk_free(f16BitCache);
-        f16BitCache = NULL;
-    }
 }
 
 #include "SkColorPriv.h"
 
-static inline void build_16bitcache(uint16_t dst[], const SkPMColor src[], int count)
-{
-    while (--count >= 0)
+static inline void build_16bitcache(uint16_t dst[], const SkPMColor src[],
+                                    int count) {
+    while (--count >= 0) {
         *dst++ = SkPixel32ToPixel16_ToU16(*src++);
+    }
 }
 
-const uint16_t* SkColorTable::lock16BitCache()
-{
-    if (fFlags & kColorsAreOpaque_Flag)
-    {
-        if (f16BitCache == NULL) // build the cache
-        {
-            f16BitCache = (uint16_t*)sk_malloc_throw(fCount * sizeof(uint16_t));
-            build_16bitcache(f16BitCache, fColors, fCount);
-        }
-    }
-    else    // our colors have alpha, so no cache
-    {
-        this->inval16BitCache();
-        if (f16BitCache)
-        {
-            sk_free(f16BitCache);
-            f16BitCache = NULL;
-        }
+const uint16_t* SkColorTable::lock16BitCache() {
+    if (this->isOpaque() && NULL == f16BitCache) {
+        f16BitCache = (uint16_t*)sk_malloc_throw(fCount * sizeof(uint16_t));
+        build_16bitcache(f16BitCache, fColors, fCount);
     }
 
     SkDEBUGCODE(f16BitCacheLockCount += 1);
     return f16BitCache;
 }
 
-void SkColorTable::setIsOpaque(bool isOpaque) {
-    if (isOpaque) {
-        fFlags |= kColorsAreOpaque_Flag;
-    } else {
-        fFlags &= ~kColorsAreOpaque_Flag;
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 SkColorTable::SkColorTable(SkFlattenableReadBuffer& buffer) {
@@ -143,7 +90,7 @@
     SkDEBUGCODE(fColorLockCount = 0;)
     SkDEBUGCODE(f16BitCacheLockCount = 0;)
 
-    fFlags = buffer.readUInt();
+    fAlphaType = SkToU8(buffer.readUInt());
     fCount = buffer.getArrayCount();
     fColors = (SkPMColor*)sk_malloc_throw(fCount * sizeof(SkPMColor));
     SkDEBUGCODE(const uint32_t countRead =) buffer.readColorArray(fColors);
@@ -154,6 +101,6 @@
 }
 
 void SkColorTable::flatten(SkFlattenableWriteBuffer& buffer) const {
-    buffer.writeUInt(fFlags);
+    buffer.writeUInt(fAlphaType);
     buffer.writeColorArray(fColors, fCount);
 }
diff --git a/core/SkProcSpriteBlitter.cpp b/core/SkProcSpriteBlitter.cpp
index a481920..2b535d9 100644
--- a/core/SkProcSpriteBlitter.cpp
+++ b/core/SkProcSpriteBlitter.cpp
@@ -36,7 +36,7 @@
         }
 
         if fSource.getColorTable())
-            fSource.getColorTable()->unlockColors(false);
+            fSource.getColorTable()->unlockColors();
     }
 
 private:
diff --git a/core/SkSpriteBlitter_RGB16.cpp b/core/SkSpriteBlitter_RGB16.cpp
index 9936867..8cef767 100644
--- a/core/SkSpriteBlitter_RGB16.cpp
+++ b/core/SkSpriteBlitter_RGB16.cpp
@@ -145,7 +145,7 @@
 #define SkSPRITE_PREAMBLE(srcBM, x, y)      const SkPMColor* ctable = srcBM.getColorTable()->lockColors()
 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S32A_Opaque_Pixel(dst, ctable[src])
 #define SkSPRITE_NEXT_ROW
-#define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlockColors(false)
+#define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlockColors()
 #include "SkSpriteBlitterTemplate.h"
 
 #define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8A_Blend
@@ -159,7 +159,7 @@
 #define SkSPRITE_PREAMBLE(srcBM, x, y)      const SkPMColor* ctable = srcBM.getColorTable()->lockColors(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
 #define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S32A_Blend_Pixel(dst, ctable[src], src_scale)
 #define SkSPRITE_NEXT_ROW
-#define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlockColors(false);
+#define SkSPRITE_POSTAMBLE(srcBM)           srcBM.getColorTable()->unlockColors();
 #include "SkSpriteBlitterTemplate.h"
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/gpu/SkGr.cpp b/gpu/SkGr.cpp
index 7505d75..0b60ede 100644
--- a/gpu/SkGr.cpp
+++ b/gpu/SkGr.cpp
@@ -31,7 +31,7 @@
     char* dst = (char*)buffer;
 
     memcpy(dst, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
-    ctable->unlockColors(false);
+    ctable->unlockColors();
 
     // always skip a full 256 number of entries, even if we memcpy'd fewer
     dst += kGrColorTableSize;
diff --git a/images/SkImageDecoder_libgif.cpp b/images/SkImageDecoder_libgif.cpp
index 08f37ef..ab0fbda 100644
--- a/images/SkImageDecoder_libgif.cpp
+++ b/images/SkImageDecoder_libgif.cpp
@@ -248,10 +248,13 @@
                 if (NULL == cmap) {
                     return error_return(gif, *bm, "null cmap");
                 }
-
                 colorCount = cmap->ColorCount;
-                SkAutoTMalloc<SkPMColor> colorStorage(colorCount);
-                SkPMColor* colorPtr = colorStorage.get();
+                if (colorCount > 256) {
+                    colorCount = 256;   // our kIndex8 can't support more
+                }
+
+                SkPMColor colorPtr[256]; // storage for worst-case
+                SkAlphaType alphaType = kOpaque_SkAlphaType;
                 for (int index = 0; index < colorCount; index++) {
                     colorPtr[index] = SkPackARGB32(0xFF,
                                                    cmap->Colors[index].Red,
@@ -263,10 +266,12 @@
                 bool reallyHasAlpha = transpIndex >= 0;
                 if (reallyHasAlpha) {
                     colorPtr[transpIndex] = SK_ColorTRANSPARENT; // ram in a transparent SkPMColor
+                    alphaType = kPremul_SkAlphaType;
                 }
 
-                SkAutoTUnref<SkColorTable> ctable(SkNEW_ARGS(SkColorTable, (colorPtr, colorCount)));
-                ctable->setIsOpaque(!reallyHasAlpha);
+                SkAutoTUnref<SkColorTable> ctable(SkNEW_ARGS(SkColorTable,
+                                                  (colorPtr, colorCount,
+                                                   alphaType)));
                 if (!this->allocPixelRef(bm, ctable)) {
                     return error_return(gif, *bm, "allocPixelRef");
                 }
diff --git a/images/SkImageDecoder_libpng.cpp b/images/SkImageDecoder_libpng.cpp
index 4e4106a..951083b 100644
--- a/images/SkImageDecoder_libpng.cpp
+++ b/images/SkImageDecoder_libpng.cpp
@@ -648,8 +648,6 @@
     png_colorp palette;
     png_bytep trans;
     int numTrans;
-    bool reallyHasAlpha = false;
-    SkColorTable* colorTable = NULL;
 
     png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette);
 
@@ -660,17 +658,16 @@
         the colortable by 1 (if its < 256) and duplicate the last color into that slot.
     */
     int colorCount = numPalette + (numPalette < 256);
+    SkPMColor colorStorage[256];    // worst-case storage
+    SkPMColor* colorPtr = colorStorage;
 
-    colorTable = SkNEW_ARGS(SkColorTable, (colorCount));
-
-    SkPMColor* colorPtr = colorTable->lockColors();
     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
         png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, NULL);
         *hasAlphap = (numTrans > 0);
     } else {
         numTrans = 0;
-        colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);
     }
+
     // check for bad images that might make us crash
     if (numTrans > numPalette) {
         numTrans = numPalette;
@@ -692,7 +689,7 @@
         *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue);
         palette++;
     }
-    reallyHasAlpha |= (transLessThanFF < 0);
+    bool reallyHasAlpha = (transLessThanFF < 0);
 
     for (; index < numPalette; index++) {
         *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
@@ -703,8 +700,18 @@
     if (numPalette < 256) {
         *colorPtr = colorPtr[-1];
     }
-    colorTable->unlockColors(true);
-    *colorTablep = colorTable;
+
+    SkAlphaType alphaType = kOpaque_SkAlphaType;
+    if (reallyHasAlpha) {
+        if (this->getRequireUnpremultipliedColors()) {
+            alphaType = kUnpremul_SkAlphaType;
+        } else {
+            alphaType = kPremul_SkAlphaType;
+        }
+    }
+
+    *colorTablep = SkNEW_ARGS(SkColorTable,
+                              (colorStorage, colorCount, alphaType));
     *reallyHasAlphap = reallyHasAlpha;
     return true;
 }
diff --git a/opts/SkBitmapProcState_opts_arm.cpp b/opts/SkBitmapProcState_opts_arm.cpp
index 3a3cb85..badb0f4 100644
--- a/opts/SkBitmapProcState_opts_arm.cpp
+++ b/opts/SkBitmapProcState_opts_arm.cpp
@@ -184,7 +184,7 @@
                       );
     }
 
-    s.fBitmap->getColorTable()->unlockColors(false);
+    s.fBitmap->getColorTable()->unlockColors();
 }
 #endif // SK_ARM_ARCH >= 6 && !defined(SK_CPU_BENDIAN)