Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2006 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 #include "SkAvoidXfermode.h"
      9 #include "SkColorPriv.h"
     10 #include "SkReadBuffer.h"
     11 #include "SkWriteBuffer.h"
     12 #include "SkString.h"
     13 
     14 SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) {
     15     if (tolerance > 255) {
     16         tolerance = 255;
     17     }
     18     fTolerance = SkToU8(tolerance);
     19     fOpColor = opColor;
     20     fDistMul = (256 << 14) / (tolerance + 1);
     21     fMode = mode;
     22 }
     23 
     24 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
     25 SkAvoidXfermode::SkAvoidXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {
     26     fOpColor = buffer.readColor();
     27     fDistMul = buffer.readUInt();
     28     fMode = (Mode)buffer.readUInt();
     29 }
     30 #endif
     31 
     32 SkFlattenable* SkAvoidXfermode::CreateProc(SkReadBuffer& buffer) {
     33     const SkColor color = buffer.readColor();
     34     const unsigned tolerance = buffer.readUInt();
     35     const unsigned mode = buffer.readUInt();
     36     return Create(color, tolerance, (Mode)mode);
     37 }
     38 
     39 void SkAvoidXfermode::flatten(SkWriteBuffer& buffer) const {
     40     buffer.writeColor(fOpColor);
     41     buffer.writeUInt(fTolerance);
     42     buffer.writeUInt(fMode);
     43 }
     44 
     45 // returns 0..31
     46 static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) {
     47     SkASSERT(r <= SK_R16_MASK);
     48     SkASSERT(g <= SK_G16_MASK);
     49     SkASSERT(b <= SK_B16_MASK);
     50 
     51     unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
     52     unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
     53     unsigned db = SkAbs32(SkGetPackedB16(c) - b);
     54 
     55     return SkMax32(dr, SkMax32(dg, db));
     56 }
     57 
     58 // returns 0..255
     59 static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) {
     60     SkASSERT(r <= 0xFF);
     61     SkASSERT(g <= 0xFF);
     62     SkASSERT(b <= 0xFF);
     63 
     64     unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
     65     unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
     66     unsigned db = SkAbs32(SkGetPackedB32(c) - b);
     67 
     68     return SkMax32(dr, SkMax32(dg, db));
     69 }
     70 
     71 static int scale_dist_14(int dist, uint32_t mul, uint32_t sub) {
     72     int tmp = dist * mul - sub;
     73     int result = (tmp + (1 << 13)) >> 14;
     74 
     75     return result;
     76 }
     77 
     78 static inline unsigned Accurate255To256(unsigned x) {
     79     return x + (x >> 7);
     80 }
     81 
     82 void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
     83                              const SkAlpha aa[]) const {
     84     unsigned    opR = SkColorGetR(fOpColor);
     85     unsigned    opG = SkColorGetG(fOpColor);
     86     unsigned    opB = SkColorGetB(fOpColor);
     87     uint32_t    mul = fDistMul;
     88     uint32_t    sub = (fDistMul - (1 << 14)) << 8;
     89 
     90     int MAX, mask;
     91 
     92     if (kTargetColor_Mode == fMode) {
     93         mask = -1;
     94         MAX = 255;
     95     } else {
     96         mask = 0;
     97         MAX = 0;
     98     }
     99 
    100     for (int i = 0; i < count; i++) {
    101         int d = color_dist32(dst[i], opR, opG, opB);
    102         // now reverse d if we need to
    103         d = MAX + (d ^ mask) - mask;
    104         SkASSERT((unsigned)d <= 255);
    105         d = Accurate255To256(d);
    106 
    107         d = scale_dist_14(d, mul, sub);
    108         SkASSERT(d <= 256);
    109 
    110         if (d > 0) {
    111             if (aa) {
    112                 d = SkAlphaMul(d, Accurate255To256(*aa++));
    113                 if (0 == d) {
    114                     continue;
    115                 }
    116             }
    117             dst[i] = SkFourByteInterp256(src[i], dst[i], d);
    118         }
    119     }
    120 }
    121 
    122 static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) {
    123     SkASSERT(scale <= 32);
    124     scale <<= 3;
    125 
    126     return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
    127                         SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
    128                         SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
    129 }
    130 
    131 void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
    132                              const SkAlpha aa[]) const {
    133     unsigned    opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
    134     unsigned    opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
    135     unsigned    opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
    136     uint32_t    mul = fDistMul;
    137     uint32_t    sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
    138 
    139     int MAX, mask;
    140 
    141     if (kTargetColor_Mode == fMode) {
    142         mask = -1;
    143         MAX = 31;
    144     } else {
    145         mask = 0;
    146         MAX = 0;
    147     }
    148 
    149     for (int i = 0; i < count; i++) {
    150         int d = color_dist16(dst[i], opR, opG, opB);
    151         // now reverse d if we need to
    152         d = MAX + (d ^ mask) - mask;
    153         SkASSERT((unsigned)d <= 31);
    154         // convert from 0..31 to 0..32
    155         d += d >> 4;
    156         d = scale_dist_14(d, mul, sub);
    157         SkASSERT(d <= 32);
    158 
    159         if (d > 0) {
    160             if (aa) {
    161                 d = SkAlphaMul(d, Accurate255To256(*aa++));
    162                 if (0 == d) {
    163                     continue;
    164                 }
    165             }
    166             dst[i] = SkBlend3216(src[i], dst[i], d);
    167         }
    168     }
    169 }
    170 
    171 void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
    172                              const SkAlpha aa[]) const {
    173     // override in subclass
    174 }
    175 
    176 #ifndef SK_IGNORE_TO_STRING
    177 void SkAvoidXfermode::toString(SkString* str) const {
    178     str->append("SkAvoidXfermode: opColor: ");
    179     str->appendHex(fOpColor);
    180     str->appendf("distMul: %d ", fDistMul);
    181 
    182     static const char* gModeStrings[] = { "Avoid", "Target" };
    183 
    184     str->appendf("mode: %s", gModeStrings[fMode]);
    185 }
    186 #endif
    187