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 mul(int a, int b) { 387 return a * b >> 8; 388} 389 390static int src_alpha_blend(int src, int dst, int srcA, int mask) { 391 392 return dst + mul(src - mul(srcA, dst), mask); 393} 394 395static void LCD16_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 396 const uint16_t* SK_RESTRICT mask, 397 const SkPMColor* SK_RESTRICT src, int count) { 398 for (int i = 0; i < count; ++i) { 399 uint16_t m = mask[i]; 400 if (0 == m) { 401 continue; 402 } 403 404 SkPMColor s = src[i]; 405 SkPMColor d = dst[i]; 406 407 int srcA = SkGetPackedA32(s); 408 int srcR = SkGetPackedR32(s); 409 int srcG = SkGetPackedG32(s); 410 int srcB = SkGetPackedB32(s); 411 412 srcA += srcA >> 7; 413 414 /* We want all of these in 5bits, hence the shifts in case one of them 415 * (green) is 6bits. 416 */ 417 int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5); 418 int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5); 419 int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5); 420 421 maskR = upscale31To255(maskR); 422 maskG = upscale31To255(maskG); 423 maskB = upscale31To255(maskB); 424 425 int dstR = SkGetPackedR32(d); 426 int dstG = SkGetPackedG32(d); 427 int dstB = SkGetPackedB32(d); 428 429 // LCD blitting is only supported if the dst is known/required 430 // to be opaque 431 dst[i] = SkPackARGB32(0xFF, 432 src_alpha_blend(srcR, dstR, srcA, maskR), 433 src_alpha_blend(srcG, dstG, srcA, maskG), 434 src_alpha_blend(srcB, dstB, srcA, maskB)); 435 } 436} 437 438static void LCD16_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 439 const uint16_t* SK_RESTRICT mask, 440 const SkPMColor* SK_RESTRICT src, int count) { 441 for (int i = 0; i < count; ++i) { 442 uint16_t m = mask[i]; 443 if (0 == m) { 444 continue; 445 } 446 447 SkPMColor s = src[i]; 448 SkPMColor d = dst[i]; 449 450 int srcR = SkGetPackedR32(s); 451 int srcG = SkGetPackedG32(s); 452 int srcB = SkGetPackedB32(s); 453 454 /* We want all of these in 5bits, hence the shifts in case one of them 455 * (green) is 6bits. 456 */ 457 int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5); 458 int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5); 459 int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5); 460 461 // Now upscale them to 0..32, so we can use blend32 462 maskR = SkUpscale31To32(maskR); 463 maskG = SkUpscale31To32(maskG); 464 maskB = SkUpscale31To32(maskB); 465 466 int dstR = SkGetPackedR32(d); 467 int dstG = SkGetPackedG32(d); 468 int dstB = SkGetPackedB32(d); 469 470 // LCD blitting is only supported if the dst is known/required 471 // to be opaque 472 dst[i] = SkPackARGB32(0xFF, 473 SkBlend32(srcR, dstR, maskR), 474 SkBlend32(srcG, dstG, maskG), 475 SkBlend32(srcB, dstB, maskB)); 476 } 477} 478 479static void LCD32_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 480 const SkPMColor* SK_RESTRICT mask, 481 const SkPMColor* SK_RESTRICT src, int count) { 482 for (int i = 0; i < count; ++i) { 483 SkPMColor m = mask[i]; 484 if (0 == m) { 485 continue; 486 } 487 488 SkPMColor s = src[i]; 489 int srcA = SkGetPackedA32(s); 490 int srcR = SkGetPackedR32(s); 491 int srcG = SkGetPackedG32(s); 492 int srcB = SkGetPackedB32(s); 493 494 srcA = SkAlpha255To256(srcA); 495 496 SkPMColor d = dst[i]; 497 498 int maskR = SkGetPackedR32(m); 499 int maskG = SkGetPackedG32(m); 500 int maskB = SkGetPackedB32(m); 501 502 // Now upscale them to 0..256 503 maskR = SkAlpha255To256(maskR); 504 maskG = SkAlpha255To256(maskG); 505 maskB = SkAlpha255To256(maskB); 506 507 int dstR = SkGetPackedR32(d); 508 int dstG = SkGetPackedG32(d); 509 int dstB = SkGetPackedB32(d); 510 511 // LCD blitting is only supported if the dst is known/required 512 // to be opaque 513 dst[i] = SkPackARGB32(0xFF, 514 src_alpha_blend(srcR, dstR, srcA, maskR), 515 src_alpha_blend(srcG, dstG, srcA, maskG), 516 src_alpha_blend(srcB, dstB, srcA, maskB)); 517 } 518} 519 520static void LCD32_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 521 const SkPMColor* SK_RESTRICT mask, 522 const SkPMColor* SK_RESTRICT src, int count) { 523 for (int i = 0; i < count; ++i) { 524 SkPMColor m = mask[i]; 525 if (0 == m) { 526 continue; 527 } 528 529 SkPMColor s = src[i]; 530 SkPMColor d = dst[i]; 531 532 int maskR = SkGetPackedR32(m); 533 int maskG = SkGetPackedG32(m); 534 int maskB = SkGetPackedB32(m); 535 536 int srcR = SkGetPackedR32(s); 537 int srcG = SkGetPackedG32(s); 538 int srcB = SkGetPackedB32(s); 539 540 int dstR = SkGetPackedR32(d); 541 int dstG = SkGetPackedG32(d); 542 int dstB = SkGetPackedB32(d); 543 544 // Now upscale them to 0..256, so we can use SkAlphaBlend 545 maskR = SkAlpha255To256(maskR); 546 maskG = SkAlpha255To256(maskG); 547 maskB = SkAlpha255To256(maskB); 548 549 // LCD blitting is only supported if the dst is known/required 550 // to be opaque 551 dst[i] = SkPackARGB32(0xFF, 552 SkAlphaBlend(srcR, dstR, maskR), 553 SkAlphaBlend(srcG, dstG, maskG), 554 SkAlphaBlend(srcB, dstB, maskB)); 555 } 556} 557 558SkBlitMask::RowProc SkBlitMask::RowFactory(SkBitmap::Config config, 559 SkMask::Format format, 560 RowFlags flags) { 561// make this opt-in until chrome can rebaseline 562 RowProc proc = PlatformRowProcs(config, format, flags); 563 if (proc) { 564 return proc; 565 } 566 567 static const RowProc gProcs[] = { 568 // need X coordinate to handle BW 569 false ? (RowProc)BW_RowProc_Blend : NULL, // suppress unused warning 570 false ? (RowProc)BW_RowProc_Opaque : NULL, // suppress unused warning 571 (RowProc)A8_RowProc_Blend, (RowProc)A8_RowProc_Opaque, 572 (RowProc)LCD16_RowProc_Blend, (RowProc)LCD16_RowProc_Opaque, 573 (RowProc)LCD32_RowProc_Blend, (RowProc)LCD32_RowProc_Opaque, 574 }; 575 576 int index; 577 switch (config) { 578 case SkBitmap::kARGB_8888_Config: 579 switch (format) { 580 case SkMask::kBW_Format: index = 0; break; 581 case SkMask::kA8_Format: index = 2; break; 582 case SkMask::kLCD16_Format: index = 4; break; 583 case SkMask::kLCD32_Format: index = 6; break; 584 default: 585 return NULL; 586 } 587 if (flags & kSrcIsOpaque_RowFlag) { 588 index |= 1; 589 } 590 SkASSERT((size_t)index < SK_ARRAY_COUNT(gProcs)); 591 return gProcs[index]; 592 default: 593 break; 594 } 595 return NULL; 596} 597