gfx/skia/trunk/src/core/SkXfermode.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/core/SkXfermode.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1992 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2006 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +#include "SkXfermode.h"
    1.14 +#include "SkXfermode_proccoeff.h"
    1.15 +#include "SkColorPriv.h"
    1.16 +#include "SkReadBuffer.h"
    1.17 +#include "SkWriteBuffer.h"
    1.18 +#include "SkMathPriv.h"
    1.19 +#include "SkString.h"
    1.20 +#include "SkUtilsArm.h"
    1.21 +
    1.22 +#if !SK_ARM_NEON_IS_NONE
    1.23 +#include "SkXfermode_opts_arm_neon.h"
    1.24 +#endif
    1.25 +
    1.26 +#define SkAlphaMulAlpha(a, b)   SkMulDiv255Round(a, b)
    1.27 +
    1.28 +#if 0
    1.29 +// idea for higher precision blends in xfer procs (and slightly faster)
    1.30 +// see DstATop as a probable caller
    1.31 +static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
    1.32 +    SkASSERT(a <= 255);
    1.33 +    SkASSERT(b <= 255);
    1.34 +    SkASSERT(c <= 255);
    1.35 +    SkASSERT(d <= 255);
    1.36 +    unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
    1.37 +    unsigned result = (prod + (prod >> 8)) >> 8;
    1.38 +    SkASSERT(result <= 255);
    1.39 +    return result;
    1.40 +}
    1.41 +#endif
    1.42 +
    1.43 +static inline unsigned saturated_add(unsigned a, unsigned b) {
    1.44 +    SkASSERT(a <= 255);
    1.45 +    SkASSERT(b <= 255);
    1.46 +    unsigned sum = a + b;
    1.47 +    if (sum > 255) {
    1.48 +        sum = 255;
    1.49 +    }
    1.50 +    return sum;
    1.51 +}
    1.52 +
    1.53 +static inline int clamp_signed_byte(int n) {
    1.54 +    if (n < 0) {
    1.55 +        n = 0;
    1.56 +    } else if (n > 255) {
    1.57 +        n = 255;
    1.58 +    }
    1.59 +    return n;
    1.60 +}
    1.61 +
    1.62 +static inline int clamp_div255round(int prod) {
    1.63 +    if (prod <= 0) {
    1.64 +        return 0;
    1.65 +    } else if (prod >= 255*255) {
    1.66 +        return 255;
    1.67 +    } else {
    1.68 +        return SkDiv255Round(prod);
    1.69 +    }
    1.70 +}
    1.71 +
    1.72 +///////////////////////////////////////////////////////////////////////////////
    1.73 +
    1.74 +//  kClear_Mode,    //!< [0, 0]
    1.75 +static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
    1.76 +    return 0;
    1.77 +}
    1.78 +
    1.79 +//  kSrc_Mode,      //!< [Sa, Sc]
    1.80 +static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
    1.81 +    return src;
    1.82 +}
    1.83 +
    1.84 +//  kDst_Mode,      //!< [Da, Dc]
    1.85 +static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
    1.86 +    return dst;
    1.87 +}
    1.88 +
    1.89 +//  kSrcOver_Mode,  //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
    1.90 +static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
    1.91 +#if 0
    1.92 +    // this is the old, more-correct way, but it doesn't guarantee that dst==255
    1.93 +    // will always stay opaque
    1.94 +    return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
    1.95 +#else
    1.96 +    // this is slightly faster, but more importantly guarantees that dst==255
    1.97 +    // will always stay opaque
    1.98 +    return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
    1.99 +#endif
   1.100 +}
   1.101 +
   1.102 +//  kDstOver_Mode,  //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
   1.103 +static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
   1.104 +    // this is the reverse of srcover, just flipping src and dst
   1.105 +    // see srcover's comment about the 256 for opaqueness guarantees
   1.106 +    return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
   1.107 +}
   1.108 +
   1.109 +//  kSrcIn_Mode,    //!< [Sa * Da, Sc * Da]
   1.110 +static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
   1.111 +    return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
   1.112 +}
   1.113 +
   1.114 +//  kDstIn_Mode,    //!< [Sa * Da, Sa * Dc]
   1.115 +static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
   1.116 +    return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
   1.117 +}
   1.118 +
   1.119 +//  kSrcOut_Mode,   //!< [Sa * (1 - Da), Sc * (1 - Da)]
   1.120 +static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
   1.121 +    return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
   1.122 +}
   1.123 +
   1.124 +//  kDstOut_Mode,   //!< [Da * (1 - Sa), Dc * (1 - Sa)]
   1.125 +static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
   1.126 +    return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
   1.127 +}
   1.128 +
   1.129 +//  kSrcATop_Mode,  //!< [Da, Sc * Da + (1 - Sa) * Dc]
   1.130 +static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
   1.131 +    unsigned sa = SkGetPackedA32(src);
   1.132 +    unsigned da = SkGetPackedA32(dst);
   1.133 +    unsigned isa = 255 - sa;
   1.134 +
   1.135 +    return SkPackARGB32(da,
   1.136 +                        SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
   1.137 +                            SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
   1.138 +                        SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
   1.139 +                            SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
   1.140 +                        SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
   1.141 +                            SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
   1.142 +}
   1.143 +
   1.144 +//  kDstATop_Mode,  //!< [Sa, Sa * Dc + Sc * (1 - Da)]
   1.145 +static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
   1.146 +    unsigned sa = SkGetPackedA32(src);
   1.147 +    unsigned da = SkGetPackedA32(dst);
   1.148 +    unsigned ida = 255 - da;
   1.149 +
   1.150 +    return SkPackARGB32(sa,
   1.151 +                        SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
   1.152 +                            SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
   1.153 +                        SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
   1.154 +                            SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
   1.155 +                        SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
   1.156 +                            SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
   1.157 +}
   1.158 +
   1.159 +//  kXor_Mode   [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
   1.160 +static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
   1.161 +    unsigned sa = SkGetPackedA32(src);
   1.162 +    unsigned da = SkGetPackedA32(dst);
   1.163 +    unsigned isa = 255 - sa;
   1.164 +    unsigned ida = 255 - da;
   1.165 +
   1.166 +    return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
   1.167 +                        SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
   1.168 +                            SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
   1.169 +                        SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
   1.170 +                            SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
   1.171 +                        SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
   1.172 +                            SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
   1.173 +}
   1.174 +
   1.175 +///////////////////////////////////////////////////////////////////////////////
   1.176 +
   1.177 +// kPlus_Mode
   1.178 +static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
   1.179 +    unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
   1.180 +    unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
   1.181 +    unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
   1.182 +    unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
   1.183 +    return SkPackARGB32(a, r, g, b);
   1.184 +}
   1.185 +
   1.186 +// kModulate_Mode
   1.187 +static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) {
   1.188 +    int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
   1.189 +    int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
   1.190 +    int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
   1.191 +    int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
   1.192 +    return SkPackARGB32(a, r, g, b);
   1.193 +}
   1.194 +
   1.195 +static inline int srcover_byte(int a, int b) {
   1.196 +    return a + b - SkAlphaMulAlpha(a, b);
   1.197 +}
   1.198 +
   1.199 +// kMultiply_Mode
   1.200 +// B(Cb, Cs) = Cb x Cs
   1.201 +// multiply uses its own version of blendfunc_byte because sa and da are not needed
   1.202 +static int blendfunc_multiply_byte(int sc, int dc, int sa, int da) {
   1.203 +    return clamp_div255round(sc * (255 - da)  + dc * (255 - sa)  + sc * dc);
   1.204 +}
   1.205 +
   1.206 +static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
   1.207 +    int sa = SkGetPackedA32(src);
   1.208 +    int da = SkGetPackedA32(dst);
   1.209 +    int a = srcover_byte(sa, da);
   1.210 +    int r = blendfunc_multiply_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
   1.211 +    int g = blendfunc_multiply_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
   1.212 +    int b = blendfunc_multiply_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
   1.213 +    return SkPackARGB32(a, r, g, b);
   1.214 +}
   1.215 +
   1.216 +// kScreen_Mode
   1.217 +static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
   1.218 +    int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
   1.219 +    int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
   1.220 +    int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
   1.221 +    int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
   1.222 +    return SkPackARGB32(a, r, g, b);
   1.223 +}
   1.224 +
   1.225 +// kOverlay_Mode
   1.226 +static inline int overlay_byte(int sc, int dc, int sa, int da) {
   1.227 +    int tmp = sc * (255 - da) + dc * (255 - sa);
   1.228 +    int rc;
   1.229 +    if (2 * dc <= da) {
   1.230 +        rc = 2 * sc * dc;
   1.231 +    } else {
   1.232 +        rc = sa * da - 2 * (da - dc) * (sa - sc);
   1.233 +    }
   1.234 +    return clamp_div255round(rc + tmp);
   1.235 +}
   1.236 +static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
   1.237 +    int sa = SkGetPackedA32(src);
   1.238 +    int da = SkGetPackedA32(dst);
   1.239 +    int a = srcover_byte(sa, da);
   1.240 +    int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
   1.241 +    int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
   1.242 +    int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
   1.243 +    return SkPackARGB32(a, r, g, b);
   1.244 +}
   1.245 +
   1.246 +// kDarken_Mode
   1.247 +static inline int darken_byte(int sc, int dc, int sa, int da) {
   1.248 +    int sd = sc * da;
   1.249 +    int ds = dc * sa;
   1.250 +    if (sd < ds) {
   1.251 +        // srcover
   1.252 +        return sc + dc - SkDiv255Round(ds);
   1.253 +    } else {
   1.254 +        // dstover
   1.255 +        return dc + sc - SkDiv255Round(sd);
   1.256 +    }
   1.257 +}
   1.258 +static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
   1.259 +    int sa = SkGetPackedA32(src);
   1.260 +    int da = SkGetPackedA32(dst);
   1.261 +    int a = srcover_byte(sa, da);
   1.262 +    int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
   1.263 +    int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
   1.264 +    int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
   1.265 +    return SkPackARGB32(a, r, g, b);
   1.266 +}
   1.267 +
   1.268 +// kLighten_Mode
   1.269 +static inline int lighten_byte(int sc, int dc, int sa, int da) {
   1.270 +    int sd = sc * da;
   1.271 +    int ds = dc * sa;
   1.272 +    if (sd > ds) {
   1.273 +        // srcover
   1.274 +        return sc + dc - SkDiv255Round(ds);
   1.275 +    } else {
   1.276 +        // dstover
   1.277 +        return dc + sc - SkDiv255Round(sd);
   1.278 +    }
   1.279 +}
   1.280 +static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
   1.281 +    int sa = SkGetPackedA32(src);
   1.282 +    int da = SkGetPackedA32(dst);
   1.283 +    int a = srcover_byte(sa, da);
   1.284 +    int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
   1.285 +    int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
   1.286 +    int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
   1.287 +    return SkPackARGB32(a, r, g, b);
   1.288 +}
   1.289 +
   1.290 +// kColorDodge_Mode
   1.291 +static inline int colordodge_byte(int sc, int dc, int sa, int da) {
   1.292 +    int diff = sa - sc;
   1.293 +    int rc;
   1.294 +    if (0 == dc) {
   1.295 +        return SkAlphaMulAlpha(sc, 255 - da);
   1.296 +    } else if (0 == diff) {
   1.297 +        rc = sa * da + sc * (255 - da) + dc * (255 - sa);
   1.298 +    } else {
   1.299 +        diff = dc * sa / diff;
   1.300 +        rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa);
   1.301 +    }
   1.302 +    return clamp_div255round(rc);
   1.303 +}
   1.304 +static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
   1.305 +    int sa = SkGetPackedA32(src);
   1.306 +    int da = SkGetPackedA32(dst);
   1.307 +    int a = srcover_byte(sa, da);
   1.308 +    int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
   1.309 +    int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
   1.310 +    int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
   1.311 +    return SkPackARGB32(a, r, g, b);
   1.312 +}
   1.313 +
   1.314 +// kColorBurn_Mode
   1.315 +static inline int colorburn_byte(int sc, int dc, int sa, int da) {
   1.316 +    int rc;
   1.317 +    if (dc == da) {
   1.318 +        rc = sa * da + sc * (255 - da) + dc * (255 - sa);
   1.319 +    } else if (0 == sc) {
   1.320 +        return SkAlphaMulAlpha(dc, 255 - sa);
   1.321 +    } else {
   1.322 +        int tmp = (da - dc) * sa / sc;
   1.323 +        rc = sa * (da - ((da < tmp) ? da : tmp))
   1.324 +            + sc * (255 - da) + dc * (255 - sa);
   1.325 +    }
   1.326 +    return clamp_div255round(rc);
   1.327 +}
   1.328 +static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
   1.329 +    int sa = SkGetPackedA32(src);
   1.330 +    int da = SkGetPackedA32(dst);
   1.331 +    int a = srcover_byte(sa, da);
   1.332 +    int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
   1.333 +    int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
   1.334 +    int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
   1.335 +    return SkPackARGB32(a, r, g, b);
   1.336 +}
   1.337 +
   1.338 +// kHardLight_Mode
   1.339 +static inline int hardlight_byte(int sc, int dc, int sa, int da) {
   1.340 +    int rc;
   1.341 +    if (2 * sc <= sa) {
   1.342 +        rc = 2 * sc * dc;
   1.343 +    } else {
   1.344 +        rc = sa * da - 2 * (da - dc) * (sa - sc);
   1.345 +    }
   1.346 +    return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
   1.347 +}
   1.348 +static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
   1.349 +    int sa = SkGetPackedA32(src);
   1.350 +    int da = SkGetPackedA32(dst);
   1.351 +    int a = srcover_byte(sa, da);
   1.352 +    int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
   1.353 +    int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
   1.354 +    int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
   1.355 +    return SkPackARGB32(a, r, g, b);
   1.356 +}
   1.357 +
   1.358 +// returns 255 * sqrt(n/255)
   1.359 +static U8CPU sqrt_unit_byte(U8CPU n) {
   1.360 +    return SkSqrtBits(n, 15+4);
   1.361 +}
   1.362 +
   1.363 +// kSoftLight_Mode
   1.364 +static inline int softlight_byte(int sc, int dc, int sa, int da) {
   1.365 +    int m = da ? dc * 256 / da : 0;
   1.366 +    int rc;
   1.367 +    if (2 * sc <= sa) {
   1.368 +        rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
   1.369 +    } else if (4 * dc <= da) {
   1.370 +        int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
   1.371 +        rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
   1.372 +    } else {
   1.373 +        int tmp = sqrt_unit_byte(m) - m;
   1.374 +        rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
   1.375 +    }
   1.376 +    return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
   1.377 +}
   1.378 +static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
   1.379 +    int sa = SkGetPackedA32(src);
   1.380 +    int da = SkGetPackedA32(dst);
   1.381 +    int a = srcover_byte(sa, da);
   1.382 +    int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
   1.383 +    int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
   1.384 +    int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
   1.385 +    return SkPackARGB32(a, r, g, b);
   1.386 +}
   1.387 +
   1.388 +// kDifference_Mode
   1.389 +static inline int difference_byte(int sc, int dc, int sa, int da) {
   1.390 +    int tmp = SkMin32(sc * da, dc * sa);
   1.391 +    return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
   1.392 +}
   1.393 +static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
   1.394 +    int sa = SkGetPackedA32(src);
   1.395 +    int da = SkGetPackedA32(dst);
   1.396 +    int a = srcover_byte(sa, da);
   1.397 +    int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
   1.398 +    int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
   1.399 +    int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
   1.400 +    return SkPackARGB32(a, r, g, b);
   1.401 +}
   1.402 +
   1.403 +// kExclusion_Mode
   1.404 +static inline int exclusion_byte(int sc, int dc, int, int) {
   1.405 +    // this equations is wacky, wait for SVG to confirm it
   1.406 +    //int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
   1.407 +
   1.408 +    // The above equation can be simplified as follows
   1.409 +    int r = 255*(sc + dc) - 2 * sc * dc;
   1.410 +    return clamp_div255round(r);
   1.411 +}
   1.412 +static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
   1.413 +    int sa = SkGetPackedA32(src);
   1.414 +    int da = SkGetPackedA32(dst);
   1.415 +    int a = srcover_byte(sa, da);
   1.416 +    int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
   1.417 +    int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
   1.418 +    int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
   1.419 +    return SkPackARGB32(a, r, g, b);
   1.420 +}
   1.421 +
   1.422 +// The CSS compositing spec introduces the following formulas:
   1.423 +// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
   1.424 +// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
   1.425 +// while PDF and CG uses the one from Rec. Rec. 601
   1.426 +// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
   1.427 +static inline int Lum(int r, int g, int b)
   1.428 +{
   1.429 +    return SkDiv255Round(r * 77 + g * 150 + b * 28);
   1.430 +}
   1.431 +
   1.432 +static inline int min2(int a, int b) { return a < b ? a : b; }
   1.433 +static inline int max2(int a, int b) { return a > b ? a : b; }
   1.434 +#define minimum(a, b, c) min2(min2(a, b), c)
   1.435 +#define maximum(a, b, c) max2(max2(a, b), c)
   1.436 +
   1.437 +static inline int Sat(int r, int g, int b) {
   1.438 +    return maximum(r, g, b) - minimum(r, g, b);
   1.439 +}
   1.440 +
   1.441 +static inline void setSaturationComponents(int* Cmin, int* Cmid, int* Cmax, int s) {
   1.442 +    if(*Cmax > *Cmin) {
   1.443 +        *Cmid =  SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin);
   1.444 +        *Cmax = s;
   1.445 +    } else {
   1.446 +        *Cmax = 0;
   1.447 +        *Cmid = 0;
   1.448 +    }
   1.449 +
   1.450 +    *Cmin = 0;
   1.451 +}
   1.452 +
   1.453 +static inline void SetSat(int* r, int* g, int* b, int s) {
   1.454 +    if(*r <= *g) {
   1.455 +        if(*g <= *b) {
   1.456 +            setSaturationComponents(r, g, b, s);
   1.457 +        } else if(*r <= *b) {
   1.458 +            setSaturationComponents(r, b, g, s);
   1.459 +        } else {
   1.460 +            setSaturationComponents(b, r, g, s);
   1.461 +        }
   1.462 +    } else if(*r <= *b) {
   1.463 +        setSaturationComponents(g, r, b, s);
   1.464 +    } else if(*g <= *b) {
   1.465 +        setSaturationComponents(g, b, r, s);
   1.466 +    } else {
   1.467 +        setSaturationComponents(b, g, r, s);
   1.468 +    }
   1.469 +}
   1.470 +
   1.471 +static inline void clipColor(int* r, int* g, int* b, int a) {
   1.472 +    int L = Lum(*r, *g, *b);
   1.473 +    int n = minimum(*r, *g, *b);
   1.474 +    int x = maximum(*r, *g, *b);
   1.475 +    int denom;
   1.476 +    if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
   1.477 +       *r = L + SkMulDiv(*r - L, L, denom);
   1.478 +       *g = L + SkMulDiv(*g - L, L, denom);
   1.479 +       *b = L + SkMulDiv(*b - L, L, denom);
   1.480 +    }
   1.481 +
   1.482 +    if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
   1.483 +       int numer = a - L;
   1.484 +       *r = L + SkMulDiv(*r - L, numer, denom);
   1.485 +       *g = L + SkMulDiv(*g - L, numer, denom);
   1.486 +       *b = L + SkMulDiv(*b - L, numer, denom);
   1.487 +    }
   1.488 +}
   1.489 +
   1.490 +static inline void SetLum(int* r, int* g, int* b, int a, int l) {
   1.491 +  int d = l - Lum(*r, *g, *b);
   1.492 +  *r +=  d;
   1.493 +  *g +=  d;
   1.494 +  *b +=  d;
   1.495 +
   1.496 +  clipColor(r, g, b, a);
   1.497 +}
   1.498 +
   1.499 +// non-separable blend modes are done in non-premultiplied alpha
   1.500 +#define  blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \
   1.501 +  clamp_div255round(sc * (255 - da) +  dc * (255 - sa) + blendval)
   1.502 +
   1.503 +// kHue_Mode
   1.504 +// B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
   1.505 +// Create a color with the hue of the source color and the saturation and luminosity of the backdrop color.
   1.506 +static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) {
   1.507 +    int sr = SkGetPackedR32(src);
   1.508 +    int sg = SkGetPackedG32(src);
   1.509 +    int sb = SkGetPackedB32(src);
   1.510 +    int sa = SkGetPackedA32(src);
   1.511 +
   1.512 +    int dr = SkGetPackedR32(dst);
   1.513 +    int dg = SkGetPackedG32(dst);
   1.514 +    int db = SkGetPackedB32(dst);
   1.515 +    int da = SkGetPackedA32(dst);
   1.516 +    int Sr, Sg, Sb;
   1.517 +
   1.518 +    if(sa && da) {
   1.519 +        Sr = sr * sa;
   1.520 +        Sg = sg * sa;
   1.521 +        Sb = sb * sa;
   1.522 +        SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
   1.523 +        SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
   1.524 +    } else {
   1.525 +        Sr = 0;
   1.526 +        Sg = 0;
   1.527 +        Sb = 0;
   1.528 +    }
   1.529 +
   1.530 +    int a = srcover_byte(sa, da);
   1.531 +    int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
   1.532 +    int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
   1.533 +    int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
   1.534 +    return SkPackARGB32(a, r, g, b);
   1.535 +}
   1.536 +
   1.537 +// kSaturation_Mode
   1.538 +// B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
   1.539 +// Create a color with the saturation of the source color and the hue and luminosity of the backdrop color.
   1.540 +static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) {
   1.541 +    int sr = SkGetPackedR32(src);
   1.542 +    int sg = SkGetPackedG32(src);
   1.543 +    int sb = SkGetPackedB32(src);
   1.544 +    int sa = SkGetPackedA32(src);
   1.545 +
   1.546 +    int dr = SkGetPackedR32(dst);
   1.547 +    int dg = SkGetPackedG32(dst);
   1.548 +    int db = SkGetPackedB32(dst);
   1.549 +    int da = SkGetPackedA32(dst);
   1.550 +    int Dr, Dg, Db;
   1.551 +
   1.552 +    if(sa && da) {
   1.553 +        Dr = dr * sa;
   1.554 +        Dg = dg * sa;
   1.555 +        Db = db * sa;
   1.556 +        SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
   1.557 +        SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
   1.558 +    } else {
   1.559 +        Dr = 0;
   1.560 +        Dg = 0;
   1.561 +        Db = 0;
   1.562 +    }
   1.563 +
   1.564 +    int a = srcover_byte(sa, da);
   1.565 +    int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
   1.566 +    int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
   1.567 +    int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
   1.568 +    return SkPackARGB32(a, r, g, b);
   1.569 +}
   1.570 +
   1.571 +// kColor_Mode
   1.572 +// B(Cb, Cs) = SetLum(Cs, Lum(Cb))
   1.573 +// Create a color with the hue and saturation of the source color and the luminosity of the backdrop color.
   1.574 +static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) {
   1.575 +    int sr = SkGetPackedR32(src);
   1.576 +    int sg = SkGetPackedG32(src);
   1.577 +    int sb = SkGetPackedB32(src);
   1.578 +    int sa = SkGetPackedA32(src);
   1.579 +
   1.580 +    int dr = SkGetPackedR32(dst);
   1.581 +    int dg = SkGetPackedG32(dst);
   1.582 +    int db = SkGetPackedB32(dst);
   1.583 +    int da = SkGetPackedA32(dst);
   1.584 +    int Sr, Sg, Sb;
   1.585 +
   1.586 +    if(sa && da) {
   1.587 +        Sr = sr * da;
   1.588 +        Sg = sg * da;
   1.589 +        Sb = sb * da;
   1.590 +        SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
   1.591 +    } else {
   1.592 +        Sr = 0;
   1.593 +        Sg = 0;
   1.594 +        Sb = 0;
   1.595 +    }
   1.596 +
   1.597 +    int a = srcover_byte(sa, da);
   1.598 +    int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
   1.599 +    int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
   1.600 +    int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
   1.601 +    return SkPackARGB32(a, r, g, b);
   1.602 +}
   1.603 +
   1.604 +// kLuminosity_Mode
   1.605 +// B(Cb, Cs) = SetLum(Cb, Lum(Cs))
   1.606 +// Create a color with the luminosity of the source color and the hue and saturation of the backdrop color.
   1.607 +static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
   1.608 +    int sr = SkGetPackedR32(src);
   1.609 +    int sg = SkGetPackedG32(src);
   1.610 +    int sb = SkGetPackedB32(src);
   1.611 +    int sa = SkGetPackedA32(src);
   1.612 +
   1.613 +    int dr = SkGetPackedR32(dst);
   1.614 +    int dg = SkGetPackedG32(dst);
   1.615 +    int db = SkGetPackedB32(dst);
   1.616 +    int da = SkGetPackedA32(dst);
   1.617 +    int Dr, Dg, Db;
   1.618 +
   1.619 +    if(sa && da) {
   1.620 +        Dr = dr * sa;
   1.621 +        Dg = dg * sa;
   1.622 +        Db = db * sa;
   1.623 +        SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
   1.624 +    } else {
   1.625 +        Dr = 0;
   1.626 +        Dg = 0;
   1.627 +        Db = 0;
   1.628 +    }
   1.629 +
   1.630 +    int a = srcover_byte(sa, da);
   1.631 +    int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
   1.632 +    int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
   1.633 +    int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
   1.634 +    return SkPackARGB32(a, r, g, b);
   1.635 +}
   1.636 +
   1.637 +const ProcCoeff gProcCoeffs[] = {
   1.638 +    { clear_modeproc,   SkXfermode::kZero_Coeff,    SkXfermode::kZero_Coeff },
   1.639 +    { src_modeproc,     SkXfermode::kOne_Coeff,     SkXfermode::kZero_Coeff },
   1.640 +    { dst_modeproc,     SkXfermode::kZero_Coeff,    SkXfermode::kOne_Coeff },
   1.641 +    { srcover_modeproc, SkXfermode::kOne_Coeff,     SkXfermode::kISA_Coeff },
   1.642 +    { dstover_modeproc, SkXfermode::kIDA_Coeff,     SkXfermode::kOne_Coeff },
   1.643 +    { srcin_modeproc,   SkXfermode::kDA_Coeff,      SkXfermode::kZero_Coeff },
   1.644 +    { dstin_modeproc,   SkXfermode::kZero_Coeff,    SkXfermode::kSA_Coeff },
   1.645 +    { srcout_modeproc,  SkXfermode::kIDA_Coeff,     SkXfermode::kZero_Coeff },
   1.646 +    { dstout_modeproc,  SkXfermode::kZero_Coeff,    SkXfermode::kISA_Coeff },
   1.647 +    { srcatop_modeproc, SkXfermode::kDA_Coeff,      SkXfermode::kISA_Coeff },
   1.648 +    { dstatop_modeproc, SkXfermode::kIDA_Coeff,     SkXfermode::kSA_Coeff },
   1.649 +    { xor_modeproc,     SkXfermode::kIDA_Coeff,     SkXfermode::kISA_Coeff },
   1.650 +
   1.651 +    { plus_modeproc,    SkXfermode::kOne_Coeff,     SkXfermode::kOne_Coeff },
   1.652 +    { modulate_modeproc,SkXfermode::kZero_Coeff,    SkXfermode::kSC_Coeff },
   1.653 +    { screen_modeproc,  SkXfermode::kOne_Coeff,     SkXfermode::kISC_Coeff },
   1.654 +    { overlay_modeproc,     CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.655 +    { darken_modeproc,      CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.656 +    { lighten_modeproc,     CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.657 +    { colordodge_modeproc,  CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.658 +    { colorburn_modeproc,   CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.659 +    { hardlight_modeproc,   CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.660 +    { softlight_modeproc,   CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.661 +    { difference_modeproc,  CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.662 +    { exclusion_modeproc,   CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.663 +    { multiply_modeproc,    CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.664 +    { hue_modeproc,         CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.665 +    { saturation_modeproc,  CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.666 +    { color_modeproc,       CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.667 +    { luminosity_modeproc,  CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
   1.668 +};
   1.669 +
   1.670 +///////////////////////////////////////////////////////////////////////////////
   1.671 +
   1.672 +bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) const {
   1.673 +    return false;
   1.674 +}
   1.675 +
   1.676 +bool SkXfermode::asMode(Mode* mode) const {
   1.677 +    return false;
   1.678 +}
   1.679 +
   1.680 +bool SkXfermode::asNewEffect(GrEffectRef** effect, GrTexture* background) const {
   1.681 +    return false;
   1.682 +}
   1.683 +
   1.684 +bool SkXfermode::AsNewEffectOrCoeff(SkXfermode* xfermode,
   1.685 +                                    GrEffectRef** effect,
   1.686 +                                    Coeff* src,
   1.687 +                                    Coeff* dst,
   1.688 +                                    GrTexture* background) {
   1.689 +    if (NULL == xfermode) {
   1.690 +        return ModeAsCoeff(kSrcOver_Mode, src, dst);
   1.691 +    } else if (xfermode->asCoeff(src, dst)) {
   1.692 +        return true;
   1.693 +    } else {
   1.694 +        return xfermode->asNewEffect(effect, background);
   1.695 +    }
   1.696 +}
   1.697 +
   1.698 +SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
   1.699 +    // no-op. subclasses should override this
   1.700 +    return dst;
   1.701 +}
   1.702 +
   1.703 +void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
   1.704 +                        const SkPMColor* SK_RESTRICT src, int count,
   1.705 +                        const SkAlpha* SK_RESTRICT aa) const {
   1.706 +    SkASSERT(dst && src && count >= 0);
   1.707 +
   1.708 +    if (NULL == aa) {
   1.709 +        for (int i = count - 1; i >= 0; --i) {
   1.710 +            dst[i] = this->xferColor(src[i], dst[i]);
   1.711 +        }
   1.712 +    } else {
   1.713 +        for (int i = count - 1; i >= 0; --i) {
   1.714 +            unsigned a = aa[i];
   1.715 +            if (0 != a) {
   1.716 +                SkPMColor dstC = dst[i];
   1.717 +                SkPMColor C = this->xferColor(src[i], dstC);
   1.718 +                if (0xFF != a) {
   1.719 +                    C = SkFourByteInterp(C, dstC, a);
   1.720 +                }
   1.721 +                dst[i] = C;
   1.722 +            }
   1.723 +        }
   1.724 +    }
   1.725 +}
   1.726 +
   1.727 +void SkXfermode::xfer16(uint16_t* dst,
   1.728 +                        const SkPMColor* SK_RESTRICT src, int count,
   1.729 +                        const SkAlpha* SK_RESTRICT aa) const {
   1.730 +    SkASSERT(dst && src && count >= 0);
   1.731 +
   1.732 +    if (NULL == aa) {
   1.733 +        for (int i = count - 1; i >= 0; --i) {
   1.734 +            SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
   1.735 +            dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
   1.736 +        }
   1.737 +    } else {
   1.738 +        for (int i = count - 1; i >= 0; --i) {
   1.739 +            unsigned a = aa[i];
   1.740 +            if (0 != a) {
   1.741 +                SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
   1.742 +                SkPMColor C = this->xferColor(src[i], dstC);
   1.743 +                if (0xFF != a) {
   1.744 +                    C = SkFourByteInterp(C, dstC, a);
   1.745 +                }
   1.746 +                dst[i] = SkPixel32ToPixel16_ToU16(C);
   1.747 +            }
   1.748 +        }
   1.749 +    }
   1.750 +}
   1.751 +
   1.752 +void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
   1.753 +                        const SkPMColor src[], int count,
   1.754 +                        const SkAlpha* SK_RESTRICT aa) const {
   1.755 +    SkASSERT(dst && src && count >= 0);
   1.756 +
   1.757 +    if (NULL == aa) {
   1.758 +        for (int i = count - 1; i >= 0; --i) {
   1.759 +            SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
   1.760 +            dst[i] = SkToU8(SkGetPackedA32(res));
   1.761 +        }
   1.762 +    } else {
   1.763 +        for (int i = count - 1; i >= 0; --i) {
   1.764 +            unsigned a = aa[i];
   1.765 +            if (0 != a) {
   1.766 +                SkAlpha dstA = dst[i];
   1.767 +                unsigned A = SkGetPackedA32(this->xferColor(src[i],
   1.768 +                                            (SkPMColor)(dstA << SK_A32_SHIFT)));
   1.769 +                if (0xFF != a) {
   1.770 +                    A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
   1.771 +                }
   1.772 +                dst[i] = SkToU8(A);
   1.773 +            }
   1.774 +        }
   1.775 +    }
   1.776 +}
   1.777 +
   1.778 +///////////////////////////////////////////////////////////////////////////////
   1.779 +
   1.780 +void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
   1.781 +                            const SkPMColor* SK_RESTRICT src, int count,
   1.782 +                            const SkAlpha* SK_RESTRICT aa) const {
   1.783 +    SkASSERT(dst && src && count >= 0);
   1.784 +
   1.785 +    SkXfermodeProc proc = fProc;
   1.786 +
   1.787 +    if (NULL != proc) {
   1.788 +        if (NULL == aa) {
   1.789 +            for (int i = count - 1; i >= 0; --i) {
   1.790 +                dst[i] = proc(src[i], dst[i]);
   1.791 +            }
   1.792 +        } else {
   1.793 +            for (int i = count - 1; i >= 0; --i) {
   1.794 +                unsigned a = aa[i];
   1.795 +                if (0 != a) {
   1.796 +                    SkPMColor dstC = dst[i];
   1.797 +                    SkPMColor C = proc(src[i], dstC);
   1.798 +                    if (a != 0xFF) {
   1.799 +                        C = SkFourByteInterp(C, dstC, a);
   1.800 +                    }
   1.801 +                    dst[i] = C;
   1.802 +                }
   1.803 +            }
   1.804 +        }
   1.805 +    }
   1.806 +}
   1.807 +
   1.808 +void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
   1.809 +                            const SkPMColor* SK_RESTRICT src, int count,
   1.810 +                            const SkAlpha* SK_RESTRICT aa) const {
   1.811 +    SkASSERT(dst && src && count >= 0);
   1.812 +
   1.813 +    SkXfermodeProc proc = fProc;
   1.814 +
   1.815 +    if (NULL != proc) {
   1.816 +        if (NULL == aa) {
   1.817 +            for (int i = count - 1; i >= 0; --i) {
   1.818 +                SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
   1.819 +                dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
   1.820 +            }
   1.821 +        } else {
   1.822 +            for (int i = count - 1; i >= 0; --i) {
   1.823 +                unsigned a = aa[i];
   1.824 +                if (0 != a) {
   1.825 +                    SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
   1.826 +                    SkPMColor C = proc(src[i], dstC);
   1.827 +                    if (0xFF != a) {
   1.828 +                        C = SkFourByteInterp(C, dstC, a);
   1.829 +                    }
   1.830 +                    dst[i] = SkPixel32ToPixel16_ToU16(C);
   1.831 +                }
   1.832 +            }
   1.833 +        }
   1.834 +    }
   1.835 +}
   1.836 +
   1.837 +void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
   1.838 +                            const SkPMColor* SK_RESTRICT src, int count,
   1.839 +                            const SkAlpha* SK_RESTRICT aa) const {
   1.840 +    SkASSERT(dst && src && count >= 0);
   1.841 +
   1.842 +    SkXfermodeProc proc = fProc;
   1.843 +
   1.844 +    if (NULL != proc) {
   1.845 +        if (NULL == aa) {
   1.846 +            for (int i = count - 1; i >= 0; --i) {
   1.847 +                SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
   1.848 +                dst[i] = SkToU8(SkGetPackedA32(res));
   1.849 +            }
   1.850 +        } else {
   1.851 +            for (int i = count - 1; i >= 0; --i) {
   1.852 +                unsigned a = aa[i];
   1.853 +                if (0 != a) {
   1.854 +                    SkAlpha dstA = dst[i];
   1.855 +                    SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
   1.856 +                    unsigned A = SkGetPackedA32(res);
   1.857 +                    if (0xFF != a) {
   1.858 +                        A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
   1.859 +                    }
   1.860 +                    dst[i] = SkToU8(A);
   1.861 +                }
   1.862 +            }
   1.863 +        }
   1.864 +    }
   1.865 +}
   1.866 +
   1.867 +SkProcXfermode::SkProcXfermode(SkReadBuffer& buffer)
   1.868 +        : SkXfermode(buffer) {
   1.869 +    fProc = NULL;
   1.870 +    if (!buffer.isCrossProcess()) {
   1.871 +        fProc = (SkXfermodeProc)buffer.readFunctionPtr();
   1.872 +    }
   1.873 +}
   1.874 +
   1.875 +void SkProcXfermode::flatten(SkWriteBuffer& buffer) const {
   1.876 +    this->INHERITED::flatten(buffer);
   1.877 +    if (!buffer.isCrossProcess()) {
   1.878 +        buffer.writeFunctionPtr((void*)fProc);
   1.879 +    }
   1.880 +}
   1.881 +
   1.882 +#ifndef SK_IGNORE_TO_STRING
   1.883 +void SkProcXfermode::toString(SkString* str) const {
   1.884 +    str->appendf("SkProcXfermode: %p", fProc);
   1.885 +}
   1.886 +#endif
   1.887 +
   1.888 +//////////////////////////////////////////////////////////////////////////////
   1.889 +
   1.890 +#if SK_SUPPORT_GPU
   1.891 +
   1.892 +#include "GrEffect.h"
   1.893 +#include "GrCoordTransform.h"
   1.894 +#include "GrEffectUnitTest.h"
   1.895 +#include "GrTBackendEffectFactory.h"
   1.896 +#include "gl/GrGLEffect.h"
   1.897 +
   1.898 +/**
   1.899 + * GrEffect that implements the all the separable xfer modes that cannot be expressed as Coeffs.
   1.900 + */
   1.901 +class XferEffect : public GrEffect {
   1.902 +public:
   1.903 +    static bool IsSupportedMode(SkXfermode::Mode mode) {
   1.904 +        return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode;
   1.905 +    }
   1.906 +
   1.907 +    static GrEffectRef* Create(SkXfermode::Mode mode, GrTexture* background) {
   1.908 +        if (!IsSupportedMode(mode)) {
   1.909 +            return NULL;
   1.910 +        } else {
   1.911 +            AutoEffectUnref effect(SkNEW_ARGS(XferEffect, (mode, background)));
   1.912 +            return CreateEffectRef(effect);
   1.913 +        }
   1.914 +    }
   1.915 +
   1.916 +    virtual void getConstantColorComponents(GrColor* color,
   1.917 +                                            uint32_t* validFlags) const SK_OVERRIDE {
   1.918 +        *validFlags = 0;
   1.919 +    }
   1.920 +
   1.921 +    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
   1.922 +        return GrTBackendEffectFactory<XferEffect>::getInstance();
   1.923 +    }
   1.924 +
   1.925 +    static const char* Name() { return "XferEffect"; }
   1.926 +
   1.927 +    SkXfermode::Mode mode() const { return fMode; }
   1.928 +    const GrTextureAccess&  backgroundAccess() const { return fBackgroundAccess; }
   1.929 +
   1.930 +    class GLEffect : public GrGLEffect {
   1.931 +    public:
   1.932 +        GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
   1.933 +            : GrGLEffect(factory) {
   1.934 +        }
   1.935 +        virtual void emitCode(GrGLShaderBuilder* builder,
   1.936 +                              const GrDrawEffect& drawEffect,
   1.937 +                              EffectKey key,
   1.938 +                              const char* outputColor,
   1.939 +                              const char* inputColor,
   1.940 +                              const TransformedCoordsArray& coords,
   1.941 +                              const TextureSamplerArray& samplers) SK_OVERRIDE {
   1.942 +            SkXfermode::Mode mode = drawEffect.castEffect<XferEffect>().mode();
   1.943 +            const GrTexture* backgroundTex = drawEffect.castEffect<XferEffect>().backgroundAccess().getTexture();
   1.944 +            const char* dstColor;
   1.945 +            if (backgroundTex) {
   1.946 +                dstColor = "bgColor";
   1.947 +                builder->fsCodeAppendf("\t\tvec4 %s = ", dstColor);
   1.948 +                builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
   1.949 +                builder->fsCodeAppendf(";\n");
   1.950 +            } else {
   1.951 +                dstColor = builder->dstColor();
   1.952 +            }
   1.953 +            SkASSERT(NULL != dstColor);
   1.954 +
   1.955 +            // We don't try to optimize for this case at all
   1.956 +            if (NULL == inputColor) {
   1.957 +                builder->fsCodeAppendf("\t\tconst vec4 ones = vec4(1);\n");
   1.958 +                inputColor = "ones";
   1.959 +            }
   1.960 +            builder->fsCodeAppendf("\t\t// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
   1.961 +
   1.962 +            // These all perform src-over on the alpha channel.
   1.963 +            builder->fsCodeAppendf("\t\t%s.a = %s.a + (1.0 - %s.a) * %s.a;\n",
   1.964 +                                    outputColor, inputColor, inputColor, dstColor);
   1.965 +
   1.966 +            switch (mode) {
   1.967 +                case SkXfermode::kOverlay_Mode:
   1.968 +                    // Overlay is Hard-Light with the src and dst reversed
   1.969 +                    HardLight(builder, outputColor, dstColor, inputColor);
   1.970 +                    break;
   1.971 +                case SkXfermode::kDarken_Mode:
   1.972 +                    builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
   1.973 +                                                            "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
   1.974 +                                            outputColor,
   1.975 +                                            inputColor, dstColor, inputColor,
   1.976 +                                            dstColor, inputColor, dstColor);
   1.977 +                    break;
   1.978 +                case SkXfermode::kLighten_Mode:
   1.979 +                    builder->fsCodeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
   1.980 +                                                            "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
   1.981 +                                            outputColor,
   1.982 +                                            inputColor, dstColor, inputColor,
   1.983 +                                            dstColor, inputColor, dstColor);
   1.984 +                    break;
   1.985 +                case SkXfermode::kColorDodge_Mode:
   1.986 +                    ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'r');
   1.987 +                    ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'g');
   1.988 +                    ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'b');
   1.989 +                    break;
   1.990 +                case SkXfermode::kColorBurn_Mode:
   1.991 +                    ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'r');
   1.992 +                    ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'g');
   1.993 +                    ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'b');
   1.994 +                    break;
   1.995 +                case SkXfermode::kHardLight_Mode:
   1.996 +                    HardLight(builder, outputColor, inputColor, dstColor);
   1.997 +                    break;
   1.998 +                case SkXfermode::kSoftLight_Mode:
   1.999 +                    builder->fsCodeAppendf("\t\tif (0.0 == %s.a) {\n", dstColor);
  1.1000 +                    builder->fsCodeAppendf("\t\t\t%s.rgba = %s;\n", outputColor, inputColor);
  1.1001 +                    builder->fsCodeAppendf("\t\t} else {\n");
  1.1002 +                    SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'r');
  1.1003 +                    SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'g');
  1.1004 +                    SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'b');
  1.1005 +                    builder->fsCodeAppendf("\t\t}\n");
  1.1006 +                    break;
  1.1007 +                case SkXfermode::kDifference_Mode:
  1.1008 +                    builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb -"
  1.1009 +                                                       "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);\n",
  1.1010 +                                           outputColor, inputColor, dstColor, inputColor, dstColor,
  1.1011 +                                           dstColor, inputColor);
  1.1012 +                    break;
  1.1013 +                case SkXfermode::kExclusion_Mode:
  1.1014 +                    builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - "
  1.1015 +                                                        "2.0 * %s.rgb * %s.rgb;\n",
  1.1016 +                                           outputColor, dstColor, inputColor, dstColor, inputColor);
  1.1017 +                    break;
  1.1018 +                case SkXfermode::kMultiply_Mode:
  1.1019 +                    builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + "
  1.1020 +                                                        "(1.0 - %s.a) * %s.rgb + "
  1.1021 +                                                         "%s.rgb * %s.rgb;\n",
  1.1022 +                                           outputColor, inputColor, dstColor, dstColor, inputColor,
  1.1023 +                                           inputColor, dstColor);
  1.1024 +                    break;
  1.1025 +                case SkXfermode::kHue_Mode: {
  1.1026 +                    //  SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
  1.1027 +                    SkString setSat, setLum;
  1.1028 +                    AddSatFunction(builder, &setSat);
  1.1029 +                    AddLumFunction(builder, &setLum);
  1.1030 +                    builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
  1.1031 +                                           dstColor, inputColor);
  1.1032 +                    builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
  1.1033 +                                           outputColor, setLum.c_str(), setSat.c_str(), inputColor,
  1.1034 +                                           dstColor);
  1.1035 +                    builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
  1.1036 +                                           outputColor, inputColor, dstColor, dstColor, inputColor);
  1.1037 +                    break;
  1.1038 +                }
  1.1039 +                case SkXfermode::kSaturation_Mode: {
  1.1040 +                    // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
  1.1041 +                    SkString setSat, setLum;
  1.1042 +                    AddSatFunction(builder, &setSat);
  1.1043 +                    AddLumFunction(builder, &setLum);
  1.1044 +                    builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
  1.1045 +                                           dstColor, inputColor);
  1.1046 +                    builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
  1.1047 +                                           outputColor, setLum.c_str(), setSat.c_str(), inputColor,
  1.1048 +                                           dstColor);
  1.1049 +                    builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
  1.1050 +                                           outputColor, inputColor, dstColor, dstColor, inputColor);
  1.1051 +                    break;
  1.1052 +                }
  1.1053 +                case SkXfermode::kColor_Mode: {
  1.1054 +                    //  SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
  1.1055 +                    SkString setLum;
  1.1056 +                    AddLumFunction(builder, &setLum);
  1.1057 +                    builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
  1.1058 +                                           inputColor, dstColor);
  1.1059 +                    builder->fsCodeAppendf("\t\t%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);\n",
  1.1060 +                                           outputColor, setLum.c_str(), dstColor, inputColor);
  1.1061 +                    builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
  1.1062 +                                           outputColor, inputColor, dstColor, dstColor, inputColor);
  1.1063 +                    break;
  1.1064 +                }
  1.1065 +                case SkXfermode::kLuminosity_Mode: {
  1.1066 +                    //  SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
  1.1067 +                    SkString setLum;
  1.1068 +                    AddLumFunction(builder, &setLum);
  1.1069 +                    builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
  1.1070 +                                           inputColor, dstColor);
  1.1071 +                    builder->fsCodeAppendf("\t\t%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);\n",
  1.1072 +                                           outputColor, setLum.c_str(), dstColor, inputColor);
  1.1073 +                    builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
  1.1074 +                                           outputColor, inputColor, dstColor, dstColor, inputColor);
  1.1075 +                    break;
  1.1076 +                }
  1.1077 +                default:
  1.1078 +                    GrCrash("Unknown XferEffect mode.");
  1.1079 +                    break;
  1.1080 +            }
  1.1081 +        }
  1.1082 +
  1.1083 +        static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
  1.1084 +            return drawEffect.castEffect<XferEffect>().mode();
  1.1085 +        }
  1.1086 +
  1.1087 +    private:
  1.1088 +        static void HardLight(GrGLShaderBuilder* builder,
  1.1089 +                              const char* final,
  1.1090 +                              const char* src,
  1.1091 +                              const char* dst) {
  1.1092 +            static const char kComponents[] = {'r', 'g', 'b'};
  1.1093 +            for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
  1.1094 +                char component = kComponents[i];
  1.1095 +                builder->fsCodeAppendf("\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
  1.1096 +                builder->fsCodeAppendf("\t\t\t%s.%c = 2.0 * %s.%c * %s.%c;\n", final, component, src, component, dst, component);
  1.1097 +                builder->fsCodeAppend("\t\t} else {\n");
  1.1098 +                builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);\n",
  1.1099 +                                       final, component, src, dst, dst, dst, component, src, src, component);
  1.1100 +                builder->fsCodeAppend("\t\t}\n");
  1.1101 +            }
  1.1102 +            builder->fsCodeAppendf("\t\t%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);\n",
  1.1103 +                                   final, src, dst, dst, src);
  1.1104 +        }
  1.1105 +
  1.1106 +        // Does one component of color-dodge
  1.1107 +        static void ColorDodgeComponent(GrGLShaderBuilder* builder,
  1.1108 +                                        const char* final,
  1.1109 +                                        const char* src,
  1.1110 +                                        const char* dst,
  1.1111 +                                        const char component) {
  1.1112 +            builder->fsCodeAppendf("\t\tif (0.0 == %s.%c) {\n", dst, component);
  1.1113 +            builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
  1.1114 +                                   final, component, src, component, dst);
  1.1115 +            builder->fsCodeAppend("\t\t} else {\n");
  1.1116 +            builder->fsCodeAppendf("\t\t\tfloat d = %s.a - %s.%c;\n", src, src, component);
  1.1117 +            builder->fsCodeAppend("\t\t\tif (0.0 == d) {\n");
  1.1118 +            builder->fsCodeAppendf("\t\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
  1.1119 +                                   final, component, src, dst, src, component, dst, dst, component,
  1.1120 +                                   src);
  1.1121 +            builder->fsCodeAppend("\t\t\t} else {\n");
  1.1122 +            builder->fsCodeAppendf("\t\t\t\td = min(%s.a, %s.%c * %s.a / d);\n",
  1.1123 +                                   dst, dst, component, src);
  1.1124 +            builder->fsCodeAppendf("\t\t\t\t%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
  1.1125 +                                   final, component, src, src, component, dst, dst, component, src);
  1.1126 +            builder->fsCodeAppend("\t\t\t}\n");
  1.1127 +            builder->fsCodeAppend("\t\t}\n");
  1.1128 +        }
  1.1129 +
  1.1130 +        // Does one component of color-burn
  1.1131 +        static void ColorBurnComponent(GrGLShaderBuilder* builder,
  1.1132 +                                       const char* final,
  1.1133 +                                       const char* src,
  1.1134 +                                       const char* dst,
  1.1135 +                                       const char component) {
  1.1136 +            builder->fsCodeAppendf("\t\tif (%s.a == %s.%c) {\n", dst, dst, component);
  1.1137 +            builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
  1.1138 +                                   final, component, src, dst, src, component, dst, dst, component,
  1.1139 +                                   src);
  1.1140 +            builder->fsCodeAppendf("\t\t} else if (0.0 == %s.%c) {\n", src, component);
  1.1141 +            builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
  1.1142 +                                   final, component, dst, component, src);
  1.1143 +            builder->fsCodeAppend("\t\t} else {\n");
  1.1144 +            builder->fsCodeAppendf("\t\t\tfloat d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);\n",
  1.1145 +                                   dst, dst, dst, component, src, src, component);
  1.1146 +            builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
  1.1147 +                                   final, component, src, src, component, dst, dst, component, src);
  1.1148 +            builder->fsCodeAppend("\t\t}\n");
  1.1149 +        }
  1.1150 +
  1.1151 +        // Does one component of soft-light. Caller should have already checked that dst alpha > 0.
  1.1152 +        static void SoftLightComponentPosDstAlpha(GrGLShaderBuilder* builder,
  1.1153 +                                                  const char* final,
  1.1154 +                                                  const char* src,
  1.1155 +                                                  const char* dst,
  1.1156 +                                                  const char component) {
  1.1157 +            // if (2S < Sa)
  1.1158 +            builder->fsCodeAppendf("\t\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
  1.1159 +            // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
  1.1160 +            builder->fsCodeAppendf("\t\t\t\t%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a + (1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);\n",
  1.1161 +                                   final, component, dst, component, dst, component, src, src,
  1.1162 +                                   component, dst, dst, src, component, dst, component, src, src,
  1.1163 +                                   component);
  1.1164 +            // else if (4D < Da)
  1.1165 +            builder->fsCodeAppendf("\t\t\t} else if (4.0 * %s.%c <= %s.a) {\n",
  1.1166 +                                   dst, component, dst);
  1.1167 +            builder->fsCodeAppendf("\t\t\t\tfloat DSqd = %s.%c * %s.%c;\n",
  1.1168 +                                   dst, component, dst, component);
  1.1169 +            builder->fsCodeAppendf("\t\t\t\tfloat DCub = DSqd * %s.%c;\n", dst, component);
  1.1170 +            builder->fsCodeAppendf("\t\t\t\tfloat DaSqd = %s.a * %s.a;\n", dst, dst);
  1.1171 +            builder->fsCodeAppendf("\t\t\t\tfloat DaCub = DaSqd * %s.a;\n", dst);
  1.1172 +            // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2
  1.1173 +            builder->fsCodeAppendf("\t\t\t\t%s.%c = (-DaCub*%s.%c + DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) + 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c)) / DaSqd;\n",
  1.1174 +                                   final, component, src, component, src, component, dst, component,
  1.1175 +                                   src, src, component, dst, src, src, component, src, src,
  1.1176 +                                   component);
  1.1177 +            builder->fsCodeAppendf("\t\t\t} else {\n");
  1.1178 +            // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
  1.1179 +            builder->fsCodeAppendf("\t\t\t\t%s.%c = -sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c + %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c;\n",
  1.1180 +                                    final, component, dst, dst, component, src, src, component, dst,
  1.1181 +                                    src, component, dst, component, src, src, component, src,
  1.1182 +                                    component);
  1.1183 +            builder->fsCodeAppendf("\t\t\t}\n");
  1.1184 +        }
  1.1185 +
  1.1186 +        // Adds a function that takes two colors and an alpha as input. It produces a color with the
  1.1187 +        // hue and saturation of the first color, the luminosity of the second color, and the input
  1.1188 +        // alpha. It has this signature:
  1.1189 +        //      vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
  1.1190 +        static void AddLumFunction(GrGLShaderBuilder* builder, SkString* setLumFunction) {
  1.1191 +            // Emit a helper that gets the luminance of a color.
  1.1192 +            SkString getFunction;
  1.1193 +            GrGLShaderVar getLumArgs[] = {
  1.1194 +                GrGLShaderVar("color", kVec3f_GrSLType),
  1.1195 +            };
  1.1196 +            SkString getLumBody("\treturn dot(vec3(0.3, 0.59, 0.11), color);\n");
  1.1197 +            builder->fsEmitFunction(kFloat_GrSLType,
  1.1198 +                                    "luminance",
  1.1199 +                                    SK_ARRAY_COUNT(getLumArgs), getLumArgs,
  1.1200 +                                    getLumBody.c_str(),
  1.1201 +                                    &getFunction);
  1.1202 +
  1.1203 +            // Emit the set luminance function.
  1.1204 +            GrGLShaderVar setLumArgs[] = {
  1.1205 +                GrGLShaderVar("hueSat", kVec3f_GrSLType),
  1.1206 +                GrGLShaderVar("alpha", kFloat_GrSLType),
  1.1207 +                GrGLShaderVar("lumColor", kVec3f_GrSLType),
  1.1208 +            };
  1.1209 +            SkString setLumBody;
  1.1210 +            setLumBody.printf("\tfloat diff = %s(lumColor - hueSat);\n", getFunction.c_str());
  1.1211 +            setLumBody.append("\tvec3 outColor = hueSat + diff;\n");
  1.1212 +            setLumBody.appendf("\tfloat outLum = %s(outColor);\n", getFunction.c_str());
  1.1213 +            setLumBody.append("\tfloat minComp = min(min(outColor.r, outColor.g), outColor.b);\n"
  1.1214 +                              "\tfloat maxComp = max(max(outColor.r, outColor.g), outColor.b);\n"
  1.1215 +                              "\tif (minComp < 0.0) {\n"
  1.1216 +                              "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) / (outLum - minComp);\n"
  1.1217 +                              "\t}\n"
  1.1218 +                              "\tif (maxComp > alpha) {\n"
  1.1219 +                              "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) / (maxComp - outLum);\n"
  1.1220 +                              "\t}\n"
  1.1221 +                              "\treturn outColor;\n");
  1.1222 +            builder->fsEmitFunction(kVec3f_GrSLType,
  1.1223 +                                    "set_luminance",
  1.1224 +                                    SK_ARRAY_COUNT(setLumArgs), setLumArgs,
  1.1225 +                                    setLumBody.c_str(),
  1.1226 +                                    setLumFunction);
  1.1227 +        }
  1.1228 +
  1.1229 +        // Adds a function that creates a color with the hue and luminosity of one input color and
  1.1230 +        // the saturation of another color. It will have this signature:
  1.1231 +        //      float set_saturation(vec3 hueLumColor, vec3 satColor)
  1.1232 +        static void AddSatFunction(GrGLShaderBuilder* builder, SkString* setSatFunction) {
  1.1233 +            // Emit a helper that gets the saturation of a color
  1.1234 +            SkString getFunction;
  1.1235 +            GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
  1.1236 +            SkString getSatBody;
  1.1237 +            getSatBody.printf("\treturn max(max(color.r, color.g), color.b) - "
  1.1238 +                              "min(min(color.r, color.g), color.b);\n");
  1.1239 +            builder->fsEmitFunction(kFloat_GrSLType,
  1.1240 +                                    "saturation",
  1.1241 +                                    SK_ARRAY_COUNT(getSatArgs), getSatArgs,
  1.1242 +                                    getSatBody.c_str(),
  1.1243 +                                    &getFunction);
  1.1244 +
  1.1245 +            // Emit a helper that sets the saturation given sorted input channels. This used
  1.1246 +            // to use inout params for min, mid, and max components but that seems to cause
  1.1247 +            // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
  1.1248 +            // adjusted min, mid, and max inputs, respectively.
  1.1249 +            SkString helperFunction;
  1.1250 +            GrGLShaderVar helperArgs[] = {
  1.1251 +                GrGLShaderVar("minComp", kFloat_GrSLType),
  1.1252 +                GrGLShaderVar("midComp", kFloat_GrSLType),
  1.1253 +                GrGLShaderVar("maxComp", kFloat_GrSLType),
  1.1254 +                GrGLShaderVar("sat", kFloat_GrSLType),
  1.1255 +            };
  1.1256 +            static const char kHelperBody[] = "\tif (minComp < maxComp) {\n"
  1.1257 +                                              "\t\tvec3 result;\n"
  1.1258 +                                              "\t\tresult.r = 0.0;\n"
  1.1259 +                                              "\t\tresult.g = sat * (midComp - minComp) / (maxComp - minComp);\n"
  1.1260 +                                              "\t\tresult.b = sat;\n"
  1.1261 +                                              "\t\treturn result;\n"
  1.1262 +                                              "\t} else {\n"
  1.1263 +                                              "\t\treturn vec3(0, 0, 0);\n"
  1.1264 +                                              "\t}\n";
  1.1265 +            builder->fsEmitFunction(kVec3f_GrSLType,
  1.1266 +                                    "set_saturation_helper",
  1.1267 +                                    SK_ARRAY_COUNT(helperArgs), helperArgs,
  1.1268 +                                    kHelperBody,
  1.1269 +                                    &helperFunction);
  1.1270 +
  1.1271 +            GrGLShaderVar setSatArgs[] = {
  1.1272 +                GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
  1.1273 +                GrGLShaderVar("satColor", kVec3f_GrSLType),
  1.1274 +            };
  1.1275 +            const char* helpFunc = helperFunction.c_str();
  1.1276 +            SkString setSatBody;
  1.1277 +            setSatBody.appendf("\tfloat sat = %s(satColor);\n"
  1.1278 +                               "\tif (hueLumColor.r <= hueLumColor.g) {\n"
  1.1279 +                               "\t\tif (hueLumColor.g <= hueLumColor.b) {\n"
  1.1280 +                               "\t\t\thueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);\n"
  1.1281 +                               "\t\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
  1.1282 +                               "\t\t\thueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);\n"
  1.1283 +                               "\t\t} else {\n"
  1.1284 +                               "\t\t\thueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);\n"
  1.1285 +                               "\t\t}\n"
  1.1286 +                               "\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
  1.1287 +                               "\t\thueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);\n"
  1.1288 +                               "\t} else if (hueLumColor.g <= hueLumColor.b) {\n"
  1.1289 +                               "\t\thueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);\n"
  1.1290 +                               "\t} else {\n"
  1.1291 +                               "\t\thueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);\n"
  1.1292 +                               "\t}\n"
  1.1293 +                               "\treturn hueLumColor;\n",
  1.1294 +                               getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
  1.1295 +                               helpFunc, helpFunc);
  1.1296 +            builder->fsEmitFunction(kVec3f_GrSLType,
  1.1297 +                                    "set_saturation",
  1.1298 +                                    SK_ARRAY_COUNT(setSatArgs), setSatArgs,
  1.1299 +                                    setSatBody.c_str(),
  1.1300 +                                    setSatFunction);
  1.1301 +
  1.1302 +        }
  1.1303 +
  1.1304 +        typedef GrGLEffect INHERITED;
  1.1305 +    };
  1.1306 +
  1.1307 +    GR_DECLARE_EFFECT_TEST;
  1.1308 +
  1.1309 +private:
  1.1310 +    XferEffect(SkXfermode::Mode mode, GrTexture* background)
  1.1311 +        : fMode(mode) {
  1.1312 +        if (background) {
  1.1313 +            fBackgroundTransform.reset(kLocal_GrCoordSet, background);
  1.1314 +            this->addCoordTransform(&fBackgroundTransform);
  1.1315 +            fBackgroundAccess.reset(background);
  1.1316 +            this->addTextureAccess(&fBackgroundAccess);
  1.1317 +        } else {
  1.1318 +            this->setWillReadDstColor();
  1.1319 +        }
  1.1320 +    }
  1.1321 +    virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
  1.1322 +        const XferEffect& s = CastEffect<XferEffect>(other);
  1.1323 +        return fMode == s.fMode &&
  1.1324 +               fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture();
  1.1325 +    }
  1.1326 +
  1.1327 +    SkXfermode::Mode fMode;
  1.1328 +    GrCoordTransform fBackgroundTransform;
  1.1329 +    GrTextureAccess  fBackgroundAccess;
  1.1330 +
  1.1331 +    typedef GrEffect INHERITED;
  1.1332 +};
  1.1333 +
  1.1334 +GR_DEFINE_EFFECT_TEST(XferEffect);
  1.1335 +GrEffectRef* XferEffect::TestCreate(SkRandom* rand,
  1.1336 +                                    GrContext*,
  1.1337 +                                    const GrDrawTargetCaps&,
  1.1338 +                                    GrTexture*[]) {
  1.1339 +    int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
  1.1340 +
  1.1341 +    AutoEffectUnref gEffect(SkNEW_ARGS(XferEffect, (static_cast<SkXfermode::Mode>(mode), NULL)));
  1.1342 +    return CreateEffectRef(gEffect);
  1.1343 +}
  1.1344 +
  1.1345 +#endif
  1.1346 +
  1.1347 +///////////////////////////////////////////////////////////////////////////////
  1.1348 +///////////////////////////////////////////////////////////////////////////////
  1.1349 +
  1.1350 +SkProcCoeffXfermode::SkProcCoeffXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {
  1.1351 +    uint32_t mode32 = buffer.read32() % SK_ARRAY_COUNT(gProcCoeffs);
  1.1352 +    if (mode32 >= SK_ARRAY_COUNT(gProcCoeffs)) {
  1.1353 +        // out of range, just set to something harmless
  1.1354 +        mode32 = SkXfermode::kSrcOut_Mode;
  1.1355 +    }
  1.1356 +    fMode = (SkXfermode::Mode)mode32;
  1.1357 +
  1.1358 +    const ProcCoeff& rec = gProcCoeffs[fMode];
  1.1359 +    // these may be valid, or may be CANNOT_USE_COEFF
  1.1360 +    fSrcCoeff = rec.fSC;
  1.1361 +    fDstCoeff = rec.fDC;
  1.1362 +    // now update our function-ptr in the super class
  1.1363 +    this->INHERITED::setProc(rec.fProc);
  1.1364 +}
  1.1365 +
  1.1366 +bool SkProcCoeffXfermode::asMode(Mode* mode) const {
  1.1367 +    if (mode) {
  1.1368 +        *mode = fMode;
  1.1369 +    }
  1.1370 +    return true;
  1.1371 +}
  1.1372 +
  1.1373 +bool SkProcCoeffXfermode::asCoeff(Coeff* sc, Coeff* dc) const {
  1.1374 +    if (CANNOT_USE_COEFF == fSrcCoeff) {
  1.1375 +        return false;
  1.1376 +    }
  1.1377 +
  1.1378 +    if (sc) {
  1.1379 +        *sc = fSrcCoeff;
  1.1380 +    }
  1.1381 +    if (dc) {
  1.1382 +        *dc = fDstCoeff;
  1.1383 +    }
  1.1384 +    return true;
  1.1385 +}
  1.1386 +
  1.1387 +#if SK_SUPPORT_GPU
  1.1388 +bool SkProcCoeffXfermode::asNewEffect(GrEffectRef** effect,
  1.1389 +                                      GrTexture* background) const {
  1.1390 +    if (XferEffect::IsSupportedMode(fMode)) {
  1.1391 +        if (NULL != effect) {
  1.1392 +            *effect = XferEffect::Create(fMode, background);
  1.1393 +            SkASSERT(NULL != *effect);
  1.1394 +        }
  1.1395 +        return true;
  1.1396 +    }
  1.1397 +    return false;
  1.1398 +}
  1.1399 +#endif
  1.1400 +
  1.1401 +void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const {
  1.1402 +    this->INHERITED::flatten(buffer);
  1.1403 +    buffer.write32(fMode);
  1.1404 +}
  1.1405 +
  1.1406 +const char* SkXfermode::ModeName(Mode mode) {
  1.1407 +    SkASSERT((unsigned) mode <= (unsigned)kLastMode);
  1.1408 +    const char* gModeStrings[] = {
  1.1409 +        "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
  1.1410 +        "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
  1.1411 +        "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
  1.1412 +        "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
  1.1413 +        "Multiply", "Hue", "Saturation", "Color",  "Luminosity"
  1.1414 +    };
  1.1415 +    return gModeStrings[mode];
  1.1416 +    SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, mode_count);
  1.1417 +}
  1.1418 +
  1.1419 +#ifndef SK_IGNORE_TO_STRING
  1.1420 +void SkProcCoeffXfermode::toString(SkString* str) const {
  1.1421 +    str->append("SkProcCoeffXfermode: ");
  1.1422 +
  1.1423 +    str->append("mode: ");
  1.1424 +    str->append(ModeName(fMode));
  1.1425 +
  1.1426 +    static const char* gCoeffStrings[kCoeffCount] = {
  1.1427 +        "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
  1.1428 +    };
  1.1429 +
  1.1430 +    str->append(" src: ");
  1.1431 +    if (CANNOT_USE_COEFF == fSrcCoeff) {
  1.1432 +        str->append("can't use");
  1.1433 +    } else {
  1.1434 +        str->append(gCoeffStrings[fSrcCoeff]);
  1.1435 +    }
  1.1436 +
  1.1437 +    str->append(" dst: ");
  1.1438 +    if (CANNOT_USE_COEFF == fDstCoeff) {
  1.1439 +        str->append("can't use");
  1.1440 +    } else {
  1.1441 +        str->append(gCoeffStrings[fDstCoeff]);
  1.1442 +    }
  1.1443 +}
  1.1444 +#endif
  1.1445 +
  1.1446 +///////////////////////////////////////////////////////////////////////////////
  1.1447 +
  1.1448 +class SkClearXfermode : public SkProcCoeffXfermode {
  1.1449 +public:
  1.1450 +    static SkClearXfermode* Create(const ProcCoeff& rec) {
  1.1451 +        return SkNEW_ARGS(SkClearXfermode, (rec));
  1.1452 +    }
  1.1453 +
  1.1454 +    virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
  1.1455 +    virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
  1.1456 +
  1.1457 +    SK_TO_STRING_OVERRIDE()
  1.1458 +    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
  1.1459 +
  1.1460 +private:
  1.1461 +    SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
  1.1462 +    SkClearXfermode(SkReadBuffer& buffer)
  1.1463 +        : SkProcCoeffXfermode(buffer) {}
  1.1464 +
  1.1465 +    typedef SkProcCoeffXfermode INHERITED;
  1.1466 +};
  1.1467 +
  1.1468 +void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
  1.1469 +                             const SkPMColor* SK_RESTRICT, int count,
  1.1470 +                             const SkAlpha* SK_RESTRICT aa) const {
  1.1471 +    SkASSERT(dst && count >= 0);
  1.1472 +
  1.1473 +    if (NULL == aa) {
  1.1474 +        memset(dst, 0, count << 2);
  1.1475 +    } else {
  1.1476 +        for (int i = count - 1; i >= 0; --i) {
  1.1477 +            unsigned a = aa[i];
  1.1478 +            if (0xFF == a) {
  1.1479 +                dst[i] = 0;
  1.1480 +            } else if (a != 0) {
  1.1481 +                dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
  1.1482 +            }
  1.1483 +        }
  1.1484 +    }
  1.1485 +}
  1.1486 +void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
  1.1487 +                             const SkPMColor* SK_RESTRICT, int count,
  1.1488 +                             const SkAlpha* SK_RESTRICT aa) const {
  1.1489 +    SkASSERT(dst && count >= 0);
  1.1490 +
  1.1491 +    if (NULL == aa) {
  1.1492 +        memset(dst, 0, count);
  1.1493 +    } else {
  1.1494 +        for (int i = count - 1; i >= 0; --i) {
  1.1495 +            unsigned a = aa[i];
  1.1496 +            if (0xFF == a) {
  1.1497 +                dst[i] = 0;
  1.1498 +            } else if (0 != a) {
  1.1499 +                dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
  1.1500 +            }
  1.1501 +        }
  1.1502 +    }
  1.1503 +}
  1.1504 +
  1.1505 +#ifndef SK_IGNORE_TO_STRING
  1.1506 +void SkClearXfermode::toString(SkString* str) const {
  1.1507 +    this->INHERITED::toString(str);
  1.1508 +}
  1.1509 +#endif
  1.1510 +
  1.1511 +///////////////////////////////////////////////////////////////////////////////
  1.1512 +
  1.1513 +class SkSrcXfermode : public SkProcCoeffXfermode {
  1.1514 +public:
  1.1515 +    static SkSrcXfermode* Create(const ProcCoeff& rec) {
  1.1516 +        return SkNEW_ARGS(SkSrcXfermode, (rec));
  1.1517 +    }
  1.1518 +
  1.1519 +    virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
  1.1520 +    virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
  1.1521 +
  1.1522 +    SK_TO_STRING_OVERRIDE()
  1.1523 +    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
  1.1524 +
  1.1525 +private:
  1.1526 +    SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
  1.1527 +    SkSrcXfermode(SkReadBuffer& buffer)
  1.1528 +        : SkProcCoeffXfermode(buffer) {}
  1.1529 +
  1.1530 +    typedef SkProcCoeffXfermode INHERITED;
  1.1531 +};
  1.1532 +
  1.1533 +void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
  1.1534 +                           const SkPMColor* SK_RESTRICT src, int count,
  1.1535 +                           const SkAlpha* SK_RESTRICT aa) const {
  1.1536 +    SkASSERT(dst && src && count >= 0);
  1.1537 +
  1.1538 +    if (NULL == aa) {
  1.1539 +        memcpy(dst, src, count << 2);
  1.1540 +    } else {
  1.1541 +        for (int i = count - 1; i >= 0; --i) {
  1.1542 +            unsigned a = aa[i];
  1.1543 +            if (a == 0xFF) {
  1.1544 +                dst[i] = src[i];
  1.1545 +            } else if (a != 0) {
  1.1546 +                dst[i] = SkFourByteInterp(src[i], dst[i], a);
  1.1547 +            }
  1.1548 +        }
  1.1549 +    }
  1.1550 +}
  1.1551 +
  1.1552 +void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
  1.1553 +                           const SkPMColor* SK_RESTRICT src, int count,
  1.1554 +                           const SkAlpha* SK_RESTRICT aa) const {
  1.1555 +    SkASSERT(dst && src && count >= 0);
  1.1556 +
  1.1557 +    if (NULL == aa) {
  1.1558 +        for (int i = count - 1; i >= 0; --i) {
  1.1559 +            dst[i] = SkToU8(SkGetPackedA32(src[i]));
  1.1560 +        }
  1.1561 +    } else {
  1.1562 +        for (int i = count - 1; i >= 0; --i) {
  1.1563 +            unsigned a = aa[i];
  1.1564 +            if (0 != a) {
  1.1565 +                unsigned srcA = SkGetPackedA32(src[i]);
  1.1566 +                if (a == 0xFF) {
  1.1567 +                    dst[i] = SkToU8(srcA);
  1.1568 +                } else {
  1.1569 +                    dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
  1.1570 +                }
  1.1571 +            }
  1.1572 +        }
  1.1573 +    }
  1.1574 +}
  1.1575 +#ifndef SK_IGNORE_TO_STRING
  1.1576 +void SkSrcXfermode::toString(SkString* str) const {
  1.1577 +    this->INHERITED::toString(str);
  1.1578 +}
  1.1579 +#endif
  1.1580 +
  1.1581 +///////////////////////////////////////////////////////////////////////////////
  1.1582 +
  1.1583 +class SkDstInXfermode : public SkProcCoeffXfermode {
  1.1584 +public:
  1.1585 +    static SkDstInXfermode* Create(const ProcCoeff& rec) {
  1.1586 +        return SkNEW_ARGS(SkDstInXfermode, (rec));
  1.1587 +    }
  1.1588 +
  1.1589 +    virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
  1.1590 +
  1.1591 +    SK_TO_STRING_OVERRIDE()
  1.1592 +    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstInXfermode)
  1.1593 +
  1.1594 +private:
  1.1595 +    SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
  1.1596 +    SkDstInXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {}
  1.1597 +
  1.1598 +    typedef SkProcCoeffXfermode INHERITED;
  1.1599 +};
  1.1600 +
  1.1601 +void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
  1.1602 +                             const SkPMColor* SK_RESTRICT src, int count,
  1.1603 +                             const SkAlpha* SK_RESTRICT aa) const {
  1.1604 +    SkASSERT(dst && src);
  1.1605 +
  1.1606 +    if (count <= 0) {
  1.1607 +        return;
  1.1608 +    }
  1.1609 +    if (NULL != aa) {
  1.1610 +        return this->INHERITED::xfer32(dst, src, count, aa);
  1.1611 +    }
  1.1612 +
  1.1613 +    do {
  1.1614 +        unsigned a = SkGetPackedA32(*src);
  1.1615 +        *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
  1.1616 +        dst++;
  1.1617 +        src++;
  1.1618 +    } while (--count != 0);
  1.1619 +}
  1.1620 +
  1.1621 +#ifndef SK_IGNORE_TO_STRING
  1.1622 +void SkDstInXfermode::toString(SkString* str) const {
  1.1623 +    this->INHERITED::toString(str);
  1.1624 +}
  1.1625 +#endif
  1.1626 +
  1.1627 +///////////////////////////////////////////////////////////////////////////////
  1.1628 +
  1.1629 +class SkDstOutXfermode : public SkProcCoeffXfermode {
  1.1630 +public:
  1.1631 +    static SkDstOutXfermode* Create(const ProcCoeff& rec) {
  1.1632 +        return SkNEW_ARGS(SkDstOutXfermode, (rec));
  1.1633 +    }
  1.1634 +
  1.1635 +    virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
  1.1636 +
  1.1637 +    SK_TO_STRING_OVERRIDE()
  1.1638 +    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
  1.1639 +
  1.1640 +private:
  1.1641 +    SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
  1.1642 +    SkDstOutXfermode(SkReadBuffer& buffer)
  1.1643 +        : INHERITED(buffer) {}
  1.1644 +
  1.1645 +    typedef SkProcCoeffXfermode INHERITED;
  1.1646 +};
  1.1647 +
  1.1648 +void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
  1.1649 +                              const SkPMColor* SK_RESTRICT src, int count,
  1.1650 +                              const SkAlpha* SK_RESTRICT aa) const {
  1.1651 +    SkASSERT(dst && src);
  1.1652 +
  1.1653 +    if (count <= 0) {
  1.1654 +        return;
  1.1655 +    }
  1.1656 +    if (NULL != aa) {
  1.1657 +        return this->INHERITED::xfer32(dst, src, count, aa);
  1.1658 +    }
  1.1659 +
  1.1660 +    do {
  1.1661 +        unsigned a = SkGetPackedA32(*src);
  1.1662 +        *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
  1.1663 +        dst++;
  1.1664 +        src++;
  1.1665 +    } while (--count != 0);
  1.1666 +}
  1.1667 +
  1.1668 +#ifndef SK_IGNORE_TO_STRING
  1.1669 +void SkDstOutXfermode::toString(SkString* str) const {
  1.1670 +    this->INHERITED::toString(str);
  1.1671 +}
  1.1672 +#endif
  1.1673 +
  1.1674 +///////////////////////////////////////////////////////////////////////////////
  1.1675 +
  1.1676 +SK_DECLARE_STATIC_MUTEX(gCachedXfermodesMutex);
  1.1677 +static SkXfermode* gCachedXfermodes[SkXfermode::kLastMode + 1];
  1.1678 +
  1.1679 +void SkXfermode::Term() {
  1.1680 +    SkAutoMutexAcquire ac(gCachedXfermodesMutex);
  1.1681 +
  1.1682 +    for (size_t i = 0; i < SK_ARRAY_COUNT(gCachedXfermodes); ++i) {
  1.1683 +        SkSafeUnref(gCachedXfermodes[i]);
  1.1684 +        gCachedXfermodes[i] = NULL;
  1.1685 +    }
  1.1686 +}
  1.1687 +
  1.1688 +extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec,
  1.1689 +                                                      SkXfermode::Mode mode);
  1.1690 +extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
  1.1691 +
  1.1692 +SkXfermode* SkXfermode::Create(Mode mode) {
  1.1693 +    SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
  1.1694 +    SkASSERT(SK_ARRAY_COUNT(gCachedXfermodes) == kModeCount);
  1.1695 +
  1.1696 +    if ((unsigned)mode >= kModeCount) {
  1.1697 +        // report error
  1.1698 +        return NULL;
  1.1699 +    }
  1.1700 +
  1.1701 +    // Skia's "defaut" mode is srcover. NULL in SkPaint is interpreted as srcover
  1.1702 +    // so we can just return NULL from the factory.
  1.1703 +    if (kSrcOver_Mode == mode) {
  1.1704 +        return NULL;
  1.1705 +    }
  1.1706 +
  1.1707 +    // guard our access to gCachedXfermodes, since we may write into it
  1.1708 +    SkAutoMutexAcquire ac(gCachedXfermodesMutex);
  1.1709 +
  1.1710 +    SkXfermode* xfer = gCachedXfermodes[mode];
  1.1711 +    if (NULL == xfer) {
  1.1712 +        ProcCoeff rec = gProcCoeffs[mode];
  1.1713 +
  1.1714 +        SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
  1.1715 +
  1.1716 +        if (pp != NULL) {
  1.1717 +            rec.fProc = pp;
  1.1718 +        }
  1.1719 +
  1.1720 +        // check if we have a platform optim for that
  1.1721 +        SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
  1.1722 +        if (xfm != NULL) {
  1.1723 +            xfer = xfm;
  1.1724 +        } else {
  1.1725 +            // All modes can in theory be represented by the ProcCoeff rec, since
  1.1726 +            // it contains function ptrs. However, a few modes are both simple and
  1.1727 +            // commonly used, so we call those out for their own subclasses here.
  1.1728 +            switch (mode) {
  1.1729 +                case kClear_Mode:
  1.1730 +                    xfer = SkClearXfermode::Create(rec);
  1.1731 +                    break;
  1.1732 +                case kSrc_Mode:
  1.1733 +                    xfer = SkSrcXfermode::Create(rec);
  1.1734 +                    break;
  1.1735 +                case kSrcOver_Mode:
  1.1736 +                    SkASSERT(false);    // should not land here
  1.1737 +                    break;
  1.1738 +                case kDstIn_Mode:
  1.1739 +                    xfer = SkDstInXfermode::Create(rec);
  1.1740 +                    break;
  1.1741 +                case kDstOut_Mode:
  1.1742 +                    xfer = SkDstOutXfermode::Create(rec);
  1.1743 +                    break;
  1.1744 +                default:
  1.1745 +                    // no special-case, just rely in the rec and its function-ptrs
  1.1746 +                    xfer = SkProcCoeffXfermode::Create(rec, mode);
  1.1747 +                    break;
  1.1748 +            }
  1.1749 +        }
  1.1750 +        gCachedXfermodes[mode] = xfer;
  1.1751 +    }
  1.1752 +    return SkSafeRef(xfer);
  1.1753 +}
  1.1754 +
  1.1755 +SkXfermodeProc SkXfermode::GetProc(Mode mode) {
  1.1756 +    SkXfermodeProc  proc = NULL;
  1.1757 +    if ((unsigned)mode < kModeCount) {
  1.1758 +        proc = gProcCoeffs[mode].fProc;
  1.1759 +    }
  1.1760 +    return proc;
  1.1761 +}
  1.1762 +
  1.1763 +bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
  1.1764 +    SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
  1.1765 +
  1.1766 +    if ((unsigned)mode >= (unsigned)kModeCount) {
  1.1767 +        // illegal mode parameter
  1.1768 +        return false;
  1.1769 +    }
  1.1770 +
  1.1771 +    const ProcCoeff& rec = gProcCoeffs[mode];
  1.1772 +
  1.1773 +    if (CANNOT_USE_COEFF == rec.fSC) {
  1.1774 +        return false;
  1.1775 +    }
  1.1776 +
  1.1777 +    SkASSERT(CANNOT_USE_COEFF != rec.fDC);
  1.1778 +    if (src) {
  1.1779 +        *src = rec.fSC;
  1.1780 +    }
  1.1781 +    if (dst) {
  1.1782 +        *dst = rec.fDC;
  1.1783 +    }
  1.1784 +    return true;
  1.1785 +}
  1.1786 +
  1.1787 +bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
  1.1788 +    if (NULL == xfer) {
  1.1789 +        if (mode) {
  1.1790 +            *mode = kSrcOver_Mode;
  1.1791 +        }
  1.1792 +        return true;
  1.1793 +    }
  1.1794 +    return xfer->asMode(mode);
  1.1795 +}
  1.1796 +
  1.1797 +bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
  1.1798 +    if (NULL == xfer) {
  1.1799 +        return ModeAsCoeff(kSrcOver_Mode, src, dst);
  1.1800 +    }
  1.1801 +    return xfer->asCoeff(src, dst);
  1.1802 +}
  1.1803 +
  1.1804 +bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
  1.1805 +    // if xfer==null then the mode is srcover
  1.1806 +    Mode m = kSrcOver_Mode;
  1.1807 +    if (xfer && !xfer->asMode(&m)) {
  1.1808 +        return false;
  1.1809 +    }
  1.1810 +    return mode == m;
  1.1811 +}
  1.1812 +
  1.1813 +///////////////////////////////////////////////////////////////////////////////
  1.1814 +//////////// 16bit xfermode procs
  1.1815 +
  1.1816 +#ifdef SK_DEBUG
  1.1817 +static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
  1.1818 +static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
  1.1819 +#endif
  1.1820 +
  1.1821 +static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
  1.1822 +    SkASSERT(require_255(src));
  1.1823 +    return SkPixel32ToPixel16(src);
  1.1824 +}
  1.1825 +
  1.1826 +static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
  1.1827 +    return dst;
  1.1828 +}
  1.1829 +
  1.1830 +static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
  1.1831 +    SkASSERT(require_0(src));
  1.1832 +    return dst;
  1.1833 +}
  1.1834 +
  1.1835 +static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
  1.1836 +    SkASSERT(require_255(src));
  1.1837 +    return SkPixel32ToPixel16(src);
  1.1838 +}
  1.1839 +
  1.1840 +static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
  1.1841 +    SkASSERT(require_0(src));
  1.1842 +    return dst;
  1.1843 +}
  1.1844 +
  1.1845 +static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
  1.1846 +    SkASSERT(require_255(src));
  1.1847 +    return dst;
  1.1848 +}
  1.1849 +
  1.1850 +static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
  1.1851 +    SkASSERT(require_255(src));
  1.1852 +    return SkPixel32ToPixel16(src);
  1.1853 +}
  1.1854 +
  1.1855 +static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
  1.1856 +    SkASSERT(require_255(src));
  1.1857 +    return dst;
  1.1858 +}
  1.1859 +
  1.1860 +static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
  1.1861 +    SkASSERT(require_0(src));
  1.1862 +    return dst;
  1.1863 +}
  1.1864 +
  1.1865 +static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
  1.1866 +    unsigned isa = 255 - SkGetPackedA32(src);
  1.1867 +
  1.1868 +    return SkPackRGB16(
  1.1869 +           SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
  1.1870 +           SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
  1.1871 +           SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
  1.1872 +}
  1.1873 +
  1.1874 +static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
  1.1875 +    SkASSERT(require_0(src));
  1.1876 +    return dst;
  1.1877 +}
  1.1878 +
  1.1879 +static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
  1.1880 +    SkASSERT(require_255(src));
  1.1881 +    return SkPixel32ToPixel16(src);
  1.1882 +}
  1.1883 +
  1.1884 +static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
  1.1885 +    SkASSERT(require_255(src));
  1.1886 +    return dst;
  1.1887 +}
  1.1888 +
  1.1889 +/*********
  1.1890 +    darken and lighten boil down to this.
  1.1891 +
  1.1892 +    darken  = (1 - Sa) * Dc + min(Sc, Dc)
  1.1893 +    lighten = (1 - Sa) * Dc + max(Sc, Dc)
  1.1894 +
  1.1895 +    if (Sa == 0) these become
  1.1896 +        darken  = Dc + min(0, Dc) = 0
  1.1897 +        lighten = Dc + max(0, Dc) = Dc
  1.1898 +
  1.1899 +    if (Sa == 1) these become
  1.1900 +        darken  = min(Sc, Dc)
  1.1901 +        lighten = max(Sc, Dc)
  1.1902 +*/
  1.1903 +
  1.1904 +static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
  1.1905 +    SkASSERT(require_0(src));
  1.1906 +    return 0;
  1.1907 +}
  1.1908 +
  1.1909 +static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
  1.1910 +    SkASSERT(require_255(src));
  1.1911 +    unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
  1.1912 +    unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
  1.1913 +    unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
  1.1914 +    return SkPackRGB16(r, g, b);
  1.1915 +}
  1.1916 +
  1.1917 +static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
  1.1918 +    SkASSERT(require_0(src));
  1.1919 +    return dst;
  1.1920 +}
  1.1921 +
  1.1922 +static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
  1.1923 +    SkASSERT(require_255(src));
  1.1924 +    unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
  1.1925 +    unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
  1.1926 +    unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
  1.1927 +    return SkPackRGB16(r, g, b);
  1.1928 +}
  1.1929 +
  1.1930 +struct Proc16Rec {
  1.1931 +    SkXfermodeProc16    fProc16_0;
  1.1932 +    SkXfermodeProc16    fProc16_255;
  1.1933 +    SkXfermodeProc16    fProc16_General;
  1.1934 +};
  1.1935 +
  1.1936 +static const Proc16Rec gModeProcs16[] = {
  1.1937 +    { NULL,                 NULL,                   NULL            }, // CLEAR
  1.1938 +    { NULL,                 src_modeproc16_255,     NULL            },
  1.1939 +    { dst_modeproc16,       dst_modeproc16,         dst_modeproc16  },
  1.1940 +    { srcover_modeproc16_0, srcover_modeproc16_255, NULL            },
  1.1941 +    { dstover_modeproc16_0, dstover_modeproc16_255, NULL            },
  1.1942 +    { NULL,                 srcin_modeproc16_255,   NULL            },
  1.1943 +    { NULL,                 dstin_modeproc16_255,   NULL            },
  1.1944 +    { NULL,                 NULL,                   NULL            },// SRC_OUT
  1.1945 +    { dstout_modeproc16_0,  NULL,                   NULL            },
  1.1946 +    { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16  },
  1.1947 +    { NULL,                 dstatop_modeproc16_255, NULL            },
  1.1948 +    { NULL,                 NULL,                   NULL            }, // XOR
  1.1949 +
  1.1950 +    { NULL,                 NULL,                   NULL            }, // plus
  1.1951 +    { NULL,                 NULL,                   NULL            }, // modulate
  1.1952 +    { NULL,                 NULL,                   NULL            }, // screen
  1.1953 +    { NULL,                 NULL,                   NULL            }, // overlay
  1.1954 +    { darken_modeproc16_0,  darken_modeproc16_255,  NULL            }, // darken
  1.1955 +    { lighten_modeproc16_0, lighten_modeproc16_255, NULL            }, // lighten
  1.1956 +    { NULL,                 NULL,                   NULL            }, // colordodge
  1.1957 +    { NULL,                 NULL,                   NULL            }, // colorburn
  1.1958 +    { NULL,                 NULL,                   NULL            }, // hardlight
  1.1959 +    { NULL,                 NULL,                   NULL            }, // softlight
  1.1960 +    { NULL,                 NULL,                   NULL            }, // difference
  1.1961 +    { NULL,                 NULL,                   NULL            }, // exclusion
  1.1962 +    { NULL,                 NULL,                   NULL            }, // multiply
  1.1963 +    { NULL,                 NULL,                   NULL            }, // hue
  1.1964 +    { NULL,                 NULL,                   NULL            }, // saturation
  1.1965 +    { NULL,                 NULL,                   NULL            }, // color
  1.1966 +    { NULL,                 NULL,                   NULL            }, // luminosity
  1.1967 +};
  1.1968 +
  1.1969 +SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
  1.1970 +    SkXfermodeProc16  proc16 = NULL;
  1.1971 +    if ((unsigned)mode < kModeCount) {
  1.1972 +        const Proc16Rec& rec = gModeProcs16[mode];
  1.1973 +        unsigned a = SkColorGetA(srcColor);
  1.1974 +
  1.1975 +        if (0 == a) {
  1.1976 +            proc16 = rec.fProc16_0;
  1.1977 +        } else if (255 == a) {
  1.1978 +            proc16 = rec.fProc16_255;
  1.1979 +        } else {
  1.1980 +            proc16 = rec.fProc16_General;
  1.1981 +        }
  1.1982 +    }
  1.1983 +    return proc16;
  1.1984 +}
  1.1985 +
  1.1986 +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
  1.1987 +    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
  1.1988 +    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
  1.1989 +    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
  1.1990 +    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
  1.1991 +    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
  1.1992 +#if !SK_ARM_NEON_IS_NONE
  1.1993 +    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkNEONProcCoeffXfermode)
  1.1994 +#endif
  1.1995 +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END

mercurial