1 /* 2 * Copyright 2007 The Android Open Source Project 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 9 #include "SkScaledBitmapSampler.h" 10 #include "SkBitmap.h" 11 #include "SkColorPriv.h" 12 #include "SkDither.h" 13 #include "SkTypes.h" 14 15 // 8888 16 17 static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow, 18 const uint8_t* SK_RESTRICT src, 19 int width, int deltaSrc, int, const SkPMColor[]) { 20 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 21 for (int x = 0; x < width; x++) { 22 dst[x] = SkPackARGB32(0xFF, src[0], src[0], src[0]); 23 src += deltaSrc; 24 } 25 return false; 26 } 27 28 static SkScaledBitmapSampler::RowProc get_gray_to_8888_proc(const SkImageDecoder& decoder) { 29 // Dither, unpremul, and skipZeroes have no effect 30 return Sample_Gray_D8888; 31 } 32 33 static bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow, 34 const uint8_t* SK_RESTRICT src, 35 int width, int deltaSrc, int, const SkPMColor[]) { 36 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 37 for (int x = 0; x < width; x++) { 38 dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]); 39 src += deltaSrc; 40 } 41 return false; 42 } 43 44 static SkScaledBitmapSampler::RowProc get_RGBx_to_8888_proc(const SkImageDecoder& decoder) { 45 // Dither, unpremul, and skipZeroes have no effect 46 return Sample_RGBx_D8888; 47 } 48 49 static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow, 50 const uint8_t* SK_RESTRICT src, 51 int width, int deltaSrc, int, const SkPMColor[]) { 52 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 53 unsigned alphaMask = 0xFF; 54 for (int x = 0; x < width; x++) { 55 unsigned alpha = src[3]; 56 dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); 57 src += deltaSrc; 58 alphaMask &= alpha; 59 } 60 return alphaMask != 0xFF; 61 } 62 63 static bool Sample_RGBA_D8888_Unpremul(void* SK_RESTRICT dstRow, 64 const uint8_t* SK_RESTRICT src, 65 int width, int deltaSrc, int, 66 const SkPMColor[]) { 67 uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow); 68 unsigned alphaMask = 0xFF; 69 for (int x = 0; x < width; x++) { 70 unsigned alpha = src[3]; 71 dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]); 72 src += deltaSrc; 73 alphaMask &= alpha; 74 } 75 return alphaMask != 0xFF; 76 } 77 78 static bool Sample_RGBA_D8888_SkipZ(void* SK_RESTRICT dstRow, 79 const uint8_t* SK_RESTRICT src, 80 int width, int deltaSrc, int, 81 const SkPMColor[]) { 82 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 83 unsigned alphaMask = 0xFF; 84 for (int x = 0; x < width; x++) { 85 unsigned alpha = src[3]; 86 if (0 != alpha) { 87 dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); 88 } 89 src += deltaSrc; 90 alphaMask &= alpha; 91 } 92 return alphaMask != 0xFF; 93 } 94 95 static SkScaledBitmapSampler::RowProc get_RGBA_to_8888_proc(const SkImageDecoder& decoder) { 96 // Dither has no effect. 97 if (decoder.getRequireUnpremultipliedColors()) { 98 // We could check each component for a zero, at the expense of extra checks. 99 // For now, just return unpremul. 100 return Sample_RGBA_D8888_Unpremul; 101 } 102 // Supply the versions that premultiply the colors 103 if (decoder.getSkipWritingZeroes()) { 104 return Sample_RGBA_D8888_SkipZ; 105 } 106 return Sample_RGBA_D8888; 107 } 108 109 // 565 110 111 static bool Sample_Gray_D565(void* SK_RESTRICT dstRow, 112 const uint8_t* SK_RESTRICT src, 113 int width, int deltaSrc, int, const SkPMColor[]) { 114 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; 115 for (int x = 0; x < width; x++) { 116 dst[x] = SkPack888ToRGB16(src[0], src[0], src[0]); 117 src += deltaSrc; 118 } 119 return false; 120 } 121 122 static bool Sample_Gray_D565_D(void* SK_RESTRICT dstRow, 123 const uint8_t* SK_RESTRICT src, 124 int width, int deltaSrc, int y, const SkPMColor[]) { 125 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; 126 DITHER_565_SCAN(y); 127 for (int x = 0; x < width; x++) { 128 dst[x] = SkDitherRGBTo565(src[0], src[0], src[0], DITHER_VALUE(x)); 129 src += deltaSrc; 130 } 131 return false; 132 } 133 134 static SkScaledBitmapSampler::RowProc get_gray_to_565_proc(const SkImageDecoder& decoder) { 135 // Unpremul and skip zeroes make no difference 136 if (decoder.getDitherImage()) { 137 return Sample_Gray_D565_D; 138 } 139 return Sample_Gray_D565; 140 } 141 142 static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow, 143 const uint8_t* SK_RESTRICT src, 144 int width, int deltaSrc, int, const SkPMColor[]) { 145 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; 146 for (int x = 0; x < width; x++) { 147 dst[x] = SkPack888ToRGB16(src[0], src[1], src[2]); 148 src += deltaSrc; 149 } 150 return false; 151 } 152 153 static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow, 154 const uint8_t* SK_RESTRICT src, 155 int width, int deltaSrc, int y, 156 const SkPMColor[]) { 157 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; 158 DITHER_565_SCAN(y); 159 for (int x = 0; x < width; x++) { 160 dst[x] = SkDitherRGBTo565(src[0], src[1], src[2], DITHER_VALUE(x)); 161 src += deltaSrc; 162 } 163 return false; 164 } 165 166 static SkScaledBitmapSampler::RowProc get_RGBx_to_565_proc(const SkImageDecoder& decoder) { 167 // Unpremul and skip zeroes make no difference 168 if (decoder.getDitherImage()) { 169 return Sample_RGBx_D565_D; 170 } 171 return Sample_RGBx_D565; 172 } 173 174 175 static bool Sample_D565_D565(void* SK_RESTRICT dstRow, 176 const uint8_t* SK_RESTRICT src, 177 int width, int deltaSrc, int, const SkPMColor[]) { 178 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; 179 uint16_t* SK_RESTRICT castedSrc = (uint16_t*) src; 180 for (int x = 0; x < width; x++) { 181 dst[x] = castedSrc[0]; 182 castedSrc += deltaSrc >> 1; 183 } 184 return false; 185 } 186 187 static SkScaledBitmapSampler::RowProc get_565_to_565_proc(const SkImageDecoder& decoder) { 188 // Unpremul, dither, and skip zeroes have no effect 189 return Sample_D565_D565; 190 } 191 192 // 4444 193 194 static bool Sample_Gray_D4444(void* SK_RESTRICT dstRow, 195 const uint8_t* SK_RESTRICT src, 196 int width, int deltaSrc, int, const SkPMColor[]) { 197 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 198 for (int x = 0; x < width; x++) { 199 unsigned gray = src[0] >> 4; 200 dst[x] = SkPackARGB4444(0xF, gray, gray, gray); 201 src += deltaSrc; 202 } 203 return false; 204 } 205 206 static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow, 207 const uint8_t* SK_RESTRICT src, 208 int width, int deltaSrc, int y, const SkPMColor[]) { 209 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 210 DITHER_4444_SCAN(y); 211 for (int x = 0; x < width; x++) { 212 dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[0], src[0], 213 DITHER_VALUE(x)); 214 src += deltaSrc; 215 } 216 return false; 217 } 218 219 static SkScaledBitmapSampler::RowProc get_gray_to_4444_proc(const SkImageDecoder& decoder) { 220 // Skip zeroes and unpremul make no difference 221 if (decoder.getDitherImage()) { 222 return Sample_Gray_D4444_D; 223 } 224 return Sample_Gray_D4444; 225 } 226 227 static bool Sample_RGBx_D4444(void* SK_RESTRICT dstRow, 228 const uint8_t* SK_RESTRICT src, 229 int width, int deltaSrc, int, const SkPMColor[]) { 230 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 231 for (int x = 0; x < width; x++) { 232 dst[x] = SkPackARGB4444(0xF, src[0] >> 4, src[1] >> 4, src[2] >> 4); 233 src += deltaSrc; 234 } 235 return false; 236 } 237 238 static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow, 239 const uint8_t* SK_RESTRICT src, 240 int width, int deltaSrc, int y, const SkPMColor[]) { 241 SkPMColor16* dst = (SkPMColor16*)dstRow; 242 DITHER_4444_SCAN(y); 243 244 for (int x = 0; x < width; x++) { 245 dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[1], src[2], 246 DITHER_VALUE(x)); 247 src += deltaSrc; 248 } 249 return false; 250 } 251 252 static SkScaledBitmapSampler::RowProc get_RGBx_to_4444_proc(const SkImageDecoder& decoder) { 253 // Skip zeroes and unpremul make no difference 254 if (decoder.getDitherImage()) { 255 return Sample_RGBx_D4444_D; 256 } 257 return Sample_RGBx_D4444; 258 } 259 260 static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow, 261 const uint8_t* SK_RESTRICT src, 262 int width, int deltaSrc, int, const SkPMColor[]) { 263 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 264 unsigned alphaMask = 0xFF; 265 266 for (int x = 0; x < width; x++) { 267 unsigned alpha = src[3]; 268 SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); 269 dst[x] = SkPixel32ToPixel4444(c); 270 src += deltaSrc; 271 alphaMask &= alpha; 272 } 273 return alphaMask != 0xFF; 274 } 275 276 static bool Sample_RGBA_D4444_SkipZ(void* SK_RESTRICT dstRow, 277 const uint8_t* SK_RESTRICT src, 278 int width, int deltaSrc, int, 279 const SkPMColor[]) { 280 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 281 unsigned alphaMask = 0xFF; 282 283 for (int x = 0; x < width; x++) { 284 unsigned alpha = src[3]; 285 if (alpha != 0) { 286 SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); 287 dst[x] = SkPixel32ToPixel4444(c); 288 } 289 src += deltaSrc; 290 alphaMask &= alpha; 291 } 292 return alphaMask != 0xFF; 293 } 294 295 296 static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow, 297 const uint8_t* SK_RESTRICT src, 298 int width, int deltaSrc, int y, 299 const SkPMColor[]) { 300 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 301 unsigned alphaMask = 0xFF; 302 DITHER_4444_SCAN(y); 303 304 for (int x = 0; x < width; x++) { 305 unsigned alpha = src[3]; 306 SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); 307 dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x)); 308 src += deltaSrc; 309 alphaMask &= alpha; 310 } 311 return alphaMask != 0xFF; 312 } 313 314 static bool Sample_RGBA_D4444_D_SkipZ(void* SK_RESTRICT dstRow, 315 const uint8_t* SK_RESTRICT src, 316 int width, int deltaSrc, int y, 317 const SkPMColor[]) { 318 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 319 unsigned alphaMask = 0xFF; 320 DITHER_4444_SCAN(y); 321 322 for (int x = 0; x < width; x++) { 323 unsigned alpha = src[3]; 324 if (alpha != 0) { 325 SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]); 326 dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x)); 327 } 328 src += deltaSrc; 329 alphaMask &= alpha; 330 } 331 return alphaMask != 0xFF; 332 } 333 334 static SkScaledBitmapSampler::RowProc get_RGBA_to_4444_proc(const SkImageDecoder& decoder) { 335 if (decoder.getRequireUnpremultipliedColors()) { 336 // Unpremultiplied is not supported for 4444 337 return NULL; 338 } 339 const bool dither = decoder.getDitherImage(); 340 if (decoder.getSkipWritingZeroes()) { 341 if (dither) { 342 return Sample_RGBA_D4444_D_SkipZ; 343 } 344 return Sample_RGBA_D4444_SkipZ; 345 } 346 if (dither) { 347 return Sample_RGBA_D4444_D; 348 } 349 return Sample_RGBA_D4444; 350 } 351 352 // Index 353 354 #define A32_MASK_IN_PLACE (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT) 355 356 static bool Sample_Index_D8888(void* SK_RESTRICT dstRow, 357 const uint8_t* SK_RESTRICT src, 358 int width, int deltaSrc, int, const SkPMColor ctable[]) { 359 360 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 361 SkPMColor cc = A32_MASK_IN_PLACE; 362 for (int x = 0; x < width; x++) { 363 SkPMColor c = ctable[*src]; 364 cc &= c; 365 dst[x] = c; 366 src += deltaSrc; 367 } 368 return cc != A32_MASK_IN_PLACE; 369 } 370 371 static bool Sample_Index_D8888_SkipZ(void* SK_RESTRICT dstRow, 372 const uint8_t* SK_RESTRICT src, 373 int width, int deltaSrc, int, 374 const SkPMColor ctable[]) { 375 376 SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; 377 SkPMColor cc = A32_MASK_IN_PLACE; 378 for (int x = 0; x < width; x++) { 379 SkPMColor c = ctable[*src]; 380 cc &= c; 381 if (c != 0) { 382 dst[x] = c; 383 } 384 src += deltaSrc; 385 } 386 return cc != A32_MASK_IN_PLACE; 387 } 388 389 static SkScaledBitmapSampler::RowProc get_index_to_8888_proc(const SkImageDecoder& decoder) { 390 if (decoder.getRequireUnpremultipliedColors()) { 391 // Unpremultiplied is not supported for an index source. 392 return NULL; 393 } 394 // Dither makes no difference 395 if (decoder.getSkipWritingZeroes()) { 396 return Sample_Index_D8888_SkipZ; 397 } 398 return Sample_Index_D8888; 399 } 400 401 static bool Sample_Index_D565(void* SK_RESTRICT dstRow, 402 const uint8_t* SK_RESTRICT src, 403 int width, int deltaSrc, int, const SkPMColor ctable[]) { 404 405 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; 406 for (int x = 0; x < width; x++) { 407 dst[x] = SkPixel32ToPixel16(ctable[*src]); 408 src += deltaSrc; 409 } 410 return false; 411 } 412 413 static bool Sample_Index_D565_D(void* SK_RESTRICT dstRow, 414 const uint8_t* SK_RESTRICT src, int width, 415 int deltaSrc, int y, const SkPMColor ctable[]) { 416 417 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; 418 DITHER_565_SCAN(y); 419 420 for (int x = 0; x < width; x++) { 421 SkPMColor c = ctable[*src]; 422 dst[x] = SkDitherRGBTo565(SkGetPackedR32(c), SkGetPackedG32(c), 423 SkGetPackedB32(c), DITHER_VALUE(x)); 424 src += deltaSrc; 425 } 426 return false; 427 } 428 429 static SkScaledBitmapSampler::RowProc get_index_to_565_proc(const SkImageDecoder& decoder) { 430 // Unpremultiplied and skip zeroes make no difference 431 if (decoder.getDitherImage()) { 432 return Sample_Index_D565_D; 433 } 434 return Sample_Index_D565; 435 } 436 437 static bool Sample_Index_D4444(void* SK_RESTRICT dstRow, 438 const uint8_t* SK_RESTRICT src, int width, 439 int deltaSrc, int y, const SkPMColor ctable[]) { 440 441 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 442 SkPMColor cc = A32_MASK_IN_PLACE; 443 for (int x = 0; x < width; x++) { 444 SkPMColor c = ctable[*src]; 445 cc &= c; 446 dst[x] = SkPixel32ToPixel4444(c); 447 src += deltaSrc; 448 } 449 return cc != A32_MASK_IN_PLACE; 450 } 451 452 static bool Sample_Index_D4444_D(void* SK_RESTRICT dstRow, 453 const uint8_t* SK_RESTRICT src, int width, 454 int deltaSrc, int y, const SkPMColor ctable[]) { 455 456 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 457 SkPMColor cc = A32_MASK_IN_PLACE; 458 DITHER_4444_SCAN(y); 459 460 for (int x = 0; x < width; x++) { 461 SkPMColor c = ctable[*src]; 462 cc &= c; 463 dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x)); 464 src += deltaSrc; 465 } 466 return cc != A32_MASK_IN_PLACE; 467 } 468 469 static bool Sample_Index_D4444_SkipZ(void* SK_RESTRICT dstRow, 470 const uint8_t* SK_RESTRICT src, int width, 471 int deltaSrc, int y, const SkPMColor ctable[]) { 472 473 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 474 SkPMColor cc = A32_MASK_IN_PLACE; 475 for (int x = 0; x < width; x++) { 476 SkPMColor c = ctable[*src]; 477 cc &= c; 478 if (c != 0) { 479 dst[x] = SkPixel32ToPixel4444(c); 480 } 481 src += deltaSrc; 482 } 483 return cc != A32_MASK_IN_PLACE; 484 } 485 486 static bool Sample_Index_D4444_D_SkipZ(void* SK_RESTRICT dstRow, 487 const uint8_t* SK_RESTRICT src, int width, 488 int deltaSrc, int y, const SkPMColor ctable[]) { 489 490 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 491 SkPMColor cc = A32_MASK_IN_PLACE; 492 DITHER_4444_SCAN(y); 493 494 for (int x = 0; x < width; x++) { 495 SkPMColor c = ctable[*src]; 496 cc &= c; 497 if (c != 0) { 498 dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x)); 499 } 500 src += deltaSrc; 501 } 502 return cc != A32_MASK_IN_PLACE; 503 } 504 505 static SkScaledBitmapSampler::RowProc get_index_to_4444_proc(const SkImageDecoder& decoder) { 506 // Unpremul not allowed 507 if (decoder.getRequireUnpremultipliedColors()) { 508 return NULL; 509 } 510 const bool dither = decoder.getDitherImage(); 511 if (decoder.getSkipWritingZeroes()) { 512 if (dither) { 513 return Sample_Index_D4444_D_SkipZ; 514 } 515 return Sample_Index_D4444_SkipZ; 516 } 517 if (dither) { 518 return Sample_Index_D4444_D; 519 } 520 return Sample_Index_D4444; 521 } 522 523 static bool Sample_Index_DI(void* SK_RESTRICT dstRow, 524 const uint8_t* SK_RESTRICT src, 525 int width, int deltaSrc, int, const SkPMColor[]) { 526 if (1 == deltaSrc) { 527 memcpy(dstRow, src, width); 528 } else { 529 uint8_t* SK_RESTRICT dst = (uint8_t*)dstRow; 530 for (int x = 0; x < width; x++) { 531 dst[x] = src[0]; 532 src += deltaSrc; 533 } 534 } 535 return false; 536 } 537 538 static SkScaledBitmapSampler::RowProc get_index_to_index_proc(const SkImageDecoder& decoder) { 539 // Unpremul not allowed 540 if (decoder.getRequireUnpremultipliedColors()) { 541 return NULL; 542 } 543 // Ignore dither and skip zeroes 544 return Sample_Index_DI; 545 } 546 547 // A8 548 static bool Sample_Gray_DA8(void* SK_RESTRICT dstRow, 549 const uint8_t* SK_RESTRICT src, 550 int width, int deltaSrc, int, 551 const SkPMColor[]) { 552 // Sampling Gray to A8 uses the same function as Index to Index8, 553 // except we assume that there is alpha for speed, since an A8 554 // bitmap with no alpha is not interesting. 555 (void) Sample_Index_DI(dstRow, src, width, deltaSrc, /* y unused */ 0, 556 /* ctable unused */ NULL); 557 return true; 558 } 559 560 static SkScaledBitmapSampler::RowProc get_gray_to_A8_proc(const SkImageDecoder& decoder) { 561 if (decoder.getRequireUnpremultipliedColors()) { 562 return NULL; 563 } 564 // Ignore skip and dither. 565 return Sample_Gray_DA8; 566 } 567 568 typedef SkScaledBitmapSampler::RowProc (*RowProcChooser)(const SkImageDecoder& decoder); 569 /////////////////////////////////////////////////////////////////////////////// 570 571 #include "SkScaledBitmapSampler.h" 572 573 SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height, 574 int sampleSize) { 575 fCTable = NULL; 576 fDstRow = NULL; 577 fRowProc = NULL; 578 579 if (width <= 0 || height <= 0) { 580 sk_throw(); 581 } 582 583 SkDEBUGCODE(fSampleMode = kUninitialized_SampleMode); 584 585 if (sampleSize <= 1) { 586 fScaledWidth = width; 587 fScaledHeight = height; 588 fX0 = fY0 = 0; 589 fDX = fDY = 1; 590 return; 591 } 592 593 int dx = SkMin32(sampleSize, width); 594 int dy = SkMin32(sampleSize, height); 595 596 fScaledWidth = width / dx; 597 fScaledHeight = height / dy; 598 599 SkASSERT(fScaledWidth > 0); 600 SkASSERT(fScaledHeight > 0); 601 602 fX0 = dx >> 1; 603 fY0 = dy >> 1; 604 605 SkASSERT(fX0 >= 0 && fX0 < width); 606 SkASSERT(fY0 >= 0 && fY0 < height); 607 608 fDX = dx; 609 fDY = dy; 610 611 SkASSERT(fDX > 0 && (fX0 + fDX * (fScaledWidth - 1)) < width); 612 SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height); 613 } 614 615 bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, 616 const SkImageDecoder& decoder, 617 const SkPMColor ctable[]) { 618 static const RowProcChooser gProcChoosers[] = { 619 get_gray_to_8888_proc, 620 get_RGBx_to_8888_proc, 621 get_RGBA_to_8888_proc, 622 get_index_to_8888_proc, 623 NULL, // 565 to 8888 624 625 get_gray_to_565_proc, 626 get_RGBx_to_565_proc, 627 get_RGBx_to_565_proc, // The source alpha will be ignored. 628 get_index_to_565_proc, 629 get_565_to_565_proc, 630 631 get_gray_to_4444_proc, 632 get_RGBx_to_4444_proc, 633 get_RGBA_to_4444_proc, 634 get_index_to_4444_proc, 635 NULL, // 565 to 4444 636 637 NULL, // gray to index 638 NULL, // rgbx to index 639 NULL, // rgba to index 640 get_index_to_index_proc, 641 NULL, // 565 to index 642 643 get_gray_to_A8_proc, 644 NULL, // rgbx to a8 645 NULL, // rgba to a8 646 NULL, // index to a8 647 NULL, // 565 to a8 648 }; 649 650 // The jump between dst configs in the table 651 static const int gProcDstConfigSpan = 5; 652 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gProcChoosers) == 5 * gProcDstConfigSpan, 653 gProcs_has_the_wrong_number_of_entries); 654 655 fCTable = ctable; 656 657 int index = 0; 658 switch (sc) { 659 case SkScaledBitmapSampler::kGray: 660 fSrcPixelSize = 1; 661 index += 0; 662 break; 663 case SkScaledBitmapSampler::kRGB: 664 fSrcPixelSize = 3; 665 index += 1; 666 break; 667 case SkScaledBitmapSampler::kRGBX: 668 fSrcPixelSize = 4; 669 index += 1; 670 break; 671 case SkScaledBitmapSampler::kRGBA: 672 fSrcPixelSize = 4; 673 index += 2; 674 break; 675 case SkScaledBitmapSampler::kIndex: 676 fSrcPixelSize = 1; 677 index += 3; 678 break; 679 case SkScaledBitmapSampler::kRGB_565: 680 fSrcPixelSize = 2; 681 index += 4; 682 break; 683 default: 684 return false; 685 } 686 687 switch (dst->config()) { 688 case SkBitmap::kARGB_8888_Config: 689 index += 0 * gProcDstConfigSpan; 690 break; 691 case SkBitmap::kRGB_565_Config: 692 index += 1 * gProcDstConfigSpan; 693 break; 694 case SkBitmap::kARGB_4444_Config: 695 index += 2 * gProcDstConfigSpan; 696 break; 697 case SkBitmap::kIndex8_Config: 698 index += 3 * gProcDstConfigSpan; 699 break; 700 case SkBitmap::kA8_Config: 701 index += 4 * gProcDstConfigSpan; 702 break; 703 default: 704 return false; 705 } 706 707 RowProcChooser chooser = gProcChoosers[index]; 708 if (NULL == chooser) { 709 fRowProc = NULL; 710 } else { 711 fRowProc = chooser(decoder); 712 } 713 fDstRow = (char*)dst->getPixels(); 714 fDstRowBytes = dst->rowBytes(); 715 fCurrY = 0; 716 return fRowProc != NULL; 717 } 718 719 bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) { 720 SkASSERT(kInterlaced_SampleMode != fSampleMode); 721 SkDEBUGCODE(fSampleMode = kConsecutive_SampleMode); 722 SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight); 723 724 bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth, 725 fDX * fSrcPixelSize, fCurrY, fCTable); 726 fDstRow += fDstRowBytes; 727 fCurrY += 1; 728 return hadAlpha; 729 } 730 731 bool SkScaledBitmapSampler::sampleInterlaced(const uint8_t* SK_RESTRICT src, int srcY) { 732 SkASSERT(kConsecutive_SampleMode != fSampleMode); 733 SkDEBUGCODE(fSampleMode = kInterlaced_SampleMode); 734 // Any line that should be a part of the destination can be created by the formula: 735 // fY0 + (some multiplier) * fDY 736 // so if srcY - fY0 is not an integer multiple of fDY that srcY will be skipped. 737 const int srcYMinusY0 = srcY - fY0; 738 if (srcYMinusY0 % fDY != 0) { 739 // This line is not part of the output, so return false for alpha, since we have 740 // not added an alpha to the output. 741 return false; 742 } 743 // Unlike in next(), where the data is used sequentially, this function skips around, 744 // so fDstRow and fCurrY are never updated. fDstRow must always be the starting point 745 // of the destination bitmap's pixels, which is used to calculate the destination row 746 // each time this function is called. 747 const int dstY = srcYMinusY0 / fDY; 748 SkASSERT(dstY < fScaledHeight); 749 char* dstRow = fDstRow + dstY * fDstRowBytes; 750 return fRowProc(dstRow, src + fX0 * fSrcPixelSize, fScaledWidth, 751 fDX * fSrcPixelSize, dstY, fCTable); 752 } 753 754 #ifdef SK_DEBUG 755 // The following code is for a test to ensure that changing the method to get the right row proc 756 // did not change the row proc unintentionally. Tested by ImageDecodingTest.cpp 757 758 // friend of SkScaledBitmapSampler solely for the purpose of accessing fRowProc. 759 class RowProcTester { 760 public: 761 static SkScaledBitmapSampler::RowProc getRowProc(const SkScaledBitmapSampler& sampler) { 762 return sampler.fRowProc; 763 } 764 }; 765 766 767 // Table showing the expected RowProc for each combination of inputs. 768 // Table formated as follows: 769 // Each group of 5 consecutive rows represents sampling from a single 770 // SkScaledBitmapSampler::SrcConfig. 771 // Within each set, each row represents a different destination SkBitmap::Config 772 // Each column represents a different combination of dither and unpremul. 773 // D = dither ~D = no dither 774 // U = unpremul ~U = no unpremul 775 // ~D~U D~U ~DU DU 776 SkScaledBitmapSampler::RowProc gTestProcs[] = { 777 // Gray 778 Sample_Gray_DA8, Sample_Gray_DA8, NULL, NULL, // to A8 779 NULL, NULL, NULL, NULL, // to Index8 780 Sample_Gray_D565, Sample_Gray_D565_D, Sample_Gray_D565, Sample_Gray_D565_D, // to 565 781 Sample_Gray_D4444, Sample_Gray_D4444_D, Sample_Gray_D4444, Sample_Gray_D4444_D, // to 4444 782 Sample_Gray_D8888, Sample_Gray_D8888, Sample_Gray_D8888, Sample_Gray_D8888, // to 8888 783 // Index 784 NULL, NULL, NULL, NULL, // to A8 785 Sample_Index_DI, Sample_Index_DI, NULL, NULL, // to Index8 786 Sample_Index_D565, Sample_Index_D565_D, Sample_Index_D565, Sample_Index_D565_D, // to 565 787 Sample_Index_D4444, Sample_Index_D4444_D, NULL, NULL, // to 4444 788 Sample_Index_D8888, Sample_Index_D8888, NULL, NULL, // to 8888 789 // RGB 790 NULL, NULL, NULL, NULL, // to A8 791 NULL, NULL, NULL, NULL, // to Index8 792 Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565 793 Sample_RGBx_D4444, Sample_RGBx_D4444_D, Sample_RGBx_D4444, Sample_RGBx_D4444_D, // to 4444 794 Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, // to 8888 795 // RGBx is the same as RGB 796 NULL, NULL, NULL, NULL, // to A8 797 NULL, NULL, NULL, NULL, // to Index8 798 Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565 799 Sample_RGBx_D4444, Sample_RGBx_D4444_D, Sample_RGBx_D4444, Sample_RGBx_D4444_D, // to 4444 800 Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, // to 8888 801 // RGBA 802 NULL, NULL, NULL, NULL, // to A8 803 NULL, NULL, NULL, NULL, // to Index8 804 Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565 805 Sample_RGBA_D4444, Sample_RGBA_D4444_D, NULL, NULL, // to 4444 806 Sample_RGBA_D8888, Sample_RGBA_D8888, Sample_RGBA_D8888_Unpremul, Sample_RGBA_D8888_Unpremul, // to 8888 807 // RGB_565 808 NULL, NULL, NULL, NULL, // to A8 809 NULL, NULL, NULL, NULL, // to Index8 810 Sample_D565_D565, Sample_D565_D565, Sample_D565_D565, Sample_D565_D565, // to 565 811 NULL, NULL, NULL, NULL, // to 4444 812 NULL, NULL, NULL, NULL, // to 8888 813 }; 814 815 // Dummy class that allows instantiation of an ImageDecoder, so begin can query its fields. 816 class DummyDecoder : public SkImageDecoder { 817 public: 818 DummyDecoder() {} 819 protected: 820 virtual bool onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) SK_OVERRIDE { 821 return false; 822 } 823 }; 824 825 void test_row_proc_choice(); 826 void test_row_proc_choice() { 827 SkBitmap dummyBitmap; 828 DummyDecoder dummyDecoder; 829 size_t procCounter = 0; 830 for (int sc = SkScaledBitmapSampler::kGray; sc <= SkScaledBitmapSampler::kRGB_565; ++sc) { 831 for (int c = SkBitmap::kA8_Config; c <= SkBitmap::kARGB_8888_Config; ++c) { 832 for (int unpremul = 0; unpremul <= 1; ++unpremul) { 833 for (int dither = 0; dither <= 1; ++dither) { 834 // Arbitrary width/height/sampleSize to allow SkScaledBitmapSampler to 835 // be considered valid. 836 SkScaledBitmapSampler sampler(10, 10, 1); 837 dummyBitmap.setConfig((SkBitmap::Config) c, 10, 10); 838 dummyDecoder.setDitherImage(SkToBool(dither)); 839 dummyDecoder.setRequireUnpremultipliedColors(SkToBool(unpremul)); 840 sampler.begin(&dummyBitmap, (SkScaledBitmapSampler::SrcConfig) sc, 841 dummyDecoder); 842 SkScaledBitmapSampler::RowProc expected = gTestProcs[procCounter]; 843 SkScaledBitmapSampler::RowProc actual = RowProcTester::getRowProc(sampler); 844 SkASSERT(expected == actual); 845 procCounter++; 846 } 847 } 848 } 849 } 850 SkASSERT(SK_ARRAY_COUNT(gTestProcs) == procCounter); 851 } 852 #endif // SK_DEBUG 853