Home | History | Annotate | Download | only in images
      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