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