aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/images
diff options
context:
space:
mode:
authorGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-10-01 17:27:15 +0000
committerGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-10-01 17:27:15 +0000
commit8d2392487cd97e68c0a71da9fd5d2b42ecac5ec8 (patch)
treee7133b74f371352488ce900f9371bc68977ee1ea /src/images
parent3702b2587cb18021d8efdd001ab3c9085f0ac51a (diff)
Add an option on SkImageDecoder to skip writing 0s.
Only implemented for PNG. Add a getter and setter, and sets the default to false in the constructor. Also copies the setting in copyFieldsToOther. Fix an indpendent bug where fDitherImage was not being copied in copyFieldsToOther. In SkScaledBitmapSampler::begin, consolidate the settings passed in by passing a const reference to the decoder. The decoder can be referenced for its settings of dither, unpremultiplied, and now skipping writing zeroes. Update callers to use the new API. In png decoder, rather than passing around a pointer to an initial read of getDitherImage, and potentially changing it, look at the field on the decoder itself, and modify it directly. This is a change in behavior - now if that same decoder is used to decode a different image, the dither setting has changed. I think this is okay because A) the typical use case is to use a new decoder for each decode, B) we do not make any promises that a decode does not change the decoder and C) it makes the code in SkScaledBitmapSampler much cleaner. In SkScaledBitmapScampler, add new row procs for skipping zeroes. Now that choosing the row proc has five dimensions (src config, dst config, dither, skip writing zeroes, unpremultiplied), use a new method: each src/dst combination has a function for choosing the right proc depending on the decoder. SkScaledBitmapScampler::RowProc is now public for convenience. Remove Sample_Gray_D8888_Unpremul, which is effectively no different from Sample_Gray_D8888. In cases where unpremultiplied was trivial, such as 565 and when sampling from gray, decoding may now succeed. Add a benchmark (currently disabled) for comparing the speed of skipping writing zeroes versus not skipping. For this particular image, which is mostly transparent pixels, normal decoding took about 3.6 milliseconds, while skipping zeroes in the decode took only about 2.5 milliseconds (this is on a Nexus 4). Presumably it would be slower on an image with a small amount of transparency, but there will be no slowdown for an image which reports that it has no transparency. In SkImageRef_ashmem, always skip writing zeroes, since ashmem memory is guaranteed to be initialized to 0. Add a flag to skip writing zeroes in skimage. Add a regression test for choosing the rowproc to ensure I did not change any behavior accidentally. BUG=skia:1661 R=reed@google.com Review URL: https://codereview.chromium.org/24269006 git-svn-id: http://skia.googlecode.com/svn/trunk@11558 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/images')
-rw-r--r--src/images/SkImageDecoder.cpp3
-rw-r--r--src/images/SkImageDecoder_libbmp.cpp2
-rw-r--r--src/images/SkImageDecoder_libjpeg.cpp4
-rw-r--r--src/images/SkImageDecoder_libpng.cpp19
-rw-r--r--src/images/SkImageRef_ashmem.cpp3
-rw-r--r--src/images/SkScaledBitmapSampler.cpp517
-rw-r--r--src/images/SkScaledBitmapSampler.h20
7 files changed, 446 insertions, 122 deletions
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index 1544edf366..15cd1a60c0 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -40,6 +40,7 @@ SkImageDecoder::SkImageDecoder()
, fDefaultPref(SkBitmap::kNo_Config)
, fDitherImage(true)
, fUsePrefTable(false)
+ , fSkipWritingZeroes(false)
, fPreferQualityOverSpeed(false)
, fRequireUnpremultipliedColors(false) {
}
@@ -63,6 +64,8 @@ void SkImageDecoder::copyFieldsToOther(SkImageDecoder* other) {
} else {
other->fDefaultPref = fDefaultPref;
}
+ other->setDitherImage(fDitherImage);
+ other->setSkipWritingZeroes(fSkipWritingZeroes);
other->setPreferQualityOverSpeed(fPreferQualityOverSpeed);
other->setRequireUnpremultipliedColors(fRequireUnpremultipliedColors);
}
diff --git a/src/images/SkImageDecoder_libbmp.cpp b/src/images/SkImageDecoder_libbmp.cpp
index 3eb181f781..2283dbf51d 100644
--- a/src/images/SkImageDecoder_libbmp.cpp
+++ b/src/images/SkImageDecoder_libbmp.cpp
@@ -146,7 +146,7 @@ bool SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
SkAutoLockPixels alp(*bm);
- if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, getDitherImage())) {
+ if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
return false;
}
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index 37be2a7091..3b3ea887e3 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -588,7 +588,7 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
return return_false(cinfo, *bm, "jpeg colorspace");
}
- if (!sampler.begin(bm, sc, this->getDitherImage())) {
+ if (!sampler.begin(bm, sc, *this)) {
return return_false(cinfo, *bm, "sampler.begin");
}
@@ -827,7 +827,7 @@ bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
return return_false(*cinfo, *bm, "jpeg colorspace");
}
- if (!sampler.begin(&bitmap, sc, this->getDitherImage())) {
+ if (!sampler.begin(&bitmap, sc, *this)) {
return return_false(*cinfo, bitmap, "sampler.begin");
}
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index b6aa329104..e942f21c78 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -91,7 +91,7 @@ private:
SkColorTable **colorTablep);
bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
SkBitmap::Config *config, bool *hasAlpha,
- bool *doDither, SkPMColor *theTranspColor);
+ SkPMColor *theTranspColor);
typedef SkImageDecoder INHERITED;
};
@@ -294,10 +294,9 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
SkBitmap::Config config;
bool hasAlpha = false;
- bool doDither = this->getDitherImage();
SkPMColor theTranspColor = 0; // 0 tells us not to try to match
- if (!getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theTranspColor)) {
+ if (!this->getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &theTranspColor)) {
return false;
}
@@ -377,8 +376,7 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
upscale png's palette to a direct model
*/
SkAutoLockColors ctLock(colorTable);
- if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors(),
- this->getRequireUnpremultipliedColors())) {
+ if (!sampler.begin(decodedBitmap, sc, *this, ctLock.colors())) {
return false;
}
const int height = decodedBitmap->height();
@@ -446,7 +444,6 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
SkBitmap::Config* SK_RESTRICT configp,
bool* SK_RESTRICT hasAlphap,
- bool* SK_RESTRICT doDitherp,
SkPMColor* SK_RESTRICT theTranspColorp) {
png_uint_32 origWidth, origHeight;
int bitDepth, colorType;
@@ -456,7 +453,7 @@ bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
// check for sBIT chunk data, in case we should disable dithering because
// our data is not truely 8bits per component
png_color_8p sig_bit;
- if (*doDitherp && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) {
+ if (this->getDitherImage() && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) {
#if 0
SkDebugf("----- sBIT %d %d %d %d\n", sig_bit->red, sig_bit->green,
sig_bit->blue, sig_bit->alpha);
@@ -465,7 +462,7 @@ bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
if (pos_le(sig_bit->red, SK_R16_BITS) &&
pos_le(sig_bit->green, SK_G16_BITS) &&
pos_le(sig_bit->blue, SK_B16_BITS)) {
- *doDitherp = false;
+ this->setDitherImage(false);
}
}
@@ -724,10 +721,9 @@ bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
SkBitmap::Config config;
bool hasAlpha = false;
- bool doDither = this->getDitherImage();
SkPMColor theTranspColor = 0; // 0 tells us not to try to match
- if (!getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theTranspColor)) {
+ if (!this->getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &theTranspColor)) {
return false;
}
@@ -834,8 +830,7 @@ bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
upscale png's palette to a direct model
*/
SkAutoLockColors ctLock(colorTable);
- if (!sampler.begin(&decodedBitmap, sc, doDither, ctLock.colors(),
- this->getRequireUnpremultipliedColors())) {
+ if (!sampler.begin(&decodedBitmap, sc, *this, ctLock.colors())) {
return false;
}
const int height = decodedBitmap.height();
diff --git a/src/images/SkImageRef_ashmem.cpp b/src/images/SkImageRef_ashmem.cpp
index 0186bf6a55..0dba1d1191 100644
--- a/src/images/SkImageRef_ashmem.cpp
+++ b/src/images/SkImageRef_ashmem.cpp
@@ -134,6 +134,9 @@ bool SkImageRef_ashmem::onDecode(SkImageDecoder* codec, SkStreamRewindable* stre
return this->INHERITED::onDecode(codec, stream, bitmap, config, mode);
}
+ // Ashmem memory is guaranteed to be initialized to 0.
+ codec->setSkipWritingZeroes(true);
+
AshmemAllocator alloc(&fRec, this->getURI());
codec->setAllocator(&alloc);
diff --git a/src/images/SkScaledBitmapSampler.cpp b/src/images/SkScaledBitmapSampler.cpp
index 021f86ba86..3bab8de9fd 100644
--- a/src/images/SkScaledBitmapSampler.cpp
+++ b/src/images/SkScaledBitmapSampler.cpp
@@ -25,6 +25,11 @@ static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow,
return false;
}
+static SkScaledBitmapSampler::RowProc get_gray_to_8888_proc(const SkImageDecoder& decoder) {
+ // Dither, unpremul, and skipZeroes have no effect
+ return Sample_Gray_D8888;
+}
+
static bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor[]) {
@@ -36,6 +41,11 @@ static bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow,
return false;
}
+static SkScaledBitmapSampler::RowProc get_RGBx_to_8888_proc(const SkImageDecoder& decoder) {
+ // Dither, unpremul, and skipZeroes have no effect
+ return Sample_RGBx_D8888;
+}
+
static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor[]) {
@@ -50,6 +60,52 @@ static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow,
return alphaMask != 0xFF;
}
+static bool Sample_RGBA_D8888_Unpremul(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int,
+ const SkPMColor[]) {
+ uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow);
+ unsigned alphaMask = 0xFF;
+ for (int x = 0; x < width; x++) {
+ unsigned alpha = src[3];
+ dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
+ src += deltaSrc;
+ alphaMask &= alpha;
+ }
+ return alphaMask != 0xFF;
+}
+
+static bool Sample_RGBA_D8888_SkipZ(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int,
+ const SkPMColor[]) {
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
+ unsigned alphaMask = 0xFF;
+ for (int x = 0; x < width; x++) {
+ unsigned alpha = src[3];
+ if (0 != alpha) {
+ dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
+ }
+ src += deltaSrc;
+ alphaMask &= alpha;
+ }
+ return alphaMask != 0xFF;
+}
+
+static SkScaledBitmapSampler::RowProc get_RGBA_to_8888_proc(const SkImageDecoder& decoder) {
+ // Dither has no effect.
+ if (decoder.getRequireUnpremultipliedColors()) {
+ // We could check each component for a zero, at the expense of extra checks.
+ // For now, just return unpremul.
+ return Sample_RGBA_D8888_Unpremul;
+ }
+ // Supply the versions that premultiply the colors
+ if (decoder.getSkipWritingZeroes()) {
+ return Sample_RGBA_D8888_SkipZ;
+ }
+ return Sample_RGBA_D8888;
+}
+
// 565
static bool Sample_Gray_D565(void* SK_RESTRICT dstRow,
@@ -75,6 +131,14 @@ static bool Sample_Gray_D565_D(void* SK_RESTRICT dstRow,
return false;
}
+static SkScaledBitmapSampler::RowProc get_gray_to_565_proc(const SkImageDecoder& decoder) {
+ // Unpremul and skip zeroes make no difference
+ if (decoder.getDitherImage()) {
+ return Sample_Gray_D565_D;
+ }
+ return Sample_Gray_D565;
+}
+
static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor[]) {
@@ -86,6 +150,28 @@ static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow,
return false;
}
+static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int y,
+ const SkPMColor[]) {
+ uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
+ DITHER_565_SCAN(y);
+ for (int x = 0; x < width; x++) {
+ dst[x] = SkDitherRGBTo565(src[0], src[1], src[2], DITHER_VALUE(x));
+ src += deltaSrc;
+ }
+ return false;
+}
+
+static SkScaledBitmapSampler::RowProc get_RGBx_to_565_proc(const SkImageDecoder& decoder) {
+ // Unpremul and skip zeroes make no difference
+ if (decoder.getDitherImage()) {
+ return Sample_RGBx_D565_D;
+ }
+ return Sample_RGBx_D565;
+}
+
+
static bool Sample_D565_D565(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor[]) {
@@ -98,16 +184,9 @@ static bool Sample_D565_D565(void* SK_RESTRICT dstRow,
return false;
}
-static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int y, const SkPMColor[]) {
- uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
- DITHER_565_SCAN(y);
- for (int x = 0; x < width; x++) {
- dst[x] = SkDitherRGBTo565(src[0], src[1], src[2], DITHER_VALUE(x));
- src += deltaSrc;
- }
- return false;
+static SkScaledBitmapSampler::RowProc get_565_to_565_proc(const SkImageDecoder& decoder) {
+ // Unpremul, dither, and skip zeroes have no effect
+ return Sample_D565_D565;
}
// 4444
@@ -137,6 +216,14 @@ static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow,
return false;
}
+static SkScaledBitmapSampler::RowProc get_gray_to_4444_proc(const SkImageDecoder& decoder) {
+ // Skip zeroes and unpremul make no difference
+ if (decoder.getDitherImage()) {
+ return Sample_Gray_D4444_D;
+ }
+ return Sample_Gray_D4444;
+}
+
static bool Sample_RGBx_D4444(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor[]) {
@@ -162,6 +249,14 @@ static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow,
return false;
}
+static SkScaledBitmapSampler::RowProc get_RGBx_to_4444_proc(const SkImageDecoder& decoder) {
+ // Skip zeroes and unpremul make no difference
+ if (decoder.getDitherImage()) {
+ return Sample_RGBx_D4444_D;
+ }
+ return Sample_RGBx_D4444;
+}
+
static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor[]) {
@@ -178,9 +273,30 @@ static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow,
return alphaMask != 0xFF;
}
+static bool Sample_RGBA_D4444_SkipZ(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int,
+ const SkPMColor[]) {
+ SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
+ unsigned alphaMask = 0xFF;
+
+ for (int x = 0; x < width; x++) {
+ unsigned alpha = src[3];
+ if (alpha != 0) {
+ SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
+ dst[x] = SkPixel32ToPixel4444(c);
+ }
+ src += deltaSrc;
+ alphaMask &= alpha;
+ }
+ return alphaMask != 0xFF;
+}
+
+
static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int y, const SkPMColor[]) {
+ int width, int deltaSrc, int y,
+ const SkPMColor[]) {
SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
unsigned alphaMask = 0xFF;
DITHER_4444_SCAN(y);
@@ -195,6 +311,44 @@ static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow,
return alphaMask != 0xFF;
}
+static bool Sample_RGBA_D4444_D_SkipZ(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int y,
+ const SkPMColor[]) {
+ SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
+ unsigned alphaMask = 0xFF;
+ DITHER_4444_SCAN(y);
+
+ for (int x = 0; x < width; x++) {
+ unsigned alpha = src[3];
+ if (alpha != 0) {
+ SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
+ dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
+ }
+ src += deltaSrc;
+ alphaMask &= alpha;
+ }
+ return alphaMask != 0xFF;
+}
+
+static SkScaledBitmapSampler::RowProc get_RGBA_to_4444_proc(const SkImageDecoder& decoder) {
+ if (decoder.getRequireUnpremultipliedColors()) {
+ // Unpremultiplied is not supported for 4444
+ return NULL;
+ }
+ const bool dither = decoder.getDitherImage();
+ if (decoder.getSkipWritingZeroes()) {
+ if (dither) {
+ return Sample_RGBA_D4444_D_SkipZ;
+ }
+ return Sample_RGBA_D4444_SkipZ;
+ }
+ if (dither) {
+ return Sample_RGBA_D4444_D;
+ }
+ return Sample_RGBA_D4444;
+}
+
// Index
#define A32_MASK_IN_PLACE (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT)
@@ -214,6 +368,36 @@ static bool Sample_Index_D8888(void* SK_RESTRICT dstRow,
return cc != A32_MASK_IN_PLACE;
}
+static bool Sample_Index_D8888_SkipZ(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int,
+ const SkPMColor ctable[]) {
+
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
+ SkPMColor cc = A32_MASK_IN_PLACE;
+ for (int x = 0; x < width; x++) {
+ SkPMColor c = ctable[*src];
+ cc &= c;
+ if (c != 0) {
+ dst[x] = c;
+ }
+ src += deltaSrc;
+ }
+ return cc != A32_MASK_IN_PLACE;
+}
+
+static SkScaledBitmapSampler::RowProc get_index_to_8888_proc(const SkImageDecoder& decoder) {
+ if (decoder.getRequireUnpremultipliedColors()) {
+ // Unpremultiplied is not supported for an index source.
+ return NULL;
+ }
+ // Dither makes no difference
+ if (decoder.getSkipWritingZeroes()) {
+ return Sample_Index_D8888_SkipZ;
+ }
+ return Sample_Index_D8888;
+}
+
static bool Sample_Index_D565(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor ctable[]) {
@@ -242,6 +426,14 @@ static bool Sample_Index_D565_D(void* SK_RESTRICT dstRow,
return false;
}
+static SkScaledBitmapSampler::RowProc get_index_to_565_proc(const SkImageDecoder& decoder) {
+ // Unpremultiplied and skip zeroes make no difference
+ if (decoder.getDitherImage()) {
+ return Sample_Index_D565_D;
+ }
+ return Sample_Index_D565;
+}
+
static bool Sample_Index_D4444(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src, int width,
int deltaSrc, int y, const SkPMColor ctable[]) {
@@ -274,6 +466,60 @@ static bool Sample_Index_D4444_D(void* SK_RESTRICT dstRow,
return cc != A32_MASK_IN_PLACE;
}
+static bool Sample_Index_D4444_SkipZ(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src, int width,
+ int deltaSrc, int y, const SkPMColor ctable[]) {
+
+ SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
+ SkPMColor cc = A32_MASK_IN_PLACE;
+ for (int x = 0; x < width; x++) {
+ SkPMColor c = ctable[*src];
+ cc &= c;
+ if (c != 0) {
+ dst[x] = SkPixel32ToPixel4444(c);
+ }
+ src += deltaSrc;
+ }
+ return cc != A32_MASK_IN_PLACE;
+}
+
+static bool Sample_Index_D4444_D_SkipZ(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src, int width,
+ int deltaSrc, int y, const SkPMColor ctable[]) {
+
+ SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
+ SkPMColor cc = A32_MASK_IN_PLACE;
+ DITHER_4444_SCAN(y);
+
+ for (int x = 0; x < width; x++) {
+ SkPMColor c = ctable[*src];
+ cc &= c;
+ if (c != 0) {
+ dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
+ }
+ src += deltaSrc;
+ }
+ return cc != A32_MASK_IN_PLACE;
+}
+
+static SkScaledBitmapSampler::RowProc get_index_to_4444_proc(const SkImageDecoder& decoder) {
+ // Unpremul not allowed
+ if (decoder.getRequireUnpremultipliedColors()) {
+ return NULL;
+ }
+ const bool dither = decoder.getDitherImage();
+ if (decoder.getSkipWritingZeroes()) {
+ if (dither) {
+ return Sample_Index_D4444_D_SkipZ;
+ }
+ return Sample_Index_D4444_SkipZ;
+ }
+ if (dither) {
+ return Sample_Index_D4444_D;
+ }
+ return Sample_Index_D4444;
+}
+
static bool Sample_Index_DI(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor[]) {
@@ -289,6 +535,15 @@ static bool Sample_Index_DI(void* SK_RESTRICT dstRow,
return false;
}
+static SkScaledBitmapSampler::RowProc get_index_to_index_proc(const SkImageDecoder& decoder) {
+ // Unpremul not allowed
+ if (decoder.getRequireUnpremultipliedColors()) {
+ return NULL;
+ }
+ // Ignore dither and skip zeroes
+ return Sample_Index_DI;
+}
+
// A8
static bool Sample_Gray_DA8(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
@@ -298,41 +553,15 @@ static bool Sample_Gray_DA8(void* SK_RESTRICT dstRow,
return true;
}
-// 8888 Unpremul
-
-static bool Sample_Gray_D8888_Unpremul(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int,
- const SkPMColor[]) {
- uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow);
- for (int x = 0; x < width; x++) {
- dst[x] = SkPackARGB32NoCheck(0xFF, src[0], src[0], src[0]);
- src += deltaSrc;
- }
- return false;
-}
-
-// Sample_RGBx_D8888_Unpremul is no different from Sample_RGBx_D8888, since alpha
-// is 0xFF
-
-static bool Sample_RGBA_D8888_Unpremul(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int,
- const SkPMColor[]) {
- uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow);
- unsigned alphaMask = 0xFF;
- for (int x = 0; x < width; x++) {
- unsigned alpha = src[3];
- dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
- src += deltaSrc;
- alphaMask &= alpha;
+static SkScaledBitmapSampler::RowProc get_gray_to_A8_proc(const SkImageDecoder& decoder) {
+ if (decoder.getRequireUnpremultipliedColors()) {
+ return NULL;
}
- return alphaMask != 0xFF;
+ // Ignore skip and dither.
+ return Sample_Gray_DA8;
}
-// Sample_Index_D8888_Unpremul is the same as Sample_Index_D8888, since the
-// color table has its colors inserted unpremultiplied.
-
+typedef SkScaledBitmapSampler::RowProc (*RowProcChooser)(const SkImageDecoder& decoder);
///////////////////////////////////////////////////////////////////////////////
#include "SkScaledBitmapSampler.h"
@@ -377,58 +606,49 @@ SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height,
SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height);
}
-bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither,
- const SkPMColor ctable[],
- bool requireUnpremul) {
- static const RowProc gProcs[] = {
- // 8888 (no dither distinction)
- Sample_Gray_D8888, Sample_Gray_D8888,
- Sample_RGBx_D8888, Sample_RGBx_D8888,
- Sample_RGBA_D8888, Sample_RGBA_D8888,
- Sample_Index_D8888, Sample_Index_D8888,
- NULL, NULL,
- // 565 (no alpha distinction)
- Sample_Gray_D565, Sample_Gray_D565_D,
- Sample_RGBx_D565, Sample_RGBx_D565_D,
- Sample_RGBx_D565, Sample_RGBx_D565_D,
- Sample_Index_D565, Sample_Index_D565_D,
- Sample_D565_D565, Sample_D565_D565,
- // 4444
- Sample_Gray_D4444, Sample_Gray_D4444_D,
- Sample_RGBx_D4444, Sample_RGBx_D4444_D,
- Sample_RGBA_D4444, Sample_RGBA_D4444_D,
- Sample_Index_D4444, Sample_Index_D4444_D,
- NULL, NULL,
- // Index8
- NULL, NULL,
- NULL, NULL,
- NULL, NULL,
- Sample_Index_DI, Sample_Index_DI,
- NULL, NULL,
- // A8
- Sample_Gray_DA8, Sample_Gray_DA8,
- NULL, NULL,
- NULL, NULL,
- NULL, NULL,
- NULL, NULL,
- // 8888 Unpremul (no dither distinction)
- Sample_Gray_D8888_Unpremul, Sample_Gray_D8888_Unpremul,
- Sample_RGBx_D8888, Sample_RGBx_D8888,
- Sample_RGBA_D8888_Unpremul, Sample_RGBA_D8888_Unpremul,
- Sample_Index_D8888, Sample_Index_D8888,
- NULL, NULL,
+bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc,
+ const SkImageDecoder& decoder,
+ const SkPMColor ctable[]) {
+ static const RowProcChooser gProcChoosers[] = {
+ get_gray_to_8888_proc,
+ get_RGBx_to_8888_proc,
+ get_RGBA_to_8888_proc,
+ get_index_to_8888_proc,
+ NULL, // 565 to 8888
+
+ get_gray_to_565_proc,
+ get_RGBx_to_565_proc,
+ get_RGBx_to_565_proc, // The source alpha will be ignored.
+ get_index_to_565_proc,
+ get_565_to_565_proc,
+
+ get_gray_to_4444_proc,
+ get_RGBx_to_4444_proc,
+ get_RGBA_to_4444_proc,
+ get_index_to_4444_proc,
+ NULL, // 565 to 4444
+
+ NULL, // gray to index
+ NULL, // rgbx to index
+ NULL, // rgba to index
+ get_index_to_index_proc,
+ NULL, // 565 to index
+
+ get_gray_to_A8_proc,
+ NULL, // rgbx to a8
+ NULL, // rgba to a8
+ NULL, // index to a8
+ NULL, // 565 to a8
};
+
// The jump between dst configs in the table
- static const int gProcDstConfigSpan = 10;
- SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gProcs) == 6 * gProcDstConfigSpan,
+ static const int gProcDstConfigSpan = 5;
+ SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gProcChoosers) == 5 * gProcDstConfigSpan,
gProcs_has_the_wrong_number_of_entries);
fCTable = ctable;
int index = 0;
- if (dither) {
- index += 1;
- }
switch (sc) {
case SkScaledBitmapSampler::kGray:
fSrcPixelSize = 1;
@@ -436,23 +656,23 @@ bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither,
break;
case SkScaledBitmapSampler::kRGB:
fSrcPixelSize = 3;
- index += 2;
+ index += 1;
break;
case SkScaledBitmapSampler::kRGBX:
fSrcPixelSize = 4;
- index += 2;
+ index += 1;
break;
case SkScaledBitmapSampler::kRGBA:
fSrcPixelSize = 4;
- index += 4;
+ index += 2;
break;
case SkScaledBitmapSampler::kIndex:
fSrcPixelSize = 1;
- index += 6;
+ index += 3;
break;
case SkScaledBitmapSampler::kRGB_565:
fSrcPixelSize = 2;
- index += 8;
+ index += 4;
break;
default:
return false;
@@ -478,14 +698,12 @@ bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, bool dither,
return false;
}
- if (requireUnpremul) {
- if (dst->config() != SkBitmap::kARGB_8888_Config) {
- return false;
- }
- index += 5 * gProcDstConfigSpan;
+ RowProcChooser chooser = gProcChoosers[index];
+ if (NULL == chooser) {
+ fRowProc = NULL;
+ } else {
+ fRowProc = chooser(decoder);
}
-
- fRowProc = gProcs[index];
fDstRow = (char*)dst->getPixels();
fDstRowBytes = dst->rowBytes();
fCurrY = 0;
@@ -501,3 +719,102 @@ bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) {
fCurrY += 1;
return hadAlpha;
}
+
+#ifdef SK_DEBUG
+// The following code is for a test to ensure that changing the method to get the right row proc
+// did not change the row proc unintentionally. Tested by ImageDecodingTest.cpp
+
+// friend of SkScaledBitmapSampler solely for the purpose of accessing fRowProc.
+class RowProcTester {
+public:
+ static SkScaledBitmapSampler::RowProc getRowProc(const SkScaledBitmapSampler& sampler) {
+ return sampler.fRowProc;
+ }
+};
+
+
+// Table showing the expected RowProc for each combination of inputs.
+// Table formated as follows:
+// Each group of 5 consecutive rows represents sampling from a single
+// SkScaledBitmapSampler::SrcConfig.
+// Within each set, each row represents a different destination SkBitmap::Config
+// Each column represents a different combination of dither and unpremul.
+// D = dither ~D = no dither
+// U = unpremul ~U = no unpremul
+// ~D~U D~U ~DU DU
+SkScaledBitmapSampler::RowProc gTestProcs[] = {
+ // Gray
+ Sample_Gray_DA8, Sample_Gray_DA8, NULL, NULL, // to A8
+ NULL, NULL, NULL, NULL, // to Index8
+ Sample_Gray_D565, Sample_Gray_D565_D, Sample_Gray_D565, Sample_Gray_D565_D, // to 565
+ Sample_Gray_D4444, Sample_Gray_D4444_D, Sample_Gray_D4444, Sample_Gray_D4444_D, // to 4444
+ Sample_Gray_D8888, Sample_Gray_D8888, Sample_Gray_D8888, Sample_Gray_D8888, // to 8888
+ // Index
+ NULL, NULL, NULL, NULL, // to A8
+ Sample_Index_DI, Sample_Index_DI, NULL, NULL, // to Index8
+ Sample_Index_D565, Sample_Index_D565_D, Sample_Index_D565, Sample_Index_D565_D, // to 565
+ Sample_Index_D4444, Sample_Index_D4444_D, NULL, NULL, // to 4444
+ Sample_Index_D8888, Sample_Index_D8888, NULL, NULL, // to 8888
+ // RGB
+ NULL, NULL, NULL, NULL, // to A8
+ NULL, NULL, NULL, NULL, // to Index8
+ Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565
+ Sample_RGBx_D4444, Sample_RGBx_D4444_D, Sample_RGBx_D4444, Sample_RGBx_D4444_D, // to 4444
+ Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, // to 8888
+ // RGBx is the same as RGB
+ NULL, NULL, NULL, NULL, // to A8
+ NULL, NULL, NULL, NULL, // to Index8
+ Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565
+ Sample_RGBx_D4444, Sample_RGBx_D4444_D, Sample_RGBx_D4444, Sample_RGBx_D4444_D, // to 4444
+ Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, // to 8888
+ // RGBA
+ NULL, NULL, NULL, NULL, // to A8
+ NULL, NULL, NULL, NULL, // to Index8
+ Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565
+ Sample_RGBA_D4444, Sample_RGBA_D4444_D, NULL, NULL, // to 4444
+ Sample_RGBA_D8888, Sample_RGBA_D8888, Sample_RGBA_D8888_Unpremul, Sample_RGBA_D8888_Unpremul, // to 8888
+ // RGB_565
+ NULL, NULL, NULL, NULL, // to A8
+ NULL, NULL, NULL, NULL, // to Index8
+ Sample_D565_D565, Sample_D565_D565, Sample_D565_D565, Sample_D565_D565, // to 565
+ NULL, NULL, NULL, NULL, // to 4444
+ NULL, NULL, NULL, NULL, // to 8888
+};
+
+// Dummy class that allows instantiation of an ImageDecoder, so begin can query its fields.
+class DummyDecoder : public SkImageDecoder {
+public:
+ DummyDecoder() {}
+protected:
+ virtual bool onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) SK_OVERRIDE {
+ return false;
+ }
+};
+
+void test_row_proc_choice() {
+ SkBitmap dummyBitmap;
+ DummyDecoder dummyDecoder;
+ size_t procCounter = 0;
+ for (int sc = SkScaledBitmapSampler::kGray; sc <= SkScaledBitmapSampler::kRGB_565; ++sc) {
+ for (int c = SkBitmap::kA8_Config; c <= SkBitmap::kARGB_8888_Config; ++c) {
+ for (int unpremul = 0; unpremul <= 1; ++unpremul) {
+ for (int dither = 0; dither <= 1; ++dither) {
+ // Arbitrary width/height/sampleSize to allow SkScaledBitmapSampler to
+ // be considered valid.
+ SkScaledBitmapSampler sampler(10, 10, 1);
+ dummyBitmap.setConfig((SkBitmap::Config) c, 10, 10);
+ dummyDecoder.setDitherImage(SkToBool(dither));
+ dummyDecoder.setRequireUnpremultipliedColors(SkToBool(unpremul));
+ sampler.begin(&dummyBitmap, (SkScaledBitmapSampler::SrcConfig) sc,
+ dummyDecoder);
+ SkScaledBitmapSampler::RowProc expected = gTestProcs[procCounter];
+ SkScaledBitmapSampler::RowProc actual = RowProcTester::getRowProc(sampler);
+ SkASSERT(expected == actual);
+ procCounter++;
+ }
+ }
+ }
+ }
+ SkASSERT(SK_ARRAY_COUNT(gTestProcs) == procCounter);
+}
+#endif // SK_DEBUG
diff --git a/src/images/SkScaledBitmapSampler.h b/src/images/SkScaledBitmapSampler.h
index 6477db2178..a293fe7ebb 100644
--- a/src/images/SkScaledBitmapSampler.h
+++ b/src/images/SkScaledBitmapSampler.h
@@ -10,6 +10,7 @@
#include "SkTypes.h"
#include "SkColor.h"
+#include "SkImageDecoder.h"
class SkBitmap;
@@ -35,12 +36,17 @@ public:
// Given a dst bitmap (with pixels already allocated) and a src-config,
// prepares iterator to process the src colors and write them into dst.
// Returns false if the request cannot be fulfulled.
- bool begin(SkBitmap* dst, SrcConfig sc, bool doDither,
- const SkPMColor* = NULL, bool requireUnPremul = false);
+ bool begin(SkBitmap* dst, SrcConfig sc, const SkImageDecoder& decoder,
+ const SkPMColor* = NULL);
// call with row of src pixels, for y = 0...scaledHeight-1.
// returns true if the row had non-opaque alpha in it
bool next(const uint8_t* SK_RESTRICT src);
+ typedef bool (*RowProc)(void* SK_RESTRICT dstRow,
+ const uint8_t* SK_RESTRICT src,
+ int width, int deltaSrc, int y,
+ const SkPMColor[]);
+
private:
int fScaledWidth;
int fScaledHeight;
@@ -50,11 +56,6 @@ private:
int fDX; // step between X samples
int fDY; // step between Y samples
- typedef bool (*RowProc)(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int y,
- const SkPMColor[]);
-
// setup state
char* fDstRow; // points into bitmap's pixels
size_t fDstRowBytes;
@@ -64,6 +65,11 @@ private:
// optional reference to the src colors if the src is a palette model
const SkPMColor* fCTable;
+
+#ifdef SK_DEBUG
+ // Helper class allowing a test to have access to fRowProc.
+ friend class RowProcTester;
+#endif
};
#endif