- Add astcbitmap to gm slides
- Add additional ASTC formats
- Add astc image decoder files

R=reed@google.com, robertphillips@google.com, halcanary@google.com

Author: krajcevski@google.com

Review URL: https://codereview.chromium.org/444093002
diff --git a/gm/astcbitmap.cpp b/gm/astcbitmap.cpp
new file mode 100644
index 0000000..3c9079c
--- /dev/null
+++ b/gm/astcbitmap.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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 "gm.h"
+
+#include "Resources.h"
+#include "SkCanvas.h"
+#include "SkData.h"
+#include "SkDecodingImageGenerator.h"
+#include "SkImageDecoder.h"
+#include "SkOSFile.h"
+#include "SkTextureCompressor.h"
+
+static const char *kASTCFilenames[] = {
+    "mandrill_128x128_4x4.astc",    // kASTC_4x4_Format
+    "mandrill_130x128_5x4.astc",    // kASTC_5x4_Format
+    "mandrill_130x130_5x5.astc",    // kASTC_5x5_Format
+    "mandrill_132x130_6x5.astc",    // kASTC_6x5_Format
+    "mandrill_132x132_6x6.astc",    // kASTC_6x6_Format
+    "mandrill_128x130_8x5.astc",    // kASTC_8x5_Format
+    "mandrill_128x132_8x6.astc",    // kASTC_8x6_Format
+    "mandrill_128x128_8x8.astc",    // kASTC_8x8_Format
+    "mandrill_130x130_10x5.astc",   // kASTC_10x5_Format
+    "mandrill_130x132_10x6.astc",   // kASTC_10x6_Format
+    "mandrill_130x128_10x8.astc",   // kASTC_10x8_Format
+    "mandrill_130x130_10x10.astc",  // kASTC_10x10_Format
+    "mandrill_132x130_12x10.astc",  // kASTC_12x10_Format
+    "mandrill_132x132_12x12.astc",  // kASTC_12x12_Format
+};
+
+static const int kNumASTCFilenames = SK_ARRAY_COUNT(kASTCFilenames);
+
+static inline const char *get_astc_filename(int idx) {
+    if (idx < 0 || kNumASTCFilenames <= idx) {
+        return "";
+    }
+
+    return kASTCFilenames[idx];
+}
+
+namespace skiagm {
+
+/**
+ *  Test decoding an image from an ASTC file and then from compressed ASTC data.
+ */
+class ASTCBitmapGM : public GM {
+public:
+    ASTCBitmapGM() { }
+    virtual ~ASTCBitmapGM() { }
+
+protected:
+    virtual SkString onShortName() SK_OVERRIDE {
+        return SkString("astcbitmap");
+    }
+
+    virtual SkISize onISize() SK_OVERRIDE {
+        return SkISize::Make(kGMDimension, kGMDimension);
+    }
+
+    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+        for (int j = 0; j < 4; ++j) {
+            for (int i = 0; i < 4; ++i) {
+                SkString filename = GetResourcePath(get_astc_filename(j*4+i));
+                if (filename == GetResourcePath("")) {
+                    continue;
+                }
+
+                SkAutoTUnref<SkData> fileData(SkData::NewFromFileName(filename.c_str()));
+                if (NULL == fileData) {
+                    SkDebugf("Could not open the file. Did you forget to set the resourcePath?\n");
+                    return;
+                }
+
+                SkBitmap bm;
+                if (!SkInstallDiscardablePixelRef(
+                        SkDecodingImageGenerator::Create(
+                            fileData, SkDecodingImageGenerator::Options()), &bm)) {
+                    SkDebugf("Could not install discardable pixel ref.\n");
+                    return;
+                }
+
+                const SkScalar bmX = static_cast<SkScalar>(i*kBitmapDimension);
+                const SkScalar bmY = static_cast<SkScalar>(j*kBitmapDimension);
+                canvas->drawBitmap(bm, bmX, bmY);
+            }
+        }
+    }
+
+private:
+    static const int kGMDimension = 600;
+    static const int kBitmapDimension = kGMDimension/4;
+
+    typedef GM INHERITED;
+};
+
+}  // namespace skiagm
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEF_GM( return SkNEW(skiagm::ASTCBitmapGM); )
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index d9c1872..c55da89 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -18,6 +18,7 @@
         '../gm/alphagradients.cpp',
         '../gm/arcofzorro.cpp',
         '../gm/arithmode.cpp',
+        '../gm/astcbitmap.cpp',
         '../gm/beziereffects.cpp',
         '../gm/bigblurs.cpp',
         '../gm/bigmatrix.cpp',
diff --git a/gyp/images.gyp b/gyp/images.gyp
index ee1840b..3cc66a0 100644
--- a/gyp/images.gyp
+++ b/gyp/images.gyp
@@ -59,6 +59,7 @@
         '../src/images/SkImageDecoder_wbmp.cpp',
         '../src/images/SkImageDecoder_pkm.cpp',
         '../src/images/SkImageDecoder_ktx.cpp',
+        '../src/images/SkImageDecoder_astc.cpp',
         '../src/images/SkImageDecoder_libbmp.cpp',
         '../src/images/SkImageDecoder_libgif.cpp',
         '../src/images/SkImageDecoder_libico.cpp',
diff --git a/include/core/SkImageDecoder.h b/include/core/SkImageDecoder.h
index b258afe..2b91080 100644
--- a/include/core/SkImageDecoder.h
+++ b/include/core/SkImageDecoder.h
@@ -37,6 +37,7 @@
         kWEBP_Format,
         kPKM_Format,
         kKTX_Format,
+        kASTC_Format,
 
         kLastKnownFormat = kKTX_Format,
     };
@@ -525,6 +526,7 @@
 DECLARE_DECODER_CREATOR(WEBPImageDecoder);
 DECLARE_DECODER_CREATOR(PKMImageDecoder);
 DECLARE_DECODER_CREATOR(KTXImageDecoder);
+DECLARE_DECODER_CREATOR(ASTCImageDecoder);
 
 // Typedefs to make registering decoder and formatter callbacks easier.
 // These have to be defined outside SkImageDecoder. :(
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index 2863739..69dc0b5 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -37,19 +37,33 @@
 }
 
 static inline GrPixelConfig fmt_to_config(SkTextureCompressor::Format fmt) {
-    static const GrPixelConfig configMap[] = {
-        kLATC_GrPixelConfig,       // kLATC_Format,
-        kR11_EAC_GrPixelConfig,    // kR11_EAC_Format,
-        kETC1_GrPixelConfig,       // kETC1_Format,
-        kASTC_12x12_GrPixelConfig  // kASTC_12x12_Format,
-    };
-    GR_STATIC_ASSERT(0 == SkTextureCompressor::kLATC_Format);
-    GR_STATIC_ASSERT(1 == SkTextureCompressor::kR11_EAC_Format);
-    GR_STATIC_ASSERT(2 == SkTextureCompressor::kETC1_Format);
-    GR_STATIC_ASSERT(3 == SkTextureCompressor::kASTC_12x12_Format);
-    GR_STATIC_ASSERT(SK_ARRAY_COUNT(configMap) == SkTextureCompressor::kFormatCnt);
 
-    return configMap[fmt];
+    GrPixelConfig config;
+    switch (fmt) {
+        case SkTextureCompressor::kLATC_Format:
+            config = kLATC_GrPixelConfig;
+            break;
+
+        case SkTextureCompressor::kR11_EAC_Format:
+            config = kR11_EAC_GrPixelConfig;
+            break;
+
+        case SkTextureCompressor::kASTC_12x12_Format:
+            config = kASTC_12x12_GrPixelConfig;
+            break;
+
+        case SkTextureCompressor::kETC1_Format:
+            config = kETC1_GrPixelConfig;
+            break;
+
+        default:
+            SkDEBUGFAIL("No GrPixelConfig for compression format!");
+            // Best guess
+            config = kAlpha_8_GrPixelConfig;
+            break;
+    }
+
+    return config;
 }
 
 #if GR_COMPRESS_ALPHA_MASK
diff --git a/src/images/SkForceLinking.cpp b/src/images/SkForceLinking.cpp
index 442f0f7..6cc0704 100644
--- a/src/images/SkForceLinking.cpp
+++ b/src/images/SkForceLinking.cpp
@@ -20,6 +20,7 @@
         CreateICOImageDecoder();
         CreatePKMImageDecoder();
         CreateKTXImageDecoder();
+        CreateASTCImageDecoder();
         CreateWBMPImageDecoder();
         // Only link GIF and PNG on platforms that build them. See images.gyp
 #if !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_WIN) && !defined(SK_BUILD_FOR_NACL) \
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index fcba910..0e2018c 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -86,6 +86,8 @@
             return "PKM";
         case kKTX_Format:
             return "KTX";
+        case kASTC_Format:
+            return "ASTC";
         case kJPEG_Format:
             return "JPEG";
         case kPNG_Format:
diff --git a/src/images/SkImageDecoder_astc.cpp b/src/images/SkImageDecoder_astc.cpp
new file mode 100644
index 0000000..79e9804
--- /dev/null
+++ b/src/images/SkImageDecoder_astc.cpp
@@ -0,0 +1,209 @@
+/*
+ * 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 "SkEndian.h"
+#include "SkColorPriv.h"
+#include "SkImageDecoder.h"
+#include "SkScaledBitmapSampler.h"
+#include "SkStream.h"
+#include "SkStreamPriv.h"
+#include "SkTypes.h"
+
+#include "SkTextureCompressor.h"
+
+class SkASTCImageDecoder : public SkImageDecoder {
+public:
+    SkASTCImageDecoder() { }
+
+    virtual Format getFormat() const SK_OVERRIDE {
+        return kASTC_Format;
+    }
+
+protected:
+    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
+
+private:
+    typedef SkImageDecoder INHERITED;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static const uint32_t kASTCMagicNumber = 0x5CA1AB13;
+
+static inline int read_24bit(const uint8_t* buf) {
+    // Assume everything is little endian...
+    return
+        static_cast<int>(buf[0]) |
+        (static_cast<int>(buf[1]) << 8) |
+        (static_cast<int>(buf[2]) << 16);
+}
+
+bool SkASTCImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
+    SkAutoMalloc autoMal;
+    const size_t length = SkCopyStreamToStorage(&autoMal, stream);
+    if (0 == length) {
+        return false;
+    }
+
+    unsigned char* buf = (unsigned char*)autoMal.get();
+
+    // Make sure that the magic header is there...
+    SkASSERT(SkEndian_SwapLE32(*(reinterpret_cast<uint32_t*>(buf))) == kASTCMagicNumber);
+
+    // Advance past the magic header
+    buf += 4;
+
+    const int blockDimX = buf[0];
+    const int blockDimY = buf[1];
+    const int blockDimZ = buf[2];
+
+    if (1 != blockDimZ) {
+        // We don't support decoding 3D
+        return false;
+    }
+
+    // Choose the proper ASTC format
+    SkTextureCompressor::Format astcFormat;
+    if (4 == blockDimX && 4 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_4x4_Format;
+    } else if (5 == blockDimX && 4 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_5x4_Format;
+    } else if (5 == blockDimX && 5 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_5x5_Format;
+    } else if (6 == blockDimX && 5 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_6x5_Format;
+    } else if (6 == blockDimX && 6 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_6x6_Format;
+    } else if (8 == blockDimX && 5 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_8x5_Format;
+    } else if (8 == blockDimX && 6 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_8x6_Format;
+    } else if (8 == blockDimX && 8 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_8x8_Format;
+    } else if (10 == blockDimX && 5 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_10x5_Format;
+    } else if (10 == blockDimX && 6 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_10x6_Format;
+    } else if (10 == blockDimX && 8 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_10x8_Format;
+    } else if (10 == blockDimX && 10 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_10x10_Format;
+    } else if (12 == blockDimX && 10 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_12x10_Format;
+    } else if (12 == blockDimX && 12 == blockDimY) {
+        astcFormat = SkTextureCompressor::kASTC_12x12_Format;
+    } else {
+        // We don't support any other block dimensions..
+        return false;
+    }
+
+    // Advance buf past the block dimensions
+    buf += 3;
+
+    // Read the width/height/depth from the buffer...
+    const int width = read_24bit(buf);
+    const int height = read_24bit(buf + 3);
+    const int depth = read_24bit(buf + 6);
+
+    if (1 != depth) {
+        // We don't support decoding 3D.
+        return false;
+    }
+
+    // Advance the buffer past the image dimensions
+    buf += 9;
+
+#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
+    // should we allow the Chooser (if present) to pick a config for us???
+    if (!this->chooseFromOneChoice(kN32_SkColorType, width, height)) {
+        return false;
+    }
+#endif
+
+    // Setup the sampler...
+    SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
+
+    // Determine the alpha of the bitmap...
+    SkAlphaType alphaType = kOpaque_SkAlphaType;
+    if (this->getRequireUnpremultipliedColors()) {
+        alphaType = kUnpremul_SkAlphaType;
+    } else {
+        alphaType = kPremul_SkAlphaType;
+    }
+
+    // Set the config...
+    bm->setInfo(SkImageInfo::MakeN32(sampler.scaledWidth(), sampler.scaledHeight(), alphaType));
+
+    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
+        return true;
+    }
+
+    if (!this->allocPixelRef(bm, NULL)) {
+        return false;
+    }
+
+    // Lock the pixels, since we're about to write to them...
+    SkAutoLockPixels alp(*bm);
+
+    if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, *this)) {
+        return false;
+    }
+
+    // ASTC Data is encoded as RGBA pixels, so we should extract it as such
+    int nPixels = width * height;
+    SkAutoMalloc outRGBAData(nPixels * 4);
+    uint8_t *outRGBADataPtr = reinterpret_cast<uint8_t *>(outRGBAData.get());
+
+    // Decode ASTC
+    if (!SkTextureCompressor::DecompressBufferFromFormat(
+            outRGBADataPtr, width*4, buf, width, height, astcFormat)) {
+    }
+
+    // Set each of the pixels...
+    const int srcRowBytes = width * 4;
+    const int dstHeight = sampler.scaledHeight();
+    const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBADataPtr);
+    srcRow += sampler.srcY0() * srcRowBytes;
+    for (int y = 0; y < dstHeight; ++y) {
+        sampler.next(srcRow);
+        srcRow += sampler.srcDY() * srcRowBytes;
+    }
+
+    return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+DEFINE_DECODER_CREATOR(ASTCImageDecoder);
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static bool is_astc(SkStreamRewindable* stream) {
+    // Read the ASTC header and make sure it's valid.
+    uint32_t magic;
+    if (stream->read((void*)&magic, 4) != 4) {
+        return false;
+    }
+
+    return kASTCMagicNumber == SkEndian_SwapLE32(magic);
+}
+
+static SkImageDecoder* sk_libastc_dfactory(SkStreamRewindable* stream) {
+    if (is_astc(stream)) {
+        return SkNEW(SkASTCImageDecoder);
+    }
+    return NULL;
+}
+
+static SkImageDecoder_DecodeReg gReg(sk_libastc_dfactory);
+
+static SkImageDecoder::Format get_format_astc(SkStreamRewindable* stream) {
+    if (is_astc(stream)) {
+        return SkImageDecoder::kASTC_Format;
+    }
+    return SkImageDecoder::kUnknown_Format;
+}
+
+static SkImageDecoder_FormatReg gFormatReg(get_format_astc);
diff --git a/src/utils/SkTextureCompressor.cpp b/src/utils/SkTextureCompressor.cpp
index 4ced9a0..0dfc229 100644
--- a/src/utils/SkTextureCompressor.cpp
+++ b/src/utils/SkTextureCompressor.cpp
@@ -45,24 +45,31 @@
     }
 
     // No specialized arguments, return the dimensions as they are in the spec.
-    switch(format) {
-        // These formats are 64 bits per 4x4 block.
-        default:
-            SkDEBUGFAIL("Unknown compression format!");
-            // fall through
-        case kLATC_Format:
-        case kR11_EAC_Format:
-        case kETC1_Format: 
-            *dimX = 4;
-            *dimY = 4;
-            break;
+    static const struct FormatDimensions {
+        const int fBlockSizeX;
+        const int fBlockSizeY;
+    } kFormatDimensions[kFormatCnt] = {
+        { 4, 4 }, // kLATC_Format
+        { 4, 4 }, // kR11_EAC_Format
+        { 4, 4 }, // kETC1_Format
+        { 4, 4 }, // kASTC_4x4_Format
+        { 5, 4 }, // kASTC_5x4_Format
+        { 5, 5 }, // kASTC_5x5_Format
+        { 6, 5 }, // kASTC_6x5_Format
+        { 6, 6 }, // kASTC_6x6_Format
+        { 8, 5 }, // kASTC_8x5_Format
+        { 8, 6 }, // kASTC_8x6_Format
+        { 8, 8 }, // kASTC_8x8_Format
+        { 10, 5 }, // kASTC_10x5_Format
+        { 10, 6 }, // kASTC_10x6_Format
+        { 10, 8 }, // kASTC_10x8_Format
+        { 10, 10 }, // kASTC_10x10_Format
+        { 12, 10 }, // kASTC_12x10_Format
+        { 12, 12 }, // kASTC_12x12_Format
+    };
 
-        // This format is 12x12 blocks to 128 bits.
-        case kASTC_12x12_Format:
-            *dimX = 12;
-            *dimY = 12;
-            break;        
-    }
+    *dimX = kFormatDimensions[format].fBlockSizeX;
+    *dimY = kFormatDimensions[format].fBlockSizeY;
 }
 
 int GetCompressedDataSize(Format fmt, int width, int height) {
@@ -79,7 +86,20 @@
             encodedBlockSize = 8;
             break;
 
-        // This format is 12x12 blocks to 128 bits.
+        // This format is 128 bits.
+        case kASTC_4x4_Format:
+        case kASTC_5x4_Format:
+        case kASTC_5x5_Format:
+        case kASTC_6x5_Format:
+        case kASTC_6x6_Format:
+        case kASTC_8x5_Format:
+        case kASTC_8x6_Format:
+        case kASTC_8x8_Format:
+        case kASTC_10x5_Format:
+        case kASTC_10x6_Format:
+        case kASTC_10x8_Format:
+        case kASTC_10x10_Format:
+        case kASTC_12x10_Format:
         case kASTC_12x12_Format:
             encodedBlockSize = 16;
             break;
@@ -214,9 +234,23 @@
         case kETC1_Format:
             return 0 == etc1_decode_image(src, dst, width, height, 3, dstRowBytes);
 #endif
+
+        case kASTC_4x4_Format:
+        case kASTC_5x4_Format:
+        case kASTC_5x5_Format:
+        case kASTC_6x5_Format:
+        case kASTC_6x6_Format:
+        case kASTC_8x5_Format:
+        case kASTC_8x6_Format:
+        case kASTC_8x8_Format:
+        case kASTC_10x5_Format:
+        case kASTC_10x6_Format:
+        case kASTC_10x8_Format:
+        case kASTC_10x10_Format:
+        case kASTC_12x10_Format:
         case kASTC_12x12_Format:
-            // TODO(krajcevski) .. right now just fall through and return false.
-            return false;
+            DecompressASTC(dst, dstRowBytes, src, width, height, dimX, dimY);
+            return true;
 
         default:
             // Do nothing...
diff --git a/src/utils/SkTextureCompressor.h b/src/utils/SkTextureCompressor.h
index d82bf07..d5c1d25 100644
--- a/src/utils/SkTextureCompressor.h
+++ b/src/utils/SkTextureCompressor.h
@@ -30,6 +30,19 @@
                             //    bitmap to insert alphas.
 
         // Multi-purpose formats
+        kASTC_4x4_Format,   // 4x4 blocks, no compression, decompresses RGBA
+        kASTC_5x4_Format,   // 5x4 blocks, no compression, decompresses RGBA
+        kASTC_5x5_Format,   // 5x5 blocks, no compression, decompresses RGBA
+        kASTC_6x5_Format,   // 6x5 blocks, no compression, decompresses RGBA
+        kASTC_6x6_Format,   // 6x6 blocks, no compression, decompresses RGBA
+        kASTC_8x5_Format,   // 8x5 blocks, no compression, decompresses RGBA
+        kASTC_8x6_Format,   // 8x6 blocks, no compression, decompresses RGBA
+        kASTC_8x8_Format,   // 8x8 blocks, no compression, decompresses RGBA
+        kASTC_10x5_Format,  // 10x5 blocks, no compression, decompresses RGBA
+        kASTC_10x6_Format,  // 10x6 blocks, no compression, decompresses RGBA
+        kASTC_10x8_Format,  // 10x8 blocks, no compression, decompresses RGBA
+        kASTC_10x10_Format, // 10x10 blocks, no compression, decompresses RGBA
+        kASTC_12x10_Format, // 12x10 blocks, no compression, decompresses RGBA
         kASTC_12x12_Format, // 12x12 blocks, compresses A8, decompresses RGBA
 
         kLast_Format = kASTC_12x12_Format
diff --git a/src/utils/SkTextureCompressor_ASTC.cpp b/src/utils/SkTextureCompressor_ASTC.cpp
index 25d87fd..13fec8f 100644
--- a/src/utils/SkTextureCompressor_ASTC.cpp
+++ b/src/utils/SkTextureCompressor_ASTC.cpp
@@ -1708,7 +1708,8 @@
         // The rest of the CEM config will be between the dual plane bit selector
         // and the texel weight grid.
         const int lowCEM = static_cast<int>(read_astc_bits(fBlock, 23, 29));
-        SkASSERT(lastWeight - dualPlaneBitLoc > 31);
+        SkASSERT(lastWeight >= dualPlaneBitLoc);
+        SkASSERT(lastWeight - dualPlaneBitLoc < 31);
         int fullCEM = static_cast<int>(read_astc_bits(fBlock, dualPlaneBitLoc, lastWeight));
 
         // Attach the config at the end of the weight grid to the CEM values
diff --git a/tests/ImageDecodingTest.cpp b/tests/ImageDecodingTest.cpp
index 5e63611..8838e75 100644
--- a/tests/ImageDecodingTest.cpp
+++ b/tests/ImageDecodingTest.cpp
@@ -55,9 +55,10 @@
         // decoders do not, so skip them as well.
         case SkImageDecoder::kICO_Format:
         case SkImageDecoder::kBMP_Format:
-        // KTX is a Texture format so it's not particularly clear how to 
-        // decode the alpha from it.
+        // KTX and ASTC are texture formats so it's not particularly clear how to 
+        // decode the alpha from them.
         case SkImageDecoder::kKTX_Format:
+        case SkImageDecoder::kASTC_Format:
         // The rest of these are opaque.
         case SkImageDecoder::kPKM_Format:
         case SkImageDecoder::kWBMP_Format:
diff --git a/tests/TextureCompressionTest.cpp b/tests/TextureCompressionTest.cpp
index 8694389..da7a87b 100644
--- a/tests/TextureCompressionTest.cpp
+++ b/tests/TextureCompressionTest.cpp
@@ -12,6 +12,32 @@
 #include "SkTextureCompressor.h"
 #include "Test.h"
 
+// TODO: Create separate tests for RGB and RGBA data once
+// ASTC and ETC1 decompression is implemented.
+
+static bool decompresses_a8(SkTextureCompressor::Format fmt) {
+    switch (fmt) {
+        case SkTextureCompressor::kLATC_Format:
+        case SkTextureCompressor::kR11_EAC_Format:
+            return true;
+
+        default:
+            return false;
+    }
+}
+
+static bool compresses_a8(SkTextureCompressor::Format fmt) {
+    switch (fmt) {
+        case SkTextureCompressor::kLATC_Format:
+        case SkTextureCompressor::kR11_EAC_Format:
+        case SkTextureCompressor::kASTC_12x12_Format:
+            return true;
+
+        default:
+            return false;
+    }
+}
+
 /**
  * Make sure that we properly fail when we don't have multiple of four image dimensions.
  */
@@ -38,6 +64,9 @@
     
     for (int i = 0; i < SkTextureCompressor::kFormatCnt; ++i) {
         const SkTextureCompressor::Format fmt = static_cast<SkTextureCompressor::Format>(i);
+        if (!compresses_a8(fmt)) {
+            continue;
+        }
         SkAutoDataUnref data(SkTextureCompressor::CompressBitmapToFormat(bitmap, fmt));
         REPORTER_ASSERT(reporter, NULL == data);
     }
@@ -69,6 +98,9 @@
 
     for (int i = 0; i < SkTextureCompressor::kFormatCnt; ++i) {
         const SkTextureCompressor::Format fmt = static_cast<SkTextureCompressor::Format>(i);
+        if (!compresses_a8(fmt)) {
+            continue;
+        }
         SkAutoDataUnref data(SkTextureCompressor::CompressBitmapToFormat(bitmap, fmt));
         REPORTER_ASSERT(reporter, NULL == data);
     }
@@ -134,10 +166,7 @@
 
         // Ignore formats for RGBA data, since the decompressed buffer
         // won't match the size and contents of the original.
-        // TODO: Create separate tests for RGB and RGBA data once
-        // ASTC and ETC1 decompression is implemented.
-        if (SkTextureCompressor::kASTC_12x12_Format == fmt ||
-            SkTextureCompressor::kETC1_Format == fmt) {
+        if (!decompresses_a8(fmt) || !compresses_a8(fmt)) {
             continue;
         }
 
diff --git a/third_party/ktx/ktx.cpp b/third_party/ktx/ktx.cpp
index ebcc5eb..d62833f 100644
--- a/third_party/ktx/ktx.cpp
+++ b/third_party/ktx/ktx.cpp
@@ -19,15 +19,41 @@
 static inline uint32_t compressed_fmt_to_gl_define(SkTextureCompressor::Format fmt) {
     static const uint32_t kGLDefineMap[SkTextureCompressor::kFormatCnt] = {
         GR_GL_COMPRESSED_LUMINANCE_LATC1,  // kLATC_Format
-        GR_GL_COMPRESSED_R11,  // kR11_EAC_Format
-        GR_GL_COMPRESSED_RGB8_ETC1,  // kETC1_Format
+        GR_GL_COMPRESSED_R11,              // kR11_EAC_Format
+        GR_GL_COMPRESSED_RGB8_ETC1,        // kETC1_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_4x4,    // kASTC_4x4_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_5x4,    // kASTC_5x4_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_5x5,    // kASTC_5x5_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_6x5,    // kASTC_6x5_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_6x6,    // kASTC_6x6_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_8x5,    // kASTC_8x5_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_8x6,    // kASTC_8x6_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_8x8,    // kASTC_8x8_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_10x5,   // kASTC_10x5_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_10x6,   // kASTC_10x6_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_10x8,   // kASTC_10x8_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_10x10,  // kASTC_10x10_Format
+        GR_GL_COMPRESSED_RGBA_ASTC_12x10,  // kASTC_12x10_Format
         GR_GL_COMPRESSED_RGBA_ASTC_12x12,  // kASTC_12x12_Format
     };
 
     GR_STATIC_ASSERT(0 == SkTextureCompressor::kLATC_Format);
     GR_STATIC_ASSERT(1 == SkTextureCompressor::kR11_EAC_Format);
     GR_STATIC_ASSERT(2 == SkTextureCompressor::kETC1_Format);
-    GR_STATIC_ASSERT(3 == SkTextureCompressor::kASTC_12x12_Format);
+    GR_STATIC_ASSERT(3 == SkTextureCompressor::kASTC_4x4_Format);
+    GR_STATIC_ASSERT(4 == SkTextureCompressor::kASTC_5x4_Format);
+    GR_STATIC_ASSERT(5 == SkTextureCompressor::kASTC_5x5_Format);
+    GR_STATIC_ASSERT(6 == SkTextureCompressor::kASTC_6x5_Format);
+    GR_STATIC_ASSERT(7 == SkTextureCompressor::kASTC_6x6_Format);
+    GR_STATIC_ASSERT(8 == SkTextureCompressor::kASTC_8x5_Format);
+    GR_STATIC_ASSERT(9 == SkTextureCompressor::kASTC_8x6_Format);
+    GR_STATIC_ASSERT(10 == SkTextureCompressor::kASTC_8x8_Format);
+    GR_STATIC_ASSERT(11 == SkTextureCompressor::kASTC_10x5_Format);
+    GR_STATIC_ASSERT(12 == SkTextureCompressor::kASTC_10x6_Format);
+    GR_STATIC_ASSERT(13 == SkTextureCompressor::kASTC_10x8_Format);
+    GR_STATIC_ASSERT(14 == SkTextureCompressor::kASTC_10x10_Format);
+    GR_STATIC_ASSERT(15 == SkTextureCompressor::kASTC_12x10_Format);
+    GR_STATIC_ASSERT(16 == SkTextureCompressor::kASTC_12x12_Format);
     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kGLDefineMap) == SkTextureCompressor::kFormatCnt);
 
     return kGLDefineMap[fmt];