/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkCanvas.h" #include "SkColorPriv.h" namespace { /** Copies all pixels from a bitmap to a dst ptr with a given rowBytes and Config8888. The bitmap must have kARGB_8888_Config. */ inline void SkCopyBitmapToConfig8888(uint32_t* dstPixels, size_t dstRowBytes, SkCanvas::Config8888 dstConfig8888, const SkBitmap& srcBmp); /** * Copies all pixels in a bitmap to a dst ptr with row bytes. The src bitmap * is assumed to have pixels and be kARGB_8888_Config. No conversion is applied */ inline void SkCopyARGB8888BitmapTo(uint32_t* dstPixels, size_t dstRowBytes, const SkBitmap& srcBmp); /** Copies over all pixels in a bitmap from a src ptr with a given rowBytes and Config8888. The bitmap must have pixels and be kARGB_8888_Config. */ inline void SkCopyConfig8888ToBitmap(const SkBitmap& dstBmp, const uint32_t* srcPixels, size_t srcRowBytes, SkCanvas::Config8888 srcConfig8888); } /////////////////////////////////////////////////////////////////////////////// // Implementation namespace { template inline uint32_t pack_config8888(uint32_t a, uint32_t r, uint32_t g, uint32_t b) { #ifdef SK_CPU_LENDIAN return (a << (A_IDX * 8)) | (r << (R_IDX * 8)) | (g << (G_IDX * 8)) | (b << (B_IDX * 8)); #else return (a << ((3-A_IDX) * 8)) | (r << ((3-R_IDX) * 8)) | (g << ((3-G_IDX) * 8)) | (b << ((3-B_IDX) * 8)); #endif } template inline void unpack_config8888(uint32_t color, uint32_t* a, uint32_t* r, uint32_t* g, uint32_t* b) { #ifdef SK_CPU_LENDIAN *a = (color >> (A_IDX * 8)) & 0xff; *r = (color >> (R_IDX * 8)) & 0xff; *g = (color >> (G_IDX * 8)) & 0xff; *b = (color >> (B_IDX * 8)) & 0xff; #else *a = (color >> ((3 - A_IDX) * 8)) & 0xff; *r = (color >> ((3 - R_IDX) * 8)) & 0xff; *g = (color >> ((3 - G_IDX) * 8)) & 0xff; *b = (color >> ((3 - B_IDX) * 8)) & 0xff; #endif } template inline void bitmap_copy_to_config8888(uint32_t* dstPixels, size_t dstRowBytes, const SkBitmap& srcBmp) { SkASSERT(SkBitmap::kARGB_8888_Config == srcBmp.config()); SkAutoLockPixels alp(srcBmp); int w = srcBmp.width(); int h = srcBmp.height(); size_t srcRowBytes = srcBmp.rowBytes(); intptr_t src = reinterpret_cast(srcBmp.getPixels()); intptr_t dst = reinterpret_cast(dstPixels); for (int y = 0; y < h; ++y) { const SkPMColor* srcRow = reinterpret_cast(src); uint32_t* dstRow = reinterpret_cast(dst); for (int x = 0; x < w; ++x) { SkPMColor pmcolor = srcRow[x]; if (UNPM) { U8CPU a, r, g, b; a = SkGetPackedA32(pmcolor); if (a) { // We're doing the explicit divide to match WebKit layout // test expectations. We can modify and rebaseline if there // it can be shown that there is a more performant way to // unpremul. r = SkGetPackedR32(pmcolor) * 0xff / a; g = SkGetPackedG32(pmcolor) * 0xff / a; b = SkGetPackedB32(pmcolor) * 0xff / a; dstRow[x] = pack_config8888(a, r, g, b); } else { dstRow[x] = 0; } } else { dstRow[x] = pack_config8888( SkGetPackedA32(pmcolor), SkGetPackedR32(pmcolor), SkGetPackedG32(pmcolor), SkGetPackedB32(pmcolor)); } } dst += dstRowBytes; src += srcRowBytes; } } template inline void config8888_copy_to_bitmap(const SkBitmap& dstBmp, const uint32_t* srcPixels, size_t srcRowBytes) { SkASSERT(SkBitmap::kARGB_8888_Config == dstBmp.config()); SkAutoLockPixels alp(dstBmp); int w = dstBmp.width(); int h = dstBmp.height(); size_t dstRowBytes = dstBmp.rowBytes(); intptr_t src = reinterpret_cast(srcPixels); intptr_t dst = reinterpret_cast(dstBmp.getPixels()); for (int y = 0; y < h; ++y) { const uint32_t* srcRow = reinterpret_cast(src); SkPMColor* dstRow = reinterpret_cast(dst); for (int x = 0; x < w; ++x) { uint32_t c8888 = srcRow[x]; uint32_t a, r, g, b; unpack_config8888(c8888, &a, &r, &g, &b); if (PM) { // This matches WebKit's conversion which we are replacing. // We can consider alternative rounding rules for performance. r = SkMulDiv255Ceiling(r, a); g = SkMulDiv255Ceiling(g, a); b = SkMulDiv255Ceiling(b, a); } dstRow[x] = SkPackARGB32(a, r, g, b); } src += srcRowBytes; dst += dstRowBytes; } } #ifdef SK_CPU_LENDIAN static const int SK_NATIVE_A_IDX = SK_A32_SHIFT / 8; static const int SK_NATIVE_R_IDX = SK_R32_SHIFT / 8; static const int SK_NATIVE_G_IDX = SK_G32_SHIFT / 8; static const int SK_NATIVE_B_IDX = SK_B32_SHIFT / 8; #else static const int SK_NATIVE_A_IDX = 3 - (SK_A32_SHIFT / 8); static const int SK_NATIVE_R_IDX = 3 - (SK_R32_SHIFT / 8); static const int SK_NATIVE_G_IDX = 3 - (SK_G32_SHIFT / 8); static const int SK_NATIVE_B_IDX = 3 - (SK_B32_SHIFT / 8); #endif inline void SkCopyBitmapToConfig8888(uint32_t* dstPixels, size_t dstRowBytes, SkCanvas::Config8888 dstConfig8888, const SkBitmap& srcBmp) { switch (dstConfig8888) { case SkCanvas::kNative_Premul_Config8888: bitmap_copy_to_config8888( dstPixels, dstRowBytes, srcBmp); break; case SkCanvas::kNative_Unpremul_Config8888: bitmap_copy_to_config8888( dstPixels, dstRowBytes, srcBmp); break; case SkCanvas::kBGRA_Premul_Config8888: bitmap_copy_to_config8888 ( dstPixels, dstRowBytes, srcBmp); break; case SkCanvas::kBGRA_Unpremul_Config8888: bitmap_copy_to_config8888 ( dstPixels, dstRowBytes, srcBmp); break; case SkCanvas::kRGBA_Premul_Config8888: bitmap_copy_to_config8888 ( dstPixels, dstRowBytes, srcBmp); break; case SkCanvas::kRGBA_Unpremul_Config8888: bitmap_copy_to_config8888 ( dstPixels, dstRowBytes, srcBmp); break; default: SkASSERT(false && "unexpected Config8888"); break; } } inline void SkCopyConfig8888ToBitmap(const SkBitmap& dstBmp, const uint32_t* srcPixels, size_t srcRowBytes, SkCanvas::Config8888 srcConfig8888) { switch (srcConfig8888) { case SkCanvas::kNative_Premul_Config8888: config8888_copy_to_bitmap( dstBmp, srcPixels, srcRowBytes); break; case SkCanvas::kNative_Unpremul_Config8888: config8888_copy_to_bitmap( dstBmp, srcPixels, srcRowBytes); break; case SkCanvas::kBGRA_Premul_Config8888: config8888_copy_to_bitmap ( dstBmp, srcPixels, srcRowBytes); break; case SkCanvas::kBGRA_Unpremul_Config8888: config8888_copy_to_bitmap ( dstBmp, srcPixels, srcRowBytes); break; case SkCanvas::kRGBA_Premul_Config8888: config8888_copy_to_bitmap ( dstBmp, srcPixels, srcRowBytes); break; case SkCanvas::kRGBA_Unpremul_Config8888: config8888_copy_to_bitmap ( dstBmp, srcPixels, srcRowBytes); break; default: SkASSERT(false && "unexpected Config8888"); break; } } inline void SkCopyARGB8888BitmapTo(uint32_t* dstPixels, size_t dstRowBytes, const SkBitmap& srcBmp) { SkASSERT(SkBitmap::kARGB_8888_Config == srcBmp.config()); SkAutoLockPixels alp(srcBmp); int w = srcBmp.width(); int h = srcBmp.height(); size_t srcRowBytes = srcBmp.rowBytes(); size_t tightRowBytes = w * 4; char* src = reinterpret_cast(srcBmp.getPixels()); char* dst = reinterpret_cast(dstPixels); if (tightRowBytes == srcRowBytes && tightRowBytes == dstRowBytes) { memcpy(dst, src, tightRowBytes * h); } else { for (int y = 0; y < h; ++y) { memcpy(dst, src, tightRowBytes); dst += dstRowBytes; src += srcRowBytes; } } } }