Index: src/images/SkScaledBitmapSampler.cpp |
diff --git a/src/images/SkScaledBitmapSampler.cpp b/src/images/SkScaledBitmapSampler.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5ffd64889396b57ac8b5bf893f7f106212be00f1 |
--- /dev/null |
+++ b/src/images/SkScaledBitmapSampler.cpp |
@@ -0,0 +1,877 @@ |
+/* |
+ * Copyright 2007 The Android Open Source Project |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+ |
+#include "SkScaledBitmapSampler.h" |
+#include "SkBitmap.h" |
+#include "SkColorPriv.h" |
+#include "SkDither.h" |
+#include "SkTypes.h" |
+ |
+// 8888 |
+ |
+static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow, |
+ const uint8_t* SK_RESTRICT src, |
+ int width, int deltaSrc, int, const SkPMColor[]) { |
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; |
+ for (int x = 0; x < width; x++) { |
+ dst[x] = SkPackARGB32(0xFF, src[0], src[0], src[0]); |
+ src += deltaSrc; |
+ } |
+ return false; |
+} |
+ |
+static SkScaledBitmapSampler::RowProc |
+get_gray_to_8888_proc(const SkScaledBitmapSampler::Options& opts) { |
+ // 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[]) { |
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; |
+ for (int x = 0; x < width; x++) { |
+ dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]); |
+ src += deltaSrc; |
+ } |
+ return false; |
+} |
+ |
+static SkScaledBitmapSampler::RowProc |
+get_RGBx_to_8888_proc(const SkScaledBitmapSampler::Options& opts) { |
+ // 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[]) { |
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; |
+ unsigned alphaMask = 0xFF; |
+ for (int x = 0; x < width; x++) { |
+ unsigned alpha = src[3]; |
+ dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); |
+ src += deltaSrc; |
+ alphaMask &= alpha; |
+ } |
+ 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 SkScaledBitmapSampler::Options& opts) { |
+ // Dither has no effect. |
+ if (!opts.fPremultiplyAlpha) { |
+ // 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 (opts.fSkipZeros) { |
+ return Sample_RGBA_D8888_SkipZ; |
+ } |
+ return Sample_RGBA_D8888; |
+} |
+ |
+// 565 |
+ |
+static bool Sample_Gray_D565(void* SK_RESTRICT dstRow, |
+ const uint8_t* SK_RESTRICT src, |
+ int width, int deltaSrc, int, const SkPMColor[]) { |
+ uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; |
+ for (int x = 0; x < width; x++) { |
+ dst[x] = SkPack888ToRGB16(src[0], src[0], src[0]); |
+ src += deltaSrc; |
+ } |
+ return false; |
+} |
+ |
+static bool Sample_Gray_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[0], src[0], DITHER_VALUE(x)); |
+ src += deltaSrc; |
+ } |
+ return false; |
+} |
+ |
+static SkScaledBitmapSampler::RowProc |
+get_gray_to_565_proc(const SkScaledBitmapSampler::Options& opts) { |
+ // Unpremul and skip zeroes make no difference |
+ if (opts.fDither) { |
+ 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[]) { |
+ uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; |
+ for (int x = 0; x < width; x++) { |
+ dst[x] = SkPack888ToRGB16(src[0], src[1], src[2]); |
+ src += deltaSrc; |
+ } |
+ 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 SkScaledBitmapSampler::Options& opts) { |
+ // Unpremul and skip zeroes make no difference |
+ if (opts.fDither) { |
+ 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[]) { |
+ uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; |
+ uint16_t* SK_RESTRICT castedSrc = (uint16_t*) src; |
+ for (int x = 0; x < width; x++) { |
+ dst[x] = castedSrc[0]; |
+ castedSrc += deltaSrc >> 1; |
+ } |
+ return false; |
+} |
+ |
+static SkScaledBitmapSampler::RowProc |
+get_565_to_565_proc(const SkScaledBitmapSampler::Options& opts) { |
+ // Unpremul, dither, and skip zeroes have no effect |
+ return Sample_D565_D565; |
+} |
+ |
+// 4444 |
+ |
+static bool Sample_Gray_D4444(void* SK_RESTRICT dstRow, |
+ const uint8_t* SK_RESTRICT src, |
+ int width, int deltaSrc, int, const SkPMColor[]) { |
+ SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; |
+ for (int x = 0; x < width; x++) { |
+ unsigned gray = src[0] >> 4; |
+ dst[x] = SkPackARGB4444(0xF, gray, gray, gray); |
+ src += deltaSrc; |
+ } |
+ return false; |
+} |
+ |
+static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow, |
+ const uint8_t* SK_RESTRICT src, |
+ int width, int deltaSrc, int y, const SkPMColor[]) { |
+ SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; |
+ DITHER_4444_SCAN(y); |
+ for (int x = 0; x < width; x++) { |
+ dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[0], src[0], |
+ DITHER_VALUE(x)); |
+ src += deltaSrc; |
+ } |
+ return false; |
+} |
+ |
+static SkScaledBitmapSampler::RowProc |
+get_gray_to_4444_proc(const SkScaledBitmapSampler::Options& opts) { |
+ // Skip zeroes and unpremul make no difference |
+ if (opts.fDither) { |
+ 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[]) { |
+ SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; |
+ for (int x = 0; x < width; x++) { |
+ dst[x] = SkPackARGB4444(0xF, src[0] >> 4, src[1] >> 4, src[2] >> 4); |
+ src += deltaSrc; |
+ } |
+ return false; |
+} |
+ |
+static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow, |
+ const uint8_t* SK_RESTRICT src, |
+ int width, int deltaSrc, int y, const SkPMColor[]) { |
+ SkPMColor16* dst = (SkPMColor16*)dstRow; |
+ DITHER_4444_SCAN(y); |
+ |
+ for (int x = 0; x < width; x++) { |
+ dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[1], src[2], |
+ DITHER_VALUE(x)); |
+ src += deltaSrc; |
+ } |
+ return false; |
+} |
+ |
+static SkScaledBitmapSampler::RowProc |
+get_RGBx_to_4444_proc(const SkScaledBitmapSampler::Options& opts) { |
+ // Skip zeroes and unpremul make no difference |
+ if (opts.fDither) { |
+ 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[]) { |
+ SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; |
+ unsigned alphaMask = 0xFF; |
+ |
+ for (int x = 0; x < width; x++) { |
+ unsigned alpha = src[3]; |
+ 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_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[]) { |
+ SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; |
+ unsigned alphaMask = 0xFF; |
+ DITHER_4444_SCAN(y); |
+ |
+ for (int x = 0; x < width; x++) { |
+ unsigned alpha = src[3]; |
+ 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 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 SkScaledBitmapSampler::Options& opts) { |
+ if (!opts.fPremultiplyAlpha) { |
+ // Unpremultiplied is not supported for 4444 |
+ return nullptr; |
+ } |
+ if (opts.fSkipZeros) { |
+ if (opts.fDither) { |
+ return Sample_RGBA_D4444_D_SkipZ; |
+ } |
+ return Sample_RGBA_D4444_SkipZ; |
+ } |
+ if (opts.fDither) { |
+ return Sample_RGBA_D4444_D; |
+ } |
+ return Sample_RGBA_D4444; |
+} |
+ |
+// Index |
+ |
+#define A32_MASK_IN_PLACE (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT) |
+ |
+static bool Sample_Index_D8888(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; |
+ dst[x] = c; |
+ src += deltaSrc; |
+ } |
+ 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 SkScaledBitmapSampler::Options& opts) { |
+ // The caller is expected to have created the source colortable |
+ // properly with respect to opts.fPremultiplyAlpha, so premul makes |
+ // no difference here. |
+ // Dither makes no difference |
+ if (opts.fSkipZeros) { |
+ 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[]) { |
+ |
+ uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; |
+ for (int x = 0; x < width; x++) { |
+ dst[x] = SkPixel32ToPixel16(ctable[*src]); |
+ src += deltaSrc; |
+ } |
+ return false; |
+} |
+ |
+static bool Sample_Index_D565_D(void* SK_RESTRICT dstRow, |
+ const uint8_t* SK_RESTRICT src, int width, |
+ int deltaSrc, int y, const SkPMColor ctable[]) { |
+ |
+ uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; |
+ DITHER_565_SCAN(y); |
+ |
+ for (int x = 0; x < width; x++) { |
+ SkPMColor c = ctable[*src]; |
+ dst[x] = SkDitherRGBTo565(SkGetPackedR32(c), SkGetPackedG32(c), |
+ SkGetPackedB32(c), DITHER_VALUE(x)); |
+ src += deltaSrc; |
+ } |
+ return false; |
+} |
+ |
+static SkScaledBitmapSampler::RowProc |
+get_index_to_565_proc(const SkScaledBitmapSampler::Options& opts) { |
+ // Unpremultiplied and skip zeroes make no difference |
+ if (opts.fDither) { |
+ 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[]) { |
+ |
+ 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; |
+ dst[x] = SkPixel32ToPixel4444(c); |
+ src += deltaSrc; |
+ } |
+ return cc != A32_MASK_IN_PLACE; |
+} |
+ |
+static bool Sample_Index_D4444_D(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; |
+ dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x)); |
+ src += deltaSrc; |
+ } |
+ 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 SkScaledBitmapSampler::Options& opts) { |
+ // Unpremul not allowed |
+ if (!opts.fPremultiplyAlpha) { |
+ return nullptr; |
+ } |
+ if (opts.fSkipZeros) { |
+ if (opts.fDither) { |
+ return Sample_Index_D4444_D_SkipZ; |
+ } |
+ return Sample_Index_D4444_SkipZ; |
+ } |
+ if (opts.fDither) { |
+ 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[]) { |
+ if (1 == deltaSrc) { |
+ memcpy(dstRow, src, width); |
+ } else { |
+ uint8_t* SK_RESTRICT dst = (uint8_t*)dstRow; |
+ for (int x = 0; x < width; x++) { |
+ dst[x] = src[0]; |
+ src += deltaSrc; |
+ } |
+ } |
+ return false; |
+} |
+ |
+static SkScaledBitmapSampler::RowProc |
+get_index_to_index_proc(const SkScaledBitmapSampler::Options& opts) { |
+ // Unpremul not allowed |
+ if (!opts.fPremultiplyAlpha) { |
+ return nullptr; |
+ } |
+ // 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, |
+ int width, int deltaSrc, int, |
+ const SkPMColor[]) { |
+ // Sampling Gray to A8 uses the same function as Index to Index8, |
+ // except we assume that there is alpha for speed, since an A8 |
+ // bitmap with no alpha is not interesting. |
+ (void) Sample_Index_DI(dstRow, src, width, deltaSrc, /* y unused */ 0, |
+ /* ctable unused */ nullptr); |
+ return true; |
+} |
+ |
+static SkScaledBitmapSampler::RowProc |
+get_gray_to_A8_proc(const SkScaledBitmapSampler::Options& opts) { |
+ if (!opts.fPremultiplyAlpha) { |
+ return nullptr; |
+ } |
+ // Ignore skip and dither. |
+ return Sample_Gray_DA8; |
+} |
+ |
+typedef SkScaledBitmapSampler::RowProc (*RowProcChooser)(const SkScaledBitmapSampler::Options&); |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+#include "SkScaledBitmapSampler.h" |
+ |
+SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height, |
+ int sampleSize) { |
+ fCTable = nullptr; |
+ fDstRow = nullptr; |
+ fRowProc = nullptr; |
+ |
+ if (width <= 0 || height <= 0) { |
+ sk_throw(); |
+ } |
+ |
+ SkDEBUGCODE(fSampleMode = kUninitialized_SampleMode); |
+ |
+ if (sampleSize <= 1) { |
+ fScaledWidth = width; |
+ fScaledHeight = height; |
+ fX0 = fY0 = 0; |
+ fDX = fDY = 1; |
+ return; |
+ } |
+ |
+ int dx = SkMin32(sampleSize, width); |
+ int dy = SkMin32(sampleSize, height); |
+ |
+ fScaledWidth = width / dx; |
+ fScaledHeight = height / dy; |
+ |
+ SkASSERT(fScaledWidth > 0); |
+ SkASSERT(fScaledHeight > 0); |
+ |
+ fX0 = dx >> 1; |
+ fY0 = dy >> 1; |
+ |
+ SkASSERT(fX0 >= 0 && fX0 < width); |
+ SkASSERT(fY0 >= 0 && fY0 < height); |
+ |
+ fDX = dx; |
+ fDY = dy; |
+ |
+ SkASSERT(fDX > 0 && (fX0 + fDX * (fScaledWidth - 1)) < width); |
+ SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height); |
+} |
+ |
+bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, |
+ const Options& opts, |
+ 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, |
+ nullptr, // 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, |
+ nullptr, // 565 to 4444 |
+ |
+ nullptr, // gray to index |
+ nullptr, // rgbx to index |
+ nullptr, // rgba to index |
+ get_index_to_index_proc, |
+ nullptr, // 565 to index |
+ |
+ get_gray_to_A8_proc, |
+ nullptr, // rgbx to a8 |
+ nullptr, // rgba to a8 |
+ nullptr, // index to a8 |
+ nullptr, // 565 to a8 |
+ }; |
+ |
+ // The jump between dst configs in the table |
+ static const int gProcDstConfigSpan = 5; |
+ static_assert(SK_ARRAY_COUNT(gProcChoosers) == 5 * gProcDstConfigSpan, |
+ "gProcs_has_the_wrong_number_of_entries"); |
+ |
+ fCTable = ctable; |
+ |
+ int index = 0; |
+ switch (sc) { |
+ case SkScaledBitmapSampler::kGray: |
+ fSrcPixelSize = 1; |
+ index += 0; |
+ break; |
+ case SkScaledBitmapSampler::kRGB: |
+ fSrcPixelSize = 3; |
+ index += 1; |
+ break; |
+ case SkScaledBitmapSampler::kRGBX: |
+ fSrcPixelSize = 4; |
+ index += 1; |
+ break; |
+ case SkScaledBitmapSampler::kRGBA: |
+ fSrcPixelSize = 4; |
+ index += 2; |
+ break; |
+ case SkScaledBitmapSampler::kIndex: |
+ fSrcPixelSize = 1; |
+ index += 3; |
+ break; |
+ case SkScaledBitmapSampler::kRGB_565: |
+ fSrcPixelSize = 2; |
+ index += 4; |
+ break; |
+ default: |
+ return false; |
+ } |
+ |
+ switch (dst->colorType()) { |
+ case kN32_SkColorType: |
+ index += 0 * gProcDstConfigSpan; |
+ break; |
+ case kRGB_565_SkColorType: |
+ index += 1 * gProcDstConfigSpan; |
+ break; |
+ case kARGB_4444_SkColorType: |
+ index += 2 * gProcDstConfigSpan; |
+ break; |
+ case kIndex_8_SkColorType: |
+ index += 3 * gProcDstConfigSpan; |
+ break; |
+ case kAlpha_8_SkColorType: |
+ index += 4 * gProcDstConfigSpan; |
+ break; |
+ default: |
+ return false; |
+ } |
+ |
+ RowProcChooser chooser = gProcChoosers[index]; |
+ if (nullptr == chooser) { |
+ fRowProc = nullptr; |
+ } else { |
+ fRowProc = chooser(opts); |
+ } |
+ fDstRow = (char*)dst->getPixels(); |
+ fDstRowBytes = dst->rowBytes(); |
+ fCurrY = 0; |
+ return fRowProc != nullptr; |
+} |
+ |
+bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, |
+ const SkImageDecoder& decoder, |
+ const SkPMColor ctable[]) { |
+ return this->begin(dst, sc, Options(decoder), ctable); |
+} |
+ |
+bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) { |
+ SkASSERT(kInterlaced_SampleMode != fSampleMode); |
+ SkDEBUGCODE(fSampleMode = kConsecutive_SampleMode); |
+ SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight); |
+ |
+ bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth, |
+ fDX * fSrcPixelSize, fCurrY, fCTable); |
+ fDstRow += fDstRowBytes; |
+ fCurrY += 1; |
+ return hadAlpha; |
+} |
+ |
+bool SkScaledBitmapSampler::sampleInterlaced(const uint8_t* SK_RESTRICT src, int srcY) { |
+ SkASSERT(kConsecutive_SampleMode != fSampleMode); |
+ SkDEBUGCODE(fSampleMode = kInterlaced_SampleMode); |
+ // Any line that should be a part of the destination can be created by the formula: |
+ // fY0 + (some multiplier) * fDY |
+ // so if srcY - fY0 is not an integer multiple of fDY that srcY will be skipped. |
+ const int srcYMinusY0 = srcY - fY0; |
+ if (srcYMinusY0 % fDY != 0) { |
+ // This line is not part of the output, so return false for alpha, since we have |
+ // not added an alpha to the output. |
+ return false; |
+ } |
+ // Unlike in next(), where the data is used sequentially, this function skips around, |
+ // so fDstRow and fCurrY are never updated. fDstRow must always be the starting point |
+ // of the destination bitmap's pixels, which is used to calculate the destination row |
+ // each time this function is called. |
+ const int dstY = srcYMinusY0 / fDY; |
+ if (dstY >= fScaledHeight) { |
+ return false; |
+ } |
+ char* dstRow = fDstRow + dstY * fDstRowBytes; |
+ return fRowProc(dstRow, src + fX0 * fSrcPixelSize, fScaledWidth, |
+ fDX * fSrcPixelSize, dstY, fCTable); |
+} |
+ |
+#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, nullptr, nullptr, // to A8 |
+ nullptr, nullptr, nullptr, nullptr, // 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 |
+ nullptr, nullptr, nullptr, nullptr, // to A8 |
+ Sample_Index_DI, Sample_Index_DI, nullptr, nullptr, // 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, nullptr, nullptr, // to 4444 |
+ Sample_Index_D8888, Sample_Index_D8888, Sample_Index_D8888, Sample_Index_D8888, // to 8888 |
+ // RGB |
+ nullptr, nullptr, nullptr, nullptr, // to A8 |
+ nullptr, nullptr, nullptr, nullptr, // 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 |
+ nullptr, nullptr, nullptr, nullptr, // to A8 |
+ nullptr, nullptr, nullptr, nullptr, // 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 |
+ nullptr, nullptr, nullptr, nullptr, // to A8 |
+ nullptr, nullptr, nullptr, nullptr, // 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, nullptr, nullptr, // to 4444 |
+ Sample_RGBA_D8888, Sample_RGBA_D8888, Sample_RGBA_D8888_Unpremul, Sample_RGBA_D8888_Unpremul, // to 8888 |
+ // RGB_565 |
+ nullptr, nullptr, nullptr, nullptr, // to A8 |
+ nullptr, nullptr, nullptr, nullptr, // to Index8 |
+ Sample_D565_D565, Sample_D565_D565, Sample_D565_D565, Sample_D565_D565, // to 565 |
+ nullptr, nullptr, nullptr, nullptr, // to 4444 |
+ nullptr, nullptr, nullptr, nullptr, // to 8888 |
+}; |
+ |
+// Dummy class that allows instantiation of an ImageDecoder, so begin can query its fields. |
+class DummyDecoder : public SkImageDecoder { |
+public: |
+ DummyDecoder() {} |
+protected: |
+ Result onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) override { |
+ return kFailure; |
+ } |
+}; |
+ |
+void test_row_proc_choice(); |
+void test_row_proc_choice() { |
+ const SkColorType colorTypes[] = { |
+ kAlpha_8_SkColorType, kIndex_8_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType, |
+ kN32_SkColorType |
+ }; |
+ |
+ SkBitmap dummyBitmap; |
+ DummyDecoder dummyDecoder; |
+ size_t procCounter = 0; |
+ for (int sc = SkScaledBitmapSampler::kGray; sc <= SkScaledBitmapSampler::kRGB_565; ++sc) { |
+ for (size_t c = 0; c < SK_ARRAY_COUNT(colorTypes); ++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.setInfo(SkImageInfo::Make(10, 10, |
+ colorTypes[c], kPremul_SkAlphaType)); |
+ 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 |