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