/* * 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 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 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; } // 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 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_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 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; } // 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 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 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_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; } // 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_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 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_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; } // A8 static bool Sample_Gray_DA8(void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, int deltaSrc, int, const SkPMColor[]) { memcpy(dstRow, src, width); 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(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(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; } // Sample_Index_D8888_Unpremul is the same as Sample_Index_D8888, since the // color table has its colors inserted unpremultiplied. /////////////////////////////////////////////////////////////////////////////// #include "SkScaledBitmapSampler.h" SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height, int sampleSize) { fCTable = NULL; fDstRow = NULL; fRowProc = NULL; if (width <= 0 || height <= 0) { sk_throw(); } 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, 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, }; // The jump between dst configs in the table static const int gProcDstConfigSpan = 10; SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gProcs) == 6 * gProcDstConfigSpan, gProcs_has_the_wrong_number_of_entries); fCTable = ctable; int index = 0; if (dither) { index += 1; } switch (sc) { case SkScaledBitmapSampler::kGray: fSrcPixelSize = 1; index += 0; break; case SkScaledBitmapSampler::kRGB: fSrcPixelSize = 3; index += 2; break; case SkScaledBitmapSampler::kRGBX: fSrcPixelSize = 4; index += 2; break; case SkScaledBitmapSampler::kRGBA: fSrcPixelSize = 4; index += 4; break; case SkScaledBitmapSampler::kIndex: fSrcPixelSize = 1; index += 6; break; case SkScaledBitmapSampler::kRGB_565: fSrcPixelSize = 2; index += 8; break; default: return false; } switch (dst->config()) { case SkBitmap::kARGB_8888_Config: index += 0 * gProcDstConfigSpan; break; case SkBitmap::kRGB_565_Config: index += 1 * gProcDstConfigSpan; break; case SkBitmap::kARGB_4444_Config: index += 2 * gProcDstConfigSpan; break; case SkBitmap::kIndex8_Config: index += 3 * gProcDstConfigSpan; break; case SkBitmap::kA8_Config: index += 4 * gProcDstConfigSpan; break; default: return false; } if (requireUnpremul) { if (dst->config() != SkBitmap::kARGB_8888_Config) { return false; } index += 5 * gProcDstConfigSpan; } fRowProc = gProcs[index]; fDstRow = (char*)dst->getPixels(); fDstRowBytes = dst->rowBytes(); fCurrY = 0; return fRowProc != NULL; } bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) { SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight); bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth, fDX * fSrcPixelSize, fCurrY, fCTable); fDstRow += fDstRowBytes; fCurrY += 1; return hadAlpha; }