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 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 
    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     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 
    410 static 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 
    422 static 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 
    438 static SkScaledBitmapSampler::RowProc
    439 get_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 
    447 static 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 
    462 static 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 
    479 static 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 
    496 static 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 
    515 static SkScaledBitmapSampler::RowProc
    516 get_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 
    533 static 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 
    548 static SkScaledBitmapSampler::RowProc
    549 get_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
    559 static 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 
    571 static SkScaledBitmapSampler::RowProc
    572 get_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 
    580 typedef SkScaledBitmapSampler::RowProc (*RowProcChooser)(const SkScaledBitmapSampler::Options&);
    581 ///////////////////////////////////////////////////////////////////////////////
    582 
    583 #include "SkScaledBitmapSampler.h"
    584 
    585 SkScaledBitmapSampler::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 
    627 bool 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 
    731 bool 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 
    737 bool 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 
    749 bool 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.
    777 class RowProcTester {
    778 public:
    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
    794 SkScaledBitmapSampler::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.
    834 class DummyDecoder : public SkImageDecoder {
    835 public:
    836     DummyDecoder() {}
    837 protected:
    838     virtual bool onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) SK_OVERRIDE {
    839         return false;
    840     }
    841 };
    842 
    843 void test_row_proc_choice();
    844 void 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