1 #define __NR_COMPOSE_C__
3 /*
4 * Pixel buffer rendering library
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 *
9 * This code is in public domain
10 */
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
16 #include <string.h>
17 #include "nr-pixops.h"
19 #ifdef WITH_MMX
20 /* fixme: */
21 #ifdef __cplusplus
22 extern "C" {
23 #endif /* __cplusplus */
24 int nr_have_mmx (void);
25 void nr_mmx_R8G8B8A8_P_EMPTY_A8_RGBAP (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned char *c);
26 void nr_mmx_R8G8B8A8_P_R8G8B8A8_P_A8_RGBAP (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned char *c);
27 void nr_mmx_R8G8B8_R8G8B8_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha);
28 #define NR_PIXOPS_MMX nr_have_mmx ()
29 #ifdef __cplusplus
30 }
31 #endif /* __cplusplus */
32 #endif
34 // Naming: nr_RESULT_BACKGROUND_FOREGROUND_extra
36 void
37 nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
38 {
39 unsigned int r, c;
41 for (r = h; r > 0; r--) {
42 if (alpha == 0) {
43 memset(px, 0x0, 4 * w);
44 } else if (alpha == 255) {
45 memcpy(px, spx, 4 * w);
46 } else {
47 unsigned char *d = px;
48 const unsigned char *s = spx;
49 for (c = w; c > 0; c--) {
50 *d++ = *s++;
51 *d++ = *s++;
52 *d++ = *s++;
53 *d++ = NR_PREMUL_111(*s, alpha);
54 s++;
55 }
56 }
57 px += rs;
58 spx += srs;
59 }
60 }
62 void
63 nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
64 {
65 unsigned int r, c;
67 for (r = h; r > 0; r--) {
68 if (alpha == 0) {
69 memset(px, 0x0, 4 * w);
70 } else {
71 unsigned char *d = px;
72 const unsigned char *s = spx;
73 for (c = w; c > 0; c--) {
74 if (s[3] == 0) {
75 d[3] = 0;
76 } else if (s[3] == 255) {
77 memcpy(d, s, 4);
78 } else {
79 d[0] = NR_DEMUL_111(s[0], s[3]);
80 d[1] = NR_DEMUL_111(s[1], s[3]);
81 d[2] = NR_DEMUL_111(s[2], s[3]);
82 d[3] = NR_PREMUL_111(s[3], alpha);
83 }
84 d += 4;
85 s += 4;
86 }
87 }
88 px += rs;
89 spx += srs;
90 }
91 }
93 void
94 nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
95 {
96 unsigned int r, c;
98 for (r = h; r > 0; r--) {
99 unsigned char *d = px;
100 const unsigned char *s = spx;
101 if (alpha == 0) {
102 memset(px, 0x0, 4 * w);
103 } else if (alpha == 255) {
104 for (c = w; c > 0; c--) {
105 d[0] = NR_PREMUL_111(s[0], s[3]);
106 d[1] = NR_PREMUL_111(s[1], s[3]);
107 d[2] = NR_PREMUL_111(s[2], s[3]);
108 d[3] = s[3];
109 d += 4;
110 s += 4;
111 }
112 } else {
113 for (c = w; c > 0; c--) {
114 if (s[3] == 0) {
115 memset(d, 0, 4);
116 } else {
117 unsigned int a;
118 a = NR_PREMUL_112(s[3], alpha);
119 d[0] = NR_PREMUL_121(s[0], a);
120 d[1] = NR_PREMUL_121(s[1], a);
121 d[2] = NR_PREMUL_121(s[2], a);
122 d[3] = NR_NORMALIZE_21(a);
123 }
124 d += 4;
125 s += 4;
126 }
127 }
128 px += rs;
129 spx += srs;
130 }
131 }
133 void
134 nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
135 {
136 unsigned int r, c;
138 for (r = h; r > 0; r--) {
139 if (alpha == 0) {
140 memset(px, 0x0, 4 * w);
141 } else if (alpha == 255) {
142 memcpy(px, spx, 4 * w);
143 } else {
144 unsigned char *d = px;
145 const unsigned char *s = spx;
146 for (c = w; c > 0; c--) {
147 d[0] = NR_PREMUL_111(s[0], alpha);
148 d[1] = NR_PREMUL_111(s[1], alpha);
149 d[2] = NR_PREMUL_111(s[2], alpha);
150 d[3] = NR_PREMUL_111(s[3], alpha);
151 d += 4;
152 s += 4;
153 }
154 }
155 px += rs;
156 spx += srs;
157 }
158 }
160 void
161 nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
162 {
163 unsigned int r, c;
165 if (alpha == 0) {
166 /* NOP */
167 } else if (alpha == 255) {
168 for (r = h; r > 0; r--) {
169 unsigned char *d = px;
170 const unsigned char *s = spx;
171 for (c = w; c > 0; c--) {
172 if (s[3] == 0) {
173 /* Transparent FG, NOP */
174 } else if ((s[3] == 255) || (d[3] == 0)) {
175 /* Full coverage, COPY */
176 memcpy(d, s, 4);
177 } else {
178 /* Full composition */
179 unsigned int ca;
180 ca = NR_COMPOSEA_112(s[3], d[3]);
181 d[0] = NR_COMPOSENNN_111121(s[0], s[3], d[0], d[3], ca);
182 d[1] = NR_COMPOSENNN_111121(s[1], s[3], d[1], d[3], ca);
183 d[2] = NR_COMPOSENNN_111121(s[2], s[3], d[2], d[3], ca);
184 d[3] = NR_NORMALIZE_21(ca);
185 }
186 d += 4;
187 s += 4;
188 }
189 px += rs;
190 spx += srs;
191 }
192 } else {
193 for (r = h; r > 0; r--) {
194 unsigned char *d = px;
195 const unsigned char *s = spx;
196 for (c = w; c > 0; c--) {
197 unsigned int a;
198 a = NR_PREMUL_112(s[3], alpha);
199 if (a == 0) {
200 /* Transparent FG, NOP */
201 } else if ((a == 255*255) || (d[3] == 0)) {
202 /* Full coverage, COPY */
203 d[0] = s[0];
204 d[1] = s[1];
205 d[2] = s[2];
206 d[3] = NR_NORMALIZE_21(a);
207 } else {
208 /* Full composition */
209 unsigned int ca;
210 ca = NR_COMPOSEA_213(a, d[3]);
211 d[0] = NR_COMPOSENNN_121131(s[0], a, d[0], d[3], ca);
212 d[1] = NR_COMPOSENNN_121131(s[1], a, d[1], d[3], ca);
213 d[2] = NR_COMPOSENNN_121131(s[2], a, d[2], d[3], ca);
214 d[3] = NR_NORMALIZE_31(ca);
215 }
216 d += 4;
217 s += 4;
218 }
219 px += rs;
220 spx += srs;
221 }
222 }
223 }
225 void
226 nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
227 {
228 unsigned int r, c;
230 if (alpha == 0) {
231 /* NOP */
232 } else if (alpha == 255) {
233 for (r = h; r > 0; r--) {
234 unsigned char *d = px;
235 const unsigned char *s = spx;
236 for (c = w; c > 0; c--) {
237 if (s[3] == 0) {
238 /* Transparent FG, NOP */
239 } else if (s[3] == 255) {
240 /* Full coverage, demul src */
241 // dc' = ((1 - sa) * da*dc + sc)/da' = sc/da' = sc
242 // da' = 1 - (1 - sa) * (1 - da) = 1 - 0 * (1 - da) = 1
243 memcpy(d, s, 4);
244 } else if (d[3] == 0) {
245 /* Full coverage, demul src */
246 // dc' = ((1 - sa) * da*dc + sc)/da' = sc/da' = sc/sa = sc/sa
247 // da' = 1 - (1 - sa) * (1 - da) = 1 - (1 - sa) = sa
248 d[0] = NR_DEMUL_111(s[0], s[3]);
249 d[1] = NR_DEMUL_111(s[1], s[3]);
250 d[2] = NR_DEMUL_111(s[2], s[3]);
251 d[3] = s[3];
252 } else {
253 /* Full composition */
254 // dc' = ((1 - sa) * da*dc + sc)/da' = ((1 - sa) * da*dc + sc)/da'
255 // da' = 1 - (1 - sa) * (1 - da) = 1 - (1 - sa) * (1 - da)
256 unsigned int da = NR_COMPOSEA_112(s[3], d[3]);
257 d[0] = NR_COMPOSEPNN_111121(s[0], s[3], d[0], d[3], da);
258 d[1] = NR_COMPOSEPNN_111121(s[1], s[3], d[1], d[3], da);
259 d[2] = NR_COMPOSEPNN_111121(s[2], s[3], d[2], d[3], da);
260 d[3] = NR_NORMALIZE_21(da);
261 }
262 d += 4;
263 s += 4;
264 }
265 px += rs;
266 spx += srs;
267 }
268 } else {
269 for (r = h; r > 0; r--) {
270 unsigned char *d = px;
271 const unsigned char *s = spx;
272 for (c = w; c > 0; c--) {
273 unsigned int a;
274 a = NR_PREMUL_112(s[3], alpha);
275 if (a == 0) {
276 /* Transparent FG, NOP */
277 } else if (d[3] == 0) {
278 /* Full coverage, demul src */
279 // dc' = ((1 - alpha*sa) * da*dc + alpha*sc)/da' = alpha*sc/da' = alpha*sc/(alpha*sa) = sc/sa
280 // da' = 1 - (1 - alpha*sa) * (1 - da) = 1 - (1 - alpha*sa) = alpha*sa
281 d[0] = NR_DEMUL_111(s[0], s[3]);
282 d[1] = NR_DEMUL_111(s[1], s[3]);
283 d[2] = NR_DEMUL_111(s[2], s[3]);
284 d[3] = NR_NORMALIZE_21(a);
285 } else {
286 // dc' = ((1 - alpha*sa) * da*dc + alpha*sc)/da'
287 // da' = 1 - (1 - alpha*sa) * (1 - da)
288 unsigned int da = NR_COMPOSEA_213(a, d[3]);
289 d[0] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[0], alpha), a, d[0], d[3], da);
290 d[1] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[1], alpha), a, d[1], d[3], da);
291 d[2] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[2], alpha), a, d[2], d[3], da);
292 d[3] = NR_NORMALIZE_31(da);
293 }
294 d += 4;
295 s += 4;
296 }
297 px += rs;
298 spx += srs;
299 }
300 }
301 }
303 void
304 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
305 {
306 unsigned int r, c;
308 if (alpha == 0) {
309 /* NOP */
310 } else if (alpha == 255) {
311 for (r = h; r > 0; r--) {
312 unsigned char *d = px;
313 const unsigned char *s = spx;
314 for (c = w; c > 0; c--) {
315 if (s[3] == 0) {
316 /* Transparent FG, NOP */
317 } else if (s[3] == 255) {
318 /* Opaque FG, COPY */
319 // dc' = (1 - sa) * dc + sa*sc = sa*sc = sc
320 // da' = 1 - (1 - sa) * (1 - da) = 1 - 0 * (1 - da) = 1 (= sa)
321 memcpy(d, s, 4);
322 } else if (d[3] == 0) {
323 /* Transparent BG, premul src */
324 // dc' = (1 - sa) * dc + sa*sc = sa*sc
325 // da' = 1 - (1 - sa) * (1 - da) = 1 - (1 - sa) = sa
326 d[0] = NR_PREMUL_111(s[0], s[3]);
327 d[1] = NR_PREMUL_111(s[1], s[3]);
328 d[2] = NR_PREMUL_111(s[2], s[3]);
329 d[3] = s[3];
330 } else {
331 // dc' = (1 - sa) * dc + sa*sc
332 // da' = 1 - (1 - sa) * (1 - da)
333 d[0] = NR_COMPOSENPP_1111(s[0], s[3], d[0]);
334 d[1] = NR_COMPOSENPP_1111(s[1], s[3], d[1]);
335 d[2] = NR_COMPOSENPP_1111(s[2], s[3], d[2]);
336 d[3] = NR_COMPOSEA_111(s[3], d[3]);
337 }
338 d += 4;
339 s += 4;
340 }
341 px += rs;
342 spx += srs;
343 }
344 } else {
345 for (r = h; r > 0; r--) {
346 unsigned char *d = px;
347 const unsigned char *s = spx;
348 for (c = w; c > 0; c--) {
349 unsigned int a;
350 a = NR_PREMUL_112 (s[3], alpha);
351 if (a == 0) {
352 /* Transparent FG, NOP */
353 } else if (d[3] == 0) {
354 /* Transparent BG, premul src */
355 // dc' = (1 - alpha*sa) * dc + alpha*sa*sc = alpha*sa*sc
356 // da' = 1 - (1 - alpha*sa) * (1 - da) = 1 - (1 - alpha*sa) = alpha*sa
357 d[0] = NR_PREMUL_121(s[0], a);
358 d[1] = NR_PREMUL_121(s[1], a);
359 d[2] = NR_PREMUL_121(s[2], a);
360 d[3] = NR_NORMALIZE_21(a);
361 } else {
362 // dc' = (1 - alpha*sa) * dc + alpha*sa*sc
363 // da' = 1 - (1 - alpha*sa) * (1 - da)
364 d[0] = NR_COMPOSENPP_1211(s[0], a, d[0]);
365 d[1] = NR_COMPOSENPP_1211(s[1], a, d[1]);
366 d[2] = NR_COMPOSENPP_1211(s[2], a, d[2]);
367 d[3] = NR_COMPOSEA_211(a, d[3]);
368 }
369 d += 4;
370 s += 4;
371 }
372 px += rs;
373 spx += srs;
374 }
375 }
376 }
378 void
379 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
380 {
381 unsigned int r, c;
383 if (alpha == 0) {
384 /* Transparent FG, NOP */
385 } else if (alpha == 255) {
386 /* Simple */
387 for (r = h; r > 0; r--) {
388 unsigned char *d = px;
389 const unsigned char *s = spx;
390 for (c = w; c > 0; c--) {
391 if (s[3] == 0) {
392 /* Transparent FG, NOP */
393 } else if ((s[3] == 255) || (d[3] == 0)) {
394 /* Transparent BG, COPY */
395 memcpy(d, s, 4);
396 } else {
397 d[0] = NR_COMPOSEPPP_1111(s[0], s[3], d[0]);
398 d[1] = NR_COMPOSEPPP_1111(s[1], s[3], d[1]);
399 d[2] = NR_COMPOSEPPP_1111(s[2], s[3], d[2]);
400 d[3] = NR_COMPOSEA_111(s[3], d[3]);
401 }
402 d += 4;
403 s += 4;
404 }
405 px += rs;
406 spx += srs;
407 }
408 } else {
409 for (r = h; r > 0; r--) {
410 unsigned char *d = px;
411 const unsigned char *s = spx;
412 for (c = w; c > 0; c--) {
413 if (s[3] == 0) {
414 /* Transparent FG, NOP */
415 } else if (d[3] == 0) {
416 /* Transparent BG, COPY */
417 d[0] = NR_PREMUL_111(s[0], alpha);
418 d[1] = NR_PREMUL_111(s[1], alpha);
419 d[2] = NR_PREMUL_111(s[2], alpha);
420 d[3] = NR_PREMUL_111(s[3], alpha);
421 } else {
422 // dc' = (1 - alpha*sa) * dc + alpha*sc
423 // da' = 1 - (1 - alpha*sa) * (1 - da)
424 unsigned int a;
425 a = NR_PREMUL_112(s[3], alpha);
426 d[0] = NR_COMPOSEPPP_2211(NR_PREMUL_112(alpha, s[0]), a, d[0]);
427 d[1] = NR_COMPOSEPPP_2211(NR_PREMUL_112(alpha, s[1]), a, d[1]);
428 d[2] = NR_COMPOSEPPP_2211(NR_PREMUL_112(alpha, s[2]), a, d[2]);
429 d[3] = NR_COMPOSEA_211(a, d[3]);
430 }
431 d += 4;
432 s += 4;
433 }
434 px += rs;
435 spx += srs;
436 }
437 }
438 }
440 /* Masked operations */
442 void
443 nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
444 {
445 unsigned int r, c;
447 for (r = h; r > 0; r--) {
448 unsigned char *d = px;
449 const unsigned char *s = spx;
450 const unsigned char *m = mpx;
451 for (c = w; c > 0; c--) {
452 d[0] = s[0];
453 d[1] = s[1];
454 d[2] = s[2];
455 d[3] = NR_PREMUL_111(s[3], m[0]);
456 d += 4;
457 s += 4;
458 m += 1;
459 }
460 px += rs;
461 spx += srs;
462 mpx += mrs;
463 }
464 }
466 void
467 nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
468 {
469 unsigned int r, c;
471 for (r = h; r > 0; r--) {
472 unsigned char *d = px;
473 const unsigned char *s = spx;
474 const unsigned char *m = mpx;
475 for (c = w; c > 0; c--) {
476 unsigned int a;
477 a = NR_PREMUL_112 (s[3], m[0]);
478 if (a == 0) {
479 d[3] = 0;
480 } else if (a == 255*255) {
481 memcpy(d, s, 4);
482 } else {
483 // dc' = ((1 - m*sa) * da*dc + m*sc)/da' = m*sc/da' = m*sc/(m*sa) = sc/sa
484 // da' = 1 - (1 - m*sa) * (1 - da) = 1 - (1 - m*sa) = m*sa
485 d[0] = NR_DEMUL_111(s[0], s[3]);
486 d[1] = NR_DEMUL_111(s[1], s[3]);
487 d[2] = NR_DEMUL_111(s[2], s[3]);
488 d[3] = NR_NORMALIZE_21(a);
489 }
490 d += 4;
491 s += 4;
492 m += 1;
493 }
494 px += rs;
495 spx += srs;
496 mpx += mrs;
497 }
498 }
500 void
501 nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
502 {
503 unsigned int r, c;
505 for (r = h; r > 0; r--) {
506 unsigned char *d = px;
507 const unsigned char *s = spx;
508 const unsigned char *m = mpx;
509 for (c = w; c > 0; c--) {
510 unsigned int a;
511 a = NR_PREMUL_112(s[3], m[0]);
512 if (a == 0) {
513 memset(d, 0, 4);
514 } else if (a == 255*255) {
515 memcpy(d, s, 4);
516 } else {
517 d[0] = NR_PREMUL_121(s[0], a);
518 d[1] = NR_PREMUL_121(s[1], a);
519 d[2] = NR_PREMUL_121(s[2], a);
520 d[3] = NR_NORMALIZE_21(a);
521 }
522 d += 4;
523 s += 4;
524 m += 1;
525 }
526 px += rs;
527 spx += srs;
528 mpx += mrs;
529 }
530 }
532 void
533 nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
534 {
535 unsigned int r, c;
537 for (r = h; r > 0; r--) {
538 unsigned char *d = px;
539 const unsigned char *s = spx;
540 const unsigned char *m = mpx;
541 for (c = w; c > 0; c--) {
542 d[0] = NR_PREMUL_111(s[0], m[0]);
543 d[1] = NR_PREMUL_111(s[1], m[0]);
544 d[2] = NR_PREMUL_111(s[2], m[0]);
545 d[3] = NR_PREMUL_111(s[3], m[0]);
546 d += 4;
547 s += 4;
548 m += 1;
549 }
550 px += rs;
551 spx += srs;
552 mpx += mrs;
553 }
554 }
556 void
557 nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
558 {
559 unsigned int r, c;
561 for (r = h; r > 0; r--) {
562 unsigned char *d = px;
563 const unsigned char *s = spx;
564 const unsigned char *m = mpx;
565 for (c = w; c > 0; c--) {
566 unsigned int a;
567 a = NR_PREMUL_112(s[3], m[0]);
568 if (a == 0) {
569 /* Transparent FG, NOP */
570 } else if ((a == 255*255) || (d[3] == 0)) {
571 /* Full coverage, COPY */
572 d[0] = s[0];
573 d[1] = s[1];
574 d[2] = s[2];
575 d[3] = NR_NORMALIZE_21(a);
576 } else {
577 /* Full composition */
578 unsigned int ca;
579 ca = NR_COMPOSEA_213(a, d[3]);
580 d[0] = NR_COMPOSENNN_121131(s[0], a, d[0], d[3], ca);
581 d[1] = NR_COMPOSENNN_121131(s[1], a, d[1], d[3], ca);
582 d[2] = NR_COMPOSENNN_121131(s[2], a, d[2], d[3], ca);
583 d[3] = NR_NORMALIZE_31(ca);
584 }
585 d += 4;
586 s += 4;
587 m += 1;
588 }
589 px += rs;
590 spx += srs;
591 mpx += mrs;
592 }
593 }
595 void
596 nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
597 {
598 unsigned int r, c;
600 for (r = h; r > 0; r--) {
601 unsigned char *d = px;
602 const unsigned char *s = spx;
603 const unsigned char *m = mpx;
604 for (c = w; c > 0; c--) {
605 unsigned int a;
606 a = NR_PREMUL_112(s[3], m[0]);
607 if (a == 0) {
608 /* Transparent FG, NOP */
609 } else if (a == 255*255) {
610 /* Opaque FG, COPY */
611 memcpy(d, s, 4);
612 } else if (d[3] == 0) {
613 /* Full coverage, demul src */
614 // dc' = ((1 - m*sa) * da*dc + m*sc)/da' = m*sc/da' = m*sc/(m*sa) = sc/sa
615 // da' = 1 - (1 - m*sa) * (1 - da) = 1 - (1 - m*sa) = m*sa
616 d[0] = NR_DEMUL_111(s[0], s[3]);
617 d[1] = NR_DEMUL_111(s[1], s[3]);
618 d[2] = NR_DEMUL_111(s[2], s[3]);
619 d[3] = NR_NORMALIZE_21(a);
620 } else if (m[0] == 255) {
621 /* Full composition */
622 // dc' = ((1 - m*sa) * da*dc + m*sc)/da' = ((1 - sa) * da*dc + sc)/da'
623 // da' = 1 - (1 - m*sa) * (1 - da) = 1 - (1 - sa) * (1 - da)
624 unsigned int da = NR_COMPOSEA_112(s[3], d[3]);
625 d[0] = NR_COMPOSEPNN_111121(s[0], s[3], d[0], d[3], da);
626 d[1] = NR_COMPOSEPNN_111121(s[1], s[3], d[1], d[3], da);
627 d[2] = NR_COMPOSEPNN_111121(s[2], s[3], d[2], d[3], da);
628 d[3] = NR_NORMALIZE_21(da);
629 } else {
630 // dc' = ((1 - m*sa) * da*dc + m*sc)/da'
631 // da' = 1 - (1 - m*sa) * (1 - da)
632 unsigned int da = NR_COMPOSEA_213(a, d[3]);
633 d[0] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[0], m[0]), a, d[0], d[3], da);
634 d[1] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[1], m[0]), a, d[1], d[3], da);
635 d[2] = NR_COMPOSEPNN_221131(NR_PREMUL_112(s[2], m[0]), a, d[2], d[3], da);
636 d[3] = NR_NORMALIZE_31(da);
637 }
638 d += 4;
639 s += 4;
640 m += 1;
641 }
642 px += rs;
643 spx += srs;
644 mpx += mrs;
645 }
646 }
648 void
649 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
650 {
651 unsigned int r, c;
653 for (r = h; r>0; r--) {
654 unsigned char *d = px;
655 const unsigned char *s = spx;
656 const unsigned char *m = mpx;
657 for (c = w; c>0; c--) {
658 unsigned int a;
659 a = NR_PREMUL_112(s[3], m[0]);
660 if (a == 0) {
661 /* Transparent FG, NOP */
662 } else if (a == 255*255) {
663 memcpy(d, s, 4);
664 } else {
665 d[0] = NR_COMPOSENPP_1211(s[0], a, d[0]);
666 d[1] = NR_COMPOSENPP_1211(s[1], a, d[1]);
667 d[2] = NR_COMPOSENPP_1211(s[2], a, d[2]);
668 d[3] = NR_COMPOSEA_211(a, d[3]);
669 }
670 d += 4;
671 s += 4;
672 m += 1;
673 }
674 px += rs;
675 spx += srs;
676 mpx += mrs;
677 }
678 }
680 void
681 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
682 {
683 unsigned int r, c;
685 for (r = h; r > 0; r--) {
686 unsigned char *d = px;
687 const unsigned char *s = spx;
688 const unsigned char *m = mpx;
689 for (c = w; c > 0; c--) {
690 unsigned int a;
691 a = NR_PREMUL_112 (s[3], m[0]);
692 if (a == 0) {
693 /* Transparent FG, NOP */
694 } else if (a == 255*255) {
695 /* Opaque FG, COPY */
696 memcpy(d, s, 4);
697 } else if (d[3] == 0) {
698 /* Transparent BG, COPY */
699 // dc' = (1 - m*sa) * dc + m*sc = m*sc
700 // da' = 1 - (1 - m*sa) * (1 - da) = 1 - (1 - m*sa) = m*sa
701 d[0] = NR_PREMUL_111 (s[0], m[0]);
702 d[1] = NR_PREMUL_111 (s[1], m[0]);
703 d[2] = NR_PREMUL_111 (s[2], m[0]);
704 d[3] = NR_NORMALIZE_21(a);
705 } else {
706 // dc' = (1 - m*sa) * dc + m*sc
707 // da' = 1 - (1 - m*sa) * (1 - da)
708 d[0] = NR_COMPOSEPPP_2211 (NR_PREMUL_112 (s[0], m[0]), a, d[0]);
709 d[1] = NR_COMPOSEPPP_2211 (NR_PREMUL_112 (s[1], m[0]), a, d[1]);
710 d[2] = NR_COMPOSEPPP_2211 (NR_PREMUL_112 (s[2], m[0]), a, d[2]);
711 d[3] = NR_COMPOSEA_211(a, d[3]);
712 }
713 d += 4;
714 s += 4;
715 m += 1;
716 }
717 px += rs;
718 spx += srs;
719 mpx += mrs;
720 }
721 }
723 /* FINAL DST MASK COLOR */
725 void
726 nr_R8G8B8A8_N_EMPTY_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba)
727 {
728 unsigned int r, g, b, a;
729 unsigned int x, y;
731 r = NR_RGBA32_R (rgba);
732 g = NR_RGBA32_G (rgba);
733 b = NR_RGBA32_B (rgba);
734 a = NR_RGBA32_A (rgba);
736 for (y = h; y > 0; y--) {
737 if (a == 0) {
738 memset(px, 0, w*4);
739 } else {
740 unsigned char *d = px;
741 const unsigned char *m = mpx;
742 for (x = w; x > 0; x--) {
743 d[0] = r;
744 d[1] = g;
745 d[2] = b;
746 d[3] = NR_PREMUL_111 (m[0], a);
747 d += 4;
748 m += 1;
749 }
750 }
751 px += rs;
752 mpx += mrs;
753 }
754 }
756 void
757 nr_R8G8B8A8_P_EMPTY_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba)
758 {
759 unsigned int r, g, b, a;
760 unsigned int x, y;
762 r = NR_RGBA32_R (rgba);
763 g = NR_RGBA32_G (rgba);
764 b = NR_RGBA32_B (rgba);
765 a = NR_RGBA32_A (rgba);
767 #ifdef WITH_MMX
768 if (NR_PIXOPS_MMX) {
769 unsigned char c[4];
770 c[0] = NR_PREMUL_111 (r, a);
771 c[1] = NR_PREMUL_111 (g, a);
772 c[2] = NR_PREMUL_111 (b, a);
773 c[3] = a;
774 /* WARNING: MMX composer REQUIRES w > 0 and h > 0 */
775 nr_mmx_R8G8B8A8_P_EMPTY_A8_RGBAP (px, w, h, rs, mpx, mrs, c);
776 return;
777 }
778 #endif
780 if ( a != 255 ){
781 // Pre-premultiply color values
782 r *= a;
783 g *= a;
784 b *= a;
785 }
787 for (y = h; y > 0; y--) {
788 unsigned char *d = px;
789 const unsigned char *m = mpx;
790 if (a == 0) {
791 memset(px, 0, w*4);
792 } else if (a == 255) {
793 for (x = w; x > 0; x--) {
794 d[0] = NR_PREMUL_111(m[0], r);
795 d[1] = NR_PREMUL_111(m[0], g);
796 d[2] = NR_PREMUL_111(m[0], b);
797 d[3] = m[0];
798 d += 4;
799 m += 1;
800 }
801 } else {
802 for (x = w; x > 0; x--) {
803 // Color values are already premultiplied with a
804 d[0] = NR_PREMUL_121(m[0], r);
805 d[1] = NR_PREMUL_121(m[0], g);
806 d[2] = NR_PREMUL_121(m[0], b);
807 d[3] = NR_PREMUL_111(m[0], a);
808 d += 4;
809 m += 1;
810 }
811 }
812 px += rs;
813 mpx += mrs;
814 }
815 }
817 void
818 nr_R8G8B8_R8G8B8_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba)
819 {
820 unsigned int r, g, b, a;
821 unsigned int x, y;
823 r = NR_RGBA32_R (rgba);
824 g = NR_RGBA32_G (rgba);
825 b = NR_RGBA32_B (rgba);
826 a = NR_RGBA32_A (rgba);
828 if (a == 0) {
829 /* NOP */
830 } else if (a == 255) {
831 for (y = h; y > 0; y--) {
832 unsigned char *d = px;
833 const unsigned char *m = mpx;
834 for (x = w; x > 0; x--) {
835 d[0] = NR_COMPOSEN11_1111 (r, m[0], d[0]);
836 d[1] = NR_COMPOSEN11_1111 (g, m[0], d[1]);
837 d[2] = NR_COMPOSEN11_1111 (b, m[0], d[2]);
838 d += 3;
839 m += 1;
840 }
841 px += rs;
842 mpx += mrs;
843 }
844 } else {
845 for (y = h; y > 0; y--) {
846 unsigned char *d = px;
847 const unsigned char *m = mpx;
848 for (x = w; x > 0; x--) {
849 // dc' = (1 - m*sa) * dc + m*sa*sc
850 unsigned int alpha;
851 alpha = NR_PREMUL_112 (a, m[0]);
852 d[0] = NR_COMPOSEN11_1211 (r, alpha, d[0]);
853 d[1] = NR_COMPOSEN11_1211 (g, alpha, d[1]);
854 d[2] = NR_COMPOSEN11_1211 (b, alpha, d[2]);
855 d += 3;
856 m += 1;
857 }
858 px += rs;
859 mpx += mrs;
860 }
861 }
862 }
864 void
865 nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *mpx, int mrs, unsigned long rgba)
866 {
867 unsigned int r, g, b, a;
868 unsigned int x, y;
870 r = NR_RGBA32_R (rgba);
871 g = NR_RGBA32_G (rgba);
872 b = NR_RGBA32_B (rgba);
873 a = NR_RGBA32_A (rgba);
875 if (a == 0) {
876 /* NOP */
877 } else if (a == 255) {
878 for (y = h; y > 0; y--) {
879 unsigned char *d = px;
880 const unsigned char *m = mpx;
881 for (x = w; x > 0; x--) {
882 if (m[0] == 0) {
883 /* Transparent FG, NOP */
884 } else if (m[0] == 255 || d[3] == 0) {
885 /* Full coverage, COPY */
886 d[0] = r;
887 d[1] = g;
888 d[2] = b;
889 d[3] = m[0];
890 } else {
891 /* Full composition */
892 unsigned int da = NR_COMPOSEA_112(m[0], d[3]);
893 d[0] = NR_COMPOSENNN_111121(r, m[0], d[0], d[3], da);
894 d[1] = NR_COMPOSENNN_111121(g, m[0], d[1], d[3], da);
895 d[2] = NR_COMPOSENNN_111121(b, m[0], d[2], d[3], da);
896 d[3] = NR_NORMALIZE_21(da);
897 }
898 d += 4;
899 m += 1;
900 }
901 px += rs;
902 mpx += mrs;
903 }
904 } else {
905 for (y = h; y > 0; y--) {
906 unsigned char *d = px;
907 const unsigned char *m = mpx;
908 for (x = w; x > 0; x--) {
909 unsigned int ca;
910 ca = NR_PREMUL_112 (m[0], a);
911 if (ca == 0) {
912 /* Transparent FG, NOP */
913 } else if (d[3] == 0) {
914 /* Full coverage, COPY */
915 d[0] = r;
916 d[1] = g;
917 d[2] = b;
918 d[3] = NR_NORMALIZE_21(ca);
919 } else {
920 /* Full composition */
921 unsigned int da = NR_COMPOSEA_213(ca, d[3]);
922 d[0] = NR_COMPOSENNN_121131(r, ca, d[0], d[3], da);
923 d[1] = NR_COMPOSENNN_121131(g, ca, d[1], d[3], da);
924 d[2] = NR_COMPOSENNN_121131(b, ca, d[2], d[3], da);
925 d[3] = NR_NORMALIZE_31(da);
926 }
927 d += 4;
928 m += 1;
929 }
930 px += rs;
931 mpx += mrs;
932 }
933 }
934 }
936 void
937 nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned long rgba)
938 {
939 unsigned int r, g, b, a;
940 unsigned int x, y;
942 r = NR_RGBA32_R (rgba);
943 g = NR_RGBA32_G (rgba);
944 b = NR_RGBA32_B (rgba);
945 a = NR_RGBA32_A (rgba);
947 #ifdef WITH_MMX
948 if (NR_PIXOPS_MMX && a != 0) {
949 unsigned char c[4];
950 c[0] = NR_PREMUL_111 (r, a);
951 c[1] = NR_PREMUL_111 (g, a);
952 c[2] = NR_PREMUL_111 (b, a);
953 c[3] = a;
954 /* WARNING: MMX composer REQUIRES w > 0 and h > 0 */
955 nr_mmx_R8G8B8A8_P_R8G8B8A8_P_A8_RGBAP (px, w, h, rs, spx, srs, c);
956 return;
957 }
958 #endif
960 if (a == 0) {
961 /* Transparent FG, NOP */
962 } else if (a == 255) {
963 /* Simple */
964 for (y = h; y > 0; y--) {
965 unsigned char *d, *s;
966 d = (unsigned char *) px;
967 s = (unsigned char *) spx;
968 for (x = w; x > 0; x--) {
969 if (s[0] == 0) {
970 /* Transparent FG, NOP */
971 } else {
972 /* Full composition */
973 unsigned int invca = 255-s[0]; // By swapping the arguments GCC can better optimize these calls
974 d[0] = NR_COMPOSENPP_1111(d[0], invca, r);
975 d[1] = NR_COMPOSENPP_1111(d[1], invca, g);
976 d[2] = NR_COMPOSENPP_1111(d[2], invca, b);
977 d[3] = NR_COMPOSEA_111(s[0], d[3]);
978 }
979 d += 4;
980 s += 1;
981 }
982 px += rs;
983 spx += srs;
984 }
985 } else {
986 for (y = h; y > 0; y--) {
987 unsigned char *d, *s;
988 d = (unsigned char *) px;
989 s = (unsigned char *) spx;
990 for (x = w; x > 0; x--) {
991 unsigned int ca;
992 ca = NR_PREMUL_112 (s[0], a);
993 if (ca == 0) {
994 /* Transparent FG, NOP */
995 } else {
996 /* Full composition */
997 unsigned int invca = 255*255-ca; // By swapping the arguments GCC can better optimize these calls
998 d[0] = NR_COMPOSENPP_1211(d[0], invca, r);
999 d[1] = NR_COMPOSENPP_1211(d[1], invca, g);
1000 d[2] = NR_COMPOSENPP_1211(d[2], invca, b);
1001 d[3] = NR_COMPOSEA_211(ca, d[3]);
1002 }
1003 d += 4;
1004 s += 1;
1005 }
1006 px += rs;
1007 spx += srs;
1008 }
1009 }
1010 }
1012 /* RGB */
1014 void
1015 nr_R8G8B8_R8G8B8_R8G8B8A8_P (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
1016 {
1017 unsigned int r, c;
1019 #ifdef WITH_MMX
1020 if (NR_PIXOPS_MMX && alpha != 0) {
1021 /* WARNING: MMX composer REQUIRES w > 0 and h > 0 */
1022 nr_mmx_R8G8B8_R8G8B8_R8G8B8A8_P (px, w, h, rs, spx, srs, alpha);
1023 return;
1024 }
1025 #endif
1027 if (alpha == 0) {
1028 /* NOP */
1029 } else if (alpha == 255) {
1030 for (r = h; r > 0; r--) {
1031 unsigned char *d = px;
1032 const unsigned char *s = spx;
1033 for (c = w; c > 0; c--) {
1034 // dc' = (1 - alpha*sa) * dc + alpha*sc = (1 - sa) * dc + sc
1035 if (s[3] == 0) {
1036 /* NOP */
1037 } else if (s[3] == 255) {
1038 d[0] = s[0];
1039 d[1] = s[1];
1040 d[2] = s[2];
1041 } else {
1042 d[0] = NR_COMPOSEP11_1111(s[0], s[3], d[0]);
1043 d[1] = NR_COMPOSEP11_1111(s[1], s[3], d[1]);
1044 d[2] = NR_COMPOSEP11_1111(s[2], s[3], d[2]);
1045 }
1046 d += 3;
1047 s += 4;
1048 }
1049 px += rs;
1050 spx += srs;
1051 }
1052 } else {
1053 for (r = h; r > 0; r--) {
1054 unsigned char *d = px;
1055 const unsigned char *s = spx;
1056 for (c = w; c > 0; c--) {
1057 unsigned int a;
1058 a = NR_PREMUL_112(s[3], alpha);
1059 // dc' = (1 - alpha*sa) * dc + alpha*sc
1060 if (a == 0) {
1061 /* NOP */
1062 } else {
1063 d[0] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[0], alpha), a, d[0]);
1064 d[1] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[1], alpha), a, d[1]);
1065 d[2] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[2], alpha), a, d[2]);
1066 }
1067 /* a == 255 is impossible, because alpha < 255 */
1068 d += 3;
1069 s += 4;
1070 }
1071 px += rs;
1072 spx += srs;
1073 }
1074 }
1075 }
1077 void
1078 nr_R8G8B8_R8G8B8_R8G8B8A8_N (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, unsigned int alpha)
1079 {
1080 unsigned int r, c;
1082 if (alpha == 0) {
1083 /* NOP */
1084 } else if (alpha == 255) {
1085 for (r = h; r > 0; r--) {
1086 unsigned char *d = px;
1087 const unsigned char *s = spx;
1088 for (c = w; c > 0; c--) {
1089 // dc' = (1 - alpha*sa) * dc + alpha*sa*sc = (1 - sa) * dc + sa*sc
1090 if (s[3] == 0) {
1091 /* NOP */
1092 } else if (s[3] == 255) {
1093 d[0] = s[0];
1094 d[1] = s[1];
1095 d[2] = s[2];
1096 } else {
1097 d[0] = NR_COMPOSEN11_1111(s[0], s[3], d[0]);
1098 d[1] = NR_COMPOSEN11_1111(s[1], s[3], d[1]);
1099 d[2] = NR_COMPOSEN11_1111(s[2], s[3], d[2]);
1100 }
1101 d += 3;
1102 s += 4;
1103 }
1104 px += rs;
1105 spx += srs;
1106 }
1107 } else {
1108 for (r = h; r > 0; r--) {
1109 unsigned char *d = px;
1110 const unsigned char *s = spx;
1111 for (c = w; c > 0; c--) {
1112 unsigned int a;
1113 a = NR_PREMUL_112(s[3], alpha);
1114 // dc' = (1 - alpha*sa) * dc + alpha*sa*sc
1115 if (a == 0) {
1116 /* NOP */
1117 } else {
1118 d[0] = NR_COMPOSEN11_1211(s[0], a, d[0]);
1119 d[1] = NR_COMPOSEN11_1211(s[1], a, d[1]);
1120 d[2] = NR_COMPOSEN11_1211(s[2], a, d[2]);
1121 }
1122 /* a == 255 is impossible, because alpha < 255 */
1123 d += 3;
1124 s += 4;
1125 }
1126 px += rs;
1127 spx += srs;
1128 }
1129 }
1130 }
1132 void
1133 nr_R8G8B8_R8G8B8_R8G8B8A8_P_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
1134 {
1135 unsigned int x, y;
1137 for (y = h; y > 0; y--) {
1138 unsigned char* d = px;
1139 const unsigned char* s = spx;
1140 const unsigned char* m = mpx;
1141 for (x = w; x > 0; x--) {
1142 unsigned int a;
1143 a = NR_PREMUL_112(s[3], m[0]);
1144 if (a == 0) {
1145 /* NOP */
1146 } else if (a == 255*255) {
1147 memcpy(d, s, 3);
1148 } else {
1149 // dc' = (1 - m*sa) * dc + m*sc
1150 d[0] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[0], m[0]), a, d[0]);
1151 d[1] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[1], m[0]), a, d[1]);
1152 d[2] = NR_COMPOSEP11_2211(NR_PREMUL_112(s[2], m[0]), a, d[2]);
1153 }
1154 d += 3;
1155 s += 4;
1156 m += 1;
1157 }
1158 px += rs;
1159 spx += srs;
1160 mpx += mrs;
1161 }
1162 }
1164 void
1165 nr_R8G8B8_R8G8B8_R8G8B8A8_N_A8 (unsigned char *px, int w, int h, int rs, const unsigned char *spx, int srs, const unsigned char *mpx, int mrs)
1166 {
1167 unsigned int x, y;
1169 for (y = h; y > 0; y--) {
1170 unsigned char* d = px;
1171 const unsigned char* s = spx;
1172 const unsigned char* m = mpx;
1173 for (x = w; x > 0; x--) {
1174 unsigned int a;
1175 a = NR_PREMUL_112(s[3], m[0]);
1176 if (a == 0) {
1177 /* NOP */
1178 } else if (a == 255*255) {
1179 memcpy(d, s, 3);
1180 } else {
1181 // dc' = (1 - m*sa) * dc + m*sa*sc
1182 d[0] = NR_COMPOSEN11_1211(s[0], a, d[0]);
1183 d[1] = NR_COMPOSEN11_1211(s[1], a, d[1]);
1184 d[2] = NR_COMPOSEN11_1211(s[2], a, d[2]);
1185 }
1186 d += 3;
1187 s += 4;
1188 m += 1;
1189 }
1190 px += rs;
1191 spx += srs;
1192 mpx += mrs;
1193 }
1194 }