 Chromium Code Reviews
 Chromium Code Reviews Issue 1055743003:
  Swizzler changes Index8 and 565  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master
    
  
    Issue 1055743003:
  Swizzler changes Index8 and 565  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master| Index: src/codec/SkCodec_libbmp.cpp | 
| diff --git a/src/codec/SkCodec_libbmp.cpp b/src/codec/SkCodec_libbmp.cpp | 
| index 2b20faebad050c9d67a3769edc147f247c5e6ac3..1fa92f0ded738814a142a28cc655c173284c5827 100644 | 
| --- a/src/codec/SkCodec_libbmp.cpp | 
| +++ b/src/codec/SkCodec_libbmp.cpp | 
| @@ -9,6 +9,7 @@ | 
| #include "SkCodecPriv.h" | 
| #include "SkColorPriv.h" | 
| #include "SkStream.h" | 
| +#include "SkUtils.h" | 
| /* | 
| * | 
| @@ -23,12 +24,33 @@ static bool conversion_possible(const SkImageInfo& dst, | 
| return false; | 
| } | 
| - // Check for supported color and alpha types | 
| + // 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 src.alphaType() == dst.alphaType() || | 
| - (kPremul_SkAlphaType == dst.alphaType() && | 
| - kUnpremul_SkAlphaType == src.alphaType()); | 
| + return true; | 
| + // Allow output to kIndex_8 from compatible inputs | 
| + case kIndex_8_SkColorType: | 
| + return kIndex_8_SkColorType == src.colorType(); | 
| default: | 
| return false; | 
| } | 
| @@ -420,12 +442,17 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool isIco, SkCodec** codecOut) { | 
| } | 
| iBuffer.free(); | 
| - // Additionally, 32 bit bmp-in-icos use the alpha channel | 
| - if (isIco && 32 == bitsPerPixel) { | 
| + // 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)) { | 
| alphaType = kUnpremul_SkAlphaType; | 
| } | 
| - // Check for valid bits per pixel input | 
| + // Check for valid bits per pixel. | 
| + // At the same time, use this information to choose a suggested color type | 
| + // and to set default masks. | 
| + SkColorType colorType = kN32_SkColorType; | 
| switch (bitsPerPixel) { | 
| // In addition to more standard pixel compression formats, bmp supports | 
| // the use of bit masks to determine pixel components. The standard | 
| @@ -440,10 +467,18 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool isIco, SkCodec** codecOut) { | 
| inputFormat = kBitMask_BitmapInputFormat; | 
| } | 
| break; | 
| + // We want to decode to kIndex_8 for input formats that are already | 
| + // designed in index format. | 
| case 1: | 
| case 2: | 
| case 4: | 
| case 8: | 
| + // 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) { | 
| + colorType = kIndex_8_SkColorType; | 
| + } | 
| case 24: | 
| case 32: | 
| break; | 
| @@ -476,11 +511,10 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool isIco, SkCodec** codecOut) { | 
| if (codecOut) { | 
| // Return the codec | 
| - // We will use ImageInfo to store width, height, and alpha type. We | 
| - // will set color type to kN32_SkColorType because that should be the | 
| - // default output. | 
| + // We will use ImageInfo to store width, height, suggested color type, and | 
| + // suggested alpha type. | 
| const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, | 
| - kN32_SkColorType, alphaType); | 
| + colorType, alphaType); | 
| *codecOut = SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel, | 
| inputFormat, masks.detach(), | 
| numColors, bytesPerColor, | 
| @@ -541,8 +575,9 @@ SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, | 
| */ | 
| SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, | 
| void* dst, size_t dstRowBytes, | 
| - const Options&, | 
| - SkPMColor*, int*) { | 
| + const Options& opts, | 
| + SkPMColor* inputColorPtr, | 
| + int* inputColorCount) { | 
| // Check for proper input and output formats | 
| SkCodec::RewindState rewindState = this->rewindIfNeeded(); | 
| if (rewindState == kCouldNotRewind_RewindState) { | 
| @@ -562,17 +597,26 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, | 
| } | 
| // Create the color table if necessary and prepare the stream for decode | 
| - if (!createColorTable(dstInfo.alphaType())) { | 
| + // 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 | 
| + if (kIndex_8_SkColorType == dstInfo.colorType()) { | 
| + SkASSERT(NULL != inputColorPtr); | 
| + SkASSERT(NULL != inputColorCount); | 
| + SkASSERT(NULL != fColorTable.get()); | 
| + sk_memcpy32(inputColorPtr, fColorTable->readColors(), *inputColorCount); | 
| + } | 
| + | 
| // Perform the decode | 
| switch (fInputFormat) { | 
| case kBitMask_BitmapInputFormat: | 
| return decodeMask(dstInfo, dst, dstRowBytes); | 
| case kRLE_BitmapInputFormat: | 
| - return decodeRLE(dstInfo, dst, dstRowBytes); | 
| + return decodeRLE(dstInfo, dst, dstRowBytes, opts); | 
| case kStandard_BitmapInputFormat: | 
| return decode(dstInfo, dst, dstRowBytes); | 
| default: | 
| @@ -586,7 +630,7 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, | 
| * Process the color table for the bmp input | 
| * | 
| */ | 
| - bool SkBmpCodec::createColorTable(SkAlphaType alphaType) { | 
| + bool SkBmpCodec::createColorTable(SkAlphaType alphaType, int* numColors) { | 
| // Allocate memory for color table | 
| uint32_t colorBytes = 0; | 
| uint32_t maxColors = 0; | 
| @@ -599,6 +643,15 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, | 
| fNumColors = maxColors; | 
| } | 
| + // Inform the caller of the number of colors | 
| + if (NULL != numColors) { | 
| + SkASSERT(256 == *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)); | 
| @@ -632,9 +685,13 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, | 
| 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 = kOpaque_SkAlphaType == alphaType ? 0xFF : | 
| - (fMasks->getAlphaMask() >> 24) & | 
| - get_byte(cBuffer.get(), i*fBytesPerColor + 3); | 
| + uint8_t alpha; | 
| + if (kOpaque_SkAlphaType == alphaType || kRLE_BitmapInputFormat == fInputFormat) { | 
| 
scroggo
2015/04/07 21:15:34
This appears to fix a separate bug?
 
msarett
2015/04/08 13:59:10
Yes it fixes a bug that was almost introduced with
 | 
| + alpha = 0xFF; | 
| + } else { | 
| + alpha = (fMasks->getAlphaMask() >> 24) & | 
| + get_byte(cBuffer.get(), i*fBytesPerColor + 3); | 
| + } | 
| colorTable[i] = packARGB(alpha, red, green, blue); | 
| } | 
| @@ -740,7 +797,7 @@ SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, | 
| * Set an RLE pixel using the color table | 
| * | 
| */ | 
| -void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, | 
| +void SkBmpCodec::setRLEPixel(void* dst, size_t dstRowBytes, | 
| const SkImageInfo& dstInfo, uint32_t x, uint32_t y, | 
| uint8_t index) { | 
| // Set the row | 
| @@ -755,17 +812,11 @@ void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, | 
| // Set the pixel based on destination color type | 
| switch (dstInfo.colorType()) { | 
| case kN32_SkColorType: { | 
| - SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, | 
| + SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst, | 
| row * (int) dstRowBytes); | 
| dstRow[x] = fColorTable->operator[](index); | 
| break; | 
| } | 
| - case kRGB_565_SkColorType: { | 
| - uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, | 
| - row * (int) dstRowBytes); | 
| - dstRow[x] = SkPixel32ToPixel16(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. | 
| @@ -779,7 +830,7 @@ void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, | 
| * Set an RLE pixel from R, G, B values | 
| * | 
| */ | 
| -void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes, | 
| +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) { | 
| @@ -795,17 +846,11 @@ void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes, | 
| // Set the pixel based on destination color type | 
| switch (dstInfo.colorType()) { | 
| case kN32_SkColorType: { | 
| - SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, | 
| + SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst, | 
| row * (int) dstRowBytes); | 
| dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue); | 
| break; | 
| } | 
| - case kRGB_565_SkColorType: { | 
| - uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, | 
| - row * (int) dstRowBytes); | 
| - dstRow[x] = SkPack888ToRGB16(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. | 
| @@ -821,7 +866,8 @@ void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes, | 
| * | 
| */ | 
| SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, | 
| - void* dst, size_t dstRowBytes) { | 
| + 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; | 
| @@ -846,10 +892,15 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, | 
| // Destination parameters | 
| int x = 0; | 
| int y = 0; | 
| - // If the code skips pixels, remaining pixels are transparent or black | 
| - // TODO: Skip this if memory was already zeroed. | 
| - memset(dst, 0, dstRowBytes * height); | 
| - SkPMColor* dstPtr = (SkPMColor*) dst; | 
| + | 
| + // 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, 0, SK_ColorTRANSPARENT, NULL); | 
| + } | 
| while (true) { | 
| // Every entry takes at least two bytes | 
| @@ -920,11 +971,11 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, | 
| case 4: { | 
| SkASSERT(currByte < totalBytes); | 
| uint8_t val = buffer.get()[currByte++]; | 
| - setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, | 
| + setRLEPixel(dst, dstRowBytes, dstInfo, x++, | 
| y, val >> 4); | 
| numPixels--; | 
| if (numPixels != 0) { | 
| - setRLEPixel(dstPtr, dstRowBytes, dstInfo, | 
| + setRLEPixel(dst, dstRowBytes, dstInfo, | 
| x++, y, val & 0xF); | 
| numPixels--; | 
| } | 
| @@ -932,7 +983,7 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, | 
| } | 
| case 8: | 
| SkASSERT(currByte < totalBytes); | 
| - setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, | 
| + setRLEPixel(dst, dstRowBytes, dstInfo, x++, | 
| y, buffer.get()[currByte++]); | 
| numPixels--; | 
| break; | 
| @@ -941,7 +992,7 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, | 
| uint8_t blue = buffer.get()[currByte++]; | 
| uint8_t green = buffer.get()[currByte++]; | 
| uint8_t red = buffer.get()[currByte++]; | 
| - setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, | 
| + setRLE24Pixel(dst, dstRowBytes, dstInfo, | 
| x++, y, red, green, blue); | 
| numPixels--; | 
| } | 
| @@ -977,7 +1028,7 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, | 
| uint8_t green = buffer.get()[currByte++]; | 
| uint8_t red = buffer.get()[currByte++]; | 
| while (x < endX) { | 
| - setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, x++, y, red, | 
| + setRLE24Pixel(dst, dstRowBytes, dstInfo, x++, y, red, | 
| green, blue); | 
| } | 
| } else { | 
| @@ -994,7 +1045,7 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, | 
| // Set the indicated number of pixels | 
| for (int which = 0; x < endX; x++) { | 
| - setRLEPixel(dstPtr, dstRowBytes, dstInfo, x, y, | 
| + setRLEPixel(dst, dstRowBytes, dstInfo, x, y, | 
| indices[which]); | 
| which = !which; | 
| } | 
| @@ -1084,7 +1135,8 @@ SkCodec::Result SkBmpCodec::decode(const SkImageInfo& dstInfo, | 
| // 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. | 
| + // bmp images are intended to be opaque. Here, we make those corrections | 
| + // in the kN32 case. | 
| /* | 
| SkPMColor* dstRow = (SkPMColor*) dst; | 
| if (SkSwizzler::kBGRA == config) { |