SkXfermode.cpp revision 8d3cd7a170c810e3816bf00220cbef51e7b16795
1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkXfermode.h"
11#include "SkColorPriv.h"
12#include "SkFlattenableBuffers.h"
13#include "SkMathPriv.h"
14#include "SkString.h"
15
16SK_DEFINE_INST_COUNT(SkXfermode)
17
18#define SkAlphaMulAlpha(a, b)   SkMulDiv255Round(a, b)
19
20#if 0
21// idea for higher precision blends in xfer procs (and slightly faster)
22// see DstATop as a probable caller
23static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
24    SkASSERT(a <= 255);
25    SkASSERT(b <= 255);
26    SkASSERT(c <= 255);
27    SkASSERT(d <= 255);
28    unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
29    unsigned result = (prod + (prod >> 8)) >> 8;
30    SkASSERT(result <= 255);
31    return result;
32}
33#endif
34
35static inline unsigned saturated_add(unsigned a, unsigned b) {
36    SkASSERT(a <= 255);
37    SkASSERT(b <= 255);
38    unsigned sum = a + b;
39    if (sum > 255) {
40        sum = 255;
41    }
42    return sum;
43}
44
45static inline int clamp_signed_byte(int n) {
46    if (n < 0) {
47        n = 0;
48    } else if (n > 255) {
49        n = 255;
50    }
51    return n;
52}
53
54static inline int clamp_div255round(int prod) {
55    if (prod <= 0) {
56        return 0;
57    } else if (prod >= 255*255) {
58        return 255;
59    } else {
60        return SkDiv255Round(prod);
61    }
62}
63
64static inline int clamp_max(int value, int max) {
65    if (value > max) {
66        value = max;
67    }
68    return value;
69}
70
71///////////////////////////////////////////////////////////////////////////////
72
73//  kClear_Mode,    //!< [0, 0]
74static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
75    return 0;
76}
77
78//  kSrc_Mode,      //!< [Sa, Sc]
79static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
80    return src;
81}
82
83//  kDst_Mode,      //!< [Da, Dc]
84static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
85    return dst;
86}
87
88//  kSrcOver_Mode,  //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
89static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
90#if 0
91    // this is the old, more-correct way, but it doesn't guarantee that dst==255
92    // will always stay opaque
93    return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
94#else
95    // this is slightly faster, but more importantly guarantees that dst==255
96    // will always stay opaque
97    return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
98#endif
99}
100
101//  kDstOver_Mode,  //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
102static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
103    // this is the reverse of srcover, just flipping src and dst
104    // see srcover's comment about the 256 for opaqueness guarantees
105    return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
106}
107
108//  kSrcIn_Mode,    //!< [Sa * Da, Sc * Da]
109static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
110    return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
111}
112
113//  kDstIn_Mode,    //!< [Sa * Da, Sa * Dc]
114static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
115    return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
116}
117
118//  kSrcOut_Mode,   //!< [Sa * (1 - Da), Sc * (1 - Da)]
119static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
120    return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
121}
122
123//  kDstOut_Mode,   //!< [Da * (1 - Sa), Dc * (1 - Sa)]
124static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
125    return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
126}
127
128//  kSrcATop_Mode,  //!< [Da, Sc * Da + (1 - Sa) * Dc]
129static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
130    unsigned sa = SkGetPackedA32(src);
131    unsigned da = SkGetPackedA32(dst);
132    unsigned isa = 255 - sa;
133
134    return SkPackARGB32(da,
135                        SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
136                            SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
137                        SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
138                            SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
139                        SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
140                            SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
141}
142
143//  kDstATop_Mode,  //!< [Sa, Sa * Dc + Sc * (1 - Da)]
144static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
145    unsigned sa = SkGetPackedA32(src);
146    unsigned da = SkGetPackedA32(dst);
147    unsigned ida = 255 - da;
148
149    return SkPackARGB32(sa,
150                        SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
151                            SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
152                        SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
153                            SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
154                        SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
155                            SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
156}
157
158//  kXor_Mode   [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
159static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
160    unsigned sa = SkGetPackedA32(src);
161    unsigned da = SkGetPackedA32(dst);
162    unsigned isa = 255 - sa;
163    unsigned ida = 255 - da;
164
165    return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
166                        SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
167                            SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
168                        SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
169                            SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
170                        SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
171                            SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
172}
173
174///////////////////////////////////////////////////////////////////////////////
175
176// kPlus_Mode
177static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
178    unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
179    unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
180    unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
181    unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
182    return SkPackARGB32(a, r, g, b);
183}
184
185// kModulate_Mode
186static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) {
187    int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
188    int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
189    int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
190    int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
191    return SkPackARGB32(a, r, g, b);
192}
193
194// kScreen_Mode
195static inline int srcover_byte(int a, int b) {
196    return a + b - SkAlphaMulAlpha(a, b);
197}
198static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
199    int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
200    int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
201    int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
202    int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
203    return SkPackARGB32(a, r, g, b);
204}
205
206// kOverlay_Mode
207static inline int overlay_byte(int sc, int dc, int sa, int da) {
208    int tmp = sc * (255 - da) + dc * (255 - sa);
209    int rc;
210    if (2 * dc <= da) {
211        rc = 2 * sc * dc;
212    } else {
213        rc = sa * da - 2 * (da - dc) * (sa - sc);
214    }
215    return clamp_div255round(rc + tmp);
216}
217static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
218    int sa = SkGetPackedA32(src);
219    int da = SkGetPackedA32(dst);
220    int a = srcover_byte(sa, da);
221    int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
222    int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
223    int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
224    return SkPackARGB32(a, r, g, b);
225}
226
227// kDarken_Mode
228static inline int darken_byte(int sc, int dc, int sa, int da) {
229    int sd = sc * da;
230    int ds = dc * sa;
231    if (sd < ds) {
232        // srcover
233        return sc + dc - SkDiv255Round(ds);
234    } else {
235        // dstover
236        return dc + sc - SkDiv255Round(sd);
237    }
238}
239static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
240    int sa = SkGetPackedA32(src);
241    int da = SkGetPackedA32(dst);
242    int a = srcover_byte(sa, da);
243    int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
244    int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
245    int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
246    return SkPackARGB32(a, r, g, b);
247}
248
249// kLighten_Mode
250static inline int lighten_byte(int sc, int dc, int sa, int da) {
251    int sd = sc * da;
252    int ds = dc * sa;
253    if (sd > ds) {
254        // srcover
255        return sc + dc - SkDiv255Round(ds);
256    } else {
257        // dstover
258        return dc + sc - SkDiv255Round(sd);
259    }
260}
261static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
262    int sa = SkGetPackedA32(src);
263    int da = SkGetPackedA32(dst);
264    int a = srcover_byte(sa, da);
265    int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
266    int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
267    int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
268    return SkPackARGB32(a, r, g, b);
269}
270
271// kColorDodge_Mode
272static inline int colordodge_byte(int sc, int dc, int sa, int da) {
273    int diff = sa - sc;
274    int rc;
275    if (0 == diff) {
276        rc = sa * da + sc * (255 - da) + dc * (255 - sa);
277        rc = SkDiv255Round(rc);
278    } else {
279        int tmp = (dc * sa << 15) / (da * diff);
280        rc = SkDiv255Round(sa * da) * tmp >> 15;
281        // don't clamp here, since we'll do it in our modeproc
282    }
283    return rc;
284}
285static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
286    // added to avoid div-by-zero in colordodge_byte
287    if (0 == dst) {
288        return src;
289    }
290
291    int sa = SkGetPackedA32(src);
292    int da = SkGetPackedA32(dst);
293    int a = srcover_byte(sa, da);
294    int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
295    int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
296    int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
297    r = clamp_max(r, a);
298    g = clamp_max(g, a);
299    b = clamp_max(b, a);
300    return SkPackARGB32(a, r, g, b);
301}
302
303// kColorBurn_Mode
304static inline int colorburn_byte(int sc, int dc, int sa, int da) {
305    int rc;
306    if (dc == da && 0 == sc) {
307        rc = sa * da + dc * (255 - sa);
308    } else if (0 == sc) {
309        return SkAlphaMulAlpha(dc, 255 - sa);
310    } else {
311        int tmp = (sa * (da - dc) * 256) / (sc * da);
312        if (tmp > 256) {
313            tmp = 256;
314        }
315        int tmp2 = sa * da;
316        rc = tmp2 - (tmp2 * tmp >> 8) + sc * (255 - da) + dc * (255 - sa);
317    }
318    return SkDiv255Round(rc);
319}
320static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
321    // added to avoid div-by-zero in colorburn_byte
322    if (0 == dst) {
323        return src;
324    }
325
326    int sa = SkGetPackedA32(src);
327    int da = SkGetPackedA32(dst);
328    int a = srcover_byte(sa, da);
329    int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
330    int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
331    int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
332    return SkPackARGB32(a, r, g, b);
333}
334
335// kHardLight_Mode
336static inline int hardlight_byte(int sc, int dc, int sa, int da) {
337    int rc;
338    if (2 * sc <= sa) {
339        rc = 2 * sc * dc;
340    } else {
341        rc = sa * da - 2 * (da - dc) * (sa - sc);
342    }
343    return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
344}
345static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
346    int sa = SkGetPackedA32(src);
347    int da = SkGetPackedA32(dst);
348    int a = srcover_byte(sa, da);
349    int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
350    int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
351    int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
352    return SkPackARGB32(a, r, g, b);
353}
354
355// returns 255 * sqrt(n/255)
356static U8CPU sqrt_unit_byte(U8CPU n) {
357    return SkSqrtBits(n, 15+4);
358}
359
360// kSoftLight_Mode
361static inline int softlight_byte(int sc, int dc, int sa, int da) {
362    int m = da ? dc * 256 / da : 0;
363    int rc;
364    if (2 * sc <= sa) {
365        rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
366    } else if (4 * dc <= da) {
367        int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
368        rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
369    } else {
370        int tmp = sqrt_unit_byte(m) - m;
371        rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
372    }
373    return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
374}
375static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
376    int sa = SkGetPackedA32(src);
377    int da = SkGetPackedA32(dst);
378    int a = srcover_byte(sa, da);
379    int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
380    int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
381    int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
382    return SkPackARGB32(a, r, g, b);
383}
384
385// kDifference_Mode
386static inline int difference_byte(int sc, int dc, int sa, int da) {
387    int tmp = SkMin32(sc * da, dc * sa);
388    return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
389}
390static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
391    int sa = SkGetPackedA32(src);
392    int da = SkGetPackedA32(dst);
393    int a = srcover_byte(sa, da);
394    int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
395    int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
396    int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
397    return SkPackARGB32(a, r, g, b);
398}
399
400// kExclusion_Mode
401static inline int exclusion_byte(int sc, int dc, int sa, int da) {
402    // this equations is wacky, wait for SVG to confirm it
403    int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
404    return clamp_div255round(r);
405}
406static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
407    int sa = SkGetPackedA32(src);
408    int da = SkGetPackedA32(dst);
409    int a = srcover_byte(sa, da);
410    int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
411    int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
412    int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
413    return SkPackARGB32(a, r, g, b);
414}
415
416struct ProcCoeff {
417    SkXfermodeProc      fProc;
418    SkXfermode::Coeff   fSC;
419    SkXfermode::Coeff   fDC;
420};
421
422#define CANNOT_USE_COEFF    SkXfermode::Coeff(-1)
423
424static const ProcCoeff gProcCoeffs[] = {
425    { clear_modeproc,   SkXfermode::kZero_Coeff,    SkXfermode::kZero_Coeff },
426    { src_modeproc,     SkXfermode::kOne_Coeff,     SkXfermode::kZero_Coeff },
427    { dst_modeproc,     SkXfermode::kZero_Coeff,    SkXfermode::kOne_Coeff },
428    { srcover_modeproc, SkXfermode::kOne_Coeff,     SkXfermode::kISA_Coeff },
429    { dstover_modeproc, SkXfermode::kIDA_Coeff,     SkXfermode::kOne_Coeff },
430    { srcin_modeproc,   SkXfermode::kDA_Coeff,      SkXfermode::kZero_Coeff },
431    { dstin_modeproc,   SkXfermode::kZero_Coeff,    SkXfermode::kSA_Coeff },
432    { srcout_modeproc,  SkXfermode::kIDA_Coeff,     SkXfermode::kZero_Coeff },
433    { dstout_modeproc,  SkXfermode::kZero_Coeff,    SkXfermode::kISA_Coeff },
434    { srcatop_modeproc, SkXfermode::kDA_Coeff,      SkXfermode::kISA_Coeff },
435    { dstatop_modeproc, SkXfermode::kIDA_Coeff,     SkXfermode::kSA_Coeff },
436    { xor_modeproc,     SkXfermode::kIDA_Coeff,     SkXfermode::kISA_Coeff },
437
438    { plus_modeproc,    SkXfermode::kOne_Coeff,     SkXfermode::kOne_Coeff },
439    { modulate_modeproc,SkXfermode::kZero_Coeff,    SkXfermode::kSC_Coeff },
440    { screen_modeproc,      CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
441    { overlay_modeproc,     CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
442    { darken_modeproc,      CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
443    { lighten_modeproc,     CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
444    { colordodge_modeproc,  CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
445    { colorburn_modeproc,   CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
446    { hardlight_modeproc,   CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
447    { softlight_modeproc,   CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
448    { difference_modeproc,  CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
449    { exclusion_modeproc,   CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
450};
451
452///////////////////////////////////////////////////////////////////////////////
453
454bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) const {
455    return false;
456}
457
458bool SkXfermode::asMode(Mode* mode) const {
459    return false;
460}
461
462SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
463    // no-op. subclasses should override this
464    return dst;
465}
466
467void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
468                        const SkPMColor* SK_RESTRICT src, int count,
469                        const SkAlpha* SK_RESTRICT aa) const {
470    SkASSERT(dst && src && count >= 0);
471
472    if (NULL == aa) {
473        for (int i = count - 1; i >= 0; --i) {
474            dst[i] = this->xferColor(src[i], dst[i]);
475        }
476    } else {
477        for (int i = count - 1; i >= 0; --i) {
478            unsigned a = aa[i];
479            if (0 != a) {
480                SkPMColor dstC = dst[i];
481                SkPMColor C = this->xferColor(src[i], dstC);
482                if (0xFF != a) {
483                    C = SkFourByteInterp(C, dstC, a);
484                }
485                dst[i] = C;
486            }
487        }
488    }
489}
490
491void SkXfermode::xfer16(uint16_t* dst,
492                        const SkPMColor* SK_RESTRICT src, int count,
493                        const SkAlpha* SK_RESTRICT aa) const {
494    SkASSERT(dst && src && count >= 0);
495
496    if (NULL == aa) {
497        for (int i = count - 1; i >= 0; --i) {
498            SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
499            dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
500        }
501    } else {
502        for (int i = count - 1; i >= 0; --i) {
503            unsigned a = aa[i];
504            if (0 != a) {
505                SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
506                SkPMColor C = this->xferColor(src[i], dstC);
507                if (0xFF != a) {
508                    C = SkFourByteInterp(C, dstC, a);
509                }
510                dst[i] = SkPixel32ToPixel16_ToU16(C);
511            }
512        }
513    }
514}
515
516void SkXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
517                          const SkPMColor* SK_RESTRICT src, int count,
518                          const SkAlpha* SK_RESTRICT aa) const {
519    SkASSERT(dst && src && count >= 0);
520
521    if (NULL == aa) {
522        for (int i = count - 1; i >= 0; --i) {
523            SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
524            dst[i] = SkPixel32ToPixel4444(this->xferColor(src[i], dstC));
525        }
526    } else {
527        for (int i = count - 1; i >= 0; --i) {
528            unsigned a = aa[i];
529            if (0 != a) {
530                SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
531                SkPMColor C = this->xferColor(src[i], dstC);
532                if (0xFF != a) {
533                    C = SkFourByteInterp(C, dstC, a);
534                }
535                dst[i] = SkPixel32ToPixel4444(C);
536            }
537        }
538    }
539}
540
541void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
542                        const SkPMColor src[], int count,
543                        const SkAlpha* SK_RESTRICT aa) const {
544    SkASSERT(dst && src && count >= 0);
545
546    if (NULL == aa) {
547        for (int i = count - 1; i >= 0; --i) {
548            SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
549            dst[i] = SkToU8(SkGetPackedA32(res));
550        }
551    } else {
552        for (int i = count - 1; i >= 0; --i) {
553            unsigned a = aa[i];
554            if (0 != a) {
555                SkAlpha dstA = dst[i];
556                unsigned A = SkGetPackedA32(this->xferColor(src[i],
557                                            (SkPMColor)(dstA << SK_A32_SHIFT)));
558                if (0xFF != a) {
559                    A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
560                }
561                dst[i] = SkToU8(A);
562            }
563        }
564    }
565}
566
567///////////////////////////////////////////////////////////////////////////////
568
569void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
570                            const SkPMColor* SK_RESTRICT src, int count,
571                            const SkAlpha* SK_RESTRICT aa) const {
572    SkASSERT(dst && src && count >= 0);
573
574    SkXfermodeProc proc = fProc;
575
576    if (NULL != proc) {
577        if (NULL == aa) {
578            for (int i = count - 1; i >= 0; --i) {
579                dst[i] = proc(src[i], dst[i]);
580            }
581        } else {
582            for (int i = count - 1; i >= 0; --i) {
583                unsigned a = aa[i];
584                if (0 != a) {
585                    SkPMColor dstC = dst[i];
586                    SkPMColor C = proc(src[i], dstC);
587                    if (a != 0xFF) {
588                        C = SkFourByteInterp(C, dstC, a);
589                    }
590                    dst[i] = C;
591                }
592            }
593        }
594    }
595}
596
597void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
598                            const SkPMColor* SK_RESTRICT src, int count,
599                            const SkAlpha* SK_RESTRICT aa) const {
600    SkASSERT(dst && src && count >= 0);
601
602    SkXfermodeProc proc = fProc;
603
604    if (NULL != proc) {
605        if (NULL == aa) {
606            for (int i = count - 1; i >= 0; --i) {
607                SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
608                dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
609            }
610        } else {
611            for (int i = count - 1; i >= 0; --i) {
612                unsigned a = aa[i];
613                if (0 != a) {
614                    SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
615                    SkPMColor C = proc(src[i], dstC);
616                    if (0xFF != a) {
617                        C = SkFourByteInterp(C, dstC, a);
618                    }
619                    dst[i] = SkPixel32ToPixel16_ToU16(C);
620                }
621            }
622        }
623    }
624}
625
626void SkProcXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
627                              const SkPMColor* SK_RESTRICT src, int count,
628                              const SkAlpha* SK_RESTRICT aa) const {
629    SkASSERT(dst && src && count >= 0);
630
631    SkXfermodeProc proc = fProc;
632
633    if (NULL != proc) {
634        if (NULL == aa) {
635            for (int i = count - 1; i >= 0; --i) {
636                SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
637                dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
638            }
639        } else {
640            for (int i = count - 1; i >= 0; --i) {
641                unsigned a = aa[i];
642                if (0 != a) {
643                    SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
644                    SkPMColor C = proc(src[i], dstC);
645                    if (0xFF != a) {
646                        C = SkFourByteInterp(C, dstC, a);
647                    }
648                    dst[i] = SkPixel32ToPixel4444(C);
649                }
650            }
651        }
652    }
653}
654
655void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
656                            const SkPMColor* SK_RESTRICT src, int count,
657                            const SkAlpha* SK_RESTRICT aa) const {
658    SkASSERT(dst && src && count >= 0);
659
660    SkXfermodeProc proc = fProc;
661
662    if (NULL != proc) {
663        if (NULL == aa) {
664            for (int i = count - 1; i >= 0; --i) {
665                SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
666                dst[i] = SkToU8(SkGetPackedA32(res));
667            }
668        } else {
669            for (int i = count - 1; i >= 0; --i) {
670                unsigned a = aa[i];
671                if (0 != a) {
672                    SkAlpha dstA = dst[i];
673                    SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
674                    unsigned A = SkGetPackedA32(res);
675                    if (0xFF != a) {
676                        A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
677                    }
678                    dst[i] = SkToU8(A);
679                }
680            }
681        }
682    }
683}
684
685SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
686        : SkXfermode(buffer) {
687    fProc = NULL;
688    if (!buffer.isCrossProcess()) {
689        fProc = (SkXfermodeProc)buffer.readFunctionPtr();
690    }
691}
692
693void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
694    this->INHERITED::flatten(buffer);
695    if (!buffer.isCrossProcess()) {
696        buffer.writeFunctionPtr((void*)fProc);
697    }
698}
699
700#ifdef SK_DEVELOPER
701void SkProcXfermode::toString(SkString* str) const {
702    str->appendf("SkProcXfermode: %p", fProc);
703}
704#endif
705
706///////////////////////////////////////////////////////////////////////////////
707///////////////////////////////////////////////////////////////////////////////
708
709class SkProcCoeffXfermode : public SkProcXfermode {
710public:
711    SkProcCoeffXfermode(const ProcCoeff& rec, Mode mode)
712            : INHERITED(rec.fProc) {
713        fMode = mode;
714        // these may be valid, or may be CANNOT_USE_COEFF
715        fSrcCoeff = rec.fSC;
716        fDstCoeff = rec.fDC;
717    }
718
719    virtual bool asMode(Mode* mode) const SK_OVERRIDE {
720        if (mode) {
721            *mode = fMode;
722        }
723        return true;
724    }
725
726    virtual bool asCoeff(Coeff* sc, Coeff* dc) const SK_OVERRIDE {
727        if (CANNOT_USE_COEFF == fSrcCoeff) {
728            return false;
729        }
730
731        if (sc) {
732            *sc = fSrcCoeff;
733        }
734        if (dc) {
735            *dc = fDstCoeff;
736        }
737        return true;
738    }
739
740    SK_DEVELOPER_TO_STRING()
741    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkProcCoeffXfermode)
742
743protected:
744    SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
745        fMode = (SkXfermode::Mode)buffer.read32();
746
747        const ProcCoeff& rec = gProcCoeffs[fMode];
748        // these may be valid, or may be CANNOT_USE_COEFF
749        fSrcCoeff = rec.fSC;
750        fDstCoeff = rec.fDC;
751        // now update our function-ptr in the super class
752        this->INHERITED::setProc(rec.fProc);
753    }
754
755    virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
756        this->INHERITED::flatten(buffer);
757        buffer.write32(fMode);
758    }
759
760private:
761    Mode    fMode;
762    Coeff   fSrcCoeff, fDstCoeff;
763
764    typedef SkProcXfermode INHERITED;
765};
766
767#ifdef SK_DEVELOPER
768void SkProcCoeffXfermode::toString(SkString* str) const {
769    str->append("SkProcCoeffXfermode: ");
770
771    const char *gModeStrings[kLastMode+1] = {
772        "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
773        "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
774        "Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
775        "ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion"
776    };
777
778    str->append("mode: ");
779    str->append(gModeStrings[fMode]);
780
781    static const char* gCoeffStrings[kCoeffCount] = {
782        "Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
783    };
784
785    str->append(" src: ");
786    if (CANNOT_USE_COEFF == fSrcCoeff) {
787        str->append("can't use");
788    } else {
789        str->append(gCoeffStrings[fSrcCoeff]);
790    }
791
792    str->append(" dst: ");
793    if (CANNOT_USE_COEFF == fDstCoeff) {
794        str->append("can't use");
795    } else {
796        str->append(gCoeffStrings[fDstCoeff]);
797    }
798}
799#endif
800
801///////////////////////////////////////////////////////////////////////////////
802
803class SkClearXfermode : public SkProcCoeffXfermode {
804public:
805    SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
806
807    virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
808    virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
809
810    SK_DEVELOPER_TO_STRING()
811    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
812
813private:
814    SkClearXfermode(SkFlattenableReadBuffer& buffer)
815        : SkProcCoeffXfermode(buffer) {}
816
817    typedef SkProcCoeffXfermode INHERITED;
818};
819
820void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
821                             const SkPMColor* SK_RESTRICT, int count,
822                             const SkAlpha* SK_RESTRICT aa) const {
823    SkASSERT(dst && count >= 0);
824
825    if (NULL == aa) {
826        memset(dst, 0, count << 2);
827    } else {
828        for (int i = count - 1; i >= 0; --i) {
829            unsigned a = aa[i];
830            if (0xFF == a) {
831                dst[i] = 0;
832            } else if (a != 0) {
833                dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
834            }
835        }
836    }
837}
838void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
839                             const SkPMColor* SK_RESTRICT, int count,
840                             const SkAlpha* SK_RESTRICT aa) const {
841    SkASSERT(dst && count >= 0);
842
843    if (NULL == aa) {
844        memset(dst, 0, count);
845    } else {
846        for (int i = count - 1; i >= 0; --i) {
847            unsigned a = aa[i];
848            if (0xFF == a) {
849                dst[i] = 0;
850            } else if (0 != a) {
851                dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
852            }
853        }
854    }
855}
856
857#ifdef SK_DEVELOPER
858void SkClearXfermode::toString(SkString* str) const {
859    this->INHERITED::toString(str);
860}
861#endif
862
863///////////////////////////////////////////////////////////////////////////////
864
865class SkSrcXfermode : public SkProcCoeffXfermode {
866public:
867    SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
868
869    virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
870    virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
871
872    SK_DEVELOPER_TO_STRING()
873    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
874
875private:
876    SkSrcXfermode(SkFlattenableReadBuffer& buffer)
877        : SkProcCoeffXfermode(buffer) {}
878
879    typedef SkProcCoeffXfermode INHERITED;
880};
881
882void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
883                           const SkPMColor* SK_RESTRICT src, int count,
884                           const SkAlpha* SK_RESTRICT aa) const {
885    SkASSERT(dst && src && count >= 0);
886
887    if (NULL == aa) {
888        memcpy(dst, src, count << 2);
889    } else {
890        for (int i = count - 1; i >= 0; --i) {
891            unsigned a = aa[i];
892            if (a == 0xFF) {
893                dst[i] = src[i];
894            } else if (a != 0) {
895                dst[i] = SkFourByteInterp(src[i], dst[i], a);
896            }
897        }
898    }
899}
900
901void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
902                           const SkPMColor* SK_RESTRICT src, int count,
903                           const SkAlpha* SK_RESTRICT aa) const {
904    SkASSERT(dst && src && count >= 0);
905
906    if (NULL == aa) {
907        for (int i = count - 1; i >= 0; --i) {
908            dst[i] = SkToU8(SkGetPackedA32(src[i]));
909        }
910    } else {
911        for (int i = count - 1; i >= 0; --i) {
912            unsigned a = aa[i];
913            if (0 != a) {
914                unsigned srcA = SkGetPackedA32(src[i]);
915                if (a == 0xFF) {
916                    dst[i] = SkToU8(srcA);
917                } else {
918                    dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
919                }
920            }
921        }
922    }
923}
924#ifdef SK_DEVELOPER
925void SkSrcXfermode::toString(SkString* str) const {
926    this->INHERITED::toString(str);
927}
928#endif
929
930///////////////////////////////////////////////////////////////////////////////
931
932class SkDstInXfermode : public SkProcCoeffXfermode {
933public:
934    SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
935
936    virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
937
938    SK_DEVELOPER_TO_STRING()
939    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstInXfermode)
940
941private:
942    SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
943
944    typedef SkProcCoeffXfermode INHERITED;
945};
946
947void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
948                             const SkPMColor* SK_RESTRICT src, int count,
949                             const SkAlpha* SK_RESTRICT aa) const {
950    SkASSERT(dst && src);
951
952    if (count <= 0) {
953        return;
954    }
955    if (NULL != aa) {
956        return this->INHERITED::xfer32(dst, src, count, aa);
957    }
958
959    do {
960        unsigned a = SkGetPackedA32(*src);
961        *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
962        dst++;
963        src++;
964    } while (--count != 0);
965}
966
967#ifdef SK_DEVELOPER
968void SkDstInXfermode::toString(SkString* str) const {
969    this->INHERITED::toString(str);
970}
971#endif
972
973///////////////////////////////////////////////////////////////////////////////
974
975class SkDstOutXfermode : public SkProcCoeffXfermode {
976public:
977    SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
978
979    virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
980
981    SK_DEVELOPER_TO_STRING()
982    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
983
984private:
985    SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
986        : INHERITED(buffer) {}
987
988    typedef SkProcCoeffXfermode INHERITED;
989};
990
991void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
992                              const SkPMColor* SK_RESTRICT src, int count,
993                              const SkAlpha* SK_RESTRICT aa) const {
994    SkASSERT(dst && src);
995
996    if (count <= 0) {
997        return;
998    }
999    if (NULL != aa) {
1000        return this->INHERITED::xfer32(dst, src, count, aa);
1001    }
1002
1003    do {
1004        unsigned a = SkGetPackedA32(*src);
1005        *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
1006        dst++;
1007        src++;
1008    } while (--count != 0);
1009}
1010
1011#ifdef SK_DEVELOPER
1012void SkDstOutXfermode::toString(SkString* str) const {
1013    this->INHERITED::toString(str);
1014}
1015#endif
1016
1017///////////////////////////////////////////////////////////////////////////////
1018
1019SkXfermode* SkXfermode::Create(Mode mode) {
1020    SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
1021    SkASSERT((unsigned)mode < kModeCount);
1022
1023    const ProcCoeff& rec = gProcCoeffs[mode];
1024
1025    switch (mode) {
1026        case kClear_Mode:
1027            return SkNEW_ARGS(SkClearXfermode, (rec));
1028        case kSrc_Mode:
1029            return SkNEW_ARGS(SkSrcXfermode, (rec));
1030        case kSrcOver_Mode:
1031            return NULL;
1032        case kDstIn_Mode:
1033            return SkNEW_ARGS(SkDstInXfermode, (rec));
1034        case kDstOut_Mode:
1035            return SkNEW_ARGS(SkDstOutXfermode, (rec));
1036        default:
1037            return SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
1038    }
1039}
1040
1041SkXfermodeProc SkXfermode::GetProc(Mode mode) {
1042    SkXfermodeProc  proc = NULL;
1043    if ((unsigned)mode < kModeCount) {
1044        proc = gProcCoeffs[mode].fProc;
1045    }
1046    return proc;
1047}
1048
1049bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
1050    SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
1051
1052    if ((unsigned)mode >= (unsigned)kModeCount) {
1053        // illegal mode parameter
1054        return false;
1055    }
1056
1057    const ProcCoeff& rec = gProcCoeffs[mode];
1058
1059    if (CANNOT_USE_COEFF == rec.fSC) {
1060        return false;
1061    }
1062
1063    SkASSERT(CANNOT_USE_COEFF != rec.fDC);
1064    if (src) {
1065        *src = rec.fSC;
1066    }
1067    if (dst) {
1068        *dst = rec.fDC;
1069    }
1070    return true;
1071}
1072
1073bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
1074    if (NULL == xfer) {
1075        if (mode) {
1076            *mode = kSrcOver_Mode;
1077        }
1078        return true;
1079    }
1080    return xfer->asMode(mode);
1081}
1082
1083bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
1084    if (NULL == xfer) {
1085        return ModeAsCoeff(kSrcOver_Mode, src, dst);
1086    }
1087    return xfer->asCoeff(src, dst);
1088}
1089
1090bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
1091    // if xfer==null then the mode is srcover
1092    Mode m = kSrcOver_Mode;
1093    if (xfer && !xfer->asMode(&m)) {
1094        return false;
1095    }
1096    return mode == m;
1097}
1098
1099///////////////////////////////////////////////////////////////////////////////
1100//////////// 16bit xfermode procs
1101
1102#ifdef SK_DEBUG
1103static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1104static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1105#endif
1106
1107static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1108    SkASSERT(require_255(src));
1109    return SkPixel32ToPixel16(src);
1110}
1111
1112static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1113    return dst;
1114}
1115
1116static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1117    SkASSERT(require_0(src));
1118    return dst;
1119}
1120
1121static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1122    SkASSERT(require_255(src));
1123    return SkPixel32ToPixel16(src);
1124}
1125
1126static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1127    SkASSERT(require_0(src));
1128    return dst;
1129}
1130
1131static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1132    SkASSERT(require_255(src));
1133    return dst;
1134}
1135
1136static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1137    SkASSERT(require_255(src));
1138    return SkPixel32ToPixel16(src);
1139}
1140
1141static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1142    SkASSERT(require_255(src));
1143    return dst;
1144}
1145
1146static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1147    SkASSERT(require_0(src));
1148    return dst;
1149}
1150
1151static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1152    unsigned isa = 255 - SkGetPackedA32(src);
1153
1154    return SkPackRGB16(
1155           SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1156           SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1157           SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1158}
1159
1160static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1161    SkASSERT(require_0(src));
1162    return dst;
1163}
1164
1165static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1166    SkASSERT(require_255(src));
1167    return SkPixel32ToPixel16(src);
1168}
1169
1170static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1171    SkASSERT(require_255(src));
1172    return dst;
1173}
1174
1175/*********
1176    darken and lighten boil down to this.
1177
1178    darken  = (1 - Sa) * Dc + min(Sc, Dc)
1179    lighten = (1 - Sa) * Dc + max(Sc, Dc)
1180
1181    if (Sa == 0) these become
1182        darken  = Dc + min(0, Dc) = 0
1183        lighten = Dc + max(0, Dc) = Dc
1184
1185    if (Sa == 1) these become
1186        darken  = min(Sc, Dc)
1187        lighten = max(Sc, Dc)
1188*/
1189
1190static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1191    SkASSERT(require_0(src));
1192    return 0;
1193}
1194
1195static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1196    SkASSERT(require_255(src));
1197    unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1198    unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1199    unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1200    return SkPackRGB16(r, g, b);
1201}
1202
1203static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1204    SkASSERT(require_0(src));
1205    return dst;
1206}
1207
1208static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1209    SkASSERT(require_255(src));
1210    unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1211    unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1212    unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1213    return SkPackRGB16(r, g, b);
1214}
1215
1216struct Proc16Rec {
1217    SkXfermodeProc16    fProc16_0;
1218    SkXfermodeProc16    fProc16_255;
1219    SkXfermodeProc16    fProc16_General;
1220};
1221
1222static const Proc16Rec gModeProcs16[] = {
1223    { NULL,                 NULL,                   NULL            }, // CLEAR
1224    { NULL,                 src_modeproc16_255,     NULL            },
1225    { dst_modeproc16,       dst_modeproc16,         dst_modeproc16  },
1226    { srcover_modeproc16_0, srcover_modeproc16_255, NULL            },
1227    { dstover_modeproc16_0, dstover_modeproc16_255, NULL            },
1228    { NULL,                 srcin_modeproc16_255,   NULL            },
1229    { NULL,                 dstin_modeproc16_255,   NULL            },
1230    { NULL,                 NULL,                   NULL            },// SRC_OUT
1231    { dstout_modeproc16_0,  NULL,                   NULL            },
1232    { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16  },
1233    { NULL,                 dstatop_modeproc16_255, NULL            },
1234    { NULL,                 NULL,                   NULL            }, // XOR
1235
1236    { NULL,                 NULL,                   NULL            }, // plus
1237    { NULL,                 NULL,                   NULL            }, // modulate
1238    { NULL,                 NULL,                   NULL            }, // screen
1239    { NULL,                 NULL,                   NULL            }, // overlay
1240    { darken_modeproc16_0,  darken_modeproc16_255,  NULL            }, // darken
1241    { lighten_modeproc16_0, lighten_modeproc16_255, NULL            }, // lighten
1242    { NULL,                 NULL,                   NULL            }, // colordodge
1243    { NULL,                 NULL,                   NULL            }, // colorburn
1244    { NULL,                 NULL,                   NULL            }, // hardlight
1245    { NULL,                 NULL,                   NULL            }, // softlight
1246    { NULL,                 NULL,                   NULL            }, // difference
1247    { NULL,                 NULL,                   NULL            }, // exclusion
1248};
1249
1250SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
1251    SkXfermodeProc16  proc16 = NULL;
1252    if ((unsigned)mode < kModeCount) {
1253        const Proc16Rec& rec = gModeProcs16[mode];
1254        unsigned a = SkColorGetA(srcColor);
1255
1256        if (0 == a) {
1257            proc16 = rec.fProc16_0;
1258        } else if (255 == a) {
1259            proc16 = rec.fProc16_255;
1260        } else {
1261            proc16 = rec.fProc16_General;
1262        }
1263    }
1264    return proc16;
1265}
1266
1267SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
1268    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
1269    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
1270    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
1271    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
1272    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
1273SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
1274