gfx/skia/trunk/src/images/SkScaledBitmapSampler.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/images/SkScaledBitmapSampler.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,852 @@
     1.4 +/*
     1.5 + * Copyright 2007 The Android Open Source Project
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +
    1.11 +
    1.12 +#include "SkScaledBitmapSampler.h"
    1.13 +#include "SkBitmap.h"
    1.14 +#include "SkColorPriv.h"
    1.15 +#include "SkDither.h"
    1.16 +#include "SkTypes.h"
    1.17 +
    1.18 +// 8888
    1.19 +
    1.20 +static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow,
    1.21 +                              const uint8_t* SK_RESTRICT src,
    1.22 +                              int width, int deltaSrc, int, const SkPMColor[]) {
    1.23 +    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
    1.24 +    for (int x = 0; x < width; x++) {
    1.25 +        dst[x] = SkPackARGB32(0xFF, src[0], src[0], src[0]);
    1.26 +        src += deltaSrc;
    1.27 +    }
    1.28 +    return false;
    1.29 +}
    1.30 +
    1.31 +static SkScaledBitmapSampler::RowProc get_gray_to_8888_proc(const SkImageDecoder& decoder) {
    1.32 +    // Dither, unpremul, and skipZeroes have no effect
    1.33 +    return Sample_Gray_D8888;
    1.34 +}
    1.35 +
    1.36 +static bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow,
    1.37 +                              const uint8_t* SK_RESTRICT src,
    1.38 +                              int width, int deltaSrc, int, const SkPMColor[]) {
    1.39 +    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
    1.40 +    for (int x = 0; x < width; x++) {
    1.41 +        dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]);
    1.42 +        src += deltaSrc;
    1.43 +    }
    1.44 +    return false;
    1.45 +}
    1.46 +
    1.47 +static SkScaledBitmapSampler::RowProc get_RGBx_to_8888_proc(const SkImageDecoder& decoder) {
    1.48 +    // Dither, unpremul, and skipZeroes have no effect
    1.49 +    return Sample_RGBx_D8888;
    1.50 +}
    1.51 +
    1.52 +static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow,
    1.53 +                              const uint8_t* SK_RESTRICT src,
    1.54 +                              int width, int deltaSrc, int, const SkPMColor[]) {
    1.55 +    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
    1.56 +    unsigned alphaMask = 0xFF;
    1.57 +    for (int x = 0; x < width; x++) {
    1.58 +        unsigned alpha = src[3];
    1.59 +        dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
    1.60 +        src += deltaSrc;
    1.61 +        alphaMask &= alpha;
    1.62 +    }
    1.63 +    return alphaMask != 0xFF;
    1.64 +}
    1.65 +
    1.66 +static bool Sample_RGBA_D8888_Unpremul(void* SK_RESTRICT dstRow,
    1.67 +                                       const uint8_t* SK_RESTRICT src,
    1.68 +                                       int width, int deltaSrc, int,
    1.69 +                                       const SkPMColor[]) {
    1.70 +    uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow);
    1.71 +    unsigned alphaMask = 0xFF;
    1.72 +    for (int x = 0; x < width; x++) {
    1.73 +        unsigned alpha = src[3];
    1.74 +        dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
    1.75 +        src += deltaSrc;
    1.76 +        alphaMask &= alpha;
    1.77 +    }
    1.78 +    return alphaMask != 0xFF;
    1.79 +}
    1.80 +
    1.81 +static bool Sample_RGBA_D8888_SkipZ(void* SK_RESTRICT dstRow,
    1.82 +                                    const uint8_t* SK_RESTRICT src,
    1.83 +                                    int width, int deltaSrc, int,
    1.84 +                                    const SkPMColor[]) {
    1.85 +    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
    1.86 +    unsigned alphaMask = 0xFF;
    1.87 +    for (int x = 0; x < width; x++) {
    1.88 +        unsigned alpha = src[3];
    1.89 +        if (0 != alpha) {
    1.90 +            dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
    1.91 +        }
    1.92 +        src += deltaSrc;
    1.93 +        alphaMask &= alpha;
    1.94 +    }
    1.95 +    return alphaMask != 0xFF;
    1.96 +}
    1.97 +
    1.98 +static SkScaledBitmapSampler::RowProc get_RGBA_to_8888_proc(const SkImageDecoder& decoder) {
    1.99 +    // Dither has no effect.
   1.100 +    if (decoder.getRequireUnpremultipliedColors()) {
   1.101 +        // We could check each component for a zero, at the expense of extra checks.
   1.102 +        // For now, just return unpremul.
   1.103 +        return Sample_RGBA_D8888_Unpremul;
   1.104 +    }
   1.105 +    // Supply the versions that premultiply the colors
   1.106 +    if (decoder.getSkipWritingZeroes()) {
   1.107 +        return Sample_RGBA_D8888_SkipZ;
   1.108 +    }
   1.109 +    return Sample_RGBA_D8888;
   1.110 +}
   1.111 +
   1.112 +// 565
   1.113 +
   1.114 +static bool Sample_Gray_D565(void* SK_RESTRICT dstRow,
   1.115 +                             const uint8_t* SK_RESTRICT src,
   1.116 +                             int width, int deltaSrc, int, const SkPMColor[]) {
   1.117 +    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
   1.118 +    for (int x = 0; x < width; x++) {
   1.119 +        dst[x] = SkPack888ToRGB16(src[0], src[0], src[0]);
   1.120 +        src += deltaSrc;
   1.121 +    }
   1.122 +    return false;
   1.123 +}
   1.124 +
   1.125 +static bool Sample_Gray_D565_D(void* SK_RESTRICT dstRow,
   1.126 +                               const uint8_t* SK_RESTRICT src,
   1.127 +                           int width, int deltaSrc, int y, const SkPMColor[]) {
   1.128 +    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
   1.129 +    DITHER_565_SCAN(y);
   1.130 +    for (int x = 0; x < width; x++) {
   1.131 +        dst[x] = SkDitherRGBTo565(src[0], src[0], src[0], DITHER_VALUE(x));
   1.132 +        src += deltaSrc;
   1.133 +    }
   1.134 +    return false;
   1.135 +}
   1.136 +
   1.137 +static SkScaledBitmapSampler::RowProc get_gray_to_565_proc(const SkImageDecoder& decoder) {
   1.138 +    // Unpremul and skip zeroes make no difference
   1.139 +    if (decoder.getDitherImage()) {
   1.140 +        return Sample_Gray_D565_D;
   1.141 +    }
   1.142 +    return Sample_Gray_D565;
   1.143 +}
   1.144 +
   1.145 +static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow,
   1.146 +                             const uint8_t* SK_RESTRICT src,
   1.147 +                             int width, int deltaSrc, int, const SkPMColor[]) {
   1.148 +    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
   1.149 +    for (int x = 0; x < width; x++) {
   1.150 +        dst[x] = SkPack888ToRGB16(src[0], src[1], src[2]);
   1.151 +        src += deltaSrc;
   1.152 +    }
   1.153 +    return false;
   1.154 +}
   1.155 +
   1.156 +static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
   1.157 +                               const uint8_t* SK_RESTRICT src,
   1.158 +                               int width, int deltaSrc, int y,
   1.159 +                               const SkPMColor[]) {
   1.160 +    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
   1.161 +    DITHER_565_SCAN(y);
   1.162 +    for (int x = 0; x < width; x++) {
   1.163 +        dst[x] = SkDitherRGBTo565(src[0], src[1], src[2], DITHER_VALUE(x));
   1.164 +        src += deltaSrc;
   1.165 +    }
   1.166 +    return false;
   1.167 +}
   1.168 +
   1.169 +static SkScaledBitmapSampler::RowProc get_RGBx_to_565_proc(const SkImageDecoder& decoder) {
   1.170 +    // Unpremul and skip zeroes make no difference
   1.171 +    if (decoder.getDitherImage()) {
   1.172 +        return Sample_RGBx_D565_D;
   1.173 +    }
   1.174 +    return Sample_RGBx_D565;
   1.175 +}
   1.176 +
   1.177 +
   1.178 +static bool Sample_D565_D565(void* SK_RESTRICT dstRow,
   1.179 +                             const uint8_t* SK_RESTRICT src,
   1.180 +                             int width, int deltaSrc, int, const SkPMColor[]) {
   1.181 +    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
   1.182 +    uint16_t* SK_RESTRICT castedSrc = (uint16_t*) src;
   1.183 +    for (int x = 0; x < width; x++) {
   1.184 +        dst[x] = castedSrc[0];
   1.185 +        castedSrc += deltaSrc >> 1;
   1.186 +    }
   1.187 +    return false;
   1.188 +}
   1.189 +
   1.190 +static SkScaledBitmapSampler::RowProc get_565_to_565_proc(const SkImageDecoder& decoder) {
   1.191 +    // Unpremul, dither, and skip zeroes have no effect
   1.192 +    return Sample_D565_D565;
   1.193 +}
   1.194 +
   1.195 +// 4444
   1.196 +
   1.197 +static bool Sample_Gray_D4444(void* SK_RESTRICT dstRow,
   1.198 +                              const uint8_t* SK_RESTRICT src,
   1.199 +                              int width, int deltaSrc, int, const SkPMColor[]) {
   1.200 +    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
   1.201 +    for (int x = 0; x < width; x++) {
   1.202 +        unsigned gray = src[0] >> 4;
   1.203 +        dst[x] = SkPackARGB4444(0xF, gray, gray, gray);
   1.204 +        src += deltaSrc;
   1.205 +    }
   1.206 +    return false;
   1.207 +}
   1.208 +
   1.209 +static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow,
   1.210 +                                const uint8_t* SK_RESTRICT src,
   1.211 +                            int width, int deltaSrc, int y, const SkPMColor[]) {
   1.212 +    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
   1.213 +    DITHER_4444_SCAN(y);
   1.214 +    for (int x = 0; x < width; x++) {
   1.215 +        dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[0], src[0],
   1.216 +                                      DITHER_VALUE(x));
   1.217 +        src += deltaSrc;
   1.218 +    }
   1.219 +    return false;
   1.220 +}
   1.221 +
   1.222 +static SkScaledBitmapSampler::RowProc get_gray_to_4444_proc(const SkImageDecoder& decoder) {
   1.223 +    // Skip zeroes and unpremul make no difference
   1.224 +    if (decoder.getDitherImage()) {
   1.225 +        return Sample_Gray_D4444_D;
   1.226 +    }
   1.227 +    return Sample_Gray_D4444;
   1.228 +}
   1.229 +
   1.230 +static bool Sample_RGBx_D4444(void* SK_RESTRICT dstRow,
   1.231 +                              const uint8_t* SK_RESTRICT src,
   1.232 +                              int width, int deltaSrc, int, const SkPMColor[]) {
   1.233 +    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
   1.234 +    for (int x = 0; x < width; x++) {
   1.235 +        dst[x] = SkPackARGB4444(0xF, src[0] >> 4, src[1] >> 4, src[2] >> 4);
   1.236 +        src += deltaSrc;
   1.237 +    }
   1.238 +    return false;
   1.239 +}
   1.240 +
   1.241 +static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow,
   1.242 +                                const uint8_t* SK_RESTRICT src,
   1.243 +                            int width, int deltaSrc, int y, const SkPMColor[]) {
   1.244 +    SkPMColor16* dst = (SkPMColor16*)dstRow;
   1.245 +    DITHER_4444_SCAN(y);
   1.246 +
   1.247 +    for (int x = 0; x < width; x++) {
   1.248 +        dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[1], src[2],
   1.249 +                                      DITHER_VALUE(x));
   1.250 +        src += deltaSrc;
   1.251 +    }
   1.252 +    return false;
   1.253 +}
   1.254 +
   1.255 +static SkScaledBitmapSampler::RowProc get_RGBx_to_4444_proc(const SkImageDecoder& decoder) {
   1.256 +    // Skip zeroes and unpremul make no difference
   1.257 +    if (decoder.getDitherImage()) {
   1.258 +        return Sample_RGBx_D4444_D;
   1.259 +    }
   1.260 +    return Sample_RGBx_D4444;
   1.261 +}
   1.262 +
   1.263 +static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow,
   1.264 +                              const uint8_t* SK_RESTRICT src,
   1.265 +                              int width, int deltaSrc, int, const SkPMColor[]) {
   1.266 +    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
   1.267 +    unsigned alphaMask = 0xFF;
   1.268 +
   1.269 +    for (int x = 0; x < width; x++) {
   1.270 +        unsigned alpha = src[3];
   1.271 +        SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
   1.272 +        dst[x] = SkPixel32ToPixel4444(c);
   1.273 +        src += deltaSrc;
   1.274 +        alphaMask &= alpha;
   1.275 +    }
   1.276 +    return alphaMask != 0xFF;
   1.277 +}
   1.278 +
   1.279 +static bool Sample_RGBA_D4444_SkipZ(void* SK_RESTRICT dstRow,
   1.280 +                                    const uint8_t* SK_RESTRICT src,
   1.281 +                                    int width, int deltaSrc, int,
   1.282 +                                    const SkPMColor[]) {
   1.283 +    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
   1.284 +    unsigned alphaMask = 0xFF;
   1.285 +
   1.286 +    for (int x = 0; x < width; x++) {
   1.287 +        unsigned alpha = src[3];
   1.288 +        if (alpha != 0) {
   1.289 +            SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
   1.290 +            dst[x] = SkPixel32ToPixel4444(c);
   1.291 +        }
   1.292 +        src += deltaSrc;
   1.293 +        alphaMask &= alpha;
   1.294 +    }
   1.295 +    return alphaMask != 0xFF;
   1.296 +}
   1.297 +
   1.298 +
   1.299 +static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow,
   1.300 +                                const uint8_t* SK_RESTRICT src,
   1.301 +                                int width, int deltaSrc, int y,
   1.302 +                                const SkPMColor[]) {
   1.303 +    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
   1.304 +    unsigned alphaMask = 0xFF;
   1.305 +    DITHER_4444_SCAN(y);
   1.306 +
   1.307 +    for (int x = 0; x < width; x++) {
   1.308 +        unsigned alpha = src[3];
   1.309 +        SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
   1.310 +        dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
   1.311 +        src += deltaSrc;
   1.312 +        alphaMask &= alpha;
   1.313 +    }
   1.314 +    return alphaMask != 0xFF;
   1.315 +}
   1.316 +
   1.317 +static bool Sample_RGBA_D4444_D_SkipZ(void* SK_RESTRICT dstRow,
   1.318 +                                      const uint8_t* SK_RESTRICT src,
   1.319 +                                      int width, int deltaSrc, int y,
   1.320 +                                      const SkPMColor[]) {
   1.321 +    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
   1.322 +    unsigned alphaMask = 0xFF;
   1.323 +    DITHER_4444_SCAN(y);
   1.324 +
   1.325 +    for (int x = 0; x < width; x++) {
   1.326 +        unsigned alpha = src[3];
   1.327 +        if (alpha != 0) {
   1.328 +            SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
   1.329 +            dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
   1.330 +        }
   1.331 +        src += deltaSrc;
   1.332 +        alphaMask &= alpha;
   1.333 +    }
   1.334 +    return alphaMask != 0xFF;
   1.335 +}
   1.336 +
   1.337 +static SkScaledBitmapSampler::RowProc get_RGBA_to_4444_proc(const SkImageDecoder& decoder) {
   1.338 +    if (decoder.getRequireUnpremultipliedColors()) {
   1.339 +        // Unpremultiplied is not supported for 4444
   1.340 +        return NULL;
   1.341 +    }
   1.342 +    const bool dither = decoder.getDitherImage();
   1.343 +    if (decoder.getSkipWritingZeroes()) {
   1.344 +        if (dither) {
   1.345 +            return Sample_RGBA_D4444_D_SkipZ;
   1.346 +        }
   1.347 +        return Sample_RGBA_D4444_SkipZ;
   1.348 +    }
   1.349 +    if (dither) {
   1.350 +        return Sample_RGBA_D4444_D;
   1.351 +    }
   1.352 +    return Sample_RGBA_D4444;
   1.353 +}
   1.354 +
   1.355 +// Index
   1.356 +
   1.357 +#define A32_MASK_IN_PLACE   (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT)
   1.358 +
   1.359 +static bool Sample_Index_D8888(void* SK_RESTRICT dstRow,
   1.360 +                               const uint8_t* SK_RESTRICT src,
   1.361 +                       int width, int deltaSrc, int, const SkPMColor ctable[]) {
   1.362 +
   1.363 +    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
   1.364 +    SkPMColor cc = A32_MASK_IN_PLACE;
   1.365 +    for (int x = 0; x < width; x++) {
   1.366 +        SkPMColor c = ctable[*src];
   1.367 +        cc &= c;
   1.368 +        dst[x] = c;
   1.369 +        src += deltaSrc;
   1.370 +    }
   1.371 +    return cc != A32_MASK_IN_PLACE;
   1.372 +}
   1.373 +
   1.374 +static bool Sample_Index_D8888_SkipZ(void* SK_RESTRICT dstRow,
   1.375 +                                     const uint8_t* SK_RESTRICT src,
   1.376 +                                     int width, int deltaSrc, int,
   1.377 +                                     const SkPMColor ctable[]) {
   1.378 +
   1.379 +    SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
   1.380 +    SkPMColor cc = A32_MASK_IN_PLACE;
   1.381 +    for (int x = 0; x < width; x++) {
   1.382 +        SkPMColor c = ctable[*src];
   1.383 +        cc &= c;
   1.384 +        if (c != 0) {
   1.385 +            dst[x] = c;
   1.386 +        }
   1.387 +        src += deltaSrc;
   1.388 +    }
   1.389 +    return cc != A32_MASK_IN_PLACE;
   1.390 +}
   1.391 +
   1.392 +static SkScaledBitmapSampler::RowProc get_index_to_8888_proc(const SkImageDecoder& decoder) {
   1.393 +    if (decoder.getRequireUnpremultipliedColors()) {
   1.394 +        // Unpremultiplied is not supported for an index source.
   1.395 +        return NULL;
   1.396 +    }
   1.397 +    // Dither makes no difference
   1.398 +    if (decoder.getSkipWritingZeroes()) {
   1.399 +        return Sample_Index_D8888_SkipZ;
   1.400 +    }
   1.401 +    return Sample_Index_D8888;
   1.402 +}
   1.403 +
   1.404 +static bool Sample_Index_D565(void* SK_RESTRICT dstRow,
   1.405 +                               const uint8_t* SK_RESTRICT src,
   1.406 +                       int width, int deltaSrc, int, const SkPMColor ctable[]) {
   1.407 +
   1.408 +    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
   1.409 +    for (int x = 0; x < width; x++) {
   1.410 +        dst[x] = SkPixel32ToPixel16(ctable[*src]);
   1.411 +        src += deltaSrc;
   1.412 +    }
   1.413 +    return false;
   1.414 +}
   1.415 +
   1.416 +static bool Sample_Index_D565_D(void* SK_RESTRICT dstRow,
   1.417 +                                const uint8_t* SK_RESTRICT src, int width,
   1.418 +                                int deltaSrc, int y, const SkPMColor ctable[]) {
   1.419 +
   1.420 +    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
   1.421 +    DITHER_565_SCAN(y);
   1.422 +
   1.423 +    for (int x = 0; x < width; x++) {
   1.424 +        SkPMColor c = ctable[*src];
   1.425 +        dst[x] = SkDitherRGBTo565(SkGetPackedR32(c), SkGetPackedG32(c),
   1.426 +                                  SkGetPackedB32(c), DITHER_VALUE(x));
   1.427 +        src += deltaSrc;
   1.428 +    }
   1.429 +    return false;
   1.430 +}
   1.431 +
   1.432 +static SkScaledBitmapSampler::RowProc get_index_to_565_proc(const SkImageDecoder& decoder) {
   1.433 +    // Unpremultiplied and skip zeroes make no difference
   1.434 +    if (decoder.getDitherImage()) {
   1.435 +        return Sample_Index_D565_D;
   1.436 +    }
   1.437 +    return Sample_Index_D565;
   1.438 +}
   1.439 +
   1.440 +static bool Sample_Index_D4444(void* SK_RESTRICT dstRow,
   1.441 +                               const uint8_t* SK_RESTRICT src, int width,
   1.442 +                               int deltaSrc, int y, const SkPMColor ctable[]) {
   1.443 +
   1.444 +    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
   1.445 +    SkPMColor cc = A32_MASK_IN_PLACE;
   1.446 +    for (int x = 0; x < width; x++) {
   1.447 +        SkPMColor c = ctable[*src];
   1.448 +        cc &= c;
   1.449 +        dst[x] = SkPixel32ToPixel4444(c);
   1.450 +        src += deltaSrc;
   1.451 +    }
   1.452 +    return cc != A32_MASK_IN_PLACE;
   1.453 +}
   1.454 +
   1.455 +static bool Sample_Index_D4444_D(void* SK_RESTRICT dstRow,
   1.456 +                                 const uint8_t* SK_RESTRICT src, int width,
   1.457 +                                int deltaSrc, int y, const SkPMColor ctable[]) {
   1.458 +
   1.459 +    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
   1.460 +    SkPMColor cc = A32_MASK_IN_PLACE;
   1.461 +    DITHER_4444_SCAN(y);
   1.462 +
   1.463 +    for (int x = 0; x < width; x++) {
   1.464 +        SkPMColor c = ctable[*src];
   1.465 +        cc &= c;
   1.466 +        dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
   1.467 +        src += deltaSrc;
   1.468 +    }
   1.469 +    return cc != A32_MASK_IN_PLACE;
   1.470 +}
   1.471 +
   1.472 +static bool Sample_Index_D4444_SkipZ(void* SK_RESTRICT dstRow,
   1.473 +                                     const uint8_t* SK_RESTRICT src, int width,
   1.474 +                                     int deltaSrc, int y, const SkPMColor ctable[]) {
   1.475 +
   1.476 +    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
   1.477 +    SkPMColor cc = A32_MASK_IN_PLACE;
   1.478 +    for (int x = 0; x < width; x++) {
   1.479 +        SkPMColor c = ctable[*src];
   1.480 +        cc &= c;
   1.481 +        if (c != 0) {
   1.482 +            dst[x] = SkPixel32ToPixel4444(c);
   1.483 +        }
   1.484 +        src += deltaSrc;
   1.485 +    }
   1.486 +    return cc != A32_MASK_IN_PLACE;
   1.487 +}
   1.488 +
   1.489 +static bool Sample_Index_D4444_D_SkipZ(void* SK_RESTRICT dstRow,
   1.490 +                                       const uint8_t* SK_RESTRICT src, int width,
   1.491 +                                       int deltaSrc, int y, const SkPMColor ctable[]) {
   1.492 +
   1.493 +    SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
   1.494 +    SkPMColor cc = A32_MASK_IN_PLACE;
   1.495 +    DITHER_4444_SCAN(y);
   1.496 +
   1.497 +    for (int x = 0; x < width; x++) {
   1.498 +        SkPMColor c = ctable[*src];
   1.499 +        cc &= c;
   1.500 +        if (c != 0) {
   1.501 +            dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
   1.502 +        }
   1.503 +        src += deltaSrc;
   1.504 +    }
   1.505 +    return cc != A32_MASK_IN_PLACE;
   1.506 +}
   1.507 +
   1.508 +static SkScaledBitmapSampler::RowProc get_index_to_4444_proc(const SkImageDecoder& decoder) {
   1.509 +    // Unpremul not allowed
   1.510 +    if (decoder.getRequireUnpremultipliedColors()) {
   1.511 +        return NULL;
   1.512 +    }
   1.513 +    const bool dither = decoder.getDitherImage();
   1.514 +    if (decoder.getSkipWritingZeroes()) {
   1.515 +        if (dither) {
   1.516 +            return Sample_Index_D4444_D_SkipZ;
   1.517 +        }
   1.518 +        return Sample_Index_D4444_SkipZ;
   1.519 +    }
   1.520 +    if (dither) {
   1.521 +        return Sample_Index_D4444_D;
   1.522 +    }
   1.523 +    return Sample_Index_D4444;
   1.524 +}
   1.525 +
   1.526 +static bool Sample_Index_DI(void* SK_RESTRICT dstRow,
   1.527 +                            const uint8_t* SK_RESTRICT src,
   1.528 +                            int width, int deltaSrc, int, const SkPMColor[]) {
   1.529 +    if (1 == deltaSrc) {
   1.530 +        memcpy(dstRow, src, width);
   1.531 +    } else {
   1.532 +        uint8_t* SK_RESTRICT dst = (uint8_t*)dstRow;
   1.533 +        for (int x = 0; x < width; x++) {
   1.534 +            dst[x] = src[0];
   1.535 +            src += deltaSrc;
   1.536 +        }
   1.537 +    }
   1.538 +    return false;
   1.539 +}
   1.540 +
   1.541 +static SkScaledBitmapSampler::RowProc get_index_to_index_proc(const SkImageDecoder& decoder) {
   1.542 +    // Unpremul not allowed
   1.543 +    if (decoder.getRequireUnpremultipliedColors()) {
   1.544 +        return NULL;
   1.545 +    }
   1.546 +    // Ignore dither and skip zeroes
   1.547 +    return Sample_Index_DI;
   1.548 +}
   1.549 +
   1.550 +// A8
   1.551 +static bool Sample_Gray_DA8(void* SK_RESTRICT dstRow,
   1.552 +                            const uint8_t* SK_RESTRICT src,
   1.553 +                            int width, int deltaSrc, int,
   1.554 +                            const SkPMColor[]) {
   1.555 +    // Sampling Gray to A8 uses the same function as Index to Index8,
   1.556 +    // except we assume that there is alpha for speed, since an A8
   1.557 +    // bitmap with no alpha is not interesting.
   1.558 +    (void) Sample_Index_DI(dstRow, src, width, deltaSrc, /* y unused */ 0,
   1.559 +                           /* ctable unused */ NULL);
   1.560 +    return true;
   1.561 +}
   1.562 +
   1.563 +static SkScaledBitmapSampler::RowProc get_gray_to_A8_proc(const SkImageDecoder& decoder) {
   1.564 +    if (decoder.getRequireUnpremultipliedColors()) {
   1.565 +        return NULL;
   1.566 +    }
   1.567 +    // Ignore skip and dither.
   1.568 +    return Sample_Gray_DA8;
   1.569 +}
   1.570 +
   1.571 +typedef SkScaledBitmapSampler::RowProc (*RowProcChooser)(const SkImageDecoder& decoder);
   1.572 +///////////////////////////////////////////////////////////////////////////////
   1.573 +
   1.574 +#include "SkScaledBitmapSampler.h"
   1.575 +
   1.576 +SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height,
   1.577 +                                             int sampleSize) {
   1.578 +    fCTable = NULL;
   1.579 +    fDstRow = NULL;
   1.580 +    fRowProc = NULL;
   1.581 +
   1.582 +    if (width <= 0 || height <= 0) {
   1.583 +        sk_throw();
   1.584 +    }
   1.585 +
   1.586 +    SkDEBUGCODE(fSampleMode = kUninitialized_SampleMode);
   1.587 +
   1.588 +    if (sampleSize <= 1) {
   1.589 +        fScaledWidth = width;
   1.590 +        fScaledHeight = height;
   1.591 +        fX0 = fY0 = 0;
   1.592 +        fDX = fDY = 1;
   1.593 +        return;
   1.594 +    }
   1.595 +
   1.596 +    int dx = SkMin32(sampleSize, width);
   1.597 +    int dy = SkMin32(sampleSize, height);
   1.598 +
   1.599 +    fScaledWidth = width / dx;
   1.600 +    fScaledHeight = height / dy;
   1.601 +
   1.602 +    SkASSERT(fScaledWidth > 0);
   1.603 +    SkASSERT(fScaledHeight > 0);
   1.604 +
   1.605 +    fX0 = dx >> 1;
   1.606 +    fY0 = dy >> 1;
   1.607 +
   1.608 +    SkASSERT(fX0 >= 0 && fX0 < width);
   1.609 +    SkASSERT(fY0 >= 0 && fY0 < height);
   1.610 +
   1.611 +    fDX = dx;
   1.612 +    fDY = dy;
   1.613 +
   1.614 +    SkASSERT(fDX > 0 && (fX0 + fDX * (fScaledWidth - 1)) < width);
   1.615 +    SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height);
   1.616 +}
   1.617 +
   1.618 +bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc,
   1.619 +                                  const SkImageDecoder& decoder,
   1.620 +                                  const SkPMColor ctable[]) {
   1.621 +    static const RowProcChooser gProcChoosers[] = {
   1.622 +        get_gray_to_8888_proc,
   1.623 +        get_RGBx_to_8888_proc,
   1.624 +        get_RGBA_to_8888_proc,
   1.625 +        get_index_to_8888_proc,
   1.626 +        NULL, // 565 to 8888
   1.627 +
   1.628 +        get_gray_to_565_proc,
   1.629 +        get_RGBx_to_565_proc,
   1.630 +        get_RGBx_to_565_proc, // The source alpha will be ignored.
   1.631 +        get_index_to_565_proc,
   1.632 +        get_565_to_565_proc,
   1.633 +
   1.634 +        get_gray_to_4444_proc,
   1.635 +        get_RGBx_to_4444_proc,
   1.636 +        get_RGBA_to_4444_proc,
   1.637 +        get_index_to_4444_proc,
   1.638 +        NULL, // 565 to 4444
   1.639 +
   1.640 +        NULL, // gray to index
   1.641 +        NULL, // rgbx to index
   1.642 +        NULL, // rgba to index
   1.643 +        get_index_to_index_proc,
   1.644 +        NULL, // 565 to index
   1.645 +
   1.646 +        get_gray_to_A8_proc,
   1.647 +        NULL, // rgbx to a8
   1.648 +        NULL, // rgba to a8
   1.649 +        NULL, // index to a8
   1.650 +        NULL, // 565 to a8
   1.651 +    };
   1.652 +
   1.653 +    // The jump between dst configs in the table
   1.654 +    static const int gProcDstConfigSpan = 5;
   1.655 +    SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gProcChoosers) == 5 * gProcDstConfigSpan,
   1.656 +                      gProcs_has_the_wrong_number_of_entries);
   1.657 +
   1.658 +    fCTable = ctable;
   1.659 +
   1.660 +    int index = 0;
   1.661 +    switch (sc) {
   1.662 +        case SkScaledBitmapSampler::kGray:
   1.663 +            fSrcPixelSize = 1;
   1.664 +            index += 0;
   1.665 +            break;
   1.666 +        case SkScaledBitmapSampler::kRGB:
   1.667 +            fSrcPixelSize = 3;
   1.668 +            index += 1;
   1.669 +            break;
   1.670 +        case SkScaledBitmapSampler::kRGBX:
   1.671 +            fSrcPixelSize = 4;
   1.672 +            index += 1;
   1.673 +            break;
   1.674 +        case SkScaledBitmapSampler::kRGBA:
   1.675 +            fSrcPixelSize = 4;
   1.676 +            index += 2;
   1.677 +            break;
   1.678 +        case SkScaledBitmapSampler::kIndex:
   1.679 +            fSrcPixelSize = 1;
   1.680 +            index += 3;
   1.681 +            break;
   1.682 +        case SkScaledBitmapSampler::kRGB_565:
   1.683 +            fSrcPixelSize = 2;
   1.684 +            index += 4;
   1.685 +            break;
   1.686 +        default:
   1.687 +            return false;
   1.688 +    }
   1.689 +
   1.690 +    switch (dst->config()) {
   1.691 +        case SkBitmap::kARGB_8888_Config:
   1.692 +            index += 0 * gProcDstConfigSpan;
   1.693 +            break;
   1.694 +        case SkBitmap::kRGB_565_Config:
   1.695 +            index += 1 * gProcDstConfigSpan;
   1.696 +            break;
   1.697 +        case SkBitmap::kARGB_4444_Config:
   1.698 +            index += 2 * gProcDstConfigSpan;
   1.699 +            break;
   1.700 +        case SkBitmap::kIndex8_Config:
   1.701 +            index += 3 * gProcDstConfigSpan;
   1.702 +            break;
   1.703 +        case SkBitmap::kA8_Config:
   1.704 +            index += 4 * gProcDstConfigSpan;
   1.705 +            break;
   1.706 +        default:
   1.707 +            return false;
   1.708 +    }
   1.709 +
   1.710 +    RowProcChooser chooser = gProcChoosers[index];
   1.711 +    if (NULL == chooser) {
   1.712 +        fRowProc = NULL;
   1.713 +    } else {
   1.714 +        fRowProc = chooser(decoder);
   1.715 +    }
   1.716 +    fDstRow = (char*)dst->getPixels();
   1.717 +    fDstRowBytes = dst->rowBytes();
   1.718 +    fCurrY = 0;
   1.719 +    return fRowProc != NULL;
   1.720 +}
   1.721 +
   1.722 +bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) {
   1.723 +    SkASSERT(kInterlaced_SampleMode != fSampleMode);
   1.724 +    SkDEBUGCODE(fSampleMode = kConsecutive_SampleMode);
   1.725 +    SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight);
   1.726 +
   1.727 +    bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
   1.728 +                             fDX * fSrcPixelSize, fCurrY, fCTable);
   1.729 +    fDstRow += fDstRowBytes;
   1.730 +    fCurrY += 1;
   1.731 +    return hadAlpha;
   1.732 +}
   1.733 +
   1.734 +bool SkScaledBitmapSampler::sampleInterlaced(const uint8_t* SK_RESTRICT src, int srcY) {
   1.735 +    SkASSERT(kConsecutive_SampleMode != fSampleMode);
   1.736 +    SkDEBUGCODE(fSampleMode = kInterlaced_SampleMode);
   1.737 +    // Any line that should be a part of the destination can be created by the formula:
   1.738 +    // fY0 + (some multiplier) * fDY
   1.739 +    // so if srcY - fY0 is not an integer multiple of fDY that srcY will be skipped.
   1.740 +    const int srcYMinusY0 = srcY - fY0;
   1.741 +    if (srcYMinusY0 % fDY != 0) {
   1.742 +        // This line is not part of the output, so return false for alpha, since we have
   1.743 +        // not added an alpha to the output.
   1.744 +        return false;
   1.745 +    }
   1.746 +    // Unlike in next(), where the data is used sequentially, this function skips around,
   1.747 +    // so fDstRow and fCurrY are never updated. fDstRow must always be the starting point
   1.748 +    // of the destination bitmap's pixels, which is used to calculate the destination row
   1.749 +    // each time this function is called.
   1.750 +    const int dstY = srcYMinusY0 / fDY;
   1.751 +    SkASSERT(dstY < fScaledHeight);
   1.752 +    char* dstRow = fDstRow + dstY * fDstRowBytes;
   1.753 +    return fRowProc(dstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
   1.754 +                    fDX * fSrcPixelSize, dstY, fCTable);
   1.755 +}
   1.756 +
   1.757 +#ifdef SK_DEBUG
   1.758 +// The following code is for a test to ensure that changing the method to get the right row proc
   1.759 +// did not change the row proc unintentionally. Tested by ImageDecodingTest.cpp
   1.760 +
   1.761 +// friend of SkScaledBitmapSampler solely for the purpose of accessing fRowProc.
   1.762 +class RowProcTester {
   1.763 +public:
   1.764 +    static SkScaledBitmapSampler::RowProc getRowProc(const SkScaledBitmapSampler& sampler) {
   1.765 +        return sampler.fRowProc;
   1.766 +    }
   1.767 +};
   1.768 +
   1.769 +
   1.770 +// Table showing the expected RowProc for each combination of inputs.
   1.771 +// Table formated as follows:
   1.772 +// Each group of 5 consecutive rows represents sampling from a single
   1.773 +// SkScaledBitmapSampler::SrcConfig.
   1.774 +// Within each set, each row represents a different destination SkBitmap::Config
   1.775 +// Each column represents a different combination of dither and unpremul.
   1.776 +// D = dither   ~D = no dither
   1.777 +// U = unpremul ~U = no unpremul
   1.778 +//  ~D~U                D~U                     ~DU                         DU
   1.779 +SkScaledBitmapSampler::RowProc gTestProcs[] = {
   1.780 +    // Gray
   1.781 +    Sample_Gray_DA8,    Sample_Gray_DA8,        NULL,                       NULL,                       // to A8
   1.782 +    NULL,               NULL,                   NULL,                       NULL,                       // to Index8
   1.783 +    Sample_Gray_D565,   Sample_Gray_D565_D,     Sample_Gray_D565,           Sample_Gray_D565_D,         // to 565
   1.784 +    Sample_Gray_D4444,  Sample_Gray_D4444_D,    Sample_Gray_D4444,          Sample_Gray_D4444_D,        // to 4444
   1.785 +    Sample_Gray_D8888,  Sample_Gray_D8888,      Sample_Gray_D8888,          Sample_Gray_D8888,          // to 8888
   1.786 +    // Index
   1.787 +    NULL,               NULL,                   NULL,                       NULL,                       // to A8
   1.788 +    Sample_Index_DI,    Sample_Index_DI,        NULL,                       NULL,                       // to Index8
   1.789 +    Sample_Index_D565,  Sample_Index_D565_D,    Sample_Index_D565,          Sample_Index_D565_D,        // to 565
   1.790 +    Sample_Index_D4444, Sample_Index_D4444_D,   NULL,                       NULL,                       // to 4444
   1.791 +    Sample_Index_D8888, Sample_Index_D8888,     NULL,                       NULL,                       // to 8888
   1.792 +    // RGB
   1.793 +    NULL,               NULL,                   NULL,                       NULL,                       // to A8
   1.794 +    NULL,               NULL,                   NULL,                       NULL,                       // to Index8
   1.795 +    Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
   1.796 +    Sample_RGBx_D4444,  Sample_RGBx_D4444_D,    Sample_RGBx_D4444,          Sample_RGBx_D4444_D,        // to 4444
   1.797 +    Sample_RGBx_D8888,  Sample_RGBx_D8888,      Sample_RGBx_D8888,          Sample_RGBx_D8888,          // to 8888
   1.798 +    // RGBx is the same as RGB
   1.799 +    NULL,               NULL,                   NULL,                       NULL,                       // to A8
   1.800 +    NULL,               NULL,                   NULL,                       NULL,                       // to Index8
   1.801 +    Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
   1.802 +    Sample_RGBx_D4444,  Sample_RGBx_D4444_D,    Sample_RGBx_D4444,          Sample_RGBx_D4444_D,        // to 4444
   1.803 +    Sample_RGBx_D8888,  Sample_RGBx_D8888,      Sample_RGBx_D8888,          Sample_RGBx_D8888,          // to 8888
   1.804 +    // RGBA
   1.805 +    NULL,               NULL,                   NULL,                       NULL,                       // to A8
   1.806 +    NULL,               NULL,                   NULL,                       NULL,                       // to Index8
   1.807 +    Sample_RGBx_D565,   Sample_RGBx_D565_D,     Sample_RGBx_D565,           Sample_RGBx_D565_D,         // to 565
   1.808 +    Sample_RGBA_D4444,  Sample_RGBA_D4444_D,    NULL,                       NULL,                       // to 4444
   1.809 +    Sample_RGBA_D8888,  Sample_RGBA_D8888,      Sample_RGBA_D8888_Unpremul, Sample_RGBA_D8888_Unpremul, // to 8888
   1.810 +    // RGB_565
   1.811 +    NULL,               NULL,                   NULL,                       NULL,                       // to A8
   1.812 +    NULL,               NULL,                   NULL,                       NULL,                       // to Index8
   1.813 +    Sample_D565_D565,   Sample_D565_D565,       Sample_D565_D565,           Sample_D565_D565,           // to 565
   1.814 +    NULL,               NULL,                   NULL,                       NULL,                       // to 4444
   1.815 +    NULL,               NULL,                   NULL,                       NULL,                       // to 8888
   1.816 +};
   1.817 +
   1.818 +// Dummy class that allows instantiation of an ImageDecoder, so begin can query its fields.
   1.819 +class DummyDecoder : public SkImageDecoder {
   1.820 +public:
   1.821 +    DummyDecoder() {}
   1.822 +protected:
   1.823 +    virtual bool onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) SK_OVERRIDE {
   1.824 +        return false;
   1.825 +    }
   1.826 +};
   1.827 +
   1.828 +void test_row_proc_choice();
   1.829 +void test_row_proc_choice() {
   1.830 +    SkBitmap dummyBitmap;
   1.831 +    DummyDecoder dummyDecoder;
   1.832 +    size_t procCounter = 0;
   1.833 +    for (int sc = SkScaledBitmapSampler::kGray; sc <= SkScaledBitmapSampler::kRGB_565; ++sc) {
   1.834 +        for (int c = SkBitmap::kA8_Config; c <= SkBitmap::kARGB_8888_Config; ++c) {
   1.835 +            for (int unpremul = 0; unpremul <= 1; ++unpremul) {
   1.836 +                for (int dither = 0; dither <= 1; ++dither) {
   1.837 +                    // Arbitrary width/height/sampleSize to allow SkScaledBitmapSampler to
   1.838 +                    // be considered valid.
   1.839 +                    SkScaledBitmapSampler sampler(10, 10, 1);
   1.840 +                    dummyBitmap.setConfig((SkBitmap::Config) c, 10, 10);
   1.841 +                    dummyDecoder.setDitherImage(SkToBool(dither));
   1.842 +                    dummyDecoder.setRequireUnpremultipliedColors(SkToBool(unpremul));
   1.843 +                    sampler.begin(&dummyBitmap, (SkScaledBitmapSampler::SrcConfig) sc,
   1.844 +                                  dummyDecoder);
   1.845 +                    SkScaledBitmapSampler::RowProc expected = gTestProcs[procCounter];
   1.846 +                    SkScaledBitmapSampler::RowProc actual = RowProcTester::getRowProc(sampler);
   1.847 +                    SkASSERT(expected == actual);
   1.848 +                    procCounter++;
   1.849 +                }
   1.850 +            }
   1.851 +        }
   1.852 +    }
   1.853 +    SkASSERT(SK_ARRAY_COUNT(gTestProcs) == procCounter);
   1.854 +}
   1.855 +#endif // SK_DEBUG

mercurial