***Disables swizzles to 565.
We may want to enable swizzles to 565
for images that are encoded in a format
similar to 565, however, we do not want
to take images that decode naturally to
kN32 and then convert them to 565.
***Enable swizzles to kIndex_8. For images
encoded in a color table format, we suggest
that they be decoded to kIndex_8. When we
decode, we only allow conversion to kIndex_8
if it matches the suggested color type (except
wbmp which seems good as is).
***Modify dm to test images that decode to
kIndex_8.
BUG=skia:3257
BUG=skia:3440
Review URL: https://codereview.chromium.org/1055743003
diff --git a/src/codec/SkCodec_libbmp.cpp b/src/codec/SkCodec_libbmp.cpp
index 2b20fae..b553dea 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 @@
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 @@
}
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 @@
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 @@
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 @@
*/
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 @@
}
// 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 @@
* 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 @@
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 @@
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) {
+ 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 @@
* 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 @@
// 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 @@
* 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 @@
// 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 @@
*
*/
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 @@
// 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 @@
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 @@
}
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 @@
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 @@
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 @@
// 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 @@
// 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) {
diff --git a/src/codec/SkCodec_libbmp.h b/src/codec/SkCodec_libbmp.h
index 81b514e..8ad613e 100644
--- a/src/codec/SkCodec_libbmp.h
+++ b/src/codec/SkCodec_libbmp.h
@@ -86,9 +86,9 @@
/*
*
* Creates the color table
- *
+ * Sets colorCount to the new color count if it is non-NULL
*/
- bool createColorTable(SkAlphaType alphaType);
+ bool createColorTable(SkAlphaType alphaType, int* colorCount);
/*
*
@@ -121,7 +121,7 @@
* Set an RLE pixel using the color table
*
*/
- void setRLEPixel(SkPMColor* dst, size_t dstRowBytes,
+ void setRLEPixel(void* dst, size_t dstRowBytes,
const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
uint8_t index);
/*
@@ -129,7 +129,7 @@
* Set an RLE24 pixel from R, G, B values
*
*/
- void setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes,
+ 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);
@@ -139,7 +139,7 @@
*
*/
Result decodeRLE(const SkImageInfo& dstInfo, void* dst,
- size_t dstRowBytes);
+ size_t dstRowBytes, const Options& opts);
/*
*
@@ -181,7 +181,7 @@
const uint16_t fBitsPerPixel;
const BitmapInputFormat fInputFormat;
SkAutoTDelete<SkMasks> fMasks; // owned
- SkAutoTDelete<SkColorTable> fColorTable; // owned
+ SkAutoTUnref<SkColorTable> fColorTable; // owned
uint32_t fNumColors;
const uint32_t fBytesPerColor;
const uint32_t fOffset;
diff --git a/src/codec/SkCodec_libgif.cpp b/src/codec/SkCodec_libgif.cpp
index 9356a69..efb3a90 100644
--- a/src/codec/SkCodec_libgif.cpp
+++ b/src/codec/SkCodec_libgif.cpp
@@ -70,11 +70,11 @@
* This function cleans up the gif object after the decode completes
* It is used in a SkAutoTCallIProc template
*/
-int32_t SkGifCodec::CloseGif(GifFileType* gif) {
+void SkGifCodec::CloseGif(GifFileType* gif) {
#if GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0)
- return DGifCloseFile(gif);
+ DGifCloseFile(gif);
#else
- return DGifCloseFile(gif, NULL);
+ DGifCloseFile(gif, NULL);
#endif
}
@@ -131,42 +131,77 @@
}
/*
+ * Read enough of the stream to initialize the SkGifCodec.
+ * Returns a bool representing success or failure.
+ *
+ * @param codecOut
+ * If it returned true, and codecOut was not NULL,
+ * codecOut will be set to a new SkGifCodec.
+ *
+ * @param gifOut
+ * If it returned true, and codecOut was NULL,
+ * gifOut must be non-NULL and gifOut will be set to a new
+ * GifFileType pointer.
+ *
+ * @param stream
+ * Deleted on failure.
+ * codecOut will take ownership of it in the case where we created a codec.
+ * Ownership is unchanged when we returned a gifOut.
+ *
+ */
+bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** gifOut) {
+ SkAutoTDelete<SkStream> streamDeleter(stream);
+
+ // Read gif header, logical screen descriptor, and global color table
+ SkAutoTCallVProc<GifFileType, CloseGif> gif(open_gif(stream));
+
+ if (NULL == gif) {
+ gif_error("DGifOpen failed.\n");
+ return false;
+ }
+
+ if (NULL != codecOut) {
+ // Get fields from header
+ const int32_t width = gif->SWidth;
+ const int32_t height = gif->SHeight;
+ if (width <= 0 || height <= 0) {
+ gif_error("Invalid dimensions.\n");
+ return false;
+ }
+
+ // Return the codec
+ // kIndex is the most natural color type for gifs, so we set this as
+ // the default.
+ // Many gifs specify a color table index for transparent pixels. Every
+ // other pixel is guaranteed to be opaque. Despite this, because of the
+ // possiblity of transparent pixels, we cannot assume that the image is
+ // opaque. We have the option to set the alpha type as kPremul or
+ // kUnpremul. Both are valid since the alpha component will always be
+ // 0xFF or the entire 32-bit pixel will be set to zero. We prefer
+ // kPremul because we support kPremul, and it is more efficient to
+ // use kPremul directly even when kUnpremul is supported.
+ const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
+ kIndex_8_SkColorType, kPremul_SkAlphaType);
+ *codecOut = SkNEW_ARGS(SkGifCodec, (imageInfo, streamDeleter.detach(), gif.detach()));
+ } else {
+ SkASSERT(NULL != gifOut);
+ streamDeleter.detach();
+ *gifOut = gif.detach();
+ }
+ return true;
+}
+
+/*
* Assumes IsGif was called and returned true
* Creates a gif decoder
* Reads enough of the stream to determine the image format
*/
SkCodec* SkGifCodec::NewFromStream(SkStream* stream) {
- SkAutoTDelete<SkStream> streamDeleter(stream);
- // Read gif header, logical screen descriptor, and global color table
- SkAutoTCallIProc<GifFileType, CloseGif> gif(open_gif(stream));
-
- if (NULL == gif) {
- gif_error("DGifOpen failed.\n");
- return NULL;
+ SkCodec* codec = NULL;
+ if (ReadHeader(stream, &codec, NULL)) {
+ return codec;
}
-
- // Get fields from header
- const int32_t width = gif->SWidth;
- const int32_t height = gif->SHeight;
- if (width <= 0 || height <= 0) {
- gif_error("Invalid dimensions.\n");
- return NULL;
- }
-
- // Return the codec
- // kIndex is the most natural color type for gifs, so we set this as
- // the default.
- // Many gifs specify a color table index for transparent pixels. Every
- // other pixel is guaranteed to be opaque. Despite this, because of the
- // possiblity of transparent pixels, we cannot assume that the image is
- // opaque. We have the option to set the alpha type as kPremul or
- // kUnpremul. Both are valid since the alpha component will always be
- // 0xFF or the entire 32-bit pixel will be set to zero. We prefer
- // kPremul because we support kPremul, and it is more efficient to
- // use kPremul directly even when kUnpremul is supported.
- const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
- kIndex_8_SkColorType, kPremul_SkAlphaType);
- return SkNEW_ARGS(SkGifCodec, (imageInfo, streamDeleter.detach(), gif.detach()));
+ return NULL;
}
SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream,
@@ -191,6 +226,9 @@
case kN32_SkColorType:
return kPremul_SkAlphaType == dst.alphaType() ||
kUnpremul_SkAlphaType == dst.alphaType();
+ case kIndex_8_SkColorType:
+ return kPremul_SkAlphaType == dst.alphaType() ||
+ kUnpremul_SkAlphaType == dst.alphaType();
default:
return false;
}
@@ -201,11 +239,24 @@
*/
SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo,
void* dst, size_t dstRowBytes,
- const Options& opts, SkPMColor*, int*) {
- // Check for valid input parameters
- if (!this->rewindIfNeeded()) {
+ const Options& opts,
+ SkPMColor* inputColorPtr,
+ int* inputColorCount) {
+ // Rewind if necessary
+ SkCodec::RewindState rewindState = this->rewindIfNeeded();
+ if (rewindState == kCouldNotRewind_RewindState) {
return kCouldNotRewind;
+ } else if (rewindState == kRewound_RewindState) {
+ GifFileType* gifOut = NULL;
+ if (!ReadHeader(this->stream(), NULL, &gifOut)) {
+ return kCouldNotRewind;
+ } else {
+ SkASSERT(NULL != gifOut);
+ fGif.reset(gifOut);
+ }
}
+
+ // Check for valid input parameters
if (dstInfo.dimensions() != this->getInfo().dimensions()) {
return gif_error("Scaling not supported.\n", kInvalidScale);
}
@@ -285,11 +336,23 @@
imageTop = 0;
}
+ // Create a color table to store colors the giflib colorMap
+ SkPMColor alternateColorPtr[256];
+ SkPMColor* colorTable;
+ SkColorType dstColorType = dstInfo.colorType();
+ if (kIndex_8_SkColorType == dstColorType) {
+ SkASSERT(NULL != inputColorPtr);
+ SkASSERT(NULL != inputColorCount);
+ SkASSERT(256 == *inputColorCount);
+ colorTable = inputColorPtr;
+ } else {
+ colorTable = alternateColorPtr;
+ }
+
// Set up the color table
uint32_t colorCount = 0;
// Allocate maximum storage to deal with invalid indices safely
const uint32_t maxColors = 256;
- SkPMColor colorTable[maxColors];
ColorMapObject* colorMap = fGif->Image.ColorMap;
// If there is no local color table, use the global color table
if (NULL == colorMap) {
@@ -310,7 +373,6 @@
// This is used to fill unspecified pixels in the image data.
uint32_t fillIndex = fGif->SBackGroundColor;
- bool fillBackground = true;
ZeroInitialized zeroInit = opts.fZeroInitialized;
// Gifs have the option to specify the color at a single
@@ -324,14 +386,11 @@
// is out of range.
uint32_t transIndex = find_trans_index(saveExt);
- // If the background is already zeroed and we have a valid
- // transparent index, we do not need to fill the background.
if (transIndex < colorCount) {
colorTable[transIndex] = SK_ColorTRANSPARENT;
// If there is a transparent index, we also use this as
// the fill index.
fillIndex = transIndex;
- fillBackground = (kYes_ZeroInitialized != zeroInit);
} else if (fillIndex >= colorCount) {
// If the fill index is invalid, we default to 0. This
// behavior is unspecified but matches SkImageDecoder.
@@ -339,6 +398,14 @@
}
}
+ // Check if we can skip filling the background of the image. We
+ // may be able to if the memory is zero initialized.
+ bool skipBackground =
+ ((kN32_SkColorType == dstColorType && colorTable[fillIndex] == 0) ||
+ (kIndex_8_SkColorType == dstColorType && fillIndex == 0)) &&
+ kYes_ZeroInitialized == zeroInit;
+
+
// Fill in the color table for indices greater than color count.
// This allows for predictable, safe behavior.
for (uint32_t i = colorCount; i < maxColors; i++) {
@@ -357,19 +424,8 @@
// FIXME: This may not be the behavior that we want for
// animated gifs where we draw on top of the
// previous frame.
- SkColorType dstColorType = dstInfo.colorType();
- if (fillBackground) {
- switch (dstColorType) {
- case kN32_SkColorType:
- sk_memset32((SkPMColor*) dst,
- colorTable[fillIndex],
- ((int) dstRowBytes) * height
- / sizeof(SkPMColor));
- break;
- default:
- SkASSERT(false);
- break;
- }
+ if (!skipBackground) {
+ SkSwizzler::Fill(dst, dstInfo, dstRowBytes, 0, fillIndex, colorTable);
}
// Modify the dst pointer
@@ -404,7 +460,7 @@
if (GIF_ERROR == DGifGetLine(fGif, buffer.get(),
innerWidth)) {
// Recover from error by filling remainder of image
- if (fillBackground) {
+ if (!skipBackground) {
memset(buffer.get(), fillIndex, innerWidth);
for (; y < innerHeight; y++) {
swizzler->next(buffer.get(), iter.nextY());
@@ -421,12 +477,9 @@
for (int32_t y = 0; y < innerHeight; y++) {
if (GIF_ERROR == DGifGetLine(fGif, buffer.get(),
innerWidth)) {
- if (fillBackground) {
- SkPMColor* dstPtr = (SkPMColor*) SkTAddOffset
- <void*>(dst, y * dstRowBytes);
- sk_memset32(dstPtr, colorTable[fillIndex],
- (height - y) * ((int) dstRowBytes)
- / sizeof(SkPMColor));
+ if (!skipBackground) {
+ SkSwizzler::Fill(dst, dstInfo, dstRowBytes, y, fillIndex,
+ colorTable);
}
return gif_error(SkStringPrintf(
"Could not decode line %d of %d.\n",
diff --git a/src/codec/SkCodec_libgif.h b/src/codec/SkCodec_libgif.h
index de59c6c..d805acc 100644
--- a/src/codec/SkCodec_libgif.h
+++ b/src/codec/SkCodec_libgif.h
@@ -34,6 +34,27 @@
protected:
/*
+ * Read enough of the stream to initialize the SkGifCodec.
+ * Returns a bool representing success or failure.
+ *
+ * @param codecOut
+ * If it returned true, and codecOut was not NULL,
+ * codecOut will be set to a new SkGifCodec.
+ *
+ * @param gifOut
+ * If it returned true, and codecOut was NULL,
+ * gifOut must be non-NULL and gifOut will be set to a new
+ * GifFileType pointer.
+ *
+ * @param stream
+ * Deleted on failure.
+ * codecOut will take ownership of it in the case where we created a codec.
+ * Ownership is unchanged when we returned a gifOut.
+ *
+ */
+ static bool ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** gifOut);
+
+ /*
* Initiates the gif decode
*/
Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&,
@@ -49,7 +70,7 @@
* This function cleans up the gif object after the decode completes
* It is used in a SkAutoTCallIProc template
*/
- static int32_t CloseGif(GifFileType* gif);
+ static void CloseGif(GifFileType* gif);
/*
* Frees any extension data used in the decode
@@ -68,7 +89,7 @@
*/
SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, GifFileType* gif);
- SkAutoTCallIProc<GifFileType, CloseGif> fGif; // owned
+ SkAutoTCallVProc<GifFileType, CloseGif> fGif; // owned
typedef SkCodec INHERITED;
};
diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
index 121b74f..250d815 100644
--- a/src/codec/SkCodec_libpng.cpp
+++ b/src/codec/SkCodec_libpng.cpp
@@ -15,6 +15,7 @@
#include "SkSize.h"
#include "SkStream.h"
#include "SkSwizzler.h"
+#include "SkUtils.h"
///////////////////////////////////////////////////////////////////////////////
// Helper macros
@@ -119,7 +120,7 @@
// Note: SkColorTable claims to store SkPMColors, which is not necessarily
// the case here.
-bool SkPngCodec::decodePalette(bool premultiply) {
+bool SkPngCodec::decodePalette(bool premultiply, int bitDepth, int* ctableCount) {
int numPalette;
png_colorp palette;
png_bytep trans;
@@ -128,14 +129,7 @@
return false;
}
- /* BUGGY IMAGE WORKAROUND
-
- We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count
- which is a problem since we use the byte as an index. To work around this we grow
- the colortable by 1 (if its < 256) and duplicate the last color into that slot.
- */
- const int colorCount = numPalette + (numPalette < 256);
- // Note: These are not necessarily SkPMColors.
+ // Note: These are not necessarily SkPMColors
SkPMColor colorStorage[256]; // worst-case storage
SkPMColor* colorPtr = colorStorage;
@@ -175,9 +169,24 @@
palette++;
}
- // see BUGGY IMAGE WORKAROUND comment above
- if (numPalette < 256) {
- *colorPtr = colorPtr[-1];
+ /* BUGGY IMAGE WORKAROUND
+ Invalid images could contain pixel values that are greater than the number of palette
+ entries. Since we use pixel values as indices into the palette this could result in reading
+ beyond the end of the palette which could leak the contents of uninitialized memory. To
+ ensure this doesn't happen, we grow the colortable to the maximum size that can be
+ addressed by the bitdepth of the image and fill it with the last palette color or black if
+ the palette is empty (really broken image).
+ */
+ int colorCount = SkTMax(numPalette, 1 << SkTMin(bitDepth, 8));
+ SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0);
+ for (; index < colorCount; index++) {
+ *colorPtr++ = lastColor;
+ }
+
+ // Set the new color count
+ if (ctableCount != NULL) {
+ SkASSERT(256 == *ctableCount);
+ *ctableCount = colorCount;
}
fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorStorage, colorCount)));
@@ -276,10 +285,7 @@
SkAlphaType skAlphaType;
switch (colorType) {
case PNG_COLOR_TYPE_PALETTE:
- // Technically, this is true of the data, but I don't think we want
- // to support it.
- // skColorType = kIndex8_SkColorType;
- skColorType = kN32_SkColorType;
+ skColorType = kIndex_8_SkColorType;
skAlphaType = has_transparency_in_palette(png_ptr, info_ptr) ?
kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
break;
@@ -387,22 +393,43 @@
static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
// TODO: Support other conversions
- if (dst.colorType() != src.colorType()) {
- return false;
- }
if (dst.profileType() != src.profileType()) {
return false;
}
- if (dst.alphaType() == src.alphaType()) {
- return true;
+
+ // 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;
+ }
}
- return kPremul_SkAlphaType == dst.alphaType() &&
- kUnpremul_SkAlphaType == src.alphaType();
+
+ // Check for supported color types
+ switch (dst.colorType()) {
+ // Allow output to kN32 from any type of input
+ case kN32_SkColorType:
+ return true;
+ default:
+ return dst.colorType() == src.colorType();
+ }
}
SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
void* dst, size_t rowBytes,
- const Options& options) {
+ const Options& options,
+ int* ctableCount) {
// FIXME: Could we use the return value of setjmp to specify the type of
// error?
if (setjmp(png_jmpbuf(fPng_ptr))) {
@@ -423,7 +450,8 @@
fReallyHasAlpha = false;
if (PNG_COLOR_TYPE_PALETTE == pngColorType) {
fSrcConfig = SkSwizzler::kIndex;
- if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType())) {
+ if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType(), bitDepth,
+ ctableCount)) {
return kInvalidInput;
}
} else if (kAlpha_8_SkColorType == requestedInfo.colorType()) {
@@ -492,8 +520,18 @@
return kInvalidConversion;
}
+ // Note that ctableCount will be modified if there is a color table
const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes,
- options);
+ options, ctableCount);
+
+ // Copy the color table to the client if necessary
+ if (kIndex_8_SkColorType == requestedInfo.colorType()) {
+ SkASSERT(NULL != ctable);
+ SkASSERT(NULL != ctableCount);
+ SkASSERT(NULL != fColorTable.get());
+ sk_memcpy32(ctable, fColorTable->readColors(), *ctableCount);
+ }
+
if (result != kSuccess) {
return result;
}
@@ -631,7 +669,9 @@
Options opts;
// FIXME: Pass this in to getScanlineDecoder?
opts.fZeroInitialized = kNo_ZeroInitialized;
- if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), opts) != kSuccess) {
+ // FIXME: onGetScanlineDecoder does not currently have a way to get color table information
+ // for a kIndex8 decoder.
+ if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), opts, NULL) != kSuccess) {
SkCodecPrintf("failed to initialize the swizzler.\n");
return NULL;
}
diff --git a/src/codec/SkCodec_libpng.h b/src/codec/SkCodec_libpng.h
index 103839b..e9bcd04 100644
--- a/src/codec/SkCodec_libpng.h
+++ b/src/codec/SkCodec_libpng.h
@@ -49,10 +49,10 @@
// Helper to set up swizzler and color table. Also calls png_read_update_info.
Result initializeSwizzler(const SkImageInfo& requestedInfo, void* dst,
- size_t rowBytes, const Options&);
+ size_t rowBytes, const Options&, int* ctableCount);
// Calls rewindIfNeeded, and returns true if the decoder can continue.
bool handleRewind();
- bool decodePalette(bool premultiply);
+ bool decodePalette(bool premultiply, int bitDepth, int* ctableCount);
void finish();
void destroyReadStruct();
diff --git a/src/codec/SkMaskSwizzler.cpp b/src/codec/SkMaskSwizzler.cpp
index 944042d..58ae11d 100644
--- a/src/codec/SkMaskSwizzler.cpp
+++ b/src/codec/SkMaskSwizzler.cpp
@@ -63,22 +63,6 @@
return COMPUTE_RESULT_ALPHA;
}
-static SkSwizzler::ResultAlpha swizzle_mask16_to_565(
- void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) {
-
- // Use the masks to decode to the destination
- uint16_t* srcPtr = (uint16_t*) srcRow;
- uint16_t* dstPtr = (uint16_t*) dstRow;
- for (int i = 0; i < width; i++) {
- uint16_t p = srcPtr[i];
- uint8_t red = masks->getRed(p);
- uint8_t green = masks->getGreen(p);
- uint8_t blue = masks->getBlue(p);
- dstPtr[i] = SkPack888ToRGB16(red, green, blue);
- }
- return SkSwizzler::kOpaque_ResultAlpha;
-}
-
static SkSwizzler::ResultAlpha swizzle_mask24_to_n32_opaque(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) {
@@ -130,21 +114,6 @@
return COMPUTE_RESULT_ALPHA;
}
-static SkSwizzler::ResultAlpha swizzle_mask24_to_565(
- void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) {
-
- // Use the masks to decode to the destination
- uint16_t* dstPtr = (uint16_t*) dstRow;
- for (int i = 0; i < 3*width; i += 3) {
- uint32_t p = srcRow[i] | (srcRow[i + 1] << 8) | srcRow[i + 2] << 16;
- uint8_t red = masks->getRed(p);
- uint8_t green = masks->getGreen(p);
- uint8_t blue = masks->getBlue(p);
- dstPtr[i/3] = SkPack888ToRGB16(red, green, blue);
- }
- return SkSwizzler::kOpaque_ResultAlpha;
-}
-
static SkSwizzler::ResultAlpha swizzle_mask32_to_n32_opaque(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) {
@@ -199,22 +168,6 @@
return COMPUTE_RESULT_ALPHA;
}
-static SkSwizzler::ResultAlpha swizzle_mask32_to_565(
- void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) {
-
- // Use the masks to decode to the destination
- uint32_t* srcPtr = (uint32_t*) srcRow;
- uint16_t* dstPtr = (uint16_t*) dstRow;
- for (int i = 0; i < width; i++) {
- uint32_t p = srcPtr[i];
- uint8_t red = masks->getRed(p);
- uint8_t green = masks->getGreen(p);
- uint8_t blue = masks->getBlue(p);
- dstPtr[i] = SkPack888ToRGB16(red, green, blue);
- }
- return SkSwizzler::kOpaque_ResultAlpha;
-}
-
/*
*
* Create a new mask swizzler
@@ -244,15 +197,6 @@
break;
}
break;
- case kRGB_565_SkColorType:
- switch (info.alphaType()) {
- case kOpaque_SkAlphaType:
- proc = &swizzle_mask16_to_565;
- break;
- default:
- break;
- }
- break;
default:
break;
}
@@ -274,15 +218,6 @@
break;
}
break;
- case kRGB_565_SkColorType:
- switch (info.alphaType()) {
- case kOpaque_SkAlphaType:
- proc = &swizzle_mask24_to_565;
- break;
- default:
- break;
- }
- break;
default:
break;
}
@@ -304,15 +239,6 @@
break;
}
break;
- case kRGB_565_SkColorType:
- switch (info.alphaType()) {
- case kOpaque_SkAlphaType:
- proc = &swizzle_mask32_to_565;
- break;
- default:
- break;
- }
- break;
default:
break;
}
diff --git a/src/codec/SkSwizzler.cpp b/src/codec/SkSwizzler.cpp
index 0486cf2..754b088 100644
--- a/src/codec/SkSwizzler.cpp
+++ b/src/codec/SkSwizzler.cpp
@@ -9,6 +9,7 @@
#include "SkColorPriv.h"
#include "SkSwizzler.h"
#include "SkTemplates.h"
+#include "SkUtils.h"
SkSwizzler::ResultAlpha SkSwizzler::GetResult(uint8_t zeroAlpha,
uint8_t maxAlpha) {
@@ -20,6 +21,29 @@
// kIndex1, kIndex2, kIndex4
+static SkSwizzler::ResultAlpha swizzle_small_index_to_index(
+ void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
+ int bitsPerPixel, int y, const SkPMColor ctable[]) {
+
+ uint8_t* SK_RESTRICT dst = (uint8_t*) dstRow;
+ INIT_RESULT_ALPHA;
+ const uint32_t pixelsPerByte = 8 / bitsPerPixel;
+ const size_t rowBytes = compute_row_bytes_ppb(width, pixelsPerByte);
+ const uint8_t mask = (1 << bitsPerPixel) - 1;
+ int x = 0;
+ for (uint32_t byte = 0; byte < rowBytes; byte++) {
+ uint8_t pixelData = src[byte];
+ for (uint32_t p = 0; p < pixelsPerByte && x < width; p++) {
+ uint8_t index = (pixelData >> (8 - bitsPerPixel)) & mask;
+ UPDATE_RESULT_ALPHA(ctable[index] >> SK_A32_SHIFT);
+ dst[x] = index;
+ pixelData <<= bitsPerPixel;
+ x++;
+ }
+ }
+ return COMPUTE_RESULT_ALPHA;
+}
+
static SkSwizzler::ResultAlpha swizzle_small_index_to_n32(
void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
int bitsPerPixel, int y, const SkPMColor ctable[]) {
@@ -44,26 +68,20 @@
return COMPUTE_RESULT_ALPHA;
}
-static SkSwizzler::ResultAlpha swizzle_small_index_to_565(
+static SkSwizzler::ResultAlpha swizzle_index_to_index(
void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
- int bitsPerPixel, int y, const SkPMColor ctable[]) {
+ int bytesPerPixel, int y, const SkPMColor ctable[]) {
- uint16_t* SK_RESTRICT dst = (uint16_t*) dstRow;
- const uint32_t pixelsPerByte = 8 / bitsPerPixel;
- const size_t rowBytes = compute_row_bytes_ppb(width, pixelsPerByte);
- const uint8_t mask = (1 << bitsPerPixel) - 1;
- int x = 0;
- for (uint32_t byte = 0; byte < rowBytes; byte++) {
- uint8_t pixelData = src[byte];
- for (uint32_t p = 0; p < pixelsPerByte && x < width; p++) {
- uint8_t index = (pixelData >> (8 - bitsPerPixel)) & mask;
- uint16_t c = SkPixel32ToPixel16(ctable[index]);
- dst[x] = c;
- pixelData <<= bitsPerPixel;
- x++;
- }
+ uint8_t* SK_RESTRICT dst = (uint8_t*) dstRow;
+ memcpy(dst, src, width);
+ // TODO (msarett): Should we skip the loop here and guess that the row is opaque/not opaque?
+ // SkScaledBitmap sampler just guesses that it is opaque. This is dangerous
+ // and probably wrong since gif and bmp (rarely) may have alpha.
+ INIT_RESULT_ALPHA;
+ for (int x = 0; x < width; x++) {
+ UPDATE_RESULT_ALPHA(ctable[src[x]] >> SK_A32_SHIFT);
}
- return SkSwizzler::kOpaque_ResultAlpha;
+ return COMPUTE_RESULT_ALPHA;
}
// kIndex
@@ -75,10 +93,9 @@
SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
INIT_RESULT_ALPHA;
for (int x = 0; x < width; x++) {
- SkPMColor c = ctable[*src];
+ SkPMColor c = ctable[src[x]];
UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT);
dst[x] = c;
- src++;
}
return COMPUTE_RESULT_ALPHA;
}
@@ -90,29 +107,15 @@
SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
INIT_RESULT_ALPHA;
for (int x = 0; x < width; x++) {
- SkPMColor c = ctable[*src];
+ SkPMColor c = ctable[src[x]];
UPDATE_RESULT_ALPHA(c >> SK_A32_SHIFT);
if (c != 0) {
dst[x] = c;
}
- src++;
}
return COMPUTE_RESULT_ALPHA;
}
-static SkSwizzler::ResultAlpha swizzle_index_to_565(
- void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
- int bytesPerPixel, int y, const SkPMColor ctable[]) {
-
- uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
- for (int x = 0; x < width; x++) {
- uint16_t c = SkPixel32ToPixel16(ctable[*src]);
- dst[x] = c;
- src++;
- }
- return SkSwizzler::kOpaque_ResultAlpha;
-}
-
#undef A32_MASK_IN_PLACE
static SkSwizzler::ResultAlpha swizzle_bgrx_to_n32(
@@ -127,18 +130,6 @@
return SkSwizzler::kOpaque_ResultAlpha;
}
-static SkSwizzler::ResultAlpha swizzle_bgrx_to_565(
- void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width,
- int bytesPerPixel, int y, const SkPMColor ctable[]) {
-
- uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
- for (int x = 0; x < width; x++) {
- dst[x] = SkPack888ToRGB16(src[2], src[1], src[0]);
- src += bytesPerPixel;
- }
- return SkSwizzler::kOpaque_ResultAlpha;
-}
-
// kBGRA
static SkSwizzler::ResultAlpha swizzle_bgra_to_n32_unpremul(
@@ -282,8 +273,8 @@
case kN32_SkColorType:
proc = &swizzle_small_index_to_n32;
break;
- case kRGB_565_SkColorType:
- proc = &swizzle_small_index_to_565;
+ case kIndex_8_SkColorType:
+ proc = &swizzle_small_index_to_index;
break;
default:
break;
@@ -301,8 +292,8 @@
break;
}
break;
- case kRGB_565_SkColorType:
- proc = &swizzle_index_to_565;
+ case kIndex_8_SkColorType:
+ proc = &swizzle_index_to_index;
break;
default:
break;
@@ -314,9 +305,6 @@
case kN32_SkColorType:
proc = &swizzle_bgrx_to_n32;
break;
- case kRGB_565_SkColorType:
- proc = &swizzle_bgrx_to_565;
- break;
default:
break;
}
@@ -433,3 +421,56 @@
return fRowProc(row, src, fDstInfo.width(), fDeltaSrc, fCurrY,
fColorTable);
}
+
+void SkSwizzler::Fill(void* dst, const SkImageInfo& dstInfo, size_t dstRowBytes, uint32_t y,
+ uint32_t colorOrIndex, SkPMColor* colorTable) {
+ SkASSERT(dst != NULL);
+ SkASSERT(y < (uint32_t) dstInfo.height());
+
+ // Get dst start row
+ void* dstRow = SkTAddOffset<void*>(dst, y * dstRowBytes);
+
+ // Calculate remaining bytes. This is tricky since the final row may not be padded.
+ const size_t totalBytes = dstInfo.getSafeSize(dstRowBytes);
+ const size_t remainingBytes = totalBytes - y * dstRowBytes;
+
+ // Use the proper memset routine to fill the remaining bytes
+ switch(dstInfo.colorType()) {
+ case kN32_SkColorType:
+ // Assume input is an index if we have a color table
+ uint32_t color;
+ if (NULL != colorTable) {
+ SkASSERT(colorOrIndex == (uint8_t) colorOrIndex);
+ color = colorTable[colorOrIndex];
+ // Otherwise, assume the input is a color
+ } else {
+ color = colorOrIndex;
+ }
+
+ // We must fill row by row in the case of unaligned row bytes
+ if (SkIsAlign4((size_t) dstRow) && SkIsAlign4(dstRowBytes)) {
+ sk_memset32((uint32_t*) dstRow, color,
+ (uint32_t) remainingBytes / sizeof(SkPMColor));
+ } else {
+ // This is an unlikely, slow case
+ SkCodecPrintf("Warning: Strange number of row bytes, fill will be slow.\n");
+ for (int32_t row = y; row < dstInfo.height(); row++) {
+ uint32_t* dstPtr = (uint32_t*) dstRow;
+ for (int32_t col = 0; col < dstInfo.width(); col++) {
+ dstPtr[col] = color;
+ }
+ dstRow = SkTAddOffset<void*>(dstRow, dstRowBytes);
+ }
+ }
+ break;
+ // On an index destination color type, always assume the input is an index
+ case kIndex_8_SkColorType:
+ SkASSERT(colorOrIndex == (uint8_t) colorOrIndex);
+ memset(dstRow, colorOrIndex, remainingBytes);
+ break;
+ default:
+ SkCodecPrintf("Error: Unsupported dst color type for fill(). Doing nothing.\n");
+ SkASSERT(false);
+ break;
+ }
+}
diff --git a/src/codec/SkSwizzler.h b/src/codec/SkSwizzler.h
index 63afbf7..6044c86 100644
--- a/src/codec/SkSwizzler.h
+++ b/src/codec/SkSwizzler.h
@@ -61,7 +61,7 @@
static bool IsOpaque(ResultAlpha r) {
return kOpaque_ResultAlpha == r;
}
-
+
/*
*
* Constructs the proper result code based on accumulated alpha masks
@@ -128,6 +128,36 @@
const SkImageInfo&, void* dst,
size_t dstRowBytes,
SkImageGenerator::ZeroInitialized);
+
+ /**
+ * Fill the remainder of the destination with a single color
+ *
+ * @param y
+ * The starting row for the fill.
+ *
+ * @param colorOrIndex
+ * @param colorTable
+ * If dstInfo.colorType() is kIndex8, colorOrIndex is assumed to be a uint8_t
+ * index, and colorTable is ignored. Each 8-bit pixel will be set to (uint8_t)
+ * index.
+ *
+ * If dstInfo.colorType() is kN32, colorOrIndex is treated differently depending on
+ * whether colorTable is NULL:
+ *
+ * A NULL colorTable means colorOrIndex is treated as an SkPMColor (premul or
+ * unpremul, depending on dstInfo.alphaType()). Each 4-byte pixel will be set to
+ * colorOrIndex.
+
+ * A non-NULL colorTable means colorOrIndex is treated as a uint8_t index into
+ * the colorTable. i.e. each 4-byte pixel will be set to
+ * colorTable[(uint8_t) colorOrIndex].
+ *
+ * Other SkColorTypes are not supported.
+ *
+ */
+ static void Fill(void* dst, const SkImageInfo& dstInfo, size_t dstRowBytes, uint32_t y,
+ uint32_t colorOrIndex, SkPMColor* colorTable);
+
/**
* Swizzle the next line. Call height times, once for each row of source.
* @param src The next row of the source data.
@@ -156,6 +186,7 @@
* destination?
*/
void setDstRow(void* dst) { fDstRow = dst; }
+
private:
#ifdef SK_DEBUG