1#include "SkBlitMask.h" 2#include "SkColor.h" 3#include "SkColorPriv.h" 4 5static void D32_A8_Color(void* SK_RESTRICT dst, size_t dstRB, 6 const void* SK_RESTRICT maskPtr, size_t maskRB, 7 SkColor color, int width, int height) { 8 SkPMColor pmc = SkPreMultiplyColor(color); 9 size_t dstOffset = dstRB - (width << 2); 10 size_t maskOffset = maskRB - width; 11 SkPMColor* SK_RESTRICT device = (SkPMColor *)dst; 12 const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr; 13 14 do { 15 int w = width; 16 do { 17 unsigned aa = *mask++; 18 *device = SkBlendARGB32(pmc, *device, aa); 19 device += 1; 20 } while (--w != 0); 21 device = (uint32_t*)((char*)device + dstOffset); 22 mask += maskOffset; 23 } while (--height != 0); 24} 25 26static void D32_A8_Opaque(void* SK_RESTRICT dst, size_t dstRB, 27 const void* SK_RESTRICT maskPtr, size_t maskRB, 28 SkColor color, int width, int height) { 29 SkPMColor pmc = SkPreMultiplyColor(color); 30 SkPMColor* SK_RESTRICT device = (SkPMColor*)dst; 31 const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr; 32 33 maskRB -= width; 34 dstRB -= (width << 2); 35 do { 36 int w = width; 37 do { 38 unsigned aa = *mask++; 39 *device = SkAlphaMulQ(pmc, SkAlpha255To256(aa)) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa)); 40 device += 1; 41 } while (--w != 0); 42 device = (uint32_t*)((char*)device + dstRB); 43 mask += maskRB; 44 } while (--height != 0); 45} 46 47static void D32_A8_Black(void* SK_RESTRICT dst, size_t dstRB, 48 const void* SK_RESTRICT maskPtr, size_t maskRB, 49 SkColor, int width, int height) { 50 SkPMColor* SK_RESTRICT device = (SkPMColor*)dst; 51 const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr; 52 53 maskRB -= width; 54 dstRB -= (width << 2); 55 do { 56 int w = width; 57 do { 58 unsigned aa = *mask++; 59 *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa)); 60 device += 1; 61 } while (--w != 0); 62 device = (uint32_t*)((char*)device + dstRB); 63 mask += maskRB; 64 } while (--height != 0); 65} 66 67SkBlitMask::BlitLCD16RowProc SkBlitMask::BlitLCD16RowFactory(bool isOpaque) { 68 BlitLCD16RowProc proc = PlatformBlitRowProcs16(isOpaque); 69 if (proc) { 70 return proc; 71 } 72 73 if (isOpaque) { 74 return SkBlitLCD16OpaqueRow; 75 } else { 76 return SkBlitLCD16Row; 77 } 78} 79 80static void D32_LCD16_Proc(void* SK_RESTRICT dst, size_t dstRB, 81 const void* SK_RESTRICT mask, size_t maskRB, 82 SkColor color, int width, int height) { 83 84 SkPMColor* dstRow = (SkPMColor*)dst; 85 const uint16_t* srcRow = (const uint16_t*)mask; 86 SkPMColor opaqueDst; 87 88 SkBlitMask::BlitLCD16RowProc proc = NULL; 89 bool isOpaque = (0xFF == SkColorGetA(color)); 90 proc = SkBlitMask::BlitLCD16RowFactory(isOpaque); 91 SkASSERT(proc != NULL); 92 93 if (isOpaque) { 94 opaqueDst = SkPreMultiplyColor(color); 95 } else { 96 opaqueDst = 0; // ignored 97 } 98 99 do { 100 proc(dstRow, srcRow, color, width, opaqueDst); 101 dstRow = (SkPMColor*)((char*)dstRow + dstRB); 102 srcRow = (const uint16_t*)((const char*)srcRow + maskRB); 103 } while (--height != 0); 104} 105 106/////////////////////////////////////////////////////////////////////////////// 107 108static void blit_lcd32_opaque_row(SkPMColor* SK_RESTRICT dst, 109 const SkPMColor* SK_RESTRICT src, 110 SkColor color, int width) { 111 int srcR = SkColorGetR(color); 112 int srcG = SkColorGetG(color); 113 int srcB = SkColorGetB(color); 114 115 for (int i = 0; i < width; i++) { 116 SkPMColor mask = src[i]; 117 if (0 == mask) { 118 continue; 119 } 120 121 SkPMColor d = dst[i]; 122 123 int maskR = SkGetPackedR32(mask); 124 int maskG = SkGetPackedG32(mask); 125 int maskB = SkGetPackedB32(mask); 126 127 // Now upscale them to 0..256, so we can use SkAlphaBlend 128 maskR = SkAlpha255To256(maskR); 129 maskG = SkAlpha255To256(maskG); 130 maskB = SkAlpha255To256(maskB); 131 132 int dstR = SkGetPackedR32(d); 133 int dstG = SkGetPackedG32(d); 134 int dstB = SkGetPackedB32(d); 135 136 // LCD blitting is only supported if the dst is known/required 137 // to be opaque 138 dst[i] = SkPackARGB32(0xFF, 139 SkAlphaBlend(srcR, dstR, maskR), 140 SkAlphaBlend(srcG, dstG, maskG), 141 SkAlphaBlend(srcB, dstB, maskB)); 142 } 143} 144 145static void blit_lcd32_row(SkPMColor* SK_RESTRICT dst, 146 const SkPMColor* SK_RESTRICT src, 147 SkColor color, int width) { 148 int srcA = SkColorGetA(color); 149 int srcR = SkColorGetR(color); 150 int srcG = SkColorGetG(color); 151 int srcB = SkColorGetB(color); 152 153 srcA = SkAlpha255To256(srcA); 154 155 for (int i = 0; i < width; i++) { 156 SkPMColor mask = src[i]; 157 if (0 == mask) { 158 continue; 159 } 160 161 SkPMColor d = dst[i]; 162 163 int maskR = SkGetPackedR32(mask); 164 int maskG = SkGetPackedG32(mask); 165 int maskB = SkGetPackedB32(mask); 166 167 // Now upscale them to 0..256, so we can use SkAlphaBlend 168 maskR = SkAlpha255To256(maskR); 169 maskG = SkAlpha255To256(maskG); 170 maskB = SkAlpha255To256(maskB); 171 172 maskR = maskR * srcA >> 8; 173 maskG = maskG * srcA >> 8; 174 maskB = maskB * srcA >> 8; 175 176 int dstR = SkGetPackedR32(d); 177 int dstG = SkGetPackedG32(d); 178 int dstB = SkGetPackedB32(d); 179 180 // LCD blitting is only supported if the dst is known/required 181 // to be opaque 182 dst[i] = SkPackARGB32(0xFF, 183 SkAlphaBlend(srcR, dstR, maskR), 184 SkAlphaBlend(srcG, dstG, maskG), 185 SkAlphaBlend(srcB, dstB, maskB)); 186 } 187} 188 189static void D32_LCD32_Blend(void* SK_RESTRICT dst, size_t dstRB, 190 const void* SK_RESTRICT mask, size_t maskRB, 191 SkColor color, int width, int height) { 192 SkASSERT(height > 0); 193 SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst; 194 const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask; 195 196 do { 197 blit_lcd32_row(dstRow, srcRow, color, width); 198 dstRow = (SkPMColor*)((char*)dstRow + dstRB); 199 srcRow = (const SkPMColor*)((const char*)srcRow + maskRB); 200 } while (--height != 0); 201} 202 203static void D32_LCD32_Opaque(void* SK_RESTRICT dst, size_t dstRB, 204 const void* SK_RESTRICT mask, size_t maskRB, 205 SkColor color, int width, int height) { 206 SkASSERT(height > 0); 207 SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst; 208 const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask; 209 210 do { 211 blit_lcd32_opaque_row(dstRow, srcRow, color, width); 212 dstRow = (SkPMColor*)((char*)dstRow + dstRB); 213 srcRow = (const SkPMColor*)((const char*)srcRow + maskRB); 214 } while (--height != 0); 215} 216 217/////////////////////////////////////////////////////////////////////////////// 218 219static SkBlitMask::ColorProc D32_A8_Factory(SkColor color) { 220 if (SK_ColorBLACK == color) { 221 return D32_A8_Black; 222 } else if (0xFF == SkColorGetA(color)) { 223 return D32_A8_Opaque; 224 } else { 225 return D32_A8_Color; 226 } 227} 228 229static SkBlitMask::ColorProc D32_LCD32_Factory(SkColor color) { 230 return (0xFF == SkColorGetA(color)) ? D32_LCD32_Opaque : D32_LCD32_Blend; 231} 232 233SkBlitMask::ColorProc SkBlitMask::ColorFactory(SkBitmap::Config config, 234 SkMask::Format format, 235 SkColor color) { 236 ColorProc proc = PlatformColorProcs(config, format, color); 237 if (proc) { 238 return proc; 239 } 240 241 switch (config) { 242 case SkBitmap::kARGB_8888_Config: 243 switch (format) { 244 case SkMask::kA8_Format: 245 return D32_A8_Factory(color); 246 case SkMask::kLCD16_Format: 247 return D32_LCD16_Proc; 248 case SkMask::kLCD32_Format: 249 return D32_LCD32_Factory(color); 250 default: 251 break; 252 } 253 break; 254 default: 255 break; 256 } 257 return NULL; 258} 259 260bool SkBlitMask::BlitColor(const SkBitmap& device, const SkMask& mask, 261 const SkIRect& clip, SkColor color) { 262 ColorProc proc = ColorFactory(device.config(), mask.fFormat, color); 263 if (proc) { 264 int x = clip.fLeft; 265 int y = clip.fTop; 266 proc(device.getAddr32(x, y), device.rowBytes(), mask.getAddr(x, y), 267 mask.fRowBytes, color, clip.width(), clip.height()); 268 return true; 269 } 270 return false; 271} 272 273/////////////////////////////////////////////////////////////////////////////// 274/////////////////////////////////////////////////////////////////////////////// 275 276static void BW_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 277 const uint8_t* SK_RESTRICT mask, 278 const SkPMColor* SK_RESTRICT src, int count) { 279 int i, octuple = (count + 7) >> 3; 280 for (i = 0; i < octuple; ++i) { 281 int m = *mask++; 282 if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } 283 if (m & 0x40) { dst[1] = SkPMSrcOver(src[1], dst[1]); } 284 if (m & 0x20) { dst[2] = SkPMSrcOver(src[2], dst[2]); } 285 if (m & 0x10) { dst[3] = SkPMSrcOver(src[3], dst[3]); } 286 if (m & 0x08) { dst[4] = SkPMSrcOver(src[4], dst[4]); } 287 if (m & 0x04) { dst[5] = SkPMSrcOver(src[5], dst[5]); } 288 if (m & 0x02) { dst[6] = SkPMSrcOver(src[6], dst[6]); } 289 if (m & 0x01) { dst[7] = SkPMSrcOver(src[7], dst[7]); } 290 src += 8; 291 dst += 8; 292 } 293 count &= 7; 294 if (count > 0) { 295 int m = *mask; 296 do { 297 if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } 298 m <<= 1; 299 src += 1; 300 dst += 1; 301 } while (--count > 0); 302 } 303} 304 305static void BW_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 306 const uint8_t* SK_RESTRICT mask, 307 const SkPMColor* SK_RESTRICT src, int count) { 308 int i, octuple = (count + 7) >> 3; 309 for (i = 0; i < octuple; ++i) { 310 int m = *mask++; 311 if (m & 0x80) { dst[0] = src[0]; } 312 if (m & 0x40) { dst[1] = src[1]; } 313 if (m & 0x20) { dst[2] = src[2]; } 314 if (m & 0x10) { dst[3] = src[3]; } 315 if (m & 0x08) { dst[4] = src[4]; } 316 if (m & 0x04) { dst[5] = src[5]; } 317 if (m & 0x02) { dst[6] = src[6]; } 318 if (m & 0x01) { dst[7] = src[7]; } 319 src += 8; 320 dst += 8; 321 } 322 count &= 7; 323 if (count > 0) { 324 int m = *mask; 325 do { 326 if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } 327 m <<= 1; 328 src += 1; 329 dst += 1; 330 } while (--count > 0); 331 } 332} 333 334static void A8_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 335 const uint8_t* SK_RESTRICT mask, 336 const SkPMColor* SK_RESTRICT src, int count) { 337 for (int i = 0; i < count; ++i) { 338 if (mask[i]) { 339 dst[i] = SkBlendARGB32(src[i], dst[i], mask[i]); 340 } 341 } 342} 343 344// expand the steps that SkAlphaMulQ performs, but this way we can 345// exand.. add.. combine 346// instead of 347// expand..combine add expand..combine 348// 349#define EXPAND0(v, m, s) ((v) & (m)) * (s) 350#define EXPAND1(v, m, s) (((v) >> 8) & (m)) * (s) 351#define COMBINE(e0, e1, m) ((((e0) >> 8) & (m)) | ((e1) & ~(m))) 352 353static void A8_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 354 const uint8_t* SK_RESTRICT mask, 355 const SkPMColor* SK_RESTRICT src, int count) { 356#if 0 // suppress warning 357 const uint32_t rbmask = gMask_00FF00FF; 358#endif 359 for (int i = 0; i < count; ++i) { 360 int m = mask[i]; 361 if (m) { 362 m += (m >> 7); 363#if 1 364 // this is slightly slower than the expand/combine version, but it 365 // is much closer to the old results, so we use it for now to reduce 366 // rebaselining. 367 dst[i] = SkAlphaMulQ(src[i], m) + SkAlphaMulQ(dst[i], 256 - m); 368#else 369 uint32_t v = src[i]; 370 uint32_t s0 = EXPAND0(v, rbmask, m); 371 uint32_t s1 = EXPAND1(v, rbmask, m); 372 v = dst[i]; 373 uint32_t d0 = EXPAND0(v, rbmask, m); 374 uint32_t d1 = EXPAND1(v, rbmask, m); 375 dst[i] = COMBINE(s0 + d0, s1 + d1, rbmask); 376#endif 377 } 378 } 379} 380 381static int upscale31To255(int value) { 382 value = (value << 3) | (value >> 2); 383 return value; 384} 385 386static int src_alpha_blend(int src, int dst, int srcA, int mask) { 387 388 return dst + SkAlphaMul(src - SkAlphaMul(srcA, dst), mask); 389} 390 391static void LCD16_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 392 const uint16_t* SK_RESTRICT mask, 393 const SkPMColor* SK_RESTRICT src, int count) { 394 for (int i = 0; i < count; ++i) { 395 uint16_t m = mask[i]; 396 if (0 == m) { 397 continue; 398 } 399 400 SkPMColor s = src[i]; 401 SkPMColor d = dst[i]; 402 403 int srcA = SkGetPackedA32(s); 404 int srcR = SkGetPackedR32(s); 405 int srcG = SkGetPackedG32(s); 406 int srcB = SkGetPackedB32(s); 407 408 srcA += srcA >> 7; 409 410 /* We want all of these in 5bits, hence the shifts in case one of them 411 * (green) is 6bits. 412 */ 413 int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5); 414 int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5); 415 int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5); 416 417 maskR = upscale31To255(maskR); 418 maskG = upscale31To255(maskG); 419 maskB = upscale31To255(maskB); 420 421 int dstR = SkGetPackedR32(d); 422 int dstG = SkGetPackedG32(d); 423 int dstB = SkGetPackedB32(d); 424 425 // LCD blitting is only supported if the dst is known/required 426 // to be opaque 427 dst[i] = SkPackARGB32(0xFF, 428 src_alpha_blend(srcR, dstR, srcA, maskR), 429 src_alpha_blend(srcG, dstG, srcA, maskG), 430 src_alpha_blend(srcB, dstB, srcA, maskB)); 431 } 432} 433 434static void LCD16_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 435 const uint16_t* SK_RESTRICT mask, 436 const SkPMColor* SK_RESTRICT src, int count) { 437 for (int i = 0; i < count; ++i) { 438 uint16_t m = mask[i]; 439 if (0 == m) { 440 continue; 441 } 442 443 SkPMColor s = src[i]; 444 SkPMColor d = dst[i]; 445 446 int srcR = SkGetPackedR32(s); 447 int srcG = SkGetPackedG32(s); 448 int srcB = SkGetPackedB32(s); 449 450 /* We want all of these in 5bits, hence the shifts in case one of them 451 * (green) is 6bits. 452 */ 453 int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5); 454 int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5); 455 int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5); 456 457 // Now upscale them to 0..32, so we can use blend32 458 maskR = SkUpscale31To32(maskR); 459 maskG = SkUpscale31To32(maskG); 460 maskB = SkUpscale31To32(maskB); 461 462 int dstR = SkGetPackedR32(d); 463 int dstG = SkGetPackedG32(d); 464 int dstB = SkGetPackedB32(d); 465 466 // LCD blitting is only supported if the dst is known/required 467 // to be opaque 468 dst[i] = SkPackARGB32(0xFF, 469 SkBlend32(srcR, dstR, maskR), 470 SkBlend32(srcG, dstG, maskG), 471 SkBlend32(srcB, dstB, maskB)); 472 } 473} 474 475static void LCD32_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 476 const SkPMColor* SK_RESTRICT mask, 477 const SkPMColor* SK_RESTRICT src, int count) { 478 for (int i = 0; i < count; ++i) { 479 SkPMColor m = mask[i]; 480 if (0 == m) { 481 continue; 482 } 483 484 SkPMColor s = src[i]; 485 int srcA = SkGetPackedA32(s); 486 int srcR = SkGetPackedR32(s); 487 int srcG = SkGetPackedG32(s); 488 int srcB = SkGetPackedB32(s); 489 490 srcA = SkAlpha255To256(srcA); 491 492 SkPMColor d = dst[i]; 493 494 int maskR = SkGetPackedR32(m); 495 int maskG = SkGetPackedG32(m); 496 int maskB = SkGetPackedB32(m); 497 498 // Now upscale them to 0..256 499 maskR = SkAlpha255To256(maskR); 500 maskG = SkAlpha255To256(maskG); 501 maskB = SkAlpha255To256(maskB); 502 503 int dstR = SkGetPackedR32(d); 504 int dstG = SkGetPackedG32(d); 505 int dstB = SkGetPackedB32(d); 506 507 // LCD blitting is only supported if the dst is known/required 508 // to be opaque 509 dst[i] = SkPackARGB32(0xFF, 510 src_alpha_blend(srcR, dstR, srcA, maskR), 511 src_alpha_blend(srcG, dstG, srcA, maskG), 512 src_alpha_blend(srcB, dstB, srcA, maskB)); 513 } 514} 515 516static void LCD32_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 517 const SkPMColor* SK_RESTRICT mask, 518 const SkPMColor* SK_RESTRICT src, int count) { 519 for (int i = 0; i < count; ++i) { 520 SkPMColor m = mask[i]; 521 if (0 == m) { 522 continue; 523 } 524 525 SkPMColor s = src[i]; 526 SkPMColor d = dst[i]; 527 528 int maskR = SkGetPackedR32(m); 529 int maskG = SkGetPackedG32(m); 530 int maskB = SkGetPackedB32(m); 531 532 int srcR = SkGetPackedR32(s); 533 int srcG = SkGetPackedG32(s); 534 int srcB = SkGetPackedB32(s); 535 536 int dstR = SkGetPackedR32(d); 537 int dstG = SkGetPackedG32(d); 538 int dstB = SkGetPackedB32(d); 539 540 // Now upscale them to 0..256, so we can use SkAlphaBlend 541 maskR = SkAlpha255To256(maskR); 542 maskG = SkAlpha255To256(maskG); 543 maskB = SkAlpha255To256(maskB); 544 545 // LCD blitting is only supported if the dst is known/required 546 // to be opaque 547 dst[i] = SkPackARGB32(0xFF, 548 SkAlphaBlend(srcR, dstR, maskR), 549 SkAlphaBlend(srcG, dstG, maskG), 550 SkAlphaBlend(srcB, dstB, maskB)); 551 } 552} 553 554SkBlitMask::RowProc SkBlitMask::RowFactory(SkBitmap::Config config, 555 SkMask::Format format, 556 RowFlags flags) { 557// make this opt-in until chrome can rebaseline 558 RowProc proc = PlatformRowProcs(config, format, flags); 559 if (proc) { 560 return proc; 561 } 562 563 static const RowProc gProcs[] = { 564 // need X coordinate to handle BW 565 false ? (RowProc)BW_RowProc_Blend : NULL, // suppress unused warning 566 false ? (RowProc)BW_RowProc_Opaque : NULL, // suppress unused warning 567 (RowProc)A8_RowProc_Blend, (RowProc)A8_RowProc_Opaque, 568 (RowProc)LCD16_RowProc_Blend, (RowProc)LCD16_RowProc_Opaque, 569 (RowProc)LCD32_RowProc_Blend, (RowProc)LCD32_RowProc_Opaque, 570 }; 571 572 int index; 573 switch (config) { 574 case SkBitmap::kARGB_8888_Config: 575 switch (format) { 576 case SkMask::kBW_Format: index = 0; break; 577 case SkMask::kA8_Format: index = 2; break; 578 case SkMask::kLCD16_Format: index = 4; break; 579 case SkMask::kLCD32_Format: index = 6; break; 580 default: 581 return NULL; 582 } 583 if (flags & kSrcIsOpaque_RowFlag) { 584 index |= 1; 585 } 586 SkASSERT((size_t)index < SK_ARRAY_COUNT(gProcs)); 587 return gProcs[index]; 588 default: 589 break; 590 } 591 return NULL; 592} 593