1 /* 2 * Copyright 2014 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 "SkBlitMask.h" 9 #include "SkColor.h" 10 #include "SkColorPriv.h" 11 12 static void D32_A8_Color(void* SK_RESTRICT dst, size_t dstRB, 13 const void* SK_RESTRICT maskPtr, size_t maskRB, 14 SkColor color, int width, int height) { 15 SkPMColor pmc = SkPreMultiplyColor(color); 16 size_t dstOffset = dstRB - (width << 2); 17 size_t maskOffset = maskRB - width; 18 SkPMColor* SK_RESTRICT device = (SkPMColor *)dst; 19 const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr; 20 21 do { 22 int w = width; 23 do { 24 unsigned aa = *mask++; 25 *device = SkBlendARGB32(pmc, *device, aa); 26 device += 1; 27 } while (--w != 0); 28 device = (uint32_t*)((char*)device + dstOffset); 29 mask += maskOffset; 30 } while (--height != 0); 31 } 32 33 static void D32_A8_Opaque(void* SK_RESTRICT dst, size_t dstRB, 34 const void* SK_RESTRICT maskPtr, size_t maskRB, 35 SkColor color, int width, int height) { 36 SkPMColor pmc = SkPreMultiplyColor(color); 37 SkPMColor* SK_RESTRICT device = (SkPMColor*)dst; 38 const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr; 39 40 maskRB -= width; 41 dstRB -= (width << 2); 42 do { 43 int w = width; 44 do { 45 unsigned aa = *mask++; 46 *device = SkAlphaMulQ(pmc, SkAlpha255To256(aa)) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa)); 47 device += 1; 48 } while (--w != 0); 49 device = (uint32_t*)((char*)device + dstRB); 50 mask += maskRB; 51 } while (--height != 0); 52 } 53 54 static void D32_A8_Black(void* SK_RESTRICT dst, size_t dstRB, 55 const void* SK_RESTRICT maskPtr, size_t maskRB, 56 SkColor, int width, int height) { 57 SkPMColor* SK_RESTRICT device = (SkPMColor*)dst; 58 const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr; 59 60 maskRB -= width; 61 dstRB -= (width << 2); 62 do { 63 int w = width; 64 do { 65 unsigned aa = *mask++; 66 *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa)); 67 device += 1; 68 } while (--w != 0); 69 device = (uint32_t*)((char*)device + dstRB); 70 mask += maskRB; 71 } while (--height != 0); 72 } 73 74 SkBlitMask::BlitLCD16RowProc SkBlitMask::BlitLCD16RowFactory(bool isOpaque) { 75 BlitLCD16RowProc proc = PlatformBlitRowProcs16(isOpaque); 76 if (proc) { 77 return proc; 78 } 79 80 if (isOpaque) { 81 return SkBlitLCD16OpaqueRow; 82 } else { 83 return SkBlitLCD16Row; 84 } 85 } 86 87 static void D32_LCD16_Proc(void* SK_RESTRICT dst, size_t dstRB, 88 const void* SK_RESTRICT mask, size_t maskRB, 89 SkColor color, int width, int height) { 90 91 SkPMColor* dstRow = (SkPMColor*)dst; 92 const uint16_t* srcRow = (const uint16_t*)mask; 93 SkPMColor opaqueDst; 94 95 SkBlitMask::BlitLCD16RowProc proc = NULL; 96 bool isOpaque = (0xFF == SkColorGetA(color)); 97 proc = SkBlitMask::BlitLCD16RowFactory(isOpaque); 98 SkASSERT(proc != NULL); 99 100 if (isOpaque) { 101 opaqueDst = SkPreMultiplyColor(color); 102 } else { 103 opaqueDst = 0; // ignored 104 } 105 106 do { 107 proc(dstRow, srcRow, color, width, opaqueDst); 108 dstRow = (SkPMColor*)((char*)dstRow + dstRB); 109 srcRow = (const uint16_t*)((const char*)srcRow + maskRB); 110 } while (--height != 0); 111 } 112 113 /////////////////////////////////////////////////////////////////////////////// 114 115 static SkBlitMask::ColorProc D32_A8_Factory(SkColor color) { 116 if (SK_ColorBLACK == color) { 117 return D32_A8_Black; 118 } else if (0xFF == SkColorGetA(color)) { 119 return D32_A8_Opaque; 120 } else { 121 return D32_A8_Color; 122 } 123 } 124 125 SkBlitMask::ColorProc SkBlitMask::ColorFactory(SkColorType ct, 126 SkMask::Format format, 127 SkColor color) { 128 ColorProc proc = PlatformColorProcs(ct, format, color); 129 if (proc) { 130 return proc; 131 } 132 133 switch (ct) { 134 case kN32_SkColorType: 135 switch (format) { 136 case SkMask::kA8_Format: 137 return D32_A8_Factory(color); 138 case SkMask::kLCD16_Format: 139 return D32_LCD16_Proc; 140 default: 141 break; 142 } 143 break; 144 default: 145 break; 146 } 147 return NULL; 148 } 149 150 bool SkBlitMask::BlitColor(const SkBitmap& device, const SkMask& mask, 151 const SkIRect& clip, SkColor color) { 152 ColorProc proc = ColorFactory(device.colorType(), mask.fFormat, color); 153 if (proc) { 154 int x = clip.fLeft; 155 int y = clip.fTop; 156 proc(device.getAddr32(x, y), device.rowBytes(), mask.getAddr(x, y), 157 mask.fRowBytes, color, clip.width(), clip.height()); 158 return true; 159 } 160 return false; 161 } 162 163 /////////////////////////////////////////////////////////////////////////////// 164 /////////////////////////////////////////////////////////////////////////////// 165 166 static void BW_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 167 const uint8_t* SK_RESTRICT mask, 168 const SkPMColor* SK_RESTRICT src, int count) { 169 int i, octuple = (count + 7) >> 3; 170 for (i = 0; i < octuple; ++i) { 171 int m = *mask++; 172 if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } 173 if (m & 0x40) { dst[1] = SkPMSrcOver(src[1], dst[1]); } 174 if (m & 0x20) { dst[2] = SkPMSrcOver(src[2], dst[2]); } 175 if (m & 0x10) { dst[3] = SkPMSrcOver(src[3], dst[3]); } 176 if (m & 0x08) { dst[4] = SkPMSrcOver(src[4], dst[4]); } 177 if (m & 0x04) { dst[5] = SkPMSrcOver(src[5], dst[5]); } 178 if (m & 0x02) { dst[6] = SkPMSrcOver(src[6], dst[6]); } 179 if (m & 0x01) { dst[7] = SkPMSrcOver(src[7], dst[7]); } 180 src += 8; 181 dst += 8; 182 } 183 count &= 7; 184 if (count > 0) { 185 int m = *mask; 186 do { 187 if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } 188 m <<= 1; 189 src += 1; 190 dst += 1; 191 } while (--count > 0); 192 } 193 } 194 195 static void BW_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 196 const uint8_t* SK_RESTRICT mask, 197 const SkPMColor* SK_RESTRICT src, int count) { 198 int i, octuple = (count + 7) >> 3; 199 for (i = 0; i < octuple; ++i) { 200 int m = *mask++; 201 if (m & 0x80) { dst[0] = src[0]; } 202 if (m & 0x40) { dst[1] = src[1]; } 203 if (m & 0x20) { dst[2] = src[2]; } 204 if (m & 0x10) { dst[3] = src[3]; } 205 if (m & 0x08) { dst[4] = src[4]; } 206 if (m & 0x04) { dst[5] = src[5]; } 207 if (m & 0x02) { dst[6] = src[6]; } 208 if (m & 0x01) { dst[7] = src[7]; } 209 src += 8; 210 dst += 8; 211 } 212 count &= 7; 213 if (count > 0) { 214 int m = *mask; 215 do { 216 if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } 217 m <<= 1; 218 src += 1; 219 dst += 1; 220 } while (--count > 0); 221 } 222 } 223 224 static void A8_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 225 const uint8_t* SK_RESTRICT mask, 226 const SkPMColor* SK_RESTRICT src, int count) { 227 for (int i = 0; i < count; ++i) { 228 if (mask[i]) { 229 dst[i] = SkBlendARGB32(src[i], dst[i], mask[i]); 230 } 231 } 232 } 233 234 // expand the steps that SkAlphaMulQ performs, but this way we can 235 // exand.. add.. combine 236 // instead of 237 // expand..combine add expand..combine 238 // 239 #define EXPAND0(v, m, s) ((v) & (m)) * (s) 240 #define EXPAND1(v, m, s) (((v) >> 8) & (m)) * (s) 241 #define COMBINE(e0, e1, m) ((((e0) >> 8) & (m)) | ((e1) & ~(m))) 242 243 static void A8_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 244 const uint8_t* SK_RESTRICT mask, 245 const SkPMColor* SK_RESTRICT src, int count) { 246 for (int i = 0; i < count; ++i) { 247 int m = mask[i]; 248 if (m) { 249 m += (m >> 7); 250 #if 1 251 // this is slightly slower than the expand/combine version, but it 252 // is much closer to the old results, so we use it for now to reduce 253 // rebaselining. 254 dst[i] = SkAlphaMulQ(src[i], m) + SkAlphaMulQ(dst[i], 256 - m); 255 #else 256 uint32_t v = src[i]; 257 uint32_t s0 = EXPAND0(v, rbmask, m); 258 uint32_t s1 = EXPAND1(v, rbmask, m); 259 v = dst[i]; 260 uint32_t d0 = EXPAND0(v, rbmask, m); 261 uint32_t d1 = EXPAND1(v, rbmask, m); 262 dst[i] = COMBINE(s0 + d0, s1 + d1, rbmask); 263 #endif 264 } 265 } 266 } 267 268 static int upscale31To255(int value) { 269 value = (value << 3) | (value >> 2); 270 return value; 271 } 272 273 static int src_alpha_blend(int src, int dst, int srcA, int mask) { 274 275 return dst + SkAlphaMul(src - SkAlphaMul(srcA, dst), mask); 276 } 277 278 static void LCD16_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 279 const uint16_t* SK_RESTRICT mask, 280 const SkPMColor* SK_RESTRICT src, int count) { 281 for (int i = 0; i < count; ++i) { 282 uint16_t m = mask[i]; 283 if (0 == m) { 284 continue; 285 } 286 287 SkPMColor s = src[i]; 288 SkPMColor d = dst[i]; 289 290 int srcA = SkGetPackedA32(s); 291 int srcR = SkGetPackedR32(s); 292 int srcG = SkGetPackedG32(s); 293 int srcB = SkGetPackedB32(s); 294 295 srcA += srcA >> 7; 296 297 /* We want all of these in 5bits, hence the shifts in case one of them 298 * (green) is 6bits. 299 */ 300 int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5); 301 int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5); 302 int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5); 303 304 maskR = upscale31To255(maskR); 305 maskG = upscale31To255(maskG); 306 maskB = upscale31To255(maskB); 307 308 int dstR = SkGetPackedR32(d); 309 int dstG = SkGetPackedG32(d); 310 int dstB = SkGetPackedB32(d); 311 312 // LCD blitting is only supported if the dst is known/required 313 // to be opaque 314 dst[i] = SkPackARGB32(0xFF, 315 src_alpha_blend(srcR, dstR, srcA, maskR), 316 src_alpha_blend(srcG, dstG, srcA, maskG), 317 src_alpha_blend(srcB, dstB, srcA, maskB)); 318 } 319 } 320 321 static void LCD16_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 322 const uint16_t* SK_RESTRICT mask, 323 const SkPMColor* SK_RESTRICT src, int count) { 324 for (int i = 0; i < count; ++i) { 325 uint16_t m = mask[i]; 326 if (0 == m) { 327 continue; 328 } 329 330 SkPMColor s = src[i]; 331 SkPMColor d = dst[i]; 332 333 int srcR = SkGetPackedR32(s); 334 int srcG = SkGetPackedG32(s); 335 int srcB = SkGetPackedB32(s); 336 337 /* We want all of these in 5bits, hence the shifts in case one of them 338 * (green) is 6bits. 339 */ 340 int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5); 341 int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5); 342 int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5); 343 344 // Now upscale them to 0..32, so we can use blend32 345 maskR = SkUpscale31To32(maskR); 346 maskG = SkUpscale31To32(maskG); 347 maskB = SkUpscale31To32(maskB); 348 349 int dstR = SkGetPackedR32(d); 350 int dstG = SkGetPackedG32(d); 351 int dstB = SkGetPackedB32(d); 352 353 // LCD blitting is only supported if the dst is known/required 354 // to be opaque 355 dst[i] = SkPackARGB32(0xFF, 356 SkBlend32(srcR, dstR, maskR), 357 SkBlend32(srcG, dstG, maskG), 358 SkBlend32(srcB, dstB, maskB)); 359 } 360 } 361 362 SkBlitMask::RowProc SkBlitMask::RowFactory(SkColorType ct, 363 SkMask::Format format, 364 RowFlags flags) { 365 // make this opt-in until chrome can rebaseline 366 RowProc proc = PlatformRowProcs(ct, format, flags); 367 if (proc) { 368 return proc; 369 } 370 371 static const RowProc gProcs[] = { 372 // need X coordinate to handle BW 373 false ? (RowProc)BW_RowProc_Blend : NULL, // suppress unused warning 374 false ? (RowProc)BW_RowProc_Opaque : NULL, // suppress unused warning 375 (RowProc)A8_RowProc_Blend, (RowProc)A8_RowProc_Opaque, 376 (RowProc)LCD16_RowProc_Blend, (RowProc)LCD16_RowProc_Opaque, 377 }; 378 379 int index; 380 switch (ct) { 381 case kN32_SkColorType: 382 switch (format) { 383 case SkMask::kBW_Format: index = 0; break; 384 case SkMask::kA8_Format: index = 2; break; 385 case SkMask::kLCD16_Format: index = 4; break; 386 default: 387 return NULL; 388 } 389 if (flags & kSrcIsOpaque_RowFlag) { 390 index |= 1; 391 } 392 SkASSERT((size_t)index < SK_ARRAY_COUNT(gProcs)); 393 return gProcs[index]; 394 default: 395 break; 396 } 397 return NULL; 398 } 399