1/* libs/graphics/sgl/SkBlitter_ARGB32.cpp 2** 3** Copyright 2006, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18#include "SkCoreBlitters.h" 19#include "SkColorPriv.h" 20#include "SkShader.h" 21#include "SkUtils.h" 22#include "SkXfermode.h" 23 24#if defined(SK_SUPPORT_LCDTEXT) 25namespace skia_blitter_support { 26// subpixel helper functions from SkBlitter_ARGB32_Subpixel.cpp 27uint32_t* adjustForSubpixelClip(const SkMask& mask, 28 const SkIRect& clip, const SkBitmap& device, 29 int* widthAdjustment, int* heightAdjustment, 30 const uint32_t** alpha32); 31extern uint32_t BlendLCDPixelWithColor(const uint32_t alphaPixel, const uint32_t originalPixel, 32 const uint32_t sourcePixel); 33extern uint32_t BlendLCDPixelWithOpaqueColor(const uint32_t alphaPixel, const uint32_t originalPixel, 34 const uint32_t sourcePixel); 35extern uint32_t BlendLCDPixelWithBlack(const uint32_t alphaPixel, const uint32_t originalPixel); 36} 37 38using namespace skia_blitter_support; 39#endif 40 41/////////////////////////////////////////////////////////////////////////////// 42 43static inline int upscale31To32(int value) { 44 SkASSERT((unsigned)value <= 31); 45 return value + (value >> 4); 46} 47 48static inline int blend32(int src, int dst, int scale) { 49 SkASSERT((unsigned)src <= 0xFF); 50 SkASSERT((unsigned)dst <= 0xFF); 51 SkASSERT((unsigned)scale <= 32); 52 return dst + ((src - dst) * scale >> 5); 53} 54 55static void blit_lcd16_opaque(SkPMColor dst[], const uint16_t src[], 56 SkPMColor color, int width) { 57 int srcR = SkGetPackedR32(color); 58 int srcG = SkGetPackedG32(color); 59 int srcB = SkGetPackedB32(color); 60 61 for (int i = 0; i < width; i++) { 62 uint16_t mask = src[i]; 63 if (0 == mask) { 64 continue; 65 } 66 67 SkPMColor d = dst[i]; 68 69 /* We want all of these in 5bits, hence the shifts in case one of them 70 * (green) is 6bits. 71 */ 72 int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5); 73 int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5); 74 int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5); 75 76 // Now upscale them to 0..256, so we can use SkAlphaBlend 77 maskR = upscale31To32(maskR); 78 maskG = upscale31To32(maskG); 79 maskB = upscale31To32(maskB); 80 81 int maskA = SkMax32(SkMax32(maskR, maskG), maskB); 82 83 int dstA = SkGetPackedA32(d); 84 int dstR = SkGetPackedR32(d); 85 int dstG = SkGetPackedG32(d); 86 int dstB = SkGetPackedB32(d); 87 88 dst[i] = SkPackARGB32(blend32(0xFF, dstA, maskA), 89 blend32(srcR, dstR, maskR), 90 blend32(srcG, dstG, maskG), 91 blend32(srcB, dstB, maskB)); 92 } 93} 94 95static void blitmask_lcd16(const SkBitmap& device, const SkMask& mask, 96 const SkIRect& clip, SkPMColor srcColor) { 97 int x = clip.fLeft; 98 int y = clip.fTop; 99 int width = clip.width(); 100 int height = clip.height(); 101 102 SkPMColor* dstRow = device.getAddr32(x, y); 103 const uint16_t* srcRow = mask.getAddrLCD16(x, y); 104 105 do { 106 blit_lcd16_opaque(dstRow, srcRow, srcColor, width); 107 dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes()); 108 srcRow = (const uint16_t*)((const char*)srcRow + mask.fRowBytes); 109 } while (--height != 0); 110} 111 112////////////////////////////////////////////////////////////////////////////////////// 113 114static void SkARGB32_Blit32(const SkBitmap& device, const SkMask& mask, 115 const SkIRect& clip, SkPMColor srcColor) { 116 U8CPU alpha = SkGetPackedA32(srcColor); 117 unsigned flags = SkBlitRow::kSrcPixelAlpha_Flag32; 118 if (alpha != 255) { 119 flags |= SkBlitRow::kGlobalAlpha_Flag32; 120 } 121 SkBlitRow::Proc32 proc = SkBlitRow::Factory32(flags); 122 123 int x = clip.fLeft; 124 int y = clip.fTop; 125 int width = clip.width(); 126 int height = clip.height(); 127 128 SkPMColor* dstRow = device.getAddr32(x, y); 129 const SkPMColor* srcRow = reinterpret_cast<const SkPMColor*>(mask.getAddr(x, y)); 130 131 do { 132 proc(dstRow, srcRow, width, alpha); 133 dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes()); 134 srcRow = (const SkPMColor*)((const char*)srcRow + mask.fRowBytes); 135 } while (--height != 0); 136} 137 138////////////////////////////////////////////////////////////////////////////////////// 139 140SkARGB32_Blitter::SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint) 141 : INHERITED(device) { 142 SkColor color = paint.getColor(); 143 fColor = color; 144 145 fSrcA = SkColorGetA(color); 146 unsigned scale = SkAlpha255To256(fSrcA); 147 fSrcR = SkAlphaMul(SkColorGetR(color), scale); 148 fSrcG = SkAlphaMul(SkColorGetG(color), scale); 149 fSrcB = SkAlphaMul(SkColorGetB(color), scale); 150 151 fPMColor = SkPackARGB32(fSrcA, fSrcR, fSrcG, fSrcB); 152 fColor32Proc = SkBlitRow::ColorProcFactory(); 153 154 // init the pro for blitmask 155 fBlitMaskProc = SkBlitMask::Factory(SkBitmap::kARGB_8888_Config, color); 156} 157 158const SkBitmap* SkARGB32_Blitter::justAnOpaqueColor(uint32_t* value) { 159 if (255 == fSrcA) { 160 *value = fPMColor; 161 return &fDevice; 162 } 163 return NULL; 164} 165 166#if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used without having been initialized 167#pragma warning ( push ) 168#pragma warning ( disable : 4701 ) 169#endif 170 171void SkARGB32_Blitter::blitH(int x, int y, int width) { 172 SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); 173 174 uint32_t* device = fDevice.getAddr32(x, y); 175 fColor32Proc(device, device, width, fPMColor); 176} 177 178void SkARGB32_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], 179 const int16_t runs[]) { 180 if (fSrcA == 0) { 181 return; 182 } 183 184 uint32_t color = fPMColor; 185 uint32_t* device = fDevice.getAddr32(x, y); 186 unsigned opaqueMask = fSrcA; // if fSrcA is 0xFF, then we will catch the fast opaque case 187 188 for (;;) { 189 int count = runs[0]; 190 SkASSERT(count >= 0); 191 if (count <= 0) { 192 return; 193 } 194 unsigned aa = antialias[0]; 195 if (aa) { 196 if ((opaqueMask & aa) == 255) { 197 sk_memset32(device, color, count); 198 } else { 199 uint32_t sc = SkAlphaMulQ(color, SkAlpha255To256(aa)); 200 fColor32Proc(device, device, count, sc); 201 } 202 } 203 runs += count; 204 antialias += count; 205 device += count; 206 } 207} 208 209////////////////////////////////////////////////////////////////////////////////////// 210 211#define solid_8_pixels(mask, dst, color) \ 212 do { \ 213 if (mask & 0x80) dst[0] = color; \ 214 if (mask & 0x40) dst[1] = color; \ 215 if (mask & 0x20) dst[2] = color; \ 216 if (mask & 0x10) dst[3] = color; \ 217 if (mask & 0x08) dst[4] = color; \ 218 if (mask & 0x04) dst[5] = color; \ 219 if (mask & 0x02) dst[6] = color; \ 220 if (mask & 0x01) dst[7] = color; \ 221 } while (0) 222 223#define SK_BLITBWMASK_NAME SkARGB32_BlitBW 224#define SK_BLITBWMASK_ARGS , SkPMColor color 225#define SK_BLITBWMASK_BLIT8(mask, dst) solid_8_pixels(mask, dst, color) 226#define SK_BLITBWMASK_GETADDR getAddr32 227#define SK_BLITBWMASK_DEVTYPE uint32_t 228#include "SkBlitBWMaskTemplate.h" 229 230#define blend_8_pixels(mask, dst, sc, dst_scale) \ 231 do { \ 232 if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ(dst[0], dst_scale); } \ 233 if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ(dst[1], dst_scale); } \ 234 if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ(dst[2], dst_scale); } \ 235 if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ(dst[3], dst_scale); } \ 236 if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ(dst[4], dst_scale); } \ 237 if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ(dst[5], dst_scale); } \ 238 if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ(dst[6], dst_scale); } \ 239 if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ(dst[7], dst_scale); } \ 240 } while (0) 241 242#define SK_BLITBWMASK_NAME SkARGB32_BlendBW 243#define SK_BLITBWMASK_ARGS , uint32_t sc, unsigned dst_scale 244#define SK_BLITBWMASK_BLIT8(mask, dst) blend_8_pixels(mask, dst, sc, dst_scale) 245#define SK_BLITBWMASK_GETADDR getAddr32 246#define SK_BLITBWMASK_DEVTYPE uint32_t 247#include "SkBlitBWMaskTemplate.h" 248 249void SkARGB32_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) { 250 SkASSERT(mask.fBounds.contains(clip)); 251 SkASSERT(fSrcA != 0xFF); 252 253 if (fSrcA == 0) { 254 return; 255 } 256 257 if (mask.fFormat == SkMask::kBW_Format) { 258 SkARGB32_BlendBW(fDevice, mask, clip, fPMColor, SkAlpha255To256(255 - fSrcA)); 259 return; 260 } else if (SkMask::kARGB32_Format == mask.fFormat) { 261 SkARGB32_Blit32(fDevice, mask, clip, fPMColor); 262 return; 263 } else if (SkMask::kLCD16_Format == mask.fFormat) { 264 blitmask_lcd16(fDevice, mask, clip, fPMColor); 265 return; 266 } 267 268 int x = clip.fLeft; 269 int y = clip.fTop; 270 271 fBlitMaskProc(fDevice.getAddr32(x, y), fDevice.rowBytes(), 272 SkBitmap::kARGB_8888_Config, 273 mask.getAddr(x, y), mask.fRowBytes, 274 fColor, clip.width(), clip.height()); 275} 276 277void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask, 278 const SkIRect& clip) { 279 SkASSERT(mask.fBounds.contains(clip)); 280 281 if (mask.fFormat == SkMask::kBW_Format) { 282 SkARGB32_BlitBW(fDevice, mask, clip, fPMColor); 283 return; 284 } else if (SkMask::kARGB32_Format == mask.fFormat) { 285 SkARGB32_Blit32(fDevice, mask, clip, fPMColor); 286 return; 287 } else if (SkMask::kLCD16_Format == mask.fFormat) { 288 blitmask_lcd16(fDevice, mask, clip, fPMColor); 289 return; 290 } 291 292 int x = clip.fLeft; 293 int y = clip.fTop; 294 int width = clip.width(); 295 int height = clip.height(); 296 297#if defined(SK_SUPPORT_LCDTEXT) 298 const bool lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format; 299 const bool verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format; 300 301 // In LCD mode the masks have either an extra couple of rows or columns on the edges. 302 if (lcdMode || verticalLCDMode) { 303 int widthAdjustment, heightAdjustment; 304 const uint32_t* alpha32; 305 uint32_t* device = adjustForSubpixelClip(mask, clip, fDevice, &widthAdjustment, &heightAdjustment, &alpha32); 306 307 width += widthAdjustment; 308 height += heightAdjustment; 309 310 unsigned devRB = fDevice.rowBytes() - (width << 2); 311 unsigned alphaExtraRowWords = mask.rowWordsLCD() - width; 312 SkPMColor srcColor = fPMColor; 313 314 do { 315 unsigned w = width; 316 do { 317 const uint32_t alphaPixel = *alpha32++; 318 const uint32_t originalPixel = *device; 319 *device++ = BlendLCDPixelWithOpaqueColor(alphaPixel, originalPixel, srcColor); 320 } while (--w != 0); 321 device = (uint32_t*)((char*)device + devRB); 322 alpha32 += alphaExtraRowWords; 323 } while (--height != 0); 324 325 return; 326 } 327#endif 328 329 fBlitMaskProc(fDevice.getAddr32(x, y), fDevice.rowBytes(), 330 SkBitmap::kARGB_8888_Config, 331 mask.getAddr(x, y), mask.fRowBytes, fColor, width, height); 332} 333 334////////////////////////////////////////////////////////////////////////////////////// 335 336void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { 337 if (alpha == 0 || fSrcA == 0) { 338 return; 339 } 340 341 uint32_t* device = fDevice.getAddr32(x, y); 342 uint32_t color = fPMColor; 343 344 if (alpha != 255) { 345 color = SkAlphaMulQ(color, SkAlpha255To256(alpha)); 346 } 347 348 unsigned dst_scale = 255 - SkGetPackedA32(color); 349 uint32_t prevDst = ~device[0]; 350 uint32_t result SK_INIT_TO_AVOID_WARNING; 351 uint32_t rowBytes = fDevice.rowBytes(); 352 353 while (--height >= 0) { 354 uint32_t dst = device[0]; 355 if (dst != prevDst) { 356 result = color + SkAlphaMulQ(dst, dst_scale); 357 prevDst = dst; 358 } 359 device[0] = result; 360 device = (uint32_t*)((char*)device + rowBytes); 361 } 362} 363 364void SkARGB32_Blitter::blitRect(int x, int y, int width, int height) { 365 SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() && y + height <= fDevice.height()); 366 367 if (fSrcA == 0) { 368 return; 369 } 370 371 uint32_t* device = fDevice.getAddr32(x, y); 372 uint32_t color = fPMColor; 373 size_t rowBytes = fDevice.rowBytes(); 374 375 while (--height >= 0) { 376 fColor32Proc(device, device, width, color); 377 device = (uint32_t*)((char*)device + rowBytes); 378 } 379} 380 381#if defined _WIN32 && _MSC_VER >= 1300 382#pragma warning ( pop ) 383#endif 384 385/////////////////////////////////////////////////////////////////////// 386 387void SkARGB32_Black_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) { 388 SkASSERT(mask.fBounds.contains(clip)); 389 390 if (mask.fFormat == SkMask::kBW_Format) { 391 SkPMColor black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT); 392 393 SkARGB32_BlitBW(fDevice, mask, clip, black); 394 } else if (SkMask::kARGB32_Format == mask.fFormat) { 395 SkARGB32_Blit32(fDevice, mask, clip, fPMColor); 396 } else if (SkMask::kLCD16_Format == mask.fFormat) { 397 blitmask_lcd16(fDevice, mask, clip, fPMColor); 398 } else { 399#if defined(SK_SUPPORT_LCDTEXT) 400 const bool lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format; 401 const bool verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format; 402#endif 403 404 // In LCD mode the masks have either an extra couple of rows or columns on the edges. 405 unsigned width = clip.width(); 406 unsigned height = clip.height(); 407 408 SkASSERT((int)height > 0); 409 SkASSERT((int)width > 0); 410 411#if defined(SK_SUPPORT_LCDTEXT) 412 if (lcdMode || verticalLCDMode) { 413 int widthAdjustment, heightAdjustment; 414 const uint32_t* alpha32; 415 uint32_t* device = adjustForSubpixelClip(mask, clip, fDevice, &widthAdjustment, &heightAdjustment, &alpha32); 416 417 width += widthAdjustment; 418 height += heightAdjustment; 419 420 unsigned deviceRB = fDevice.rowBytes() - (width << 2); 421 unsigned alphaExtraRowWords = mask.rowWordsLCD() - width; 422 423 do { 424 unsigned w = width; 425 do { 426 const uint32_t alphaPixel = *alpha32++; 427 const uint32_t originalPixel = *device; 428 *device++ = BlendLCDPixelWithBlack(alphaPixel, originalPixel); 429 } while (--w != 0); 430 device = (uint32_t*)((char*)device + deviceRB); 431 alpha32 += alphaExtraRowWords; 432 } while (--height != 0); 433 434 return; 435 } 436#endif 437 438 uint32_t* device = fDevice.getAddr32(clip.fLeft, clip.fTop); 439 unsigned maskRB = mask.fRowBytes - width; 440 unsigned deviceRB = fDevice.rowBytes() - (width << 2); 441 const uint8_t* alpha = mask.getAddr(clip.fLeft, clip.fTop); 442 do { 443 unsigned w = width; 444 do { 445 unsigned aa = *alpha++; 446 *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa)); 447 device += 1; 448 } while (--w != 0); 449 device = (uint32_t*)((char*)device + deviceRB); 450 alpha += maskRB; 451 } while (--height != 0); 452 } 453} 454 455void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], 456 const int16_t runs[]) { 457 uint32_t* device = fDevice.getAddr32(x, y); 458 SkPMColor black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT); 459 460 for (;;) { 461 int count = runs[0]; 462 SkASSERT(count >= 0); 463 if (count <= 0) { 464 return; 465 } 466 unsigned aa = antialias[0]; 467 if (aa) { 468 if (aa == 255) { 469 sk_memset32(device, black, count); 470 } else { 471 SkPMColor src = aa << SK_A32_SHIFT; 472 unsigned dst_scale = 256 - aa; 473 int n = count; 474 do { 475 --n; 476 device[n] = src + SkAlphaMulQ(device[n], dst_scale); 477 } while (n > 0); 478 } 479 } 480 runs += count; 481 antialias += count; 482 device += count; 483 } 484} 485 486////////////////////////////////////////////////////////////////////////////////////////// 487 488SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device, 489 const SkPaint& paint) : INHERITED(device, paint) { 490 fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor))); 491 492 fXfermode = paint.getXfermode(); 493 SkSafeRef(fXfermode); 494 495 int flags = 0; 496 if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { 497 flags |= SkBlitRow::kSrcPixelAlpha_Flag32; 498 } 499 // we call this on the output from the shader 500 fProc32 = SkBlitRow::Factory32(flags); 501 // we call this on the output from the shader + alpha from the aa buffer 502 fProc32Blend = SkBlitRow::Factory32(flags | SkBlitRow::kGlobalAlpha_Flag32); 503} 504 505SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() { 506 SkSafeUnref(fXfermode); 507 sk_free(fBuffer); 508} 509 510void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) { 511 SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); 512 513 uint32_t* device = fDevice.getAddr32(x, y); 514 515 if (fXfermode == NULL && (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { 516 fShader->shadeSpan(x, y, device, width); 517 } else { 518 SkPMColor* span = fBuffer; 519 fShader->shadeSpan(x, y, span, width); 520 if (fXfermode) { 521 fXfermode->xfer32(device, span, width, NULL); 522 } else { 523 fProc32(device, span, width, 255); 524 } 525 } 526} 527 528/////////////////////////////////////////////////////////////////////////////////////////////// 529 530void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], 531 const int16_t runs[]) { 532 SkPMColor* span = fBuffer; 533 uint32_t* device = fDevice.getAddr32(x, y); 534 SkShader* shader = fShader; 535 536 if (fXfermode) { 537 for (;;) { 538 SkXfermode* xfer = fXfermode; 539 540 int count = *runs; 541 if (count <= 0) 542 break; 543 int aa = *antialias; 544 if (aa) { 545 shader->shadeSpan(x, y, span, count); 546 if (aa == 255) { 547 xfer->xfer32(device, span, count, NULL); 548 } else { 549 // count is almost always 1 550 for (int i = count - 1; i >= 0; --i) { 551 xfer->xfer32(&device[i], &span[i], 1, antialias); 552 } 553 } 554 } 555 device += count; 556 runs += count; 557 antialias += count; 558 x += count; 559 } 560 } else if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) { 561 for (;;) { 562 int count = *runs; 563 if (count <= 0) { 564 break; 565 } 566 int aa = *antialias; 567 if (aa) { 568 if (aa == 255) { 569 // cool, have the shader draw right into the device 570 shader->shadeSpan(x, y, device, count); 571 } else { 572 shader->shadeSpan(x, y, span, count); 573 fProc32Blend(device, span, count, aa); 574 } 575 } 576 device += count; 577 runs += count; 578 antialias += count; 579 x += count; 580 } 581 } else { // no xfermode but the shader not opaque 582 for (;;) { 583 int count = *runs; 584 if (count <= 0) { 585 break; 586 } 587 int aa = *antialias; 588 if (aa) { 589 fShader->shadeSpan(x, y, span, count); 590 if (aa == 255) { 591 fProc32(device, span, count, 255); 592 } else { 593 fProc32Blend(device, span, count, aa); 594 } 595 } 596 device += count; 597 runs += count; 598 antialias += count; 599 x += count; 600 } 601 } 602} 603