michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "SkSpriteBlitter.h" michael@0: #include "SkBlitRow.h" michael@0: #include "SkTemplates.h" michael@0: #include "SkUtils.h" michael@0: #include "SkColorPriv.h" michael@0: michael@0: #define D16_S32A_Opaque_Pixel(dst, sc) \ michael@0: do { \ michael@0: if (sc) { \ michael@0: *dst = SkSrcOver32To16(sc, *dst); \ michael@0: } \ michael@0: } while (0) michael@0: michael@0: static inline void D16_S32A_Blend_Pixel_helper(uint16_t* dst, SkPMColor sc, michael@0: unsigned src_scale) { michael@0: uint16_t dc = *dst; michael@0: unsigned sa = SkGetPackedA32(sc); michael@0: unsigned dr, dg, db; michael@0: michael@0: if (255 == sa) { michael@0: dr = SkAlphaBlend(SkPacked32ToR16(sc), SkGetPackedR16(dc), src_scale); michael@0: dg = SkAlphaBlend(SkPacked32ToG16(sc), SkGetPackedG16(dc), src_scale); michael@0: db = SkAlphaBlend(SkPacked32ToB16(sc), SkGetPackedB16(dc), src_scale); michael@0: } else { michael@0: unsigned dst_scale = 255 - SkAlphaMul(sa, src_scale); michael@0: dr = (SkPacked32ToR16(sc) * src_scale + michael@0: SkGetPackedR16(dc) * dst_scale) >> 8; michael@0: dg = (SkPacked32ToG16(sc) * src_scale + michael@0: SkGetPackedG16(dc) * dst_scale) >> 8; michael@0: db = (SkPacked32ToB16(sc) * src_scale + michael@0: SkGetPackedB16(dc) * dst_scale) >> 8; michael@0: } michael@0: *dst = SkPackRGB16(dr, dg, db); michael@0: } michael@0: michael@0: #define D16_S32A_Blend_Pixel(dst, sc, src_scale) \ michael@0: do { if (sc) D16_S32A_Blend_Pixel_helper(dst, sc, src_scale); } while (0) michael@0: michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class Sprite_D16_S16_Opaque : public SkSpriteBlitter { michael@0: public: michael@0: Sprite_D16_S16_Opaque(const SkBitmap& source) michael@0: : SkSpriteBlitter(source) {} michael@0: michael@0: // overrides michael@0: virtual void blitRect(int x, int y, int width, int height) { michael@0: uint16_t* SK_RESTRICT dst = fDevice->getAddr16(x, y); michael@0: const uint16_t* SK_RESTRICT src = fSource->getAddr16(x - fLeft, michael@0: y - fTop); michael@0: size_t dstRB = fDevice->rowBytes(); michael@0: size_t srcRB = fSource->rowBytes(); michael@0: michael@0: while (--height >= 0) { michael@0: memcpy(dst, src, width << 1); michael@0: dst = (uint16_t*)((char*)dst + dstRB); michael@0: src = (const uint16_t*)((const char*)src + srcRB); michael@0: } michael@0: } michael@0: }; michael@0: michael@0: #define D16_S16_Blend_Pixel(dst, sc, scale) \ michael@0: do { \ michael@0: uint16_t dc = *dst; \ michael@0: *dst = SkBlendRGB16(sc, dc, scale); \ michael@0: } while (0) michael@0: michael@0: #define SkSPRITE_CLASSNAME Sprite_D16_S16_Blend michael@0: #define SkSPRITE_ARGS , uint8_t alpha michael@0: #define SkSPRITE_FIELDS uint8_t fSrcAlpha; michael@0: #define SkSPRITE_INIT fSrcAlpha = alpha; michael@0: #define SkSPRITE_DST_TYPE uint16_t michael@0: #define SkSPRITE_SRC_TYPE uint16_t michael@0: #define SkSPRITE_DST_GETADDR getAddr16 michael@0: #define SkSPRITE_SRC_GETADDR getAddr16 michael@0: #define SkSPRITE_PREAMBLE(srcBM, x, y) int scale = SkAlpha255To256(fSrcAlpha); michael@0: #define SkSPRITE_BLIT_PIXEL(dst, src) D16_S16_Blend_Pixel(dst, src, scale) michael@0: #define SkSPRITE_NEXT_ROW michael@0: #define SkSPRITE_POSTAMBLE(srcBM) michael@0: #include "SkSpriteBlitterTemplate.h" michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #define D16_S4444_Opaque(dst, sc) \ michael@0: do { \ michael@0: uint16_t dc = *dst; \ michael@0: *dst = SkSrcOver4444To16(sc, dc); \ michael@0: } while (0) michael@0: michael@0: #define SkSPRITE_CLASSNAME Sprite_D16_S4444_Opaque michael@0: #define SkSPRITE_ARGS michael@0: #define SkSPRITE_FIELDS michael@0: #define SkSPRITE_INIT michael@0: #define SkSPRITE_DST_TYPE uint16_t michael@0: #define SkSPRITE_SRC_TYPE SkPMColor16 michael@0: #define SkSPRITE_DST_GETADDR getAddr16 michael@0: #define SkSPRITE_SRC_GETADDR getAddr16 michael@0: #define SkSPRITE_PREAMBLE(srcBM, x, y) michael@0: #define SkSPRITE_BLIT_PIXEL(dst, src) D16_S4444_Opaque(dst, src) michael@0: #define SkSPRITE_NEXT_ROW michael@0: #define SkSPRITE_POSTAMBLE(srcBM) michael@0: #include "SkSpriteBlitterTemplate.h" michael@0: michael@0: #define D16_S4444_Blend(dst, sc, scale16) \ michael@0: do { \ michael@0: uint16_t dc = *dst; \ michael@0: *dst = SkBlend4444To16(sc, dc, scale16); \ michael@0: } while (0) michael@0: michael@0: michael@0: #define SkSPRITE_CLASSNAME Sprite_D16_S4444_Blend michael@0: #define SkSPRITE_ARGS , uint8_t alpha michael@0: #define SkSPRITE_FIELDS uint8_t fSrcAlpha; michael@0: #define SkSPRITE_INIT fSrcAlpha = alpha; michael@0: #define SkSPRITE_DST_TYPE uint16_t michael@0: #define SkSPRITE_SRC_TYPE uint16_t michael@0: #define SkSPRITE_DST_GETADDR getAddr16 michael@0: #define SkSPRITE_SRC_GETADDR getAddr16 michael@0: #define SkSPRITE_PREAMBLE(srcBM, x, y) int scale = SkAlpha15To16(fSrcAlpha); michael@0: #define SkSPRITE_BLIT_PIXEL(dst, src) D16_S4444_Blend(dst, src, scale) michael@0: #define SkSPRITE_NEXT_ROW michael@0: #define SkSPRITE_POSTAMBLE(srcBM) michael@0: #include "SkSpriteBlitterTemplate.h" michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #define SkSPRITE_CLASSNAME Sprite_D16_SIndex8A_Opaque michael@0: #define SkSPRITE_ARGS michael@0: #define SkSPRITE_FIELDS michael@0: #define SkSPRITE_INIT michael@0: #define SkSPRITE_DST_TYPE uint16_t michael@0: #define SkSPRITE_SRC_TYPE uint8_t michael@0: #define SkSPRITE_DST_GETADDR getAddr16 michael@0: #define SkSPRITE_SRC_GETADDR getAddr8 michael@0: #define SkSPRITE_PREAMBLE(srcBM, x, y) const SkPMColor* ctable = srcBM.getColorTable()->lockColors() michael@0: #define SkSPRITE_BLIT_PIXEL(dst, src) D16_S32A_Opaque_Pixel(dst, ctable[src]) michael@0: #define SkSPRITE_NEXT_ROW michael@0: #define SkSPRITE_POSTAMBLE(srcBM) srcBM.getColorTable()->unlockColors() michael@0: #include "SkSpriteBlitterTemplate.h" michael@0: michael@0: #define SkSPRITE_CLASSNAME Sprite_D16_SIndex8A_Blend michael@0: #define SkSPRITE_ARGS , uint8_t alpha michael@0: #define SkSPRITE_FIELDS uint8_t fSrcAlpha; michael@0: #define SkSPRITE_INIT fSrcAlpha = alpha; michael@0: #define SkSPRITE_DST_TYPE uint16_t michael@0: #define SkSPRITE_SRC_TYPE uint8_t michael@0: #define SkSPRITE_DST_GETADDR getAddr16 michael@0: #define SkSPRITE_SRC_GETADDR getAddr8 michael@0: #define SkSPRITE_PREAMBLE(srcBM, x, y) const SkPMColor* ctable = srcBM.getColorTable()->lockColors(); unsigned src_scale = SkAlpha255To256(fSrcAlpha); michael@0: #define SkSPRITE_BLIT_PIXEL(dst, src) D16_S32A_Blend_Pixel(dst, ctable[src], src_scale) michael@0: #define SkSPRITE_NEXT_ROW michael@0: #define SkSPRITE_POSTAMBLE(srcBM) srcBM.getColorTable()->unlockColors(); michael@0: #include "SkSpriteBlitterTemplate.h" michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static intptr_t asint(const void* ptr) { michael@0: return reinterpret_cast(ptr) - (const char*)0; michael@0: } michael@0: michael@0: static void blitrow_d16_si8(uint16_t* SK_RESTRICT dst, michael@0: const uint8_t* SK_RESTRICT src, int count, michael@0: const uint16_t* SK_RESTRICT ctable) { michael@0: if (count <= 8) { michael@0: do { michael@0: *dst++ = ctable[*src++]; michael@0: } while (--count); michael@0: return; michael@0: } michael@0: michael@0: // eat src until we're on a 4byte boundary michael@0: while (asint(src) & 3) { michael@0: *dst++ = ctable[*src++]; michael@0: count -= 1; michael@0: } michael@0: michael@0: int qcount = count >> 2; michael@0: SkASSERT(qcount > 0); michael@0: const uint32_t* qsrc = reinterpret_cast(src); michael@0: if (asint(dst) & 2) { michael@0: do { michael@0: uint32_t s4 = *qsrc++; michael@0: #ifdef SK_CPU_LENDIAN michael@0: *dst++ = ctable[s4 & 0xFF]; michael@0: *dst++ = ctable[(s4 >> 8) & 0xFF]; michael@0: *dst++ = ctable[(s4 >> 16) & 0xFF]; michael@0: *dst++ = ctable[s4 >> 24]; michael@0: #else // BENDIAN michael@0: *dst++ = ctable[s4 >> 24]; michael@0: *dst++ = ctable[(s4 >> 16) & 0xFF]; michael@0: *dst++ = ctable[(s4 >> 8) & 0xFF]; michael@0: *dst++ = ctable[s4 & 0xFF]; michael@0: #endif michael@0: } while (--qcount); michael@0: } else { // dst is on a 4byte boundary michael@0: uint32_t* ddst = reinterpret_cast(dst); michael@0: do { michael@0: uint32_t s4 = *qsrc++; michael@0: #ifdef SK_CPU_LENDIAN michael@0: *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF]; michael@0: *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF]; michael@0: #else // BENDIAN michael@0: *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF]; michael@0: *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF]; michael@0: #endif michael@0: } while (--qcount); michael@0: dst = reinterpret_cast(ddst); michael@0: } michael@0: src = reinterpret_cast(qsrc); michael@0: count &= 3; michael@0: // catch any remaining (will be < 4) michael@0: while (--count >= 0) { michael@0: *dst++ = ctable[*src++]; michael@0: } michael@0: } michael@0: michael@0: #define SkSPRITE_ROW_PROC(d, s, n, x, y) blitrow_d16_si8(d, s, n, ctable) michael@0: michael@0: #define SkSPRITE_CLASSNAME Sprite_D16_SIndex8_Opaque michael@0: #define SkSPRITE_ARGS michael@0: #define SkSPRITE_FIELDS michael@0: #define SkSPRITE_INIT michael@0: #define SkSPRITE_DST_TYPE uint16_t michael@0: #define SkSPRITE_SRC_TYPE uint8_t michael@0: #define SkSPRITE_DST_GETADDR getAddr16 michael@0: #define SkSPRITE_SRC_GETADDR getAddr8 michael@0: #define SkSPRITE_PREAMBLE(srcBM, x, y) const uint16_t* ctable = srcBM.getColorTable()->lock16BitCache() michael@0: #define SkSPRITE_BLIT_PIXEL(dst, src) *dst = ctable[src] michael@0: #define SkSPRITE_NEXT_ROW michael@0: #define SkSPRITE_POSTAMBLE(srcBM) srcBM.getColorTable()->unlock16BitCache() michael@0: #include "SkSpriteBlitterTemplate.h" michael@0: michael@0: #define SkSPRITE_CLASSNAME Sprite_D16_SIndex8_Blend michael@0: #define SkSPRITE_ARGS , uint8_t alpha michael@0: #define SkSPRITE_FIELDS uint8_t fSrcAlpha; michael@0: #define SkSPRITE_INIT fSrcAlpha = alpha; michael@0: #define SkSPRITE_DST_TYPE uint16_t michael@0: #define SkSPRITE_SRC_TYPE uint8_t michael@0: #define SkSPRITE_DST_GETADDR getAddr16 michael@0: #define SkSPRITE_SRC_GETADDR getAddr8 michael@0: #define SkSPRITE_PREAMBLE(srcBM, x, y) const uint16_t* ctable = srcBM.getColorTable()->lock16BitCache(); unsigned src_scale = SkAlpha255To256(fSrcAlpha); michael@0: #define SkSPRITE_BLIT_PIXEL(dst, src) D16_S16_Blend_Pixel(dst, ctable[src], src_scale) michael@0: #define SkSPRITE_NEXT_ROW michael@0: #define SkSPRITE_POSTAMBLE(srcBM) srcBM.getColorTable()->unlock16BitCache(); michael@0: #include "SkSpriteBlitterTemplate.h" michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class Sprite_D16_S32_BlitRowProc : public SkSpriteBlitter { michael@0: public: michael@0: Sprite_D16_S32_BlitRowProc(const SkBitmap& source) michael@0: : SkSpriteBlitter(source) {} michael@0: michael@0: // overrides michael@0: michael@0: virtual void setup(const SkBitmap& device, int left, int top, michael@0: const SkPaint& paint) { michael@0: this->INHERITED::setup(device, left, top, paint); michael@0: michael@0: unsigned flags = 0; michael@0: michael@0: if (paint.getAlpha() < 0xFF) { michael@0: flags |= SkBlitRow::kGlobalAlpha_Flag; michael@0: } michael@0: if (!fSource->isOpaque()) { michael@0: flags |= SkBlitRow::kSrcPixelAlpha_Flag; michael@0: } michael@0: if (paint.isDither()) { michael@0: flags |= SkBlitRow::kDither_Flag; michael@0: } michael@0: fProc = SkBlitRow::Factory(flags, SkBitmap::kRGB_565_Config); michael@0: } michael@0: michael@0: virtual void blitRect(int x, int y, int width, int height) { michael@0: uint16_t* SK_RESTRICT dst = fDevice->getAddr16(x, y); michael@0: const SkPMColor* SK_RESTRICT src = fSource->getAddr32(x - fLeft, michael@0: y - fTop); michael@0: size_t dstRB = fDevice->rowBytes(); michael@0: size_t srcRB = fSource->rowBytes(); michael@0: SkBlitRow::Proc proc = fProc; michael@0: U8CPU alpha = fPaint->getAlpha(); michael@0: michael@0: while (--height >= 0) { michael@0: proc(dst, src, width, alpha, x, y); michael@0: y += 1; michael@0: dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB); michael@0: src = (const SkPMColor* SK_RESTRICT)((const char*)src + srcRB); michael@0: } michael@0: } michael@0: michael@0: private: michael@0: SkBlitRow::Proc fProc; michael@0: michael@0: typedef SkSpriteBlitter INHERITED; michael@0: }; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source, const SkPaint& paint, michael@0: SkTBlitterAllocator* allocator) { michael@0: michael@0: SkASSERT(allocator != NULL); michael@0: michael@0: if (paint.getMaskFilter() != NULL) { // may add cases for this michael@0: return NULL; michael@0: } michael@0: if (paint.getXfermode() != NULL) { // may add cases for this michael@0: return NULL; michael@0: } michael@0: if (paint.getColorFilter() != NULL) { // may add cases for this michael@0: return NULL; michael@0: } michael@0: michael@0: SkSpriteBlitter* blitter = NULL; michael@0: unsigned alpha = paint.getAlpha(); michael@0: michael@0: switch (source.colorType()) { michael@0: case kPMColor_SkColorType: { michael@0: blitter = allocator->createT(source); michael@0: break; michael@0: } michael@0: case kARGB_4444_SkColorType: michael@0: if (255 == alpha) { michael@0: blitter = allocator->createT(source); michael@0: } else { michael@0: blitter = allocator->createT(source, alpha >> 4); michael@0: } michael@0: break; michael@0: case kRGB_565_SkColorType: michael@0: if (255 == alpha) { michael@0: blitter = allocator->createT(source); michael@0: } else { michael@0: blitter = allocator->createT(source, alpha); michael@0: } michael@0: break; michael@0: case kIndex_8_SkColorType: michael@0: if (paint.isDither()) { michael@0: // we don't support dither yet in these special cases michael@0: break; michael@0: } michael@0: if (source.isOpaque()) { michael@0: if (255 == alpha) { michael@0: blitter = allocator->createT(source); michael@0: } else { michael@0: blitter = allocator->createT(source, alpha); michael@0: } michael@0: } else { michael@0: if (255 == alpha) { michael@0: blitter = allocator->createT(source); michael@0: } else { michael@0: blitter = allocator->createT(source, alpha); michael@0: } michael@0: } michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: return blitter; michael@0: }