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 17static 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 28static SkScaledBitmapSampler::RowProc 29get_gray_to_8888_proc(const SkScaledBitmapSampler::Options& opts) { 30 // Dither, unpremul, and skipZeroes have no effect 31 return Sample_Gray_D8888; 32} 33 34static 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 45static SkScaledBitmapSampler::RowProc 46get_RGBx_to_8888_proc(const SkScaledBitmapSampler::Options& opts) { 47 // Dither, unpremul, and skipZeroes have no effect 48 return Sample_RGBx_D8888; 49} 50 51static 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 65static 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 80static 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 97static SkScaledBitmapSampler::RowProc 98get_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 114static 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 125static 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 137static SkScaledBitmapSampler::RowProc 138get_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 146static 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 157static 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 170static SkScaledBitmapSampler::RowProc 171get_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 180static 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 192static SkScaledBitmapSampler::RowProc 193get_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 200static 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 212static 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 225static SkScaledBitmapSampler::RowProc 226get_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 234static 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 245static 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 259static SkScaledBitmapSampler::RowProc 260get_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 268static 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 284static 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 304static 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 322static 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 342static SkScaledBitmapSampler::RowProc 343get_RGBA_to_4444_proc(const SkScaledBitmapSampler::Options& opts) { 344 if (!opts.fPremultiplyAlpha) { 345 // Unpremultiplied is not supported for 4444 346 return NULL; 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 364static 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 379static 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 397static SkScaledBitmapSampler::RowProc 398get_index_to_8888_proc(const SkScaledBitmapSampler::Options& opts) { 399 if (!opts.fPremultiplyAlpha) { 400 // Unpremultiplied is not supported for an index source. 401 return NULL; 402 } 403 // Dither makes no difference 404 if (opts.fSkipZeros) { 405 return Sample_Index_D8888_SkipZ; 406 } 407 return Sample_Index_D8888; 408} 409 410static bool Sample_Index_D565(void* SK_RESTRICT dstRow, 411 const uint8_t* SK_RESTRICT src, 412 int width, int deltaSrc, int, const SkPMColor ctable[]) { 413 414 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; 415 for (int x = 0; x < width; x++) { 416 dst[x] = SkPixel32ToPixel16(ctable[*src]); 417 src += deltaSrc; 418 } 419 return false; 420} 421 422static bool Sample_Index_D565_D(void* SK_RESTRICT dstRow, 423 const uint8_t* SK_RESTRICT src, int width, 424 int deltaSrc, int y, const SkPMColor ctable[]) { 425 426 uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; 427 DITHER_565_SCAN(y); 428 429 for (int x = 0; x < width; x++) { 430 SkPMColor c = ctable[*src]; 431 dst[x] = SkDitherRGBTo565(SkGetPackedR32(c), SkGetPackedG32(c), 432 SkGetPackedB32(c), DITHER_VALUE(x)); 433 src += deltaSrc; 434 } 435 return false; 436} 437 438static SkScaledBitmapSampler::RowProc 439get_index_to_565_proc(const SkScaledBitmapSampler::Options& opts) { 440 // Unpremultiplied and skip zeroes make no difference 441 if (opts.fDither) { 442 return Sample_Index_D565_D; 443 } 444 return Sample_Index_D565; 445} 446 447static bool Sample_Index_D4444(void* SK_RESTRICT dstRow, 448 const uint8_t* SK_RESTRICT src, int width, 449 int deltaSrc, int y, const SkPMColor ctable[]) { 450 451 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 452 SkPMColor cc = A32_MASK_IN_PLACE; 453 for (int x = 0; x < width; x++) { 454 SkPMColor c = ctable[*src]; 455 cc &= c; 456 dst[x] = SkPixel32ToPixel4444(c); 457 src += deltaSrc; 458 } 459 return cc != A32_MASK_IN_PLACE; 460} 461 462static bool Sample_Index_D4444_D(void* SK_RESTRICT dstRow, 463 const uint8_t* SK_RESTRICT src, int width, 464 int deltaSrc, int y, const SkPMColor ctable[]) { 465 466 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 467 SkPMColor cc = A32_MASK_IN_PLACE; 468 DITHER_4444_SCAN(y); 469 470 for (int x = 0; x < width; x++) { 471 SkPMColor c = ctable[*src]; 472 cc &= c; 473 dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x)); 474 src += deltaSrc; 475 } 476 return cc != A32_MASK_IN_PLACE; 477} 478 479static bool Sample_Index_D4444_SkipZ(void* SK_RESTRICT dstRow, 480 const uint8_t* SK_RESTRICT src, int width, 481 int deltaSrc, int y, const SkPMColor ctable[]) { 482 483 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 484 SkPMColor cc = A32_MASK_IN_PLACE; 485 for (int x = 0; x < width; x++) { 486 SkPMColor c = ctable[*src]; 487 cc &= c; 488 if (c != 0) { 489 dst[x] = SkPixel32ToPixel4444(c); 490 } 491 src += deltaSrc; 492 } 493 return cc != A32_MASK_IN_PLACE; 494} 495 496static bool Sample_Index_D4444_D_SkipZ(void* SK_RESTRICT dstRow, 497 const uint8_t* SK_RESTRICT src, int width, 498 int deltaSrc, int y, const SkPMColor ctable[]) { 499 500 SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow; 501 SkPMColor cc = A32_MASK_IN_PLACE; 502 DITHER_4444_SCAN(y); 503 504 for (int x = 0; x < width; x++) { 505 SkPMColor c = ctable[*src]; 506 cc &= c; 507 if (c != 0) { 508 dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x)); 509 } 510 src += deltaSrc; 511 } 512 return cc != A32_MASK_IN_PLACE; 513} 514 515static SkScaledBitmapSampler::RowProc 516get_index_to_4444_proc(const SkScaledBitmapSampler::Options& opts) { 517 // Unpremul not allowed 518 if (!opts.fPremultiplyAlpha) { 519 return NULL; 520 } 521 if (opts.fSkipZeros) { 522 if (opts.fDither) { 523 return Sample_Index_D4444_D_SkipZ; 524 } 525 return Sample_Index_D4444_SkipZ; 526 } 527 if (opts.fDither) { 528 return Sample_Index_D4444_D; 529 } 530 return Sample_Index_D4444; 531} 532 533static bool Sample_Index_DI(void* SK_RESTRICT dstRow, 534 const uint8_t* SK_RESTRICT src, 535 int width, int deltaSrc, int, const SkPMColor[]) { 536 if (1 == deltaSrc) { 537 memcpy(dstRow, src, width); 538 } else { 539 uint8_t* SK_RESTRICT dst = (uint8_t*)dstRow; 540 for (int x = 0; x < width; x++) { 541 dst[x] = src[0]; 542 src += deltaSrc; 543 } 544 } 545 return false; 546} 547 548static SkScaledBitmapSampler::RowProc 549get_index_to_index_proc(const SkScaledBitmapSampler::Options& opts) { 550 // Unpremul not allowed 551 if (!opts.fPremultiplyAlpha) { 552 return NULL; 553 } 554 // Ignore dither and skip zeroes 555 return Sample_Index_DI; 556} 557 558// A8 559static bool Sample_Gray_DA8(void* SK_RESTRICT dstRow, 560 const uint8_t* SK_RESTRICT src, 561 int width, int deltaSrc, int, 562 const SkPMColor[]) { 563 // Sampling Gray to A8 uses the same function as Index to Index8, 564 // except we assume that there is alpha for speed, since an A8 565 // bitmap with no alpha is not interesting. 566 (void) Sample_Index_DI(dstRow, src, width, deltaSrc, /* y unused */ 0, 567 /* ctable unused */ NULL); 568 return true; 569} 570 571static SkScaledBitmapSampler::RowProc 572get_gray_to_A8_proc(const SkScaledBitmapSampler::Options& opts) { 573 if (!opts.fPremultiplyAlpha) { 574 return NULL; 575 } 576 // Ignore skip and dither. 577 return Sample_Gray_DA8; 578} 579 580typedef SkScaledBitmapSampler::RowProc (*RowProcChooser)(const SkScaledBitmapSampler::Options&); 581/////////////////////////////////////////////////////////////////////////////// 582 583#include "SkScaledBitmapSampler.h" 584 585SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height, 586 int sampleSize) { 587 fCTable = NULL; 588 fDstRow = NULL; 589 fRowProc = NULL; 590 591 if (width <= 0 || height <= 0) { 592 sk_throw(); 593 } 594 595 SkDEBUGCODE(fSampleMode = kUninitialized_SampleMode); 596 597 if (sampleSize <= 1) { 598 fScaledWidth = width; 599 fScaledHeight = height; 600 fX0 = fY0 = 0; 601 fDX = fDY = 1; 602 return; 603 } 604 605 int dx = SkMin32(sampleSize, width); 606 int dy = SkMin32(sampleSize, height); 607 608 fScaledWidth = width / dx; 609 fScaledHeight = height / dy; 610 611 SkASSERT(fScaledWidth > 0); 612 SkASSERT(fScaledHeight > 0); 613 614 fX0 = dx >> 1; 615 fY0 = dy >> 1; 616 617 SkASSERT(fX0 >= 0 && fX0 < width); 618 SkASSERT(fY0 >= 0 && fY0 < height); 619 620 fDX = dx; 621 fDY = dy; 622 623 SkASSERT(fDX > 0 && (fX0 + fDX * (fScaledWidth - 1)) < width); 624 SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height); 625} 626 627bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, 628 const Options& opts, 629 const SkPMColor ctable[]) { 630 static const RowProcChooser gProcChoosers[] = { 631 get_gray_to_8888_proc, 632 get_RGBx_to_8888_proc, 633 get_RGBA_to_8888_proc, 634 get_index_to_8888_proc, 635 NULL, // 565 to 8888 636 637 get_gray_to_565_proc, 638 get_RGBx_to_565_proc, 639 get_RGBx_to_565_proc, // The source alpha will be ignored. 640 get_index_to_565_proc, 641 get_565_to_565_proc, 642 643 get_gray_to_4444_proc, 644 get_RGBx_to_4444_proc, 645 get_RGBA_to_4444_proc, 646 get_index_to_4444_proc, 647 NULL, // 565 to 4444 648 649 NULL, // gray to index 650 NULL, // rgbx to index 651 NULL, // rgba to index 652 get_index_to_index_proc, 653 NULL, // 565 to index 654 655 get_gray_to_A8_proc, 656 NULL, // rgbx to a8 657 NULL, // rgba to a8 658 NULL, // index to a8 659 NULL, // 565 to a8 660 }; 661 662 // The jump between dst configs in the table 663 static const int gProcDstConfigSpan = 5; 664 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gProcChoosers) == 5 * gProcDstConfigSpan, 665 gProcs_has_the_wrong_number_of_entries); 666 667 fCTable = ctable; 668 669 int index = 0; 670 switch (sc) { 671 case SkScaledBitmapSampler::kGray: 672 fSrcPixelSize = 1; 673 index += 0; 674 break; 675 case SkScaledBitmapSampler::kRGB: 676 fSrcPixelSize = 3; 677 index += 1; 678 break; 679 case SkScaledBitmapSampler::kRGBX: 680 fSrcPixelSize = 4; 681 index += 1; 682 break; 683 case SkScaledBitmapSampler::kRGBA: 684 fSrcPixelSize = 4; 685 index += 2; 686 break; 687 case SkScaledBitmapSampler::kIndex: 688 fSrcPixelSize = 1; 689 index += 3; 690 break; 691 case SkScaledBitmapSampler::kRGB_565: 692 fSrcPixelSize = 2; 693 index += 4; 694 break; 695 default: 696 return false; 697 } 698 699 switch (dst->colorType()) { 700 case kN32_SkColorType: 701 index += 0 * gProcDstConfigSpan; 702 break; 703 case kRGB_565_SkColorType: 704 index += 1 * gProcDstConfigSpan; 705 break; 706 case kARGB_4444_SkColorType: 707 index += 2 * gProcDstConfigSpan; 708 break; 709 case kIndex_8_SkColorType: 710 index += 3 * gProcDstConfigSpan; 711 break; 712 case kAlpha_8_SkColorType: 713 index += 4 * gProcDstConfigSpan; 714 break; 715 default: 716 return false; 717 } 718 719 RowProcChooser chooser = gProcChoosers[index]; 720 if (NULL == chooser) { 721 fRowProc = NULL; 722 } else { 723 fRowProc = chooser(opts); 724 } 725 fDstRow = (char*)dst->getPixels(); 726 fDstRowBytes = dst->rowBytes(); 727 fCurrY = 0; 728 return fRowProc != NULL; 729} 730 731bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc, 732 const SkImageDecoder& decoder, 733 const SkPMColor ctable[]) { 734 return this->begin(dst, sc, Options(decoder), ctable); 735} 736 737bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) { 738 SkASSERT(kInterlaced_SampleMode != fSampleMode); 739 SkDEBUGCODE(fSampleMode = kConsecutive_SampleMode); 740 SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight); 741 742 bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth, 743 fDX * fSrcPixelSize, fCurrY, fCTable); 744 fDstRow += fDstRowBytes; 745 fCurrY += 1; 746 return hadAlpha; 747} 748 749bool SkScaledBitmapSampler::sampleInterlaced(const uint8_t* SK_RESTRICT src, int srcY) { 750 SkASSERT(kConsecutive_SampleMode != fSampleMode); 751 SkDEBUGCODE(fSampleMode = kInterlaced_SampleMode); 752 // Any line that should be a part of the destination can be created by the formula: 753 // fY0 + (some multiplier) * fDY 754 // so if srcY - fY0 is not an integer multiple of fDY that srcY will be skipped. 755 const int srcYMinusY0 = srcY - fY0; 756 if (srcYMinusY0 % fDY != 0) { 757 // This line is not part of the output, so return false for alpha, since we have 758 // not added an alpha to the output. 759 return false; 760 } 761 // Unlike in next(), where the data is used sequentially, this function skips around, 762 // so fDstRow and fCurrY are never updated. fDstRow must always be the starting point 763 // of the destination bitmap's pixels, which is used to calculate the destination row 764 // each time this function is called. 765 const int dstY = srcYMinusY0 / fDY; 766 SkASSERT(dstY < fScaledHeight); 767 char* dstRow = fDstRow + dstY * fDstRowBytes; 768 return fRowProc(dstRow, src + fX0 * fSrcPixelSize, fScaledWidth, 769 fDX * fSrcPixelSize, dstY, fCTable); 770} 771 772#ifdef SK_DEBUG 773// The following code is for a test to ensure that changing the method to get the right row proc 774// did not change the row proc unintentionally. Tested by ImageDecodingTest.cpp 775 776// friend of SkScaledBitmapSampler solely for the purpose of accessing fRowProc. 777class RowProcTester { 778public: 779 static SkScaledBitmapSampler::RowProc getRowProc(const SkScaledBitmapSampler& sampler) { 780 return sampler.fRowProc; 781 } 782}; 783 784 785// Table showing the expected RowProc for each combination of inputs. 786// Table formated as follows: 787// Each group of 5 consecutive rows represents sampling from a single 788// SkScaledBitmapSampler::SrcConfig. 789// Within each set, each row represents a different destination SkBitmap::Config 790// Each column represents a different combination of dither and unpremul. 791// D = dither ~D = no dither 792// U = unpremul ~U = no unpremul 793// ~D~U D~U ~DU DU 794SkScaledBitmapSampler::RowProc gTestProcs[] = { 795 // Gray 796 Sample_Gray_DA8, Sample_Gray_DA8, NULL, NULL, // to A8 797 NULL, NULL, NULL, NULL, // to Index8 798 Sample_Gray_D565, Sample_Gray_D565_D, Sample_Gray_D565, Sample_Gray_D565_D, // to 565 799 Sample_Gray_D4444, Sample_Gray_D4444_D, Sample_Gray_D4444, Sample_Gray_D4444_D, // to 4444 800 Sample_Gray_D8888, Sample_Gray_D8888, Sample_Gray_D8888, Sample_Gray_D8888, // to 8888 801 // Index 802 NULL, NULL, NULL, NULL, // to A8 803 Sample_Index_DI, Sample_Index_DI, NULL, NULL, // to Index8 804 Sample_Index_D565, Sample_Index_D565_D, Sample_Index_D565, Sample_Index_D565_D, // to 565 805 Sample_Index_D4444, Sample_Index_D4444_D, NULL, NULL, // to 4444 806 Sample_Index_D8888, Sample_Index_D8888, NULL, NULL, // to 8888 807 // RGB 808 NULL, NULL, NULL, NULL, // to A8 809 NULL, NULL, NULL, NULL, // to Index8 810 Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565 811 Sample_RGBx_D4444, Sample_RGBx_D4444_D, Sample_RGBx_D4444, Sample_RGBx_D4444_D, // to 4444 812 Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, // to 8888 813 // RGBx is the same as RGB 814 NULL, NULL, NULL, NULL, // to A8 815 NULL, NULL, NULL, NULL, // to Index8 816 Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565 817 Sample_RGBx_D4444, Sample_RGBx_D4444_D, Sample_RGBx_D4444, Sample_RGBx_D4444_D, // to 4444 818 Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, // to 8888 819 // RGBA 820 NULL, NULL, NULL, NULL, // to A8 821 NULL, NULL, NULL, NULL, // to Index8 822 Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565 823 Sample_RGBA_D4444, Sample_RGBA_D4444_D, NULL, NULL, // to 4444 824 Sample_RGBA_D8888, Sample_RGBA_D8888, Sample_RGBA_D8888_Unpremul, Sample_RGBA_D8888_Unpremul, // to 8888 825 // RGB_565 826 NULL, NULL, NULL, NULL, // to A8 827 NULL, NULL, NULL, NULL, // to Index8 828 Sample_D565_D565, Sample_D565_D565, Sample_D565_D565, Sample_D565_D565, // to 565 829 NULL, NULL, NULL, NULL, // to 4444 830 NULL, NULL, NULL, NULL, // to 8888 831}; 832 833// Dummy class that allows instantiation of an ImageDecoder, so begin can query its fields. 834class DummyDecoder : public SkImageDecoder { 835public: 836 DummyDecoder() {} 837protected: 838 virtual bool onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) SK_OVERRIDE { 839 return false; 840 } 841}; 842 843void test_row_proc_choice(); 844void test_row_proc_choice() { 845 const SkColorType colorTypes[] = { 846 kAlpha_8_SkColorType, kIndex_8_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType, 847 kN32_SkColorType 848 }; 849 850 SkBitmap dummyBitmap; 851 DummyDecoder dummyDecoder; 852 size_t procCounter = 0; 853 for (int sc = SkScaledBitmapSampler::kGray; sc <= SkScaledBitmapSampler::kRGB_565; ++sc) { 854 for (size_t c = 0; c < SK_ARRAY_COUNT(colorTypes); ++c) { 855 for (int unpremul = 0; unpremul <= 1; ++unpremul) { 856 for (int dither = 0; dither <= 1; ++dither) { 857 // Arbitrary width/height/sampleSize to allow SkScaledBitmapSampler to 858 // be considered valid. 859 SkScaledBitmapSampler sampler(10, 10, 1); 860 dummyBitmap.setInfo(SkImageInfo::Make(10, 10, 861 colorTypes[c], kPremul_SkAlphaType)); 862 dummyDecoder.setDitherImage(SkToBool(dither)); 863 dummyDecoder.setRequireUnpremultipliedColors(SkToBool(unpremul)); 864 sampler.begin(&dummyBitmap, (SkScaledBitmapSampler::SrcConfig) sc, 865 dummyDecoder); 866 SkScaledBitmapSampler::RowProc expected = gTestProcs[procCounter]; 867 SkScaledBitmapSampler::RowProc actual = RowProcTester::getRowProc(sampler); 868 SkASSERT(expected == actual); 869 procCounter++; 870 } 871 } 872 } 873 } 874 SkASSERT(SK_ARRAY_COUNT(gTestProcs) == procCounter); 875} 876#endif // SK_DEBUG 877