1 2/* 3 * Copyright 2006 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10#include "SkCoreBlitters.h" 11#include "SkColorPriv.h" 12#include "SkDither.h" 13#include "SkShader.h" 14#include "SkTemplatesPriv.h" 15#include "SkUtils.h" 16#include "SkXfermode.h" 17 18static inline SkPMColor SkBlendARGB4444(SkPMColor16 src, SkPMColor16 dst, 19 U8CPU aa) { 20 SkASSERT((unsigned)aa <= 255); 21 22 unsigned src_scale = SkAlpha255To256(aa) >> 4; 23 unsigned dst_scale = SkAlpha15To16(15 - SkAlphaMul4(SkGetPackedA4444(src), src_scale)); 24 25 uint32_t src32 = SkExpand_4444(src) * src_scale; 26 uint32_t dst32 = SkExpand_4444(dst) * dst_scale; 27 return SkCompact_4444((src32 + dst32) >> 4); 28} 29 30/////////////////////////////////////////////////////////////////////////////// 31 32class SkARGB4444_Blitter : public SkRasterBlitter { 33public: 34 SkARGB4444_Blitter(const SkBitmap& device, const SkPaint& paint); 35 virtual void blitH(int x, int y, int width); 36 virtual void blitAntiH(int x, int y, const SkAlpha antialias[], 37 const int16_t runs[]); 38 virtual void blitV(int x, int y, int height, SkAlpha alpha); 39 virtual void blitRect(int x, int y, int width, int height); 40 virtual void blitMask(const SkMask&, const SkIRect&); 41 virtual const SkBitmap* justAnOpaqueColor(uint32_t*); 42 43protected: 44 SkPMColor16 fPMColor16, fPMColor16Other; 45 SkPMColor16 fRawColor16, fRawColor16Other; 46 uint8_t fScale16; 47 48private: 49 // illegal 50 SkARGB4444_Blitter& operator=(const SkARGB4444_Blitter&); 51 52 typedef SkRasterBlitter INHERITED; 53}; 54 55 56SkARGB4444_Blitter::SkARGB4444_Blitter(const SkBitmap& device, 57 const SkPaint& paint) : INHERITED(device) { 58 // cache premultiplied versions in 4444 59 SkPMColor c = SkPreMultiplyColor(paint.getColor()); 60 fPMColor16 = SkPixel32ToPixel4444(c); 61 if (paint.isDither()) { 62 fPMColor16Other = SkDitherPixel32To4444(c); 63 } else { 64 fPMColor16Other = fPMColor16; 65 } 66 67 // cache raw versions in 4444 68 fRawColor16 = SkPackARGB4444(0xFF >> 4, SkColorGetR(c) >> 4, 69 SkColorGetG(c) >> 4, SkColorGetB(c) >> 4); 70 if (paint.isDither()) { 71 fRawColor16Other = SkDitherARGB32To4444(0xFF, SkColorGetR(c), 72 SkColorGetG(c), SkColorGetB(c)); 73 } else { 74 fRawColor16Other = fRawColor16; 75 } 76 77 fScale16 = SkAlpha15To16(SkGetPackedA4444(fPMColor16Other)); 78 if (16 == fScale16) { 79 // force the original to also be opaque 80 fPMColor16 |= (0xF << SK_A4444_SHIFT); 81 } 82} 83 84const SkBitmap* SkARGB4444_Blitter::justAnOpaqueColor(uint32_t* value) { 85 if (16 == fScale16) { 86 *value = fPMColor16; 87 return &fDevice; 88 } 89 return NULL; 90} 91 92static void src_over_4444(SkPMColor16 dst[], SkPMColor16 color, 93 SkPMColor16 other, unsigned invScale, int count) { 94 int twice = count >> 1; 95 while (--twice >= 0) { 96 *dst = color + SkAlphaMulQ4(*dst, invScale); 97 dst++; 98 *dst = other + SkAlphaMulQ4(*dst, invScale); 99 dst++; 100 } 101 if (count & 1) { 102 *dst = color + SkAlphaMulQ4(*dst, invScale); 103 } 104} 105 106static inline uint32_t SkExpand_4444_Replicate(SkPMColor16 c) { 107 uint32_t c32 = SkExpand_4444(c); 108 return c32 | (c32 << 4); 109} 110 111static void src_over_4444x(SkPMColor16 dst[], uint32_t color, 112 uint32_t other, unsigned invScale, int count) { 113 int twice = count >> 1; 114 uint32_t tmp; 115 while (--twice >= 0) { 116 tmp = SkExpand_4444(*dst) * invScale; 117 *dst++ = SkCompact_4444((color + tmp) >> 4); 118 tmp = SkExpand_4444(*dst) * invScale; 119 *dst++ = SkCompact_4444((other + tmp) >> 4); 120 } 121 if (count & 1) { 122 tmp = SkExpand_4444(*dst) * invScale; 123 *dst = SkCompact_4444((color + tmp) >> 4); 124 } 125} 126 127void SkARGB4444_Blitter::blitH(int x, int y, int width) { 128 SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); 129 130 if (0 == fScale16) { 131 return; 132 } 133 134 SkPMColor16* device = fDevice.getAddr16(x, y); 135 SkPMColor16 color = fPMColor16; 136 SkPMColor16 other = fPMColor16Other; 137 138 if ((x ^ y) & 1) { 139 SkTSwap<SkPMColor16>(color, other); 140 } 141 142 if (16 == fScale16) { 143 sk_dither_memset16(device, color, other, width); 144 } else { 145 src_over_4444x(device, SkExpand_4444_Replicate(color), 146 SkExpand_4444_Replicate(other), 147 16 - fScale16, width); 148 } 149} 150 151void SkARGB4444_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { 152 if (0 == alpha || 0 == fScale16) { 153 return; 154 } 155 156 SkPMColor16* device = fDevice.getAddr16(x, y); 157 SkPMColor16 color = fPMColor16; 158 SkPMColor16 other = fPMColor16Other; 159 unsigned rb = fDevice.rowBytes(); 160 161 if ((x ^ y) & 1) { 162 SkTSwap<SkPMColor16>(color, other); 163 } 164 165 if (16 == fScale16 && 255 == alpha) { 166 while (--height >= 0) { 167 *device = color; 168 device = (SkPMColor16*)((char*)device + rb); 169 SkTSwap<SkPMColor16>(color, other); 170 } 171 } else { 172 unsigned alphaScale = SkAlpha255To256(alpha); 173 uint32_t c32 = SkExpand_4444(color) * (alphaScale >> 4); 174 // need to normalize the low nibble of each expanded component 175 // so we don't overflow the add with d32 176 c32 = SkCompact_4444(c32 >> 4); 177 unsigned invScale = 16 - SkAlpha15To16(SkGetPackedA4444(c32)); 178 // now re-expand and replicate 179 c32 = SkExpand_4444_Replicate(c32); 180 181 while (--height >= 0) { 182 uint32_t d32 = SkExpand_4444(*device) * invScale; 183 *device = SkCompact_4444((c32 + d32) >> 4); 184 device = (SkPMColor16*)((char*)device + rb); 185 } 186 } 187} 188 189void SkARGB4444_Blitter::blitRect(int x, int y, int width, int height) { 190 SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() && 191 y + height <= fDevice.height()); 192 193 if (0 == fScale16) { 194 return; 195 } 196 197 SkPMColor16* device = fDevice.getAddr16(x, y); 198 SkPMColor16 color = fPMColor16; 199 SkPMColor16 other = fPMColor16Other; 200 201 if ((x ^ y) & 1) { 202 SkTSwap<SkPMColor16>(color, other); 203 } 204 205 if (16 == fScale16) { 206 while (--height >= 0) { 207 sk_dither_memset16(device, color, other, width); 208 device = (SkPMColor16*)((char*)device + fDevice.rowBytes()); 209 SkTSwap<SkPMColor16>(color, other); 210 } 211 } else { 212 unsigned invScale = 16 - fScale16; 213 214 uint32_t c32 = SkExpand_4444_Replicate(color); 215 uint32_t o32 = SkExpand_4444_Replicate(other); 216 while (--height >= 0) { 217 src_over_4444x(device, c32, o32, invScale, width); 218 device = (SkPMColor16*)((char*)device + fDevice.rowBytes()); 219 SkTSwap<uint32_t>(c32, o32); 220 } 221 } 222} 223 224void SkARGB4444_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], 225 const int16_t runs[]) { 226 if (0 == fScale16) { 227 return; 228 } 229 230 SkPMColor16* device = fDevice.getAddr16(x, y); 231 SkPMColor16 color = fPMColor16; 232 SkPMColor16 other = fPMColor16Other; 233 234 if ((x ^ y) & 1) { 235 SkTSwap<SkPMColor16>(color, other); 236 } 237 238 for (;;) { 239 int count = runs[0]; 240 SkASSERT(count >= 0); 241 if (count <= 0) { 242 return; 243 } 244 245 unsigned aa = antialias[0]; 246 if (aa) { 247 if (0xFF == aa) { 248 if (16 == fScale16) { 249 sk_dither_memset16(device, color, other, count); 250 } else { 251 src_over_4444(device, color, other, 16 - fScale16, count); 252 } 253 } else { 254 // todo: respect dithering 255 aa = SkAlpha255To256(aa); // FIX 256 SkPMColor16 src = SkAlphaMulQ4(color, aa >> 4); 257 unsigned dst_scale = SkAlpha15To16(15 - SkGetPackedA4444(src)); // FIX 258 int n = count; 259 do { 260 --n; 261 device[n] = src + SkAlphaMulQ4(device[n], dst_scale); 262 } while (n > 0); 263 } 264 } 265 266 runs += count; 267 antialias += count; 268 device += count; 269 270 if (count & 1) { 271 SkTSwap<SkPMColor16>(color, other); 272 } 273 } 274} 275 276/////////////////////////////////////////////////////////////////////////////// 277 278#define solid_8_pixels(mask, dst, color) \ 279 do { \ 280 if (mask & 0x80) dst[0] = color; \ 281 if (mask & 0x40) dst[1] = color; \ 282 if (mask & 0x20) dst[2] = color; \ 283 if (mask & 0x10) dst[3] = color; \ 284 if (mask & 0x08) dst[4] = color; \ 285 if (mask & 0x04) dst[5] = color; \ 286 if (mask & 0x02) dst[6] = color; \ 287 if (mask & 0x01) dst[7] = color; \ 288 } while (0) 289 290#define SK_BLITBWMASK_NAME SkARGB4444_BlitBW 291#define SK_BLITBWMASK_ARGS , SkPMColor16 color 292#define SK_BLITBWMASK_BLIT8(mask, dst) solid_8_pixels(mask, dst, color) 293#define SK_BLITBWMASK_GETADDR getAddr16 294#define SK_BLITBWMASK_DEVTYPE uint16_t 295#include "SkBlitBWMaskTemplate.h" 296 297#define blend_8_pixels(mask, dst, sc, dst_scale) \ 298 do { \ 299 if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ4(dst[0], dst_scale); } \ 300 if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ4(dst[1], dst_scale); } \ 301 if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ4(dst[2], dst_scale); } \ 302 if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ4(dst[3], dst_scale); } \ 303 if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ4(dst[4], dst_scale); } \ 304 if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ4(dst[5], dst_scale); } \ 305 if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ4(dst[6], dst_scale); } \ 306 if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ4(dst[7], dst_scale); } \ 307 } while (0) 308 309#define SK_BLITBWMASK_NAME SkARGB4444_BlendBW 310#define SK_BLITBWMASK_ARGS , uint16_t sc, unsigned dst_scale 311#define SK_BLITBWMASK_BLIT8(mask, dst) blend_8_pixels(mask, dst, sc, dst_scale) 312#define SK_BLITBWMASK_GETADDR getAddr16 313#define SK_BLITBWMASK_DEVTYPE uint16_t 314#include "SkBlitBWMaskTemplate.h" 315 316void SkARGB4444_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) { 317 SkASSERT(mask.fBounds.contains(clip)); 318 319 if (0 == fScale16) { 320 return; 321 } 322 323 if (mask.fFormat == SkMask::kBW_Format) { 324 if (16 == fScale16) { 325 SkARGB4444_BlitBW(fDevice, mask, clip, fPMColor16); 326 } else { 327 SkARGB4444_BlendBW(fDevice, mask, clip, fPMColor16, 16 - fScale16); 328 } 329 return; 330 } 331 332 int x = clip.fLeft; 333 int y = clip.fTop; 334 int width = clip.width(); 335 int height = clip.height(); 336 337 SkPMColor16* device = fDevice.getAddr16(x, y); 338 const uint8_t* alpha = mask.getAddr8(x, y); 339 SkPMColor16 srcColor = fPMColor16; 340 unsigned devRB = fDevice.rowBytes() - (width << 1); 341 unsigned maskRB = mask.fRowBytes - width; 342 343 do { 344 int w = width; 345 do { 346 unsigned aa = *alpha++; 347 *device = SkBlendARGB4444(srcColor, *device, aa); 348 device += 1; 349 } while (--w != 0); 350 device = (SkPMColor16*)((char*)device + devRB); 351 alpha += maskRB; 352 } while (--height != 0); 353} 354 355/////////////////////////////////////////////////////////////////////////////// 356 357class SkARGB4444_Shader_Blitter : public SkShaderBlitter { 358 SkXfermode* fXfermode; 359 SkBlitRow::Proc fOpaqueProc; 360 SkBlitRow::Proc fAlphaProc; 361 SkPMColor* fBuffer; 362 uint8_t* fAAExpand; 363public: 364 365SkARGB4444_Shader_Blitter(const SkBitmap& device, const SkPaint& paint) 366 : INHERITED(device, paint) { 367 const int width = device.width(); 368 fBuffer = (SkPMColor*)sk_malloc_throw(width * sizeof(SkPMColor) + width); 369 fAAExpand = (uint8_t*)(fBuffer + width); 370 371 fXfermode = paint.getXfermode(); 372 SkSafeRef(fXfermode); 373 374 unsigned flags = 0; 375 if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { 376 flags |= SkBlitRow::kSrcPixelAlpha_Flag; 377 } 378 if (paint.isDither()) { 379 flags |= SkBlitRow::kDither_Flag; 380 } 381 fOpaqueProc = SkBlitRow::Factory(flags, SkBitmap::kARGB_4444_Config); 382 fAlphaProc = SkBlitRow::Factory(flags | SkBlitRow::kGlobalAlpha_Flag, 383 SkBitmap::kARGB_4444_Config); 384} 385 386virtual ~SkARGB4444_Shader_Blitter() { 387 SkSafeUnref(fXfermode); 388 sk_free(fBuffer); 389} 390 391virtual void blitH(int x, int y, int width) { 392 SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); 393 394 SkPMColor16* device = fDevice.getAddr16(x, y); 395 SkPMColor* span = fBuffer; 396 397 fShader->shadeSpan(x, y, span, width); 398 if (fXfermode) { 399 fXfermode->xfer4444(device, span, width, NULL); 400 } else { 401 fOpaqueProc(device, span, width, 0xFF, x, y); 402 } 403} 404 405virtual void blitAntiH(int x, int y, const SkAlpha antialias[], 406 const int16_t runs[]) { 407 SkPMColor* SK_RESTRICT span = fBuffer; 408 uint8_t* SK_RESTRICT aaExpand = fAAExpand; 409 SkPMColor16* device = fDevice.getAddr16(x, y); 410 SkShader* shader = fShader; 411 SkXfermode* xfer = fXfermode; 412 413 if (NULL != xfer) { 414 for (;;) { 415 int count = *runs; 416 if (count <= 0) { 417 break; 418 } 419 int aa = *antialias; 420 if (aa) { 421 shader->shadeSpan(x, y, span, count); 422 if (255 == aa) { 423 xfer->xfer4444(device, span, count, NULL); 424 } else { 425 const uint8_t* aaBuffer = antialias; 426 if (count > 1) { 427 memset(aaExpand, aa, count); 428 aaBuffer = aaExpand; 429 } 430 xfer->xfer4444(device, span, count, aaBuffer); 431 } 432 } 433 device += count; 434 runs += count; 435 antialias += count; 436 x += count; 437 } 438 } else { // no xfermode 439 for (;;) { 440 int count = *runs; 441 if (count <= 0) { 442 break; 443 } 444 int aa = *antialias; 445 if (aa) { 446 fShader->shadeSpan(x, y, span, count); 447 if (255 == aa) { 448 fOpaqueProc(device, span, count, aa, x, y); 449 } else { 450 fAlphaProc(device, span, count, aa, x, y); 451 } 452 } 453 device += count; 454 runs += count; 455 antialias += count; 456 x += count; 457 } 458 } 459} 460 461private: 462 typedef SkShaderBlitter INHERITED; 463}; 464 465/////////////////////////////////////////////////////////////////////////////// 466/////////////////////////////////////////////////////////////////////////////// 467 468SkBlitter* SkBlitter_ChooseD4444(const SkBitmap& device, 469 const SkPaint& paint, 470 void* storage, size_t storageSize) 471{ 472 SkBlitter* blitter; 473 474 if (paint.getShader()) { 475 SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Shader_Blitter, storage, storageSize, (device, paint)); 476 } else { 477 SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Blitter, storage, storageSize, (device, paint)); 478 } 479 return blitter; 480} 481 482