1/* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "include/core/SkColorFilter.h" 9#include "include/core/SkPaint.h" 10#include "include/private/SkColorData.h" 11#include "include/private/SkTemplates.h" 12#include "src/core/SkArenaAlloc.h" 13#include "src/core/SkBlitRow.h" 14#include "src/core/SkSpriteBlitter.h" 15#include "src/core/SkXfermodePriv.h" 16 17/////////////////////////////////////////////////////////////////////////////// 18 19static void S32_src(uint16_t dst[], const SkPMColor src[], int count) { 20 for (int i = 0; i < count; ++i) { 21 dst[i] = SkPixel32ToPixel16(src[i]); 22 } 23} 24 25static void S32_srcover(uint16_t dst[], const SkPMColor src[], int count) { 26 for (int i = 0; i < count; ++i) { 27 dst[i] = SkSrcOver32To16(src[i], dst[i]); 28 } 29} 30 31class Sprite_D16_S32 : public SkSpriteBlitter { 32public: 33 Sprite_D16_S32(const SkPixmap& src, SkBlendMode mode) : INHERITED(src) { 34 SkASSERT(src.colorType() == kN32_SkColorType); 35 SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver); 36 37 fUseSrcOver = (mode == SkBlendMode::kSrcOver) && !src.isOpaque(); 38 } 39 40 void blitRect(int x, int y, int width, int height) override { 41 SkASSERT(width > 0 && height > 0); 42 uint16_t* SK_RESTRICT dst = fDst.writable_addr16(x, y); 43 const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop); 44 size_t dstRB = fDst.rowBytes(); 45 size_t srcRB = fSource.rowBytes(); 46 47 do { 48 if (fUseSrcOver) { 49 S32_srcover(dst, src, width); 50 } else { 51 S32_src(dst, src, width); 52 } 53 54 dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB); 55 src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB); 56 } while (--height != 0); 57 } 58 59private: 60 bool fUseSrcOver; 61 62 using INHERITED = SkSpriteBlitter; 63}; 64 65SkSpriteBlitter* SkSpriteBlitter::ChooseL565(const SkPixmap& source, const SkPaint& paint, 66 SkArenaAlloc* allocator) { 67 SkASSERT(allocator != nullptr); 68 69 if (paint.getColorFilter() != nullptr) { 70 return nullptr; 71 } 72 if (paint.getMaskFilter() != nullptr) { 73 return nullptr; 74 } 75 76 U8CPU alpha = paint.getAlpha(); 77 if (alpha != 0xFF) { 78 return nullptr; 79 } 80 81 const auto bm = paint.asBlendMode(); 82 if ((source.colorType() == kN32_SkColorType) && bm) { 83 switch (bm.value()) { 84 case SkBlendMode::kSrc: 85 case SkBlendMode::kSrcOver: 86 return allocator->make<Sprite_D16_S32>(source, bm.value()); 87 default: 88 break; 89 } 90 } 91 return nullptr; 92} 93 94////////////////////////////////////////////////////////////////////////////////////////////////// 95 96static unsigned div255(unsigned a, unsigned b) { 97 return (a * b * 257 + 127) >> 16; 98} 99 100static void S32_src_da8(uint8_t dst[], const SkPMColor src[], int count) { 101 for (int i = 0; i < count; ++i) { 102 dst[i] = SkGetPackedA32(src[i]); 103 } 104} 105 106static void S32_srcover_da8(uint8_t dst[], const SkPMColor src[], int count) { 107 for (int i = 0; i < count; ++i) { 108 SkPMColor c = src[i]; 109 if (c) { 110 unsigned a = SkGetPackedA32(c); 111 if (a == 0xFF) { 112 dst[i] = 0xFF; 113 } else { 114 dst[i] = a + div255(255 - a, dst[i]); 115 } 116 } 117 } 118} 119 120class Sprite_D8_S32 : public SkSpriteBlitter { 121public: 122 Sprite_D8_S32(const SkPixmap& src, SkBlendMode mode) : INHERITED(src) { 123 SkASSERT(src.colorType() == kN32_SkColorType); 124 SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver); 125 126 fUseSrcOver = (mode == SkBlendMode::kSrcOver) && !src.isOpaque(); 127 } 128 129 void blitRect(int x, int y, int width, int height) override { 130 SkASSERT(width > 0 && height > 0); 131 uint8_t* SK_RESTRICT dst = fDst.writable_addr8(x, y); 132 const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop); 133 size_t dstRB = fDst.rowBytes(); 134 size_t srcRB = fSource.rowBytes(); 135 136 do { 137 if (fUseSrcOver) { 138 S32_srcover_da8(dst, src, width); 139 } else { 140 S32_src_da8(dst, src, width); 141 } 142 143 dst = (uint8_t* SK_RESTRICT)((char*)dst + dstRB); 144 src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB); 145 } while (--height != 0); 146 } 147 148private: 149 bool fUseSrcOver; 150 151 using INHERITED = SkSpriteBlitter; 152}; 153 154SkSpriteBlitter* SkSpriteBlitter::ChooseLA8(const SkPixmap& source, const SkPaint& paint, 155 SkArenaAlloc* allocator) { 156 SkASSERT(allocator != nullptr); 157 158 if (paint.getColorFilter() != nullptr) { 159 return nullptr; 160 } 161 if (paint.getMaskFilter() != nullptr) { 162 return nullptr; 163 } 164 165 U8CPU alpha = paint.getAlpha(); 166 if (alpha != 0xFF) { 167 return nullptr; 168 } 169 170 const auto bm = paint.asBlendMode(); 171 if ((source.colorType() == kN32_SkColorType) && bm) { 172 switch (bm.value()) { 173 case SkBlendMode::kSrc: 174 case SkBlendMode::kSrcOver: 175 return allocator->make<Sprite_D8_S32>(source, bm.value()); 176 default: 177 break; 178 } 179 } 180 return nullptr; 181} 182