| /* | 
 |  * Copyright 2006 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 "SkSpriteBlitter.h" | 
 | #include "SkBlitRow.h" | 
 | #include "SkColorFilter.h" | 
 | #include "SkColorPriv.h" | 
 | #include "SkTemplates.h" | 
 | #include "SkUtils.h" | 
 | #include "SkXfermode.h" | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | class Sprite_D32_S32 : public SkSpriteBlitter { | 
 | public: | 
 |     Sprite_D32_S32(const SkPixmap& src, U8CPU alpha)  : INHERITED(src) { | 
 |         SkASSERT(src.colorType() == kN32_SkColorType); | 
 |  | 
 |         unsigned flags32 = 0; | 
 |         if (255 != alpha) { | 
 |             flags32 |= SkBlitRow::kGlobalAlpha_Flag32; | 
 |         } | 
 |         if (!src.isOpaque()) { | 
 |             flags32 |= SkBlitRow::kSrcPixelAlpha_Flag32; | 
 |         } | 
 |  | 
 |         fProc32 = SkBlitRow::Factory32(flags32); | 
 |         fAlpha = alpha; | 
 |     } | 
 |  | 
 |     void blitRect(int x, int y, int width, int height) override { | 
 |         SkASSERT(width > 0 && height > 0); | 
 |         uint32_t* SK_RESTRICT dst = fDst.writable_addr32(x, y); | 
 |         const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop); | 
 |         size_t dstRB = fDst.rowBytes(); | 
 |         size_t srcRB = fSource.rowBytes(); | 
 |         SkBlitRow::Proc32 proc = fProc32; | 
 |         U8CPU             alpha = fAlpha; | 
 |  | 
 |         do { | 
 |             proc(dst, src, width, alpha); | 
 |             dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB); | 
 |             src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB); | 
 |         } while (--height != 0); | 
 |     } | 
 |  | 
 | private: | 
 |     SkBlitRow::Proc32   fProc32; | 
 |     U8CPU               fAlpha; | 
 |  | 
 |     typedef SkSpriteBlitter INHERITED; | 
 | }; | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | class Sprite_D32_XferFilter : public SkSpriteBlitter { | 
 | public: | 
 |     Sprite_D32_XferFilter(const SkPixmap& source, const SkPaint& paint) : SkSpriteBlitter(source) { | 
 |         fColorFilter = paint.getColorFilter(); | 
 |         SkSafeRef(fColorFilter); | 
 |  | 
 |         fXfermode = paint.getXfermode(); | 
 |         SkSafeRef(fXfermode); | 
 |  | 
 |         fBufferSize = 0; | 
 |         fBuffer = nullptr; | 
 |  | 
 |         unsigned flags32 = 0; | 
 |         if (255 != paint.getAlpha()) { | 
 |             flags32 |= SkBlitRow::kGlobalAlpha_Flag32; | 
 |         } | 
 |         if (!source.isOpaque()) { | 
 |             flags32 |= SkBlitRow::kSrcPixelAlpha_Flag32; | 
 |         } | 
 |  | 
 |         fProc32 = SkBlitRow::Factory32(flags32); | 
 |         fAlpha = paint.getAlpha(); | 
 |     } | 
 |  | 
 |     virtual ~Sprite_D32_XferFilter() { | 
 |         delete[] fBuffer; | 
 |         SkSafeUnref(fXfermode); | 
 |         SkSafeUnref(fColorFilter); | 
 |     } | 
 |  | 
 |     void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override { | 
 |         this->INHERITED::setup(dst, left, top, paint); | 
 |  | 
 |         int width = dst.width(); | 
 |         if (width > fBufferSize) { | 
 |             fBufferSize = width; | 
 |             delete[] fBuffer; | 
 |             fBuffer = new SkPMColor[width]; | 
 |         } | 
 |     } | 
 |  | 
 | protected: | 
 |     SkColorFilter*      fColorFilter; | 
 |     SkXfermode*         fXfermode; | 
 |     int                 fBufferSize; | 
 |     SkPMColor*          fBuffer; | 
 |     SkBlitRow::Proc32   fProc32; | 
 |     U8CPU               fAlpha; | 
 |  | 
 | private: | 
 |     typedef SkSpriteBlitter INHERITED; | 
 | }; | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | class Sprite_D32_S32A_XferFilter : public Sprite_D32_XferFilter { | 
 | public: | 
 |     Sprite_D32_S32A_XferFilter(const SkPixmap& source, const SkPaint& paint) | 
 |         : Sprite_D32_XferFilter(source, paint) {} | 
 |  | 
 |     void blitRect(int x, int y, int width, int height) override { | 
 |         SkASSERT(width > 0 && height > 0); | 
 |         uint32_t* SK_RESTRICT dst = fDst.writable_addr32(x, y); | 
 |         const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop); | 
 |         size_t dstRB = fDst.rowBytes(); | 
 |         size_t srcRB = fSource.rowBytes(); | 
 |         SkColorFilter* colorFilter = fColorFilter; | 
 |         SkXfermode* xfermode = fXfermode; | 
 |  | 
 |         do { | 
 |             const SkPMColor* tmp = src; | 
 |  | 
 |             if (colorFilter) { | 
 |                 colorFilter->filterSpan(src, width, fBuffer); | 
 |                 tmp = fBuffer; | 
 |             } | 
 |  | 
 |             if (xfermode) { | 
 |                 xfermode->xfer32(dst, tmp, width, nullptr); | 
 |             } else { | 
 |                 fProc32(dst, tmp, width, fAlpha); | 
 |             } | 
 |  | 
 |             dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB); | 
 |             src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB); | 
 |         } while (--height != 0); | 
 |     } | 
 |  | 
 | private: | 
 |     typedef Sprite_D32_XferFilter INHERITED; | 
 | }; | 
 |  | 
 | static void fillbuffer(SkPMColor* SK_RESTRICT dst, | 
 |                        const SkPMColor16* SK_RESTRICT src, int count) { | 
 |     SkASSERT(count > 0); | 
 |  | 
 |     do { | 
 |         *dst++ = SkPixel4444ToPixel32(*src++); | 
 |     } while (--count != 0); | 
 | } | 
 |  | 
 | class Sprite_D32_S4444_XferFilter : public Sprite_D32_XferFilter { | 
 | public: | 
 |     Sprite_D32_S4444_XferFilter(const SkPixmap& source, const SkPaint& paint) | 
 |         : Sprite_D32_XferFilter(source, paint) {} | 
 |  | 
 |     void blitRect(int x, int y, int width, int height) override { | 
 |         SkASSERT(width > 0 && height > 0); | 
 |         SkPMColor* SK_RESTRICT dst = fDst.writable_addr32(x, y); | 
 |         const SkPMColor16* SK_RESTRICT src = fSource.addr16(x - fLeft, y - fTop); | 
 |         size_t dstRB = fDst.rowBytes(); | 
 |         size_t srcRB = fSource.rowBytes(); | 
 |         SkPMColor* SK_RESTRICT buffer = fBuffer; | 
 |         SkColorFilter* colorFilter = fColorFilter; | 
 |         SkXfermode* xfermode = fXfermode; | 
 |  | 
 |         do { | 
 |             fillbuffer(buffer, src, width); | 
 |  | 
 |             if (colorFilter) { | 
 |                 colorFilter->filterSpan(buffer, width, buffer); | 
 |             } | 
 |             if (xfermode) { | 
 |                 xfermode->xfer32(dst, buffer, width, nullptr); | 
 |             } else { | 
 |                 fProc32(dst, buffer, width, fAlpha); | 
 |             } | 
 |  | 
 |             dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB); | 
 |             src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB); | 
 |         } while (--height != 0); | 
 |     } | 
 |  | 
 | private: | 
 |     typedef Sprite_D32_XferFilter INHERITED; | 
 | }; | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | static void src_row(SkPMColor* SK_RESTRICT dst, | 
 |                     const SkPMColor16* SK_RESTRICT src, int count) { | 
 |     do { | 
 |         *dst = SkPixel4444ToPixel32(*src); | 
 |         src += 1; | 
 |         dst += 1; | 
 |     } while (--count != 0); | 
 | } | 
 |  | 
 | class Sprite_D32_S4444_Opaque : public SkSpriteBlitter { | 
 | public: | 
 |     Sprite_D32_S4444_Opaque(const SkPixmap& source) : SkSpriteBlitter(source) {} | 
 |  | 
 |     void blitRect(int x, int y, int width, int height) override { | 
 |         SkASSERT(width > 0 && height > 0); | 
 |         SkPMColor* SK_RESTRICT dst = fDst.writable_addr32(x, y); | 
 |         const SkPMColor16* SK_RESTRICT src = fSource.addr16(x - fLeft, y - fTop); | 
 |         size_t dstRB = fDst.rowBytes(); | 
 |         size_t srcRB = fSource.rowBytes(); | 
 |  | 
 |         do { | 
 |             src_row(dst, src, width); | 
 |             dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB); | 
 |             src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB); | 
 |         } while (--height != 0); | 
 |     } | 
 | }; | 
 |  | 
 | static void srcover_row(SkPMColor* SK_RESTRICT dst, | 
 |                         const SkPMColor16* SK_RESTRICT src, int count) { | 
 |     do { | 
 |         *dst = SkPMSrcOver(SkPixel4444ToPixel32(*src), *dst); | 
 |         src += 1; | 
 |         dst += 1; | 
 |     } while (--count != 0); | 
 | } | 
 |  | 
 | class Sprite_D32_S4444 : public SkSpriteBlitter { | 
 | public: | 
 |     Sprite_D32_S4444(const SkPixmap& source) : SkSpriteBlitter(source) {} | 
 |  | 
 |     void blitRect(int x, int y, int width, int height) override { | 
 |         SkASSERT(width > 0 && height > 0); | 
 |         SkPMColor* SK_RESTRICT dst = fDst.writable_addr32(x, y); | 
 |         const SkPMColor16* SK_RESTRICT src = fSource.addr16(x - fLeft, y - fTop); | 
 |         size_t dstRB = fDst.rowBytes(); | 
 |         size_t srcRB = fSource.rowBytes(); | 
 |  | 
 |         do { | 
 |             srcover_row(dst, src, width); | 
 |             dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB); | 
 |             src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB); | 
 |         } while (--height != 0); | 
 |     } | 
 | }; | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | SkSpriteBlitter* SkSpriteBlitter::ChooseL32(const SkPixmap& source, const SkPaint& paint, | 
 |                                             SkTBlitterAllocator* allocator) { | 
 |     SkASSERT(allocator != nullptr); | 
 |  | 
 |     if (paint.getMaskFilter() != nullptr) { | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     U8CPU       alpha = paint.getAlpha(); | 
 |     SkXfermode* xfermode = paint.getXfermode(); | 
 |     SkColorFilter* filter = paint.getColorFilter(); | 
 |     SkSpriteBlitter* blitter = nullptr; | 
 |  | 
 |     switch (source.colorType()) { | 
 |         case kARGB_4444_SkColorType: | 
 |             if (alpha != 0xFF) { | 
 |                 return nullptr;    // we only have opaque sprites | 
 |             } | 
 |             if (xfermode || filter) { | 
 |                 blitter = allocator->createT<Sprite_D32_S4444_XferFilter>(source, paint); | 
 |             } else if (source.isOpaque()) { | 
 |                 blitter = allocator->createT<Sprite_D32_S4444_Opaque>(source); | 
 |             } else { | 
 |                 blitter = allocator->createT<Sprite_D32_S4444>(source); | 
 |             } | 
 |             break; | 
 |         case kN32_SkColorType: | 
 |             if (xfermode || filter) { | 
 |                 if (255 == alpha) { | 
 |                     // this can handle xfermode or filter, but not alpha | 
 |                     blitter = allocator->createT<Sprite_D32_S32A_XferFilter>(source, paint); | 
 |                 } | 
 |             } else { | 
 |                 // this can handle alpha, but not xfermode or filter | 
 |                 blitter = allocator->createT<Sprite_D32_S32>(source, alpha); | 
 |             } | 
 |             break; | 
 |         default: | 
 |             break; | 
 |     } | 
 |     return blitter; | 
 | } |