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 "SkSpriteBlitter.h" 9 #include "SkArenaAlloc.h" 10 #include "SkBlitRow.h" 11 #include "SkColorFilter.h" 12 #include "SkColorPriv.h" 13 #include "SkTemplates.h" 14 #include "SkUtils.h" 15 #include "SkXfermodePriv.h" 16 17 /////////////////////////////////////////////////////////////////////////////// 18 19 static 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 25 static 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 31 class Sprite_D16_S32 : public SkSpriteBlitter { 32 public: 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 59 private: 60 bool fUseSrcOver; 61 62 typedef SkSpriteBlitter INHERITED; 63 }; 64 65 SkSpriteBlitter* 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 if (source.colorType() == kN32_SkColorType) { 82 switch (paint.getBlendMode()) { 83 case SkBlendMode::kSrc: 84 case SkBlendMode::kSrcOver: 85 return allocator->make<Sprite_D16_S32>(source, paint.getBlendMode()); 86 default: 87 break; 88 } 89 } 90 return nullptr; 91 } 92 93 ////////////////////////////////////////////////////////////////////////////////////////////////// 94 95 static unsigned div255(unsigned a, unsigned b) { 96 return (a * b * 257 + 127) >> 16; 97 } 98 99 static void S32_src_da8(uint8_t dst[], const SkPMColor src[], int count) { 100 for (int i = 0; i < count; ++i) { 101 dst[i] = SkGetPackedA32(src[i]); 102 } 103 } 104 105 static void S32_srcover_da8(uint8_t dst[], const SkPMColor src[], int count) { 106 for (int i = 0; i < count; ++i) { 107 SkPMColor c = src[i]; 108 if (c) { 109 unsigned a = SkGetPackedA32(c); 110 if (a == 0xFF) { 111 dst[i] = 0xFF; 112 } else { 113 dst[i] = a + div255(255 - a, dst[i]); 114 } 115 } 116 } 117 } 118 119 class Sprite_D8_S32 : public SkSpriteBlitter { 120 public: 121 Sprite_D8_S32(const SkPixmap& src, SkBlendMode mode) : INHERITED(src) { 122 SkASSERT(src.colorType() == kN32_SkColorType); 123 SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver); 124 125 fUseSrcOver = (mode == SkBlendMode::kSrcOver) && !src.isOpaque(); 126 } 127 128 void blitRect(int x, int y, int width, int height) override { 129 SkASSERT(width > 0 && height > 0); 130 uint8_t* SK_RESTRICT dst = fDst.writable_addr8(x, y); 131 const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop); 132 size_t dstRB = fDst.rowBytes(); 133 size_t srcRB = fSource.rowBytes(); 134 135 do { 136 if (fUseSrcOver) { 137 S32_srcover_da8(dst, src, width); 138 } else { 139 S32_src_da8(dst, src, width); 140 } 141 142 dst = (uint8_t* SK_RESTRICT)((char*)dst + dstRB); 143 src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB); 144 } while (--height != 0); 145 } 146 147 private: 148 bool fUseSrcOver; 149 150 typedef SkSpriteBlitter INHERITED; 151 }; 152 153 SkSpriteBlitter* SkSpriteBlitter::ChooseLA8(const SkPixmap& source, const SkPaint& paint, 154 SkArenaAlloc* allocator) { 155 SkASSERT(allocator != nullptr); 156 157 if (paint.getColorFilter() != nullptr) { 158 return nullptr; 159 } 160 if (paint.getMaskFilter() != nullptr) { 161 return nullptr; 162 } 163 164 U8CPU alpha = paint.getAlpha(); 165 if (alpha != 0xFF) { 166 return nullptr; 167 } 168 169 if (source.colorType() == kN32_SkColorType) { 170 switch (paint.getBlendMode()) { 171 case SkBlendMode::kSrc: 172 case SkBlendMode::kSrcOver: 173 return allocator->make<Sprite_D8_S32>(source, paint.getBlendMode()); 174 default: 175 break; 176 } 177 } 178 return nullptr; 179 } 180