blob: 71482c1ddbe3b6dcc5456c03ffa3166e43876198 [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
451 { plus_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
452 { multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
453 { screen_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
454 { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
455 { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
456 { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
457 { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
458 { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
459 { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
460 { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
461 { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
462 { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
463};
464
465///////////////////////////////////////////////////////////////////////////////
466
467bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) {
468 return false;
469}
470
471bool SkXfermode::asMode(Mode* mode) {
472 return IsMode(this, mode);
473}
474
475SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) {
476 // no-op. subclasses should override this
477 return dst;
478}
479
480void SkXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
481 const SK_RESTRICT SkPMColor src[], int count,
482 const SK_RESTRICT SkAlpha aa[]) {
483 SkASSERT(dst && src && count >= 0);
484
485 if (NULL == aa) {
486 for (int i = count - 1; i >= 0; --i) {
487 dst[i] = this->xferColor(src[i], dst[i]);
488 }
489 } else {
490 for (int i = count - 1; i >= 0; --i) {
491 unsigned a = aa[i];
492 if (0 != a) {
493 SkPMColor dstC = dst[i];
494 SkPMColor C = this->xferColor(src[i], dstC);
495 if (0xFF != a) {
496 C = SkFourByteInterp(C, dstC, a);
497 }
498 dst[i] = C;
499 }
500 }
501 }
502}
503
504void SkXfermode::xfer16(SK_RESTRICT uint16_t dst[],
505 const SK_RESTRICT SkPMColor src[], int count,
506 const SK_RESTRICT SkAlpha aa[]) {
507 SkASSERT(dst && src && count >= 0);
508
509 if (NULL == aa) {
510 for (int i = count - 1; i >= 0; --i) {
511 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
512 dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
513 }
514 } else {
515 for (int i = count - 1; i >= 0; --i) {
516 unsigned a = aa[i];
517 if (0 != a) {
518 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
519 SkPMColor C = this->xferColor(src[i], dstC);
520 if (0xFF != a) {
521 C = SkFourByteInterp(C, dstC, a);
522 }
523 dst[i] = SkPixel32ToPixel16_ToU16(C);
524 }
525 }
526 }
527}
528
529void SkXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
530 const SK_RESTRICT SkPMColor src[], int count,
531 const SK_RESTRICT SkAlpha aa[])
532{
533 SkASSERT(dst && src && count >= 0);
534
535 if (NULL == aa) {
536 for (int i = count - 1; i >= 0; --i) {
537 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
538 dst[i] = SkPixel32ToPixel4444(this->xferColor(src[i], dstC));
539 }
540 } else {
541 for (int i = count - 1; i >= 0; --i) {
542 unsigned a = aa[i];
543 if (0 != a) {
544 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
545 SkPMColor C = this->xferColor(src[i], dstC);
546 if (0xFF != a) {
547 C = SkFourByteInterp(C, dstC, a);
548 }
549 dst[i] = SkPixel32ToPixel4444(C);
550 }
551 }
552 }
553}
554
555void SkXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
556 const SkPMColor src[], int count,
557 const SK_RESTRICT SkAlpha aa[])
558{
559 SkASSERT(dst && src && count >= 0);
560
561 if (NULL == aa) {
562 for (int i = count - 1; i >= 0; --i) {
563 SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
564 dst[i] = SkToU8(SkGetPackedA32(res));
565 }
566 } else {
567 for (int i = count - 1; i >= 0; --i) {
568 unsigned a = aa[i];
569 if (0 != a) {
570 SkAlpha dstA = dst[i];
571 unsigned A = SkGetPackedA32(this->xferColor(src[i],
572 (SkPMColor)(dstA << SK_A32_SHIFT)));
573 if (0xFF != a) {
574 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
575 }
576 dst[i] = SkToU8(A);
577 }
578 }
579 }
580}
581
582///////////////////////////////////////////////////////////////////////////////
583
584void SkProcXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
585 const SK_RESTRICT SkPMColor src[], int count,
586 const SK_RESTRICT SkAlpha aa[]) {
587 SkASSERT(dst && src && count >= 0);
588
589 SkXfermodeProc proc = fProc;
590
591 if (NULL != proc) {
592 if (NULL == aa) {
593 for (int i = count - 1; i >= 0; --i) {
594 dst[i] = proc(src[i], dst[i]);
595 }
596 } else {
597 for (int i = count - 1; i >= 0; --i) {
598 unsigned a = aa[i];
599 if (0 != a) {
600 SkPMColor dstC = dst[i];
601 SkPMColor C = proc(src[i], dstC);
602 if (a != 0xFF) {
603 C = SkFourByteInterp(C, dstC, a);
604 }
605 dst[i] = C;
606 }
607 }
608 }
609 }
610}
611
612void SkProcXfermode::xfer16(SK_RESTRICT uint16_t dst[],
613 const SK_RESTRICT SkPMColor src[], int count,
614 const SK_RESTRICT SkAlpha aa[]) {
615 SkASSERT(dst && src && count >= 0);
616
617 SkXfermodeProc proc = fProc;
618
619 if (NULL != proc) {
620 if (NULL == aa) {
621 for (int i = count - 1; i >= 0; --i) {
622 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
623 dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
624 }
625 } else {
626 for (int i = count - 1; i >= 0; --i) {
627 unsigned a = aa[i];
628 if (0 != a) {
629 SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
630 SkPMColor C = proc(src[i], dstC);
631 if (0xFF != a) {
632 C = SkFourByteInterp(C, dstC, a);
633 }
634 dst[i] = SkPixel32ToPixel16_ToU16(C);
635 }
636 }
637 }
638 }
639}
640
641void SkProcXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
642 const SK_RESTRICT SkPMColor src[], int count,
643 const SK_RESTRICT SkAlpha aa[]) {
644 SkASSERT(dst && src && count >= 0);
645
646 SkXfermodeProc proc = fProc;
647
648 if (NULL != proc) {
649 if (NULL == aa) {
650 for (int i = count - 1; i >= 0; --i) {
651 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
652 dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
653 }
654 } else {
655 for (int i = count - 1; i >= 0; --i) {
656 unsigned a = aa[i];
657 if (0 != a) {
658 SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
659 SkPMColor C = proc(src[i], dstC);
660 if (0xFF != a) {
661 C = SkFourByteInterp(C, dstC, a);
662 }
663 dst[i] = SkPixel32ToPixel4444(C);
664 }
665 }
666 }
667 }
668}
669
670void SkProcXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
671 const SK_RESTRICT SkPMColor src[], int count,
672 const SK_RESTRICT SkAlpha aa[]) {
673 SkASSERT(dst && src && count >= 0);
674
675 SkXfermodeProc proc = fProc;
676
677 if (NULL != proc) {
678 if (NULL == aa) {
679 for (int i = count - 1; i >= 0; --i) {
680 SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
681 dst[i] = SkToU8(SkGetPackedA32(res));
682 }
683 } else {
684 for (int i = count - 1; i >= 0; --i) {
685 unsigned a = aa[i];
686 if (0 != a) {
687 SkAlpha dstA = dst[i];
688 SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
689 unsigned A = SkGetPackedA32(res);
690 if (0xFF != a) {
691 A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
692 }
693 dst[i] = SkToU8(A);
694 }
695 }
696 }
697 }
698}
699
700SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
701 : SkXfermode(buffer) {
702 fProc = (SkXfermodeProc)buffer.readFunctionPtr();
703}
704
705void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) {
706 buffer.writeFunctionPtr((void*)fProc);
707}
708
709bool SkProcXfermode::asMode(SkXfermode::Mode* mode) {
710 for (size_t i = 0; i < SK_ARRAY_COUNT(gProcCoeffs); i++) {
711 if (gProcCoeffs[i].fProc == fProc) {
712 if (mode) {
713 *mode = static_cast<Mode>(i);
714 }
715 return true;
716 }
717 }
718 return false;
719}
720
721///////////////////////////////////////////////////////////////////////////////
722///////////////////////////////////////////////////////////////////////////////
723
724class SkProcCoeffXfermode : public SkProcXfermode {
725public:
726 SkProcCoeffXfermode(SkXfermodeProc proc, Coeff sc, Coeff dc)
727 : INHERITED(proc), fSrcCoeff(sc), fDstCoeff(dc) {
728 }
729
730 virtual bool asCoeff(Coeff* sc, Coeff* dc) {
731 if (sc) {
732 *sc = fSrcCoeff;
733 }
734 if (dc) {
735 *dc = fDstCoeff;
736 }
737 return true;
738 }
739
740 virtual Factory getFactory() { return CreateProc; }
741 virtual void flatten(SkFlattenableWriteBuffer& buffer) {
742 this->INHERITED::flatten(buffer);
743 buffer.write32(fSrcCoeff);
744 buffer.write32(fDstCoeff);
745 }
746
747protected:
748 SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer)
749 : INHERITED(buffer) {
750 fSrcCoeff = (Coeff)buffer.readU32();
751 fDstCoeff = (Coeff)buffer.readU32();
752 }
753
754private:
755 Coeff fSrcCoeff, fDstCoeff;
756
757 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
758 return SkNEW_ARGS(SkProcCoeffXfermode, (buffer)); }
759
760 typedef SkProcXfermode INHERITED;
761};
762
reed@android.com8a1c16f2008-12-17 15:59:43 +0000763///////////////////////////////////////////////////////////////////////////////
764
765class SkClearXfermode : public SkProcCoeffXfermode {
766public:
767 SkClearXfermode() : SkProcCoeffXfermode(clear_modeproc,
768 kZero_Coeff, kZero_Coeff) {}
769
770 virtual void xfer32(SK_RESTRICT SkPMColor dst[],
771 const SK_RESTRICT SkPMColor[], int count,
772 const SK_RESTRICT SkAlpha aa[]) {
773 SkASSERT(dst && count >= 0);
774
775 if (NULL == aa) {
776 memset(dst, 0, count << 2);
777 } else {
778 for (int i = count - 1; i >= 0; --i) {
779 unsigned a = aa[i];
780 if (0xFF == a) {
781 dst[i] = 0;
782 } else if (a != 0) {
783 dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
784 }
785 }
786 }
787 }
788 virtual void xferA8(SK_RESTRICT SkAlpha dst[],
789 const SK_RESTRICT SkPMColor[], int count,
790 const SK_RESTRICT SkAlpha aa[]) {
791 SkASSERT(dst && count >= 0);
792
793 if (NULL == aa) {
794 memset(dst, 0, count);
795 } else {
796 for (int i = count - 1; i >= 0; --i) {
797 unsigned a = aa[i];
798 if (0xFF == a) {
799 dst[i] = 0;
800 } else if (0 != a) {
801 dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
802 }
803 }
804 }
805 }
806
807 virtual Factory getFactory() { return CreateProc; }
808
809private:
810 SkClearXfermode(SkFlattenableReadBuffer& buffer)
811 : SkProcCoeffXfermode(buffer) {}
812
813 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
814 return SkNEW_ARGS(SkClearXfermode, (buffer));
815 }
816};
817
818///////////////////////////////////////////////////////////////////////////////
819
820class SkSrcXfermode : public SkProcCoeffXfermode {
821public:
822 SkSrcXfermode() : SkProcCoeffXfermode(src_modeproc,
823 kOne_Coeff, kZero_Coeff) {}
824
825 virtual void xfer32(SK_RESTRICT SkPMColor dst[],
826 const SK_RESTRICT SkPMColor src[], int count,
827 const SK_RESTRICT SkAlpha aa[]) {
828 SkASSERT(dst && src && count >= 0);
829
830 if (NULL == aa) {
831 memcpy(dst, src, count << 2);
832 } else {
833 for (int i = count - 1; i >= 0; --i) {
834 unsigned a = aa[i];
835 if (a == 0xFF) {
836 dst[i] = src[i];
837 } else if (a != 0) {
838 dst[i] = SkFourByteInterp(src[i], dst[i], a);
839 }
840 }
841 }
842 }
843
844 virtual void xferA8(SK_RESTRICT SkAlpha dst[],
845 const SK_RESTRICT SkPMColor src[], int count,
846 const SK_RESTRICT SkAlpha aa[]) {
847 SkASSERT(dst && src && count >= 0);
848
849 if (NULL == aa) {
850 for (int i = count - 1; i >= 0; --i) {
851 dst[i] = SkToU8(SkGetPackedA32(src[i]));
852 }
853 } else {
854 for (int i = count - 1; i >= 0; --i) {
855 unsigned a = aa[i];
856 if (0 != a) {
857 unsigned srcA = SkGetPackedA32(src[i]);
858 if (a == 0xFF) {
859 dst[i] = SkToU8(srcA);
860 } else {
861 dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
862 }
863 }
864 }
865 }
866 }
867
868 virtual Factory getFactory() { return CreateProc; }
869
870private:
871 SkSrcXfermode(SkFlattenableReadBuffer& buffer)
872 : SkProcCoeffXfermode(buffer) {}
873
874 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
875 return SkNEW_ARGS(SkSrcXfermode, (buffer));
876 }
877};
878
879class SkDstInXfermode : public SkProcCoeffXfermode {
880public:
881 SkDstInXfermode() : SkProcCoeffXfermode(dstin_modeproc,
882 kZero_Coeff, kSA_Coeff) {}
883
884 virtual void xfer32(SK_RESTRICT SkPMColor dst[],
885 const SK_RESTRICT SkPMColor src[], int count,
886 const SK_RESTRICT SkAlpha aa[]) {
887 SkASSERT(dst && src);
888
889 if (count <= 0) {
890 return;
891 }
892 if (NULL != aa) {
893 return this->INHERITED::xfer32(dst, src, count, aa);
894 }
895
896 do {
897 unsigned a = SkGetPackedA32(*src);
898 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
899 dst++;
900 src++;
901 } while (--count != 0);
902 }
903
904 virtual Factory getFactory() { return CreateProc; }
905
906private:
907 SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
908
909 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
910 return SkNEW_ARGS(SkDstInXfermode, (buffer));
911 }
912
913 typedef SkProcCoeffXfermode INHERITED;
914};
915
916class SkDstOutXfermode : public SkProcCoeffXfermode {
917public:
918 SkDstOutXfermode() : SkProcCoeffXfermode(dstout_modeproc,
919 kZero_Coeff, kISA_Coeff) {}
920
921 virtual void xfer32(SK_RESTRICT SkPMColor dst[],
922 const SK_RESTRICT SkPMColor src[], int count,
923 const SK_RESTRICT SkAlpha aa[]) {
924 SkASSERT(dst && src);
925
926 if (count <= 0) {
927 return;
928 }
929 if (NULL != aa) {
930 return this->INHERITED::xfer32(dst, src, count, aa);
931 }
932
933 do {
934 unsigned a = SkGetPackedA32(*src);
935 *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
936 dst++;
937 src++;
938 } while (--count != 0);
939 }
940
941 virtual Factory getFactory() { return CreateProc; }
942
943private:
944 SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
945 : INHERITED(buffer) {}
946
947 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
948 return SkNEW_ARGS(SkDstOutXfermode, (buffer));
949 }
950
951 typedef SkProcCoeffXfermode INHERITED;
952};
953
954///////////////////////////////////////////////////////////////////////////////
955
reed@android.coma0f5d152009-06-22 17:38:10 +0000956SkXfermode* SkXfermode::Create(Mode mode) {
957 SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
958 SkASSERT((unsigned)mode < kModeCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000959
960 switch (mode) {
961 case kClear_Mode:
962 return SkNEW(SkClearXfermode);
963 case kSrc_Mode:
964 return SkNEW(SkSrcXfermode);
965 case kSrcOver_Mode:
966 return NULL;
967 case kDstIn_Mode:
968 return SkNEW(SkDstInXfermode);
969 case kDstOut_Mode:
970 return SkNEW(SkDstOutXfermode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971 // use the table
972 default: {
973 const ProcCoeff& rec = gProcCoeffs[mode];
reed@android.coma0f5d152009-06-22 17:38:10 +0000974 if ((unsigned)rec.fSC < SkXfermode::kCoeffCount &&
975 (unsigned)rec.fDC < SkXfermode::kCoeffCount) {
976 return SkNEW_ARGS(SkProcCoeffXfermode, (rec.fProc,
977 rec.fSC,
978 rec.fDC));
979 } else {
980 return SkNEW_ARGS(SkProcXfermode, (rec.fProc));
981 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982 }
983 }
984}
985
reed@android.coma0f5d152009-06-22 17:38:10 +0000986bool SkXfermode::IsMode(SkXfermode* xfer, Mode* mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987 if (NULL == xfer) {
988 if (mode) {
989 *mode = kSrcOver_Mode;
990 }
991 return true;
992 }
993
994 SkXfermode::Coeff sc, dc;
995 if (xfer->asCoeff(&sc, &dc)) {
996 SkASSERT((unsigned)sc < (unsigned)SkXfermode::kCoeffCount);
997 SkASSERT((unsigned)dc < (unsigned)SkXfermode::kCoeffCount);
998
999 const ProcCoeff* rec = gProcCoeffs;
1000 for (size_t i = 0; i < SK_ARRAY_COUNT(gProcCoeffs); i++) {
1001 if (rec[i].fSC == sc && rec[i].fDC == dc) {
1002 if (mode) {
reed@android.coma0f5d152009-06-22 17:38:10 +00001003 *mode = static_cast<Mode>(i);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001004 }
1005 return true;
1006 }
1007 }
1008 }
1009
1010 // no coefficients, or not found in our table
1011 return false;
1012}
1013
reed@android.coma0f5d152009-06-22 17:38:10 +00001014SkXfermodeProc SkXfermode::GetProc(Mode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001015 SkXfermodeProc proc = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001016 if ((unsigned)mode < kModeCount) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001017 proc = gProcCoeffs[mode].fProc;
1018 }
1019 return proc;
1020}
1021
1022///////////////////////////////////////////////////////////////////////////////
1023//////////// 16bit xfermode procs
1024
1025#ifdef SK_DEBUG
1026static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
1027static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
1028#endif
1029
1030static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
1031 SkASSERT(require_255(src));
1032 return SkPixel32ToPixel16(src);
1033}
1034
1035static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
1036 return dst;
1037}
1038
1039static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
1040 SkASSERT(require_0(src));
1041 return dst;
1042}
1043
1044static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
1045 SkASSERT(require_255(src));
1046 return SkPixel32ToPixel16(src);
1047}
1048
1049static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
1050 SkASSERT(require_0(src));
1051 return dst;
1052}
1053
1054static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
1055 SkASSERT(require_255(src));
1056 return dst;
1057}
1058
1059static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
1060 SkASSERT(require_255(src));
1061 return SkPixel32ToPixel16(src);
1062}
1063
1064static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
1065 SkASSERT(require_255(src));
1066 return dst;
1067}
1068
1069static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
1070 SkASSERT(require_0(src));
1071 return dst;
1072}
1073
1074static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
1075 unsigned isa = 255 - SkGetPackedA32(src);
1076
1077 return SkPackRGB16(
1078 SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
1079 SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
1080 SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
1081}
1082
1083static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
1084 SkASSERT(require_0(src));
1085 return dst;
1086}
1087
1088static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1089 SkASSERT(require_255(src));
1090 return SkPixel32ToPixel16(src);
1091}
1092
1093static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
1094 SkASSERT(require_255(src));
1095 return dst;
1096}
1097
1098/*********
1099 darken and lighten boil down to this.
1100
1101 darken = (1 - Sa) * Dc + min(Sc, Dc)
1102 lighten = (1 - Sa) * Dc + max(Sc, Dc)
1103
1104 if (Sa == 0) these become
1105 darken = Dc + min(0, Dc) = 0
1106 lighten = Dc + max(0, Dc) = Dc
1107
1108 if (Sa == 1) these become
1109 darken = min(Sc, Dc)
1110 lighten = max(Sc, Dc)
1111*/
1112
1113static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
1114 SkASSERT(require_0(src));
1115 return 0;
1116}
1117
1118static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
1119 SkASSERT(require_255(src));
1120 unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1121 unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1122 unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1123 return SkPackRGB16(r, g, b);
1124}
1125
1126static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
1127 SkASSERT(require_0(src));
1128 return dst;
1129}
1130
1131static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
1132 SkASSERT(require_255(src));
1133 unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
1134 unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
1135 unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
1136 return SkPackRGB16(r, g, b);
1137}
1138
1139struct Proc16Rec {
1140 SkXfermodeProc16 fProc16_0;
1141 SkXfermodeProc16 fProc16_255;
1142 SkXfermodeProc16 fProc16_General;
1143};
1144
reed@android.coma0f5d152009-06-22 17:38:10 +00001145static const Proc16Rec gModeProcs16[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001146 { NULL, NULL, NULL }, // CLEAR
1147 { NULL, src_modeproc16_255, NULL },
1148 { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
1149 { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
1150 { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
1151 { NULL, srcin_modeproc16_255, NULL },
1152 { NULL, dstin_modeproc16_255, NULL },
1153 { NULL, NULL, NULL },// SRC_OUT
1154 { dstout_modeproc16_0, NULL, NULL },
1155 { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
1156 { NULL, dstatop_modeproc16_255, NULL },
1157 { NULL, NULL, NULL }, // XOR
reed@android.coma0f5d152009-06-22 17:38:10 +00001158
1159 { NULL, NULL, NULL }, // plus
1160 { NULL, NULL, NULL }, // multiply
1161 { NULL, NULL, NULL }, // screen
1162 { NULL, NULL, NULL }, // overlay
1163 { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
1164 { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
1165 { NULL, NULL, NULL }, // colordodge
1166 { NULL, NULL, NULL }, // colorburn
1167 { NULL, NULL, NULL }, // hardlight
1168 { NULL, NULL, NULL }, // softlight
1169 { NULL, NULL, NULL }, // difference
1170 { NULL, NULL, NULL }, // exclusion
reed@android.com8a1c16f2008-12-17 15:59:43 +00001171};
1172
reed@android.coma0f5d152009-06-22 17:38:10 +00001173SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001174 SkXfermodeProc16 proc16 = NULL;
reed@android.coma0f5d152009-06-22 17:38:10 +00001175 if ((unsigned)mode < kModeCount) {
1176 const Proc16Rec& rec = gModeProcs16[mode];
reed@android.com8a1c16f2008-12-17 15:59:43 +00001177 unsigned a = SkColorGetA(srcColor);
1178
1179 if (0 == a) {
1180 proc16 = rec.fProc16_0;
1181 } else if (255 == a) {
1182 proc16 = rec.fProc16_255;
1183 } else {
1184 proc16 = rec.fProc16_General;
1185 }
1186 }
1187 return proc16;
1188}
1189