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