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 "SkColorData.h" 13 #include "SkPaint.h" 14 #include "SkTemplates.h" 15 #include "SkUtils.h" 16 #include "SkXfermodePriv.h" 17 18 /////////////////////////////////////////////////////////////////////////////// 19 20 static void S32_src(uint16_t dst[], const SkPMColor src[], int count) { 21 for (int i = 0; i < count; ++i) { 22 dst[i] = SkPixel32ToPixel16(src[i]); 23 } 24 } 25 26 static void S32_srcover(uint16_t dst[], const SkPMColor src[], int count) { 27 for (int i = 0; i < count; ++i) { 28 dst[i] = SkSrcOver32To16(src[i], dst[i]); 29 } 30 } 31 32 class Sprite_D16_S32 : public SkSpriteBlitter { 33 public: 34 Sprite_D16_S32(const SkPixmap& src, SkBlendMode mode) : INHERITED(src) { 35 SkASSERT(src.colorType() == kN32_SkColorType); 36 SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver); 37 38 fUseSrcOver = (mode == SkBlendMode::kSrcOver) && !src.isOpaque(); 39 } 40 41 void blitRect(int x, int y, int width, int height) override { 42 SkASSERT(width > 0 && height > 0); 43 uint16_t* SK_RESTRICT dst = fDst.writable_addr16(x, y); 44 const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop); 45 size_t dstRB = fDst.rowBytes(); 46 size_t srcRB = fSource.rowBytes(); 47 48 do { 49 if (fUseSrcOver) { 50 S32_srcover(dst, src, width); 51 } else { 52 S32_src(dst, src, width); 53 } 54 55 dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB); 56 src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB); 57 } while (--height != 0); 58 } 59 60 private: 61 bool fUseSrcOver; 62 63 typedef SkSpriteBlitter INHERITED; 64 }; 65 66 SkSpriteBlitter* SkSpriteBlitter::ChooseL565(const SkPixmap& source, const SkPaint& paint, 67 SkArenaAlloc* allocator) { 68 SkASSERT(allocator != nullptr); 69 70 if (paint.getColorFilter() != nullptr) { 71 return nullptr; 72 } 73 if (paint.getMaskFilter() != nullptr) { 74 return nullptr; 75 } 76 77 U8CPU alpha = paint.getAlpha(); 78 if (alpha != 0xFF) { 79 return nullptr; 80 } 81 82 if (source.colorType() == kN32_SkColorType) { 83 switch (paint.getBlendMode()) { 84 case SkBlendMode::kSrc: 85 case SkBlendMode::kSrcOver: 86 return allocator->make<Sprite_D16_S32>(source, paint.getBlendMode()); 87 default: 88 break; 89 } 90 } 91 return nullptr; 92 } 93 94 ////////////////////////////////////////////////////////////////////////////////////////////////// 95 96 static unsigned div255(unsigned a, unsigned b) { 97 return (a * b * 257 + 127) >> 16; 98 } 99 100 static 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 106 static 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 120 class Sprite_D8_S32 : public SkSpriteBlitter { 121 public: 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 148 private: 149 bool fUseSrcOver; 150 151 typedef SkSpriteBlitter INHERITED; 152 }; 153 154 SkSpriteBlitter* 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 if (source.colorType() == kN32_SkColorType) { 171 switch (paint.getBlendMode()) { 172 case SkBlendMode::kSrc: 173 case SkBlendMode::kSrcOver: 174 return allocator->make<Sprite_D8_S32>(source, paint.getBlendMode()); 175 default: 176 break; 177 } 178 } 179 return nullptr; 180 } 181