Home | History | Annotate | Download | only in effects
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "SkColorMatrixFilter.h"
      9 #include "SkColorMatrix.h"
     10 #include "SkColorPriv.h"
     11 #include "SkUnPreMultiply.h"
     12 
     13 static int32_t rowmul4(const int32_t array[], unsigned r, unsigned g,
     14                           unsigned b, unsigned a) {
     15     return array[0] * r + array[1] * g  + array[2] * b + array[3] * a + array[4];
     16 }
     17 
     18 static int32_t rowmul3(const int32_t array[], unsigned r, unsigned g,
     19                        unsigned b) {
     20     return array[0] * r + array[1] * g  + array[2] * b + array[4];
     21 }
     22 
     23 static void General(SkColorMatrixFilter::State* state,
     24                     unsigned r, unsigned g, unsigned b, unsigned a) {
     25     const int32_t* SK_RESTRICT array = state->fArray;
     26     const int shift = state->fShift;
     27     int32_t* SK_RESTRICT result = state->fResult;
     28 
     29     result[0] = rowmul4(&array[0], r, g, b, a) >> shift;
     30     result[1] = rowmul4(&array[5], r, g, b, a) >> shift;
     31     result[2] = rowmul4(&array[10], r, g, b, a) >> shift;
     32     result[3] = rowmul4(&array[15], r, g, b, a) >> shift;
     33 }
     34 
     35 static void General16(SkColorMatrixFilter::State* state,
     36                       unsigned r, unsigned g, unsigned b, unsigned a) {
     37     const int32_t* SK_RESTRICT array = state->fArray;
     38     int32_t* SK_RESTRICT result = state->fResult;
     39 
     40     result[0] = rowmul4(&array[0], r, g, b, a) >> 16;
     41     result[1] = rowmul4(&array[5], r, g, b, a) >> 16;
     42     result[2] = rowmul4(&array[10], r, g, b, a) >> 16;
     43     result[3] = rowmul4(&array[15], r, g, b, a) >> 16;
     44 }
     45 
     46 static void AffineAdd(SkColorMatrixFilter::State* state,
     47                       unsigned r, unsigned g, unsigned b, unsigned a) {
     48     const int32_t* SK_RESTRICT array = state->fArray;
     49     const int shift = state->fShift;
     50     int32_t* SK_RESTRICT result = state->fResult;
     51 
     52     result[0] = rowmul3(&array[0], r, g, b) >> shift;
     53     result[1] = rowmul3(&array[5], r, g, b) >> shift;
     54     result[2] = rowmul3(&array[10], r, g, b) >> shift;
     55     result[3] = a;
     56 }
     57 
     58 static void AffineAdd16(SkColorMatrixFilter::State* state,
     59                         unsigned r, unsigned g, unsigned b, unsigned a) {
     60     const int32_t* SK_RESTRICT array = state->fArray;
     61     int32_t* SK_RESTRICT result = state->fResult;
     62 
     63     result[0] = rowmul3(&array[0], r, g, b) >> 16;
     64     result[1] = rowmul3(&array[5], r, g, b) >> 16;
     65     result[2] = rowmul3(&array[10], r, g, b) >> 16;
     66     result[3] = a;
     67 }
     68 
     69 static void ScaleAdd(SkColorMatrixFilter::State* state,
     70                      unsigned r, unsigned g, unsigned b, unsigned a) {
     71     const int32_t* SK_RESTRICT array = state->fArray;
     72     const int shift = state->fShift;
     73     int32_t* SK_RESTRICT result = state->fResult;
     74 
     75     // cast to (int) to keep the expression signed for the shift
     76     result[0] = (array[0] * (int)r + array[4]) >> shift;
     77     result[1] = (array[6] * (int)g + array[9]) >> shift;
     78     result[2] = (array[12] * (int)b + array[14]) >> shift;
     79     result[3] = a;
     80 }
     81 
     82 static void ScaleAdd16(SkColorMatrixFilter::State* state,
     83                        unsigned r, unsigned g, unsigned b, unsigned a) {
     84     const int32_t* SK_RESTRICT array = state->fArray;
     85     int32_t* SK_RESTRICT result = state->fResult;
     86 
     87     // cast to (int) to keep the expression signed for the shift
     88     result[0] = (array[0] * (int)r + array[4]) >> 16;
     89     result[1] = (array[6] * (int)g + array[9]) >> 16;
     90     result[2] = (array[12] * (int)b + array[14]) >> 16;
     91     result[3] = a;
     92 }
     93 
     94 static void Add(SkColorMatrixFilter::State* state,
     95                 unsigned r, unsigned g, unsigned b, unsigned a) {
     96     const int32_t* SK_RESTRICT array = state->fArray;
     97     const int shift = state->fShift;
     98     int32_t* SK_RESTRICT result = state->fResult;
     99 
    100     result[0] = r + (array[4] >> shift);
    101     result[1] = g + (array[9] >> shift);
    102     result[2] = b + (array[14] >> shift);
    103     result[3] = a;
    104 }
    105 
    106 static void Add16(SkColorMatrixFilter::State* state,
    107                   unsigned r, unsigned g, unsigned b, unsigned a) {
    108     const int32_t* SK_RESTRICT array = state->fArray;
    109     int32_t* SK_RESTRICT result = state->fResult;
    110 
    111     result[0] = r + (array[4] >> 16);
    112     result[1] = g + (array[9] >> 16);
    113     result[2] = b + (array[14] >> 16);
    114     result[3] = a;
    115 }
    116 
    117 #define kNO_ALPHA_FLAGS (SkColorFilter::kAlphaUnchanged_Flag |  \
    118                          SkColorFilter::kHasFilter16_Flag)
    119 
    120 // src is [20] but some compilers won't accept __restrict__ on anything
    121 // but an raw pointer or reference
    122 void SkColorMatrixFilter::setup(const SkScalar* SK_RESTRICT src) {
    123     if (NULL == src) {
    124         fProc = NULL;   // signals identity
    125         fFlags  = kNO_ALPHA_FLAGS;
    126         // fState is undefined, but that is OK, since we shouldn't look at it
    127         return;
    128     }
    129 
    130     int32_t* array = fState.fArray;
    131 
    132     int i;
    133     SkFixed max = 0;
    134 
    135     for (int i = 0; i < 20; i++) {
    136         SkFixed value = SkScalarToFixed(src[i]);
    137         array[i] = value;
    138         value = SkAbs32(value);
    139         max = SkMax32(max, value);
    140     }
    141 
    142     /*  All of fArray[] values must fit in 23 bits, to safely allow me to
    143         multiply them by 8bit unsigned values, and get a signed answer without
    144         overflow. This means clz needs to be 9 or bigger
    145     */
    146     int bits = SkCLZ(max);
    147     int32_t one = SK_Fixed1;
    148 
    149     fState.fShift = 16; // we are starting out as fixed 16.16
    150     if (bits < 9) {
    151         bits = 9 - bits;
    152         fState.fShift -= bits;
    153         for (i = 0; i < 20; i++) {
    154             array[i] >>= bits;
    155         }
    156         one >>= bits;
    157     }
    158 
    159     // check if we have to munge Alpha
    160     int32_t changesAlpha = (array[15] | array[16] | array[17] |
    161                             (array[18] - one) | array[19]);
    162     int32_t usesAlpha = (array[3] | array[8] | array[13]);
    163     bool shiftIs16 = (16 == fState.fShift);
    164 
    165     if (changesAlpha | usesAlpha) {
    166         fProc = shiftIs16 ? General16 : General;
    167         fFlags = changesAlpha ? 0 : SkColorFilter::kAlphaUnchanged_Flag;
    168     } else {
    169         fFlags = kNO_ALPHA_FLAGS;
    170 
    171         int32_t needsScale = (array[0] - one) |       // red axis
    172                              (array[6] - one) |       // green axis
    173                              (array[12] - one);       // blue axis
    174 
    175         int32_t needs3x3 =  array[1] | array[2] |     // red off-axis
    176                             array[5] | array[7] |     // green off-axis
    177                             array[10] | array[11];    // blue off-axis
    178 
    179         if (needs3x3) {
    180             fProc = shiftIs16 ? AffineAdd16 : AffineAdd;
    181         } else if (needsScale) {
    182             fProc = shiftIs16 ? ScaleAdd16 : ScaleAdd;
    183         } else if (array[4] | array[9] | array[14]) {   // needs add
    184             fProc = shiftIs16 ? Add16 : Add;
    185         } else {
    186             fProc = NULL;   // identity
    187         }
    188     }
    189 
    190     /*  preround our add values so we get a rounded shift. We do this after we
    191         analyze the array, so we don't miss the case where the caller has zeros
    192         which could make us accidentally take the General or Add case.
    193     */
    194     if (NULL != fProc) {
    195         int32_t add = 1 << (fState.fShift - 1);
    196         array[4] += add;
    197         array[9] += add;
    198         array[14] += add;
    199         array[19] += add;
    200     }
    201 }
    202 
    203 ///////////////////////////////////////////////////////////////////////////////
    204 
    205 static int32_t pin(int32_t value, int32_t max) {
    206     if (value < 0) {
    207         value = 0;
    208     }
    209     if (value > max) {
    210         value = max;
    211     }
    212     return value;
    213 }
    214 
    215 SkColorMatrixFilter::SkColorMatrixFilter() {
    216     this->setup(NULL);
    217 }
    218 
    219 SkColorMatrixFilter::SkColorMatrixFilter(const SkColorMatrix& cm) {
    220     this->setup(cm.fMat);
    221 }
    222 
    223 SkColorMatrixFilter::SkColorMatrixFilter(const SkScalar array[20]) {
    224     this->setup(array);
    225 }
    226 
    227 uint32_t SkColorMatrixFilter::getFlags() {
    228     return this->INHERITED::getFlags() | fFlags;
    229 }
    230 
    231 void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count,
    232                                      SkPMColor dst[]) {
    233     Proc proc = fProc;
    234     State* state = &fState;
    235     int32_t* result = state->fResult;
    236 
    237     if (NULL == proc) {
    238         if (src != dst) {
    239             memcpy(dst, src, count * sizeof(SkPMColor));
    240         }
    241         return;
    242     }
    243 
    244     const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
    245 
    246     for (int i = 0; i < count; i++) {
    247         SkPMColor c = src[i];
    248 
    249         unsigned r = SkGetPackedR32(c);
    250         unsigned g = SkGetPackedG32(c);
    251         unsigned b = SkGetPackedB32(c);
    252         unsigned a = SkGetPackedA32(c);
    253 
    254         // need our components to be un-premultiplied
    255         if (255 != a) {
    256             SkUnPreMultiply::Scale scale = table[a];
    257             r = SkUnPreMultiply::ApplyScale(scale, r);
    258             g = SkUnPreMultiply::ApplyScale(scale, g);
    259             b = SkUnPreMultiply::ApplyScale(scale, b);
    260 
    261             SkASSERT(r <= 255);
    262             SkASSERT(g <= 255);
    263             SkASSERT(b <= 255);
    264         }
    265 
    266         proc(state, r, g, b, a);
    267 
    268         r = pin(result[0], SK_R32_MASK);
    269         g = pin(result[1], SK_G32_MASK);
    270         b = pin(result[2], SK_B32_MASK);
    271         a = pin(result[3], SK_A32_MASK);
    272         // re-prepremultiply if needed
    273         dst[i] = SkPremultiplyARGBInline(a, r, g, b);
    274     }
    275 }
    276 
    277 void SkColorMatrixFilter::filterSpan16(const uint16_t src[], int count,
    278                                        uint16_t dst[]) {
    279     SkASSERT(fFlags & SkColorFilter::kHasFilter16_Flag);
    280 
    281     Proc   proc = fProc;
    282     State* state = &fState;
    283     int32_t* result = state->fResult;
    284 
    285     if (NULL == proc) {
    286         if (src != dst) {
    287             memcpy(dst, src, count * sizeof(uint16_t));
    288         }
    289         return;
    290     }
    291 
    292     for (int i = 0; i < count; i++) {
    293         uint16_t c = src[i];
    294 
    295         // expand to 8bit components (since our matrix translate is 8bit biased
    296         unsigned r = SkPacked16ToR32(c);
    297         unsigned g = SkPacked16ToG32(c);
    298         unsigned b = SkPacked16ToB32(c);
    299 
    300         proc(state, r, g, b, 0);
    301 
    302         r = pin(result[0], SK_R32_MASK);
    303         g = pin(result[1], SK_G32_MASK);
    304         b = pin(result[2], SK_B32_MASK);
    305 
    306         // now packed it back down to 16bits (hmmm, could dither...)
    307         dst[i] = SkPack888ToRGB16(r, g, b);
    308     }
    309 }
    310 
    311 ///////////////////////////////////////////////////////////////////////////////
    312 
    313 void SkColorMatrixFilter::flatten(SkFlattenableWriteBuffer& buffer)  {
    314     this->INHERITED::flatten(buffer);
    315 
    316     buffer.writeFunctionPtr((void*)fProc);
    317     buffer.writeMul4(&fState, sizeof(fState));
    318     buffer.write32(fFlags);
    319 }
    320 
    321 SkFlattenable::Factory SkColorMatrixFilter::getFactory() { return CreateProc;  }
    322 
    323 SkColorMatrixFilter::SkColorMatrixFilter(SkFlattenableReadBuffer& buffer)
    324         : INHERITED(buffer) {
    325     fProc = (Proc)buffer.readFunctionPtr();
    326     buffer.read(&fState, sizeof(fState));
    327     fFlags = buffer.readU32();
    328 }
    329 
    330 bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) {
    331     int32_t* array = fState.fArray;
    332     int unshift = 16 - fState.fShift;
    333     for (int i = 0; i < 20; i++) {
    334         matrix[i] = SkFixedToScalar(array[i] << unshift);
    335     }
    336     if (NULL != fProc) {
    337         // Undo the offset applied to the constant column in setup().
    338         SkFixed offset = 1 << (fState.fShift - 1);
    339         matrix[4] = SkFixedToScalar((array[4] - offset) << unshift);
    340         matrix[9] = SkFixedToScalar((array[9] - offset) << unshift);
    341         matrix[14] = SkFixedToScalar((array[14] - offset) << unshift);
    342         matrix[19] = SkFixedToScalar((array[19] - offset) << unshift);
    343     }
    344     return true;
    345 }
    346 
    347 SkFlattenable* SkColorMatrixFilter::CreateProc(SkFlattenableReadBuffer& buf) {
    348     return SkNEW_ARGS(SkColorMatrixFilter, (buf));
    349 }
    350 
    351 void SkColorMatrixFilter::setMatrix(const SkColorMatrix& matrix) {
    352     setup(matrix.fMat);
    353 }
    354 
    355 void SkColorMatrixFilter::setArray(const SkScalar array[20]) {
    356     setup(array);
    357 }
    358 
    359 SK_DEFINE_FLATTENABLE_REGISTRAR(SkColorMatrixFilter)
    360