blob: 9514bfaa812447a9c42ea1ce42edabce3761083a [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
reed@android.com543ed932009-04-24 12:43:40 +000048static 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
reed@android.com8a1c16f2008-12-17 15:59:43 +000058///////////////////////////////////////////////////////////////////////////////
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
reed@android.com1116fb22009-03-03 20:31:12 +0000357// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000359#if 0
360 // this is the old, more-correct way, but it doesn't guarantee that dst==255
361 // will always stay opaque
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
reed@android.com1116fb22009-03-03 20:31:12 +0000363#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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368}
369
reed@android.com1116fb22009-03-03 20:31:12 +0000370// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
reed@android.com1116fb22009-03-03 20:31:12 +0000372 // 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));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375}
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
reed@android.com543ed932009-04-24 12:43:40 +0000513static 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000521///////////////////////////////////////////////////////////////////////////////
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
reed@android.com543ed932009-04-24 12:43:40 +0000722#define CANNOT_USE_COEFF SkXfermode::Coeff(-1)
723
reed@android.com8a1c16f2008-12-17 15:59:43 +0000724static 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 },
reed@android.com543ed932009-04-24 12:43:40 +0000737 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
738 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
reed@android.com8a1c16f2008-12-17 15:59:43 +0000739 { mult_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
reed@android.com543ed932009-04-24 12:43:40 +0000740 { screen_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
741 { add_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742};
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
reed@android.comfc25abd2009-01-15 14:38:33 +0000805#ifdef SK_DEBUGx
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806static 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