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