Home | History | Annotate | Download | only in core
      1 #include "SkConfig8888.h"
      2 
      3 namespace {
      4 
      5 template <int A_IDX, int R_IDX, int G_IDX, int B_IDX>
      6 inline uint32_t pack_config8888(uint32_t a, uint32_t r,
      7                                 uint32_t g, uint32_t b) {
      8 #ifdef SK_CPU_LENDIAN
      9     return (a << (A_IDX * 8)) | (r << (R_IDX * 8)) |
     10            (g << (G_IDX * 8)) | (b << (B_IDX * 8));
     11 #else
     12     return (a << ((3-A_IDX) * 8)) | (r << ((3-R_IDX) * 8)) |
     13            (g << ((3-G_IDX) * 8)) | (b << ((3-B_IDX) * 8));
     14 #endif
     15 }
     16 
     17 template <int A_IDX, int R_IDX, int G_IDX, int B_IDX>
     18 inline void unpack_config8888(uint32_t color,
     19                               uint32_t* a, uint32_t* r,
     20                               uint32_t* g, uint32_t* b) {
     21 #ifdef SK_CPU_LENDIAN
     22     *a = (color >> (A_IDX * 8)) & 0xff;
     23     *r = (color >> (R_IDX * 8)) & 0xff;
     24     *g = (color >> (G_IDX * 8)) & 0xff;
     25     *b = (color >> (B_IDX * 8)) & 0xff;
     26 #else
     27     *a = (color >> ((3 - A_IDX) * 8)) & 0xff;
     28     *r = (color >> ((3 - R_IDX) * 8)) & 0xff;
     29     *g = (color >> ((3 - G_IDX) * 8)) & 0xff;
     30     *b = (color >> ((3 - B_IDX) * 8)) & 0xff;
     31 #endif
     32 }
     33 
     34 #ifdef SK_CPU_LENDIAN
     35     static const int SK_NATIVE_A_IDX = SK_A32_SHIFT / 8;
     36     static const int SK_NATIVE_R_IDX = SK_R32_SHIFT / 8;
     37     static const int SK_NATIVE_G_IDX = SK_G32_SHIFT / 8;
     38     static const int SK_NATIVE_B_IDX = SK_B32_SHIFT / 8;
     39 #else
     40     static const int SK_NATIVE_A_IDX = 3 - (SK_A32_SHIFT / 8);
     41     static const int SK_NATIVE_R_IDX = 3 - (SK_R32_SHIFT / 8);
     42     static const int SK_NATIVE_G_IDX = 3 - (SK_G32_SHIFT / 8);
     43     static const int SK_NATIVE_B_IDX = 3 - (SK_B32_SHIFT / 8);
     44 #endif
     45 
     46 /**
     47  * convert_pixel<OUT_CFG, IN_CFG converts a pixel value from one Config8888 to
     48  * another. It is implemented by first expanding OUT_CFG to r, g, b, a indices
     49  * and an is_premul bool as params to another template function. Then IN_CFG is
     50  * expanded via another function call.
     51  */
     52 
     53 template <bool OUT_PM, int OUT_A_IDX, int OUT_R_IDX, int OUT_G_IDX, int OUT_B_IDX,
     54           bool IN_PM,  int IN_A_IDX,  int IN_R_IDX,  int IN_G_IDX,  int IN_B_IDX>
     55 inline uint32_t convert_pixel(uint32_t pixel) {
     56     uint32_t a, r, g, b;
     57     unpack_config8888<IN_A_IDX, IN_R_IDX, IN_G_IDX, IN_B_IDX>(pixel, &a, &r, &g, &b);
     58     if (IN_PM && !OUT_PM) {
     59         // We're doing the explicit divide to match WebKit layout
     60         // test expectations. We can modify and rebaseline if there
     61         // it can be shown that there is a more performant way to
     62         // unpremul.
     63         if (a) {
     64             r = r * 0xff / a;
     65             g = g * 0xff / a;
     66             b = b * 0xff / a;
     67         } else {
     68             return 0;
     69         }
     70     } else if (!IN_PM && OUT_PM) {
     71         // This matches WebKit's conversion which we are replacing.
     72         // We can consider alternative rounding rules for performance.
     73         r = SkMulDiv255Ceiling(r, a);
     74         g = SkMulDiv255Ceiling(g, a);
     75         b = SkMulDiv255Ceiling(b, a);
     76     }
     77     return pack_config8888<OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX>(a, r, g, b);
     78 }
     79 
     80 template <bool OUT_PM, int OUT_A_IDX, int OUT_R_IDX, int OUT_G_IDX, int OUT_B_IDX, SkCanvas::Config8888 IN_CFG>
     81 inline uint32_t convert_pixel(uint32_t pixel) {
     82     switch(IN_CFG) {
     83         case SkCanvas::kNative_Premul_Config8888:
     84             return convert_pixel<OUT_PM, OUT_A_IDX,       OUT_R_IDX,       OUT_G_IDX,       OUT_B_IDX,
     85                                  true,  SK_NATIVE_A_IDX,  SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(pixel);
     86             break;
     87         case SkCanvas::kNative_Unpremul_Config8888:
     88             return convert_pixel<OUT_PM, OUT_A_IDX,       OUT_R_IDX,       OUT_G_IDX,       OUT_B_IDX,
     89                                  false,  SK_NATIVE_A_IDX, SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(pixel);
     90             break;
     91         case SkCanvas::kBGRA_Premul_Config8888:
     92             return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX,
     93                                  true,  3,         2,         1,         0>(pixel);
     94             break;
     95         case SkCanvas::kBGRA_Unpremul_Config8888:
     96             return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX,
     97                                  false,  3,         2,         1,         0>(pixel);
     98             break;
     99         case SkCanvas::kRGBA_Premul_Config8888:
    100             return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX,
    101                                  true,  3,         0,         1,         2>(pixel);
    102             break;
    103         case SkCanvas::kRGBA_Unpremul_Config8888:
    104             return convert_pixel<OUT_PM, OUT_A_IDX, OUT_R_IDX, OUT_G_IDX, OUT_B_IDX,
    105                                  false,  3,         0,         1,         2>(pixel);
    106             break;
    107         default:
    108             SkDEBUGFAIL("Unexpected config8888");
    109             return 0;
    110             break;
    111     }
    112 }
    113 
    114 template <SkCanvas::Config8888 OUT_CFG, SkCanvas::Config8888 IN_CFG>
    115 inline uint32_t convert_pixel(uint32_t pixel) {
    116     switch(OUT_CFG) {
    117         case SkCanvas::kNative_Premul_Config8888:
    118             return convert_pixel<true,  SK_NATIVE_A_IDX,  SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX, IN_CFG>(pixel);
    119             break;
    120         case SkCanvas::kNative_Unpremul_Config8888:
    121             return convert_pixel<false,  SK_NATIVE_A_IDX,  SK_NATIVE_R_IDX, SK_NATIVE_G_IDX, SK_NATIVE_B_IDX, IN_CFG>(pixel);
    122             break;
    123         case SkCanvas::kBGRA_Premul_Config8888:
    124             return convert_pixel<true, 3, 2, 1, 0, IN_CFG>(pixel);
    125             break;
    126         case SkCanvas::kBGRA_Unpremul_Config8888:
    127             return convert_pixel<false, 3, 2, 1, 0, IN_CFG>(pixel);
    128             break;
    129         case SkCanvas::kRGBA_Premul_Config8888:
    130             return convert_pixel<true, 3, 0, 1, 2, IN_CFG>(pixel);
    131             break;
    132         case SkCanvas::kRGBA_Unpremul_Config8888:
    133             return convert_pixel<false, 3, 0, 1, 2, IN_CFG>(pixel);
    134             break;
    135         default:
    136             SkDEBUGFAIL("Unexpected config8888");
    137             return 0;
    138             break;
    139     }
    140 }
    141 
    142 /**
    143  * SkConvertConfig8888Pixels has 6 * 6 possible combinations of src and dst
    144  * configs. Each is implemented as an instantiation templated function. Two
    145  * levels of switch statements are used to select the correct instantiation, one
    146  * for the src config and one for the dst config.
    147  */
    148 
    149 template <SkCanvas::Config8888 DST_CFG, SkCanvas::Config8888 SRC_CFG>
    150 inline void convert_config8888(uint32_t* dstPixels,
    151                                size_t dstRowBytes,
    152                                const uint32_t* srcPixels,
    153                                size_t srcRowBytes,
    154                                int width,
    155                                int height) {
    156     intptr_t dstPix = reinterpret_cast<intptr_t>(dstPixels);
    157     intptr_t srcPix = reinterpret_cast<intptr_t>(srcPixels);
    158 
    159     for (int y = 0; y < height; ++y) {
    160         srcPixels = reinterpret_cast<const uint32_t*>(srcPix);
    161         dstPixels = reinterpret_cast<uint32_t*>(dstPix);
    162         for (int x = 0; x < width; ++x) {
    163             dstPixels[x] = convert_pixel<DST_CFG, SRC_CFG>(srcPixels[x]);
    164         }
    165         dstPix += dstRowBytes;
    166         srcPix += srcRowBytes;
    167     }
    168 }
    169 
    170 template <SkCanvas::Config8888 SRC_CFG>
    171 inline void convert_config8888(uint32_t* dstPixels,
    172                                size_t dstRowBytes,
    173                                SkCanvas::Config8888 dstConfig,
    174                                const uint32_t* srcPixels,
    175                                size_t srcRowBytes,
    176                                int width,
    177                                int height) {
    178     switch(dstConfig) {
    179         case SkCanvas::kNative_Premul_Config8888:
    180             convert_config8888<SkCanvas::kNative_Premul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    181             break;
    182         case SkCanvas::kNative_Unpremul_Config8888:
    183             convert_config8888<SkCanvas::kNative_Unpremul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    184             break;
    185         case SkCanvas::kBGRA_Premul_Config8888:
    186             convert_config8888<SkCanvas::kBGRA_Premul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    187             break;
    188         case SkCanvas::kBGRA_Unpremul_Config8888:
    189             convert_config8888<SkCanvas::kBGRA_Unpremul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    190             break;
    191         case SkCanvas::kRGBA_Premul_Config8888:
    192             convert_config8888<SkCanvas::kRGBA_Premul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    193             break;
    194         case SkCanvas::kRGBA_Unpremul_Config8888:
    195             convert_config8888<SkCanvas::kRGBA_Unpremul_Config8888, SRC_CFG>(dstPixels, dstRowBytes, srcPixels, srcRowBytes, width, height);
    196             break;
    197         default:
    198             SkDEBUGFAIL("Unexpected config8888");
    199             break;
    200     }
    201 }
    202 
    203 }
    204 
    205 void SkConvertConfig8888Pixels(uint32_t* dstPixels,
    206                                size_t dstRowBytes,
    207                                SkCanvas::Config8888 dstConfig,
    208                                const uint32_t* srcPixels,
    209                                size_t srcRowBytes,
    210                                SkCanvas::Config8888 srcConfig,
    211                                int width,
    212                                int height) {
    213     if (srcConfig == dstConfig) {
    214         if (srcPixels == dstPixels) {
    215             return;
    216         }
    217         if (dstRowBytes == srcRowBytes &&
    218             4U * width == srcRowBytes) {
    219             memcpy(dstPixels, srcPixels, srcRowBytes * height);
    220             return;
    221         } else {
    222             intptr_t srcPix = reinterpret_cast<intptr_t>(srcPixels);
    223             intptr_t dstPix = reinterpret_cast<intptr_t>(dstPixels);
    224             for (int y = 0; y < height; ++y) {
    225                 srcPixels = reinterpret_cast<const uint32_t*>(srcPix);
    226                 dstPixels = reinterpret_cast<uint32_t*>(dstPix);
    227                 memcpy(dstPixels, srcPixels, 4 * width);
    228                 srcPix += srcRowBytes;
    229                 dstPix += dstRowBytes;
    230             }
    231             return;
    232         }
    233     }
    234     switch(srcConfig) {
    235         case SkCanvas::kNative_Premul_Config8888:
    236             convert_config8888<SkCanvas::kNative_Premul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    237             break;
    238         case SkCanvas::kNative_Unpremul_Config8888:
    239             convert_config8888<SkCanvas::kNative_Unpremul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    240             break;
    241         case SkCanvas::kBGRA_Premul_Config8888:
    242             convert_config8888<SkCanvas::kBGRA_Premul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    243             break;
    244         case SkCanvas::kBGRA_Unpremul_Config8888:
    245             convert_config8888<SkCanvas::kBGRA_Unpremul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    246             break;
    247         case SkCanvas::kRGBA_Premul_Config8888:
    248             convert_config8888<SkCanvas::kRGBA_Premul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    249             break;
    250         case SkCanvas::kRGBA_Unpremul_Config8888:
    251             convert_config8888<SkCanvas::kRGBA_Unpremul_Config8888>(dstPixels, dstRowBytes, dstConfig, srcPixels, srcRowBytes, width, height);
    252             break;
    253         default:
    254             SkDEBUGFAIL("Unexpected config8888");
    255             break;
    256     }
    257 }
    258 
    259 uint32_t SkPackConfig8888(SkCanvas::Config8888 config,
    260                           uint32_t a,
    261                           uint32_t r,
    262                           uint32_t g,
    263                           uint32_t b) {
    264     switch (config) {
    265         case SkCanvas::kNative_Premul_Config8888:
    266         case SkCanvas::kNative_Unpremul_Config8888:
    267             return pack_config8888<SK_NATIVE_A_IDX,
    268                                    SK_NATIVE_R_IDX,
    269                                    SK_NATIVE_G_IDX,
    270                                    SK_NATIVE_B_IDX>(a, r, g, b);
    271         case SkCanvas::kBGRA_Premul_Config8888:
    272         case SkCanvas::kBGRA_Unpremul_Config8888:
    273             return pack_config8888<3, 2, 1, 0>(a, r, g, b);
    274         case SkCanvas::kRGBA_Premul_Config8888:
    275         case SkCanvas::kRGBA_Unpremul_Config8888:
    276             return pack_config8888<3, 0, 1, 2>(a, r, g, b);
    277         default:
    278             SkDEBUGFAIL("Unexpected config8888");
    279             return 0;
    280     }
    281 }
    282