SkXfermode.cpp revision eba9f316916f3381d6a5dd5c1300fea6ec6da8dc
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 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
58///////////////////////////////////////////////////////////////////////////////
59
60bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) {
61    return false;
62}
63
64SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) {
65    // no-op. subclasses should override this
66    return dst;
67}
68
69void SkXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
70                        const SK_RESTRICT SkPMColor src[], int count,
71                        const SK_RESTRICT SkAlpha aa[]) {
72    SkASSERT(dst && src && count >= 0);
73
74    if (NULL == aa) {
75        for (int i = count - 1; i >= 0; --i) {
76            dst[i] = this->xferColor(src[i], dst[i]);
77        }
78    } else {
79        for (int i = count - 1; i >= 0; --i) {
80            unsigned a = aa[i];
81            if (0 != a) {
82                SkPMColor dstC = dst[i];
83                SkPMColor C = this->xferColor(src[i], dstC);
84                if (0xFF != a) {
85                    C = SkFourByteInterp(C, dstC, a);
86                }
87                dst[i] = C;
88            }
89        }
90    }
91}
92
93void SkXfermode::xfer16(SK_RESTRICT uint16_t dst[],
94                        const SK_RESTRICT SkPMColor src[], int count,
95                        const SK_RESTRICT SkAlpha aa[]) {
96    SkASSERT(dst && src && count >= 0);
97
98    if (NULL == aa) {
99        for (int i = count - 1; i >= 0; --i) {
100            SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
101            dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
102        }
103    } else {
104        for (int i = count - 1; i >= 0; --i) {
105            unsigned a = aa[i];
106            if (0 != a) {
107                SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
108                SkPMColor C = this->xferColor(src[i], dstC);
109                if (0xFF != a) {
110                    C = SkFourByteInterp(C, dstC, a);
111                }
112                dst[i] = SkPixel32ToPixel16_ToU16(C);
113            }
114        }
115    }
116}
117
118void SkXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
119                          const SK_RESTRICT SkPMColor src[], int count,
120                          const SK_RESTRICT SkAlpha aa[])
121{
122    SkASSERT(dst && src && count >= 0);
123
124    if (NULL == aa) {
125        for (int i = count - 1; i >= 0; --i) {
126            SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
127            dst[i] = SkPixel32ToPixel4444(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 = SkPixel4444ToPixel32(dst[i]);
134                SkPMColor C = this->xferColor(src[i], dstC);
135                if (0xFF != a) {
136                    C = SkFourByteInterp(C, dstC, a);
137                }
138                dst[i] = SkPixel32ToPixel4444(C);
139            }
140        }
141    }
142}
143
144void SkXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
145                        const 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 res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
153            dst[i] = SkToU8(SkGetPackedA32(res));
154        }
155    } else {
156        for (int i = count - 1; i >= 0; --i) {
157            unsigned a = aa[i];
158            if (0 != a) {
159                SkAlpha dstA = dst[i];
160                unsigned A = SkGetPackedA32(this->xferColor(src[i],
161                                            (SkPMColor)(dstA << SK_A32_SHIFT)));
162                if (0xFF != a) {
163                    A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
164                }
165                dst[i] = SkToU8(A);
166            }
167        }
168    }
169}
170
171///////////////////////////////////////////////////////////////////////////////
172
173void SkProcXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
174                            const SK_RESTRICT SkPMColor src[], int count,
175                            const SK_RESTRICT SkAlpha aa[]) {
176    SkASSERT(dst && src && count >= 0);
177
178    SkXfermodeProc proc = fProc;
179
180    if (NULL != proc) {
181        if (NULL == aa) {
182            for (int i = count - 1; i >= 0; --i) {
183                dst[i] = proc(src[i], dst[i]);
184            }
185        } else {
186            for (int i = count - 1; i >= 0; --i) {
187                unsigned a = aa[i];
188                if (0 != a) {
189                    SkPMColor dstC = dst[i];
190                    SkPMColor C = proc(src[i], dstC);
191                    if (a != 0xFF) {
192                        C = SkFourByteInterp(C, dstC, a);
193                    }
194                    dst[i] = C;
195                }
196            }
197        }
198    }
199}
200
201void SkProcXfermode::xfer16(SK_RESTRICT uint16_t dst[],
202                            const SK_RESTRICT SkPMColor src[], int count,
203                            const SK_RESTRICT SkAlpha aa[]) {
204    SkASSERT(dst && src && count >= 0);
205
206    SkXfermodeProc proc = fProc;
207
208    if (NULL != proc) {
209        if (NULL == aa) {
210            for (int i = count - 1; i >= 0; --i) {
211                SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
212                dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
213            }
214        } else {
215            for (int i = count - 1; i >= 0; --i) {
216                unsigned a = aa[i];
217                if (0 != a) {
218                    SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
219                    SkPMColor C = proc(src[i], dstC);
220                    if (0xFF != a) {
221                        C = SkFourByteInterp(C, dstC, a);
222                    }
223                    dst[i] = SkPixel32ToPixel16_ToU16(C);
224                }
225            }
226        }
227    }
228}
229
230void SkProcXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
231                              const SK_RESTRICT SkPMColor src[], int count,
232                              const SK_RESTRICT SkAlpha aa[]) {
233    SkASSERT(dst && src && count >= 0);
234
235    SkXfermodeProc proc = fProc;
236
237    if (NULL != proc) {
238        if (NULL == aa) {
239            for (int i = count - 1; i >= 0; --i) {
240                SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
241                dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
242            }
243        } else {
244            for (int i = count - 1; i >= 0; --i) {
245                unsigned a = aa[i];
246                if (0 != a) {
247                    SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
248                    SkPMColor C = proc(src[i], dstC);
249                    if (0xFF != a) {
250                        C = SkFourByteInterp(C, dstC, a);
251                    }
252                    dst[i] = SkPixel32ToPixel4444(C);
253                }
254            }
255        }
256    }
257}
258
259void SkProcXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
260                            const SK_RESTRICT SkPMColor src[], int count,
261                            const SK_RESTRICT SkAlpha aa[]) {
262    SkASSERT(dst && src && count >= 0);
263
264    SkXfermodeProc proc = fProc;
265
266    if (NULL != proc) {
267        if (NULL == aa) {
268            for (int i = count - 1; i >= 0; --i) {
269                SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
270                dst[i] = SkToU8(SkGetPackedA32(res));
271            }
272        } else {
273            for (int i = count - 1; i >= 0; --i) {
274                unsigned a = aa[i];
275                if (0 != a) {
276                    SkAlpha dstA = dst[i];
277                    SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
278                    unsigned A = SkGetPackedA32(res);
279                    if (0xFF != a) {
280                        A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
281                    }
282                    dst[i] = SkToU8(A);
283                }
284            }
285        }
286    }
287}
288
289SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
290        : SkXfermode(buffer) {
291    fProc = (SkXfermodeProc)buffer.readFunctionPtr();
292}
293
294void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) {
295    buffer.writeFunctionPtr((void*)fProc);
296}
297
298///////////////////////////////////////////////////////////////////////////////
299///////////////////////////////////////////////////////////////////////////////
300
301class SkProcCoeffXfermode : public SkProcXfermode {
302public:
303    SkProcCoeffXfermode(SkXfermodeProc proc, Coeff sc, Coeff dc)
304            : INHERITED(proc), fSrcCoeff(sc), fDstCoeff(dc) {
305    }
306
307    virtual bool asCoeff(Coeff* sc, Coeff* dc) {
308        if (sc) {
309            *sc = fSrcCoeff;
310        }
311        if (dc) {
312            *dc = fDstCoeff;
313        }
314        return true;
315    }
316
317    virtual Factory getFactory() { return CreateProc; }
318    virtual void flatten(SkFlattenableWriteBuffer& buffer) {
319        this->INHERITED::flatten(buffer);
320        buffer.write32(fSrcCoeff);
321        buffer.write32(fDstCoeff);
322    }
323
324protected:
325    SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer)
326            : INHERITED(buffer) {
327        fSrcCoeff = (Coeff)buffer.readU32();
328        fDstCoeff = (Coeff)buffer.readU32();
329    }
330
331private:
332    Coeff   fSrcCoeff, fDstCoeff;
333
334    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
335    return SkNEW_ARGS(SkProcCoeffXfermode, (buffer)); }
336
337    typedef SkProcXfermode INHERITED;
338};
339
340///////////////////////////////////////////////////////////////////////////////
341
342//  kClear_Mode,    //!< [0, 0]
343static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
344    return 0;
345}
346
347//  kSrc_Mode,      //!< [Sa, Sc]
348static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
349    return src;
350}
351
352//  kDst_Mode,      //!< [Da, Dc]
353static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
354    return dst;
355}
356
357//  kSrcOver_Mode,  //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
358static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
359#if 0
360    // this is the old, more-correct way, but it doesn't guarantee that dst==255
361    // will always stay opaque
362    return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
363#else
364    // this is slightly faster, but more importantly guarantees that dst==255
365    // will always stay opaque
366    return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
367#endif
368}
369
370//  kDstOver_Mode,  //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
371static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
372    // this is the reverse of srcover, just flipping src and dst
373    // see srcover's comment about the 256 for opaqueness guarantees
374    return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
375}
376
377//  kSrcIn_Mode,    //!< [Sa * Da, Sc * Da]
378static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
379    return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
380}
381
382//  kDstIn_Mode,    //!< [Sa * Da, Sa * Dc]
383static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
384    return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
385}
386
387//  kSrcOut_Mode,   //!< [Sa * (1 - Da), Sc * (1 - Da)]
388static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
389    return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
390}
391
392//  kDstOut_Mode,   //!< [Da * (1 - Sa), Dc * (1 - Sa)]
393static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
394    return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
395}
396
397//  kSrcATop_Mode,  //!< [Da, Sc * Da + (1 - Sa) * Dc]
398static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
399    unsigned sa = SkGetPackedA32(src);
400    unsigned da = SkGetPackedA32(dst);
401    unsigned isa = 255 - sa;
402
403    return SkPackARGB32(da,
404                        SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
405                            SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
406                        SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
407                            SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
408                        SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
409                            SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
410}
411
412//  kDstATop_Mode,  //!< [Sa, Sa * Dc + Sc * (1 - Da)]
413static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
414    unsigned sa = SkGetPackedA32(src);
415    unsigned da = SkGetPackedA32(dst);
416    unsigned ida = 255 - da;
417
418    return SkPackARGB32(sa,
419                        SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
420                            SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
421                        SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
422                            SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
423                        SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
424                            SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
425}
426
427//  kXor_Mode   [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
428static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
429    unsigned sa = SkGetPackedA32(src);
430    unsigned da = SkGetPackedA32(dst);
431    unsigned isa = 255 - sa;
432    unsigned ida = 255 - da;
433
434    return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
435                        SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
436                            SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
437                        SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
438                            SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
439                        SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
440                            SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
441}
442
443
444// kDarken_Mode,   [Sa + Da - Sa·Da, Sc·(1 - Da) + Dc·(1 - Sa) + min(Sc, Dc)]
445
446static inline unsigned darken_p(unsigned src, unsigned dst,
447                                unsigned src_mul, unsigned dst_mul) {
448    return ((dst_mul * src + src_mul * dst) >> 8) + SkMin32(src, dst);
449}
450
451static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
452    unsigned sa = SkGetPackedA32(src);
453    unsigned da = SkGetPackedA32(dst);
454    unsigned src_scale = SkAlpha255To256(255 - sa);
455    unsigned dst_scale = SkAlpha255To256(255 - da);
456
457    unsigned ra = sa + da - SkAlphaMulAlpha(sa, da);
458    unsigned rr = darken_p(SkGetPackedR32(src), SkGetPackedR32(dst),
459                           src_scale, dst_scale);
460    unsigned rg = darken_p(SkGetPackedG32(src), SkGetPackedG32(dst),
461                           src_scale, dst_scale);
462    unsigned rb = darken_p(SkGetPackedB32(src), SkGetPackedB32(dst),
463                           src_scale, dst_scale);
464
465    return SkPackARGB32(ra, SkFastMin32(rr, ra),
466                        SkFastMin32(rg, ra), SkFastMin32(rb, ra));
467}
468
469// kLighten_Mode,  [Sa + Da - Sa·Da, Sc·(1 - Da) + Dc·(1 - Sa) + max(Sc, Dc)]
470static inline unsigned lighten_p(unsigned src, unsigned dst,
471                                 unsigned src_mul, unsigned dst_mul) {
472    return ((dst_mul * src + src_mul * dst) >> 8) + SkMax32(src, dst);
473}
474
475static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
476    unsigned sa = SkGetPackedA32(src);
477    unsigned da = SkGetPackedA32(dst);
478    unsigned src_scale = SkAlpha255To256(255 - sa);
479    unsigned dst_scale = SkAlpha255To256(255 - da);
480
481    unsigned ra = sa + da - SkAlphaMulAlpha(sa, da);
482    unsigned rr = lighten_p(SkGetPackedR32(src), SkGetPackedR32(dst),
483                            src_scale, dst_scale);
484    unsigned rg = lighten_p(SkGetPackedG32(src), SkGetPackedG32(dst),
485                            src_scale, dst_scale);
486    unsigned rb = lighten_p(SkGetPackedB32(src), SkGetPackedB32(dst),
487                            src_scale, dst_scale);
488
489    return SkPackARGB32(ra, SkFastMin32(rr, ra),
490                        SkFastMin32(rg, ra), SkFastMin32(rb, ra));
491}
492
493static SkPMColor mult_modeproc(SkPMColor src, SkPMColor dst) {
494    int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
495    int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
496    int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
497    int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
498    return SkPackARGB32(a, r, g, b);
499}
500
501static inline int screen_byte(int a, int b) {
502    return a + b - SkAlphaMulAlpha(a, b);
503}
504
505static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
506    int a = screen_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
507    int r = screen_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
508    int g = screen_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
509    int b = screen_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
510    return SkPackARGB32(a, r, g, b);
511}
512
513static SkPMColor add_modeproc(SkPMColor src, SkPMColor dst) {
514    unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
515    unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
516    unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
517    unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
518    return SkPackARGB32(a, r, g, b);
519}
520
521///////////////////////////////////////////////////////////////////////////////
522
523class SkClearXfermode : public SkProcCoeffXfermode {
524public:
525    SkClearXfermode() : SkProcCoeffXfermode(clear_modeproc,
526                                            kZero_Coeff, kZero_Coeff) {}
527
528    virtual void xfer32(SK_RESTRICT SkPMColor dst[],
529                        const SK_RESTRICT SkPMColor[], int count,
530                        const SK_RESTRICT SkAlpha aa[]) {
531        SkASSERT(dst && count >= 0);
532
533        if (NULL == aa) {
534            memset(dst, 0, count << 2);
535        } else {
536            for (int i = count - 1; i >= 0; --i) {
537                unsigned a = aa[i];
538                if (0xFF == a) {
539                    dst[i] = 0;
540                } else if (a != 0) {
541                    dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
542                }
543            }
544        }
545    }
546    virtual void xferA8(SK_RESTRICT SkAlpha dst[],
547                        const SK_RESTRICT SkPMColor[], int count,
548                        const SK_RESTRICT SkAlpha aa[]) {
549        SkASSERT(dst && count >= 0);
550
551        if (NULL == aa) {
552            memset(dst, 0, count);
553        } else {
554            for (int i = count - 1; i >= 0; --i) {
555                unsigned a = aa[i];
556                if (0xFF == a) {
557                    dst[i] = 0;
558                } else if (0 != a) {
559                    dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
560                }
561            }
562        }
563    }
564
565    virtual Factory getFactory() { return CreateProc; }
566
567private:
568    SkClearXfermode(SkFlattenableReadBuffer& buffer)
569        : SkProcCoeffXfermode(buffer) {}
570
571    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
572        return SkNEW_ARGS(SkClearXfermode, (buffer));
573    }
574};
575
576///////////////////////////////////////////////////////////////////////////////
577
578class SkSrcXfermode : public SkProcCoeffXfermode {
579public:
580    SkSrcXfermode() : SkProcCoeffXfermode(src_modeproc,
581                                          kOne_Coeff, kZero_Coeff) {}
582
583    virtual void xfer32(SK_RESTRICT SkPMColor dst[],
584                        const SK_RESTRICT SkPMColor src[], int count,
585                        const SK_RESTRICT SkAlpha aa[]) {
586        SkASSERT(dst && src && count >= 0);
587
588        if (NULL == aa) {
589            memcpy(dst, src, count << 2);
590        } else {
591            for (int i = count - 1; i >= 0; --i) {
592                unsigned a = aa[i];
593                if (a == 0xFF) {
594                    dst[i] = src[i];
595                } else if (a != 0) {
596                    dst[i] = SkFourByteInterp(src[i], dst[i], a);
597                }
598            }
599        }
600    }
601
602    virtual void xferA8(SK_RESTRICT SkAlpha dst[],
603                        const SK_RESTRICT SkPMColor src[], int count,
604                        const SK_RESTRICT SkAlpha aa[]) {
605        SkASSERT(dst && src && count >= 0);
606
607        if (NULL == aa) {
608            for (int i = count - 1; i >= 0; --i) {
609                dst[i] = SkToU8(SkGetPackedA32(src[i]));
610            }
611        } else {
612            for (int i = count - 1; i >= 0; --i) {
613                unsigned a = aa[i];
614                if (0 != a) {
615                    unsigned srcA = SkGetPackedA32(src[i]);
616                    if (a == 0xFF) {
617                        dst[i] = SkToU8(srcA);
618                    } else {
619                        dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
620                    }
621                }
622            }
623        }
624    }
625
626    virtual Factory getFactory() { return CreateProc; }
627
628private:
629    SkSrcXfermode(SkFlattenableReadBuffer& buffer)
630        : SkProcCoeffXfermode(buffer) {}
631
632    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
633        return SkNEW_ARGS(SkSrcXfermode, (buffer));
634    }
635};
636
637class SkDstInXfermode : public SkProcCoeffXfermode {
638public:
639    SkDstInXfermode() : SkProcCoeffXfermode(dstin_modeproc,
640                                            kZero_Coeff, kSA_Coeff) {}
641
642    virtual void xfer32(SK_RESTRICT SkPMColor dst[],
643                        const SK_RESTRICT SkPMColor src[], int count,
644                        const SK_RESTRICT SkAlpha aa[]) {
645        SkASSERT(dst && src);
646
647        if (count <= 0) {
648            return;
649        }
650        if (NULL != aa) {
651            return this->INHERITED::xfer32(dst, src, count, aa);
652        }
653
654        do {
655            unsigned a = SkGetPackedA32(*src);
656            *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
657            dst++;
658            src++;
659        } while (--count != 0);
660    }
661
662    virtual Factory getFactory() { return CreateProc; }
663
664private:
665    SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
666
667    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
668        return SkNEW_ARGS(SkDstInXfermode, (buffer));
669    }
670
671    typedef SkProcCoeffXfermode INHERITED;
672};
673
674class SkDstOutXfermode : public SkProcCoeffXfermode {
675public:
676    SkDstOutXfermode() : SkProcCoeffXfermode(dstout_modeproc,
677                                             kZero_Coeff, kISA_Coeff) {}
678
679    virtual void xfer32(SK_RESTRICT SkPMColor dst[],
680                        const SK_RESTRICT SkPMColor src[], int count,
681                        const SK_RESTRICT SkAlpha aa[]) {
682        SkASSERT(dst && src);
683
684        if (count <= 0) {
685            return;
686        }
687        if (NULL != aa) {
688            return this->INHERITED::xfer32(dst, src, count, aa);
689        }
690
691        do {
692            unsigned a = SkGetPackedA32(*src);
693            *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
694            dst++;
695            src++;
696        } while (--count != 0);
697    }
698
699    virtual Factory getFactory() { return CreateProc; }
700
701private:
702    SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
703        : INHERITED(buffer) {}
704
705    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
706        return SkNEW_ARGS(SkDstOutXfermode, (buffer));
707    }
708
709    typedef SkProcCoeffXfermode INHERITED;
710};
711
712///////////////////////////////////////////////////////////////////////////////
713
714#include "SkPorterDuff.h"
715
716struct ProcCoeff {
717    SkXfermodeProc      fProc;
718    SkXfermode::Coeff   fSC;
719    SkXfermode::Coeff   fDC;
720};
721
722#define CANNOT_USE_COEFF    SkXfermode::Coeff(-1)
723
724static const ProcCoeff gProcCoeffs[] = {
725    { clear_modeproc,   SkXfermode::kZero_Coeff,    SkXfermode::kZero_Coeff },
726    { src_modeproc,     SkXfermode::kOne_Coeff,     SkXfermode::kZero_Coeff },
727    { dst_modeproc,     SkXfermode::kZero_Coeff,    SkXfermode::kOne_Coeff },
728    { srcover_modeproc, SkXfermode::kOne_Coeff,     SkXfermode::kISA_Coeff },
729    { dstover_modeproc, SkXfermode::kIDA_Coeff,     SkXfermode::kOne_Coeff },
730    { srcin_modeproc,   SkXfermode::kDA_Coeff,      SkXfermode::kZero_Coeff },
731    { dstin_modeproc,   SkXfermode::kZero_Coeff,    SkXfermode::kSA_Coeff },
732    { srcout_modeproc,  SkXfermode::kIDA_Coeff,     SkXfermode::kZero_Coeff },
733    { dstout_modeproc,  SkXfermode::kZero_Coeff,    SkXfermode::kISA_Coeff },
734    { srcatop_modeproc, SkXfermode::kDA_Coeff,      SkXfermode::kISA_Coeff },
735    { dstatop_modeproc, SkXfermode::kIDA_Coeff,     SkXfermode::kSA_Coeff },
736    { xor_modeproc,     SkXfermode::kIDA_Coeff,     SkXfermode::kISA_Coeff },
737    { darken_modeproc,  CANNOT_USE_COEFF,           CANNOT_USE_COEFF },
738    { lighten_modeproc, CANNOT_USE_COEFF,           CANNOT_USE_COEFF },
739    { mult_modeproc,    SkXfermode::kZero_Coeff,    SkXfermode::kSC_Coeff },
740    { screen_modeproc,  SkXfermode::kOne_Coeff,     SkXfermode::kISC_Coeff },
741    { add_modeproc,     CANNOT_USE_COEFF,           CANNOT_USE_COEFF }
742};
743
744SkXfermode* SkPorterDuff::CreateXfermode(SkPorterDuff::Mode mode) {
745    SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == SkPorterDuff::kModeCount);
746    SkASSERT((unsigned)mode < SkPorterDuff::kModeCount);
747
748    switch (mode) {
749        case kClear_Mode:
750            return SkNEW(SkClearXfermode);
751        case kSrc_Mode:
752            return SkNEW(SkSrcXfermode);
753        case kSrcOver_Mode:
754            return NULL;
755        case kDstIn_Mode:
756            return SkNEW(SkDstInXfermode);
757        case kDstOut_Mode:
758            return SkNEW(SkDstOutXfermode);
759        // these two can't be represented with Coeff
760        case kDarken_Mode:
761            return SkNEW_ARGS(SkProcXfermode, (darken_modeproc));
762        case kLighten_Mode:
763            return SkNEW_ARGS(SkProcXfermode, (lighten_modeproc));
764        // use the table
765        default: {
766            const ProcCoeff& rec = gProcCoeffs[mode];
767            SkASSERT((unsigned)rec.fSC < SkXfermode::kCoeffCount);
768            SkASSERT((unsigned)rec.fDC < SkXfermode::kCoeffCount);
769            return SkNEW_ARGS(SkProcCoeffXfermode, (rec.fProc,
770                                                    rec.fSC, rec.fDC));
771        }
772    }
773}
774
775bool SkPorterDuff::IsMode(SkXfermode* xfer, Mode* mode) {
776    if (NULL == xfer) {
777        if (mode) {
778            *mode = kSrcOver_Mode;
779        }
780        return true;
781    }
782
783    SkXfermode::Coeff sc, dc;
784    if (xfer->asCoeff(&sc, &dc)) {
785        SkASSERT((unsigned)sc < (unsigned)SkXfermode::kCoeffCount);
786        SkASSERT((unsigned)dc < (unsigned)SkXfermode::kCoeffCount);
787
788        const ProcCoeff* rec = gProcCoeffs;
789        for (size_t i = 0; i < SK_ARRAY_COUNT(gProcCoeffs); i++) {
790            if (rec[i].fSC == sc && rec[i].fDC == dc) {
791                if (mode) {
792                    *mode = SkPorterDuff::Mode(i);
793                }
794                return true;
795            }
796        }
797    }
798
799    // no coefficients, or not found in our table
800    return false;
801}
802
803///////////////////////////////////////////////////////////////////////////////
804
805#ifdef SK_DEBUGx
806static void unit_test() {
807    for (unsigned a = 0; a <= 255; a++) {
808        for (unsigned c = 0; c <= a; c++) {
809            SkPMColor pm = SkPackARGB32(a, c, c, c);
810            for (unsigned aa = 0; aa <= 255; aa++) {
811                for (unsigned cc = 0; cc <= aa; cc++) {
812                    SkPMColor pm2 = SkPackARGB32(aa, cc, cc, cc);
813
814                    const size_t N = SK_ARRAY_COUNT(gProcCoeffs);
815                    for (size_t i = 0; i < N; i++) {
816                        gProcCoeffs[i].fProc(pm, pm2);
817                    }
818                }
819            }
820        }
821    }
822}
823#endif
824
825SkXfermodeProc SkPorterDuff::GetXfermodeProc(Mode mode) {
826#ifdef SK_DEBUGx
827    static bool gUnitTest;
828    if (!gUnitTest) {
829        gUnitTest = true;
830        unit_test();
831    }
832#endif
833
834    SkXfermodeProc  proc = NULL;
835
836    if ((unsigned)mode < SkPorterDuff::kModeCount) {
837        proc = gProcCoeffs[mode].fProc;
838    }
839    return proc;
840}
841
842///////////////////////////////////////////////////////////////////////////////
843//////////// 16bit xfermode procs
844
845#ifdef SK_DEBUG
846static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
847static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
848#endif
849
850static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
851    SkASSERT(require_255(src));
852    return SkPixel32ToPixel16(src);
853}
854
855static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
856    return dst;
857}
858
859static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
860    SkASSERT(require_0(src));
861    return dst;
862}
863
864static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
865    SkASSERT(require_255(src));
866    return SkPixel32ToPixel16(src);
867}
868
869static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
870    SkASSERT(require_0(src));
871    return dst;
872}
873
874static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
875    SkASSERT(require_255(src));
876    return dst;
877}
878
879static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
880    SkASSERT(require_255(src));
881    return SkPixel32ToPixel16(src);
882}
883
884static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
885    SkASSERT(require_255(src));
886    return dst;
887}
888
889static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
890    SkASSERT(require_0(src));
891    return dst;
892}
893
894static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
895    unsigned isa = 255 - SkGetPackedA32(src);
896
897    return SkPackRGB16(
898           SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
899           SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
900           SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
901}
902
903static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
904    SkASSERT(require_0(src));
905    return dst;
906}
907
908static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
909    SkASSERT(require_255(src));
910    return SkPixel32ToPixel16(src);
911}
912
913static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
914    SkASSERT(require_255(src));
915    return dst;
916}
917
918/*********
919    darken and lighten boil down to this.
920
921    darken  = (1 - Sa) * Dc + min(Sc, Dc)
922    lighten = (1 - Sa) * Dc + max(Sc, Dc)
923
924    if (Sa == 0) these become
925        darken  = Dc + min(0, Dc) = 0
926        lighten = Dc + max(0, Dc) = Dc
927
928    if (Sa == 1) these become
929        darken  = min(Sc, Dc)
930        lighten = max(Sc, Dc)
931*/
932
933static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
934    SkASSERT(require_0(src));
935    return 0;
936}
937
938static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
939    SkASSERT(require_255(src));
940    unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
941    unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
942    unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
943    return SkPackRGB16(r, g, b);
944}
945
946static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
947    SkASSERT(require_0(src));
948    return dst;
949}
950
951static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
952    SkASSERT(require_255(src));
953    unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
954    unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
955    unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
956    return SkPackRGB16(r, g, b);
957}
958
959struct Proc16Rec {
960    SkXfermodeProc16    fProc16_0;
961    SkXfermodeProc16    fProc16_255;
962    SkXfermodeProc16    fProc16_General;
963};
964
965static const Proc16Rec gPorterDuffModeProcs16[] = {
966    { NULL,                 NULL,                   NULL            }, // CLEAR
967    { NULL,                 src_modeproc16_255,     NULL            },
968    { dst_modeproc16,       dst_modeproc16,         dst_modeproc16  },
969    { srcover_modeproc16_0, srcover_modeproc16_255, NULL            },
970    { dstover_modeproc16_0, dstover_modeproc16_255, NULL            },
971    { NULL,                 srcin_modeproc16_255,   NULL            },
972    { NULL,                 dstin_modeproc16_255,   NULL            },
973    { NULL,                 NULL,                   NULL            },// SRC_OUT
974    { dstout_modeproc16_0,  NULL,                   NULL            },
975    { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16  },
976    { NULL,                 dstatop_modeproc16_255, NULL            },
977    { NULL,                 NULL,                   NULL            }, // XOR
978    { darken_modeproc16_0,  darken_modeproc16_255,  NULL            },
979    { lighten_modeproc16_0, lighten_modeproc16_255, NULL            },
980    { NULL,                 NULL,                   NULL            },//multiply
981    { NULL,                 NULL,                   NULL            }// screen
982};
983
984SkXfermodeProc16 SkPorterDuff::GetXfermodeProc16(Mode mode, SkColor srcColor) {
985    SkXfermodeProc16  proc16 = NULL;
986
987    if ((unsigned)mode < SkPorterDuff::kModeCount) {
988        const Proc16Rec& rec = gPorterDuffModeProcs16[mode];
989
990        unsigned a = SkColorGetA(srcColor);
991
992        if (0 == a) {
993            proc16 = rec.fProc16_0;
994        } else if (255 == a) {
995            proc16 = rec.fProc16_255;
996        } else {
997            proc16 = rec.fProc16_General;
998        }
999    }
1000    return proc16;
1001}
1002
1003