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