1 #include "SkBlitMask.h" 2 #include "SkColor.h" 3 #include "SkColorPriv.h" 4 5 static 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 26 static 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 47 static 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 67 SkBlitMask::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 80 static 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 108 static 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 145 static 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 189 static 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 203 static 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 219 static 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 229 static SkBlitMask::ColorProc D32_LCD32_Factory(SkColor color) { 230 return (0xFF == SkColorGetA(color)) ? D32_LCD32_Opaque : D32_LCD32_Blend; 231 } 232 233 SkBlitMask::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 260 bool 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 276 static 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 305 static 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 334 static 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 353 static void A8_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 354 const uint8_t* SK_RESTRICT mask, 355 const SkPMColor* SK_RESTRICT src, int count) { 356 const uint32_t rbmask = gMask_00FF00FF; 357 for (int i = 0; i < count; ++i) { 358 int m = mask[i]; 359 if (m) { 360 m += (m >> 7); 361 #if 1 362 // this is slightly slower than the expand/combine version, but it 363 // is much closer to the old results, so we use it for now to reduce 364 // rebaselining. 365 dst[i] = SkAlphaMulQ(src[i], m) + SkAlphaMulQ(dst[i], 256 - m); 366 #else 367 uint32_t v = src[i]; 368 uint32_t s0 = EXPAND0(v, rbmask, m); 369 uint32_t s1 = EXPAND1(v, rbmask, m); 370 v = dst[i]; 371 uint32_t d0 = EXPAND0(v, rbmask, m); 372 uint32_t d1 = EXPAND1(v, rbmask, m); 373 dst[i] = COMBINE(s0 + d0, s1 + d1, rbmask); 374 #endif 375 } 376 } 377 } 378 379 static int upscale31To255(int value) { 380 value = (value << 3) | (value >> 2); 381 return value; 382 } 383 384 static int mul(int a, int b) { 385 return a * b >> 8; 386 } 387 388 static int src_alpha_blend(int src, int dst, int srcA, int mask) { 389 390 return dst + mul(src - mul(srcA, dst), mask); 391 } 392 393 static void LCD16_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 394 const uint16_t* SK_RESTRICT mask, 395 const SkPMColor* SK_RESTRICT src, int count) { 396 for (int i = 0; i < count; ++i) { 397 uint16_t m = mask[i]; 398 if (0 == m) { 399 continue; 400 } 401 402 SkPMColor s = src[i]; 403 SkPMColor d = dst[i]; 404 405 int srcA = SkGetPackedA32(s); 406 int srcR = SkGetPackedR32(s); 407 int srcG = SkGetPackedG32(s); 408 int srcB = SkGetPackedB32(s); 409 410 srcA += srcA >> 7; 411 412 /* We want all of these in 5bits, hence the shifts in case one of them 413 * (green) is 6bits. 414 */ 415 int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5); 416 int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5); 417 int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5); 418 419 maskR = upscale31To255(maskR); 420 maskG = upscale31To255(maskG); 421 maskB = upscale31To255(maskB); 422 423 int dstR = SkGetPackedR32(d); 424 int dstG = SkGetPackedG32(d); 425 int dstB = SkGetPackedB32(d); 426 427 // LCD blitting is only supported if the dst is known/required 428 // to be opaque 429 dst[i] = SkPackARGB32(0xFF, 430 src_alpha_blend(srcR, dstR, srcA, maskR), 431 src_alpha_blend(srcG, dstG, srcA, maskG), 432 src_alpha_blend(srcB, dstB, srcA, maskB)); 433 } 434 } 435 436 static void LCD16_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 437 const uint16_t* SK_RESTRICT mask, 438 const SkPMColor* SK_RESTRICT src, int count) { 439 for (int i = 0; i < count; ++i) { 440 uint16_t m = mask[i]; 441 if (0 == m) { 442 continue; 443 } 444 445 SkPMColor s = src[i]; 446 SkPMColor d = dst[i]; 447 448 int srcR = SkGetPackedR32(s); 449 int srcG = SkGetPackedG32(s); 450 int srcB = SkGetPackedB32(s); 451 452 /* We want all of these in 5bits, hence the shifts in case one of them 453 * (green) is 6bits. 454 */ 455 int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5); 456 int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5); 457 int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5); 458 459 // Now upscale them to 0..32, so we can use blend32 460 maskR = SkUpscale31To32(maskR); 461 maskG = SkUpscale31To32(maskG); 462 maskB = SkUpscale31To32(maskB); 463 464 int dstR = SkGetPackedR32(d); 465 int dstG = SkGetPackedG32(d); 466 int dstB = SkGetPackedB32(d); 467 468 // LCD blitting is only supported if the dst is known/required 469 // to be opaque 470 dst[i] = SkPackARGB32(0xFF, 471 SkBlend32(srcR, dstR, maskR), 472 SkBlend32(srcG, dstG, maskG), 473 SkBlend32(srcB, dstB, maskB)); 474 } 475 } 476 477 static void LCD32_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 478 const SkPMColor* SK_RESTRICT mask, 479 const SkPMColor* SK_RESTRICT src, int count) { 480 for (int i = 0; i < count; ++i) { 481 SkPMColor m = mask[i]; 482 if (0 == m) { 483 continue; 484 } 485 486 SkPMColor s = src[i]; 487 int srcA = SkGetPackedA32(s); 488 int srcR = SkGetPackedR32(s); 489 int srcG = SkGetPackedG32(s); 490 int srcB = SkGetPackedB32(s); 491 492 srcA = SkAlpha255To256(srcA); 493 494 SkPMColor d = dst[i]; 495 496 int maskR = SkGetPackedR32(m); 497 int maskG = SkGetPackedG32(m); 498 int maskB = SkGetPackedB32(m); 499 500 // Now upscale them to 0..256 501 maskR = SkAlpha255To256(maskR); 502 maskG = SkAlpha255To256(maskG); 503 maskB = SkAlpha255To256(maskB); 504 505 int dstR = SkGetPackedR32(d); 506 int dstG = SkGetPackedG32(d); 507 int dstB = SkGetPackedB32(d); 508 509 // LCD blitting is only supported if the dst is known/required 510 // to be opaque 511 dst[i] = SkPackARGB32(0xFF, 512 src_alpha_blend(srcR, dstR, srcA, maskR), 513 src_alpha_blend(srcG, dstG, srcA, maskG), 514 src_alpha_blend(srcB, dstB, srcA, maskB)); 515 } 516 } 517 518 static void LCD32_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 519 const SkPMColor* SK_RESTRICT mask, 520 const SkPMColor* SK_RESTRICT src, int count) { 521 for (int i = 0; i < count; ++i) { 522 SkPMColor m = mask[i]; 523 if (0 == m) { 524 continue; 525 } 526 527 SkPMColor s = src[i]; 528 SkPMColor d = dst[i]; 529 530 int maskR = SkGetPackedR32(m); 531 int maskG = SkGetPackedG32(m); 532 int maskB = SkGetPackedB32(m); 533 534 int srcR = SkGetPackedR32(s); 535 int srcG = SkGetPackedG32(s); 536 int srcB = SkGetPackedB32(s); 537 538 int dstR = SkGetPackedR32(d); 539 int dstG = SkGetPackedG32(d); 540 int dstB = SkGetPackedB32(d); 541 542 // Now upscale them to 0..256, so we can use SkAlphaBlend 543 maskR = SkAlpha255To256(maskR); 544 maskG = SkAlpha255To256(maskG); 545 maskB = SkAlpha255To256(maskB); 546 547 // LCD blitting is only supported if the dst is known/required 548 // to be opaque 549 dst[i] = SkPackARGB32(0xFF, 550 SkAlphaBlend(srcR, dstR, maskR), 551 SkAlphaBlend(srcG, dstG, maskG), 552 SkAlphaBlend(srcB, dstB, maskB)); 553 } 554 } 555 556 SkBlitMask::RowProc SkBlitMask::RowFactory(SkBitmap::Config config, 557 SkMask::Format format, 558 RowFlags flags) { 559 // make this opt-in until chrome can rebaseline 560 RowProc proc = PlatformRowProcs(config, format, flags); 561 if (proc) { 562 return proc; 563 } 564 565 static const RowProc gProcs[] = { 566 // need X coordinate to handle BW 567 NULL, NULL, //(RowProc)BW_RowProc_Blend, (RowProc)BW_RowProc_Opaque, 568 (RowProc)A8_RowProc_Blend, (RowProc)A8_RowProc_Opaque, 569 (RowProc)LCD16_RowProc_Blend, (RowProc)LCD16_RowProc_Opaque, 570 (RowProc)LCD32_RowProc_Blend, (RowProc)LCD32_RowProc_Opaque, 571 }; 572 573 int index; 574 switch (config) { 575 case SkBitmap::kARGB_8888_Config: 576 switch (format) { 577 case SkMask::kBW_Format: index = 0; break; 578 case SkMask::kA8_Format: index = 2; break; 579 case SkMask::kLCD16_Format: index = 4; break; 580 case SkMask::kLCD32_Format: index = 6; break; 581 default: 582 return NULL; 583 } 584 if (flags & kSrcIsOpaque_RowFlag) { 585 index |= 1; 586 } 587 SkASSERT((size_t)index < SK_ARRAY_COUNT(gProcs)); 588 return gProcs[index]; 589 default: 590 break; 591 } 592 return NULL; 593 } 594 595