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 12static 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 33static 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 54static 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 74SkBlitMask::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 87static 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 115static void blit_lcd32_opaque_row(SkPMColor* SK_RESTRICT dst, 116 const SkPMColor* SK_RESTRICT src, 117 SkColor color, int width) { 118 int srcR = SkColorGetR(color); 119 int srcG = SkColorGetG(color); 120 int srcB = SkColorGetB(color); 121 122 for (int i = 0; i < width; i++) { 123 SkPMColor mask = src[i]; 124 if (0 == mask) { 125 continue; 126 } 127 128 SkPMColor d = dst[i]; 129 130 int maskR = SkGetPackedR32(mask); 131 int maskG = SkGetPackedG32(mask); 132 int maskB = SkGetPackedB32(mask); 133 134 // Now upscale them to 0..256, so we can use SkAlphaBlend 135 maskR = SkAlpha255To256(maskR); 136 maskG = SkAlpha255To256(maskG); 137 maskB = SkAlpha255To256(maskB); 138 139 int dstR = SkGetPackedR32(d); 140 int dstG = SkGetPackedG32(d); 141 int dstB = SkGetPackedB32(d); 142 143 // LCD blitting is only supported if the dst is known/required 144 // to be opaque 145 dst[i] = SkPackARGB32(0xFF, 146 SkAlphaBlend(srcR, dstR, maskR), 147 SkAlphaBlend(srcG, dstG, maskG), 148 SkAlphaBlend(srcB, dstB, maskB)); 149 } 150} 151 152static void blit_lcd32_row(SkPMColor* SK_RESTRICT dst, 153 const SkPMColor* SK_RESTRICT src, 154 SkColor color, int width) { 155 int srcA = SkColorGetA(color); 156 int srcR = SkColorGetR(color); 157 int srcG = SkColorGetG(color); 158 int srcB = SkColorGetB(color); 159 160 srcA = SkAlpha255To256(srcA); 161 162 for (int i = 0; i < width; i++) { 163 SkPMColor mask = src[i]; 164 if (0 == mask) { 165 continue; 166 } 167 168 SkPMColor d = dst[i]; 169 170 int maskR = SkGetPackedR32(mask); 171 int maskG = SkGetPackedG32(mask); 172 int maskB = SkGetPackedB32(mask); 173 174 // Now upscale them to 0..256, so we can use SkAlphaBlend 175 maskR = SkAlpha255To256(maskR); 176 maskG = SkAlpha255To256(maskG); 177 maskB = SkAlpha255To256(maskB); 178 179 maskR = maskR * srcA >> 8; 180 maskG = maskG * srcA >> 8; 181 maskB = maskB * srcA >> 8; 182 183 int dstR = SkGetPackedR32(d); 184 int dstG = SkGetPackedG32(d); 185 int dstB = SkGetPackedB32(d); 186 187 // LCD blitting is only supported if the dst is known/required 188 // to be opaque 189 dst[i] = SkPackARGB32(0xFF, 190 SkAlphaBlend(srcR, dstR, maskR), 191 SkAlphaBlend(srcG, dstG, maskG), 192 SkAlphaBlend(srcB, dstB, maskB)); 193 } 194} 195 196static void D32_LCD32_Blend(void* SK_RESTRICT dst, size_t dstRB, 197 const void* SK_RESTRICT mask, size_t maskRB, 198 SkColor color, int width, int height) { 199 SkASSERT(height > 0); 200 SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst; 201 const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask; 202 203 do { 204 blit_lcd32_row(dstRow, srcRow, color, width); 205 dstRow = (SkPMColor*)((char*)dstRow + dstRB); 206 srcRow = (const SkPMColor*)((const char*)srcRow + maskRB); 207 } while (--height != 0); 208} 209 210static void D32_LCD32_Opaque(void* SK_RESTRICT dst, size_t dstRB, 211 const void* SK_RESTRICT mask, size_t maskRB, 212 SkColor color, int width, int height) { 213 SkASSERT(height > 0); 214 SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst; 215 const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask; 216 217 do { 218 blit_lcd32_opaque_row(dstRow, srcRow, color, width); 219 dstRow = (SkPMColor*)((char*)dstRow + dstRB); 220 srcRow = (const SkPMColor*)((const char*)srcRow + maskRB); 221 } while (--height != 0); 222} 223 224/////////////////////////////////////////////////////////////////////////////// 225 226static SkBlitMask::ColorProc D32_A8_Factory(SkColor color) { 227 if (SK_ColorBLACK == color) { 228 return D32_A8_Black; 229 } else if (0xFF == SkColorGetA(color)) { 230 return D32_A8_Opaque; 231 } else { 232 return D32_A8_Color; 233 } 234} 235 236static SkBlitMask::ColorProc D32_LCD32_Factory(SkColor color) { 237 return (0xFF == SkColorGetA(color)) ? D32_LCD32_Opaque : D32_LCD32_Blend; 238} 239 240SkBlitMask::ColorProc SkBlitMask::ColorFactory(SkColorType ct, 241 SkMask::Format format, 242 SkColor color) { 243 ColorProc proc = PlatformColorProcs(ct, format, color); 244 if (proc) { 245 return proc; 246 } 247 248 switch (ct) { 249 case kN32_SkColorType: 250 switch (format) { 251 case SkMask::kA8_Format: 252 return D32_A8_Factory(color); 253 case SkMask::kLCD16_Format: 254 return D32_LCD16_Proc; 255 case SkMask::kLCD32_Format: 256 return D32_LCD32_Factory(color); 257 default: 258 break; 259 } 260 break; 261 default: 262 break; 263 } 264 return NULL; 265} 266 267bool SkBlitMask::BlitColor(const SkBitmap& device, const SkMask& mask, 268 const SkIRect& clip, SkColor color) { 269 ColorProc proc = ColorFactory(device.colorType(), mask.fFormat, color); 270 if (proc) { 271 int x = clip.fLeft; 272 int y = clip.fTop; 273 proc(device.getAddr32(x, y), device.rowBytes(), mask.getAddr(x, y), 274 mask.fRowBytes, color, clip.width(), clip.height()); 275 return true; 276 } 277 return false; 278} 279 280/////////////////////////////////////////////////////////////////////////////// 281/////////////////////////////////////////////////////////////////////////////// 282 283static void BW_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 284 const uint8_t* SK_RESTRICT mask, 285 const SkPMColor* SK_RESTRICT src, int count) { 286 int i, octuple = (count + 7) >> 3; 287 for (i = 0; i < octuple; ++i) { 288 int m = *mask++; 289 if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } 290 if (m & 0x40) { dst[1] = SkPMSrcOver(src[1], dst[1]); } 291 if (m & 0x20) { dst[2] = SkPMSrcOver(src[2], dst[2]); } 292 if (m & 0x10) { dst[3] = SkPMSrcOver(src[3], dst[3]); } 293 if (m & 0x08) { dst[4] = SkPMSrcOver(src[4], dst[4]); } 294 if (m & 0x04) { dst[5] = SkPMSrcOver(src[5], dst[5]); } 295 if (m & 0x02) { dst[6] = SkPMSrcOver(src[6], dst[6]); } 296 if (m & 0x01) { dst[7] = SkPMSrcOver(src[7], dst[7]); } 297 src += 8; 298 dst += 8; 299 } 300 count &= 7; 301 if (count > 0) { 302 int m = *mask; 303 do { 304 if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } 305 m <<= 1; 306 src += 1; 307 dst += 1; 308 } while (--count > 0); 309 } 310} 311 312static void BW_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 313 const uint8_t* SK_RESTRICT mask, 314 const SkPMColor* SK_RESTRICT src, int count) { 315 int i, octuple = (count + 7) >> 3; 316 for (i = 0; i < octuple; ++i) { 317 int m = *mask++; 318 if (m & 0x80) { dst[0] = src[0]; } 319 if (m & 0x40) { dst[1] = src[1]; } 320 if (m & 0x20) { dst[2] = src[2]; } 321 if (m & 0x10) { dst[3] = src[3]; } 322 if (m & 0x08) { dst[4] = src[4]; } 323 if (m & 0x04) { dst[5] = src[5]; } 324 if (m & 0x02) { dst[6] = src[6]; } 325 if (m & 0x01) { dst[7] = src[7]; } 326 src += 8; 327 dst += 8; 328 } 329 count &= 7; 330 if (count > 0) { 331 int m = *mask; 332 do { 333 if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } 334 m <<= 1; 335 src += 1; 336 dst += 1; 337 } while (--count > 0); 338 } 339} 340 341static void A8_RowProc_Blend(SkPMColor* SK_RESTRICT dst, 342 const uint8_t* SK_RESTRICT mask, 343 const SkPMColor* SK_RESTRICT src, int count) { 344 for (int i = 0; i < count; ++i) { 345 if (mask[i]) { 346 dst[i] = SkBlendARGB32(src[i], dst[i], mask[i]); 347 } 348 } 349} 350 351// expand the steps that SkAlphaMulQ performs, but this way we can 352// exand.. add.. combine 353// instead of 354// expand..combine add expand..combine 355// 356#define EXPAND0(v, m, s) ((v) & (m)) * (s) 357#define EXPAND1(v, m, s) (((v) >> 8) & (m)) * (s) 358#define COMBINE(e0, e1, m) ((((e0) >> 8) & (m)) | ((e1) & ~(m))) 359 360static void A8_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, 361 const uint8_t* SK_RESTRICT mask, 362 const SkPMColor* SK_RESTRICT src, int count) { 363 for (int i = 0; i < count; ++i) { 364 int m = mask[i]; 365 if (m) { 366 m += (m >> 7); 367#if 1 368 // this is slightly slower than the expand/combine version, but it 369 // is much closer to the old results, so we use it for now to reduce 370 // rebaselining. 371 dst[i] = SkAlphaMulQ(src[i], m) + SkAlphaMulQ(dst[i], 256 - m); 372#else 373 uint32_t v = src[i]; 374 uint32_t s0 = EXPAND0(v, rbmask, m); 375 uint32_t s1 = EXPAND1(v, rbmask, m); 376 v = dst[i]; 377 uint32_t d0 = EXPAND0(v, rbmask, m); 378 uint32_t d1 = EXPAND1(v, rbmask, m); 379 dst[i] = COMBINE(s0 + d0, s1 + d1, rbmask); 380#endif 381 } 382 } 383} 384 385static int upscale31To255(int value) { 386 value = (value << 3) | (value >> 2); 387 return value; 388} 389 390static int src_alpha_blend(int src, int dst, int srcA, int mask) { 391 392 return dst + SkAlphaMul(src - SkAlphaMul(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(SkColorType ct, 559 SkMask::Format format, 560 RowFlags flags) { 561// make this opt-in until chrome can rebaseline 562 RowProc proc = PlatformRowProcs(ct, 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 (ct) { 578 case kN32_SkColorType: 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