comparison mupdf-source/source/fitz/draw-paint.c @ 3:2c135c81b16c

MERGE: upstream PyMuPDF 1.26.4 with MuPDF 1.26.7
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:44:09 +0200
parents b50eed0cc0ef
children
comparison
equal deleted inserted replaced
0:6015a75abc2d 3:2c135c81b16c
1 // Copyright (C) 2004-2025 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 #include "mupdf/fitz.h"
24
25 #include "draw-imp.h"
26 #include "glyph-imp.h"
27 #include "pixmap-imp.h"
28
29 #include <string.h>
30 #include <assert.h>
31
32 /*
33
34 The functions in this file implement various flavours of Porter-Duff blending.
35
36 We take the following as definitions:
37
38 Cx = Color (from plane x)
39 ax = Alpha (from plane x)
40 cx = Cx.ax = Premultiplied color (from plane x)
41
42 The general PorterDuff blending equation is:
43
44 Blend Z = X op Y cz = Fx.cx + Fy.cy where Fx and Fy depend on op
45
46 The two operations we use in this file are: '(X in Y) over Z' and
47 'S over Z'. The definitions of the 'over' and 'in' operations are as
48 follows:
49
50 For S over Z, Fs = 1, Fz = 1-as
51 For X in Y, Fx = ay, Fy = 0
52
53 We have 2 choices; we can either work with premultiplied data, or non
54 premultiplied data. Our
55
56 First the premultiplied case:
57
58 Let S = (X in Y)
59 Let R = (X in Y) over Z = S over Z
60
61 cs = cx.Fx + cy.Fy (where Fx = ay, Fy = 0)
62 = cx.ay
63 as = ax.Fx + ay.Fy
64 = ax.ay
65
66 cr = cs.Fs + cz.Fz (where Fs = 1, Fz = 1-as)
67 = cs + cz.(1-as)
68 = cx.ay + cz.(1-ax.ay)
69 ar = as.Fs + az.Fz
70 = as + az.(1-as)
71 = ax.ay + az.(1-ax.ay)
72
73 This has various nice properties, like not needing any divisions, and
74 being symmetric in color and alpha, so this is what we use. Because we
75 went through the pain of deriving the non premultiplied forms, we list
76 them here too, though they are not used.
77
78 Non Pre-multiplied case:
79
80 Cs.as = Fx.Cx.ax + Fy.Cy.ay (where Fx = ay, Fy = 0)
81 = Cx.ay.ax
82 Cs = (Cx.ay.ax)/(ay.ax)
83 = Cx
84 Cr.ar = Fs.Cs.as + Fz.Cz.az (where Fs = 1, Fz = 1-as)
85 = Cs.as + (1-as).Cz.az
86 = Cx.ax.ay + Cz.az.(1-ax.ay)
87 Cr = (Cx.ax.ay + Cz.az.(1-ax.ay))/(ax.ay + az.(1-ax.ay))
88
89 Much more complex, it seems. However, if we could restrict ourselves to
90 the case where we were always plotting onto an opaque background (i.e.
91 az = 1), then:
92
93 Cr = Cx.(ax.ay) + Cz.(1-ax.ay)
94 = (Cx-Cz)*(1-ax.ay) + Cz (a single MLA operation)
95 ar = 1
96
97 Sadly, this is not true in the general case, so we abandon this effort
98 and stick to using the premultiplied form.
99
100 */
101
102 typedef unsigned char byte;
103
104 /* These are used by the non-aa scan converter */
105
106 static fz_forceinline void
107 template_solid_color_1_da(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da)
108 {
109 int sa = FZ_EXPAND(color[1]);
110 TRACK_FN();
111 if (sa == 0)
112 return;
113 if (sa == 256)
114 {
115 do
116 {
117 dp[0] = color[0];
118 dp[1] = 255;
119 dp += 2;
120 }
121 while (--w);
122 }
123 else
124 {
125 do
126 {
127 dp[0] = FZ_BLEND(color[0], dp[0], sa);
128 dp[1] = FZ_BLEND(255, dp[1], sa);
129 dp += 2;
130 }
131 while (--w);
132 }
133 }
134
135 static inline int isbigendian(void)
136 {
137 union { int i; char c[sizeof(int)]; } u = {1};
138 return u.c[0] != 1;
139 }
140
141 static fz_forceinline void
142 template_solid_color_3_da(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da)
143 {
144 unsigned int rgba = *(int *)color;
145 int sa = FZ_EXPAND(color[3]);
146 TRACK_FN();
147 if (sa == 0)
148 return;
149 if (isbigendian())
150 rgba |= 0x000000FF;
151 else
152 rgba |= 0xFF000000;
153 if (sa == 256)
154 {
155 do
156 {
157 *(unsigned int *)dp = rgba;
158 dp += 4;
159 }
160 while (--w);
161 }
162 else
163 {
164 unsigned int mask = 0xFF00FF00;
165 unsigned int rb = rgba & (mask>>8);
166 unsigned int ga = (rgba & mask)>>8;
167 do
168 {
169 unsigned int RGBA = *(unsigned int *)dp;
170 unsigned int RB = (RGBA<<8) & mask;
171 unsigned int GA = RGBA & mask;
172 RB += (rb-(RB>>8))*sa;
173 GA += (ga-(GA>>8))*sa;
174 RB &= mask;
175 GA &= mask;
176 *(unsigned int *)dp = (RB>>8) | GA;
177 dp += 4;
178 }
179 while (--w);
180 }
181 }
182
183 static fz_forceinline void
184 template_solid_color_4_da(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da)
185 {
186 int sa = FZ_EXPAND(color[4]);
187 TRACK_FN();
188 if (sa == 0)
189 return;
190 if (sa == 256)
191 {
192 #ifdef ARCH_UNALIGNED_OK
193 if (w > 4)
194 {
195 if (isbigendian())
196 {
197 const uint32_t a = *(uint32_t*)color;
198 const uint32_t b = 0xFF000000|(a>>8);
199 const uint32_t c = 0x00FF0000|(a>>16)|(a<<24);
200 const uint32_t d = 0x0000FF00|(a>>24)|(a<<16);
201 const uint32_t e = 0x000000FF|(a<<8);
202 w -= 3;
203 do
204 {
205 ((uint32_t *)(void *)dp)[0] = a;
206 ((uint32_t *)(void *)dp)[1] = b;
207 ((uint32_t *)(void *)dp)[2] = c;
208 ((uint32_t *)(void *)dp)[3] = d;
209 ((uint32_t *)(void *)dp)[4] = e;
210 dp += 20;
211 w -= 4;
212 }
213 while (w > 0);
214 }
215 else
216 {
217 const uint32_t a = *(uint32_t*)color;
218 const uint32_t b = 0x000000FF|(a<<8);
219 const uint32_t c = 0x0000FF00|(a<<16)|(a>>24);
220 const uint32_t d = 0x00FF0000|(a<<24)|(a>>16);
221 const uint32_t e = 0xFF000000|(a>>8);
222 w -= 3;
223 do
224 {
225 ((uint32_t *)(void *)dp)[0] = a;
226 ((uint32_t *)(void *)dp)[1] = b;
227 ((uint32_t *)(void *)dp)[2] = c;
228 ((uint32_t *)(void *)dp)[3] = d;
229 ((uint32_t *)(void *)dp)[4] = e;
230 dp += 20;
231 w -= 4;
232 }
233 while (w > 0);
234 }
235 w += 3;
236 if (w == 0)
237 return;
238 }
239 #endif
240 do
241 {
242 dp[0] = color[0];
243 dp[1] = color[1];
244 dp[2] = color[2];
245 dp[3] = color[3];
246 dp[4] = 255;
247 dp += 5;
248 }
249 while (--w);
250 }
251 else
252 {
253 do
254 {
255 dp[0] = FZ_BLEND(color[0], dp[0], sa);
256 dp[1] = FZ_BLEND(color[1], dp[1], sa);
257 dp[2] = FZ_BLEND(color[2], dp[2], sa);
258 dp[3] = FZ_BLEND(color[3], dp[3], sa);
259 dp[4] = FZ_BLEND(255, dp[5], sa);
260 dp += 5;
261 }
262 while (--w);
263 }
264 }
265
266 static fz_forceinline void
267 template_solid_color_N_256(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da)
268 {
269 int k;
270 int n1 = n - da;
271 if (n == 3 && da == 0 && w >= 7)
272 {
273 union {uint32_t w[3]; byte b[12];} u;
274
275 u.b[0] = u.b[3] = u.b[6] = u.b[9] = color[0];
276 u.b[1] = u.b[4] = u.b[7] = u.b[10] = color[1];
277 u.b[2] = u.b[5] = u.b[8] = u.b[11] = color[2];
278
279 switch (((intptr_t)dp) & 3)
280 {
281 case 3:
282 *dp++ = color[0];
283 *(uint32_t *)dp = u.w[1];
284 dp += 4;
285 *(uint32_t *)dp = u.w[2];
286 dp += 4;
287 w -= 3;
288 break;
289 case 2:
290 *dp++ = color[0];
291 *dp++ = color[1];
292 *(uint32_t *)dp = u.w[2];
293 dp += 4;
294 w -= 2;
295 break;
296 case 1:
297 *dp++ = color[0];
298 *dp++ = color[1];
299 *dp++ = color[2];
300 w -= 1;
301 break;
302 }
303 w -= 4;
304 do
305 {
306 *(uint32_t *)dp = u.w[0];
307 dp += 4;
308 *(uint32_t *)dp = u.w[1];
309 dp += 4;
310 *(uint32_t *)dp = u.w[2];
311 dp += 4;
312 w -= 4;
313 }
314 while (w > 0);
315 w += 4;
316 if (w == 0)
317 return;
318 }
319 do
320 {
321 dp[0] = color[0];
322 if (n1 > 1)
323 dp[1] = color[1];
324 if (n1 > 2)
325 dp[2] = color[2];
326 for (k = 3; k < n1; k++)
327 dp[k] = color[k];
328 if (da)
329 dp[n1] = 255;
330 dp += n;
331 }
332 while (--w);
333 }
334
335 static fz_forceinline void
336 template_solid_color_N_256_op(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
337 {
338 int k;
339 int n1 = n - da;
340 do
341 {
342 if (fz_overprint_component(eop, 0))
343 dp[0] = color[0];
344 if (n1 > 1)
345 if (fz_overprint_component(eop, 1))
346 dp[1] = color[1];
347 if (n1 > 2)
348 if (fz_overprint_component(eop, 2))
349 dp[2] = color[2];
350 for (k = 3; k < n1; k++)
351 if (fz_overprint_component(eop, k))
352 dp[k] = color[k];
353 if (da)
354 dp[n1] = 255;
355 dp += n;
356 }
357 while (--w);
358 }
359
360 static fz_forceinline void
361 template_solid_color_N_sa(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, int sa)
362 {
363 int k;
364 int n1 = n - da;
365 do
366 {
367 for (k = 0; k < n1; k++)
368 dp[k] = FZ_BLEND(color[k], dp[k], sa);
369 if (da)
370 dp[k] = FZ_BLEND(255, dp[k], sa);
371 dp += n;
372 }
373 while (--w);
374 }
375
376 static fz_forceinline void
377 template_solid_color_N_sa_op(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, int sa, const fz_overprint * FZ_RESTRICT eop)
378 {
379 int k;
380 int n1 = n - da;
381 do
382 {
383 for (k = 0; k < n1; k++)
384 if (fz_overprint_component(eop, k))
385 dp[k] = FZ_BLEND(color[k], dp[k], sa);
386 if (da)
387 dp[k] = FZ_BLEND(255, dp[k], sa);
388 dp += n;
389 }
390 while (--w);
391 }
392
393 #if FZ_PLOTTERS_N
394 static fz_forceinline void
395 template_solid_color_N_general(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, int sa)
396 {
397 int k;
398 int n1 = n - da;
399 if (sa == 256)
400 {
401 do
402 {
403 dp[0] = color[0];
404 if (n1 > 1)
405 dp[1] = color[1];
406 if (n1 > 2)
407 dp[2] = color[2];
408 for (k = 3; k < n1; k++)
409 dp[k] = color[k];
410 if (da)
411 dp[n1] = 255;
412 dp += n;
413 }
414 while (--w);
415 }
416 else
417 {
418 do
419 {
420 for (k = 0; k < n1; k++)
421 dp[k] = FZ_BLEND(color[k], dp[k], sa);
422 if (da)
423 dp[k] = FZ_BLEND(255, dp[k], sa);
424 dp += n;
425 }
426 while (--w);
427 }
428 }
429
430 static fz_forceinline void
431 template_solid_color_N_general_op(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, int sa, const fz_overprint * FZ_RESTRICT eop)
432 {
433 int k;
434 int n1 = n - da;
435 if (sa == 256)
436 {
437 do
438 {
439 if (fz_overprint_component(eop, 0))
440 dp[0] = color[0];
441 if (n1 > 1)
442 if (fz_overprint_component(eop, 1))
443 dp[1] = color[1];
444 if (n1 > 2)
445 if (fz_overprint_component(eop, 2))
446 dp[2] = color[2];
447 for (k = 3; k < n1; k++)
448 if (fz_overprint_component(eop, k))
449 dp[k] = color[k];
450 if (da)
451 dp[n1] = 255;
452 dp += n;
453 }
454 while (--w);
455 }
456 else
457 {
458 do
459 {
460 for (k = 0; k < n1; k++)
461 if (fz_overprint_component(eop, k))
462 dp[k] = FZ_BLEND(color[k], dp[k], sa);
463 if (da)
464 dp[k] = FZ_BLEND(255, dp[k], sa);
465 dp += n;
466 }
467 while (--w);
468 }
469 }
470 #endif
471
472 static fz_forceinline void
473 template_solid_color_0_da(byte * FZ_RESTRICT dp, int w, int sa)
474 {
475 if (sa == 256)
476 {
477 memset(dp, 255, w);
478 }
479 else
480 {
481 do
482 {
483 *dp = FZ_BLEND(255, *dp, sa);
484 dp++;
485 }
486 while (--w);
487 }
488 }
489
490 #if FZ_PLOTTERS_G
491 static void paint_solid_color_1_alpha(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
492 {
493 TRACK_FN();
494 template_solid_color_N_sa(dp, 1, w, color, 0, FZ_EXPAND(color[1]));
495 }
496
497 static void paint_solid_color_1(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
498 {
499 TRACK_FN();
500 template_solid_color_N_256(dp, 1, w, color, 0);
501 }
502
503 static void paint_solid_color_1_da(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
504 {
505 TRACK_FN();
506 template_solid_color_1_da(dp, 2, w, color, 1);
507 }
508 #endif /* FZ_PLOTTERS_G */
509
510 static void paint_solid_color_0_da(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
511 {
512 TRACK_FN();
513 template_solid_color_0_da(dp, w, 256);
514 }
515
516 #if FZ_PLOTTERS_RGB
517 static void paint_solid_color_3_alpha(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
518 {
519 TRACK_FN();
520 template_solid_color_N_sa(dp, 3, w, color, 0, FZ_EXPAND(color[3]));
521 }
522
523 static void paint_solid_color_3(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
524 {
525 TRACK_FN();
526 template_solid_color_N_256(dp, 3, w, color, 0);
527 }
528
529 static void paint_solid_color_3_da(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
530 {
531 TRACK_FN();
532 template_solid_color_3_da(dp, 4, w, color, 1);
533 }
534 #endif /* FZ_PLOTTERS_RGB */
535
536 #if FZ_PLOTTERS_CMYK
537 static void paint_solid_color_4_alpha(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
538 {
539 TRACK_FN();
540 template_solid_color_N_sa(dp, 4, w, color, 0, FZ_EXPAND(color[4]));
541 }
542
543 static void paint_solid_color_4(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
544 {
545 TRACK_FN();
546 template_solid_color_N_256(dp, 4, w, color, 0);
547 }
548
549 static void paint_solid_color_4_da(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
550 {
551 TRACK_FN();
552 template_solid_color_4_da(dp, 5, w, color, 1);
553 }
554 #endif /* FZ_PLOTTERS_CMYK */
555
556 #if FZ_PLOTTERS_N
557 static void paint_solid_color_N_alpha(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
558 {
559 TRACK_FN();
560 template_solid_color_N_sa(dp, n, w, color, 0, FZ_EXPAND(color[n]));
561 }
562
563 static void paint_solid_color_N(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
564 {
565 TRACK_FN();
566 template_solid_color_N_256(dp, n, w, color, 0);
567 }
568
569 static void paint_solid_color_N_da(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
570 {
571 TRACK_FN();
572 template_solid_color_N_general(dp, n, w, color, 1, FZ_EXPAND(color[n-1]));
573 }
574 #endif /* FZ_PLOTTERS_N */
575
576 #if FZ_ENABLE_SPOT_RENDERING
577 static void paint_solid_color_N_alpha_op(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
578 {
579 TRACK_FN();
580 template_solid_color_N_sa_op(dp, n, w, color, 0, FZ_EXPAND(color[n]), eop);
581 }
582
583 static void paint_solid_color_N_op(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
584 {
585 TRACK_FN();
586 template_solid_color_N_256_op(dp, n, w, color, 0, eop);
587 }
588
589 static void paint_solid_color_N_da_op(byte * FZ_RESTRICT dp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
590 {
591 TRACK_FN();
592 template_solid_color_N_general_op(dp, n, w, color, 1, FZ_EXPAND(color[n-1]), eop);
593 }
594 #endif /* FZ_ENABLE_SPOT_RENDERING */
595
596 fz_solid_color_painter_t *
597 fz_get_solid_color_painter(int n, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
598 {
599 #if FZ_ENABLE_SPOT_RENDERING
600 if (fz_overprint_required(eop))
601 {
602 if (da)
603 return paint_solid_color_N_da_op;
604 else if (color[n] == 255)
605 return paint_solid_color_N_op;
606 else
607 return paint_solid_color_N_alpha_op;
608 }
609 #endif /* FZ_ENABLE_SPOT_RENDERING */
610 switch (n-da)
611 {
612 case 0:
613 return paint_solid_color_0_da;
614 #if FZ_PLOTTERS_G
615 case 1:
616 if (da)
617 return paint_solid_color_1_da;
618 else if (color[1] == 255)
619 return paint_solid_color_1;
620 else
621 return paint_solid_color_1_alpha;
622 #endif /* FZ_PLOTTERS_G */
623 #if FZ_PLOTTERS_RGB
624 case 3:
625 if (da)
626 return paint_solid_color_3_da;
627 else if (color[3] == 255)
628 return paint_solid_color_3;
629 else
630 return paint_solid_color_3_alpha;
631 #endif /* FZ_PLOTTERS_RGB */
632 #if FZ_PLOTTERS_CMYK
633 case 4:
634 if (da)
635 return paint_solid_color_4_da;
636 else if (color[4] == 255)
637 return paint_solid_color_4;
638 else
639 return paint_solid_color_4_alpha;
640 #endif /* FZ_PLOTTERS_CMYK */
641 default:
642 #if FZ_PLOTTERS_N
643 if (da)
644 return paint_solid_color_N_da;
645 else if (color[n] == 255)
646 return paint_solid_color_N;
647 else
648 return paint_solid_color_N_alpha;
649 #else
650 return NULL;
651 #endif /* FZ_PLOTTERS_N */
652 }
653 }
654
655 /* Blend a non-premultiplied color in mask over destination */
656
657 static fz_forceinline void
658 template_span_with_color_1_da_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da)
659 {
660 int g = color[0];
661 do
662 {
663 int ma = *mp++;
664 ma = FZ_EXPAND(ma);
665 if (ma == 256)
666 {
667 dp[0] = g;
668 dp[1] = 255;
669 }
670 else if (ma != 0)
671 {
672 dp[0] = FZ_BLEND(g, dp[0], ma);
673 dp[1] = FZ_BLEND(255, dp[1], ma);
674 }
675 dp += 2;
676 }
677 while (--w);
678 }
679
680 static fz_forceinline void
681 template_span_with_color_1_da_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da)
682 {
683 int sa = FZ_EXPAND(color[1]);
684 int g = color[0];
685 do
686 {
687 int ma = *mp++;
688 ma = FZ_EXPAND(ma);
689 if (ma != 0)
690 {
691 ma = FZ_COMBINE(ma, sa);
692 dp[0] = FZ_BLEND(g, dp[0], ma);
693 dp[1] = FZ_BLEND(255, dp[1], ma);
694 }
695 dp += 2;
696 }
697 while (--w);
698 }
699
700 static fz_forceinline void
701 template_span_with_color_3_da_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da)
702 {
703 unsigned int rgba = *((const unsigned int *)color);
704 unsigned int mask, rb, ga;
705 if (isbigendian())
706 rgba |= 0x000000FF;
707 else
708 rgba |= 0xFF000000;
709 mask = 0xFF00FF00;
710 rb = rgba & (mask>>8);
711 ga = (rgba & mask)>>8;
712 do
713 {
714 unsigned int ma = *mp++;
715 dp += 4;
716 ma = FZ_EXPAND(ma);
717 if (ma == 256)
718 {
719 ((unsigned int *)dp)[-1] = rgba;
720 }
721 else if (ma != 0)
722 {
723 unsigned int RGBA = ((unsigned int *)dp)[-1];
724 unsigned int RB = (RGBA<<8) & mask;
725 unsigned int GA = RGBA & mask;
726 RB += (rb-(RB>>8))*ma;
727 GA += (ga-(GA>>8))*ma;
728 RB &= mask;
729 GA &= mask;
730 ((unsigned int *)dp)[-1] = (RB>>8) | GA;
731 }
732 }
733 while (--w);
734 }
735
736 static fz_forceinline void
737 template_span_with_color_3_da_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da)
738 {
739 unsigned int rgba = *((const unsigned int *)color);
740 unsigned int mask, rb, ga;
741 int sa = FZ_EXPAND(color[3]);
742 if (isbigendian())
743 rgba |= 0x000000FF;
744 else
745 rgba |= 0xFF000000;
746 mask = 0xFF00FF00;
747 rb = rgba & (mask>>8);
748 ga = (rgba & mask)>>8;
749 do
750 {
751 unsigned int ma = *mp++;
752 ma = FZ_COMBINE(FZ_EXPAND(ma), sa);
753 dp += 4;
754 if (ma != 0)
755 {
756 unsigned int RGBA = ((unsigned int*)dp)[-1];
757 unsigned int RB = (RGBA<<8) & mask;
758 unsigned int GA = RGBA & mask;
759 RB += (rb-(RB>>8))*ma;
760 GA += (ga-(GA>>8))*ma;
761 RB &= mask;
762 GA &= mask;
763 ((unsigned int *)dp)[-1] = (RB>>8) | GA;
764 }
765 }
766 while (--w);
767 }
768
769 static fz_forceinline void
770 template_span_with_color_4_da_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da)
771 {
772 int c = color[0];
773 int m = color[1];
774 int y = color[2];
775 int k = color[3];
776 TRACK_FN();
777 do
778 {
779 int ma = *mp++;
780 ma = FZ_EXPAND(ma);
781 if (ma == 256)
782 {
783 dp[0] = c;
784 dp[1] = m;
785 dp[2] = y;
786 dp[3] = k;
787 dp[4] = 255;
788 }
789 else if (ma != 0)
790 {
791 dp[0] = FZ_BLEND(c, dp[0], ma);
792 dp[1] = FZ_BLEND(m, dp[1], ma);
793 dp[2] = FZ_BLEND(y, dp[2], ma);
794 dp[3] = FZ_BLEND(k, dp[3], ma);
795 dp[4] = FZ_BLEND(255, dp[4], ma);
796 }
797 dp += 5;
798 }
799 while (--w);
800 }
801
802 static fz_forceinline void
803 template_span_with_color_4_da_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da)
804 {
805 int sa = FZ_EXPAND(color[4]);
806 int c = color[0];
807 int m = color[1];
808 int y = color[2];
809 int k = color[3];
810 TRACK_FN();
811 do
812 {
813 int ma = *mp++;
814 ma = FZ_EXPAND(ma);
815 if (ma != 0)
816 {
817 ma = FZ_COMBINE(ma, sa);
818 dp[0] = FZ_BLEND(c, dp[0], ma);
819 dp[1] = FZ_BLEND(m, dp[1], ma);
820 dp[2] = FZ_BLEND(y, dp[2], ma);
821 dp[3] = FZ_BLEND(k, dp[3], ma);
822 dp[4] = FZ_BLEND(255, dp[4], ma);
823 }
824 dp += 5;
825 }
826 while (--w);
827 }
828
829 static fz_forceinline void
830 template_span_with_color_N_general_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da)
831 {
832 int k;
833 int n1 = n - da;
834 do
835 {
836 int ma = *mp++;
837 ma = FZ_EXPAND(ma);
838 if (ma == 256)
839 {
840 if (n1 > 0)
841 dp[0] = color[0];
842 if (n1 > 1)
843 dp[1] = color[1];
844 if (n1 > 2)
845 dp[2] = color[2];
846 for (k = 3; k < n1; k++)
847 dp[k] = color[k];
848 if (da)
849 dp[n1] = 255;
850 }
851 else if (ma != 0)
852 {
853 if (n1 > 0)
854 dp[0] = FZ_BLEND(color[0], dp[0], ma);
855 if (n1 > 1)
856 dp[1] = FZ_BLEND(color[1], dp[1], ma);
857 if (n1 > 2)
858 dp[2] = FZ_BLEND(color[2], dp[2], ma);
859 for (k = 3; k < n1; k++)
860 dp[k] = FZ_BLEND(color[k], dp[k], ma);
861 if (da)
862 dp[n1] = FZ_BLEND(255, dp[n1], ma);
863 }
864 dp += n;
865 }
866 while (--w);
867 }
868
869 static fz_forceinline void
870 template_span_with_color_N_general_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da)
871 {
872 int k;
873 int n1 = n - da;
874 int sa = FZ_EXPAND(color[n1]);
875 do
876 {
877 int ma = *mp++;
878 ma = FZ_COMBINE(FZ_EXPAND(ma), sa);
879 if (n1 > 0)
880 dp[0] = FZ_BLEND(color[0], dp[0], ma);
881 if (n1 > 1)
882 dp[1] = FZ_BLEND(color[1], dp[1], ma);
883 if (n1 > 2)
884 dp[2] = FZ_BLEND(color[2], dp[2], ma);
885 for (k = 3; k < n1; k++)
886 dp[k] = FZ_BLEND(color[k], dp[k], ma);
887 if (da)
888 dp[n1] = FZ_BLEND(255, dp[n1], ma);
889 dp += n;
890 }
891 while (--w);
892 }
893
894 static fz_forceinline void
895 template_span_with_color_N_general_op_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
896 {
897 int k;
898 int n1 = n - da;
899 do
900 {
901 int ma = *mp++;
902 ma = FZ_EXPAND(ma);
903 if (ma == 256)
904 {
905 if (n1 > 0)
906 if (fz_overprint_component(eop, 0))
907 dp[0] = color[0];
908 if (n1 > 1)
909 if (fz_overprint_component(eop, 1))
910 dp[1] = color[1];
911 if (n1 > 2)
912 if (fz_overprint_component(eop, 2))
913 dp[2] = color[2];
914 for (k = 3; k < n1; k++)
915 if (fz_overprint_component(eop, k))
916 dp[k] = color[k];
917 if (da)
918 dp[n1] = 255;
919 }
920 else if (ma != 0)
921 {
922 for (k = 0; k < n1; k++)
923 if (fz_overprint_component(eop, k))
924 dp[k] = FZ_BLEND(color[k], dp[k], ma);
925 if (da)
926 dp[n1] = FZ_BLEND(255, dp[k], ma);
927 }
928 dp += n;
929 }
930 while (--w);
931 }
932
933 static fz_forceinline void
934 template_span_with_color_N_general_op_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
935 {
936 int k;
937 int n1 = n - da;
938 int sa = FZ_EXPAND(color[n1]);
939 do
940 {
941 int ma = *mp++;
942 ma = FZ_COMBINE(FZ_EXPAND(ma), sa);
943 for (k = 0; k < n1; k++)
944 if (fz_overprint_component(eop, k))
945 dp[k] = FZ_BLEND(color[k], dp[k], ma);
946 if (da)
947 dp[k] = FZ_BLEND(255, dp[k], ma);
948 dp += n;
949 }
950 while (--w);
951 }
952
953 static void
954 paint_span_with_color_0_da_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
955 {
956 TRACK_FN();
957 template_span_with_color_N_general_solid(dp, mp, 1, w, color, 1);
958 }
959
960 static void
961 paint_span_with_color_0_da_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
962 {
963 TRACK_FN();
964 template_span_with_color_N_general_alpha(dp, mp, 1, w, color, 1);
965 }
966
967 static void
968 paint_span_with_color_1_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
969 {
970 TRACK_FN();
971 template_span_with_color_N_general_solid(dp, mp, 1, w, color, 0);
972 }
973
974 static void
975 paint_span_with_color_1_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
976 {
977 TRACK_FN();
978 template_span_with_color_N_general_alpha(dp, mp, 1, w, color, 0);
979 }
980
981 static void
982 paint_span_with_color_1_da_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
983 {
984 TRACK_FN();
985 template_span_with_color_1_da_solid(dp, mp, 2, w, color, 1);
986 }
987
988 static void
989 paint_span_with_color_1_da_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
990 {
991 TRACK_FN();
992 template_span_with_color_1_da_alpha(dp, mp, 2, w, color, 1);
993 }
994
995 #if FZ_PLOTTERS_RGB
996 static void
997 paint_span_with_color_3_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
998 {
999 TRACK_FN();
1000 template_span_with_color_N_general_solid(dp, mp, 3, w, color, 0);
1001 }
1002
1003 static void
1004 paint_span_with_color_3_da_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1005 {
1006 TRACK_FN();
1007 template_span_with_color_3_da_solid(dp, mp, 4, w, color, 1);
1008 }
1009
1010 static void
1011 paint_span_with_color_3_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1012 {
1013 TRACK_FN();
1014 template_span_with_color_N_general_alpha(dp, mp, 3, w, color, 0);
1015 }
1016
1017 static void
1018 paint_span_with_color_3_da_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1019 {
1020 TRACK_FN();
1021 template_span_with_color_3_da_alpha(dp, mp, 4, w, color, 1);
1022 }
1023 #endif /* FZ_PLOTTERS_RGB */
1024
1025 #if FZ_PLOTTERS_CMYK
1026 static void
1027 paint_span_with_color_4_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1028 {
1029 TRACK_FN();
1030 template_span_with_color_N_general_solid(dp, mp, 4, w, color, 0);
1031 }
1032
1033 static void
1034 paint_span_with_color_4_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1035 {
1036 TRACK_FN();
1037 template_span_with_color_N_general_alpha(dp, mp, 4, w, color, 0);
1038 }
1039
1040 static void
1041 paint_span_with_color_4_da_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1042 {
1043 TRACK_FN();
1044 template_span_with_color_4_da_solid(dp, mp, 5, w, color, 1);
1045 }
1046
1047 static void
1048 paint_span_with_color_4_da_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1049 {
1050 TRACK_FN();
1051 template_span_with_color_4_da_alpha(dp, mp, 5, w, color, 1);
1052 }
1053 #endif /* FZ_PLOTTERS_CMYK */
1054
1055 #if FZ_PLOTTERS_N
1056 static void
1057 paint_span_with_color_N_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1058 {
1059 TRACK_FN();
1060 template_span_with_color_N_general_solid(dp, mp, n, w, color, 0);
1061 }
1062
1063 static void
1064 paint_span_with_color_N_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1065 {
1066 TRACK_FN();
1067 template_span_with_color_N_general_alpha(dp, mp, n, w, color, 0);
1068 }
1069
1070 static void
1071 paint_span_with_color_N_da_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1072 {
1073 TRACK_FN();
1074 template_span_with_color_N_general_solid(dp, mp, n, w, color, 1);
1075 }
1076
1077 static void
1078 paint_span_with_color_N_da_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1079 {
1080 TRACK_FN();
1081 template_span_with_color_N_general_alpha(dp, mp, n, w, color, 1);
1082 }
1083 #endif /* FZ_PLOTTERS_N */
1084
1085 #if FZ_ENABLE_SPOT_RENDERING
1086 static void
1087 paint_span_with_color_N_op_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1088 {
1089 TRACK_FN();
1090 template_span_with_color_N_general_op_solid(dp, mp, n, w, color, 0, eop);
1091 }
1092
1093 static void
1094 paint_span_with_color_N_op_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1095 {
1096 TRACK_FN();
1097 template_span_with_color_N_general_op_alpha(dp, mp, n, w, color, 0, eop);
1098 }
1099
1100 static void
1101 paint_span_with_color_N_da_op_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1102 {
1103 TRACK_FN();
1104 template_span_with_color_N_general_op_solid(dp, mp, n, w, color, 1, eop);
1105 }
1106
1107 static void
1108 paint_span_with_color_N_da_op_alpha(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT mp, int n, int w, const byte * FZ_RESTRICT color, int da, const fz_overprint * FZ_RESTRICT eop)
1109 {
1110 TRACK_FN();
1111 template_span_with_color_N_general_op_alpha(dp, mp, n, w, color, 1, eop);
1112 }
1113 #endif /* FZ_ENABLE_SPOT_RENDERING */
1114
1115 fz_span_color_painter_t *
1116 fz_get_span_color_painter(int n, int da, const byte * FZ_RESTRICT color, const fz_overprint * FZ_RESTRICT eop)
1117 {
1118 byte alpha = color[n-da];
1119 if (alpha == 0)
1120 return NULL;
1121 #if FZ_ENABLE_SPOT_RENDERING
1122 if (fz_overprint_required(eop))
1123 {
1124 if (alpha == 255)
1125 return da ? paint_span_with_color_N_da_op_solid : paint_span_with_color_N_op_solid;
1126 else
1127 return da ? paint_span_with_color_N_da_op_alpha : paint_span_with_color_N_op_alpha;
1128 }
1129 #endif /* FZ_ENABLE_SPOT_RENDERING */
1130 switch(n-da)
1131 {
1132 case 0:
1133 if (alpha == 255)
1134 return da ? paint_span_with_color_0_da_solid : NULL;
1135 else
1136 return da ? paint_span_with_color_0_da_alpha : NULL;
1137 case 1:
1138 if (alpha == 255)
1139 return da ? paint_span_with_color_1_da_solid : paint_span_with_color_1_solid;
1140 else
1141 return da ? paint_span_with_color_1_da_alpha : paint_span_with_color_1_alpha;
1142 #if FZ_PLOTTERS_RGB
1143 case 3:
1144 if (alpha == 255)
1145 return da ? paint_span_with_color_3_da_solid : paint_span_with_color_3_solid;
1146 else
1147 return da ? paint_span_with_color_3_da_alpha : paint_span_with_color_3_alpha;
1148 #endif/* FZ_PLOTTERS_RGB */
1149 #if FZ_PLOTTERS_CMYK
1150 case 4:
1151 if (alpha == 255)
1152 return da ? paint_span_with_color_4_da_solid : paint_span_with_color_4_solid;
1153 else
1154 return da ? paint_span_with_color_4_da_alpha : paint_span_with_color_4_alpha;
1155 #endif/* FZ_PLOTTERS_CMYK */
1156 #if FZ_PLOTTERS_N
1157 default:
1158 if (alpha == 255)
1159 return da ? paint_span_with_color_N_da_solid : paint_span_with_color_N_solid;
1160 else
1161 return da ? paint_span_with_color_N_da_alpha : paint_span_with_color_N_alpha;
1162 #else
1163 default: return NULL;
1164 #endif /* FZ_PLOTTERS_N */
1165 }
1166 }
1167
1168 /* Blend source in mask over destination */
1169
1170 /* FIXME: There is potential for SWAR optimisation here */
1171 static fz_forceinline void
1172 template_span_with_mask_1_general(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, int a, const byte * FZ_RESTRICT mp, int w)
1173 {
1174 do
1175 {
1176 int ma = *mp++;
1177 ma = FZ_EXPAND(ma);
1178 if (ma == 0 || (a && sp[1] == 0))
1179 {
1180 dp += 1 + a;
1181 sp += 1 + a;
1182 }
1183 else if (ma == 256)
1184 {
1185 *dp++ = *sp++;
1186 if (a)
1187 *dp++ = *sp++;
1188 }
1189 else
1190 {
1191 *dp = FZ_BLEND(*sp, *dp, ma);
1192 sp++; dp++;
1193 if (a)
1194 {
1195 *dp = FZ_BLEND(*sp, *dp, ma);
1196 sp++; dp++;
1197 }
1198 }
1199 }
1200 while (--w);
1201 }
1202
1203 static fz_forceinline void
1204 template_span_with_mask_3_general(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, int a, const byte * FZ_RESTRICT mp, int w)
1205 {
1206 do
1207 {
1208 int ma = *mp++;
1209 ma = FZ_EXPAND(ma);
1210 if (ma == 0 || (a && sp[3] == 0))
1211 {
1212 dp += 3 + a;
1213 sp += 3 + a;
1214 }
1215 else if (ma == 256)
1216 {
1217 if (a)
1218 {
1219 *(int32_t *)dp = *(int32_t *)sp;
1220 sp += 4; dp += 4;
1221 }
1222 else
1223 {
1224 *dp++ = *sp++;
1225 *dp++ = *sp++;
1226 *dp++ = *sp++;
1227 }
1228 }
1229 else if (a)
1230 {
1231 const uint32_t mask = 0x00ff00ff;
1232 uint32_t d0 = *(uint32_t *)dp;
1233 uint32_t d1 = d0>>8;
1234 uint32_t s0 = *(uint32_t *)sp;
1235 uint32_t s1 = s0>>8;
1236 d0 &= mask;
1237 d1 &= mask;
1238 s0 &= mask;
1239 s1 &= mask;
1240 d0 = (((d0<<8) + (s0-d0)*ma)>>8) & mask;
1241 d1 = ((d1<<8) + (s1-d1)*ma) & ~mask;
1242 d0 |= d1;
1243
1244 #ifndef NDEBUG
1245 if (isbigendian())
1246 {
1247 assert((d0 & 0xff) >= (d0>>24));
1248 assert((d0 & 0xff) >= ((d0>>16) & 0xff));
1249 assert((d0 & 0xff) >= ((d0>>8) & 0xff));
1250 }
1251 else
1252 {
1253 assert((d0>>24) >= (d0 & 0xff));
1254 assert((d0>>24) >= ((d0>>8) & 0xff));
1255 assert((d0>>24) >= ((d0>>16) & 0xff));
1256 }
1257 #endif
1258
1259 *(uint32_t *)dp = d0;
1260 sp += 4;
1261 dp += 4;
1262 }
1263 else
1264 {
1265 *dp = FZ_BLEND(*sp, *dp, ma);
1266 sp++; dp++;
1267 *dp = FZ_BLEND(*sp, *dp, ma);
1268 sp++; dp++;
1269 *dp = FZ_BLEND(*sp, *dp, ma);
1270 sp++; dp++;
1271 }
1272 }
1273 while (--w);
1274 }
1275
1276 static fz_forceinline void
1277 template_span_with_mask_4_general(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, int a, const byte * FZ_RESTRICT mp, int w)
1278 {
1279 do
1280 {
1281 int ma = *mp++;
1282 ma = FZ_EXPAND(ma);
1283 if (ma == 0 || (a && sp[4] == 0))
1284 {
1285 dp += 4 + a;
1286 sp += 4 + a;
1287 }
1288 else if (ma == 256)
1289 {
1290 if (!a)
1291 {
1292 *(uint32_t *)dp = *(uint32_t *)sp;
1293 dp += 4;
1294 sp += 4;
1295 }
1296 else
1297 {
1298 *dp++ = *sp++;
1299 *dp++ = *sp++;
1300 *dp++ = *sp++;
1301 *dp++ = *sp++;
1302 *dp++ = *sp++;
1303 }
1304 }
1305 else if (a)
1306 {
1307 *dp = FZ_BLEND(*sp, *dp, ma);
1308 sp++; dp++;
1309 *dp = FZ_BLEND(*sp, *dp, ma);
1310 sp++; dp++;
1311 *dp = FZ_BLEND(*sp, *dp, ma);
1312 sp++; dp++;
1313 *dp = FZ_BLEND(*sp, *dp, ma);
1314 sp++; dp++;
1315 *dp = FZ_BLEND(*sp, *dp, ma);
1316 sp++; dp++;
1317 }
1318 else
1319 {
1320 const uint32_t mask = 0x00ff00ff;
1321 uint32_t d0 = *(uint32_t *)dp;
1322 uint32_t d1 = d0>>8;
1323 uint32_t s0 = *(uint32_t *)sp;
1324 uint32_t s1 = s0>>8;
1325 sp += 4;
1326 d0 &= mask;
1327 d1 &= mask;
1328 s0 &= mask;
1329 s1 &= mask;
1330 d0 = (((d0<<8) + (s0-d0)*ma)>>8) & mask;
1331 d1 = ((d1<<8) + (s1-d1)*ma) & ~mask;
1332 d0 |= d1;
1333 *(uint32_t *)dp = d0;
1334 dp += 4;
1335 }
1336 }
1337 while (--w);
1338 }
1339
1340 static fz_forceinline void
1341 template_span_with_mask_N_general(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, int a, const byte * FZ_RESTRICT mp, int n, int w)
1342 {
1343 do
1344 {
1345 int ma = *mp++;
1346 ma = FZ_EXPAND(ma);
1347 if (ma == 0 || (a && sp[n] == 0))
1348 {
1349 dp += n + a;
1350 sp += n + a;
1351 }
1352 else if (ma == 256)
1353 {
1354 int k;
1355 for (k = 0; k < n; k++)
1356 *dp++ = *sp++;
1357 if (a)
1358 *dp++ = *sp++;
1359 }
1360 else
1361 {
1362 int k;
1363 for (k = 0; k < n; k++)
1364 {
1365 *dp = FZ_BLEND(*sp, *dp, ma);
1366 sp++; dp++;
1367 }
1368 if (a)
1369 {
1370 *dp = FZ_BLEND(*sp, *dp, ma);
1371 sp++; dp++;
1372 }
1373 }
1374 }
1375 while (--w);
1376 }
1377
1378 static void
1379 paint_span_with_mask_0_a(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, const byte * FZ_RESTRICT mp, int w, int n, int a, const fz_overprint * FZ_RESTRICT eop)
1380 {
1381 TRACK_FN();
1382 template_span_with_mask_N_general(dp, sp, 1, mp, 0, w);
1383 }
1384
1385 static void
1386 paint_span_with_mask_1_a(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, const byte * FZ_RESTRICT mp, int w, int n, int a, const fz_overprint * FZ_RESTRICT eop)
1387 {
1388 TRACK_FN();
1389 template_span_with_mask_1_general(dp, sp, 1, mp, w);
1390 }
1391
1392 static void
1393 paint_span_with_mask_1(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, const byte * FZ_RESTRICT mp, int w, int n, int a, const fz_overprint * FZ_RESTRICT eop)
1394 {
1395 TRACK_FN();
1396 template_span_with_mask_1_general(dp, sp, 0, mp, w);
1397 }
1398
1399 #if FZ_PLOTTERS_RGB
1400 static void
1401 paint_span_with_mask_3_a(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, const byte * FZ_RESTRICT mp, int w, int n, int a, const fz_overprint * FZ_RESTRICT eop)
1402 {
1403 TRACK_FN();
1404 template_span_with_mask_3_general(dp, sp, 1, mp, w);
1405 }
1406
1407 static void
1408 paint_span_with_mask_3(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, const byte * FZ_RESTRICT mp, int w, int n, int a, const fz_overprint * FZ_RESTRICT eop)
1409 {
1410 TRACK_FN();
1411 template_span_with_mask_3_general(dp, sp, 0, mp, w);
1412 }
1413 #endif /* FZ_PLOTTERS_RGB */
1414
1415 #if FZ_PLOTTERS_CMYK
1416 static void
1417 paint_span_with_mask_4_a(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, const byte * FZ_RESTRICT mp, int w, int n, int a, const fz_overprint * FZ_RESTRICT eop)
1418 {
1419 TRACK_FN();
1420 template_span_with_mask_4_general(dp, sp, 1, mp, w);
1421 }
1422
1423 static void
1424 paint_span_with_mask_4(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, const byte * FZ_RESTRICT mp, int w, int n, int a, const fz_overprint * FZ_RESTRICT eop)
1425 {
1426 TRACK_FN();
1427 template_span_with_mask_4_general(dp, sp, 0, mp, w);
1428 }
1429 #endif /* FZ_PLOTTERS_CMYK */
1430
1431 #if FZ_PLOTTERS_N
1432 static void
1433 paint_span_with_mask_N_a(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, const byte * FZ_RESTRICT mp, int w, int n, int a, const fz_overprint * FZ_RESTRICT eop)
1434 {
1435 TRACK_FN();
1436 template_span_with_mask_N_general(dp, sp, 1, mp, n, w);
1437 }
1438
1439 static void
1440 paint_span_with_mask_N(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, const byte * FZ_RESTRICT mp, int w, int n, int a, const fz_overprint * FZ_RESTRICT eop)
1441 {
1442 TRACK_FN();
1443 template_span_with_mask_N_general(dp, sp, 0, mp, n, w);
1444 }
1445 #endif /* FZ_PLOTTERS_N */
1446
1447 typedef void (fz_span_mask_painter_t)(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, const byte * FZ_RESTRICT mp, int w, int n, int a, const fz_overprint * FZ_RESTRICT eop);
1448
1449 static fz_span_mask_painter_t *
1450 fz_get_span_mask_painter(int a, int n)
1451 {
1452 switch(n)
1453 {
1454 case 0:
1455 /* assert(a); */
1456 return paint_span_with_mask_0_a;
1457 case 1:
1458 if (a)
1459 return paint_span_with_mask_1_a;
1460 else
1461 return paint_span_with_mask_1;
1462 #if FZ_PLOTTERS_RGB
1463 case 3:
1464 if (a)
1465 return paint_span_with_mask_3_a;
1466 else
1467 return paint_span_with_mask_3;
1468 #endif /* FZ_PLOTTERS_RGB */
1469 #if FZ_PLOTTERS_CMYK
1470 case 4:
1471 if (a)
1472 return paint_span_with_mask_4_a;
1473 else
1474 return paint_span_with_mask_4;
1475 #endif /* FZ_PLOTTERS_CMYK */
1476 default:
1477 {
1478 #if FZ_PLOTTERS_N
1479 if (a)
1480 return paint_span_with_mask_N_a;
1481 else
1482 return paint_span_with_mask_N;
1483 #else
1484 return NULL;
1485 #endif /* FZ_PLOTTERS_N */
1486 }
1487 }
1488 }
1489
1490 /* Blend source in constant alpha over destination */
1491
1492 static fz_forceinline void
1493 template_span_1_with_alpha_general(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int w, int alpha)
1494 {
1495 if (sa)
1496 alpha = FZ_EXPAND(alpha);
1497 do
1498 {
1499 int masa = (sa ? FZ_COMBINE(sp[1], alpha) : alpha);
1500 int t = FZ_EXPAND(255-masa);
1501 *dp = FZ_COMBINE(*sp, alpha) + FZ_COMBINE(*dp, t);
1502 dp++; sp++;
1503 if (da)
1504 {
1505 *dp = masa + FZ_COMBINE(*dp, t);
1506 dp++;
1507 }
1508 if (sa)
1509 sp++;
1510 }
1511 while (--w);
1512 }
1513
1514 static fz_forceinline void
1515 template_span_3_with_alpha_general(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int w, int alpha)
1516 {
1517 if (sa)
1518 alpha = FZ_EXPAND(alpha);
1519 do
1520 {
1521 int masa = (sa ? FZ_COMBINE(sp[3], alpha) : alpha);
1522 int t = FZ_EXPAND(255-masa);
1523 *dp = FZ_COMBINE(*sp, alpha) + FZ_COMBINE(*dp, t);
1524 sp++; dp++;
1525 *dp = FZ_COMBINE(*sp, alpha) + FZ_COMBINE(*dp, t);
1526 sp++; dp++;
1527 *dp = FZ_COMBINE(*sp, alpha) + FZ_COMBINE(*dp, t);
1528 sp++; dp++;
1529 if (da)
1530 {
1531 *dp = masa + FZ_COMBINE(*dp, t);
1532 dp++;
1533 }
1534 if (sa)
1535 sp++;
1536 }
1537 while (--w);
1538 }
1539
1540 static fz_forceinline void
1541 template_span_4_with_alpha_general(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int w, int alpha)
1542 {
1543 if (sa)
1544 alpha = FZ_EXPAND(alpha);
1545 do
1546 {
1547 int masa = (sa ? FZ_COMBINE(sp[4], alpha) : alpha);
1548 int t = FZ_EXPAND(255-masa);
1549 *dp = FZ_COMBINE(*sp, alpha) + FZ_COMBINE(*dp, t);
1550 sp++; dp++;
1551 *dp = FZ_COMBINE(*sp, alpha) + FZ_COMBINE(*dp, t);
1552 sp++; dp++;
1553 *dp = FZ_COMBINE(*sp, alpha) + FZ_COMBINE(*dp, t);
1554 sp++; dp++;
1555 *dp = FZ_COMBINE(*sp, alpha) + FZ_COMBINE(*dp, t);
1556 sp++; dp++;
1557 if (da)
1558 {
1559 *dp = masa + FZ_COMBINE(*dp, t);
1560 dp++;
1561 }
1562 if (sa)
1563 sp++;
1564 }
1565 while (--w);
1566 }
1567
1568 #if FZ_PLOTTERS_N
1569 static fz_forceinline void
1570 template_span_N_with_alpha_general(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n1, int w, int alpha)
1571 {
1572 if (sa)
1573 alpha = FZ_EXPAND(alpha);
1574 do
1575 {
1576 int masa = (sa ? FZ_COMBINE(sp[n1], alpha) : alpha);
1577 int t = FZ_EXPAND(255-masa);
1578 int k;
1579 for (k = 0; k < n1; k++)
1580 {
1581 *dp = FZ_COMBINE(*sp, alpha) + FZ_COMBINE(*dp, t);
1582 sp++; dp++;
1583 }
1584 if (da)
1585 {
1586 *dp = masa + FZ_COMBINE(*dp, t);
1587 dp++;
1588 }
1589 if (sa)
1590 sp++;
1591 }
1592 while (--w);
1593 }
1594
1595 static fz_forceinline void
1596 template_span_N_with_alpha_general_op(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n1, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1597 {
1598 if (sa)
1599 alpha = FZ_EXPAND(alpha);
1600 do
1601 {
1602 int masa = (sa ? FZ_COMBINE(sp[n1], alpha) : alpha);
1603 int t = FZ_EXPAND(255-masa);
1604 int k;
1605 for (k = 0; k < n1; k++)
1606 {
1607 if (fz_overprint_component(eop, k))
1608 *dp = FZ_COMBINE(*sp, alpha) + FZ_COMBINE(*dp, t);
1609 sp++;
1610 dp++;
1611 }
1612 if (da)
1613 {
1614 *dp = masa + FZ_COMBINE(*dp, t);
1615 dp++;
1616 }
1617 if (sa)
1618 sp++;
1619 }
1620 while (--w);
1621 }
1622 #endif
1623
1624 /* Blend source over destination */
1625
1626 static fz_forceinline void
1627 template_span_1_general(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int w)
1628 {
1629 do
1630 {
1631 int t = (sa ? FZ_EXPAND(sp[1]): 256);
1632 if (t == 0)
1633 {
1634 dp += 1 + da; sp += 1 + sa;
1635 }
1636 else
1637 {
1638 t = 256 - t;
1639 if (t == 0)
1640 {
1641 *dp++ = *sp++;
1642 if (da)
1643 *dp++ = (sa ? *sp : 255);
1644 if (sa)
1645 sp++;
1646 }
1647 else
1648 {
1649 *dp = *sp + FZ_COMBINE(*dp, t);
1650 sp++;
1651 dp++;
1652 if (da)
1653 {
1654 *dp = *sp + FZ_COMBINE(*dp, t);
1655 dp++;
1656 }
1657 sp++;
1658 }
1659 }
1660 }
1661 while (--w);
1662 }
1663
1664 static fz_forceinline void
1665 template_span_3_general(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int w)
1666 {
1667 do
1668 {
1669 int t = (sa ? FZ_EXPAND(sp[3]) : 256);
1670 if (t == 0)
1671 {
1672 dp += 3 + da; sp += 3 + sa;
1673 }
1674 else
1675 {
1676 t = 256 - t;
1677 if (t == 0)
1678 {
1679 if (da && sa)
1680 *(int32_t *)dp = *(const int32_t *)sp;
1681 else
1682 {
1683 dp[0] = sp[0];
1684 dp[1] = sp[1];
1685 dp[2] = sp[2];
1686 if (da)
1687 dp[3] = 255;
1688 }
1689 dp += 3+da; sp += 3+sa;
1690 }
1691 else
1692 {
1693 /* sa != 0 as t != 0 */
1694 *dp = *sp++ + FZ_COMBINE(*dp, t);
1695 dp++;
1696 *dp = *sp++ + FZ_COMBINE(*dp, t);
1697 dp++;
1698 *dp = *sp++ + FZ_COMBINE(*dp, t);
1699 dp++;
1700 if (da)
1701 {
1702 *dp = *sp + FZ_COMBINE(*dp, t);
1703 dp++;
1704 }
1705 sp++;
1706 }
1707 }
1708 }
1709 while (--w);
1710 }
1711
1712 static fz_forceinline void
1713 template_span_4_general(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int w)
1714 {
1715 do
1716 {
1717 int t = (sa ? FZ_EXPAND(sp[4]) : 256);
1718 if (t == 0)
1719 {
1720 dp += 4+da; sp += 4+sa;
1721 }
1722 else
1723 {
1724 t = 256 - t;
1725 if (t == 0)
1726 {
1727 dp[0] = sp[0];
1728 dp[1] = sp[1];
1729 dp[2] = sp[2];
1730 dp[3] = sp[3];
1731 if (da)
1732 dp[4] = (sa ? sp[4] : 255);
1733 dp += 4+da; sp += 4 + sa;
1734 }
1735 else
1736 {
1737 /* sa != 0 as t != 0 */
1738 *dp = *sp++ + FZ_COMBINE(*dp, t);
1739 dp++;
1740 *dp = *sp++ + FZ_COMBINE(*dp, t);
1741 dp++;
1742 *dp = *sp++ + FZ_COMBINE(*dp, t);
1743 dp++;
1744 *dp = *sp++ + FZ_COMBINE(*dp, t);
1745 dp++;
1746 if (da)
1747 {
1748 *dp = *sp + FZ_COMBINE(*dp, t);
1749 dp++;
1750 }
1751 sp++;
1752 }
1753 }
1754 }
1755 while (--w);
1756 }
1757
1758 #if FZ_PLOTTERS_N
1759 static fz_forceinline void
1760 template_span_N_general(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n1, int w)
1761 {
1762 do
1763 {
1764 int t = (sa ? FZ_EXPAND(sp[n1]) : 256);
1765 if (t == 0)
1766 {
1767 dp += n1 + da; sp += n1 + sa;
1768 }
1769 else
1770 {
1771 t = 256 - t;
1772 if (t == 0)
1773 {
1774 int k;
1775 for (k = 0; k < n1; k++)
1776 *dp++ = *sp++;
1777 if (da)
1778 *dp++ = (sa ? *sp : 255);
1779 if (sa)
1780 sp++;
1781 }
1782 else
1783 {
1784 /* sa != 0, as t != 0 */
1785 int k;
1786 for (k = 0; k < n1; k++)
1787 {
1788 *dp = *sp + FZ_COMBINE(*dp, t);
1789 sp++;
1790 dp++;
1791 }
1792 if (da)
1793 {
1794 *dp = *sp + FZ_COMBINE(*dp, t);
1795 dp++;
1796 }
1797 sp++;
1798 }
1799 }
1800 }
1801 while (--w);
1802 }
1803
1804 static fz_forceinline void
1805 template_span_N_general_op(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n1, int w, const fz_overprint * FZ_RESTRICT eop)
1806 {
1807 do
1808 {
1809 int t = (sa ? FZ_EXPAND(sp[n1]) : 256);
1810 if (t == 0)
1811 {
1812 dp += n1 + da; sp += n1 + sa;
1813 }
1814 else
1815 {
1816 t = 256 - t;
1817 if (t == 0)
1818 {
1819 int k;
1820 for (k = 0; k < n1; k++)
1821 {
1822 if (fz_overprint_component(eop, k))
1823 *dp = *sp;
1824 dp++;
1825 sp++;
1826 }
1827 if (da)
1828 *dp++ = (sa ? *sp : 255);
1829 if (sa)
1830 sp++;
1831 }
1832 else
1833 {
1834 int k;
1835 /* sa can never be 0 here, as t != 0. */
1836 for (k = 0; k < n1; k++)
1837 {
1838 if (fz_overprint_component(eop, k))
1839 *dp = *sp + FZ_COMBINE(*dp, t);
1840 sp++;
1841 dp++;
1842 }
1843 if (da)
1844 {
1845 *dp = *sp + FZ_COMBINE(*dp, t);
1846 dp++;
1847 }
1848 sp++;
1849 }
1850 }
1851 }
1852 while (--w);
1853 }
1854 #endif
1855
1856 static void
1857 paint_span_0_da_sa(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1858 {
1859 TRACK_FN();
1860 do
1861 {
1862 int s = *sp++;
1863 int t = FZ_EXPAND(255 - s);
1864 *dp = s + FZ_COMBINE(*dp, t);
1865 dp ++;
1866 }
1867 while (--w);
1868 }
1869
1870 static void
1871 paint_span_0_da_sa_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1872 {
1873 TRACK_FN();
1874 alpha = FZ_EXPAND(alpha);
1875 do
1876 {
1877 int masa = FZ_COMBINE(sp[0], alpha);
1878 int t = FZ_EXPAND(255-masa);
1879 *dp = masa + FZ_COMBINE(*dp, t);
1880 dp++;
1881 sp++;
1882 }
1883 while (--w);
1884 }
1885
1886 static void
1887 paint_span_1_sa(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1888 {
1889 TRACK_FN();
1890 template_span_1_general(dp, 0, sp, 1, w);
1891 }
1892
1893 static void
1894 paint_span_1_sa_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1895 {
1896 TRACK_FN();
1897 template_span_1_with_alpha_general(dp, 0, sp, 1, w, alpha);
1898 }
1899
1900 static void
1901 paint_span_1_da_sa(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1902 {
1903 TRACK_FN();
1904 template_span_1_general(dp, 1, sp, 1, w);
1905 }
1906
1907 static void
1908 paint_span_1_da_sa_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1909 {
1910 TRACK_FN();
1911 template_span_1_with_alpha_general(dp, 1, sp, 1, w, alpha);
1912 }
1913
1914 #if FZ_PLOTTERS_G
1915 static void
1916 paint_span_1_da(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1917 {
1918 TRACK_FN();
1919 template_span_1_general(dp, 1, sp, 0, w);
1920 }
1921
1922 static void
1923 paint_span_1_da_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1924 {
1925 TRACK_FN();
1926 template_span_1_with_alpha_general(dp, 1, sp, 0, w, alpha);
1927 }
1928
1929 static void
1930 paint_span_1(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1931 {
1932 TRACK_FN();
1933 template_span_1_general(dp, 0, sp, 0, w);
1934 }
1935
1936 static void
1937 paint_span_1_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1938 {
1939 TRACK_FN();
1940 template_span_1_with_alpha_general(dp, 0, sp, 0, w, alpha);
1941 }
1942 #endif /* FZ_PLOTTERS_G */
1943
1944 #if FZ_PLOTTERS_RGB
1945 static void
1946 paint_span_3_da_sa(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1947 {
1948 TRACK_FN();
1949 template_span_3_general(dp, 1, sp, 1, w);
1950 }
1951
1952 static void
1953 paint_span_3_da_sa_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1954 {
1955 TRACK_FN();
1956 template_span_3_with_alpha_general(dp, 1, sp, 1, w, alpha);
1957 }
1958
1959 static void
1960 paint_span_3_da(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1961 {
1962 TRACK_FN();
1963 template_span_3_general(dp, 1, sp, 0, w);
1964 }
1965
1966 static void
1967 paint_span_3_da_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1968 {
1969 TRACK_FN();
1970 template_span_3_with_alpha_general(dp, 1, sp, 0, w, alpha);
1971 }
1972
1973 static void
1974 paint_span_3_sa(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1975 {
1976 TRACK_FN();
1977 template_span_3_general(dp, 0, sp, 1, w);
1978 }
1979
1980 static void
1981 paint_span_3_sa_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1982 {
1983 TRACK_FN();
1984 template_span_3_with_alpha_general(dp, 0, sp, 1, w, alpha);
1985 }
1986
1987 static void
1988 paint_span_3(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1989 {
1990 TRACK_FN();
1991 template_span_3_general(dp, 0, sp, 0, w);
1992 }
1993
1994 static void
1995 paint_span_3_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
1996 {
1997 TRACK_FN();
1998 template_span_3_with_alpha_general(dp, 0, sp, 0, w, alpha);
1999 }
2000 #endif /* FZ_PLOTTERS_RGB */
2001
2002 #if FZ_PLOTTERS_CMYK
2003 static void
2004 paint_span_4_da_sa(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2005 {
2006 TRACK_FN();
2007 template_span_4_general(dp, 1, sp, 1, w);
2008 }
2009
2010 static void
2011 paint_span_4_da_sa_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2012 {
2013 TRACK_FN();
2014 template_span_4_with_alpha_general(dp, 1, sp, 1, w, alpha);
2015 }
2016
2017 static void
2018 paint_span_4_da(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2019 {
2020 TRACK_FN();
2021 template_span_4_general(dp, 1, sp, 0, w);
2022 }
2023
2024 static void
2025 paint_span_4_da_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2026 {
2027 TRACK_FN();
2028 template_span_4_with_alpha_general(dp, 1, sp, 0, w, alpha);
2029 }
2030
2031 static void
2032 paint_span_4_sa(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2033 {
2034 TRACK_FN();
2035 template_span_4_general(dp, 0, sp, 1, w);
2036 }
2037
2038 static void
2039 paint_span_4_sa_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2040 {
2041 TRACK_FN();
2042 template_span_4_with_alpha_general(dp, 0, sp, 1, w, alpha);
2043 }
2044
2045 static void
2046 paint_span_4(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2047 {
2048 TRACK_FN();
2049 template_span_4_general(dp, 0, sp, 0, w);
2050 }
2051
2052 static void
2053 paint_span_4_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2054 {
2055 TRACK_FN();
2056 template_span_4_with_alpha_general(dp, 0, sp, 0, w, alpha);
2057 }
2058 #endif /* FZ_PLOTTERS_CMYK */
2059
2060 #if FZ_PLOTTERS_N
2061 static void
2062 paint_span_N_da_sa(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2063 {
2064 TRACK_FN();
2065 template_span_N_general(dp, 1, sp, 1, n, w);
2066 }
2067
2068 static void
2069 paint_span_N_da_sa_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2070 {
2071 TRACK_FN();
2072 template_span_N_with_alpha_general(dp, 1, sp, 1, n, w, alpha);
2073 }
2074
2075 static void
2076 paint_span_N_da(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2077 {
2078 TRACK_FN();
2079 template_span_N_general(dp, 1, sp, 0, n, w);
2080 }
2081
2082 static void
2083 paint_span_N_da_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2084 {
2085 TRACK_FN();
2086 template_span_N_with_alpha_general(dp, 1, sp, 0, n, w, alpha);
2087 }
2088
2089 static void
2090 paint_span_N_sa(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2091 {
2092 TRACK_FN();
2093 template_span_N_general(dp, 0, sp, 1, n, w);
2094 }
2095
2096 static void
2097 paint_span_N_sa_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2098 {
2099 TRACK_FN();
2100 template_span_N_with_alpha_general(dp, 0, sp, 1, n, w, alpha);
2101 }
2102
2103 static void
2104 paint_span_N(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2105 {
2106 TRACK_FN();
2107 template_span_N_general(dp, 0, sp, 0, n, w);
2108 }
2109
2110 static void
2111 paint_span_N_alpha(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2112 {
2113 TRACK_FN();
2114 template_span_N_with_alpha_general(dp, 0, sp, 0, n, w, alpha);
2115 }
2116 #endif /* FZ_PLOTTERS_N */
2117
2118 #if FZ_ENABLE_SPOT_RENDERING
2119 static void
2120 paint_span_N_general_op(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2121 {
2122 TRACK_FN();
2123 template_span_N_general_op(dp, da, sp, sa, n, w, eop);
2124 }
2125
2126 static void
2127 paint_span_N_general_alpha_op(byte * FZ_RESTRICT dp, int da, const byte * FZ_RESTRICT sp, int sa, int n, int w, int alpha, const fz_overprint * FZ_RESTRICT eop)
2128 {
2129 TRACK_FN();
2130 template_span_N_with_alpha_general_op(dp, da, sp, sa, n, w, alpha, eop);
2131 }
2132 #endif /* FZ_ENABLE_SPOT_RENDERING */
2133
2134 fz_span_painter_t *
2135 fz_get_span_painter(int da, int sa, int n, int alpha, const fz_overprint * FZ_RESTRICT eop)
2136 {
2137 #if FZ_ENABLE_SPOT_RENDERING
2138 if (fz_overprint_required(eop))
2139 {
2140 if (alpha == 255)
2141 return paint_span_N_general_op;
2142 else if (alpha > 0)
2143 return paint_span_N_general_alpha_op;
2144 else
2145 return NULL;
2146 }
2147 #endif /* FZ_ENABLE_SPOT_RENDERING */
2148 switch (n)
2149 {
2150 case 0:
2151 if (alpha == 255)
2152 return paint_span_0_da_sa;
2153 else if (alpha > 0)
2154 return paint_span_0_da_sa_alpha;
2155 break;
2156 case 1:
2157 if (sa)
2158 if (da)
2159 {
2160 if (alpha == 255)
2161 return paint_span_1_da_sa;
2162 else if (alpha > 0)
2163 return paint_span_1_da_sa_alpha;
2164 }
2165 else
2166 {
2167 if (alpha == 255)
2168 return paint_span_1_sa;
2169 else if (alpha > 0)
2170 return paint_span_1_sa_alpha;
2171 }
2172 else
2173 #if FZ_PLOTTERS_G
2174 if (da)
2175 {
2176 if (alpha == 255)
2177 return paint_span_1_da;
2178 else if (alpha > 0)
2179 return paint_span_1_da_alpha;
2180 }
2181 else
2182 {
2183 if (alpha == 255)
2184 return paint_span_1;
2185 else if (alpha > 0)
2186 return paint_span_1_alpha;
2187 }
2188 #else
2189 goto fallback;
2190 #endif /* FZ_PLOTTERS_G */
2191 break;
2192 #if FZ_PLOTTERS_RGB
2193 case 3:
2194 if (da)
2195 if (sa)
2196 {
2197 if (alpha == 255)
2198 return paint_span_3_da_sa;
2199 else if (alpha > 0)
2200 return paint_span_3_da_sa_alpha;
2201 }
2202 else
2203 {
2204 if (alpha == 255)
2205 return paint_span_3_da;
2206 else if (alpha > 0)
2207 return paint_span_3_da_alpha;
2208 }
2209 else
2210 if (sa)
2211 {
2212 if (alpha == 255)
2213 return paint_span_3_sa;
2214 else if (alpha > 0)
2215 return paint_span_3_sa_alpha;
2216 }
2217 else
2218 {
2219 if (alpha == 255)
2220 return paint_span_3;
2221 else if (alpha > 0)
2222 return paint_span_3_alpha;
2223 }
2224 break;
2225 #endif /* FZ_PLOTTERS_RGB */
2226 #if FZ_PLOTTERS_CMYK
2227 case 4:
2228 if (da)
2229 if (sa)
2230 {
2231 if (alpha == 255)
2232 return paint_span_4_da_sa;
2233 else if (alpha > 0)
2234 return paint_span_4_da_sa_alpha;
2235 }
2236 else
2237 {
2238 if (alpha == 255)
2239 return paint_span_4_da;
2240 else if (alpha > 0)
2241 return paint_span_4_da_alpha;
2242 }
2243 else
2244 if (sa)
2245 {
2246 if (alpha == 255)
2247 return paint_span_4_sa;
2248 else if (alpha > 0)
2249 return paint_span_4_sa_alpha;
2250 }
2251 else
2252 {
2253 if (alpha == 255)
2254 return paint_span_4;
2255 else if (alpha > 0)
2256 return paint_span_4_alpha;
2257 }
2258 break;
2259 #endif /* FZ_PLOTTERS_CMYK */
2260 default:
2261 {
2262 #if !FZ_PLOTTERS_G
2263 fallback:{}
2264 #endif /* FZ_PLOTTERS_G */
2265 #if FZ_PLOTTERS_N
2266 if (da)
2267 if (sa)
2268 {
2269 if (alpha == 255)
2270 return paint_span_N_da_sa;
2271 else if (alpha > 0)
2272 return paint_span_N_da_sa_alpha;
2273 }
2274 else
2275 {
2276 if (alpha == 255)
2277 return paint_span_N_da;
2278 else if (alpha > 0)
2279 return paint_span_N_da_alpha;
2280 }
2281 else
2282 if (sa)
2283 {
2284 if (alpha == 255)
2285 return paint_span_N_sa;
2286 else if (alpha > 0)
2287 return paint_span_N_sa_alpha;
2288 }
2289 else
2290 {
2291 if (alpha == 255)
2292 return paint_span_N;
2293 else if (alpha > 0)
2294 return paint_span_N_alpha;
2295 }
2296 #endif /* FZ_PLOTTERS_N */
2297 break;
2298 }
2299 }
2300 return NULL;
2301 }
2302
2303 /*
2304 * Pixmap blending functions
2305 */
2306
2307 void
2308 fz_paint_pixmap_with_bbox(fz_pixmap * FZ_RESTRICT dst, const fz_pixmap * FZ_RESTRICT src, int alpha, fz_irect bbox)
2309 {
2310 const unsigned char *sp;
2311 unsigned char *dp;
2312 int x, y, w, h, n, da, sa;
2313 fz_span_painter_t *fn;
2314
2315 assert(dst->n - dst->alpha == src->n - src->alpha);
2316
2317 if (alpha == 0)
2318 return;
2319
2320 bbox = fz_intersect_irect(bbox, fz_pixmap_bbox_no_ctx(dst));
2321 bbox = fz_intersect_irect(bbox, fz_pixmap_bbox_no_ctx(src));
2322
2323 x = bbox.x0;
2324 y = bbox.y0;
2325 w = fz_irect_width(bbox);
2326 h = fz_irect_height(bbox);
2327 if (w == 0 || h == 0)
2328 return;
2329
2330 n = src->n;
2331 sp = src->samples + (y - src->y) * (size_t)src->stride + (x - src->x) * (size_t)src->n;
2332 sa = src->alpha;
2333 dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (x - dst->x) * (size_t)dst->n;
2334 da = dst->alpha;
2335
2336 n -= sa;
2337 fn = fz_get_span_painter(da, sa, n, alpha, 0);
2338 if (fn == NULL)
2339 return;
2340
2341 while (h--)
2342 {
2343 (*fn)(dp, da, sp, sa, n, w, alpha, 0);
2344 sp += src->stride;
2345 dp += dst->stride;
2346 }
2347 }
2348
2349 void
2350 fz_paint_pixmap(fz_pixmap * FZ_RESTRICT dst, const fz_pixmap * FZ_RESTRICT src, int alpha)
2351 {
2352 const unsigned char *sp;
2353 unsigned char *dp;
2354 fz_irect bbox;
2355 int x, y, w, h, n, da, sa;
2356 fz_span_painter_t *fn;
2357
2358 if (alpha == 0)
2359 return;
2360
2361 if (dst->n - dst->alpha != src->n - src->alpha)
2362 {
2363 // fprintf(stderr, "fz_paint_pixmap - FIXME\n");
2364 return;
2365 }
2366 assert(dst->n - dst->alpha == src->n - src->alpha);
2367
2368 bbox = fz_intersect_irect(fz_pixmap_bbox_no_ctx(src), fz_pixmap_bbox_no_ctx(dst));
2369 x = bbox.x0;
2370 y = bbox.y0;
2371 w = fz_irect_width(bbox);
2372 h = fz_irect_height(bbox);
2373 if (w == 0 || h == 0)
2374 return;
2375
2376 n = src->n;
2377 sp = src->samples + (y - src->y) * (size_t)src->stride + (x - src->x) * (size_t)src->n;
2378 sa = src->alpha;
2379 dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (x - dst->x) * (size_t)dst->n;
2380 da = dst->alpha;
2381
2382 n -= sa;
2383 fn = fz_get_span_painter(da, sa, n, alpha, 0);
2384 if (fn == NULL)
2385 return;
2386
2387 while (h--)
2388 {
2389 (*fn)(dp, da, sp, sa, n, w, alpha, 0);
2390 sp += src->stride;
2391 dp += dst->stride;
2392 }
2393 }
2394
2395 static fz_forceinline void
2396 paint_span_alpha_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, int n, int w)
2397 {
2398 TRACK_FN();
2399 sp += n-1;
2400 do
2401 {
2402 int s = *sp;
2403 int t = FZ_EXPAND(255 - s);
2404 sp += n;
2405 *dp = s + FZ_COMBINE(*dp, t);
2406 dp ++;
2407 }
2408 while (--w);
2409 }
2410
2411 static fz_forceinline void
2412 paint_span_alpha_not_solid(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, int n, int w, int alpha)
2413 {
2414 TRACK_FN();
2415 sp += n-1;
2416 alpha = FZ_EXPAND(alpha);
2417 do
2418 {
2419 int masa = FZ_COMBINE(sp[0], alpha);
2420 sp += n;
2421 *dp = FZ_BLEND(*sp, *dp, masa);
2422 dp++;
2423 }
2424 while (--w);
2425 }
2426
2427 void
2428 fz_paint_pixmap_alpha(fz_pixmap * FZ_RESTRICT dst, const fz_pixmap * FZ_RESTRICT src, int alpha)
2429 {
2430 const unsigned char *sp;
2431 unsigned char *dp;
2432 fz_irect bbox;
2433 int x, y, w, h, n;
2434
2435 if (alpha == 0)
2436 return;
2437
2438 assert(dst->n == 1 && dst->alpha == 1 && src->n >= 1 && src->alpha == 1);
2439
2440 bbox = fz_intersect_irect(fz_pixmap_bbox_no_ctx(src), fz_pixmap_bbox_no_ctx(dst));
2441 x = bbox.x0;
2442 y = bbox.y0;
2443 w = fz_irect_width(bbox);
2444 h = fz_irect_height(bbox);
2445 if (w == 0 || h == 0)
2446 return;
2447
2448 n = src->n;
2449 sp = src->samples + (y - src->y) * (size_t)src->stride + (x - src->x) * (size_t)src->n;
2450 dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (x - dst->x) * (size_t)dst->n;
2451
2452 if (alpha == 255)
2453 {
2454 while (h--)
2455 {
2456 paint_span_alpha_solid(dp, sp, n, w);
2457 sp += src->stride;
2458 dp += dst->stride;
2459 }
2460 }
2461 else
2462 {
2463 while (h--)
2464 {
2465 paint_span_alpha_not_solid(dp, sp, n, w, alpha);
2466 sp += src->stride;
2467 dp += dst->stride;
2468 }
2469 }
2470 }
2471
2472 void
2473 fz_paint_pixmap_with_overprint(fz_pixmap * FZ_RESTRICT dst, const fz_pixmap * FZ_RESTRICT src, const fz_overprint * FZ_RESTRICT eop)
2474 {
2475 const unsigned char *sp;
2476 unsigned char *dp;
2477 fz_irect bbox;
2478 int x, y, w, h, n, da, sa;
2479 fz_span_painter_t *fn;
2480
2481 if (dst->n - dst->alpha != src->n - src->alpha)
2482 {
2483 // fprintf(stderr, "fz_paint_pixmap_with_overprint - FIXME\n");
2484 return;
2485 }
2486 assert(dst->n - dst->alpha == src->n - src->alpha);
2487
2488 bbox = fz_intersect_irect(fz_pixmap_bbox_no_ctx(src), fz_pixmap_bbox_no_ctx(dst));
2489 x = bbox.x0;
2490 y = bbox.y0;
2491 w = fz_irect_width(bbox);
2492 h = fz_irect_height(bbox);
2493 if (w == 0 || h == 0)
2494 return;
2495
2496 n = src->n;
2497 sp = src->samples + (y - src->y) * (size_t)src->stride + (x - src->x) * (size_t)src->n;
2498 sa = src->alpha;
2499 dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (x - dst->x) * (size_t)dst->n;
2500 da = dst->alpha;
2501
2502 n -= sa;
2503 fn = fz_get_span_painter(da, sa, n, 255, eop);
2504 if (fn == NULL)
2505 return;
2506
2507 while (h--)
2508 {
2509 (*fn)(dp, da, sp, sa, n, w, 255, eop);
2510 sp += src->stride;
2511 dp += dst->stride;
2512 }
2513 }
2514
2515 void
2516 fz_paint_pixmap_with_mask(fz_pixmap * FZ_RESTRICT dst, const fz_pixmap * FZ_RESTRICT src, const fz_pixmap * FZ_RESTRICT msk)
2517 {
2518 const unsigned char *sp, *mp;
2519 unsigned char *dp;
2520 fz_irect bbox;
2521 int x, y, w, h, n, sa, da;
2522 fz_span_mask_painter_t *fn;
2523
2524 assert(dst->n == src->n);
2525 assert(msk->n == 1);
2526
2527 bbox = fz_pixmap_bbox_no_ctx(dst);
2528 bbox = fz_intersect_irect(bbox, fz_pixmap_bbox_no_ctx(src));
2529 bbox = fz_intersect_irect(bbox, fz_pixmap_bbox_no_ctx(msk));
2530
2531 x = bbox.x0;
2532 y = bbox.y0;
2533 w = fz_irect_width(bbox);
2534 h = fz_irect_height(bbox);
2535 if (w == 0 || h == 0)
2536 return;
2537
2538 n = src->n;
2539 sp = src->samples + (y - src->y) * (size_t)src->stride + (x - src->x) * (size_t)src->n;
2540 sa = src->alpha;
2541 mp = msk->samples + (y - msk->y) * (size_t)msk->stride + (x - msk->x) * (size_t)msk->n;
2542 dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (x - dst->x) * (size_t)dst->n;
2543 da = dst->alpha;
2544
2545 /* sa == da, or something has gone very wrong! */
2546 assert(sa == da);
2547
2548 n -= sa;
2549 fn = fz_get_span_mask_painter(da, n);
2550 if (fn == NULL)
2551 return;
2552
2553 while (h--)
2554 {
2555 (*fn)(dp, sp, mp, w, n, sa, NULL);
2556 sp += src->stride;
2557 dp += dst->stride;
2558 mp += msk->stride;
2559 }
2560 }
2561
2562 static fz_forceinline void
2563 paint_over_span_with_mask(byte * FZ_RESTRICT dp, const byte * FZ_RESTRICT sp, const byte * FZ_RESTRICT mp, int w)
2564 {
2565 do
2566 {
2567 int ma = *mp++;
2568 ma = FZ_EXPAND(ma);
2569 if (ma == 0 || *sp == 0)
2570 {
2571 dp++;
2572 sp++;
2573 }
2574 else
2575 {
2576 int a = *sp++;
2577 if (ma != 256)
2578 a = fz_mul255(ma, a);
2579 *dp = 255 - fz_mul255(255 - a, 255 - *dp);
2580 dp++;
2581 }
2582 }
2583 while (--w);
2584 }
2585
2586 void
2587 fz_paint_over_pixmap_with_mask(fz_pixmap * FZ_RESTRICT dst, const fz_pixmap * FZ_RESTRICT src, const fz_pixmap * FZ_RESTRICT msk)
2588 {
2589 const unsigned char *sp, *mp;
2590 unsigned char *dp;
2591 fz_irect bbox;
2592 int x, y, w, h;
2593
2594 assert(dst->n == src->n);
2595 assert(msk->n == 1);
2596
2597 bbox = fz_pixmap_bbox_no_ctx(dst);
2598 bbox = fz_intersect_irect(bbox, fz_pixmap_bbox_no_ctx(src));
2599 bbox = fz_intersect_irect(bbox, fz_pixmap_bbox_no_ctx(msk));
2600
2601 x = bbox.x0;
2602 y = bbox.y0;
2603 w = fz_irect_width(bbox);
2604 h = fz_irect_height(bbox);
2605 if (w == 0 || h == 0)
2606 return;
2607
2608 /* sa == da, or something has gone very wrong! */
2609 assert(src->alpha == dst->alpha && dst->alpha == 1 && src->n == 1);
2610 sp = src->samples + (y - src->y) * (size_t)src->stride + (size_t)(x - src->x);
2611 mp = msk->samples + (y - msk->y) * (size_t)msk->stride + (size_t)(x - msk->x);
2612 dp = dst->samples + (y - dst->y) * (size_t)dst->stride + (size_t)(x - dst->x);
2613
2614
2615 while (h--)
2616 {
2617 paint_over_span_with_mask(dp, sp, mp, w);
2618 sp += src->stride;
2619 dp += dst->stride;
2620 mp += msk->stride;
2621 }
2622 }
2623
2624 static inline void
2625 fz_paint_glyph_mask(int span, unsigned char *dp, int da, const fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
2626 {
2627 while (h--)
2628 {
2629 int skip_xx, ww, len, extend;
2630 const unsigned char *runp;
2631 unsigned char *ddp = dp;
2632 int offset = ((const int *)(glyph->data))[skip_y++];
2633 if (offset >= 0)
2634 {
2635 int eol = 0;
2636 runp = &glyph->data[offset];
2637 extend = 0;
2638 ww = w;
2639 skip_xx = skip_x;
2640 while (skip_xx)
2641 {
2642 int v = *runp++;
2643 switch (v & 3)
2644 {
2645 case 0: /* Extend */
2646 extend = v>>2;
2647 len = 0;
2648 break;
2649 case 1: /* Transparent */
2650 len = (v>>2) + 1 + (extend<<6);
2651 extend = 0;
2652 if (len > skip_xx)
2653 {
2654 len -= skip_xx;
2655 goto transparent_run;
2656 }
2657 break;
2658 case 2: /* Solid */
2659 eol = v & 4;
2660 len = (v>>3) + 1 + (extend<<5);
2661 extend = 0;
2662 if (len > skip_xx)
2663 {
2664 len -= skip_xx;
2665 goto solid_run;
2666 }
2667 break;
2668 default: /* Intermediate */
2669 eol = v & 4;
2670 len = (v>>3) + 1 + (extend<<5);
2671 extend = 0;
2672 if (len > skip_xx)
2673 {
2674 runp += skip_xx;
2675 len -= skip_xx;
2676 goto intermediate_run;
2677 }
2678 runp += len;
2679 break;
2680 }
2681 if (eol)
2682 {
2683 ww = 0;
2684 break;
2685 }
2686 skip_xx -= len;
2687 }
2688 while (ww > 0)
2689 {
2690 int v = *runp++;
2691 switch(v & 3)
2692 {
2693 case 0: /* Extend */
2694 extend = v>>2;
2695 break;
2696 case 1: /* Transparent */
2697 len = (v>>2) + 1 + (extend<<6);
2698 extend = 0;
2699 transparent_run:
2700 if (len > ww)
2701 len = ww;
2702 ww -= len;
2703 ddp += len;
2704 break;
2705 case 2: /* Solid */
2706 eol = v & 4;
2707 len = (v>>3) + 1 + (extend<<5);
2708 extend = 0;
2709 solid_run:
2710 if (len > ww)
2711 len = ww;
2712 ww -= len;
2713 do
2714 {
2715 *ddp++ = 0xFF;
2716 }
2717 while (--len);
2718 break;
2719 default: /* Intermediate */
2720 eol = v & 4;
2721 len = (v>>3) + 1 + (extend<<5);
2722 extend = 0;
2723 intermediate_run:
2724 if (len > ww)
2725 len = ww;
2726 ww -= len;
2727 do
2728 {
2729 int a = *runp++;
2730 v = *ddp;
2731 if (v == 0)
2732 {
2733 *ddp++ = a;
2734 }
2735 else
2736 {
2737 a = FZ_EXPAND(a);
2738 *ddp = FZ_BLEND(0xFF, v, a);
2739 ddp++;
2740 }
2741 }
2742 while (--len);
2743 break;
2744 }
2745 if (eol)
2746 break;
2747 }
2748 }
2749 dp += span;
2750 }
2751 }
2752
2753 static inline void
2754 fz_paint_glyph_mask_alpha(int span, unsigned char *dp, int da, const fz_glyph *glyph, int w, int h, int skip_x, int skip_y, unsigned char alpha)
2755 {
2756 while (h--)
2757 {
2758 int skip_xx, ww, len, extend;
2759 const unsigned char *runp;
2760 unsigned char *ddp = dp;
2761 int offset = ((const int *)(glyph->data))[skip_y++];
2762 if (offset >= 0)
2763 {
2764 int eol = 0;
2765 runp = &glyph->data[offset];
2766 extend = 0;
2767 ww = w;
2768 skip_xx = skip_x;
2769 while (skip_xx)
2770 {
2771 int v = *runp++;
2772 switch (v & 3)
2773 {
2774 case 0: /* Extend */
2775 extend = v>>2;
2776 len = 0;
2777 break;
2778 case 1: /* Transparent */
2779 len = (v>>2) + 1 + (extend<<6);
2780 extend = 0;
2781 if (len > skip_xx)
2782 {
2783 len -= skip_xx;
2784 goto transparent_run;
2785 }
2786 break;
2787 case 2: /* Solid */
2788 eol = v & 4;
2789 len = (v>>3) + 1 + (extend<<5);
2790 extend = 0;
2791 if (len > skip_xx)
2792 {
2793 len -= skip_xx;
2794 goto solid_run;
2795 }
2796 break;
2797 default: /* Intermediate */
2798 eol = v & 4;
2799 len = (v>>3) + 1 + (extend<<5);
2800 extend = 0;
2801 if (len > skip_xx)
2802 {
2803 runp += skip_xx;
2804 len -= skip_xx;
2805 goto intermediate_run;
2806 }
2807 runp += len;
2808 break;
2809 }
2810 if (eol)
2811 {
2812 ww = 0;
2813 break;
2814 }
2815 skip_xx -= len;
2816 }
2817 while (ww > 0)
2818 {
2819 int v = *runp++;
2820 switch(v & 3)
2821 {
2822 case 0: /* Extend */
2823 extend = v>>2;
2824 break;
2825 case 1: /* Transparent */
2826 len = (v>>2) + 1 + (extend<<6);
2827 extend = 0;
2828 transparent_run:
2829 if (len > ww)
2830 len = ww;
2831 ww -= len;
2832 ddp += len;
2833 break;
2834 case 2: /* Solid */
2835 eol = v & 4;
2836 len = (v>>3) + 1 + (extend<<5);
2837 extend = 0;
2838 solid_run:
2839 if (len > ww)
2840 len = ww;
2841 ww -= len;
2842 do
2843 {
2844 *ddp++ = alpha;
2845 }
2846 while (--len);
2847 break;
2848 default: /* Intermediate */
2849 eol = v & 4;
2850 len = (v>>3) + 1 + (extend<<5);
2851 extend = 0;
2852 intermediate_run:
2853 if (len > ww)
2854 len = ww;
2855 ww -= len;
2856 do
2857 {
2858 int a = *runp++;
2859 v = *ddp;
2860 if (v == 0)
2861 {
2862 *ddp++ = fz_mul255(a, alpha);
2863 }
2864 else
2865 {
2866 a = FZ_EXPAND(a);
2867 *ddp = FZ_BLEND(alpha, v, a);
2868 ddp++;
2869 }
2870 }
2871 while (--len);
2872 break;
2873 }
2874 if (eol)
2875 break;
2876 }
2877 }
2878 dp += span;
2879 }
2880 }
2881
2882 #define N 1
2883 #include "paint-glyph.h"
2884
2885 #define ALPHA
2886 #define N 1
2887 #include "paint-glyph.h"
2888
2889 #if FZ_PLOTTERS_G
2890 #define DA
2891 #define N 1
2892 #include "paint-glyph.h"
2893
2894 #define DA
2895 #define ALPHA
2896 #define N 1
2897 #include "paint-glyph.h"
2898 #endif /* FZ_PLOTTERS_G */
2899
2900 #if FZ_PLOTTERS_RGB
2901 #define DA
2902 #define N 3
2903 #include "paint-glyph.h"
2904
2905 #define DA
2906 #define ALPHA
2907 #define N 3
2908 #include "paint-glyph.h"
2909
2910 #define N 3
2911 #include "paint-glyph.h"
2912
2913 #define ALPHA
2914 #define N 3
2915 #include "paint-glyph.h"
2916 #endif /* FZ_PLOTTERS_RGB */
2917
2918 #if FZ_PLOTTERS_CMYK
2919 #define DA
2920 #define N 4
2921 #include "paint-glyph.h"
2922
2923 #define DA
2924 #define ALPHA
2925 #define N 4
2926 #include "paint-glyph.h"
2927
2928 #define ALPHA
2929 #define N 4
2930 #include "paint-glyph.h"
2931
2932 #define N 4
2933 #include "paint-glyph.h"
2934 #endif /* FZ_PLOTTERS_CMYK */
2935
2936 #if FZ_PLOTTERS_N
2937 #define ALPHA
2938 #include "paint-glyph.h"
2939
2940 #define DA
2941 #include "paint-glyph.h"
2942
2943 #define DA
2944 #define ALPHA
2945 #include "paint-glyph.h"
2946
2947 #include "paint-glyph.h"
2948 #endif /* FZ_PLOTTERS_N */
2949
2950 #if FZ_ENABLE_SPOT_RENDERING
2951 #define ALPHA
2952 #define EOP
2953 #include "paint-glyph.h"
2954
2955 #define DA
2956 #define EOP
2957 #include "paint-glyph.h"
2958
2959 #define DA
2960 #define ALPHA
2961 #define EOP
2962 #include "paint-glyph.h"
2963
2964 #define EOP
2965 #include "paint-glyph.h"
2966 #endif /* FZ_ENABLE_SPOT_RENDERING */
2967
2968 static void
2969 fz_paint_glyph_alpha(const unsigned char * FZ_RESTRICT colorbv, int n, int span, unsigned char * FZ_RESTRICT dp, int da, const fz_glyph *glyph, int w, int h, int skip_x, int skip_y, const fz_overprint * FZ_RESTRICT eop)
2970 {
2971 #if FZ_ENABLE_SPOT_RENDERING
2972 if (fz_overprint_required(eop))
2973 {
2974 if (da)
2975 fz_paint_glyph_alpha_N_da_op(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y, eop);
2976 else
2977 fz_paint_glyph_alpha_N_op(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y, eop);
2978 return;
2979 }
2980 #endif /* FZ_ENABLE_SPOT_RENDERING */
2981 switch (n)
2982 {
2983 case 1:
2984 if (da)
2985 #if FZ_PLOTTERS_G
2986 fz_paint_glyph_alpha_1_da(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
2987 #else
2988 goto fallback;
2989 #endif /* FZ_PLOTTERS_G */
2990 else
2991 fz_paint_glyph_alpha_1(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
2992 break;
2993 #if FZ_PLOTTERS_RGB
2994 case 3:
2995 if (da)
2996 fz_paint_glyph_alpha_3_da(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
2997 else
2998 fz_paint_glyph_alpha_3(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
2999 break;
3000 #endif /* FZ_PLOTTERS_RGB */
3001 #if FZ_PLOTTERS_CMYK
3002 case 4:
3003 if (da)
3004 fz_paint_glyph_alpha_4_da(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
3005 else
3006 fz_paint_glyph_alpha_4(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
3007 break;
3008 #endif /* FZ_PLOTTERS_CMYK */
3009 default:
3010 {
3011 #if !FZ_PLOTTERS_G
3012 fallback:{}
3013 #endif /* !FZ_PLOTTERS_G */
3014 #if FZ_PLOTTERS_N
3015 if (da)
3016 fz_paint_glyph_alpha_N_da(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y);
3017 else
3018 fz_paint_glyph_alpha_N(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y);
3019 #endif /* FZ_PLOTTERS_N */
3020 break;
3021 }
3022 }
3023 }
3024
3025 static void
3026 fz_paint_glyph_solid(const unsigned char * FZ_RESTRICT colorbv, int n, int span, unsigned char * FZ_RESTRICT dp, int da, const fz_glyph * FZ_RESTRICT glyph, int w, int h, int skip_x, int skip_y, const fz_overprint * FZ_RESTRICT eop)
3027 {
3028 #if FZ_ENABLE_SPOT_RENDERING
3029 if (fz_overprint_required(eop))
3030 {
3031 if (da)
3032 fz_paint_glyph_solid_N_da_op(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y, eop);
3033 else
3034 fz_paint_glyph_solid_N_op(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y, eop);
3035 return;
3036 }
3037 #endif /* FZ_ENABLE_SPOT_RENDERING */
3038 switch (n)
3039 {
3040 case 1:
3041 if (da)
3042 #if FZ_PLOTTERS_G
3043 fz_paint_glyph_solid_1_da(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
3044 #else
3045 goto fallback;
3046 #endif /* FZ_PLOTTERS_G */
3047 else
3048 fz_paint_glyph_solid_1(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
3049 break;
3050 #if FZ_PLOTTERS_RGB
3051 case 3:
3052 if (da)
3053 fz_paint_glyph_solid_3_da(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
3054 else
3055 fz_paint_glyph_solid_3(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
3056 break;
3057 #endif /* FZ_PLOTTERS_RGB */
3058 #if FZ_PLOTTERS_CMYK
3059 case 4:
3060 if (da)
3061 fz_paint_glyph_solid_4_da(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
3062 else
3063 fz_paint_glyph_solid_4(colorbv, span, dp, glyph, w, h, skip_x, skip_y);
3064 break;
3065 #endif /* FZ_PLOTTERS_CMYK */
3066 default:
3067 {
3068 #if !FZ_PLOTTERS_G
3069 fallback:{}
3070 #endif /* FZ_PLOTTERS_G */
3071 #if FZ_PLOTTERS_N
3072 if (da)
3073 fz_paint_glyph_solid_N_da(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y);
3074 else
3075 fz_paint_glyph_solid_N(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y);
3076 break;
3077 #endif /* FZ_PLOTTERS_N */
3078 }
3079 }
3080 }
3081
3082 void
3083 fz_paint_glyph(const unsigned char * FZ_RESTRICT colorbv, fz_pixmap * FZ_RESTRICT dst, unsigned char * FZ_RESTRICT dp, const fz_glyph * FZ_RESTRICT glyph, int w, int h, int skip_x, int skip_y, const fz_overprint * FZ_RESTRICT eop)
3084 {
3085 int n = dst->n - dst->alpha;
3086 if (dst->colorspace)
3087 {
3088 assert(n > 0);
3089 if (colorbv[n] == 255)
3090 fz_paint_glyph_solid(colorbv, n, dst->stride, dp, dst->alpha, glyph, w, h, skip_x, skip_y, eop);
3091 else if (colorbv[n] != 0)
3092 fz_paint_glyph_alpha(colorbv, n, dst->stride, dp, dst->alpha, glyph, w, h, skip_x, skip_y, eop);
3093 }
3094 else
3095 {
3096 assert(dst->alpha && dst->n == 1 && dst->colorspace == NULL && !fz_overprint_required(eop));
3097 if (colorbv == NULL || colorbv[0] == 255)
3098 fz_paint_glyph_mask(dst->stride, dp, dst->alpha, glyph, w, h, skip_x, skip_y);
3099 else
3100 fz_paint_glyph_mask_alpha(dst->stride, dp, dst->alpha, glyph, w, h, skip_x, skip_y, colorbv[0]);
3101 }
3102 }