Split SkBmpCodec into three separate classes

Will regress behavior on gold on test32bfv4.bmp, where we
will no longer fix transparent decodes.

TODO: Start fixing transparent decodes again, or decide
that we don't want to fix them and remove isTransparent
from SkSwizzler.  I think this may become more clear when I
start implementing the scanline decoder.

BUG=skia:

Review URL: https://codereview.chromium.org/1258863008
diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp
index a1f1569..4383382 100644
--- a/src/codec/SkBmpCodec.cpp
+++ b/src/codec/SkBmpCodec.cpp
@@ -6,93 +6,55 @@
  */
 
 #include "SkBmpCodec.h"
+#include "SkBmpMaskCodec.h"
+#include "SkBmpRLECodec.h"
+#include "SkBmpStandardCodec.h"
 #include "SkCodecPriv.h"
 #include "SkColorPriv.h"
 #include "SkStream.h"
 
 /*
- *
- * Checks if the conversion between the input image and the requested output
- * image has been implemented
- *
- */
-static bool conversion_possible(const SkImageInfo& dst,
-                                const SkImageInfo& src) {
-    // Ensure that the profile type is unchanged
-    if (dst.profileType() != src.profileType()) {
-        return false;
-    }
-
-    // Check for supported alpha types
-    if (src.alphaType() != dst.alphaType()) {
-        if (kOpaque_SkAlphaType == src.alphaType()) {
-            // If the source is opaque, we must decode to opaque
-            return false;
-        }
-
-        // The source is not opaque
-        switch (dst.alphaType()) {
-            case kPremul_SkAlphaType:
-            case kUnpremul_SkAlphaType:
-                // The source is not opaque, so either of these is okay
-                break;
-            default:
-                // We cannot decode a non-opaque image to opaque (or unknown)
-                return false;
-        }
-    }
-
-    // Check for supported color types
-    switch (dst.colorType()) {
-        // Allow output to kN32 from any type of input
-        case kN32_SkColorType:
-            return true;
-        // Allow output to kIndex_8 from compatible inputs
-        case kIndex_8_SkColorType:
-            return kIndex_8_SkColorType == src.colorType();
-        default:
-            return false;
-    }
-}
-
-/*
- *
  * Defines the version and type of the second bitmap header
- *
  */
-enum BitmapHeaderType {
-    kInfoV1_BitmapHeaderType,
-    kInfoV2_BitmapHeaderType,
-    kInfoV3_BitmapHeaderType,
-    kInfoV4_BitmapHeaderType,
-    kInfoV5_BitmapHeaderType,
-    kOS2V1_BitmapHeaderType,
-    kOS2VX_BitmapHeaderType,
-    kUnknown_BitmapHeaderType
+enum BmpHeaderType {
+    kInfoV1_BmpHeaderType,
+    kInfoV2_BmpHeaderType,
+    kInfoV3_BmpHeaderType,
+    kInfoV4_BmpHeaderType,
+    kInfoV5_BmpHeaderType,
+    kOS2V1_BmpHeaderType,
+    kOS2VX_BmpHeaderType,
+    kUnknown_BmpHeaderType
 };
 
 /*
- *
  * Possible bitmap compression types
- *
  */
-enum BitmapCompressionMethod {
-    kNone_BitmapCompressionMethod =          0,
-    k8BitRLE_BitmapCompressionMethod =       1,
-    k4BitRLE_BitmapCompressionMethod =       2,
-    kBitMasks_BitmapCompressionMethod =      3,
-    kJpeg_BitmapCompressionMethod =          4,
-    kPng_BitmapCompressionMethod =           5,
-    kAlphaBitMasks_BitmapCompressionMethod = 6,
-    kCMYK_BitmapCompressionMethod =          11,
-    kCMYK8BitRLE_BitmapCompressionMethod =   12,
-    kCMYK4BitRLE_BitmapCompressionMethod =   13
+enum BmpCompressionMethod {
+    kNone_BmpCompressionMethod =          0,
+    k8BitRLE_BmpCompressionMethod =       1,
+    k4BitRLE_BmpCompressionMethod =       2,
+    kBitMasks_BmpCompressionMethod =      3,
+    kJpeg_BmpCompressionMethod =          4,
+    kPng_BmpCompressionMethod =           5,
+    kAlphaBitMasks_BmpCompressionMethod = 6,
+    kCMYK_BmpCompressionMethod =          11,
+    kCMYK8BitRLE_BmpCompressionMethod =   12,
+    kCMYK4BitRLE_BmpCompressionMethod =   13
 };
 
 /*
- *
+ * Used to define the input format of the bmp
+ */
+enum BmpInputFormat {
+    kStandard_BmpInputFormat,
+    kRLE_BmpInputFormat,
+    kBitMask_BmpInputFormat,
+    kUnknown_BmpInputFormat
+};
+
+/*
  * Checks the start of the stream to see if the image is a bitmap
- *
  */
 bool SkBmpCodec::IsBmp(SkStream* stream) {
     // TODO: Support "IC", "PT", "CI", "CP", "BA"
@@ -103,35 +65,29 @@
 }
 
 /*
- *
  * Assumes IsBmp was called and returned true
  * Creates a bmp decoder
  * Reads enough of the stream to determine the image format
- *
  */
 SkCodec* SkBmpCodec::NewFromStream(SkStream* stream) {
     return SkBmpCodec::NewFromStream(stream, false);
 }
 
 /*
- *
  * Creates a bmp decoder for a bmp embedded in ico
  * Reads enough of the stream to determine the image format
- *
  */
 SkCodec* SkBmpCodec::NewFromIco(SkStream* stream) {
     return SkBmpCodec::NewFromStream(stream, true);
 }
 
 /*
- *
  * Read enough of the stream to initialize the SkBmpCodec. Returns a bool
  * representing success or failure. If it returned true, and codecOut was
  * not NULL, it will be set to a new SkBmpCodec.
  * Does *not* take ownership of the passed in SkStream.
- *
  */
-bool SkBmpCodec::ReadHeader(SkStream* stream, bool isIco, SkCodec** codecOut) {
+bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) {
     // Header size constants
     static const uint32_t kBmpHeaderBytes = 14;
     static const uint32_t kBmpHeaderBytesPlusFour = kBmpHeaderBytes + 4;
@@ -155,7 +111,7 @@
     uint32_t infoBytes;
 
     // Bmps embedded in Icos skip the first Bmp header
-    if (!isIco) {
+    if (!inIco) {
         // Read the first header and the size of the second header
         SkAutoTDeleteArray<uint8_t> hBuffer(
                 SkNEW_ARRAY(uint8_t, kBmpHeaderBytesPlusFour));
@@ -220,7 +176,7 @@
     uint16_t bitsPerPixel;
 
     // The compression method for the pixel data
-    uint32_t compression = kNone_BitmapCompressionMethod;
+    uint32_t compression = kNone_BmpCompressionMethod;
 
     // Number of colors in the color table, defaults to 0 or max (see below)
     uint32_t numColors = 0;
@@ -232,24 +188,24 @@
     int width, height;
 
     // Determine image information depending on second header format
-    BitmapHeaderType headerType;
+    BmpHeaderType headerType;
     if (infoBytes >= kBmpInfoBaseBytes) {
         // Check the version of the header
         switch (infoBytes) {
             case kBmpInfoV1Bytes:
-                headerType = kInfoV1_BitmapHeaderType;
+                headerType = kInfoV1_BmpHeaderType;
                 break;
             case kBmpInfoV2Bytes:
-                headerType = kInfoV2_BitmapHeaderType;
+                headerType = kInfoV2_BmpHeaderType;
                 break;
             case kBmpInfoV3Bytes:
-                headerType = kInfoV3_BitmapHeaderType;
+                headerType = kInfoV3_BmpHeaderType;
                 break;
             case kBmpInfoV4Bytes:
-                headerType = kInfoV4_BitmapHeaderType;
+                headerType = kInfoV4_BmpHeaderType;
                 break;
             case kBmpInfoV5Bytes:
-                headerType = kInfoV5_BitmapHeaderType;
+                headerType = kInfoV5_BmpHeaderType;
                 break;
             case 16:
             case 20:
@@ -262,7 +218,7 @@
             case 48:
             case 60:
             case kBmpOS2V2Bytes:
-                headerType = kOS2VX_BitmapHeaderType;
+                headerType = kOS2VX_BmpHeaderType;
                 break;
             default:
                 // We do not signal an error here because there is the
@@ -271,7 +227,7 @@
                 // build off of the older versions, so we may still be able to
                 // decode the bmp.
                 SkCodecPrintf("Warning: unknown bmp header format.\n");
-                headerType = kUnknown_BitmapHeaderType;
+                headerType = kUnknown_BmpHeaderType;
                 break;
         }
         // We check the size of the header before entering the if statement.
@@ -296,7 +252,7 @@
         bytesPerColor = 4;
     } else if (infoBytes >= kBmpOS2V1Bytes) {
         // The OS2V1 is treated separately because it has a unique format
-        headerType = kOS2V1_BitmapHeaderType;
+        headerType = kOS2V1_BmpHeaderType;
         width = (int) get_short(iBuffer.get(), 0);
         height = (int) get_short(iBuffer.get(), 2);
         bitsPerPixel = get_short(iBuffer.get(), 6);
@@ -315,7 +271,7 @@
     }
     // The height field for bmp in ico is double the actual height because they
     // contain an XOR mask followed by an AND mask
-    if (isIco) {
+    if (inIco) {
         height /= 2;
     }
     if (width <= 0 || height <= 0) {
@@ -331,31 +287,31 @@
 
     // Determine the input compression format and set bit masks if necessary
     uint32_t maskBytes = 0;
-    BitmapInputFormat inputFormat = kUnknown_BitmapInputFormat;
+    BmpInputFormat inputFormat = kUnknown_BmpInputFormat;
     switch (compression) {
-        case kNone_BitmapCompressionMethod:
-            inputFormat = kStandard_BitmapInputFormat;
+        case kNone_BmpCompressionMethod:
+            inputFormat = kStandard_BmpInputFormat;
             break;
-        case k8BitRLE_BitmapCompressionMethod:
+        case k8BitRLE_BmpCompressionMethod:
             if (bitsPerPixel != 8) {
                 SkCodecPrintf("Warning: correcting invalid bitmap format.\n");
                 bitsPerPixel = 8;
             }
-            inputFormat = kRLE_BitmapInputFormat;
+            inputFormat = kRLE_BmpInputFormat;
             break;
-        case k4BitRLE_BitmapCompressionMethod:
+        case k4BitRLE_BmpCompressionMethod:
             if (bitsPerPixel != 4) {
                 SkCodecPrintf("Warning: correcting invalid bitmap format.\n");
                 bitsPerPixel = 4;
             }
-            inputFormat = kRLE_BitmapInputFormat;
+            inputFormat = kRLE_BmpInputFormat;
             break;
-        case kAlphaBitMasks_BitmapCompressionMethod:
-        case kBitMasks_BitmapCompressionMethod:
+        case kAlphaBitMasks_BmpCompressionMethod:
+        case kBitMasks_BmpCompressionMethod:
             // Load the masks
-            inputFormat = kBitMask_BitmapInputFormat;
+            inputFormat = kBitMask_BmpInputFormat;
             switch (headerType) {
-                case kInfoV1_BitmapHeaderType: {
+                case kInfoV1_BmpHeaderType: {
                     // The V1 header stores the bit masks after the header
                     SkAutoTDeleteArray<uint8_t> mBuffer(
                             SkNEW_ARRAY(uint8_t, kBmpMaskBytes));
@@ -370,10 +326,10 @@
                     inputMasks.blue = get_int(mBuffer.get(), 8);
                     break;
                 }
-                case kInfoV2_BitmapHeaderType:
-                case kInfoV3_BitmapHeaderType:
-                case kInfoV4_BitmapHeaderType:
-                case kInfoV5_BitmapHeaderType:
+                case kInfoV2_BmpHeaderType:
+                case kInfoV3_BmpHeaderType:
+                case kInfoV4_BmpHeaderType:
+                case kInfoV5_BmpHeaderType:
                     // Header types are matched based on size.  If the header
                     // is V2+, we are guaranteed to be able to read at least
                     // this size.
@@ -382,7 +338,7 @@
                     inputMasks.green = get_int(iBuffer.get(), 40);
                     inputMasks.blue = get_int(iBuffer.get(), 44);
                     break;
-                case kOS2VX_BitmapHeaderType:
+                case kOS2VX_BmpHeaderType:
                     // TODO: Decide if we intend to support this.
                     //       It is unsupported in the previous version and
                     //       in chromium.  I have not come across a test case
@@ -394,21 +350,21 @@
                    return false;
             }
             break;
-        case kJpeg_BitmapCompressionMethod:
+        case kJpeg_BmpCompressionMethod:
             if (24 == bitsPerPixel) {
-                inputFormat = kRLE_BitmapInputFormat;
+                inputFormat = kRLE_BmpInputFormat;
                 break;
             }
             // Fall through
-        case kPng_BitmapCompressionMethod:
+        case kPng_BmpCompressionMethod:
             // TODO: Decide if we intend to support this.
             //       It is unsupported in the previous version and
             //       in chromium.  I think it is used mostly for printers.
             SkCodecPrintf("Error: compression format not supported.\n");
             return false;
-        case kCMYK_BitmapCompressionMethod:
-        case kCMYK8BitRLE_BitmapCompressionMethod:
-        case kCMYK4BitRLE_BitmapCompressionMethod:
+        case kCMYK_BmpCompressionMethod:
+        case kCMYK8BitRLE_BmpCompressionMethod:
+        case kCMYK4BitRLE_BmpCompressionMethod:
             // TODO: Same as above.
             SkCodecPrintf("Error: CMYK not supported for bitmap decoding.\n");
             return false;
@@ -427,9 +383,9 @@
     // out to be fully transparent.
     // As an exception, V3 bmp-in-ico may use an alpha mask.
     SkAlphaType alphaType = kOpaque_SkAlphaType;
-    if ((kInfoV3_BitmapHeaderType == headerType && isIco) ||
-            kInfoV4_BitmapHeaderType == headerType ||
-            kInfoV5_BitmapHeaderType == headerType) {
+    if ((kInfoV3_BmpHeaderType == headerType && inIco) ||
+            kInfoV4_BmpHeaderType == headerType ||
+            kInfoV5_BmpHeaderType == headerType) {
         // Header types are matched based on size.  If the header is
         // V3+, we are guaranteed to be able to read at least this size.
         SkASSERT(infoBytesRemaining > 52);
@@ -443,7 +399,7 @@
     // Additionally, 32 bit bmp-in-icos use the alpha channel.
     // And, RLE inputs may skip pixels, leaving them as transparent.  This
     // is uncommon, but we cannot be certain that an RLE bmp will be opaque.
-    if ((isIco && 32 == bitsPerPixel) || (kRLE_BitmapInputFormat == inputFormat)) {
+    if ((inIco && 32 == bitsPerPixel) || (kRLE_BmpInputFormat == inputFormat)) {
         alphaType = kUnpremul_SkAlphaType;
     }
 
@@ -458,11 +414,11 @@
         // which does not map well to any Skia color formats.  For this reason,
         // we will always enable mask mode with 16 bits per pixel.
         case 16:
-            if (kBitMask_BitmapInputFormat != inputFormat) {
+            if (kBitMask_BmpInputFormat != inputFormat) {
                 inputMasks.red = 0x7C00;
                 inputMasks.green = 0x03E0;
                 inputMasks.blue = 0x001F;
-                inputFormat = kBitMask_BitmapInputFormat;
+                inputFormat = kBitMask_BmpInputFormat;
             }
             break;
         // We want to decode to kIndex_8 for input formats that are already
@@ -474,7 +430,7 @@
             // However, we cannot in RLE format since we may need to leave some
             // pixels as transparent.  Similarly, we also cannot for ICO images
             // since we may need to apply a transparent mask.
-            if (kRLE_BitmapInputFormat != inputFormat && !isIco) {
+            if (kRLE_BmpInputFormat != inputFormat && !inIco) {
                 colorType = kIndex_8_SkColorType;
             }
         case 24:
@@ -494,7 +450,7 @@
     }
 
     // Check for a valid number of total bytes when in RLE mode
-    if (totalBytes <= offset && kRLE_BitmapInputFormat == inputFormat) {
+    if (totalBytes <= offset && kRLE_BmpInputFormat == inputFormat) {
         SkCodecPrintf("Error: RLE requires valid input size.\n");
         return false;
     }
@@ -502,36 +458,65 @@
 
     // Calculate the number of bytes read so far
     const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes;
-    if (!isIco && offset < bytesRead) {
+    if (!inIco && offset < bytesRead) {
         SkCodecPrintf("Error: pixel data offset less than header size.\n");
         return false;
     }
 
     if (codecOut) {
-        // Return the codec
-        // We will use ImageInfo to store width, height, suggested color type, and
-        // suggested alpha type.
+        // Set the image info
         const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
                 colorType, alphaType);
-        *codecOut = SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel,
-                                            inputFormat, masks.detach(),
-                                            numColors, bytesPerColor,
-                                            offset - bytesRead, rowOrder,
-                                            RLEBytes, isIco));
+
+        // Return the codec
+        switch (inputFormat) {
+            case kStandard_BmpInputFormat:
+                *codecOut = SkNEW_ARGS(SkBmpStandardCodec, (imageInfo, stream,
+                        bitsPerPixel, numColors, bytesPerColor,
+                        offset - bytesRead, rowOrder, inIco));
+                return true;
+            case kBitMask_BmpInputFormat:
+                // Bmp-in-Ico must be standard mode
+                if (inIco) {
+                    return false;
+                }
+                // Skip to the start of the pixel array.
+                // We can do this here because there is no color table to read
+                // in bit mask mode.
+                if (stream->skip(offset - bytesRead) != offset - bytesRead) {
+                    SkCodecPrintf("Error: unable to skip to image data.\n");
+                    return false;
+                }
+
+                *codecOut = SkNEW_ARGS(SkBmpMaskCodec, (imageInfo, stream,
+                        bitsPerPixel, masks.detach(), rowOrder));
+                return true;
+            case kRLE_BmpInputFormat:
+                // Bmp-in-Ico must be standard mode
+                if (inIco) {
+                    return false;
+                }
+                *codecOut = SkNEW_ARGS(SkBmpRLECodec, (
+                        imageInfo, stream, bitsPerPixel, numColors,
+                        bytesPerColor, offset - bytesRead, rowOrder, RLEBytes));
+                return true;
+            default:
+                SkASSERT(false);
+                return false;
+        }
     }
+
     return true;
 }
 
 /*
- *
  * Creates a bmp decoder
  * Reads enough of the stream to determine the image format
- *
  */
-SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool isIco) {
+SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) {
     SkAutoTDelete<SkStream> streamDeleter(stream);
     SkCodec* codec = NULL;
-    if (ReadHeader(stream, isIco, &codec)) {
+    if (ReadHeader(stream, inIco, &codec)) {
         // codec has taken ownership of stream, so we do not need to
         // delete it.
         SkASSERT(codec);
@@ -541,695 +526,48 @@
     return NULL;
 }
 
-/*
- *
- * Creates an instance of the decoder
- * Called only by NewFromStream
- *
- */
 SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream,
-                       uint16_t bitsPerPixel, BitmapInputFormat inputFormat,
-                       SkMasks* masks, uint32_t numColors,
-                       uint32_t bytesPerColor, uint32_t offset,
-                       RowOrder rowOrder, size_t RLEBytes, bool isIco)
+        uint16_t bitsPerPixel, RowOrder rowOrder)
     : INHERITED(info, stream)
     , fBitsPerPixel(bitsPerPixel)
-    , fInputFormat(inputFormat)
-    , fMasks(masks)
-    , fColorTable(NULL)
-    , fNumColors(numColors)
-    , fBytesPerColor(bytesPerColor)
-    , fOffset(offset)
     , fRowOrder(rowOrder)
-    , fRLEBytes(RLEBytes)
-    , fIsIco(isIco)
-
 {}
 
 /*
- *
- * Initiates the bitmap decode
- *
+ * Rewinds the image stream if necessary
  */
-SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo,
-                                        void* dst, size_t dstRowBytes,
-                                        const Options& opts,
-                                        SkPMColor* inputColorPtr,
-                                        int* inputColorCount) {
-    // Check for proper input and output formats
+bool SkBmpCodec::handleRewind(bool inIco) {
     SkCodec::RewindState rewindState = this->rewindIfNeeded();
     if (rewindState == kCouldNotRewind_RewindState) {
-        return kCouldNotRewind;
+        return false;
     } else if (rewindState == kRewound_RewindState) {
-        if (!ReadHeader(this->stream(), fIsIco, NULL)) {
-            return kCouldNotRewind;
-        }
-    }
-    if (opts.fSubset) {
-        // Subsets are not supported.
-        return kUnimplemented;
-    }
-    if (dstInfo.dimensions() != this->getInfo().dimensions()) {
-        SkCodecPrintf("Error: scaling not supported.\n");
-        return kInvalidScale;
-    }
-    if (!conversion_possible(dstInfo, this->getInfo())) {
-        SkCodecPrintf("Error: cannot convert input type to output type.\n");
-        return kInvalidConversion;
-    }
-
-    // Create the color table if necessary and prepare the stream for decode
-    // Note that if it is non-NULL, inputColorCount will be modified
-    if (!createColorTable(dstInfo.alphaType(), inputColorCount)) {
-        SkCodecPrintf("Error: could not create color table.\n");
-        return kInvalidInput;
-    }
-
-    // Copy the color table to the client if necessary
-    copy_color_table(dstInfo, fColorTable, inputColorPtr, inputColorCount);
-
-    // Perform the decode
-    switch (fInputFormat) {
-        case kBitMask_BitmapInputFormat:
-            return decodeMask(dstInfo, dst, dstRowBytes, opts);
-        case kRLE_BitmapInputFormat:
-            return decodeRLE(dstInfo, dst, dstRowBytes, opts);
-        case kStandard_BitmapInputFormat:
-            return decode(dstInfo, dst, dstRowBytes, opts);
-        default:
-            SkASSERT(false);
-            return kInvalidInput;
-    }
-}
-
-/*
- *
- * Process the color table for the bmp input
- *
- */
- bool SkBmpCodec::createColorTable(SkAlphaType alphaType, int* numColors) {
-    // Allocate memory for color table
-    uint32_t colorBytes = 0;
-    uint32_t maxColors = 0;
-    SkPMColor colorTable[256];
-    if (fBitsPerPixel <= 8) {
-        // Zero is a default for maxColors
-        // Also set fNumColors to maxColors when it is too large
-        maxColors = 1 << fBitsPerPixel;
-        if (fNumColors == 0 || fNumColors >= maxColors) {
-            fNumColors = maxColors;
-        }
-
-        // Inform the caller of the number of colors
-        if (NULL != numColors) {
-            // We set the number of colors to maxColors in order to ensure
-            // safe memory accesses.  Otherwise, an invalid pixel could
-            // access memory outside of our color table array.
-            *numColors = maxColors;
-        }
-
-        // Read the color table from the stream
-        colorBytes = fNumColors * fBytesPerColor;
-        SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes));
-        if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) {
-            SkCodecPrintf("Error: unable to read color table.\n");
-            return false;
-        }
-
-        // Choose the proper packing function
-        SkPMColor (*packARGB) (uint32_t, uint32_t, uint32_t, uint32_t);
-        switch (alphaType) {
-            case kOpaque_SkAlphaType:
-            case kUnpremul_SkAlphaType:
-                packARGB = &SkPackARGB32NoCheck;
-                break;
-            case kPremul_SkAlphaType:
-                packARGB = &SkPreMultiplyARGB;
-                break;
-            default:
-                // This should not be reached because conversion possible
-                // should fail if the alpha type is not one of the above
-                // values.
-                SkASSERT(false);
-                packARGB = NULL;
-                break;
-        }
-
-        // Fill in the color table
-        uint32_t i = 0;
-        for (; i < fNumColors; i++) {
-            uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor);
-            uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1);
-            uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2);
-            uint8_t alpha;
-            if (kOpaque_SkAlphaType == alphaType || kRLE_BitmapInputFormat == fInputFormat) {
-                alpha = 0xFF;
-            } else {
-                alpha = (fMasks->getAlphaMask() >> 24) &
-                        get_byte(cBuffer.get(), i*fBytesPerColor + 3);
-            }
-            colorTable[i] = packARGB(alpha, red, green, blue);
-        }
-
-        // To avoid segmentation faults on bad pixel data, fill the end of the
-        // color table with black.  This is the same the behavior as the
-        // chromium decoder.
-        for (; i < maxColors; i++) {
-            colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0);
-        }
-
-        // Set the color table
-        fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorTable, maxColors)));
-    }
-
-    // Bmp-in-Ico files do not use an offset to indicate where the pixel data
-    // begins.  Pixel data always begins immediately after the color table.
-    if (!fIsIco) {
-        // Check that we have not read past the pixel array offset
-        if(fOffset < colorBytes) {
-            // This may occur on OS 2.1 and other old versions where the color
-            // table defaults to max size, and the bmp tries to use a smaller
-            // color table.  This is invalid, and our decision is to indicate
-            // an error, rather than try to guess the intended size of the
-            // color table.
-            SkCodecPrintf("Error: pixel data offset less than color table size.\n");
-            return false;
-        }
-
-        // After reading the color table, skip to the start of the pixel array
-        if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) {
-            SkCodecPrintf("Error: unable to skip to image data.\n");
+        if (!SkBmpCodec::ReadHeader(this->stream(), inIco, NULL)) {
             return false;
         }
     }
-
-    // Return true on success
     return true;
 }
 
 /*
- *
  * Get the destination row to start filling from
- * Used to fill the remainder of the image on incomplete input
- *
+ * Used to fill the remainder of the image on incomplete input for bmps
+ * This is tricky since bmps may be kTopDown or kBottomUp.  For kTopDown,
+ * we start filling from where we left off, but for kBottomUp we start
+ * filling at the top of the image.
  */
-static inline void* get_dst_start_row(void* dst, size_t dstRowBytes, int32_t y,
-            SkBmpCodec::RowOrder rowOrder) {
-    return (SkBmpCodec::kTopDown_RowOrder == rowOrder) ?
-            SkTAddOffset<void*>(dst, y * dstRowBytes) : dst;
+void* SkBmpCodec::getDstStartRow(void* dst, size_t dstRowBytes, int32_t y) const {
+    return (kTopDown_RowOrder == fRowOrder) ? SkTAddOffset<void*>(dst, y * dstRowBytes) : dst;
 }
 
 /*
- *
- * Performs the bitmap decoding for bit masks input format
- *
+ * Compute the number of colors in the color table
  */
-SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo,
-                                       void* dst, size_t dstRowBytes,
-                                       const Options& opts) {
-    // Set constant values
-    const int width = dstInfo.width();
-    const int height = dstInfo.height();
-    const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel));
-
-    // Allocate a buffer large enough to hold the full image
-    SkAutoTDeleteArray<uint8_t>
-        srcBuffer(SkNEW_ARRAY(uint8_t, height*rowBytes));
-    uint8_t* srcRow = srcBuffer.get();
-
-    // Create the swizzler
-    SkAutoTDelete<SkMaskSwizzler> maskSwizzler(
-            SkMaskSwizzler::CreateMaskSwizzler(dstInfo, fMasks, fBitsPerPixel));
-
-    // Iterate over rows of the image
-    bool transparent = true;
-    for (int y = 0; y < height; y++) {
-        // Read a row of the input
-        if (stream()->read(srcRow, rowBytes) != rowBytes) {
-            SkCodecPrintf("Warning: incomplete input stream.\n");
-            // Fill the destination image on failure
-            SkPMColor fillColor = dstInfo.alphaType() == kOpaque_SkAlphaType ?
-                    SK_ColorBLACK : SK_ColorTRANSPARENT;
-            if (kNo_ZeroInitialized == opts.fZeroInitialized || 0 != fillColor) {
-                void* dstStart = get_dst_start_row(dst, dstRowBytes, y, fRowOrder);
-                SkSwizzler::Fill(dstStart, dstInfo, dstRowBytes, dstInfo.height() - y, fillColor,
-                        NULL);
-            }
-            return kIncompleteInput;
-        }
-
-        // Decode the row in destination format
-        int row = kBottomUp_RowOrder == fRowOrder ? height - 1 - y : y;
-        void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * row);
-        SkSwizzler::ResultAlpha r = maskSwizzler->swizzle(dstRow, srcRow);
-        transparent &= SkSwizzler::IsTransparent(r);
-
-        // Move to the next row
-        srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes);
+uint32_t SkBmpCodec::computeNumColors(uint32_t numColors) {
+    // Zero is a default for maxColors
+    // Also set fNumColors to maxColors when it is too large
+    uint32_t maxColors = 1 << fBitsPerPixel;
+    if (numColors == 0 || numColors >= maxColors) {
+        return maxColors;
     }
-
-    // Some fully transparent bmp images are intended to be opaque.  Here, we
-    // correct for this possibility.
-    if (transparent) {
-        const SkImageInfo& opaqueInfo =
-                dstInfo.makeAlphaType(kOpaque_SkAlphaType);
-        SkAutoTDelete<SkMaskSwizzler> opaqueSwizzler(
-                SkMaskSwizzler::CreateMaskSwizzler(opaqueInfo, fMasks, fBitsPerPixel));
-        srcRow = srcBuffer.get();
-        for (int y = 0; y < height; y++) {
-            // Decode the row in opaque format
-            int row = kBottomUp_RowOrder == fRowOrder ? height - 1 - y : y;
-            void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * row);
-            opaqueSwizzler->swizzle(dstRow, srcRow);
-
-            // Move to the next row
-            srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes);
-        }
-    }
-
-    // Finished decoding the entire image
-    return kSuccess;
-}
-
-/*
- *
- * Set an RLE pixel using the color table
- *
- */
-void SkBmpCodec::setRLEPixel(void* dst, size_t dstRowBytes,
-                             const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
-                             uint8_t index) {
-    // Set the row
-    int height = dstInfo.height();
-    int row;
-    if (kBottomUp_RowOrder == fRowOrder) {
-        row = height - y - 1;
-    } else {
-        row = y;
-    }
-
-    // Set the pixel based on destination color type
-    switch (dstInfo.colorType()) {
-        case kN32_SkColorType: {
-            SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst,
-                    row * (int) dstRowBytes);
-            dstRow[x] = fColorTable->operator[](index);
-            break;
-        }
-        default:
-            // This case should not be reached.  We should catch an invalid
-            // color type when we check that the conversion is possible.
-            SkASSERT(false);
-            break;
-    }
-}
-
-/*
- *
- * Set an RLE pixel from R, G, B values
- *
- */
-void SkBmpCodec::setRLE24Pixel(void* dst, size_t dstRowBytes,
-                               const SkImageInfo& dstInfo, uint32_t x,
-                               uint32_t y, uint8_t red, uint8_t green,
-                               uint8_t blue) {
-    // Set the row
-    int height = dstInfo.height();
-    int row;
-    if (kBottomUp_RowOrder == fRowOrder) {
-        row = height - y - 1;
-    } else {
-        row = y;
-    }
-
-    // Set the pixel based on destination color type
-    switch (dstInfo.colorType()) {
-        case kN32_SkColorType: {
-            SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst,
-                    row * (int) dstRowBytes);
-            dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue);
-            break;
-        }
-        default:
-            // This case should not be reached.  We should catch an invalid
-            // color type when we check that the conversion is possible.
-            SkASSERT(false);
-            break;
-    }
-}
-
-/*
- *
- * Performs the bitmap decoding for RLE input format
- * RLE decoding is performed all at once, rather than a one row at a time
- *
- */
-SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo,
-                                      void* dst, size_t dstRowBytes,
-                                      const Options& opts) {
-    // Set RLE flags
-    static const uint8_t RLE_ESCAPE = 0;
-    static const uint8_t RLE_EOL = 0;
-    static const uint8_t RLE_EOF = 1;
-    static const uint8_t RLE_DELTA = 2;
-
-    // Set constant values
-    const int width = dstInfo.width();
-    const int height = dstInfo.height();
-
-    // Input buffer parameters
-    uint32_t currByte = 0;
-    SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRLEBytes));
-    size_t totalBytes = stream()->read(buffer.get(), fRLEBytes);
-    if (totalBytes < fRLEBytes) {
-        SkCodecPrintf("Warning: incomplete RLE file.\n");
-    } else if (totalBytes <= 0) {
-        SkCodecPrintf("Error: could not read RLE image data.\n");
-        return kInvalidInput;
-    }
-
-    // Destination parameters
-    int x = 0;
-    int y = 0;
-
-    // Set the background as transparent.  Then, if the RLE code skips pixels,
-    // the skipped pixels will be transparent.
-    // Because of the need for transparent pixels, kN32 is the only color
-    // type that makes sense for the destination format.
-    SkASSERT(kN32_SkColorType == dstInfo.colorType());
-    if (kNo_ZeroInitialized == opts.fZeroInitialized) {
-        SkSwizzler::Fill(dst, dstInfo, dstRowBytes, height, SK_ColorTRANSPARENT, NULL);
-    }
-
-    while (true) {
-        // Every entry takes at least two bytes
-        if ((int) totalBytes - currByte < 2) {
-            SkCodecPrintf("Warning: incomplete RLE input.\n");
-            return kIncompleteInput;
-        }
-
-        // Read the next two bytes.  These bytes have different meanings
-        // depending on their values.  In the first interpretation, the first
-        // byte is an escape flag and the second byte indicates what special
-        // task to perform.
-        const uint8_t flag = buffer.get()[currByte++];
-        const uint8_t task = buffer.get()[currByte++];
-
-        // If we have reached a row that is beyond the image size, and the RLE
-        // code does not indicate end of file, abort and signal a warning.
-        if (y >= height && (flag != RLE_ESCAPE || (task != RLE_EOF))) {
-            SkCodecPrintf("Warning: invalid RLE input.\n");
-            return kIncompleteInput;
-        }
-
-        // Perform decoding
-        if (RLE_ESCAPE == flag) {
-            switch (task) {
-                case RLE_EOL:
-                    x = 0;
-                    y++;
-                    break;
-                case RLE_EOF:
-                    return kSuccess;
-                case RLE_DELTA: {
-                    // Two bytes are needed to specify delta
-                    if ((int) totalBytes - currByte < 2) {
-                        SkCodecPrintf("Warning: incomplete RLE input\n");
-                        return kIncompleteInput;
-                    }
-                    // Modify x and y
-                    const uint8_t dx = buffer.get()[currByte++];
-                    const uint8_t dy = buffer.get()[currByte++];
-                    x += dx;
-                    y += dy;
-                    if (x > width || y > height) {
-                        SkCodecPrintf("Warning: invalid RLE input.\n");
-                        return kIncompleteInput;
-                    }
-                    break;
-                }
-                default: {
-                    // If task does not match any of the above signals, it
-                    // indicates that we have a sequence of non-RLE pixels.
-                    // Furthermore, the value of task is equal to the number
-                    // of pixels to interpret.
-                    uint8_t numPixels = task;
-                    const size_t rowBytes = compute_row_bytes(numPixels,
-                            fBitsPerPixel);
-                    // Abort if setting numPixels moves us off the edge of the
-                    // image.  Also abort if there are not enough bytes
-                    // remaining in the stream to set numPixels.
-                    if (x + numPixels > width ||
-                            (int) totalBytes - currByte < SkAlign2(rowBytes)) {
-                        SkCodecPrintf("Warning: invalid RLE input.\n");
-                        return kIncompleteInput;
-                    }
-                    // Set numPixels number of pixels
-                    while (numPixels > 0) {
-                        switch(fBitsPerPixel) {
-                            case 4: {
-                                SkASSERT(currByte < totalBytes);
-                                uint8_t val = buffer.get()[currByte++];
-                                setRLEPixel(dst, dstRowBytes, dstInfo, x++,
-                                        y, val >> 4);
-                                numPixels--;
-                                if (numPixels != 0) {
-                                    setRLEPixel(dst, dstRowBytes, dstInfo,
-                                            x++, y, val & 0xF);
-                                    numPixels--;
-                                }
-                                break;
-                            }
-                            case 8:
-                                SkASSERT(currByte < totalBytes);
-                                setRLEPixel(dst, dstRowBytes, dstInfo, x++,
-                                        y, buffer.get()[currByte++]);
-                                numPixels--;
-                                break;
-                            case 24: {
-                                SkASSERT(currByte + 2 < totalBytes);
-                                uint8_t blue = buffer.get()[currByte++];
-                                uint8_t green = buffer.get()[currByte++];
-                                uint8_t red = buffer.get()[currByte++];
-                                setRLE24Pixel(dst, dstRowBytes, dstInfo,
-                                            x++, y, red, green, blue);
-                                numPixels--;
-                            }
-                            default:
-                                SkASSERT(false);
-                                return kInvalidInput;
-                        }
-                    }
-                    // Skip a byte if necessary to maintain alignment
-                    if (!SkIsAlign2(rowBytes)) {
-                        currByte++;
-                    }
-                    break;
-                }
-            }
-        } else {
-            // If the first byte read is not a flag, it indicates the number of
-            // pixels to set in RLE mode.
-            const uint8_t numPixels = flag;
-            const int endX = SkTMin<int>(x + numPixels, width);
-
-            if (24 == fBitsPerPixel) {
-                // In RLE24, the second byte read is part of the pixel color.
-                // There are two more required bytes to finish encoding the
-                // color.
-                if ((int) totalBytes - currByte < 2) {
-                    SkCodecPrintf("Warning: incomplete RLE input\n");
-                    return kIncompleteInput;
-                }
-
-                // Fill the pixels up to endX with the specified color
-                uint8_t blue = task;
-                uint8_t green = buffer.get()[currByte++];
-                uint8_t red = buffer.get()[currByte++];
-                while (x < endX) {
-                    setRLE24Pixel(dst, dstRowBytes, dstInfo, x++, y, red,
-                            green, blue);
-                }
-            } else {
-                // In RLE8 or RLE4, the second byte read gives the index in the
-                // color table to look up the pixel color.
-                // RLE8 has one color index that gets repeated
-                // RLE4 has two color indexes in the upper and lower 4 bits of
-                // the bytes, which are alternated
-                uint8_t indices[2] = { task, task };
-                if (4 == fBitsPerPixel) {
-                    indices[0] >>= 4;
-                    indices[1] &= 0xf;
-                }
-
-                // Set the indicated number of pixels
-                for (int which = 0; x < endX; x++) {
-                    setRLEPixel(dst, dstRowBytes, dstInfo, x, y,
-                            indices[which]);
-                    which = !which;
-                }
-            }
-        }
-    }
-}
-
-/*
- *
- * Performs the bitmap decoding for standard input format
- *
- */
-SkCodec::Result SkBmpCodec::decode(const SkImageInfo& dstInfo,
-                                   void* dst, size_t dstRowBytes,
-                                   const Options& opts) {
-    // Set constant values
-    const int width = dstInfo.width();
-    const int height = dstInfo.height();
-    const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel));
-
-    // Get swizzler configuration and choose the fill value for failures.  We will use
-    // zero as the default palette index, black for opaque images, and transparent for
-    // non-opaque images.
-    SkSwizzler::SrcConfig config;
-    uint32_t fillColorOrIndex;
-    bool zeroFill = true;
-    switch (fBitsPerPixel) {
-        case 1:
-            config = SkSwizzler::kIndex1;
-            fillColorOrIndex = 0;
-            break;
-        case 2:
-            config = SkSwizzler::kIndex2;
-            fillColorOrIndex = 0;
-            break;
-        case 4:
-            config = SkSwizzler::kIndex4;
-            fillColorOrIndex = 0;
-            break;
-        case 8:
-            config = SkSwizzler::kIndex;
-            fillColorOrIndex = 0;
-            break;
-        case 24:
-            config = SkSwizzler::kBGR;
-            fillColorOrIndex = SK_ColorBLACK;
-            zeroFill = false;
-            break;
-        case 32:
-            if (kOpaque_SkAlphaType == dstInfo.alphaType()) {
-                config = SkSwizzler::kBGRX;
-                fillColorOrIndex = SK_ColorBLACK;
-                zeroFill = false;
-            } else {
-                config = SkSwizzler::kBGRA;
-                fillColorOrIndex = SK_ColorTRANSPARENT;
-            }
-            break;
-        default:
-            SkASSERT(false);
-            return kInvalidInput;
-    }
-
-    // Get a pointer to the color table if it exists
-    const SkPMColor* colorPtr = NULL != fColorTable.get() ? fColorTable->readColors() : NULL;
-
-    // Create swizzler
-    SkAutoTDelete<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(config,
-            colorPtr, dstInfo, kNo_ZeroInitialized));
-
-    // Allocate space for a row buffer and a source for the swizzler
-    SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes));
-
-    // Iterate over rows of the image
-    // FIXME: bool transparent = true;
-    for (int y = 0; y < height; y++) {
-        // Read a row of the input
-        if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) {
-            SkCodecPrintf("Warning: incomplete input stream.\n");
-            // Fill the destination image on failure
-            if (kNo_ZeroInitialized == opts.fZeroInitialized || !zeroFill) {
-                void* dstStart = get_dst_start_row(dst, dstRowBytes, y, fRowOrder);
-                SkSwizzler::Fill(dstStart, dstInfo, dstRowBytes, dstInfo.height() - y,
-                        fillColorOrIndex, colorPtr);
-            }
-            return kIncompleteInput;
-        }
-
-        // Decode the row in destination format
-        uint32_t row;
-        if (kTopDown_RowOrder == fRowOrder) {
-            row = y;
-        } else {
-            row = height - 1 - y;
-        }
-
-        void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * row);
-        swizzler->swizzle(dstRow, srcBuffer.get());
-        // FIXME: SkSwizzler::ResultAlpha r =
-        //        swizzler->swizzle(dstRow, srcBuffer.get());
-        // FIXME: transparent &= SkSwizzler::IsTransparent(r);
-    }
-
-    // FIXME: This code exists to match the behavior in the chromium decoder
-    // and to follow the bmp specification as it relates to alpha masks.  It is
-    // commented out because we have yet to discover a test image that provides
-    // an alpha mask and uses this decode mode.
-
-    // Now we adjust the output image with some additional behavior that
-    // SkSwizzler does not support.  Firstly, all bmp images that contain
-    // alpha are masked by the alpha mask.  Secondly, many fully transparent
-    // bmp images are intended to be opaque.  Here, we make those corrections
-    // in the kN32 case.
-    /*
-    SkPMColor* dstRow = (SkPMColor*) dst;
-    if (SkSwizzler::kBGRA == config) {
-        for (int y = 0; y < height; y++) {
-            for (int x = 0; x < width; x++) {
-                if (transparent) {
-                    dstRow[x] |= 0xFF000000;
-                } else {
-                    dstRow[x] &= alphaMask;
-                }
-                dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes);
-            }
-        }
-    }
-    */
-
-    // Finally, apply the AND mask for bmp-in-ico images
-    if (fIsIco) {
-        // The AND mask is always 1 bit per pixel
-        const size_t rowBytes = SkAlign4(compute_row_bytes(width, 1));
-
-        SkPMColor* dstPtr = (SkPMColor*) dst;
-        for (int y = 0; y < height; y++) {
-            // The srcBuffer will at least be large enough
-            if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) {
-                SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n");
-                return kIncompleteInput;
-            }
-
-            int row;
-            if (kBottomUp_RowOrder == fRowOrder) {
-                row = height - y - 1;
-            } else {
-                row = y;
-            }
-
-            SkPMColor* dstRow =
-                    SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes);
-
-            for (int x = 0; x < width; x++) {
-                int quotient;
-                int modulus;
-                SkTDivMod(x, 8, &quotient, &modulus);
-                uint32_t shift = 7 - modulus;
-                uint32_t alphaBit =
-                        (srcBuffer.get()[quotient] >> shift) & 0x1;
-                dstRow[x] &= alphaBit - 1;
-            }
-        }
-    }
-
-    // Finished decoding the entire image
-    return kSuccess;
+    return numColors;
 }
diff --git a/src/codec/SkBmpCodec.h b/src/codec/SkBmpCodec.h
index 9909945..51d0300 100644
--- a/src/codec/SkBmpCodec.h
+++ b/src/codec/SkBmpCodec.h
@@ -4,6 +4,8 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+#ifndef SkBmpCodec_DEFINED
+#define SkBmpCodec_DEFINED
 
 #include "SkCodec.h"
 #include "SkColorTable.h"
@@ -13,19 +15,15 @@
 #include "SkSwizzler.h"
 #include "SkTypes.h"
 
-// TODO: rename SkCodec_libbmp files to SkBmpCodec
 /*
- *
- * This class implements the decoding for bmp images
- *
+ * This class enables code sharing between its bmp codec subclasses.  The
+ * subclasses actually do the work.
  */
 class SkBmpCodec : public SkCodec {
 public:
 
     /*
-     *
      * Describes if rows of the input start at the top or bottom of the image
-     *
      */
     enum RowOrder {
         kTopDown_RowOrder,
@@ -33,161 +31,75 @@
     };
 
     /*
-     *
      * Checks the start of the stream to see if the image is a bmp
-     *
      */
     static bool IsBmp(SkStream*);
 
     /*
-     *
      * Assumes IsBmp was called and returned true
      * Creates a bmp decoder
      * Reads enough of the stream to determine the image format
-     *
      */
     static SkCodec* NewFromStream(SkStream*);
 
     /*
-     *
      * Creates a bmp decoder for a bmp embedded in ico
      * Reads enough of the stream to determine the image format
-     *
      */
     static SkCodec* NewFromIco(SkStream*);
 
 protected:
 
-    /*
-     *
-     * Initiates the bmp decode
-     *
-     */
-    Result onGetPixels(const SkImageInfo& dstInfo, void* dst,
-                       size_t dstRowBytes, const Options&, SkPMColor*,
-                       int*) override;
+    SkBmpCodec(const SkImageInfo& info, SkStream* stream, uint16_t bitsPerPixel,
+            RowOrder rowOrder);
 
     SkEncodedFormat onGetEncodedFormat() const override { return kBMP_SkEncodedFormat; }
 
-private:
-
     /*
-     *
-     * Used to define the input format of the bmp
-     *
-     */
-    enum BitmapInputFormat {
-        kStandard_BitmapInputFormat,
-        kRLE_BitmapInputFormat,
-        kBitMask_BitmapInputFormat,
-        kUnknown_BitmapInputFormat
-    };
-
-    /*
-     *
-     * Creates the color table
-     * Sets colorCount to the new color count if it is non-NULL
-     */
-     bool createColorTable(SkAlphaType alphaType, int* colorCount);
-
-    /*
-     *
-     * Creates a bmp decoder
-     * Reads enough of the stream to determine the image format
-     *
-     */
-    static SkCodec* NewFromStream(SkStream*, bool isIco);
-
-    /*
-     *
      * Read enough of the stream to initialize the SkBmpCodec. Returns a bool
      * representing success or failure. If it returned true, and codecOut was
      * not NULL, it will be set to a new SkBmpCodec.
      * Does *not* take ownership of the passed in SkStream.
-     *
      */
-    static bool ReadHeader(SkStream*, bool isIco, SkCodec** codecOut);
+    static bool ReadHeader(SkStream*, bool inIco, SkCodec** codecOut);
 
     /*
-     *
-     * Performs the bitmap decoding for bit masks input format
-     *
+     * Rewinds the image stream if necessary
      */
-    Result decodeMask(const SkImageInfo& dstInfo, void* dst,
-                      size_t dstRowBytes, const Options& opts);
+    bool handleRewind(bool inIco);
 
     /*
-     *
-     * Set an RLE pixel using the color table
-     *
+     * Get the destination row to start filling from
+     * Used to fill the remainder of the image on incomplete input for bmps
+     * This is tricky since bmps may be kTopDown or kBottomUp.  For kTopDown,
+     * we start filling from where we left off, but for kBottomUp we start
+     * filling at the top of the image.
      */
-    void setRLEPixel(void* dst, size_t dstRowBytes,
-                     const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
-                     uint8_t index);
-    /*
-     *
-     * Set an RLE24 pixel from R, G, B values
-     *
-     */
-    void setRLE24Pixel(void* dst, size_t dstRowBytes,
-                       const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
-                       uint8_t red, uint8_t green, uint8_t blue);
+    void* getDstStartRow(void* dst, size_t dstRowBytes, int32_t y) const;
 
     /*
-     *
-     * Performs the bitmap decoding for RLE input format
-     *
+     * Compute the number of colors in the color table
      */
-    Result decodeRLE(const SkImageInfo& dstInfo, void* dst,
-                     size_t dstRowBytes, const Options& opts);
+    uint32_t computeNumColors(uint32_t numColors);
 
     /*
-     *
-     * Performs the bitmap decoding for standard input format
-     *
+     * Accessors used by subclasses
      */
-    Result decode(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts);
+    uint16_t bitsPerPixel() const { return fBitsPerPixel; }
+    RowOrder rowOrder() const { return fRowOrder; }
+
+private:
 
     /*
-     *
-     * Creates an instance of the decoder
-     * Called only by NewFromStream
-     *
-     * @param srcInfo contains the source width and height
-     * @param stream the stream of image data
-     * @param bitsPerPixel the number of bits used to store each pixel
-     * @param format the format of the bmp file
-     * @param masks optional color masks for certain bmp formats, passes
-                    ownership to SkBmpCodec
-     * @param numColors the number of colors in the color table
-     * @param bytesPerColor the number of bytes in the stream used to represent
-                            each color in the color table
-     * @param offset the offset of the image pixel data from the end of the
-     *               headers
-     * @param rowOrder indicates whether rows are ordered top-down or bottom-up
-     * @param RLEBytes used only for RLE decodes, as we must decode all
-     *                  of the data at once rather than row by row
-     *                  it indicates the amount of data left in the stream
-     *                  after decoding the headers
-     *
+     * Creates a bmp decoder
+     * Reads enough of the stream to determine the image format
      */
-    SkBmpCodec(const SkImageInfo& srcInfo, SkStream* stream,
-               uint16_t bitsPerPixel, BitmapInputFormat format,
-               SkMasks* masks, uint32_t numColors, uint32_t bytesPerColor,
-               uint32_t offset, RowOrder rowOrder, size_t RLEBytes,
-               bool isIco);
+    static SkCodec* NewFromStream(SkStream*, bool inIco);
 
-    // Fields
-    const uint16_t                      fBitsPerPixel;
-    const BitmapInputFormat             fInputFormat;
-    SkAutoTDelete<SkMasks>              fMasks;          // owned
-    SkAutoTUnref<SkColorTable>          fColorTable;     // owned
-    uint32_t                            fNumColors;
-    const uint32_t                      fBytesPerColor;
-    const uint32_t                      fOffset;
-    const RowOrder                      fRowOrder;
-    const size_t                        fRLEBytes;
-    const bool                          fIsIco;
+    const uint16_t fBitsPerPixel;
+    const RowOrder fRowOrder;
 
     typedef SkCodec INHERITED;
 };
+
+#endif
diff --git a/src/codec/SkBmpMaskCodec.cpp b/src/codec/SkBmpMaskCodec.cpp
new file mode 100644
index 0000000..f30266b
--- /dev/null
+++ b/src/codec/SkBmpMaskCodec.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBmpMaskCodec.h"
+#include "SkCodecPriv.h"
+#include "SkColorPriv.h"
+
+/*
+ * Checks if the conversion between the input image and the requested output
+ * image has been implemented
+ */
+static bool conversion_possible(const SkImageInfo& dst,
+                                const SkImageInfo& src) {
+    // Ensure that the profile type is unchanged
+    if (dst.profileType() != src.profileType()) {
+        return false;
+    }
+
+    // Ensure the alpha type is valid
+    if (!valid_alpha(dst.alphaType(), src.alphaType())) {
+        return false;
+    }
+
+    // Check for supported color types
+    switch (dst.colorType()) {
+        // Allow output to kN32
+        case kN32_SkColorType:
+            return true;
+        default:
+            return false;
+    }
+}
+
+
+/*
+ * Creates an instance of the decoder
+ */
+SkBmpMaskCodec::SkBmpMaskCodec(const SkImageInfo& info, SkStream* stream,
+                               uint16_t bitsPerPixel, SkMasks* masks,
+                               SkBmpCodec::RowOrder rowOrder)
+    : INHERITED(info, stream, bitsPerPixel, rowOrder)
+    , fMasks(masks)
+    , fMaskSwizzler(NULL)
+    , fSrcBuffer(NULL)
+{}
+
+/*
+ * Initiates the bitmap decode
+ */
+SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo,
+                                            void* dst, size_t dstRowBytes,
+                                            const Options& opts,
+                                            SkPMColor* inputColorPtr,
+                                            int* inputColorCount) {
+    if (!this->handleRewind(false)) {
+        return kCouldNotRewind;
+    }
+    if (opts.fSubset) {
+        // Subsets are not supported.
+        return kUnimplemented;
+    }
+    if (dstInfo.dimensions() != this->getInfo().dimensions()) {
+        SkCodecPrintf("Error: scaling not supported.\n");
+        return kInvalidScale;
+    }
+
+    if (!conversion_possible(dstInfo, this->getInfo())) {
+        SkCodecPrintf("Error: cannot convert input type to output type.\n");
+        return kInvalidConversion;
+    }
+
+    // Initialize a the mask swizzler
+    if (!this->initializeSwizzler(dstInfo)) {
+        SkCodecPrintf("Error: cannot initialize swizzler.\n");
+        return kInvalidConversion;
+    }
+
+    return this->decode(dstInfo, dst, dstRowBytes, opts);
+}
+
+bool SkBmpMaskCodec::initializeSwizzler(const SkImageInfo& dstInfo) {
+    // Allocate space for a row buffer
+    const size_t rowBytes = SkAlign4(compute_row_bytes(dstInfo.width(), this->bitsPerPixel()));
+    fSrcBuffer.reset(SkNEW_ARRAY(uint8_t, rowBytes));
+
+    // Create the swizzler
+    fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler(
+            dstInfo, fMasks, this->bitsPerPixel()));
+
+    if (NULL == fMaskSwizzler.get()) {
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Performs the decoding
+ */
+SkCodec::Result SkBmpMaskCodec::decode(const SkImageInfo& dstInfo,
+                                       void* dst, size_t dstRowBytes,
+                                       const Options& opts) {
+    // Set constant values
+    const int width = dstInfo.width();
+    const int height = dstInfo.height();
+    const size_t rowBytes = SkAlign4(compute_row_bytes(width, this->bitsPerPixel()));
+
+    // Iterate over rows of the image
+    uint8_t* srcRow = fSrcBuffer.get();
+    for (int y = 0; y < height; y++) {
+        // Read a row of the input
+        if (this->stream()->read(srcRow, rowBytes) != rowBytes) {
+            SkCodecPrintf("Warning: incomplete input stream.\n");
+            // Fill the destination image on failure
+            SkPMColor fillColor = dstInfo.alphaType() == kOpaque_SkAlphaType ?
+                    SK_ColorBLACK : SK_ColorTRANSPARENT;
+            if (kNo_ZeroInitialized == opts.fZeroInitialized || 0 != fillColor) {
+                void* dstStart = this->getDstStartRow(dst, dstRowBytes, y);
+                SkSwizzler::Fill(dstStart, dstInfo, dstRowBytes, dstInfo.height() - y, fillColor,
+                        NULL);
+            }
+            return kIncompleteInput;
+        }
+
+        // Decode the row in destination format
+        int row = SkBmpCodec::kBottomUp_RowOrder == this->rowOrder() ? height - 1 - y : y;
+        void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes);
+        fMaskSwizzler->swizzle(dstRow, srcRow);
+    }
+
+    // Finished decoding the entire image
+    return kSuccess;
+}
diff --git a/src/codec/SkBmpMaskCodec.h b/src/codec/SkBmpMaskCodec.h
new file mode 100644
index 0000000..6f43bb3
--- /dev/null
+++ b/src/codec/SkBmpMaskCodec.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBmpCodec.h"
+#include "SkImageInfo.h"
+#include "SkMaskSwizzler.h"
+#include "SkTypes.h"
+
+/*
+ * This class implements the decoding for bmp images using bit masks
+ */
+class SkBmpMaskCodec : public SkBmpCodec {
+public:
+
+    /*
+     * Creates an instance of the decoder
+     *
+     * Called only by SkBmpCodec::NewFromStream
+     * There should be no other callers despite this being public
+     *
+     * @param srcInfo contains the source width and height
+     * @param stream the stream of encoded image data
+     * @param bitsPerPixel the number of bits used to store each pixel
+     * @param masks color masks for certain bmp formats
+     * @param rowOrder indicates whether rows are ordered top-down or bottom-up
+     */
+    SkBmpMaskCodec(const SkImageInfo& srcInfo, SkStream* stream,
+                   uint16_t bitsPerPixel, SkMasks* masks, RowOrder rowOrder);
+
+protected:
+
+    Result onGetPixels(const SkImageInfo& dstInfo, void* dst,
+                       size_t dstRowBytes, const Options&, SkPMColor*,
+                       int*) override;
+
+private:
+
+    bool initializeSwizzler(const SkImageInfo& dstInfo);
+
+    Result decode(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
+                  const Options& opts);
+
+    SkAutoTDelete<SkMasks>              fMasks;        // owned
+    SkAutoTDelete<SkMaskSwizzler>       fMaskSwizzler;
+    SkAutoTDeleteArray<uint8_t>         fSrcBuffer;
+
+    typedef SkBmpCodec INHERITED;
+};
diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp
new file mode 100644
index 0000000..828871c
--- /dev/null
+++ b/src/codec/SkBmpRLECodec.cpp
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBmpRLECodec.h"
+#include "SkCodecPriv.h"
+#include "SkColorPriv.h"
+#include "SkScanlineDecoder.h"
+#include "SkStream.h"
+
+/*
+ * Checks if the conversion between the input image and the requested output
+ * image has been implemented
+ */
+static bool conversion_possible(const SkImageInfo& dst,
+                                const SkImageInfo& src) {
+    // Ensure that the profile type is unchanged
+    if (dst.profileType() != src.profileType()) {
+        return false;
+    }
+
+    // Ensure the alpha type is valid
+    if (!valid_alpha(dst.alphaType(), src.alphaType())) {
+        return false;
+    }
+
+    // Check for supported color types
+    switch (dst.colorType()) {
+        // Allow output to kN32 from any type of input
+        case kN32_SkColorType:
+            return true;
+        // Allow output to kIndex_8 from compatible inputs
+        case kIndex_8_SkColorType:
+            return kIndex_8_SkColorType == src.colorType();
+        default:
+            return false;
+    }
+}
+
+/*
+ * Creates an instance of the decoder
+ * Called only by NewFromStream
+ */
+SkBmpRLECodec::SkBmpRLECodec(const SkImageInfo& info, SkStream* stream,
+                             uint16_t bitsPerPixel, uint32_t numColors,
+                             uint32_t bytesPerColor, uint32_t offset,
+                             SkBmpCodec::RowOrder rowOrder, size_t RLEBytes)
+    : INHERITED(info, stream, bitsPerPixel, rowOrder)
+    , fColorTable(NULL)
+    , fNumColors(this->computeNumColors(numColors))
+    , fBytesPerColor(bytesPerColor)
+    , fOffset(offset)
+    , fStreamBuffer(SkNEW_ARRAY(uint8_t, RLEBytes))
+    , fRLEBytes(RLEBytes)
+    , fCurrRLEByte(0)
+{}
+
+/*
+ * Initiates the bitmap decode
+ */
+SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo,
+                                        void* dst, size_t dstRowBytes,
+                                        const Options& opts,
+                                        SkPMColor* inputColorPtr,
+                                        int* inputColorCount) {
+    if (!this->handleRewind(false)) {
+        return kCouldNotRewind;
+    }
+    if (opts.fSubset) {
+        // Subsets are not supported.
+        return kUnimplemented;
+    }
+    if (dstInfo.dimensions() != this->getInfo().dimensions()) {
+        SkCodecPrintf("Error: scaling not supported.\n");
+        return kInvalidScale;
+    }
+    if (!conversion_possible(dstInfo, this->getInfo())) {
+        SkCodecPrintf("Error: cannot convert input type to output type.\n");
+        return kInvalidConversion;
+    }
+
+    // Create the color table if necessary and prepare the stream for decode
+    // Note that if it is non-NULL, inputColorCount will be modified
+    if (!this->createColorTable(inputColorCount)) {
+        SkCodecPrintf("Error: could not create color table.\n");
+        return kInvalidInput;
+    }
+
+    // Copy the color table to the client if necessary
+    copy_color_table(dstInfo, fColorTable, inputColorPtr, inputColorCount);
+
+    // Initialize a swizzler if necessary
+    if (!this->initializeStreamBuffer()) {
+        SkCodecPrintf("Error: cannot initialize swizzler.\n");
+        return kInvalidConversion;
+    }
+
+    // Perform the decode
+    return decode(dstInfo, dst, dstRowBytes, opts);
+}
+
+/*
+ * Process the color table for the bmp input
+ */
+ bool SkBmpRLECodec::createColorTable(int* numColors) {
+    // Allocate memory for color table
+    uint32_t colorBytes = 0;
+    SkPMColor colorTable[256];
+    if (this->bitsPerPixel() <= 8) {
+        // Inform the caller of the number of colors
+        uint32_t maxColors = 1 << this->bitsPerPixel();
+        if (NULL != numColors) {
+            // We set the number of colors to maxColors in order to ensure
+            // safe memory accesses.  Otherwise, an invalid pixel could
+            // access memory outside of our color table array.
+            *numColors = maxColors;
+        }
+
+        // Read the color table from the stream
+        colorBytes = fNumColors * fBytesPerColor;
+        SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes));
+        if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) {
+            SkCodecPrintf("Error: unable to read color table.\n");
+            return false;
+        }
+
+        // Fill in the color table
+        uint32_t i = 0;
+        for (; i < fNumColors; i++) {
+            uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor);
+            uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1);
+            uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2);
+            colorTable[i] = SkPackARGB32NoCheck(0xFF, red, green, blue);
+        }
+
+        // To avoid segmentation faults on bad pixel data, fill the end of the
+        // color table with black.  This is the same the behavior as the
+        // chromium decoder.
+        for (; i < maxColors; i++) {
+            colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0);
+        }
+
+        // Set the color table
+        fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorTable, maxColors)));
+    }
+
+    // Check that we have not read past the pixel array offset
+    if(fOffset < colorBytes) {
+        // This may occur on OS 2.1 and other old versions where the color
+        // table defaults to max size, and the bmp tries to use a smaller
+        // color table.  This is invalid, and our decision is to indicate
+        // an error, rather than try to guess the intended size of the
+        // color table.
+        SkCodecPrintf("Error: pixel data offset less than color table size.\n");
+        return false;
+    }
+
+    // After reading the color table, skip to the start of the pixel array
+    if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) {
+        SkCodecPrintf("Error: unable to skip to image data.\n");
+        return false;
+    }
+
+    // Return true on success
+    return true;
+}
+
+bool SkBmpRLECodec::initializeStreamBuffer() {
+    // Setup a buffer to contain the full input stream
+    size_t totalBytes = this->stream()->read(fStreamBuffer.get(), fRLEBytes);
+    if (totalBytes < fRLEBytes) {
+        fRLEBytes = totalBytes;
+        SkCodecPrintf("Warning: incomplete RLE file.\n");
+    }
+    if (fRLEBytes == 0) {
+        SkCodecPrintf("Error: could not read RLE image data.\n");
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Set an RLE pixel using the color table
+ */
+void SkBmpRLECodec::setPixel(void* dst, size_t dstRowBytes,
+                             const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
+                             uint8_t index) {
+    // Set the row
+    int height = dstInfo.height();
+    int row;
+    if (SkBmpCodec::kBottomUp_RowOrder == this->rowOrder()) {
+        row = height - y - 1;
+    } else {
+        row = y;
+    }
+
+    // Set the pixel based on destination color type
+    switch (dstInfo.colorType()) {
+        case kN32_SkColorType: {
+            SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst,
+                    row * (int) dstRowBytes);
+            dstRow[x] = fColorTable->operator[](index);
+            break;
+        }
+        default:
+            // This case should not be reached.  We should catch an invalid
+            // color type when we check that the conversion is possible.
+            SkASSERT(false);
+            break;
+    }
+}
+
+/*
+ * Set an RLE pixel from R, G, B values
+ */
+void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes,
+                                const SkImageInfo& dstInfo, uint32_t x,
+                                uint32_t y, uint8_t red, uint8_t green,
+                                uint8_t blue) {
+    // Set the row
+    int height = dstInfo.height();
+    int row;
+    if (SkBmpCodec::kBottomUp_RowOrder == this->rowOrder()) {
+        row = height - y - 1;
+    } else {
+        row = y;
+    }
+
+    // Set the pixel based on destination color type
+    switch (dstInfo.colorType()) {
+        case kN32_SkColorType: {
+            SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst,
+                    row * (int) dstRowBytes);
+            dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue);
+            break;
+        }
+        default:
+            // This case should not be reached.  We should catch an invalid
+            // color type when we check that the conversion is possible.
+            SkASSERT(false);
+            break;
+    }
+}
+
+/*
+ * Performs the bitmap decoding for RLE input format
+ * RLE decoding is performed all at once, rather than a one row at a time
+ */
+SkCodec::Result SkBmpRLECodec::decode(const SkImageInfo& dstInfo,
+                                      void* dst, size_t dstRowBytes,
+                                      const Options& opts) {
+    // Set RLE flags
+    static const uint8_t RLE_ESCAPE = 0;
+    static const uint8_t RLE_EOL = 0;
+    static const uint8_t RLE_EOF = 1;
+    static const uint8_t RLE_DELTA = 2;
+
+    // Set constant values
+    const int width = dstInfo.width();
+    const int height = dstInfo.height();
+
+    // Destination parameters
+    int x = 0;
+    int y = 0;
+
+    // Set the background as transparent.  Then, if the RLE code skips pixels,
+    // the skipped pixels will be transparent.
+    // Because of the need for transparent pixels, kN32 is the only color
+    // type that makes sense for the destination format.
+    SkASSERT(kN32_SkColorType == dstInfo.colorType());
+    if (kNo_ZeroInitialized == opts.fZeroInitialized) {
+        SkSwizzler::Fill(dst, dstInfo, dstRowBytes, height, SK_ColorTRANSPARENT, NULL);
+    }
+
+    while (true) {
+        // If we have reached a row that is beyond the requested height, we have
+        // succeeded.
+        if (y >= height) {
+            // It would be better to check for the EOF marker before returning
+            // success, but we may be performing a scanline decode, which
+            // may require us to stop before decoding the full height.
+            return kSuccess;
+        }
+
+        // Every entry takes at least two bytes
+        if ((int) fRLEBytes - fCurrRLEByte < 2) {
+            SkCodecPrintf("Warning: incomplete RLE input.\n");
+            return kIncompleteInput;
+        }
+
+        // Read the next two bytes.  These bytes have different meanings
+        // depending on their values.  In the first interpretation, the first
+        // byte is an escape flag and the second byte indicates what special
+        // task to perform.
+        const uint8_t flag = fStreamBuffer.get()[fCurrRLEByte++];
+        const uint8_t task = fStreamBuffer.get()[fCurrRLEByte++];
+
+        // Perform decoding
+        if (RLE_ESCAPE == flag) {
+            switch (task) {
+                case RLE_EOL:
+                    x = 0;
+                    y++;
+                    break;
+                case RLE_EOF:
+                    return kSuccess;
+                case RLE_DELTA: {
+                    // Two bytes are needed to specify delta
+                    if ((int) fRLEBytes - fCurrRLEByte < 2) {
+                        SkCodecPrintf("Warning: incomplete RLE input\n");
+                        return kIncompleteInput;
+                    }
+                    // Modify x and y
+                    const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++];
+                    const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++];
+                    x += dx;
+                    y += dy;
+                    if (x > width || y > height) {
+                        SkCodecPrintf("Warning: invalid RLE input 1.\n");
+                        return kIncompleteInput;
+                    }
+                    break;
+                }
+                default: {
+                    // If task does not match any of the above signals, it
+                    // indicates that we have a sequence of non-RLE pixels.
+                    // Furthermore, the value of task is equal to the number
+                    // of pixels to interpret.
+                    uint8_t numPixels = task;
+                    const size_t rowBytes = compute_row_bytes(numPixels,
+                            this->bitsPerPixel());
+                    // Abort if setting numPixels moves us off the edge of the
+                    // image.  Also abort if there are not enough bytes
+                    // remaining in the stream to set numPixels.
+                    if (x + numPixels > width ||
+                            (int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) {
+                        SkCodecPrintf("Warning: invalid RLE input 2.\n");
+                        return kIncompleteInput;
+                    }
+                    // Set numPixels number of pixels
+                    while (numPixels > 0) {
+                        switch(this->bitsPerPixel()) {
+                            case 4: {
+                                SkASSERT(fCurrRLEByte < fRLEBytes);
+                                uint8_t val = fStreamBuffer.get()[fCurrRLEByte++];
+                                setPixel(dst, dstRowBytes, dstInfo, x++,
+                                        y, val >> 4);
+                                numPixels--;
+                                if (numPixels != 0) {
+                                    setPixel(dst, dstRowBytes, dstInfo,
+                                            x++, y, val & 0xF);
+                                    numPixels--;
+                                }
+                                break;
+                            }
+                            case 8:
+                                SkASSERT(fCurrRLEByte < fRLEBytes);
+                                setPixel(dst, dstRowBytes, dstInfo, x++,
+                                        y, fStreamBuffer.get()[fCurrRLEByte++]);
+                                numPixels--;
+                                break;
+                            case 24: {
+                                SkASSERT(fCurrRLEByte + 2 < fRLEBytes);
+                                uint8_t blue = fStreamBuffer.get()[fCurrRLEByte++];
+                                uint8_t green = fStreamBuffer.get()[fCurrRLEByte++];
+                                uint8_t red = fStreamBuffer.get()[fCurrRLEByte++];
+                                setRGBPixel(dst, dstRowBytes, dstInfo,
+                                            x++, y, red, green, blue);
+                                numPixels--;
+                            }
+                            default:
+                                SkASSERT(false);
+                                return kInvalidInput;
+                        }
+                    }
+                    // Skip a byte if necessary to maintain alignment
+                    if (!SkIsAlign2(rowBytes)) {
+                        fCurrRLEByte++;
+                    }
+                    break;
+                }
+            }
+        } else {
+            // If the first byte read is not a flag, it indicates the number of
+            // pixels to set in RLE mode.
+            const uint8_t numPixels = flag;
+            const int endX = SkTMin<int>(x + numPixels, width);
+
+            if (24 == this->bitsPerPixel()) {
+                // In RLE24, the second byte read is part of the pixel color.
+                // There are two more required bytes to finish encoding the
+                // color.
+                if ((int) fRLEBytes - fCurrRLEByte < 2) {
+                    SkCodecPrintf("Warning: incomplete RLE input\n");
+                    return kIncompleteInput;
+                }
+
+                // Fill the pixels up to endX with the specified color
+                uint8_t blue = task;
+                uint8_t green = fStreamBuffer.get()[fCurrRLEByte++];
+                uint8_t red = fStreamBuffer.get()[fCurrRLEByte++];
+                while (x < endX) {
+                    setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red,
+                            green, blue);
+                }
+            } else {
+                // In RLE8 or RLE4, the second byte read gives the index in the
+                // color table to look up the pixel color.
+                // RLE8 has one color index that gets repeated
+                // RLE4 has two color indexes in the upper and lower 4 bits of
+                // the bytes, which are alternated
+                uint8_t indices[2] = { task, task };
+                if (4 == this->bitsPerPixel()) {
+                    indices[0] >>= 4;
+                    indices[1] &= 0xf;
+                }
+
+                // Set the indicated number of pixels
+                for (int which = 0; x < endX; x++) {
+                    setPixel(dst, dstRowBytes, dstInfo, x, y,
+                            indices[which]);
+                    which = !which;
+                }
+            }
+        }
+    }
+}
diff --git a/src/codec/SkBmpRLECodec.h b/src/codec/SkBmpRLECodec.h
new file mode 100644
index 0000000..f1f1ae9
--- /dev/null
+++ b/src/codec/SkBmpRLECodec.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBmpCodec.h"
+#include "SkColorTable.h"
+#include "SkImageInfo.h"
+#include "SkTypes.h"
+
+/*
+ * This class implements the decoding for bmp images that use an RLE encoding
+ */
+class SkBmpRLECodec : public SkBmpCodec {
+public:
+
+    /*
+     * Creates an instance of the decoder
+     *
+     * Called only by SkBmpCodec::NewFromStream
+     * There should be no other callers despite this being public
+     *
+     * @param srcInfo contains the source width and height
+     * @param stream the stream of encoded image data
+     * @param bitsPerPixel the number of bits used to store each pixel
+     * @param numColors the number of colors in the color table
+     * @param bytesPerColor the number of bytes in the stream used to represent
+                            each color in the color table
+     * @param offset the offset of the image pixel data from the end of the
+     *               headers
+     * @param rowOrder indicates whether rows are ordered top-down or bottom-up
+     * @param RLEBytes indicates the amount of data left in the stream
+     *                 after decoding the headers
+     */
+    SkBmpRLECodec(const SkImageInfo& srcInfo, SkStream* stream,
+                  uint16_t bitsPerPixel, uint32_t numColors,
+                  uint32_t bytesPerColor, uint32_t offset,
+                  SkBmpCodec::RowOrder rowOrder, size_t RLEBytes);
+
+protected:
+
+    Result onGetPixels(const SkImageInfo& dstInfo, void* dst,
+                       size_t dstRowBytes, const Options&, SkPMColor*,
+                       int*) override;
+
+private:
+
+    /*
+     * Creates the color table
+     * Sets colorCount to the new color count if it is non-NULL
+     */
+    bool createColorTable(int* colorCount);
+
+    bool initializeStreamBuffer();
+
+    /*
+     * Set an RLE pixel using the color table
+     */
+    void setPixel(void* dst, size_t dstRowBytes,
+                  const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
+                  uint8_t index);
+    /*
+     * Set an RLE24 pixel from R, G, B values
+     */
+    void setRGBPixel(void* dst, size_t dstRowBytes,
+                     const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
+                     uint8_t red, uint8_t green, uint8_t blue);
+
+    /*
+     * Performs the bitmap decoding for RLE input format
+     */
+    Result decode(const SkImageInfo& dstInfo, void* dst,
+                  size_t dstRowBytes, const Options& opts);
+
+    SkAutoTUnref<SkColorTable>          fColorTable;    // owned
+    const uint32_t                      fNumColors;
+    const uint32_t                      fBytesPerColor;
+    const uint32_t                      fOffset;
+    SkAutoTDeleteArray<uint8_t>         fStreamBuffer;
+    size_t                              fRLEBytes;
+    uint32_t                            fCurrRLEByte;
+
+    typedef SkBmpCodec INHERITED;
+};
diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp
new file mode 100644
index 0000000..70535a7
--- /dev/null
+++ b/src/codec/SkBmpStandardCodec.cpp
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBmpStandardCodec.h"
+#include "SkCodecPriv.h"
+#include "SkColorPriv.h"
+#include "SkScanlineDecoder.h"
+#include "SkStream.h"
+
+/*
+ * Checks if the conversion between the input image and the requested output
+ * image has been implemented
+ */
+static bool conversion_possible(const SkImageInfo& dst,
+                                const SkImageInfo& src) {
+    // Ensure that the profile type is unchanged
+    if (dst.profileType() != src.profileType()) {
+        return false;
+    }
+
+    // Ensure the alpha type is valid
+    if (!valid_alpha(dst.alphaType(), src.alphaType())) {
+        return false;
+    }
+
+    // Check for supported color types
+    switch (dst.colorType()) {
+        // Allow output to kN32 from any type of input
+        case kN32_SkColorType:
+            return true;
+        // Allow output to kIndex_8 from compatible inputs
+        case kIndex_8_SkColorType:
+            return kIndex_8_SkColorType == src.colorType();
+        default:
+            return false;
+    }
+}
+
+/*
+ * Creates an instance of the decoder
+ * Called only by NewFromStream
+ */
+SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream,
+                                       uint16_t bitsPerPixel, uint32_t numColors,
+                                       uint32_t bytesPerColor, uint32_t offset,
+                                       SkBmpCodec::RowOrder rowOrder, bool inIco)
+    : INHERITED(info, stream, bitsPerPixel, rowOrder)
+    , fColorTable(NULL)
+    , fNumColors(this->computeNumColors(numColors))
+    , fBytesPerColor(bytesPerColor)
+    , fOffset(offset)
+    , fSwizzler(NULL)
+    , fSrcBuffer(NULL)
+    , fInIco(inIco)
+{}
+
+/*
+ * Initiates the bitmap decode
+ */
+SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo,
+                                        void* dst, size_t dstRowBytes,
+                                        const Options& opts,
+                                        SkPMColor* inputColorPtr,
+                                        int* inputColorCount) {
+    if (!this->handleRewind(fInIco)) {
+        return kCouldNotRewind;
+    }
+    if (opts.fSubset) {
+        // Subsets are not supported.
+        return kUnimplemented;
+    }
+    if (dstInfo.dimensions() != this->getInfo().dimensions()) {
+        SkCodecPrintf("Error: scaling not supported.\n");
+        return kInvalidScale;
+    }
+    if (!conversion_possible(dstInfo, this->getInfo())) {
+        SkCodecPrintf("Error: cannot convert input type to output type.\n");
+        return kInvalidConversion;
+    }
+
+    // Create the color table if necessary and prepare the stream for decode
+    // Note that if it is non-NULL, inputColorCount will be modified
+    if (!this->createColorTable(dstInfo.alphaType(), inputColorCount)) {
+        SkCodecPrintf("Error: could not create color table.\n");
+        return kInvalidInput;
+    }
+
+    // Copy the color table to the client if necessary
+    copy_color_table(dstInfo, fColorTable, inputColorPtr, inputColorCount);
+
+    // Initialize a swizzler if necessary
+    if (!this->initializeSwizzler(dstInfo, opts)) {
+        SkCodecPrintf("Error: cannot initialize swizzler.\n");
+        return kInvalidConversion;
+    }
+
+    return this->decode(dstInfo, dst, dstRowBytes, opts);
+}
+
+/*
+ * Process the color table for the bmp input
+ */
+ bool SkBmpStandardCodec::createColorTable(SkAlphaType alphaType, int* numColors) {
+    // Allocate memory for color table
+    uint32_t colorBytes = 0;
+    SkPMColor colorTable[256];
+    if (this->bitsPerPixel() <= 8) {
+        // Inform the caller of the number of colors
+        uint32_t maxColors = 1 << this->bitsPerPixel();
+        if (NULL != numColors) {
+            // We set the number of colors to maxColors in order to ensure
+            // safe memory accesses.  Otherwise, an invalid pixel could
+            // access memory outside of our color table array.
+            *numColors = maxColors;
+        }
+
+        // Read the color table from the stream
+        colorBytes = fNumColors * fBytesPerColor;
+        SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes));
+        if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) {
+            SkCodecPrintf("Error: unable to read color table.\n");
+            return false;
+        }
+
+        // Choose the proper packing function
+        SkPMColor (*packARGB) (uint32_t, uint32_t, uint32_t, uint32_t);
+        switch (alphaType) {
+            case kOpaque_SkAlphaType:
+            case kUnpremul_SkAlphaType:
+                packARGB = &SkPackARGB32NoCheck;
+                break;
+            case kPremul_SkAlphaType:
+                packARGB = &SkPreMultiplyARGB;
+                break;
+            default:
+                // This should not be reached because conversion possible
+                // should fail if the alpha type is not one of the above
+                // values.
+                SkASSERT(false);
+                packARGB = NULL;
+                break;
+        }
+
+        // Fill in the color table
+        uint32_t i = 0;
+        for (; i < fNumColors; i++) {
+            uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor);
+            uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1);
+            uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2);
+            uint8_t alpha;
+            if (kOpaque_SkAlphaType == alphaType) {
+                alpha = 0xFF;
+            } else {
+                alpha = get_byte(cBuffer.get(), i*fBytesPerColor + 3);
+            }
+            colorTable[i] = packARGB(alpha, red, green, blue);
+        }
+
+        // To avoid segmentation faults on bad pixel data, fill the end of the
+        // color table with black.  This is the same the behavior as the
+        // chromium decoder.
+        for (; i < maxColors; i++) {
+            colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0);
+        }
+
+        // Set the color table
+        fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorTable, maxColors)));
+    }
+
+    // Bmp-in-Ico files do not use an offset to indicate where the pixel data
+    // begins.  Pixel data always begins immediately after the color table.
+    if (!fInIco) {
+        // Check that we have not read past the pixel array offset
+        if(fOffset < colorBytes) {
+            // This may occur on OS 2.1 and other old versions where the color
+            // table defaults to max size, and the bmp tries to use a smaller
+            // color table.  This is invalid, and our decision is to indicate
+            // an error, rather than try to guess the intended size of the
+            // color table.
+            SkCodecPrintf("Error: pixel data offset less than color table size.\n");
+            return false;
+        }
+
+        // After reading the color table, skip to the start of the pixel array
+        if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) {
+            SkCodecPrintf("Error: unable to skip to image data.\n");
+            return false;
+        }
+    }
+
+    // Return true on success
+    return true;
+}
+
+bool SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo,
+                                            const Options& opts) {
+    // Allocate space for a row buffer
+    const size_t rowBytes = SkAlign4(compute_row_bytes(dstInfo.width(), this->bitsPerPixel()));
+    fSrcBuffer.reset(SkNEW_ARRAY(uint8_t, rowBytes));
+
+    // Get swizzler configuration
+    SkSwizzler::SrcConfig config;
+    switch (this->bitsPerPixel()) {
+        case 1:
+            config = SkSwizzler::kIndex1;
+            break;
+        case 2:
+            config = SkSwizzler::kIndex2;
+            break;
+        case 4:
+            config = SkSwizzler::kIndex4;
+            break;
+        case 8:
+            config = SkSwizzler::kIndex;
+            break;
+        case 24:
+            config = SkSwizzler::kBGR;
+            break;
+        case 32:
+            if (kOpaque_SkAlphaType == dstInfo.alphaType()) {
+                config = SkSwizzler::kBGRX;
+            } else {
+                config = SkSwizzler::kBGRA;
+            }
+            break;
+        default:
+            SkASSERT(false);
+            return false;
+    }
+
+    // Get a pointer to the color table if it exists
+    const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
+
+    // Create swizzler
+    fSwizzler.reset(SkSwizzler::CreateSwizzler(config,
+            colorPtr, dstInfo, opts.fZeroInitialized));
+
+    if (NULL == fSwizzler.get()) {
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Choose a fill for failures due to an incomplete image.  We will use zero as
+ * the default palette index, black for opaque images, and transparent for
+ * non-opaque images.
+ */
+static uint32_t get_fill_color_or_index(uint16_t bitsPerPixels, SkAlphaType alphaType) {
+    uint32_t fillColorOrIndex;
+    switch (bitsPerPixels) {
+        case 1:
+        case 2:
+        case 4:
+        case 8:
+            fillColorOrIndex = 0;
+            break;
+        case 24:
+            fillColorOrIndex = SK_ColorBLACK;
+            break;
+        case 32:
+            if (kOpaque_SkAlphaType == alphaType) {
+                fillColorOrIndex = SK_ColorBLACK;
+            } else {
+                fillColorOrIndex = SK_ColorTRANSPARENT;
+            }
+            break;
+        default:
+            SkASSERT(false);
+            return 0;
+    }
+    return fillColorOrIndex;
+}
+
+/*
+ * Performs the bitmap decoding for standard input format
+ */
+SkCodec::Result SkBmpStandardCodec::decode(const SkImageInfo& dstInfo,
+                                   void* dst, size_t dstRowBytes,
+                                   const Options& opts) {
+    // Set constant values
+    const int width = dstInfo.width();
+    const int height = dstInfo.height();
+    const size_t rowBytes = SkAlign4(compute_row_bytes(width, this->bitsPerPixel()));
+
+    // Iterate over rows of the image
+    for (int y = 0; y < height; y++) {
+        // Read a row of the input
+        if (this->stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) {
+            SkCodecPrintf("Warning: incomplete input stream.\n");
+            // Fill the destination image on failure
+            // Get the fill color/index and check if it is 0
+            uint32_t fillColorOrIndex = get_fill_color_or_index(this->bitsPerPixel(),
+                    dstInfo.alphaType());
+            bool zeroFill = (0 == fillColorOrIndex);
+
+            if (kNo_ZeroInitialized == opts.fZeroInitialized || !zeroFill) {
+                // Get a pointer to the color table if it exists
+                const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
+
+                void* dstStart = this->getDstStartRow(dst, dstRowBytes, y);
+                SkSwizzler::Fill(dstStart, dstInfo, dstRowBytes, dstInfo.height() - y,
+                        fillColorOrIndex, colorPtr);
+            }
+            return kIncompleteInput;
+        }
+
+        // Decode the row in destination format
+        uint32_t row;
+        if (SkBmpCodec::kTopDown_RowOrder == this->rowOrder()) {
+            row = y;
+        } else {
+            row = height - 1 - y;
+        }
+
+        void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes);
+        fSwizzler->swizzle(dstRow, fSrcBuffer.get());
+    }
+
+    // Finally, apply the AND mask for bmp-in-ico images
+    if (fInIco) {
+        // The AND mask is always 1 bit per pixel
+        const size_t rowBytes = SkAlign4(compute_row_bytes(width, 1));
+
+        SkPMColor* dstPtr = (SkPMColor*) dst;
+        for (int y = 0; y < height; y++) {
+            // The srcBuffer will at least be large enough
+            if (stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) {
+                SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n");
+                return kIncompleteInput;
+            }
+
+            int row;
+            if (SkBmpCodec::kBottomUp_RowOrder == this->rowOrder()) {
+                row = height - y - 1;
+            } else {
+                row = y;
+            }
+
+            SkPMColor* dstRow =
+                    SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes);
+
+            for (int x = 0; x < width; x++) {
+                int quotient;
+                int modulus;
+                SkTDivMod(x, 8, &quotient, &modulus);
+                uint32_t shift = 7 - modulus;
+                uint32_t alphaBit =
+                        (fSrcBuffer.get()[quotient] >> shift) & 0x1;
+                dstRow[x] &= alphaBit - 1;
+            }
+        }
+    }
+
+    // Finished decoding the entire image
+    return kSuccess;
+}
diff --git a/src/codec/SkBmpStandardCodec.h b/src/codec/SkBmpStandardCodec.h
new file mode 100644
index 0000000..ff91dcf
--- /dev/null
+++ b/src/codec/SkBmpStandardCodec.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBmpCodec.h"
+#include "SkColorTable.h"
+#include "SkImageInfo.h"
+#include "SkSwizzler.h"
+#include "SkTypes.h"
+
+/*
+ * This class implements the decoding for bmp images that use "standard" modes,
+ * which essentially means they do not contain bit masks or RLE codes.
+ */
+class SkBmpStandardCodec : public SkBmpCodec {
+public:
+
+    /*
+     * Creates an instance of the decoder
+     *
+     * Called only by SkBmpCodec::NewFromStream
+     * There should be no other callers despite this being public
+     *
+     * @param srcInfo contains the source width and height
+     * @param stream the stream of encoded image data
+     * @param bitsPerPixel the number of bits used to store each pixel
+     * @param format the format of the bmp file
+     * @param numColors the number of colors in the color table
+     * @param bytesPerColor the number of bytes in the stream used to represent
+                            each color in the color table
+     * @param offset the offset of the image pixel data from the end of the
+     *               headers
+     * @param rowOrder indicates whether rows are ordered top-down or bottom-up
+     */
+    SkBmpStandardCodec(const SkImageInfo& srcInfo, SkStream* stream,
+               uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor,
+               uint32_t offset, SkBmpCodec::RowOrder rowOrder, bool isIco);
+
+protected:
+
+    Result onGetPixels(const SkImageInfo& dstInfo, void* dst,
+                       size_t dstRowBytes, const Options&, SkPMColor*,
+                       int*) override;
+
+private:
+
+    /*
+     * Creates the color table
+     * Sets colorCount to the new color count if it is non-NULL
+     */
+    bool createColorTable(SkAlphaType alphaType, int* colorCount);
+
+    bool initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts);
+
+    Result decode(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts);
+
+    SkAutoTUnref<SkColorTable>          fColorTable;     // owned
+    const uint32_t                      fNumColors;
+    const uint32_t                      fBytesPerColor;
+    const uint32_t                      fOffset;
+    SkAutoTDelete<SkSwizzler>           fSwizzler;
+    SkAutoTDeleteArray<uint8_t>         fSrcBuffer;
+    const bool                          fInIco;
+
+    typedef SkBmpCodec INHERITED;
+};
diff --git a/src/codec/SkCodecPriv.h b/src/codec/SkCodecPriv.h
index 0c45fdd..2596787 100644
--- a/src/codec/SkCodecPriv.h
+++ b/src/codec/SkCodecPriv.h
@@ -30,6 +30,28 @@
 #define COMPUTE_RESULT_ALPHA                    \
     SkSwizzler::GetResult(zeroAlpha, maxAlpha);
 
+static inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) {
+    // Check for supported alpha types
+    if (srcAlpha != dstAlpha) {
+        if (kOpaque_SkAlphaType == srcAlpha) {
+            // If the source is opaque, we must decode to opaque
+            return false;
+        }
+
+        // The source is not opaque
+        switch (dstAlpha) {
+            case kPremul_SkAlphaType:
+            case kUnpremul_SkAlphaType:
+                // The source is not opaque, so either of these is okay
+                break;
+            default:
+                // We cannot decode a non-opaque image to opaque (or unknown)
+                return false;
+        }
+    }
+    return true;
+}
+
 /*
  * If there is a color table, get a pointer to the colors, otherwise return NULL
  */
@@ -40,7 +62,6 @@
 /*
  *
  * Copy the codec color table back to the client when kIndex8 color type is requested
- *
  */
 static inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable,
         SkPMColor* inputColorPtr, int* inputColorCount) {
@@ -53,27 +74,21 @@
 }
 
 /*
- *
  * Compute row bytes for an image using pixels per byte
- *
  */
 static inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) {
     return (width + pixelsPerByte - 1) / pixelsPerByte;
 }
 
 /*
- *
  * Compute row bytes for an image using bytes per pixel
- *
  */
 static inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) {
     return width * bytesPerPixel;
 }
 
 /*
- *
  * Compute row bytes for an image
- *
  */
 static inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) {
     if (bitsPerPixel < 16) {
@@ -88,20 +103,16 @@
 }
 
 /*
- *
  * Get a byte from a buffer
  * This method is unsafe, the caller is responsible for performing a check
- *
  */
 static inline uint8_t get_byte(uint8_t* buffer, uint32_t i) {
     return buffer[i];
 }
 
 /*
- *
  * Get a short from a buffer
  * This method is unsafe, the caller is responsible for performing a check
- *
  */
 static inline uint16_t get_short(uint8_t* buffer, uint32_t i) {
     uint16_t result;
@@ -114,10 +125,8 @@
 }
 
 /*
- *
  * Get an int from a buffer
  * This method is unsafe, the caller is responsible for performing a check
- *
  */
 static inline uint32_t get_int(uint8_t* buffer, uint32_t i) {
     uint32_t result;
diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
index 7c6a74c..f239900 100644
--- a/src/codec/SkCodec_libpng.cpp
+++ b/src/codec/SkCodec_libpng.cpp
@@ -397,24 +397,11 @@
         return false;
     }
 
-    // Check for supported alpha types
-    if (src.alphaType() != dst.alphaType()) {
-        if (kOpaque_SkAlphaType == src.alphaType()) {
-            // If the source is opaque, we must decode to opaque
-            return false;
-        }
-
-        // The source is not opaque
-        switch (dst.alphaType()) {
-            case kPremul_SkAlphaType:
-            case kUnpremul_SkAlphaType:
-                // The source is not opaque, so either of these is okay
-                break;
-            default:
-                // We cannot decode a non-opaque image to opaque (or unknown)
-                return false;
-        }
+    // Ensure the alpha type is valid
+    if (!valid_alpha(dst.alphaType(), src.alphaType())) {
+        return false;
     }
+
     // Check for supported color types
     switch (dst.colorType()) {
         case kN32_SkColorType:
diff --git a/src/codec/SkMaskSwizzler.h b/src/codec/SkMaskSwizzler.h
index 4ccc3ae..9f4dd44 100644
--- a/src/codec/SkMaskSwizzler.h
+++ b/src/codec/SkMaskSwizzler.h
@@ -4,6 +4,8 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+#ifndef SkMaskSwizzler_DEFINED
+#define SkMaskSwizzler_DEFINED
 
 #include "SkMasks.h"
 #include "SkSwizzler.h"
@@ -19,37 +21,29 @@
 public:
 
     /*
-     *
      * Create a new swizzler
      * @param masks Unowned pointer to helper class
-     *
      */
     static SkMaskSwizzler* CreateMaskSwizzler(const SkImageInfo& imageInfo,
                                               SkMasks* masks,
                                               uint32_t bitsPerPixel);
 
     /*
-     *
      * Swizzle a row
-     *
      */
     SkSwizzler::ResultAlpha swizzle(void* dst, const uint8_t* SK_RESTRICT src);
 
 private:
 
     /*
-     *
      * Row procedure used for swizzle
-     *
      */
     typedef SkSwizzler::ResultAlpha (*RowProc)(
             void* dstRow, const uint8_t* srcRow, int width,
             SkMasks* masks);
 
     /*
-     *
      * Constructor for mask swizzler
-     *
      */
     SkMaskSwizzler(const SkImageInfo& info, SkMasks* masks, RowProc proc);
 
@@ -58,3 +52,5 @@
     SkMasks*           fMasks;       // unowned
     const RowProc      fRowProc;
 };
+
+#endif
diff --git a/src/codec/SkMasks.h b/src/codec/SkMasks.h
index 31c6849..0823704 100644
--- a/src/codec/SkMasks.h
+++ b/src/codec/SkMasks.h
@@ -4,6 +4,9 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+#ifndef SkMasks_DEFINED
+#define SkMasks_DEFINED
+
 #include "SkTypes.h"
 
 /*
@@ -79,3 +82,5 @@
     const MaskInfo fBlue;
     const MaskInfo fAlpha;
 };
+
+#endif