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