1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16 /* PDF 1.4 blending functions */
17
18 #include "memory_.h"
19 #include "gx.h"
20 #include "gp.h"
21 #include "gstparam.h"
22 #include "gxblend.h"
23 #include "gxcolor2.h"
24 #include "gsicc_cache.h"
25 #include "gsicc_manage.h"
26 #include "gdevp14.h"
27 #include "gsrect.h" /* for rect_merge */
28 #include "math_.h" /* for ceil, floor */
29 #ifdef WITH_CAL
30 #include "cal.h"
31 #endif
32
33 typedef int art_s32;
34
35 #if RAW_DUMP
36 extern unsigned int global_index;
37 extern unsigned int clist_band_count;
38 #endif
39
40 #undef TRACK_COMPOSE_GROUPS
41 #ifdef TRACK_COMPOSE_GROUPS
42 int compose_groups[1<<17];
43
44 static int track_compose_groups = 0;
45
46 static void dump_track_compose_groups(void);
47 #endif
48
49
50 /* For spot colors, blend modes must be white preserving and separable. The
51 * order of the blend modes should be reordered so this is a single compare */
52 bool
blend_valid_for_spot(gs_blend_mode_t blend_mode)53 blend_valid_for_spot(gs_blend_mode_t blend_mode)
54 {
55 if (blend_mode == BLEND_MODE_Difference ||
56 blend_mode == BLEND_MODE_Exclusion ||
57 blend_mode == BLEND_MODE_Hue ||
58 blend_mode == BLEND_MODE_Saturation ||
59 blend_mode == BLEND_MODE_Color ||
60 blend_mode == BLEND_MODE_Luminosity)
61 return false;
62 else
63 return true;
64 }
65
66 /* This function is used for mapping the SMask source to a
67 monochrome luminosity value which basically is the alpha value
68 Note, that separation colors are not allowed here. Everything
69 must be in CMYK, RGB or monochrome. */
70
71 /* Note, data is planar */
72 static void
do_smask_luminosity_mapping(int num_rows,int num_cols,int n_chan,int row_stride,int plane_stride,const byte * gs_restrict src,byte * gs_restrict dst,bool isadditive,gs_transparency_mask_subtype_t SMask_SubType,const gs_memory_t * mem)73 do_smask_luminosity_mapping(int num_rows, int num_cols, int n_chan, int row_stride,
74 int plane_stride, const byte *gs_restrict src,
75 byte *gs_restrict dst, bool isadditive,
76 gs_transparency_mask_subtype_t SMask_SubType
77 #if RAW_DUMP
78 , const gs_memory_t *mem
79 #endif
80 )
81 {
82 int x,y;
83 int mask_alpha_offset,mask_C_offset,mask_M_offset,mask_Y_offset,mask_K_offset;
84 int mask_R_offset,mask_G_offset,mask_B_offset;
85 byte *dstptr;
86
87 #if RAW_DUMP
88 dump_raw_buffer(mem, num_rows, row_stride, n_chan,
89 plane_stride, row_stride,
90 "Raw_Mask", src, 0);
91
92 global_index++;
93 #endif
94 dstptr = (byte *)dst;
95 /* If subtype is Luminosity then we should just grab the Y channel */
96 if ( SMask_SubType == TRANSPARENCY_MASK_Luminosity ){
97 memcpy(dstptr, &(src[plane_stride]), plane_stride);
98 return;
99 }
100 /* If we are alpha type, then just grab that */
101 /* We need to optimize this so that we are only drawing alpha in the rect fills */
102 if ( SMask_SubType == TRANSPARENCY_MASK_Alpha ){
103 mask_alpha_offset = (n_chan - 1) * plane_stride;
104 memcpy(dstptr, &(src[mask_alpha_offset]), plane_stride);
105 return;
106 }
107 /* To avoid the if statement inside this loop,
108 decide on additive or subractive now */
109 if (isadditive || n_chan == 2) {
110 /* Now we need to split Gray from RGB */
111 if( n_chan == 2 ) {
112 /* Gray Scale case */
113 mask_alpha_offset = (n_chan - 1) * plane_stride;
114 mask_R_offset = 0;
115 for ( y = 0; y < num_rows; y++ ) {
116 for ( x = 0; x < num_cols; x++ ){
117 /* With the current design this will indicate if
118 we ever did a fill at this pixel. if not then move on.
119 This could have some serious optimization */
120 if (src[x + mask_alpha_offset] != 0x00) {
121 dstptr[x] = src[x + mask_R_offset];
122 }
123 }
124 dstptr += row_stride;
125 mask_alpha_offset += row_stride;
126 mask_R_offset += row_stride;
127 }
128 } else {
129 /* RGB case */
130 mask_R_offset = 0;
131 mask_G_offset = plane_stride;
132 mask_B_offset = 2 * plane_stride;
133 mask_alpha_offset = (n_chan - 1) * plane_stride;
134 for ( y = 0; y < num_rows; y++ ) {
135 for ( x = 0; x < num_cols; x++ ){
136 /* With the current design this will indicate if
137 we ever did a fill at this pixel. if not then move on */
138 if (src[x + mask_alpha_offset] != 0x00) {
139 /* Get luminosity of Device RGB value */
140 float temp;
141 temp = ( 0.30 * src[x + mask_R_offset] +
142 0.59 * src[x + mask_G_offset] +
143 0.11 * src[x + mask_B_offset] );
144 temp = temp * (1.0 / 255.0 ); /* May need to be optimized */
145 dstptr[x] = float_color_to_byte_color(temp);
146 }
147 }
148 dstptr += row_stride;
149 mask_alpha_offset += row_stride;
150 mask_R_offset += row_stride;
151 mask_G_offset += row_stride;
152 mask_B_offset += row_stride;
153 }
154 }
155 } else {
156 /* CMYK case */
157 mask_alpha_offset = (n_chan - 1) * plane_stride;
158 mask_C_offset = 0;
159 mask_M_offset = plane_stride;
160 mask_Y_offset = 2 * plane_stride;
161 mask_K_offset = 3 * plane_stride;
162 for ( y = 0; y < num_rows; y++ ){
163 for ( x = 0; x < num_cols; x++ ){
164 /* With the current design this will indicate if
165 we ever did a fill at this pixel. if not then move on */
166 if (src[x + mask_alpha_offset] != 0x00){
167 /* PDF spec says to use Y = 0.30 (1 - C)(1 - K) +
168 0.59 (1 - M)(1 - K) + 0.11 (1 - Y)(1 - K) */
169 /* For device CMYK */
170 float temp;
171 temp = ( 0.30 * ( 0xff - src[x + mask_C_offset]) +
172 0.59 * ( 0xff - src[x + mask_M_offset]) +
173 0.11 * ( 0xff - src[x + mask_Y_offset]) ) *
174 ( 0xff - src[x + mask_K_offset]);
175 temp = temp * (1.0 / 65025.0 ); /* May need to be optimized */
176 dstptr[x] = float_color_to_byte_color(temp);
177 }
178 }
179 dstptr += row_stride;
180 mask_alpha_offset += row_stride;
181 mask_C_offset += row_stride;
182 mask_M_offset += row_stride;
183 mask_Y_offset += row_stride;
184 mask_K_offset += row_stride;
185 }
186 }
187 }
188
189 static void
do_smask_luminosity_mapping_16(int num_rows,int num_cols,int n_chan,int row_stride,int plane_stride,const uint16_t * gs_restrict src,uint16_t * gs_restrict dst,bool isadditive,gs_transparency_mask_subtype_t SMask_SubType,const gs_memory_t * mem)190 do_smask_luminosity_mapping_16(int num_rows, int num_cols, int n_chan, int row_stride,
191 int plane_stride, const uint16_t *gs_restrict src,
192 uint16_t *gs_restrict dst, bool isadditive,
193 gs_transparency_mask_subtype_t SMask_SubType
194 #if RAW_DUMP
195 , const gs_memory_t *mem
196 #endif
197 )
198 {
199 int x,y;
200 int mask_alpha_offset,mask_C_offset,mask_M_offset,mask_Y_offset,mask_K_offset;
201 int mask_R_offset,mask_G_offset,mask_B_offset;
202 uint16_t *dstptr;
203
204 #if RAW_DUMP
205 dump_raw_buffer_be(mem, num_rows, row_stride, n_chan,
206 plane_stride, row_stride,
207 "Raw_Mask", (const byte *)src, 0);
208
209 global_index++;
210 #endif
211 dstptr = dst;
212 /* If subtype is Luminosity then we should just grab the Y channel */
213 if ( SMask_SubType == TRANSPARENCY_MASK_Luminosity ){
214 memcpy(dstptr, &(src[plane_stride]), plane_stride*2);
215 return;
216 }
217 /* If we are alpha type, then just grab that */
218 /* We need to optimize this so that we are only drawing alpha in the rect fills */
219 if ( SMask_SubType == TRANSPARENCY_MASK_Alpha ){
220 mask_alpha_offset = (n_chan - 1) * plane_stride;
221 memcpy(dstptr, &(src[mask_alpha_offset]), plane_stride*2);
222 return;
223 }
224 /* To avoid the if statement inside this loop,
225 decide on additive or subractive now */
226 if (isadditive || n_chan == 2) {
227 /* Now we need to split Gray from RGB */
228 if( n_chan == 2 ) {
229 /* Gray Scale case */
230 mask_alpha_offset = (n_chan - 1) * plane_stride;
231 mask_R_offset = 0;
232 for ( y = 0; y < num_rows; y++ ) {
233 for ( x = 0; x < num_cols; x++ ){
234 /* With the current design this will indicate if
235 we ever did a fill at this pixel. if not then move on.
236 This could have some serious optimization */
237 if (src[x + mask_alpha_offset] != 0x00) {
238 dstptr[x] = src[x + mask_R_offset];
239 }
240 }
241 dstptr += row_stride;
242 mask_alpha_offset += row_stride;
243 mask_R_offset += row_stride;
244 }
245 } else {
246 /* RGB case */
247 mask_R_offset = 0;
248 mask_G_offset = plane_stride;
249 mask_B_offset = 2 * plane_stride;
250 mask_alpha_offset = (n_chan - 1) * plane_stride;
251 for ( y = 0; y < num_rows; y++ ) {
252 for ( x = 0; x < num_cols; x++ ){
253 /* With the current design this will indicate if
254 we ever did a fill at this pixel. if not then move on */
255 if (src[x + mask_alpha_offset] != 0x00) {
256 /* Get luminosity of Device RGB value */
257 float temp;
258 temp = ( 0.30 * src[x + mask_R_offset] +
259 0.59 * src[x + mask_G_offset] +
260 0.11 * src[x + mask_B_offset] );
261 temp = temp * (1.0 / 65535.0 ); /* May need to be optimized */
262 dstptr[x] = float_color_to_color16(temp);
263 }
264 }
265 dstptr += row_stride;
266 mask_alpha_offset += row_stride;
267 mask_R_offset += row_stride;
268 mask_G_offset += row_stride;
269 mask_B_offset += row_stride;
270 }
271 }
272 } else {
273 /* CMYK case */
274 mask_alpha_offset = (n_chan - 1) * plane_stride;
275 mask_C_offset = 0;
276 mask_M_offset = plane_stride;
277 mask_Y_offset = 2 * plane_stride;
278 mask_K_offset = 3 * plane_stride;
279 for ( y = 0; y < num_rows; y++ ){
280 for ( x = 0; x < num_cols; x++ ){
281 /* With the current design this will indicate if
282 we ever did a fill at this pixel. if not then move on */
283 if (src[x + mask_alpha_offset] != 0x00){
284 /* PDF spec says to use Y = 0.30 (1 - C)(1 - K) +
285 0.59 (1 - M)(1 - K) + 0.11 (1 - Y)(1 - K) */
286 /* For device CMYK */
287 float temp;
288 temp = ( 0.30 * ( 0xffff - src[x + mask_C_offset]) +
289 0.59 * ( 0xffff - src[x + mask_M_offset]) +
290 0.11 * ( 0xffff - src[x + mask_Y_offset]) ) *
291 ( 0xffff - src[x + mask_K_offset]);
292 temp = temp * (1.0 / (65535.0*65535.0) ); /* May need to be optimized */
293 dstptr[x] = float_color_to_color16(temp);
294 }
295 }
296 dstptr += row_stride;
297 mask_alpha_offset += row_stride;
298 mask_C_offset += row_stride;
299 mask_M_offset += row_stride;
300 mask_Y_offset += row_stride;
301 mask_K_offset += row_stride;
302 }
303 }
304 }
305
306 void
smask_luminosity_mapping(int num_rows,int num_cols,int n_chan,int row_stride,int plane_stride,const byte * gs_restrict src,byte * gs_restrict dst,bool isadditive,gs_transparency_mask_subtype_t SMask_SubType,bool deep,const gs_memory_t * mem)307 smask_luminosity_mapping(int num_rows, int num_cols, int n_chan, int row_stride,
308 int plane_stride, const byte *gs_restrict src,
309 byte *gs_restrict dst, bool isadditive,
310 gs_transparency_mask_subtype_t SMask_SubType, bool deep
311 #if RAW_DUMP
312 , const gs_memory_t *mem
313 #endif
314 )
315 {
316 if (deep)
317 do_smask_luminosity_mapping_16(num_rows, num_cols, n_chan, row_stride>>1,
318 plane_stride>>1, (const uint16_t *)(const void *)src,
319 (uint16_t *)(void *)dst, isadditive, SMask_SubType
320 #if RAW_DUMP
321 , mem
322 #endif
323 );
324 else
325 do_smask_luminosity_mapping(num_rows, num_cols, n_chan, row_stride,
326 plane_stride, src, dst, isadditive, SMask_SubType
327 #if RAW_DUMP
328 , mem
329 #endif
330 );
331 }
332
333 /* soft mask gray buffer should be blended with its transparency planar data
334 during the pop for a luminosity case if we have a soft mask within a soft
335 mask. This situation is detected in the code so that we only do this
336 blending in those rare situations */
337 void
smask_blend(byte * gs_restrict src,int width,int height,int rowstride,int planestride,bool deep)338 smask_blend(byte *gs_restrict src, int width, int height, int rowstride,
339 int planestride, bool deep)
340 {
341 int x, y;
342 int position;
343
344 if (deep) {
345 uint16_t comp, a;
346 const uint16_t bg = 0;
347 uint16_t *src16 = (uint16_t *)(void *)src;
348 rowstride >>= 1;
349 planestride >>= 1;
350 for (y = 0; y < height; y++) {
351 position = y * rowstride;
352 for (x = 0; x < width; x++) {
353 a = src16[position + planestride];
354 if (a == 0) {
355 src16[position] = 0;
356 } else if (a != 0xffff) {
357 a ^= 0xffff;
358 a += a>>15;
359 comp = src16[position];
360 comp += (((bg - comp) * a) + 0x8000)>>16;
361 /* Errors in bit 16 and above are ignored */
362 src16[position] = comp;
363 }
364 position+=1;
365 }
366 }
367 } else {
368 byte comp, a;
369 int tmp;
370 const byte bg = 0;
371 for (y = 0; y < height; y++) {
372 position = y * rowstride;
373 for (x = 0; x < width; x++) {
374 a = src[position + planestride];
375 if ((a + 1) & 0xfe) {
376 a ^= 0xff;
377 comp = src[position];
378 tmp = ((bg - comp) * a) + 0x80;
379 comp += (tmp + (tmp >> 8)) >> 8;
380 src[position] = comp;
381 } else if (a == 0) {
382 src[position] = 0;
383 }
384 position+=1;
385 }
386 }
387 }
388 }
389
smask_copy(int num_rows,int num_cols,int row_stride,byte * gs_restrict src,const byte * gs_restrict dst)390 void smask_copy(int num_rows, int num_cols, int row_stride,
391 byte *gs_restrict src, const byte *gs_restrict dst)
392 {
393 int y;
394 byte *dstptr,*srcptr;
395
396 dstptr = (byte *)dst;
397 srcptr = src;
398 for ( y = 0; y < num_rows; y++ ) {
399 memcpy(dstptr,srcptr,num_cols);
400 dstptr += row_stride;
401 srcptr += row_stride;
402 }
403 }
404
smask_icc(gx_device * dev,int num_rows,int num_cols,int n_chan,int row_stride,int plane_stride,byte * gs_restrict src,const byte * gs_restrict dst,gsicc_link_t * icclink,bool deep)405 void smask_icc(gx_device *dev, int num_rows, int num_cols, int n_chan,
406 int row_stride, int plane_stride, byte *gs_restrict src, const byte *gs_restrict dst,
407 gsicc_link_t *icclink, bool deep)
408 {
409 gsicc_bufferdesc_t input_buff_desc;
410 gsicc_bufferdesc_t output_buff_desc;
411
412 #if RAW_DUMP
413 dump_raw_buffer(dev->memory, num_rows, row_stride>>deep, n_chan,
414 plane_stride, row_stride,
415 "Raw_Mask_ICC", src, deep);
416 global_index++;
417 #endif
418 /* Set up the buffer descriptors. Note that pdf14 always has
419 the alpha channels at the back end (last planes).
420 We will just handle that here and let the CMM know
421 nothing about it */
422
423 gsicc_init_buffer(&input_buff_desc, n_chan-1, 1<<deep,
424 false, false, true, plane_stride, row_stride,
425 num_rows, num_cols);
426 gsicc_init_buffer(&output_buff_desc, 1, 1<<deep,
427 false, false, true, plane_stride,
428 row_stride, num_rows, num_cols);
429 /* Transform the data */
430 (icclink->procs.map_buffer)(dev, icclink, &input_buff_desc, &output_buff_desc,
431 (void*) src, (void*) dst);
432 }
433
434 void
art_blend_luminosity_rgb_8(int n_chan,byte * gs_restrict dst,const byte * gs_restrict backdrop,const byte * gs_restrict src)435 art_blend_luminosity_rgb_8(int n_chan, byte *gs_restrict dst, const byte *gs_restrict backdrop,
436 const byte *gs_restrict src)
437 {
438 int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
439 int rs = src[0], gs = src[1], bs = src[2];
440 int delta_y;
441 int r, g, b;
442
443 /*
444 * From section 7.4 of the PDF 1.5 specification, for RGB, the luminosity
445 * is: Y = 0.30 R + 0.59 G + 0.11 B)
446 */
447 delta_y = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8;
448 r = rb + delta_y;
449 g = gb + delta_y;
450 b = bb + delta_y;
451 if ((r | g | b) & 0x100) {
452 int y;
453 int scale;
454
455 y = (rs * 77 + gs * 151 + bs * 28 + 0x80) >> 8;
456 if (delta_y > 0) {
457 int max;
458
459 max = r > g ? r : g;
460 max = b > max ? b : max;
461 scale = ((255 - y) << 16) / (max - y);
462 } else {
463 int min;
464
465 min = r < g ? r : g;
466 min = b < min ? b : min;
467 scale = (y << 16) / (y - min);
468 }
469 r = y + (((r - y) * scale + 0x8000) >> 16);
470 g = y + (((g - y) * scale + 0x8000) >> 16);
471 b = y + (((b - y) * scale + 0x8000) >> 16);
472 }
473 dst[0] = r;
474 dst[1] = g;
475 dst[2] = b;
476 }
477
478 void
art_blend_luminosity_rgb_16(int n_chan,uint16_t * gs_restrict dst,const uint16_t * gs_restrict backdrop,const uint16_t * gs_restrict src)479 art_blend_luminosity_rgb_16(int n_chan, uint16_t *gs_restrict dst, const uint16_t *gs_restrict backdrop,
480 const uint16_t *gs_restrict src)
481 {
482 int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
483 int rs = src[0], gs = src[1], bs = src[2];
484 int delta_y;
485 int r, g, b;
486
487 /*
488 * From section 7.4 of the PDF 1.5 specification, for RGB, the luminosity
489 * is: Y = 0.30 R + 0.59 G + 0.11 B)
490 */
491 delta_y = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8;
492 r = rb + delta_y;
493 g = gb + delta_y;
494 b = bb + delta_y;
495 if ((r | g | b) & 0x10000) {
496 int y;
497 int64_t scale;
498
499 /* Resort to 64 bit to avoid calculations with scale overflowing */
500 y = (rs * 77 + gs * 151 + bs * 28 + 0x80) >> 8;
501 if (delta_y > 0) {
502 int max;
503
504 max = r > g ? r : g;
505 max = b > max ? b : max;
506 scale = ((65535 - (int64_t)y) << 16) / (max - y);
507 } else {
508 int min;
509
510 min = r < g ? r : g;
511 min = b < min ? b : min;
512 scale = (((int64_t)y) << 16) / (y - min);
513 }
514 r = y + (((r - y) * scale + 0x8000) >> 16);
515 g = y + (((g - y) * scale + 0x8000) >> 16);
516 b = y + (((b - y) * scale + 0x8000) >> 16);
517 }
518 dst[0] = r;
519 dst[1] = g;
520 dst[2] = b;
521 }
522
523 void
art_blend_luminosity_custom_8(int n_chan,byte * gs_restrict dst,const byte * gs_restrict backdrop,const byte * gs_restrict src)524 art_blend_luminosity_custom_8(int n_chan, byte *gs_restrict dst, const byte *gs_restrict backdrop,
525 const byte *gs_restrict src)
526 {
527 int delta_y = 0, test = 0;
528 int r[ART_MAX_CHAN];
529 int i;
530
531 /*
532 * Since we do not know the details of the blending color space, we are
533 * simply using the average as the luminosity. First we need the
534 * delta luminosity values.
535 */
536 for (i = 0; i < n_chan; i++)
537 delta_y += src[i] - backdrop[i];
538 delta_y = (delta_y + n_chan / 2) / n_chan;
539 for (i = 0; i < n_chan; i++) {
540 r[i] = backdrop[i] + delta_y;
541 test |= r[i];
542 }
543
544 if (test & 0x100) {
545 int y;
546 int scale;
547
548 /* Assume that the luminosity is simply the average of the backdrop. */
549 y = src[0];
550 for (i = 1; i < n_chan; i++)
551 y += src[i];
552 y = (y + n_chan / 2) / n_chan;
553
554 if (delta_y > 0) {
555 int max;
556
557 max = r[0];
558 for (i = 1; i < n_chan; i++)
559 max = max(max, r[i]);
560 scale = ((255 - y) << 16) / (max - y);
561 } else {
562 int min;
563
564 min = r[0];
565 for (i = 1; i < n_chan; i++)
566 min = min(min, r[i]);
567 scale = (y << 16) / (y - min);
568 }
569 for (i = 0; i < n_chan; i++)
570 r[i] = y + (((r[i] - y) * scale + 0x8000) >> 16);
571 }
572 for (i = 0; i < n_chan; i++)
573 dst[i] = r[i];
574 }
575
576 void
art_blend_luminosity_custom_16(int n_chan,uint16_t * gs_restrict dst,const uint16_t * gs_restrict backdrop,const uint16_t * gs_restrict src)577 art_blend_luminosity_custom_16(int n_chan, uint16_t *gs_restrict dst, const uint16_t *gs_restrict backdrop,
578 const uint16_t *gs_restrict src)
579 {
580 int delta_y = 0, test = 0;
581 int r[ART_MAX_CHAN];
582 int i;
583
584 /*
585 * Since we do not know the details of the blending color space, we are
586 * simply using the average as the luminosity. First we need the
587 * delta luminosity values.
588 */
589 for (i = 0; i < n_chan; i++)
590 delta_y += src[i] - backdrop[i];
591 delta_y = (delta_y + n_chan / 2) / n_chan;
592 for (i = 0; i < n_chan; i++) {
593 r[i] = backdrop[i] + delta_y;
594 test |= r[i];
595 }
596
597 if (test & 0x10000) {
598 int y;
599 int64_t scale;
600
601 /* Resort to 64bit to avoid calculations with scale overflowing */
602 /* Assume that the luminosity is simply the average of the backdrop. */
603 y = src[0];
604 for (i = 1; i < n_chan; i++)
605 y += src[i];
606 y = (y + n_chan / 2) / n_chan;
607
608 if (delta_y > 0) {
609 int max;
610
611 max = r[0];
612 for (i = 1; i < n_chan; i++)
613 max = max(max, r[i]);
614 scale = ((65535 - (int64_t)y) << 16) / (max - y);
615 } else {
616 int min;
617
618 min = r[0];
619 for (i = 1; i < n_chan; i++)
620 min = min(min, r[i]);
621 scale = (((int64_t)y) << 16) / (y - min);
622 }
623 for (i = 0; i < n_chan; i++)
624 r[i] = y + (((r[i] - y) * scale + 0x8000) >> 16);
625 }
626 for (i = 0; i < n_chan; i++)
627 dst[i] = r[i];
628 }
629
630 /*
631 * The PDF 1.4 spec. does not give the details of the math involved in the
632 * luminosity blending. All we are given is:
633 * "Creates a color with the luminance of the source color and the hue
634 * and saturation of the backdrop color. This produces an inverse
635 * effect to that of the Color mode."
636 * From section 7.4 of the PDF 1.5 specification, which is duscussing soft
637 * masks, we are given that, for CMYK, the luminosity is:
638 * Y = 0.30 (1 - C)(1 - K) + 0.59 (1 - M)(1 - K) + 0.11 (1 - Y)(1 - K)
639 * However the results of this equation do not match the results seen from
640 * Illustrator CS. Very different results are obtained if process gray
641 * (.5, .5, .5, 0) is blended over pure cyan, versus gray (0, 0, 0, .5) over
642 * the same pure cyan. The first gives a medium cyan while the later gives a
643 * medium gray. This routine seems to match Illustrator's actions. C, M and Y
644 * are treated similar to RGB in the previous routine and black is treated
645 * separately.
646 *
647 * Our component values have already been complemented, i.e. (1 - X).
648 */
649 void
art_blend_luminosity_cmyk_8(int n_chan,byte * gs_restrict dst,const byte * gs_restrict backdrop,const byte * gs_restrict src)650 art_blend_luminosity_cmyk_8(int n_chan, byte *gs_restrict dst, const byte *gs_restrict backdrop,
651 const byte *gs_restrict src)
652 {
653 int i;
654
655 /* Treat CMY the same as RGB. */
656 art_blend_luminosity_rgb_8(3, dst, backdrop, src);
657 for (i = 3; i < n_chan; i++)
658 dst[i] = src[i];
659 }
660
661 void
art_blend_luminosity_cmyk_16(int n_chan,uint16_t * gs_restrict dst,const uint16_t * gs_restrict backdrop,const uint16_t * gs_restrict src)662 art_blend_luminosity_cmyk_16(int n_chan, uint16_t *gs_restrict dst, const uint16_t *gs_restrict backdrop,
663 const uint16_t *gs_restrict src)
664 {
665 int i;
666
667 /* Treat CMY the same as RGB. */
668 art_blend_luminosity_rgb_16(3, dst, backdrop, src);
669 for (i = 3; i < n_chan; i++)
670 dst[i] = src[i];
671 }
672
673 void
art_blend_saturation_rgb_8(int n_chan,byte * gs_restrict dst,const byte * gs_restrict backdrop,const byte * gs_restrict src)674 art_blend_saturation_rgb_8(int n_chan, byte *gs_restrict dst, const byte *gs_restrict backdrop,
675 const byte *gs_restrict src)
676 {
677 int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
678 int rs = src[0], gs = src[1], bs = src[2];
679 int minb, maxb;
680 int mins, maxs;
681 int y;
682 int scale;
683 int r, g, b;
684
685 minb = rb < gb ? rb : gb;
686 minb = minb < bb ? minb : bb;
687 maxb = rb > gb ? rb : gb;
688 maxb = maxb > bb ? maxb : bb;
689 if (minb == maxb) {
690 /* backdrop has zero saturation, avoid divide by 0 */
691 dst[0] = gb;
692 dst[1] = gb;
693 dst[2] = gb;
694 return;
695 }
696
697 mins = rs < gs ? rs : gs;
698 mins = mins < bs ? mins : bs;
699 maxs = rs > gs ? rs : gs;
700 maxs = maxs > bs ? maxs : bs;
701
702 scale = ((maxs - mins) << 16) / (maxb - minb);
703 y = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8;
704 r = y + ((((rb - y) * scale) + 0x8000) >> 16);
705 g = y + ((((gb - y) * scale) + 0x8000) >> 16);
706 b = y + ((((bb - y) * scale) + 0x8000) >> 16);
707
708 if ((r | g | b) & 0x100) {
709 int scalemin, scalemax;
710 int min, max;
711
712 min = r < g ? r : g;
713 min = min < b ? min : b;
714 max = r > g ? r : g;
715 max = max > b ? max : b;
716
717 if (min < 0)
718 scalemin = (y << 16) / (y - min);
719 else
720 scalemin = 0x10000;
721
722 if (max > 255)
723 scalemax = ((255 - y) << 16) / (max - y);
724 else
725 scalemax = 0x10000;
726
727 scale = scalemin < scalemax ? scalemin : scalemax;
728 r = y + (((r - y) * scale + 0x8000) >> 16);
729 g = y + (((g - y) * scale + 0x8000) >> 16);
730 b = y + (((b - y) * scale + 0x8000) >> 16);
731 }
732
733 dst[0] = r;
734 dst[1] = g;
735 dst[2] = b;
736 }
737
738 void
art_blend_saturation_rgb_16(int n_chan,uint16_t * gs_restrict dst,const uint16_t * gs_restrict backdrop,const uint16_t * gs_restrict src)739 art_blend_saturation_rgb_16(int n_chan, uint16_t *gs_restrict dst, const uint16_t *gs_restrict backdrop,
740 const uint16_t *gs_restrict src)
741 {
742 int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
743 int rs = src[0], gs = src[1], bs = src[2];
744 int minb, maxb;
745 int mins, maxs;
746 int y;
747 int64_t scale;
748 int64_t r, g, b;
749
750 minb = rb < gb ? rb : gb;
751 minb = minb < bb ? minb : bb;
752 maxb = rb > gb ? rb : gb;
753 maxb = maxb > bb ? maxb : bb;
754 if (minb == maxb) {
755 /* backdrop has zero saturation, avoid divide by 0 */
756 dst[0] = gb;
757 dst[1] = gb;
758 dst[2] = gb;
759 return;
760 }
761
762 mins = rs < gs ? rs : gs;
763 mins = mins < bs ? mins : bs;
764 maxs = rs > gs ? rs : gs;
765 maxs = maxs > bs ? maxs : bs;
766
767 /* -65535 <= maxs - mins <= 65535 i.e. 17 bits */
768 /* -65535 <= maxb - minb <= 65535 i.e. 17 bits */
769 /* worst case, maxb - minb == +/- 1, so scale would be 33 bits. */
770 scale = (((int64_t)(maxs - mins)) << 16) / (maxb - minb);
771 /* 0 <= y <= 65535 */
772 y = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8;
773 r = y + ((((rb - y) * scale) + 0x8000) >> 16);
774 g = y + ((((gb - y) * scale) + 0x8000) >> 16);
775 b = y + ((((bb - y) * scale) + 0x8000) >> 16);
776
777 if ((r | g | b) & (int64_t)~0xffff) {
778 int64_t scalemin, scalemax;
779 int64_t min, max;
780
781 min = r < g ? r : g;
782 min = min < b ? min : b;
783 max = r > g ? r : g;
784 max = max > b ? max : b;
785
786 if (min < 0)
787 scalemin = (((int64_t)y) << 16) / (y - min);
788 else
789 scalemin = 0x10000;
790
791 if (max > 65535)
792 scalemax = (((int64_t)(65535 - y)) << 16) / (max - y);
793 else
794 scalemax = 0x10000;
795
796 scale = scalemin < scalemax ? scalemin : scalemax;
797 r = y + (((r - y) * scale + 0x8000) >> 16);
798 g = y + (((g - y) * scale + 0x8000) >> 16);
799 b = y + (((b - y) * scale + 0x8000) >> 16);
800 }
801
802 dst[0] = r;
803 dst[1] = g;
804 dst[2] = b;
805 }
806
807 void
art_blend_saturation_custom_8(int n_chan,byte * gs_restrict dst,const byte * gs_restrict backdrop,const byte * gs_restrict src)808 art_blend_saturation_custom_8(int n_chan, byte *gs_restrict dst, const byte *gs_restrict backdrop,
809 const byte *gs_restrict src)
810 {
811 int minb, maxb;
812 int mins, maxs;
813 int y;
814 int scale;
815 int r[ART_MAX_CHAN];
816 int test = 0;
817 int temp, i;
818
819 /* Determine min and max of the backdrop */
820 minb = maxb = temp = backdrop[0];
821 for (i = 1; i < n_chan; i++) {
822 temp = backdrop[i];
823 minb = min(minb, temp);
824 maxb = max(maxb, temp);
825 }
826
827 if (minb == maxb) {
828 /* backdrop has zero saturation, avoid divide by 0 */
829 for (i = 0; i < n_chan; i++)
830 dst[i] = temp;
831 return;
832 }
833
834 /* Determine min and max of the source */
835 mins = maxs = src[0];
836 for (i = 1; i < n_chan; i++) {
837 temp = src[i];
838 mins = min(minb, temp);
839 maxs = max(minb, temp);
840 }
841
842 scale = ((maxs - mins) << 16) / (maxb - minb);
843
844 /* Assume that the saturation is simply the average of the backdrop. */
845 y = backdrop[0];
846 for (i = 1; i < n_chan; i++)
847 y += backdrop[i];
848 y = (y + n_chan / 2) / n_chan;
849
850 /* Calculate the saturated values */
851 for (i = 0; i < n_chan; i++) {
852 r[i] = y + ((((backdrop[i] - y) * scale) + 0x8000) >> 16);
853 test |= r[i];
854 }
855
856 if (test & 0x100) {
857 int scalemin, scalemax;
858 int min, max;
859
860 /* Determine min and max of our blended values */
861 min = max = temp = r[0];
862 for (i = 1; i < n_chan; i++) {
863 temp = src[i];
864 min = min(min, temp);
865 max = max(max, temp);
866 }
867
868 if (min < 0)
869 scalemin = (y << 16) / (y - min);
870 else
871 scalemin = 0x10000;
872
873 if (max > 255)
874 scalemax = ((255 - y) << 16) / (max - y);
875 else
876 scalemax = 0x10000;
877
878 scale = scalemin < scalemax ? scalemin : scalemax;
879 for (i = 0; i < n_chan; i++)
880 r[i] = y + (((r[i] - y) * scale + 0x8000) >> 16);
881 }
882
883 for (i = 0; i < n_chan; i++)
884 dst[i] = r[i];
885 }
886
887 void
art_blend_saturation_custom_16(int n_chan,uint16_t * gs_restrict dst,const uint16_t * gs_restrict backdrop,const uint16_t * gs_restrict src)888 art_blend_saturation_custom_16(int n_chan, uint16_t *gs_restrict dst, const uint16_t *gs_restrict backdrop,
889 const uint16_t *gs_restrict src)
890 {
891 int minb, maxb;
892 int mins, maxs;
893 int y;
894 int scale;
895 int r[ART_MAX_CHAN];
896 int test = 0;
897 int temp, i;
898
899 /* FIXME: Test this */
900
901 /* Determine min and max of the backdrop */
902 minb = maxb = temp = backdrop[0];
903 for (i = 1; i < n_chan; i++) {
904 temp = backdrop[i];
905 minb = min(minb, temp);
906 maxb = max(maxb, temp);
907 }
908
909 if (minb == maxb) {
910 /* backdrop has zero saturation, avoid divide by 0 */
911 for (i = 0; i < n_chan; i++)
912 dst[i] = temp;
913 return;
914 }
915
916 /* Determine min and max of the source */
917 mins = maxs = src[0];
918 for (i = 1; i < n_chan; i++) {
919 temp = src[i];
920 mins = min(minb, temp);
921 maxs = max(minb, temp);
922 }
923
924 scale = ((maxs - mins) << 16) / (maxb - minb);
925
926 /* Assume that the saturation is simply the average of the backdrop. */
927 y = backdrop[0];
928 for (i = 1; i < n_chan; i++)
929 y += backdrop[i];
930 y = (y + n_chan / 2) / n_chan;
931
932 /* Calculate the saturated values */
933 for (i = 0; i < n_chan; i++) {
934 r[i] = y + ((((backdrop[i] - y) * scale) + 0x8000) >> 16);
935 test |= r[i];
936 }
937
938 if (test & 0x10000) {
939 int scalemin, scalemax;
940 int min, max;
941
942 /* Determine min and max of our blended values */
943 min = max = temp = r[0];
944 for (i = 1; i < n_chan; i++) {
945 temp = src[i];
946 min = min(min, temp);
947 max = max(max, temp);
948 }
949
950 if (min < 0)
951 scalemin = (y << 16) / (y - min);
952 else
953 scalemin = 0x10000;
954
955 if (max > 65535)
956 scalemax = ((65535 - y) << 16) / (max - y);
957 else
958 scalemax = 0x10000;
959
960 scale = scalemin < scalemax ? scalemin : scalemax;
961 for (i = 0; i < n_chan; i++)
962 r[i] = y + (((r[i] - y) * scale + 0x8000) >> 16);
963 }
964
965 for (i = 0; i < n_chan; i++)
966 dst[i] = r[i];
967 }
968
969 /* Our component values have already been complemented, i.e. (1 - X). */
970 void
art_blend_saturation_cmyk_8(int n_chan,byte * gs_restrict dst,const byte * gs_restrict backdrop,const byte * gs_restrict src)971 art_blend_saturation_cmyk_8(int n_chan, byte *gs_restrict dst, const byte *gs_restrict backdrop,
972 const byte *gs_restrict src)
973 {
974 int i;
975
976 /* Treat CMY the same as RGB */
977 art_blend_saturation_rgb_8(3, dst, backdrop, src);
978 for (i = 3; i < n_chan; i++)
979 dst[i] = backdrop[i];
980 }
981
982 void
art_blend_saturation_cmyk_16(int n_chan,uint16_t * gs_restrict dst,const uint16_t * gs_restrict backdrop,const uint16_t * gs_restrict src)983 art_blend_saturation_cmyk_16(int n_chan, uint16_t *gs_restrict dst, const uint16_t *gs_restrict backdrop,
984 const uint16_t *gs_restrict src)
985 {
986 int i;
987
988 /* Treat CMY the same as RGB */
989 art_blend_saturation_rgb_16(3, dst, backdrop, src);
990 for (i = 3; i < n_chan; i++)
991 dst[i] = backdrop[i];
992 }
993
994 /* This array consists of floor ((x - x * x / 255.0) * 65536 / 255 +
995 0.5) for x in [0..255]. */
996 const unsigned int art_blend_sq_diff_8[256] = {
997 0, 256, 510, 762, 1012, 1260, 1506, 1750, 1992, 2231, 2469, 2705,
998 2939, 3171, 3401, 3628, 3854, 4078, 4300, 4519, 4737, 4953, 5166,
999 5378, 5588, 5795, 6001, 6204, 6406, 6606, 6803, 6999, 7192, 7384,
1000 7573, 7761, 7946, 8129, 8311, 8490, 8668, 8843, 9016, 9188, 9357,
1001 9524, 9690, 9853, 10014, 10173, 10331, 10486, 10639, 10790, 10939,
1002 11086, 11232, 11375, 11516, 11655, 11792, 11927, 12060, 12191, 12320,
1003 12447, 12572, 12695, 12816, 12935, 13052, 13167, 13280, 13390, 13499,
1004 13606, 13711, 13814, 13914, 14013, 14110, 14205, 14297, 14388, 14477,
1005 14564, 14648, 14731, 14811, 14890, 14967, 15041, 15114, 15184, 15253,
1006 15319, 15384, 15446, 15507, 15565, 15622, 15676, 15729, 15779, 15827,
1007 15874, 15918, 15960, 16001, 16039, 16075, 16110, 16142, 16172, 16200,
1008 16227, 16251, 16273, 16293, 16311, 16327, 16341, 16354, 16364, 16372,
1009 16378, 16382, 16384, 16384, 16382, 16378, 16372, 16364, 16354, 16341,
1010 16327, 16311, 16293, 16273, 16251, 16227, 16200, 16172, 16142, 16110,
1011 16075, 16039, 16001, 15960, 15918, 15874, 15827, 15779, 15729, 15676,
1012 15622, 15565, 15507, 15446, 15384, 15319, 15253, 15184, 15114, 15041,
1013 14967, 14890, 14811, 14731, 14648, 14564, 14477, 14388, 14297, 14205,
1014 14110, 14013, 13914, 13814, 13711, 13606, 13499, 13390, 13280, 13167,
1015 13052, 12935, 12816, 12695, 12572, 12447, 12320, 12191, 12060, 11927,
1016 11792, 11655, 11516, 11375, 11232, 11086, 10939, 10790, 10639, 10486,
1017 10331, 10173, 10014, 9853, 9690, 9524, 9357, 9188, 9016, 8843, 8668,
1018 8490, 8311, 8129, 7946, 7761, 7573, 7384, 7192, 6999, 6803, 6606,
1019 6406, 6204, 6001, 5795, 5588, 5378, 5166, 4953, 4737, 4519, 4300,
1020 4078, 3854, 3628, 3401, 3171, 2939, 2705, 2469, 2231, 1992, 1750,
1021 1506, 1260, 1012, 762, 510, 256, 0
1022 };
1023
1024 /* This array consists of SoftLight (x, 255) - x, for values of x in
1025 the range [0..255] (normalized to [0..255 range). The original
1026 values were directly sampled from Adobe Illustrator 9. I've fit a
1027 quadratic spline to the SoftLight (x, 1) function as follows
1028 (normalized to [0..1] range):
1029
1030 Anchor point (0, 0)
1031 Control point (0.0755, 0.302)
1032 Anchor point (0.18, 0.4245)
1033 Control point (0.4263, 0.7131)
1034 Anchor point (1, 1)
1035
1036 I don't believe this is _exactly_ the function that Adobe uses,
1037 but it really should be close enough for all practical purposes. */
1038 const byte art_blend_soft_light_8[256] = {
1039 0, 3, 6, 9, 11, 14, 16, 19, 21, 23, 26, 28, 30, 32, 33, 35, 37, 39,
1040 40, 42, 43, 45, 46, 47, 48, 49, 51, 52, 53, 53, 54, 55, 56, 57, 57,
1041 58, 58, 59, 60, 60, 60, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 63,
1042 63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
1043 64, 64, 64, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 62, 62, 62,
1044 62, 62, 62, 62, 61, 61, 61, 61, 61, 61, 60, 60, 60, 60, 60, 59, 59,
1045 59, 59, 59, 58, 58, 58, 58, 57, 57, 57, 57, 56, 56, 56, 56, 55, 55,
1046 55, 55, 54, 54, 54, 54, 53, 53, 53, 52, 52, 52, 51, 51, 51, 51, 50,
1047 50, 50, 49, 49, 49, 48, 48, 48, 47, 47, 47, 46, 46, 46, 45, 45, 45,
1048 44, 44, 43, 43, 43, 42, 42, 42, 41, 41, 40, 40, 40, 39, 39, 39, 38,
1049 38, 37, 37, 37, 36, 36, 35, 35, 35, 34, 34, 33, 33, 33, 32, 32, 31,
1050 31, 31, 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, 26, 25, 25, 25, 24,
1051 24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 19, 19, 18, 18, 17, 17, 16,
1052 16, 15, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7,
1053 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0
1054 };
1055
1056 static forceinline void
art_blend_pixel_8_inline(byte * gs_restrict dst,const byte * gs_restrict backdrop,const byte * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)1057 art_blend_pixel_8_inline(byte *gs_restrict dst, const byte *gs_restrict backdrop,
1058 const byte *gs_restrict src, int n_chan, gs_blend_mode_t blend_mode,
1059 const pdf14_nonseparable_blending_procs_t * pblend_procs,
1060 pdf14_device *p14dev)
1061 {
1062 int i;
1063 byte b, s;
1064 bits32 t;
1065
1066 switch (blend_mode) {
1067 case BLEND_MODE_Normal:
1068 case BLEND_MODE_Compatible: /* todo */
1069 memcpy(dst, src, n_chan);
1070 break;
1071 case BLEND_MODE_Multiply:
1072 for (i = 0; i < n_chan; i++) {
1073 t = ((bits32) backdrop[i]) * ((bits32) src[i]);
1074 t += 0x80;
1075 t += (t >> 8);
1076 dst[i] = t >> 8;
1077 }
1078 break;
1079 case BLEND_MODE_Screen:
1080 for (i = 0; i < n_chan; i++) {
1081 t =
1082 ((bits32) (0xff - backdrop[i])) *
1083 ((bits32) (0xff - src[i]));
1084 t += 0x80;
1085 t += (t >> 8);
1086 dst[i] = 0xff - (t >> 8);
1087 }
1088 break;
1089 case BLEND_MODE_Overlay:
1090 for (i = 0; i < n_chan; i++) {
1091 b = backdrop[i];
1092 s = src[i];
1093 if (b < 0x80)
1094 t = 2 * ((bits32) b) * ((bits32) s);
1095 else
1096 t = 0xfe01 -
1097 2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
1098 t += 0x80;
1099 t += (t >> 8);
1100 dst[i] = t >> 8;
1101 }
1102 break;
1103 case BLEND_MODE_SoftLight:
1104 for (i = 0; i < n_chan; i++) {
1105 b = backdrop[i];
1106 s = src[i];
1107 if (s < 0x80) {
1108 t = (0xff - (s << 1)) * art_blend_sq_diff_8[b];
1109 t += 0x8000;
1110 dst[i] = b - (t >> 16);
1111 } else {
1112 t =
1113 ((s << 1) -
1114 0xff) * ((bits32) (art_blend_soft_light_8[b]));
1115 t += 0x80;
1116 t += (t >> 8);
1117 dst[i] = b + (t >> 8);
1118 }
1119 }
1120 break;
1121 case BLEND_MODE_HardLight:
1122 for (i = 0; i < n_chan; i++) {
1123 b = backdrop[i];
1124 s = src[i];
1125 if (s < 0x80)
1126 t = 2 * ((bits32) b) * ((bits32) s);
1127 else
1128 t = 0xfe01 -
1129 2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
1130 t += 0x80;
1131 t += (t >> 8);
1132 dst[i] = t >> 8;
1133 }
1134 break;
1135 case BLEND_MODE_ColorDodge:
1136 for (i = 0; i < n_chan; i++) {
1137 b = backdrop[i];
1138 s = 0xff - src[i];
1139 if (b == 0)
1140 dst[i] = 0;
1141 else if (b >= s)
1142 dst[i] = 0xff;
1143 else
1144 dst[i] = (0x1fe * b + s) / (s << 1);
1145 }
1146 break;
1147 case BLEND_MODE_ColorBurn:
1148 for (i = 0; i < n_chan; i++) {
1149 b = 0xff - backdrop[i];
1150 s = src[i];
1151 if (b == 0)
1152 dst[i] = 0xff;
1153 else if (b >= s)
1154 dst[i] = 0;
1155 else
1156 dst[i] = 0xff - (0x1fe * b + s) / (s << 1);
1157 }
1158 break;
1159 case BLEND_MODE_Darken:
1160 for (i = 0; i < n_chan; i++) {
1161 b = backdrop[i];
1162 s = src[i];
1163 dst[i] = b < s ? b : s;
1164 }
1165 break;
1166 case BLEND_MODE_Lighten:
1167 for (i = 0; i < n_chan; i++) {
1168 b = backdrop[i];
1169 s = src[i];
1170 dst[i] = b > s ? b : s;
1171 }
1172 break;
1173 case BLEND_MODE_Difference:
1174 for (i = 0; i < n_chan; i++) {
1175 art_s32 tmp;
1176
1177 tmp = ((art_s32) backdrop[i]) - ((art_s32) src[i]);
1178 dst[i] = tmp < 0 ? -tmp : tmp;
1179 }
1180 break;
1181 case BLEND_MODE_Exclusion:
1182 for (i = 0; i < n_chan; i++) {
1183 b = backdrop[i];
1184 s = src[i];
1185 t = ((bits32) (0xff - b)) * ((bits32) s) +
1186 ((bits32) b) * ((bits32) (0xff - s));
1187 t += 0x80;
1188 t += (t >> 8);
1189 dst[i] = t >> 8;
1190 }
1191 break;
1192 case BLEND_MODE_Luminosity:
1193 pblend_procs->blend_luminosity(n_chan, dst, backdrop, src);
1194 break;
1195 case BLEND_MODE_Color:
1196 pblend_procs->blend_luminosity(n_chan, dst, src, backdrop);
1197 break;
1198 case BLEND_MODE_Saturation:
1199 pblend_procs->blend_saturation(n_chan, dst, backdrop, src);
1200 break;
1201 case BLEND_MODE_Hue:
1202 {
1203 byte tmp[4];
1204
1205 pblend_procs->blend_luminosity(n_chan, tmp, src, backdrop);
1206 pblend_procs->blend_saturation(n_chan, dst, tmp, backdrop);
1207 }
1208 break;
1209 /* This mode requires information about the color space as
1210 * well as the overprint mode. See Section 7.6.3 of
1211 * PDF specification */
1212 case BLEND_MODE_CompatibleOverprint:
1213 {
1214 gx_color_index drawn_comps = p14dev->op_state == PDF14_OP_STATE_FILL ?
1215 p14dev->drawn_comps_fill : p14dev->drawn_comps_stroke;
1216 bool opm = p14dev->op_state == PDF14_OP_STATE_FILL ?
1217 p14dev->effective_overprint_mode : p14dev->stroke_effective_op_mode;
1218 gx_color_index comps;
1219 /* If overprint mode is true and the current color space and
1220 * the group color space are CMYK (or CMYK and spots), then
1221 * B(cb, cs) = cs if cs is nonzero otherwise it is cb for CMYK.
1222 * Spot colors are always set to cb. The nice thing about the PDF14
1223 * compositor is that it always has CMYK + spots with spots after
1224 * the CMYK colorants (see gx_put_blended_image_cmykspot).
1225 * that way we don't have to worry about where the process colors
1226 * are.
1227
1228 * Note: The spec claims the following:
1229
1230 If the overprint mode is 1 (nonzero overprint mode) and the
1231 current color space and group color space are both DeviceCMYK,
1232 then only process color components with nonzero values replace
1233 the corresponding component values of the backdrop. All other
1234 component values leave the existing backdrop value unchanged.
1235 That is, the value of the blend function B(Cb,Cs) is the source
1236 component cs for any process (DeviceCMYK) color component whose
1237 (subtractive) color value is nonzero; otherwise it is the
1238 backdrop component cb. For spot color components, the value is
1239 always cb.
1240
1241 The equation for compositing is
1242
1243 ar*Cr = (1-as)*Cb + as*[(1-ab)*Cs+ab*B(Cb,Cs)]
1244
1245 Now if I simply set B(cb,cs) to cb for the case when the
1246 DevieCMYK value (with opm true) is zero I get
1247
1248 ar*Cr = (1-as)*Cb + as*[(1-ab)*Cs+ab*Cb]
1249
1250 But what I am seeing with AR is
1251 ar*Cr = (1-as)*Cb + as*[(1-ab)*Cb+ab*Cb] = (1-as)*Cb + as*Cb = Cb
1252 which is what I think we want.
1253
1254 The description in the spec is confusing as it says
1255 "then only process color components with nonzero values replace
1256 the corresponding component values of the backdrop. All other
1257 component values leave the existing backdrop value unchanged"
1258
1259 which makes sense for overprinting,
1260
1261 vs.
1262
1263 "That is, the value of the blend function B(Cb,Cs) is the source
1264 component cs for any process (DeviceCMYK) color component whose
1265 (subtractive) color value is nonzero; otherwise it is the
1266 backdrop component cb."
1267
1268 Which is NOT the same thing as leaving the backdrop unchanged
1269 with the compositing equation
1270 ar*Cr = (1-as)*Cb + as*[(1-ab)*Cs+ab*B(Cb,Cs)]
1271
1272 For this to work, we need to carry out the operation during
1273 the mixing of the source with the blend result. Essentially
1274 replacing that mixing with the color we have here.
1275 */
1276 if (opm && p14dev->color_info.num_components > 3
1277 && !(p14dev->ctx->additive)) {
1278 for (i = 0, comps = drawn_comps; i < 4; i++, comps >>= 1) {
1279 if ((comps & 0x1) != 0) {
1280 dst[i] = src[i];
1281 } else {
1282 dst[i] = backdrop[i];
1283 }
1284 }
1285 for (i = 4; i < n_chan; i++) {
1286 dst[i] = backdrop[i];
1287 }
1288 } else {
1289 /* Otherwise we have B(cb, cs)= cs if cs is specified in
1290 * the current color space all other color should get cb.
1291 * Essentially the standard overprint case. */
1292 for (i = 0, comps = drawn_comps; i < n_chan; ++i, comps >>= 1) {
1293 if ((comps & 0x1) != 0) {
1294 dst[i] = src[i];
1295 } else {
1296 dst[i] = backdrop[i];
1297 }
1298 }
1299 }
1300 break;
1301 }
1302 default:
1303 #ifndef GS_THREADSAFE
1304 dlprintf1("art_blend_pixel_8: blend mode %d not implemented\n",
1305 blend_mode);
1306 #endif
1307 memcpy(dst, src, n_chan);
1308 break;
1309 }
1310 }
1311
1312 void
art_blend_pixel_8(byte * gs_restrict dst,const byte * gs_restrict backdrop,const byte * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)1313 art_blend_pixel_8(byte *gs_restrict dst, const byte *gs_restrict backdrop,
1314 const byte *gs_restrict src, int n_chan, gs_blend_mode_t blend_mode,
1315 const pdf14_nonseparable_blending_procs_t * pblend_procs,
1316 pdf14_device *p14dev)
1317 {
1318 art_blend_pixel_8_inline(dst, backdrop, src, n_chan, blend_mode,
1319 pblend_procs, p14dev);
1320 }
1321
1322 static forceinline void
art_blend_pixel_16_inline(uint16_t * gs_restrict dst,const uint16_t * gs_restrict backdrop,const uint16_t * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)1323 art_blend_pixel_16_inline(uint16_t *gs_restrict dst, const uint16_t *gs_restrict backdrop,
1324 const uint16_t *gs_restrict src, int n_chan, gs_blend_mode_t blend_mode,
1325 const pdf14_nonseparable_blending_procs_t * pblend_procs,
1326 pdf14_device *p14dev)
1327 {
1328 int i;
1329 int b, s;
1330 bits32 t;
1331
1332 switch (blend_mode) {
1333 case BLEND_MODE_Normal:
1334 case BLEND_MODE_Compatible: /* todo */
1335 memcpy(dst, src, n_chan*2);
1336 break;
1337 case BLEND_MODE_Multiply:
1338 for (i = 0; i < n_chan; i++) {
1339 t = backdrop[i];
1340 t += t >> 15;
1341 t = t * src[i] + 0x8000;
1342 dst[i] = t >> 16;
1343 }
1344 break;
1345 case BLEND_MODE_Screen:
1346 for (i = 0; i < n_chan; i++) {
1347 t = backdrop[i];
1348 t += t >> 15;
1349 t = (0x10000-t) * (0xffff - src[i]) + 0x8000;
1350 dst[i] = 0xffff - (t >> 16);
1351 }
1352 break;
1353 case BLEND_MODE_Overlay:
1354 for (i = 0; i < n_chan; i++) {
1355 b = backdrop[i];
1356 b += b >> 15;
1357 s = src[i];
1358 if (b < 0x8000)
1359 t = (2 * b * s);
1360 else
1361 t = 0xffff0000 -
1362 2 * (0x10000 - b) * (0xffff - s);
1363 t = (t+0x8000)>>16;
1364 dst[i] = t;
1365 }
1366 break;
1367 case BLEND_MODE_SoftLight:
1368 for (i = 0; i < n_chan; i++) {
1369 b = backdrop[i];
1370 s = src[i];
1371 if (s < 0x8000) {
1372 unsigned int b2 = ((unsigned int)(b * (b + (b>>15))))>>16;
1373 b2 = b - b2;
1374 b2 += b2>>15;
1375 t = ((0xffff - (s << 1)) * b2) + 0x8000;
1376 dst[i] = b - (t >> 16);
1377 } else {
1378 #define art_blend_soft_light_16(B) (art_blend_soft_light_8[(B)>>8]*0x101)
1379 t = ((s << 1) - 0xffff) * art_blend_soft_light_16(b) + 0x8000;
1380 dst[i] = b + (t >> 16);
1381 }
1382 }
1383 break;
1384 case BLEND_MODE_HardLight:
1385 for (i = 0; i < n_chan; i++) {
1386 b = backdrop[i];
1387 b += b>>15;
1388 s = src[i];
1389 if (s < 0x8000)
1390 t = 2 * b * s;
1391 else
1392 t = 0xffff0000 - 2 * (0x10000 - b) * (0xffff - s);
1393 t += 0x8000;
1394 dst[i] = t >> 16;
1395 }
1396 break;
1397 case BLEND_MODE_ColorDodge:
1398 for (i = 0; i < n_chan; i++) {
1399 b = backdrop[i];
1400 s = 0xffff - src[i];
1401 if (b == 0)
1402 dst[i] = 0;
1403 else if (b >= s)
1404 dst[i] = 0xffff;
1405 else
1406 dst[i] = ((unsigned int)(0xffff * b + (s>>1))) / s;
1407 }
1408 break;
1409 case BLEND_MODE_ColorBurn:
1410 for (i = 0; i < n_chan; i++) {
1411 b = 0xffff - backdrop[i];
1412 s = src[i];
1413 if (b == 0)
1414 dst[i] = 0xffff;
1415 else if (b >= s)
1416 dst[i] = 0;
1417 else
1418 dst[i] = 0xffff - ((unsigned int)(0xffff * b + (s>>1))) / s;
1419 }
1420 break;
1421 case BLEND_MODE_Darken:
1422 for (i = 0; i < n_chan; i++) {
1423 b = backdrop[i];
1424 s = src[i];
1425 dst[i] = b < s ? b : s;
1426 }
1427 break;
1428 case BLEND_MODE_Lighten:
1429 for (i = 0; i < n_chan; i++) {
1430 b = backdrop[i];
1431 s = src[i];
1432 dst[i] = b > s ? b : s;
1433 }
1434 break;
1435 case BLEND_MODE_Difference:
1436 for (i = 0; i < n_chan; i++) {
1437 art_s32 tmp;
1438
1439 tmp = ((art_s32) backdrop[i]) - ((art_s32) src[i]);
1440 dst[i] = tmp < 0 ? -tmp : tmp;
1441 }
1442 break;
1443 case BLEND_MODE_Exclusion:
1444 for (i = 0; i < n_chan; i++) {
1445 b = backdrop[i];
1446 b += b>>15;
1447 s = src[i];
1448 t = (0x10000 - b) * s + b * (0xffff - s) + 0x8000;
1449 dst[i] = t >> 16;
1450 }
1451 break;
1452 case BLEND_MODE_Luminosity:
1453 pblend_procs->blend_luminosity16(n_chan, dst, backdrop, src);
1454 break;
1455 case BLEND_MODE_Color:
1456 pblend_procs->blend_luminosity16(n_chan, dst, src, backdrop);
1457 break;
1458 case BLEND_MODE_Saturation:
1459 pblend_procs->blend_saturation16(n_chan, dst, backdrop, src);
1460 break;
1461 case BLEND_MODE_Hue:
1462 {
1463 uint16_t tmp[4];
1464
1465 pblend_procs->blend_luminosity16(n_chan, tmp, src, backdrop);
1466 pblend_procs->blend_saturation16(n_chan, dst, tmp, backdrop);
1467 }
1468 break;
1469 /* This mode requires information about the color space as
1470 * well as the overprint mode. See Section 7.6.3 of
1471 * PDF specification */
1472 case BLEND_MODE_CompatibleOverprint:
1473 {
1474 gx_color_index drawn_comps = p14dev->op_state == PDF14_OP_STATE_FILL ?
1475 p14dev->drawn_comps_fill : p14dev->drawn_comps_stroke;
1476 bool opm = p14dev->op_state == PDF14_OP_STATE_FILL ?
1477 p14dev->effective_overprint_mode : p14dev->stroke_effective_op_mode;
1478 gx_color_index comps;
1479 /* If overprint mode is true and the current color space and
1480 * the group color space are CMYK (or CMYK and spots), then
1481 * B(cb, cs) = cs if cs is nonzero otherwise it is cb for CMYK.
1482 * Spot colors are always set to cb. The nice thing about the PDF14
1483 * compositor is that it always has CMYK + spots with spots after
1484 * the CMYK colorants (see gx_put_blended_image_cmykspot).
1485 * that way we don't have to worry about where the process colors
1486 * are. */
1487 if (opm && p14dev->color_info.num_components > 3
1488 && !(p14dev->ctx->additive)) {
1489 for (i = 0, comps = drawn_comps; i < 4; i++, comps >>= 1) {
1490 if ((comps & 0x1) != 0) {
1491 dst[i] = src[i];
1492 } else {
1493 dst[i] = backdrop[i];
1494 }
1495 }
1496 for (i = 4; i < n_chan; i++) {
1497 dst[i] = backdrop[i];
1498 }
1499 } else {
1500 /* Otherwise we have B(cb, cs)= cs if cs is specified in
1501 * the current color space all other color should get cb.
1502 * Essentially the standard overprint case. */
1503 for (i = 0, comps = drawn_comps; i < n_chan; ++i, comps >>= 1) {
1504 if ((comps & 0x1) != 0) {
1505 dst[i] = src[i];
1506 } else {
1507 dst[i] = backdrop[i];
1508 }
1509 }
1510 }
1511 break;
1512 }
1513 default:
1514 #ifndef GS_THREADSAFE
1515 dlprintf1("art_blend_pixel_16: blend mode %d not implemented\n",
1516 blend_mode);
1517 #endif
1518 memcpy(dst, src, n_chan*2);
1519 break;
1520 }
1521 }
1522
1523 void
art_blend_pixel_16(uint16_t * gs_restrict dst,const uint16_t * gs_restrict backdrop,const uint16_t * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)1524 art_blend_pixel_16(uint16_t *gs_restrict dst, const uint16_t *gs_restrict backdrop,
1525 const uint16_t *gs_restrict src, int n_chan, gs_blend_mode_t blend_mode,
1526 const pdf14_nonseparable_blending_procs_t * pblend_procs,
1527 pdf14_device *p14dev)
1528 {
1529 art_blend_pixel_16_inline(dst, backdrop, src, n_chan, blend_mode,
1530 pblend_procs, p14dev);
1531 }
1532
1533 #ifdef UNUSED
1534 byte
art_pdf_union_8(byte alpha1,byte alpha2)1535 art_pdf_union_8(byte alpha1, byte alpha2)
1536 {
1537 int tmp;
1538
1539 tmp = (0xff - alpha1) * (0xff - alpha2) + 0x80;
1540 return 0xff - ((tmp + (tmp >> 8)) >> 8);
1541 }
1542 #endif
1543
1544 static byte*
art_pdf_knockout_composite_pixel_alpha_8(byte * gs_restrict backdrop,byte tos_shape,byte * gs_restrict dst,byte * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)1545 art_pdf_knockout_composite_pixel_alpha_8(byte *gs_restrict backdrop, byte tos_shape,
1546 byte *gs_restrict dst, byte *gs_restrict src, int n_chan,
1547 gs_blend_mode_t blend_mode,
1548 const pdf14_nonseparable_blending_procs_t * pblend_procs,
1549 pdf14_device *p14dev)
1550 {
1551 byte a_b, a_s;
1552 unsigned int a_r;
1553 int tmp;
1554 int src_scale;
1555 int c_b, c_s;
1556 int i;
1557
1558 a_s = src[n_chan];
1559 a_b = backdrop[n_chan];
1560 if (a_s == 0) {
1561 /* source alpha is zero, if we have a src shape value there then copy
1562 the backdrop, else leave it alone */
1563 if (tos_shape)
1564 return backdrop;
1565 return NULL;
1566 }
1567
1568 /* In this case a_s is not zero */
1569 if (a_b == 0) {
1570 /* backdrop alpha is zero but not source alpha, just copy source pixels and
1571 avoid computation. */
1572 return src;
1573 }
1574
1575 /* Result alpha is Union of backdrop and source alpha */
1576 tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
1577 a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
1578 /* todo: verify that a_r is nonzero in all cases */
1579
1580 /* Compute a_s / a_r in 16.16 format */
1581 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
1582
1583 if (blend_mode == BLEND_MODE_Normal) {
1584 /* Do simple compositing of source over backdrop */
1585 for (i = 0; i < n_chan; i++) {
1586 c_s = src[i];
1587 c_b = backdrop[i];
1588 tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
1589 dst[i] = tmp >> 16;
1590 }
1591 } else {
1592 /* Do compositing with blending */
1593 byte blend[ART_MAX_CHAN];
1594
1595 art_blend_pixel_8(blend, backdrop, src, n_chan, blend_mode, pblend_procs,
1596 p14dev);
1597 for (i = 0; i < n_chan; i++) {
1598 int c_bl; /* Result of blend function */
1599 int c_mix; /* Blend result mixed with source color */
1600
1601 c_s = src[i];
1602 c_b = backdrop[i];
1603 c_bl = blend[i];
1604 tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
1605 c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
1606 tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
1607 dst[i] = tmp >> 16;
1608 }
1609 }
1610 dst[n_chan] = a_r;
1611 return dst;
1612 }
1613
1614 static forceinline uint16_t*
art_pdf_knockout_composite_pixel_alpha_16(uint16_t * gs_restrict backdrop,uint16_t tos_shape,uint16_t * gs_restrict dst,uint16_t * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)1615 art_pdf_knockout_composite_pixel_alpha_16(uint16_t *gs_restrict backdrop, uint16_t tos_shape, uint16_t *gs_restrict dst,
1616 uint16_t *gs_restrict src, int n_chan, gs_blend_mode_t blend_mode,
1617 const pdf14_nonseparable_blending_procs_t * pblend_procs,
1618 pdf14_device *p14dev)
1619 {
1620 int a_b, a_s;
1621 unsigned int a_r;
1622 int tmp;
1623 int src_scale;
1624 int c_b, c_s;
1625 int i;
1626
1627 a_s = src[n_chan];
1628 a_b = backdrop[n_chan];
1629 if (a_s == 0) {
1630 /* source alpha is zero, if we have a src shape value there then copy
1631 the backdrop, else leave it alone */
1632 if (tos_shape)
1633 return backdrop;
1634 return NULL;
1635 }
1636
1637 /* In this case a_s is not zero */
1638 if (a_b == 0) {
1639 /* backdrop alpha is zero but not source alpha, just copy source pixels and
1640 avoid computation. */
1641 return src;
1642 }
1643
1644 /* Result alpha is Union of backdrop and source alpha */
1645 a_b += a_b>>15;
1646 tmp = (0x10000 - a_b) * (0xffff - a_s) + 0x8000;
1647 a_r = 0xffff - (tmp >> 16);
1648 /* todo: verify that a_r is nonzero in all cases */
1649
1650 /* Compute a_s / a_r in 16.16 format */
1651 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
1652
1653 src_scale >>= 1; /* Lose a bit to avoid overflow */
1654 if (blend_mode == BLEND_MODE_Normal) {
1655 /* Do simple compositing of source over backdrop */
1656 for (i = 0; i < n_chan; i++) {
1657 c_s = src[i];
1658 c_b = backdrop[i];
1659 tmp = src_scale * (c_s - c_b) + 0x4000;
1660 dst[i] = c_b + (tmp >> 15);
1661 }
1662 } else {
1663 /* Do compositing with blending */
1664 uint16_t blend[ART_MAX_CHAN];
1665
1666 art_blend_pixel_16(blend, backdrop, src, n_chan, blend_mode, pblend_procs,
1667 p14dev);
1668 a_b >>= 1; /* Lose a bit to avoid overflow */
1669 for (i = 0; i < n_chan; i++) {
1670 int c_bl; /* Result of blend function */
1671 int c_mix; /* Blend result mixed with source color */
1672
1673 c_s = src[i];
1674 c_b = backdrop[i];
1675 c_bl = blend[i];
1676 tmp = a_b * (c_bl - c_s) + 0x4000;
1677 c_mix = c_s + (tmp >> 15);
1678 tmp = src_scale * (c_mix - c_b) + 0x4000;
1679 dst[i] = c_b + (tmp >> 15);
1680 }
1681 }
1682 dst[n_chan] = a_r;
1683 return dst;
1684 }
1685
1686 void
art_pdf_composite_pixel_alpha_8(byte * gs_restrict dst,const byte * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,int first_spot,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)1687 art_pdf_composite_pixel_alpha_8(byte *gs_restrict dst, const byte *gs_restrict src, int n_chan,
1688 gs_blend_mode_t blend_mode, int first_spot,
1689 const pdf14_nonseparable_blending_procs_t * pblend_procs, pdf14_device *p14dev)
1690 {
1691 byte a_b, a_s;
1692 unsigned int a_r;
1693 int tmp;
1694 int src_scale;
1695 int c_b, c_s;
1696 int i;
1697
1698 a_s = src[n_chan];
1699 if (a_s == 0) {
1700 /* source alpha is zero, avoid all computations and possible
1701 divide by zero errors. */
1702 return;
1703 }
1704
1705 a_b = dst[n_chan];
1706 if (a_b == 0) {
1707 /* backdrop alpha is zero, just copy source pixels and avoid
1708 computation. */
1709
1710 memcpy (dst, src, n_chan + 1);
1711
1712 return;
1713 }
1714
1715 /* Result alpha is Union of backdrop and source alpha */
1716 tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
1717 a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
1718 /* todo: verify that a_r is nonzero in all cases */
1719
1720 /* Compute a_s / a_r in 16.16 format */
1721 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
1722
1723 if (first_spot != 0) {
1724 /* Do compositing with blending */
1725 byte blend[ART_MAX_CHAN];
1726
1727 art_blend_pixel_8(blend, dst, src, first_spot, blend_mode, pblend_procs, p14dev);
1728 for (i = 0; i < first_spot; i++) {
1729 int c_bl; /* Result of blend function */
1730 int c_mix; /* Blend result mixed with source color */
1731
1732 c_s = src[i];
1733 c_b = dst[i];
1734 c_bl = blend[i];
1735 tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
1736 c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
1737 tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
1738 dst[i] = tmp >> 16;
1739 }
1740 }
1741 dst[n_chan] = a_r;
1742
1743 dst += first_spot;
1744 src += first_spot;
1745 n_chan -= first_spot;
1746 if (n_chan == 0)
1747 return;
1748
1749 /* Do simple compositing of source over backdrop */
1750 for (i = 0; i < n_chan; i++) {
1751 c_s = src[i];
1752 c_b = dst[i];
1753 tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
1754 dst[i] = tmp >> 16;
1755 }
1756 }
1757
1758 void
art_pdf_composite_pixel_alpha_16(uint16_t * gs_restrict dst,const uint16_t * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,int first_spot,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)1759 art_pdf_composite_pixel_alpha_16(uint16_t *gs_restrict dst, const uint16_t *gs_restrict src, int n_chan,
1760 gs_blend_mode_t blend_mode, int first_spot,
1761 const pdf14_nonseparable_blending_procs_t * pblend_procs, pdf14_device *p14dev)
1762 {
1763 int a_b, a_s;
1764 unsigned int a_r;
1765 unsigned int tmp;
1766 int src_scale;
1767 int c_b, c_s;
1768 int i;
1769
1770 a_s = src[n_chan];
1771 if (a_s == 0) {
1772 /* source alpha is zero, avoid all computations and possible
1773 divide by zero errors. */
1774 return;
1775 }
1776
1777 a_b = dst[n_chan];
1778 if (a_b == 0) {
1779 /* backdrop alpha is zero, just copy source pixels and avoid
1780 computation. */
1781
1782 memcpy (dst, src, (n_chan + 1)*2);
1783
1784 return;
1785 }
1786
1787 /* Result alpha is Union of backdrop and source alpha */
1788 tmp = (0xffff - a_b) * (0xffff - a_s) + 0x8000;
1789 a_r = 0xffff - (((tmp >> 16) + tmp) >> 16);
1790 /* todo: verify that a_r is nonzero in all cases */
1791
1792 /* Compute a_s / a_r in 16.16 format */
1793 src_scale = ((unsigned int)((a_s << 16) + (a_r >> 1))) / a_r;
1794
1795 src_scale >>= 1; /* Lose a bit to avoid overflow */
1796 if (first_spot != 0) {
1797 /* Do compositing with blending */
1798 uint16_t blend[ART_MAX_CHAN];
1799
1800 a_b >>= 1; /* Lose a bit to avoid overflow */
1801 art_blend_pixel_16(blend, dst, src, first_spot, blend_mode, pblend_procs, p14dev);
1802 for (i = 0; i < first_spot; i++) {
1803 int c_bl; /* Result of blend function */
1804 int c_mix; /* Blend result mixed with source color */
1805
1806 c_s = src[i];
1807 c_b = dst[i];
1808 c_bl = blend[i];
1809 tmp = a_b * (c_bl - ((int)c_s)) + 0x4000;
1810 c_mix = c_s + (((tmp >> 16) + tmp) >> 15);
1811 tmp = src_scale * (c_mix - c_b) + 0x4000;
1812 dst[i] = c_b + (tmp >> 15);
1813 }
1814 }
1815 dst[n_chan] = a_r;
1816
1817 dst += first_spot;
1818 src += first_spot;
1819 n_chan -= first_spot;
1820 if (n_chan == 0)
1821 return;
1822
1823 /* Do simple compositing of source over backdrop */
1824 for (i = 0; i < n_chan; i++) {
1825 c_s = src[i];
1826 c_b = dst[i];
1827 tmp = src_scale * (c_s - c_b) + 0x4000;
1828 dst[i] = c_b + (tmp >> 15);
1829 }
1830 }
1831
1832 static forceinline byte *
art_pdf_composite_pixel_alpha_8_inline(byte * gs_restrict dst,byte * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,int first_spot,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)1833 art_pdf_composite_pixel_alpha_8_inline(byte *gs_restrict dst, byte *gs_restrict src, int n_chan,
1834 gs_blend_mode_t blend_mode, int first_spot,
1835 const pdf14_nonseparable_blending_procs_t * pblend_procs, pdf14_device *p14dev)
1836 {
1837 byte a_b, a_s;
1838 unsigned int a_r;
1839 int tmp;
1840 int src_scale;
1841 int c_b, c_s;
1842 int i;
1843
1844 a_s = src[n_chan];
1845 if (a_s == 0) {
1846 /* source alpha is zero, avoid all computations and possible
1847 divide by zero errors. */
1848 return NULL; /* No change to destination at all! */
1849 }
1850
1851 a_b = dst[n_chan];
1852 if (a_b == 0) {
1853 /* backdrop alpha is zero, just copy source pixels and avoid
1854 computation. */
1855 return src;
1856 }
1857
1858 /* Result alpha is Union of backdrop and source alpha */
1859 tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
1860 a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
1861 /* todo: verify that a_r is nonzero in all cases */
1862
1863 /* Compute a_s / a_r in 16.16 format */
1864 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
1865
1866 if (first_spot != 0) {
1867 /* Do compositing with blending */
1868 byte blend[ART_MAX_CHAN];
1869
1870 art_blend_pixel_8_inline(blend, dst, src, first_spot, blend_mode, pblend_procs, p14dev);
1871
1872 if (blend_mode == BLEND_MODE_CompatibleOverprint) {
1873 for (i = 0; i < first_spot; i++) {
1874 /* No mixing. Blend[i] is backdrop or src */
1875 tmp = (dst[i] << 16) + src_scale * (blend[i] - dst[i]) + 0x8000;
1876 dst[i] = tmp >> 16;
1877 }
1878 } else {
1879 for (i = 0; i < first_spot; i++) {
1880 int c_bl; /* Result of blend function */
1881 int c_mix; /* Blend result mixed with source color */
1882
1883 c_s = src[i];
1884 c_b = dst[i];
1885 c_bl = blend[i];
1886 tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
1887 c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
1888 tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
1889 dst[i] = tmp >> 16;
1890 }
1891 }
1892 }
1893 dst[n_chan] = a_r;
1894
1895 n_chan -= first_spot;
1896 if (n_chan == 0)
1897 return dst;
1898 dst += first_spot;
1899 src += first_spot;
1900
1901 /* Do simple compositing of source over backdrop */
1902 for (i = 0; i < n_chan; i++) {
1903 c_s = src[i];
1904 c_b = dst[i];
1905 tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
1906 dst[i] = tmp >> 16;
1907 }
1908 return dst - first_spot;
1909 }
1910
1911 static forceinline uint16_t *
art_pdf_composite_pixel_alpha_16_inline(uint16_t * gs_restrict dst,uint16_t * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,int first_spot,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)1912 art_pdf_composite_pixel_alpha_16_inline(uint16_t *gs_restrict dst, uint16_t *gs_restrict src, int n_chan,
1913 gs_blend_mode_t blend_mode, int first_spot,
1914 const pdf14_nonseparable_blending_procs_t * pblend_procs, pdf14_device *p14dev)
1915 {
1916 int a_b, a_s;
1917 unsigned int a_r;
1918 int tmp;
1919 int src_scale;
1920 int c_b, c_s;
1921 int i;
1922
1923 a_s = src[n_chan];
1924 if (a_s == 0) {
1925 /* source alpha is zero, avoid all computations and possible
1926 divide by zero errors. */
1927 return NULL; /* No change to destination at all! */
1928 }
1929
1930 a_b = dst[n_chan];
1931 if (a_b == 0) {
1932 /* backdrop alpha is zero, just copy source pixels and avoid
1933 computation. */
1934 return src;
1935 }
1936
1937 /* Result alpha is Union of backdrop and source alpha */
1938 a_b += a_b>>15; /* a_b in 0...0x10000 range */
1939 tmp = (0x10000 - a_b) * (0xffff - a_s) + 0x8000;
1940 a_r = 0xffff - (((unsigned int)tmp) >> 16); /* a_r in 0...0xffff range */
1941 /* todo: verify that a_r is nonzero in all cases */
1942
1943 /* Compute a_s / a_r in 16.16 format */
1944 src_scale = ((unsigned int)((a_s << 16) + (a_r >> 1))) / a_r;
1945
1946 src_scale >>= 1; /* Lose a bit to avoid overflow */
1947 if (first_spot != 0) {
1948 /* Do compositing with blending */
1949 uint16_t blend[ART_MAX_CHAN];
1950
1951 art_blend_pixel_16_inline(blend, dst, src, first_spot, blend_mode, pblend_procs, p14dev);
1952
1953 if (blend_mode == BLEND_MODE_CompatibleOverprint) {
1954 for (i = 0; i < first_spot; i++) {
1955 /* No mixing. Blend[i] is backdrop or src */
1956 dst[i] += (src_scale * (blend[i] - dst[i]) + 0x4000) >> 15;
1957 }
1958 } else {
1959 a_b >>= 1; /* Lose a bit to avoid overflow */
1960 for (i = 0; i < first_spot; i++) {
1961 int c_bl; /* Result of blend function */
1962
1963 c_s = src[i];
1964 c_b = dst[i];
1965 c_bl = blend[i];
1966
1967 c_s += (a_b * (c_bl - c_s) + 0x4000) >> 15;
1968 c_b += (src_scale * (c_s - c_b) + 0x4000) >> 15;
1969 dst[i] = c_b;
1970 }
1971 }
1972 }
1973 dst[n_chan] = a_r;
1974
1975 n_chan -= first_spot;
1976 if (n_chan == 0)
1977 return dst;
1978 dst += first_spot;
1979 src += first_spot;
1980
1981 /* Do simple compositing of source over backdrop */
1982 for (i = 0; i < n_chan; i++) {
1983 c_s = src[i];
1984 c_b = dst[i];
1985 c_b += (src_scale * (c_s - c_b) + 0x4000)>>15;
1986 dst[i] = c_b;
1987 }
1988 return dst - first_spot;
1989 }
1990
1991 /**
1992 * art_pdf_composite_pixel_alpha_8_fast_mono: Tweaked version of art_pdf_composite_pixel_alpha_8_fast.
1993 * Same args, except n_chan, which is assumed to be 1:
1994 * @stride: stride between dst pixel values.
1995 * @p14dev: pdf14 device
1996 * Dst data is therefore in dst[i * stride] for 0 <= i <= 1.
1997 * Called with the guarantee that dst[stride] != 0, src[1] != 0, and that blend_mode != Normal
1998 */
1999 static inline void
art_pdf_composite_pixel_alpha_8_fast_mono(byte * gs_restrict dst,const byte * gs_restrict src,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs,int stride,pdf14_device * p14dev)2000 art_pdf_composite_pixel_alpha_8_fast_mono(byte *gs_restrict dst, const byte *gs_restrict src,
2001 gs_blend_mode_t blend_mode,
2002 const pdf14_nonseparable_blending_procs_t * pblend_procs,
2003 int stride, pdf14_device *p14dev)
2004 {
2005 byte a_b, a_s;
2006 unsigned int a_r;
2007 int tmp;
2008 int src_scale;
2009 int c_b, c_s;
2010 byte blend[ART_MAX_CHAN];
2011
2012 a_s = src[1];
2013
2014 a_b = dst[stride];
2015
2016 /* Result alpha is Union of backdrop and source alpha */
2017 tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
2018 a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
2019 /* todo: verify that a_r is nonzero in all cases */
2020
2021 /* Compute a_s / a_r in 16.16 format */
2022 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
2023
2024 /* Do compositing with blending */
2025 art_blend_pixel_8(blend, dst, src, 1, blend_mode, pblend_procs, p14dev);
2026 {
2027 int c_bl; /* Result of blend function */
2028 int c_mix; /* Blend result mixed with source color */
2029
2030 c_s = src[0];
2031 c_b = dst[0];
2032 c_bl = blend[0];
2033 tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
2034 c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
2035 tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
2036 dst[0] = tmp >> 16;
2037 }
2038 dst[stride] = a_r;
2039 }
2040
2041 static inline void
art_pdf_composite_pixel_alpha_16_fast_mono(uint16_t * gs_restrict dst,const uint16_t * gs_restrict src,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs,int stride,pdf14_device * p14dev)2042 art_pdf_composite_pixel_alpha_16_fast_mono(uint16_t *gs_restrict dst, const uint16_t *gs_restrict src,
2043 gs_blend_mode_t blend_mode,
2044 const pdf14_nonseparable_blending_procs_t * pblend_procs,
2045 int stride, pdf14_device *p14dev)
2046 {
2047 uint16_t a_b, a_s;
2048 unsigned int a_r;
2049 int tmp;
2050 int src_scale;
2051 int c_b, c_s;
2052 uint16_t blend[ART_MAX_CHAN];
2053
2054 a_s = src[1];
2055
2056 a_b = dst[stride];
2057 a_b += a_b>>15;
2058
2059 /* Result alpha is Union of backdrop and source alpha */
2060 tmp = (0x10000 - a_b) * (0xffff - a_s) + 0x8000;
2061 a_r = 0xffff - (tmp >> 16);
2062 /* todo: verify that a_r is nonzero in all cases */
2063
2064 /* Compute a_s / a_r in 16.16 format */
2065 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
2066
2067 src_scale >>= 1; /* Lose a bit to avoid overflow */
2068 a_b >>= 1; /* Lose a bit to avoid overflow */
2069 /* Do compositing with blending */
2070 art_blend_pixel_16(blend, dst, src, 1, blend_mode, pblend_procs, p14dev);
2071 {
2072 int c_bl; /* Result of blend function */
2073
2074 c_s = src[0];
2075 c_b = dst[0];
2076 c_bl = blend[0];
2077 tmp = a_b * (c_bl - c_s) + 0x4000;
2078 c_s += (tmp>>15);
2079 dst[0] = c_b + ((src_scale * (c_s - c_b) + 0x4000)>>15);
2080 }
2081 dst[stride] = a_r;
2082 }
2083
2084 /**
2085 * art_pdf_recomposite_group_8: Recomposite group pixel.
2086 * @dst: Where to store pixel, also initial backdrop of group.
2087 * @dst_alpha_g: Optional pointer to alpha g value associated with @dst.
2088 * @alpha: Alpha mask value.
2089 * @src_alpha_g: alpha_g value associated with @src.
2090 * @blend_mode: Blend mode for compositing.
2091 *
2092 * Note: this is only for non-isolated groups. This covers only the
2093 * single-alpha case. A separate function is needed for dual-alpha,
2094 * and that probably needs to treat knockout separately.
2095 * Also note the need to know if the spot colorants should be blended
2096 * normal. This occurs when we have spot colorants and the blending is set
2097 * for non-separable or non-white preserving blend modes
2098 * @src_alpha_g corresponds to $\alpha g_n$ in the Adobe notation.
2099 *
2100 * @alpha corresponds to $fk_i \cdot fm_i \cdot qk_i \cdot qm_i$.
2101 *
2102 * @NOTE: This function may corrupt src.
2103 *
2104 * Returns 1 if we need to call art_pdf_composite_pixel_alpha_8.
2105 **/
2106 static forceinline int
art_pdf_recomposite_group_8(byte * gs_restrict * dstp,byte * gs_restrict dst_alpha_g,byte * gs_restrict src,byte src_alpha_g,int n_chan,byte alpha,gs_blend_mode_t blend_mode)2107 art_pdf_recomposite_group_8(byte *gs_restrict *dstp, byte *gs_restrict dst_alpha_g,
2108 byte *gs_restrict src, byte src_alpha_g, int n_chan,
2109 byte alpha, gs_blend_mode_t blend_mode)
2110 {
2111 byte dst_alpha;
2112 int i;
2113 int tmp;
2114 int scale;
2115 byte *gs_restrict dst = *dstp;
2116
2117 if (src_alpha_g == 0)
2118 return 0;
2119
2120 if (blend_mode == BLEND_MODE_Normal && alpha == 255) {
2121 /* In this case, uncompositing and recompositing cancel each
2122 other out. Note: if the reason that alpha == 255 is that
2123 there is no constant mask and no soft mask, then this
2124 operation should be optimized away at a higher level. */
2125
2126 if (dst_alpha_g != NULL) {
2127 tmp = (255 - *dst_alpha_g) * (255 - src_alpha_g) + 0x80;
2128 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
2129 }
2130 *dstp = src;
2131 return 0;
2132 } else {
2133 /* "interesting" blend mode */
2134 dst_alpha = dst[n_chan];
2135 if (src_alpha_g != 255 && dst_alpha != 0) {
2136 /* Uncomposite the color. In other words, solve
2137 "src = (src, src_alpha_g) over dst" for src */
2138 scale = (dst_alpha * 255 * 2 + src_alpha_g) / (src_alpha_g << 1) -
2139 dst_alpha;
2140 for (i = 0; i < n_chan; i++) {
2141 int si, di;
2142
2143 si = src[i];
2144 di = dst[i];
2145 tmp = (si - di) * scale + 0x80;
2146 tmp = si + ((tmp + (tmp >> 8)) >> 8);
2147
2148 /* todo: it should be possible to optimize these cond branches */
2149 if (tmp < 0)
2150 tmp = 0;
2151 if (tmp > 255)
2152 tmp = 255;
2153 src[i] = tmp;
2154 }
2155 }
2156
2157 tmp = src_alpha_g * alpha + 0x80;
2158 tmp = (tmp + (tmp >> 8)) >> 8;
2159 src[n_chan] = tmp;
2160 if (dst_alpha_g != NULL) {
2161 tmp = (255 - *dst_alpha_g) * (255 - tmp) + 0x80;
2162 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
2163 }
2164 }
2165 return 1;
2166 /* todo: optimize BLEND_MODE_Normal buf alpha != 255 case */
2167 }
2168
2169 static forceinline int
art_pdf_ko_recomposite_group_8(byte tos_shape,byte src_alpha_g,byte * gs_restrict * dstp,byte * gs_restrict dst_alpha_g,byte * gs_restrict src,int n_chan,byte alpha,gs_blend_mode_t blend_mode,bool has_mask)2170 art_pdf_ko_recomposite_group_8(byte tos_shape,
2171 byte src_alpha_g, byte* gs_restrict* dstp,
2172 byte* gs_restrict dst_alpha_g, byte* gs_restrict src,
2173 int n_chan, byte alpha, gs_blend_mode_t blend_mode, bool has_mask)
2174 {
2175 byte* gs_restrict dst = *dstp;
2176
2177 if (tos_shape == 0 || src_alpha_g == 0) {
2178 /* If a softmask was present pass it along Bug 693548 */
2179 if (has_mask)
2180 dst[n_chan] = alpha;
2181 return 0;
2182 }
2183
2184 return art_pdf_recomposite_group_8(dstp, dst_alpha_g, src, src_alpha_g,
2185 n_chan, alpha, blend_mode);
2186 }
2187
2188 static forceinline int
art_pdf_recomposite_group_16(uint16_t * gs_restrict * dstp,uint16_t * gs_restrict dst_alpha_g,uint16_t * gs_restrict src,uint16_t src_alpha_g,int n_chan,uint16_t alpha,gs_blend_mode_t blend_mode)2189 art_pdf_recomposite_group_16(uint16_t *gs_restrict *dstp, uint16_t *gs_restrict dst_alpha_g,
2190 uint16_t *gs_restrict src, uint16_t src_alpha_g, int n_chan,
2191 uint16_t alpha, gs_blend_mode_t blend_mode)
2192 {
2193 uint16_t dst_alpha;
2194 int i;
2195 uint32_t tmp;
2196 uint16_t *gs_restrict dst = *dstp;
2197
2198 if (src_alpha_g == 0)
2199 return 0;
2200
2201 if (blend_mode == BLEND_MODE_Normal && alpha == 65535) {
2202 /* In this case, uncompositing and recompositing cancel each
2203 other out. Note: if the reason that alpha == 65535 is that
2204 there is no constant mask and no soft mask, then this
2205 operation should be optimized away at a higher level. */
2206
2207 if (dst_alpha_g != NULL) {
2208 int d = *dst_alpha_g;
2209 d += d>>15;
2210 tmp = (0x10000 - d) * (0xffff - src_alpha_g) + 0x8000;
2211 *dst_alpha_g = 0xffff - (tmp>>16);
2212 }
2213 *dstp = src;
2214 return 0;
2215 } else {
2216 /* "interesting" blend mode */
2217 dst_alpha = dst[n_chan];
2218 if (src_alpha_g != 65535 && dst_alpha != 0) {
2219 /* Uncomposite the color. In other words, solve
2220 "src = (src, src_alpha_g) over dst" for src */
2221 uint32_t scale = ((unsigned int)(dst_alpha * 65535 + (src_alpha_g>>1))) / src_alpha_g -
2222 dst_alpha;
2223 /* scale is NOT in 16.16 form here. I've seen values of 0xfefe01, for example. */
2224 for (i = 0; i < n_chan; i++) {
2225 int si, di;
2226 int64_t tmp64;
2227 int t;
2228
2229 si = src[i];
2230 di = dst[i];
2231 /* RJW: Nasty that we have to resort to 64bit here, but we'll live with it. */
2232 tmp64 = (si - di) * (uint64_t)scale + 0x8000;
2233 t = si + (tmp64 >> 16);
2234 if (t < 0)
2235 t = 0;
2236 else if (t > 65535)
2237 t = 65535;
2238 src[i] = t;
2239 }
2240 }
2241
2242 tmp = alpha + (alpha>>15);
2243 tmp = (src_alpha_g * tmp + 0x8000)>>16;
2244 src[n_chan] = tmp;
2245 if (dst_alpha_g != NULL) {
2246 uint32_t d = *dst_alpha_g;
2247 d += d>>15;
2248 tmp = (0x10000 - d) * (0xffff - tmp) + 0x8000;
2249 *dst_alpha_g = 0xffff - (tmp >> 16);
2250 }
2251 }
2252 return 1;
2253 /* todo: optimize BLEND_MODE_Normal buf alpha != 255 case */
2254 }
2255
2256 static forceinline int
art_pdf_ko_recomposite_group_16(uint16_t tos_shape,uint16_t src_alpha_g,uint16_t * gs_restrict * dstp,uint16_t * gs_restrict dst_alpha_g,uint16_t * gs_restrict src,int n_chan,uint16_t alpha,gs_blend_mode_t blend_mode,bool has_mask)2257 art_pdf_ko_recomposite_group_16(uint16_t tos_shape,
2258 uint16_t src_alpha_g, uint16_t* gs_restrict* dstp,
2259 uint16_t* gs_restrict dst_alpha_g, uint16_t* gs_restrict src,
2260 int n_chan, uint16_t alpha, gs_blend_mode_t blend_mode,
2261 bool has_mask)
2262 {
2263 uint16_t* gs_restrict dst = *dstp;
2264
2265 if (tos_shape == 0 || src_alpha_g == 0) {
2266 /* If a softmask was present pass it along Bug 693548 */
2267 if (has_mask)
2268 dst[n_chan] = alpha;
2269 return 0;
2270 }
2271
2272 return art_pdf_recomposite_group_16(dstp, dst_alpha_g, src,
2273 src_alpha_g, n_chan, alpha,
2274 blend_mode);
2275 }
2276
2277 /**
2278 * art_pdf_composite_group_8: Composite group pixel.
2279 * @dst: Where to store pixel, also initial backdrop of group.
2280 * @dst_alpha_g: Optional pointer to alpha g value.
2281 * @alpha: Alpha mask value.
2282 * @blend_mode: Blend mode for compositing.
2283 * @pblend_procs: Procs for handling non separable blending modes.
2284 *
2285 * Note: this is only for isolated groups. This covers only the
2286 * single-alpha case. A separate function is needed for dual-alpha,
2287 * and that probably needs to treat knockout separately.
2288 *
2289 * Components 0 to first_spot are blended with blend_mode.
2290 * Components first_spot to n_chan are blended with BLEND_MODE_Normal.
2291 *
2292 * @alpha corresponds to $fk_i \cdot fm_i \cdot qk_i \cdot qm_i$.
2293 *
2294 * @NOTE: This function may corrupt src.
2295 *
2296 * Returns 1 if we need to call art_pdf_composite_pixel_alpha_8.
2297 **/
2298 static forceinline int
art_pdf_composite_group_8(byte * gs_restrict dst,byte * gs_restrict dst_alpha_g,byte * gs_restrict src,int n_chan,byte alpha)2299 art_pdf_composite_group_8(byte *gs_restrict dst, byte *gs_restrict dst_alpha_g,
2300 byte *gs_restrict src, int n_chan, byte alpha)
2301 {
2302 byte src_alpha = src[n_chan]; /* $\alpha g_n$ */
2303
2304 if (src_alpha == 0)
2305 return 0;
2306
2307 if (alpha != 255) {
2308 int tmp = src_alpha * alpha + 0x80;
2309 src[n_chan] = (tmp + (tmp >> 8)) >> 8;
2310 }
2311
2312 if (dst_alpha_g != NULL) {
2313 int tmp = (255 - *dst_alpha_g) * (255 - src[n_chan]) + 0x80;
2314 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
2315 }
2316
2317 return 1;
2318 }
2319
2320 static forceinline int
art_pdf_ko_composite_group_8(byte tos_shape,byte * gs_restrict src_alpha_g,byte * gs_restrict dst,byte * gs_restrict dst_alpha_g,byte * gs_restrict src,int n_chan,byte alpha,bool has_mask)2321 art_pdf_ko_composite_group_8(byte tos_shape,
2322 byte* gs_restrict src_alpha_g, byte* gs_restrict dst,
2323 byte* gs_restrict dst_alpha_g, byte* gs_restrict src,
2324 int n_chan, byte alpha, bool has_mask)
2325 {
2326 byte src_alpha; /* $\alpha g_n$ */
2327 int tmp;
2328
2329 if (tos_shape == 0 || (src_alpha_g != NULL && *src_alpha_g == 0)) {
2330 /* If a softmask was present pass it along Bug 693548 */
2331 if (has_mask)
2332 dst[n_chan] = alpha;
2333 return 0;
2334 }
2335
2336 if (alpha != 255) {
2337 if (tos_shape != 255)
2338 return 0;
2339 src_alpha = src[n_chan];
2340 if (src_alpha == 0)
2341 return 0;
2342 tmp = src_alpha * alpha + 0x80;
2343 src[n_chan] = (tmp + (tmp >> 8)) >> 8;
2344 }
2345
2346 if (dst_alpha_g != NULL) {
2347 tmp = (255 - *dst_alpha_g) * (255 - src[n_chan]) + 0x80;
2348 *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
2349 }
2350 return 1;
2351 }
2352
2353 static forceinline int
art_pdf_composite_group_16(uint16_t * gs_restrict dst,uint16_t * gs_restrict dst_alpha_g,uint16_t * gs_restrict src,int n_chan,uint16_t alpha)2354 art_pdf_composite_group_16(uint16_t *gs_restrict dst, uint16_t *gs_restrict dst_alpha_g,
2355 uint16_t *gs_restrict src, int n_chan, uint16_t alpha)
2356 {
2357 uint16_t src_alpha = src[n_chan]; /* $\alpha g_n$ */
2358
2359 if (src_alpha == 0)
2360 return 0;
2361
2362 if (alpha != 65535) {
2363 int tmp = alpha + (alpha>>15);
2364 src[n_chan] = (src_alpha * tmp + 0x8000)>>16;
2365 }
2366
2367 if (dst_alpha_g != NULL) {
2368 int tmp = *dst_alpha_g;
2369 tmp += tmp>>15;
2370 tmp = (0x10000 - tmp) * (0xffff - src[n_chan]) + 0x8000;
2371 *dst_alpha_g = 0xffff - (tmp >> 16);
2372 }
2373
2374 return 1;
2375 }
2376
2377 static forceinline int
art_pdf_ko_composite_group_16(uint16_t tos_shape,uint16_t * gs_restrict src_alpha_g,uint16_t * gs_restrict dst,uint16_t * gs_restrict dst_alpha_g,uint16_t * gs_restrict src,int n_chan,uint16_t alpha,bool has_mask)2378 art_pdf_ko_composite_group_16(uint16_t tos_shape,
2379 uint16_t* gs_restrict src_alpha_g, uint16_t* gs_restrict dst,
2380 uint16_t* gs_restrict dst_alpha_g, uint16_t* gs_restrict src,
2381 int n_chan, uint16_t alpha, bool has_mask)
2382 {
2383 uint16_t src_alpha;
2384 int tmp;
2385
2386 if (tos_shape == 0 || (src_alpha_g != NULL && *src_alpha_g == 0)) {
2387 /* If a softmask was present pass it along Bug 693548 */
2388 if (has_mask)
2389 dst[n_chan] = alpha;
2390 return 0;
2391 }
2392
2393 if (alpha != 65535) {
2394 if (tos_shape != 65535)
2395 return 0;
2396 src_alpha = src[n_chan];
2397 if (src_alpha == 0)
2398 return 0;
2399 tmp = alpha + (alpha >> 15);
2400 src[n_chan] = (src_alpha * tmp + 0x8000) >> 16;
2401 }
2402
2403 if (dst_alpha_g != NULL) {
2404 tmp = *dst_alpha_g;
2405 tmp += tmp >> 15;
2406 tmp = (0x10000 - tmp) * (0xffff - src[n_chan]) + 0x8000;
2407 *dst_alpha_g = 0xffff - (tmp >> 16);
2408 }
2409 return 1;
2410 }
2411
2412 /* A very simple case. Knockout isolated group going to a parent that is not
2413 a knockout. Simply copy over everwhere where we have a non-zero alpha value */
2414 void
art_pdf_knockoutisolated_group_8(byte * gs_restrict dst,const byte * gs_restrict src,int n_chan)2415 art_pdf_knockoutisolated_group_8(byte *gs_restrict dst, const byte *gs_restrict src, int n_chan)
2416 {
2417 byte src_alpha;
2418
2419 src_alpha = src[n_chan];
2420 if (src_alpha == 0)
2421 return;
2422
2423 memcpy (dst, src, n_chan + 1);
2424 }
2425
2426 void
art_pdf_knockoutisolated_group_16(uint16_t * gs_restrict dst,const uint16_t * gs_restrict src,int n_chan)2427 art_pdf_knockoutisolated_group_16(uint16_t *gs_restrict dst, const uint16_t *gs_restrict src, int n_chan)
2428 {
2429 uint16_t src_alpha;
2430
2431 src_alpha = src[n_chan];
2432 if (src_alpha == 0)
2433 return;
2434
2435 memcpy (dst, src, 2*(n_chan + 1));
2436 }
2437
2438 /* An odd case where we have an alpha from the AA device and we have a current
2439 source alpha. This is done only in the case where we are doing AA and a
2440 stroke fill at the same time.
2441 We have to first do a blend with the AA alpha if there
2442 is something to blend with and then set the alpha to the source alpha.
2443 In such a case an isolated knockout group was created and in the
2444 copy_alpha code we end up here to handle the alpha from the AA code
2445 differently from the other alpha. This ensures that the stroke and fill
2446 end up blended with each other on the inside of the stroke path
2447 but that the alpha from the AA does not end up getting blended with the
2448 backdrop (unless the source alpha is not opaque) while the outside of the
2449 stroke path ends up with the alpha for both the AA effect and source alpha */
2450 void
art_pdf_knockoutisolated_group_aa_8(byte * gs_restrict dst,const byte * gs_restrict src,byte src_alpha,byte aa_alpha,int n_chan,pdf14_device * p14dev)2451 art_pdf_knockoutisolated_group_aa_8(byte *gs_restrict dst, const byte *gs_restrict src, byte src_alpha,
2452 byte aa_alpha, int n_chan, pdf14_device *p14dev)
2453 {
2454 int dst_alpha = dst[n_chan];
2455 byte temp_src[ART_MAX_CHAN + 1];
2456 int i;
2457
2458 /* Note: src[n_chan] is a blend of the aa_alpha and src_alpha */
2459 if (src[n_chan] == 0)
2460 return;
2461
2462 /* Check what is at the destination. If nothing there then just copy */
2463 if (dst_alpha == 0) {
2464 memcpy(dst, src, n_chan + 1);
2465 return;
2466 }
2467
2468 /* Now the more complex case as something is there. First blend with the AA
2469 alpha and then set our alpha to src_alpha so it will end up blending properly
2470 with the backdrop if we had an global alpha for this fill/stroke */
2471 for (i = 0; i < n_chan; i++)
2472 temp_src[i] = src[i];
2473 temp_src[n_chan] = aa_alpha;
2474 art_pdf_composite_pixel_alpha_8(dst, temp_src, n_chan, BLEND_MODE_Normal,
2475 n_chan, NULL, p14dev);
2476 dst[n_chan] = src_alpha;
2477 }
2478
2479 void
art_pdf_composite_knockout_8(byte * gs_restrict dst,const byte * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)2480 art_pdf_composite_knockout_8(byte *gs_restrict dst,
2481 const byte *gs_restrict src,
2482 int n_chan,
2483 gs_blend_mode_t blend_mode,
2484 const pdf14_nonseparable_blending_procs_t * pblend_procs,
2485 pdf14_device *p14dev)
2486 {
2487 byte src_shape = src[n_chan];
2488 int i, tmp;
2489
2490 if (blend_mode == BLEND_MODE_Normal) {
2491 /* Do simple compositing of source over backdrop */
2492 if (src_shape == 0)
2493 return;
2494 else if (src_shape == 255) {
2495 memcpy (dst, src, n_chan + 1);
2496 return;
2497 } else {
2498 /* Use src_shape to interpolate (in premultiplied alpha space)
2499 between dst and (src, opacity). */
2500 int dst_alpha = dst[n_chan];
2501 byte result_alpha;
2502
2503 tmp = (255 - dst_alpha) * src_shape + 0x80;
2504 result_alpha = dst_alpha + ((tmp + (tmp >> 8)) >> 8);
2505
2506 if (result_alpha != 0)
2507 for (i = 0; i < n_chan; i++) {
2508 /* todo: optimize this - can strength-reduce so that
2509 inner loop is a single interpolation */
2510 tmp = dst[i] * dst_alpha * (255 - src_shape) +
2511 ((int)src[i]) * 255 * src_shape + (result_alpha << 7);
2512 tmp = tmp / (result_alpha * 255);
2513 if (tmp > 255) tmp = 255;
2514 dst[i] = tmp;
2515 }
2516 dst[n_chan] = result_alpha;
2517 }
2518 } else {
2519 /* Do compositing with blending */
2520 byte blend[ART_MAX_CHAN];
2521 byte a_b, a_s;
2522 unsigned int a_r;
2523 int src_scale;
2524 int c_b, c_s;
2525
2526 a_s = src[n_chan];
2527 a_b = dst[n_chan];
2528
2529 /* Result alpha is Union of backdrop and source alpha */
2530 tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
2531 a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
2532
2533 if (a_r != 0) {
2534 /* Compute a_s / a_r in 16.16 format */
2535 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
2536
2537 art_blend_pixel_8(blend, dst, src, n_chan, blend_mode, pblend_procs, p14dev);
2538 for (i = 0; i < n_chan; i++) {
2539 int c_bl; /* Result of blend function */
2540 int c_mix; /* Blend result mixed with source color */
2541
2542 c_s = src[i];
2543 c_b = dst[i];
2544 c_bl = blend[i];
2545 tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
2546 c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
2547 tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
2548 dst[i] = tmp >> 16;
2549 }
2550 }
2551 dst[n_chan] = a_r;
2552 }
2553 }
2554
2555 void
art_pdf_composite_knockout_16(uint16_t * gs_restrict dst,const uint16_t * gs_restrict src,int n_chan,gs_blend_mode_t blend_mode,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * p14dev)2556 art_pdf_composite_knockout_16(uint16_t *gs_restrict dst,
2557 const uint16_t *gs_restrict src,
2558 int n_chan,
2559 gs_blend_mode_t blend_mode,
2560 const pdf14_nonseparable_blending_procs_t * pblend_procs,
2561 pdf14_device *p14dev)
2562 {
2563 uint16_t src_shape = src[n_chan];
2564 int i;
2565 unsigned int tmp;
2566
2567 if (blend_mode == BLEND_MODE_Normal) {
2568 /* Do simple compositing of source over backdrop */
2569 if (src_shape == 0)
2570 return;
2571 else if (src_shape == 65535) {
2572 memcpy (dst, src, (n_chan + 1)*2);
2573 return;
2574 } else {
2575 /* Use src_shape to interpolate (in premultiplied alpha space)
2576 between dst and (src, opacity). */
2577 int dst_alpha = dst[n_chan];
2578 uint16_t result_alpha;
2579
2580 tmp = (65535 - dst_alpha) * src_shape + 0x8000;
2581 result_alpha = dst_alpha + ((tmp + (tmp >> 16)) >> 16);
2582
2583 if (result_alpha != 0) {
2584 dst_alpha += dst_alpha>>15;
2585 for (i = 0; i < n_chan; i++) {
2586 /* todo: optimize this - can strength-reduce so that
2587 inner loop is a single interpolation */
2588 tmp = dst[i] * dst_alpha;
2589 tmp = (tmp>>16) * (65535 - src_shape) +
2590 src[i] * src_shape + (result_alpha>>1);
2591 tmp = tmp / result_alpha;
2592 if (tmp > 65535) tmp = 65535;
2593 dst[i] = tmp;
2594
2595 }
2596 }
2597 dst[n_chan] = result_alpha;
2598 }
2599 } else {
2600 /* Do compositing with blending */
2601 uint16_t blend[ART_MAX_CHAN];
2602 uint16_t a_b, a_s;
2603 unsigned int a_r;
2604 int src_scale;
2605 int c_b, c_s;
2606
2607 a_s = src[n_chan];
2608 a_b = dst[n_chan];
2609
2610 /* Result alpha is Union of backdrop and source alpha */
2611 tmp = (0xffff - a_b) * (0xffff - a_s) + 0x8000;
2612 a_r = 0xffff - (((tmp >> 16) + tmp) >> 16);
2613
2614 if (a_r != 0) {
2615 /* Compute a_s / a_r in 16.16 format */
2616 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
2617
2618 src_scale >>= 1; /* Lose a bit to avoid overflow */
2619 a_b >>= 1; /* Lose a bit to avoid overflow */
2620 art_blend_pixel_16(blend, dst, src, n_chan, blend_mode, pblend_procs, p14dev);
2621 for (i = 0; i < n_chan; i++) {
2622 int c_bl; /* Result of blend function */
2623 int c_mix; /* Blend result mixed with source color */
2624 int stmp;
2625
2626 c_s = src[i];
2627 c_b = dst[i];
2628 c_bl = blend[i];
2629 stmp = a_b * (c_bl - ((int)c_s)) + 0x4000;
2630 c_mix = c_s + (((stmp >> 16) + stmp) >> 15);
2631 tmp = src_scale * (c_mix - c_b) + 0x4000;
2632 dst[i] = c_b + (tmp >> 15);
2633 }
2634 }
2635 dst[n_chan] = a_r;
2636 }
2637 }
2638
2639 #if RAW_DUMP
2640 /* Debug dump of buffer data from pdf14 device. Saved in
2641 planar form with global indexing and tag information in
2642 file name */
2643 static void
do_dump_raw_buffer(const gs_memory_t * mem,int num_rows,int width,int n_chan,int plane_stride,int rowstride,char filename[],const byte * Buffer,bool deep,bool be)2644 do_dump_raw_buffer(const gs_memory_t *mem, int num_rows, int width, int n_chan,
2645 int plane_stride, int rowstride,
2646 char filename[], const byte *Buffer, bool deep, bool be)
2647 {
2648 char full_file_name[50];
2649 gp_file *fid;
2650 int z,y;
2651 const byte *buff_ptr;
2652 int max_bands;
2653
2654 /* clist_band_count is incremented at every pdf14putimage */
2655 /* Useful for catching this thing and only dumping */
2656 /* during a particular band if we have a large file */
2657 /* if (clist_band_count != 65) return; */
2658 buff_ptr = Buffer;
2659 #if RAW_DUMP_AS_PAM
2660 /* FIXME: GRAY + ALPHA + SHAPE + TAGS will be interpreted as RGB + ALPHA */
2661 if ((n_chan == 2) || (n_chan == 3)) {
2662 int x;
2663 dlprintf2("%02d)%s.pam\n",global_index,filename);dflush();
2664 gs_sprintf(full_file_name,"%02d)%s.pam",global_index,filename);
2665 fid = gp_fopen(mem,full_file_name,"wb");
2666 fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 2\nMAXVAL %d\nTUPLTYPE GRAYSCALE_ALPHA\nENDHDR\n",
2667 width, num_rows, deep ? 65535 : 255);
2668 if (deep) {
2669 for(y=0; y<num_rows; y++)
2670 for(x=0; x<width; x++)
2671 for(z=0; z<2; z++) {
2672 /* This assumes a little endian host. Sue me. */
2673 gp_fputc(Buffer[z*plane_stride + y*rowstride + x*2 + be^1], fid);
2674 gp_fputc(Buffer[z*plane_stride + y*rowstride + x*2 + be ], fid);
2675 }
2676 } else {
2677 for(y=0; y<num_rows; y++)
2678 for(x=0; x<width; x++)
2679 for(z=0; z<2; z++)
2680 gp_fputc(Buffer[z*plane_stride + y*rowstride + x], fid);
2681 }
2682 gp_fclose(fid);
2683 if (n_chan == 3) {
2684 dlprintf2("%02d)%s_shape.pgm\n",global_index,filename);dflush();
2685 gs_sprintf(full_file_name,"%02d)%s_shape.pgm",global_index,filename);
2686 fid = gp_fopen(mem,full_file_name,"wb");
2687 fprintf(fid, "P5\n%d %d %d\n",
2688 width, num_rows, deep ? 65535 : 255);
2689 if (deep) {
2690 for(y=0; y<num_rows; y++)
2691 for(x=0; x<width; x++) {
2692 /* This assumes a little endian host. Sue me. */
2693 gp_fputc(Buffer[2*plane_stride + y*rowstride + x * 2 + be^1], fid);
2694 gp_fputc(Buffer[2*plane_stride + y*rowstride + x * 2 + be ], fid);
2695 }
2696 } else {
2697 for(y=0; y<num_rows; y++)
2698 for(x=0; x<width; x++)
2699 gp_fputc(Buffer[2*plane_stride + y*rowstride + x], fid);
2700 }
2701 gp_fclose(fid);
2702 }
2703 }
2704 if ((n_chan == 4) || (n_chan == 5) || (n_chan == 6)) {
2705 int x;
2706 dprintf2("%02d)%s.pam\n",global_index,filename);dflush();
2707 gs_sprintf(full_file_name,"%02d)%s.pam",global_index,filename);
2708 fid = gp_fopen(mem,full_file_name,"wb");
2709 fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL %d\nTUPLTYPE RGB_ALPHA\nENDHDR\n",
2710 width, num_rows, deep ? 65535 : 255);
2711 if (deep) {
2712 for(y=0; y<num_rows; y++)
2713 for(x=0; x<width; x++)
2714 for(z=0; z<4; z++) {
2715 /* This assumes a little endian host. Sue me. */
2716 gp_fputc(Buffer[z*plane_stride + y*rowstride + x*2 + be^1], fid);
2717 gp_fputc(Buffer[z*plane_stride + y*rowstride + x*2 + be ], fid);
2718 }
2719 } else {
2720 for(y=0; y<num_rows; y++)
2721 for(x=0; x<width; x++)
2722 for(z=0; z<4; z++)
2723 gp_fputc(Buffer[z*plane_stride + y*rowstride + x], fid);
2724 }
2725 gp_fclose(fid);
2726 if (n_chan > 4) {
2727 gs_sprintf(full_file_name,"%02d)%s_shape.pgm",global_index,filename);
2728 fid = gp_fopen(mem,full_file_name,"wb");
2729 fprintf(fid, "P5\n%d %d %d\n",
2730 width, num_rows, deep ? 65535 : 255);
2731 if (deep) {
2732 for(y=0; y<num_rows; y++)
2733 for(x=0; x<width; x++) {
2734 /* This assumes a little endian host. Sue me. */
2735 gp_fputc(Buffer[4*plane_stride + y*rowstride + x*2 + be^1], fid);
2736 gp_fputc(Buffer[4*plane_stride + y*rowstride + x*2 + be ], fid);
2737 }
2738 } else {
2739 for(y=0; y<num_rows; y++)
2740 for(x=0; x<width; x++)
2741 gp_fputc(Buffer[4*plane_stride + y*rowstride + x], fid);
2742 }
2743 gp_fclose(fid);
2744 }
2745 if (n_chan == 6) {
2746 gs_sprintf(full_file_name,"%02d)%s_tags.pgm",global_index,filename);
2747 fid = gp_fopen(mem, full_file_name,"wb");
2748 fprintf(fid, "P5\n%d %d 255\n", width, num_rows);
2749 if (deep) {
2750 for(y=0; y<num_rows; y++)
2751 for(x=0; x<width; x++)
2752 gp_fputc(Buffer[5*plane_stride + y*rowstride + x*2 + be ], fid);
2753 } else {
2754 for(y=0; y<num_rows; y++)
2755 for(x=0; x<width; x++)
2756 gp_fputc(Buffer[5*plane_stride + y*rowstride + x], fid);
2757 }
2758 gp_fclose(fid);
2759 }
2760 return;
2761 }
2762 #endif
2763 max_bands = ( n_chan < 57 ? n_chan : 56); /* Photoshop handles at most 56 bands */
2764 dlprintf6("%02d)%s_%dx%dx%dx%d.raw\n",global_index,filename,width,num_rows,deep ? 16 : 8,max_bands);dflush();
2765 gs_sprintf(full_file_name,"%02d)%s_%dx%dx%dx%d.raw",global_index,filename,width,num_rows,deep ? 16 : 8,max_bands);
2766 fid = gp_fopen(mem, full_file_name,"wb");
2767
2768 if (be && deep) {
2769 for (z = 0; z < max_bands; ++z) {
2770 /* grab pointer to the next plane */
2771 buff_ptr = &(Buffer[z*plane_stride]);
2772 for ( y = 0; y < num_rows; y++ ) {
2773 /* write out each row */
2774 int x;
2775 for (x = 0; x < width; x++ ) {
2776 gp_fputc(buff_ptr[x*2 + be^1], fid);
2777 gp_fputc(buff_ptr[x*2 + be ], fid);
2778 }
2779 buff_ptr += rowstride;
2780 }
2781 }
2782 } else {
2783 for (z = 0; z < max_bands; ++z) {
2784 /* grab pointer to the next plane */
2785 buff_ptr = &(Buffer[z*plane_stride]);
2786 for ( y = 0; y < num_rows; y++ ) {
2787 /* write out each row */
2788 gp_fwrite(buff_ptr,sizeof(unsigned char),width<<deep,fid);
2789 buff_ptr += rowstride;
2790 }
2791 }
2792 }
2793 gp_fclose(fid);
2794 }
2795
2796 void
dump_raw_buffer(const gs_memory_t * mem,int num_rows,int width,int n_chan,int plane_stride,int rowstride,char filename[],const byte * Buffer,bool deep)2797 dump_raw_buffer(const gs_memory_t *mem, int num_rows, int width, int n_chan,
2798 int plane_stride, int rowstride,
2799 char filename[],const byte *Buffer, bool deep)
2800 {
2801 do_dump_raw_buffer(mem, num_rows, width, n_chan, plane_stride,
2802 rowstride, filename, Buffer, deep, 0);
2803 }
2804
2805 void
dump_raw_buffer_be(const gs_memory_t * mem,int num_rows,int width,int n_chan,int plane_stride,int rowstride,char filename[],const byte * Buffer,bool deep)2806 dump_raw_buffer_be(const gs_memory_t *mem, int num_rows, int width, int n_chan,
2807 int plane_stride, int rowstride,
2808 char filename[],const byte *Buffer, bool deep)
2809 {
2810 do_dump_raw_buffer(mem, num_rows, width, n_chan, plane_stride,
2811 rowstride, filename, Buffer, deep, 1);
2812 }
2813 #endif
2814
2815 typedef void (*art_pdf_compose_group_fn)(byte *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
2816 byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
2817 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag,
2818 byte *tos_alpha_g_ptr, byte *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride,
2819 byte *nos_alpha_g_ptr, bool nos_knockout, int nos_shape_offset, int nos_tag_offset,
2820 byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
2821 byte *backdrop_ptr, bool has_matte, int n_chan, bool additive, int num_spots, bool overprint,
2822 gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
2823 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev);
2824
2825 static forceinline void
template_compose_group(byte * gs_restrict tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,byte alpha,byte shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,byte * gs_restrict tos_alpha_g_ptr,byte * gs_restrict nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,byte * gs_restrict nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,byte * gs_restrict mask_row_ptr,int has_mask,pdf14_buf * gs_restrict maskbuf,byte mask_bg_alpha,const byte * gs_restrict mask_tr_fn,byte * gs_restrict backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev,int has_alpha)2826 template_compose_group(byte *gs_restrict tos_ptr, bool tos_isolated,
2827 int tos_planestride, int tos_rowstride,
2828 byte alpha, byte shape, gs_blend_mode_t blend_mode,
2829 bool tos_has_shape, int tos_shape_offset,
2830 int tos_alpha_g_offset, int tos_tag_offset,
2831 bool tos_has_tag, byte *gs_restrict tos_alpha_g_ptr,
2832 byte *gs_restrict nos_ptr,
2833 bool nos_isolated, int nos_planestride,
2834 int nos_rowstride, byte *gs_restrict nos_alpha_g_ptr,
2835 bool nos_knockout, int nos_shape_offset,
2836 int nos_tag_offset, byte *gs_restrict mask_row_ptr,
2837 int has_mask, pdf14_buf *gs_restrict maskbuf,
2838 byte mask_bg_alpha, const byte *gs_restrict mask_tr_fn,
2839 byte *gs_restrict backdrop_ptr, bool has_matte,
2840 int n_chan, bool additive, int num_spots,
2841 bool overprint, gx_color_index drawn_comps,
2842 int x0, int y0, int x1, int y1,
2843 const pdf14_nonseparable_blending_procs_t *pblend_procs,
2844 pdf14_device *pdev, int has_alpha)
2845 {
2846 byte *gs_restrict mask_curr_ptr = NULL;
2847 int width = x1 - x0;
2848 int x, y;
2849 int i;
2850 byte tos_pixel[PDF14_MAX_PLANES];
2851 byte nos_pixel[PDF14_MAX_PLANES];
2852 byte back_drop[PDF14_MAX_PLANES];
2853 bool in_mask_rect_y;
2854 bool in_mask_rect;
2855 byte pix_alpha;
2856 byte matte_alpha = 0xff;
2857 int first_spot = n_chan - num_spots;
2858 int first_blend_spot = n_chan;
2859 bool has_mask2 = has_mask;
2860 byte *gs_restrict dst;
2861 byte global_shape = (byte)(255 * pdev->shape + 0.5);
2862
2863 if (!nos_knockout && num_spots > 0 && !blend_valid_for_spot(blend_mode)) {
2864 first_blend_spot = first_spot;
2865 }
2866 if (blend_mode == BLEND_MODE_Normal)
2867 first_blend_spot = 0;
2868 if (!nos_isolated && backdrop_ptr != NULL)
2869 has_mask2 = false;
2870
2871 for (y = y1 - y0; y > 0; --y) {
2872 mask_curr_ptr = mask_row_ptr;
2873 in_mask_rect_y = (has_mask && y1 - y >= maskbuf->rect.p.y && y1 - y < maskbuf->rect.q.y);
2874 for (x = 0; x < width; x++) {
2875 in_mask_rect = (in_mask_rect_y && x0 + x >= maskbuf->rect.p.x && x0 + x < maskbuf->rect.q.x);
2876 pix_alpha = alpha;
2877 /* If we have a soft mask, then we have some special handling of the
2878 group alpha value */
2879 if (maskbuf != NULL) {
2880 if (!in_mask_rect) {
2881 /* Special case where we have a soft mask but are outside
2882 the range of the soft mask and must use the background
2883 alpha value */
2884 pix_alpha = mask_bg_alpha;
2885 matte_alpha = 0xff;
2886 } else {
2887 if (has_matte)
2888 matte_alpha = mask_tr_fn[*mask_curr_ptr];
2889 }
2890 }
2891
2892 /* Matte present, need to undo premultiplied alpha prior to blend */
2893 if (has_matte && matte_alpha != 0 && matte_alpha < 0xff) {
2894 for (i = 0; i < n_chan; i++) {
2895 /* undo */
2896 byte matte = maskbuf->matte[i]>>8;
2897 int val = tos_ptr[i * tos_planestride] - matte;
2898 int temp = ((((val * 0xff) << 8) / matte_alpha) >> 8) + matte;
2899
2900 /* clip */
2901 if (temp > 0xff)
2902 tos_pixel[i] = 0xff;
2903 else if (temp < 0)
2904 tos_pixel[i] = 0;
2905 else
2906 tos_pixel[i] = temp;
2907
2908 if (!additive) {
2909 /* Pure subtractive */
2910 tos_pixel[i] = 255 - tos_pixel[i];
2911 nos_pixel[i] = 255 - nos_ptr[i * nos_planestride];
2912 } else {
2913 /* additive or hybrid */
2914 if (i >= first_spot)
2915 nos_pixel[i] = 255 - nos_ptr[i * nos_planestride];
2916 else
2917 nos_pixel[i] = nos_ptr[i * nos_planestride];
2918 }
2919 }
2920 } else {
2921 /* No matte present */
2922 if (!additive) {
2923 /* Pure subtractive */
2924 for (i = 0; i < n_chan; ++i) {
2925 tos_pixel[i] = 255 - tos_ptr[i * tos_planestride];
2926 nos_pixel[i] = 255 - nos_ptr[i * nos_planestride];
2927 }
2928 } else {
2929 /* Additive or hybrid */
2930 for (i = 0; i < first_spot; ++i) {
2931 tos_pixel[i] = tos_ptr[i * tos_planestride];
2932 nos_pixel[i] = nos_ptr[i * nos_planestride];
2933 }
2934 for (; i < n_chan; i++) {
2935 tos_pixel[i] = 255 - tos_ptr[i * tos_planestride];
2936 nos_pixel[i] = 255 - nos_ptr[i * nos_planestride];
2937 }
2938 }
2939 }
2940 /* alpha */
2941 tos_pixel[n_chan] = has_alpha ? tos_ptr[n_chan * tos_planestride] : 255;
2942 nos_pixel[n_chan] = has_alpha ? nos_ptr[n_chan * nos_planestride] : 255;
2943
2944 if (mask_curr_ptr != NULL) {
2945 if (in_mask_rect) {
2946 byte mask = mask_tr_fn[*mask_curr_ptr++];
2947 int tmp = pix_alpha * mask + 0x80;
2948 pix_alpha = (tmp + (tmp >> 8)) >> 8;
2949 } else {
2950 mask_curr_ptr++;
2951 }
2952 }
2953
2954 dst = nos_pixel;
2955 if (nos_knockout) {
2956 /* We need to be knocking out what ever is on the nos, but may
2957 need to combine with it's backdrop */
2958 byte tos_shape = 255;
2959
2960 if (tos_has_shape)
2961 tos_shape = tos_ptr[tos_shape_offset];
2962
2963 if (nos_isolated || backdrop_ptr == NULL) {
2964 /* We do not need to compose with the backdrop */
2965 back_drop[n_chan] = 0;
2966 /* FIXME: The blend here can be simplified */
2967 } else {
2968 /* Per the PDF spec, since the tos is not isolated and we are
2969 going onto a knock out group, we do the composition with
2970 the nos initial backdrop. */
2971 if (additive) {
2972 /* additive or hybrid */
2973 for (i = 0; i < first_spot; ++i) {
2974 back_drop[i] = backdrop_ptr[i * nos_planestride];
2975 }
2976 for (; i < n_chan; i++) {
2977 back_drop[i] = 255 - backdrop_ptr[i * nos_planestride];
2978 }
2979 } else {
2980 /* pure subtractive */
2981 for (i = 0; i < n_chan; ++i) {
2982 back_drop[i] = 255 - backdrop_ptr[i * nos_planestride];
2983 }
2984 }
2985 /* alpha */
2986 back_drop[n_chan] = backdrop_ptr[n_chan * nos_planestride];
2987 }
2988 if (tos_isolated ?
2989 art_pdf_ko_composite_group_8(tos_shape, tos_alpha_g_ptr,
2990 nos_pixel, nos_alpha_g_ptr,
2991 tos_pixel, n_chan, pix_alpha,
2992 has_mask2) :
2993 art_pdf_ko_recomposite_group_8(tos_shape, has_alpha ? tos_ptr[tos_alpha_g_offset] : 255,
2994 &dst, nos_alpha_g_ptr, tos_pixel, n_chan, pix_alpha,
2995 blend_mode, has_mask2))
2996 dst = art_pdf_knockout_composite_pixel_alpha_8(back_drop, tos_shape,
2997 nos_pixel, tos_pixel,
2998 n_chan, blend_mode,
2999 pblend_procs, pdev);
3000 } else if (tos_isolated ?
3001 art_pdf_composite_group_8(nos_pixel, nos_alpha_g_ptr,
3002 tos_pixel, n_chan, pix_alpha) :
3003 art_pdf_recomposite_group_8(&dst, nos_alpha_g_ptr,
3004 tos_pixel, has_alpha ? tos_ptr[tos_alpha_g_offset] : 255, n_chan,
3005 pix_alpha, blend_mode)) {
3006 dst = art_pdf_composite_pixel_alpha_8_inline(nos_pixel, tos_pixel, n_chan,
3007 blend_mode, first_blend_spot,
3008 pblend_procs, pdev);
3009 }
3010 if (nos_shape_offset && pix_alpha != 0) {
3011 nos_ptr[nos_shape_offset] =
3012 art_pdf_union_mul_8(nos_ptr[nos_shape_offset],
3013 has_alpha ? tos_ptr[tos_shape_offset] : global_shape,
3014 shape);
3015 }
3016 if (dst)
3017 {
3018 /* Complement the results for subtractive color spaces. Again,
3019 * if we are in an additive blending color space, we are not
3020 * going to be fooling with overprint of spot colors */
3021 if (additive) {
3022 /* additive or hybrid */
3023 for (i = 0; i < first_spot; ++i) {
3024 nos_ptr[i * nos_planestride] = dst[i];
3025 }
3026 for (; i < n_chan; i++) {
3027 nos_ptr[i * nos_planestride] = 255 - dst[i];
3028 }
3029 } else {
3030 /* Pure subtractive */
3031 for (i = 0; i < n_chan; ++i)
3032 nos_ptr[i * nos_planestride] = 255 - dst[i];
3033 }
3034 /* alpha */
3035 nos_ptr[n_chan * nos_planestride] = dst[n_chan];
3036 }
3037 /* tags */
3038 if (nos_tag_offset && tos_has_tag) {
3039 nos_ptr[nos_tag_offset] |= tos_ptr[tos_tag_offset];
3040 }
3041
3042 if (nos_alpha_g_ptr != NULL)
3043 ++nos_alpha_g_ptr;
3044 if (tos_alpha_g_ptr != NULL)
3045 ++tos_alpha_g_ptr;
3046 if (backdrop_ptr != NULL)
3047 ++backdrop_ptr;
3048 ++tos_ptr;
3049 ++nos_ptr;
3050 }
3051 tos_ptr += tos_rowstride - width;
3052 nos_ptr += nos_rowstride - width;
3053 if (tos_alpha_g_ptr != NULL)
3054 tos_alpha_g_ptr += tos_rowstride - width;
3055 if (nos_alpha_g_ptr != NULL)
3056 nos_alpha_g_ptr += nos_rowstride - width;
3057 if (mask_row_ptr != NULL)
3058 mask_row_ptr += maskbuf->rowstride;
3059 if (backdrop_ptr != NULL)
3060 backdrop_ptr += nos_rowstride - width;
3061 }
3062 }
3063
3064 static void
compose_group_knockout(byte * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,byte alpha,byte shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,byte * tos_alpha_g_ptr,byte * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,byte * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,byte * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,byte mask_bg_alpha,const byte * mask_tr_fn,byte * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3065 compose_group_knockout(byte *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3066 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3067 byte *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3068 int nos_shape_offset, int nos_tag_offset,
3069 byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3070 byte *backdrop_ptr,
3071 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3072 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3073 {
3074 template_compose_group(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, blend_mode, tos_has_shape,
3075 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3076 nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */1,
3077 nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3078 backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1);
3079 }
3080
3081 static void
compose_group_nonknockout_blend(byte * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,byte alpha,byte shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,byte * tos_alpha_g_ptr,byte * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,byte * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,byte * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,byte mask_bg_alpha,const byte * mask_tr_fn,byte * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3082 compose_group_nonknockout_blend(byte *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3083 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3084 byte *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3085 int nos_shape_offset, int nos_tag_offset,
3086 byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3087 byte *backdrop_ptr,
3088 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3089 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3090 {
3091 template_compose_group(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, blend_mode, tos_has_shape,
3092 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3093 nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
3094 nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3095 backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1);
3096 }
3097
3098 static void
compose_group_nonknockout_nonblend_isolated_allmask_common(byte * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,byte alpha,byte shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,byte * tos_alpha_g_ptr,byte * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,byte * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,byte * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,byte mask_bg_alpha,const byte * mask_tr_fn,byte * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3099 compose_group_nonknockout_nonblend_isolated_allmask_common(byte *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3100 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3101 byte *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3102 int nos_shape_offset, int nos_tag_offset,
3103 byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3104 byte *backdrop_ptr,
3105 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3106 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3107 {
3108 int width = x1 - x0;
3109 int x, y;
3110 int i;
3111
3112 for (y = y1 - y0; y > 0; --y) {
3113 byte *gs_restrict mask_curr_ptr = mask_row_ptr;
3114 for (x = 0; x < width; x++) {
3115 byte mask = mask_tr_fn[*mask_curr_ptr++];
3116 byte src_alpha = tos_ptr[n_chan * tos_planestride];
3117 if (src_alpha != 0) {
3118 byte a_b;
3119
3120 int tmp = alpha * mask + 0x80;
3121 byte pix_alpha = (tmp + (tmp >> 8)) >> 8;
3122
3123 if (pix_alpha != 255) {
3124 int tmp = src_alpha * pix_alpha + 0x80;
3125 src_alpha = (tmp + (tmp >> 8)) >> 8;
3126 }
3127
3128 a_b = nos_ptr[n_chan * nos_planestride];
3129 if (a_b == 0) {
3130 /* Simple copy of colors plus alpha. */
3131 for (i = 0; i < n_chan; i++) {
3132 nos_ptr[i * nos_planestride] = tos_ptr[i * tos_planestride];
3133 }
3134 nos_ptr[i * nos_planestride] = src_alpha;
3135 } else {
3136 /* Result alpha is Union of backdrop and source alpha */
3137 int tmp = (0xff - a_b) * (0xff - src_alpha) + 0x80;
3138 unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
3139
3140 /* Compute src_alpha / a_r in 16.16 format */
3141 int src_scale = ((src_alpha << 16) + (a_r >> 1)) / a_r;
3142
3143 nos_ptr[n_chan * nos_planestride] = a_r;
3144
3145 /* Do simple compositing of source over backdrop */
3146 for (i = 0; i < n_chan; i++) {
3147 int c_s = tos_ptr[i * tos_planestride];
3148 int c_b = nos_ptr[i * nos_planestride];
3149 tmp = src_scale * (c_s - c_b) + 0x8000;
3150 nos_ptr[i * nos_planestride] = c_b + (tmp >> 16);
3151 }
3152 }
3153 }
3154 ++tos_ptr;
3155 ++nos_ptr;
3156 }
3157 tos_ptr += tos_rowstride - width;
3158 nos_ptr += nos_rowstride - width;
3159 mask_row_ptr += maskbuf->rowstride;
3160 }
3161 }
3162
3163 static void
compose_group_nonknockout_nonblend_isolated_mask_common(byte * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,byte alpha,byte shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,byte * tos_alpha_g_ptr,byte * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,byte * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,byte * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,byte mask_bg_alpha,const byte * mask_tr_fn,byte * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3164 compose_group_nonknockout_nonblend_isolated_mask_common(byte *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3165 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3166 byte *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3167 int nos_shape_offset, int nos_tag_offset,
3168 byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3169 byte *backdrop_ptr,
3170 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3171 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3172 {
3173 byte *gs_restrict mask_curr_ptr = NULL;
3174 int width = x1 - x0;
3175 int x, y;
3176 int i;
3177 bool in_mask_rect_y;
3178 bool in_mask_rect;
3179 byte pix_alpha, src_alpha;
3180
3181 for (y = y1 - y0; y > 0; --y) {
3182 mask_curr_ptr = mask_row_ptr;
3183 in_mask_rect_y = (has_mask && y1 - y >= maskbuf->rect.p.y && y1 - y < maskbuf->rect.q.y);
3184 for (x = 0; x < width; x++) {
3185 in_mask_rect = (in_mask_rect_y && has_mask && x0 + x >= maskbuf->rect.p.x && x0 + x < maskbuf->rect.q.x);
3186 pix_alpha = alpha;
3187 /* If we have a soft mask, then we have some special handling of the
3188 group alpha value */
3189 if (maskbuf != NULL) {
3190 if (!in_mask_rect) {
3191 /* Special case where we have a soft mask but are outside
3192 the range of the soft mask and must use the background
3193 alpha value */
3194 pix_alpha = mask_bg_alpha;
3195 }
3196 }
3197
3198 if (mask_curr_ptr != NULL) {
3199 if (in_mask_rect) {
3200 byte mask = mask_tr_fn[*mask_curr_ptr++];
3201 int tmp = pix_alpha * mask + 0x80;
3202 pix_alpha = (tmp + (tmp >> 8)) >> 8;
3203 } else {
3204 mask_curr_ptr++;
3205 }
3206 }
3207
3208 src_alpha = tos_ptr[n_chan * tos_planestride];
3209 if (src_alpha != 0) {
3210 byte a_b;
3211
3212 if (pix_alpha != 255) {
3213 int tmp = src_alpha * pix_alpha + 0x80;
3214 src_alpha = (tmp + (tmp >> 8)) >> 8;
3215 }
3216
3217 a_b = nos_ptr[n_chan * nos_planestride];
3218 if (a_b == 0) {
3219 /* Simple copy of colors plus alpha. */
3220 for (i = 0; i < n_chan; i++) {
3221 nos_ptr[i * nos_planestride] = tos_ptr[i * tos_planestride];
3222 }
3223 nos_ptr[i * nos_planestride] = src_alpha;
3224 } else {
3225 /* Result alpha is Union of backdrop and source alpha */
3226 int tmp = (0xff - a_b) * (0xff - src_alpha) + 0x80;
3227 unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
3228
3229 /* Compute src_alpha / a_r in 16.16 format */
3230 int src_scale = ((src_alpha << 16) + (a_r >> 1)) / a_r;
3231
3232 nos_ptr[n_chan * nos_planestride] = a_r;
3233
3234 /* Do simple compositing of source over backdrop */
3235 for (i = 0; i < n_chan; i++) {
3236 int c_s = tos_ptr[i * tos_planestride];
3237 int c_b = nos_ptr[i * nos_planestride];
3238 tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
3239 nos_ptr[i * nos_planestride] = tmp >> 16;
3240 }
3241 }
3242 }
3243 ++tos_ptr;
3244 ++nos_ptr;
3245 }
3246 tos_ptr += tos_rowstride - width;
3247 nos_ptr += nos_rowstride - width;
3248 if (mask_row_ptr != NULL)
3249 mask_row_ptr += maskbuf->rowstride;
3250 }
3251 }
3252
3253 static void
compose_group_nonknockout_nonblend_isolated_nomask_common(byte * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,byte alpha,byte shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,byte * tos_alpha_g_ptr,byte * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,byte * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,byte * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,byte mask_bg_alpha,const byte * mask_tr_fn,byte * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3254 compose_group_nonknockout_nonblend_isolated_nomask_common(byte *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3255 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3256 byte *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3257 int nos_shape_offset, int nos_tag_offset,
3258 byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3259 byte *backdrop_ptr,
3260 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3261 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3262 {
3263 template_compose_group(tos_ptr, /*tos_isolated*/1, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
3264 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/0,
3265 nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
3266 /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, /*has_mask*/0, /*maskbuf*/NULL, mask_bg_alpha, mask_tr_fn,
3267 backdrop_ptr, /*has_matte*/0, n_chan, /*additive*/1, /*num_spots*/0, /*overprint*/0, /*drawn_comps*/0, x0, y0, x1, y1, pblend_procs, pdev, 1);
3268 }
3269
3270 static void
compose_group_nonknockout_nonblend_nonisolated_mask_common(byte * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,byte alpha,byte shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,byte * tos_alpha_g_ptr,byte * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,byte * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,byte * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,byte mask_bg_alpha,const byte * mask_tr_fn,byte * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3271 compose_group_nonknockout_nonblend_nonisolated_mask_common(byte *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3272 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3273 byte *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3274 int nos_shape_offset, int nos_tag_offset,
3275 byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3276 byte *backdrop_ptr,
3277 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3278 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3279 {
3280 template_compose_group(tos_ptr, /*tos_isolated*/0, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
3281 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/0,
3282 nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
3283 /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3284 backdrop_ptr, /*has_matte*/0, n_chan, /*additive*/1, /*num_spots*/0, /*overprint*/0, /*drawn_comps*/0, x0, y0, x1, y1, pblend_procs, pdev, 1);
3285 }
3286
3287 static void
compose_group_nonknockout_nonblend_nonisolated_nomask_common(byte * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,byte alpha,byte shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,byte * tos_alpha_g_ptr,byte * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,byte * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,byte * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,byte mask_bg_alpha,const byte * mask_tr_fn,byte * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3288 compose_group_nonknockout_nonblend_nonisolated_nomask_common(byte *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3289 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3290 byte *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3291 int nos_shape_offset, int nos_tag_offset,
3292 byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3293 byte *backdrop_ptr,
3294 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3295 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3296 {
3297 template_compose_group(tos_ptr, /*tos_isolated*/0, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
3298 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/0,
3299 nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
3300 /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, /*has_mask*/0, /*maskbuf*/NULL, mask_bg_alpha, mask_tr_fn,
3301 backdrop_ptr, /*has_matte*/0, n_chan, /*additive*/1, /*num_spots*/0, /*overprint*/0, /*drawn_comps*/0, x0, y0, x1, y1, pblend_procs, pdev, 1);
3302 }
3303
3304 static void
compose_group_nonknockout_noblend_general(byte * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,byte alpha,byte shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,byte * tos_alpha_g_ptr,byte * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,byte * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,byte * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,byte mask_bg_alpha,const byte * mask_tr_fn,byte * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3305 compose_group_nonknockout_noblend_general(byte *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3306 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3307 byte *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3308 int nos_shape_offset, int nos_tag_offset,
3309 byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3310 byte *backdrop_ptr,
3311 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3312 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3313 {
3314 template_compose_group(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, tos_has_shape,
3315 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3316 nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
3317 nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3318 backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1);
3319 }
3320
3321 static void
compose_group_alphaless_knockout(byte * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,byte alpha,byte shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,byte * tos_alpha_g_ptr,byte * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,byte * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,byte * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,byte mask_bg_alpha,const byte * mask_tr_fn,byte * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3322 compose_group_alphaless_knockout(byte *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3323 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3324 byte *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3325 int nos_shape_offset, int nos_tag_offset,
3326 byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3327 byte *backdrop_ptr,
3328 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3329 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3330 {
3331 template_compose_group(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, blend_mode, tos_has_shape,
3332 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3333 nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */1,
3334 nos_shape_offset, nos_tag_offset, /* mask_row_ptr */ NULL, /* has_mask */ 0, /* maskbuf */ NULL, mask_bg_alpha, /* mask_tr_fn */ NULL,
3335 backdrop_ptr, /* has_matte */ false , n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 0);
3336 }
3337
3338 static void
compose_group_alphaless_nonknockout(byte * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,byte alpha,byte shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,byte * tos_alpha_g_ptr,byte * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,byte * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,byte * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,byte mask_bg_alpha,const byte * mask_tr_fn,byte * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3339 compose_group_alphaless_nonknockout(byte *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3340 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3341 byte *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3342 int nos_shape_offset, int nos_tag_offset,
3343 byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3344 byte *backdrop_ptr,
3345 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3346 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3347 {
3348 template_compose_group(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, blend_mode, tos_has_shape,
3349 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3350 nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
3351 nos_shape_offset, nos_tag_offset, /* mask_row_ptr */ NULL, /* has_mask */ 0, /* maskbuf */ NULL, mask_bg_alpha, /* mask_tr_fn */ NULL,
3352 backdrop_ptr, /* has_matte */ false , n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 0);
3353 }
3354
3355 static void
do_compose_group(pdf14_buf * tos,pdf14_buf * nos,pdf14_buf * maskbuf,int x0,int x1,int y0,int y1,int n_chan,bool additive,const pdf14_nonseparable_blending_procs_t * pblend_procs,bool has_matte,bool overprint,gx_color_index drawn_comps,gs_memory_t * memory,gx_device * dev)3356 do_compose_group(pdf14_buf *tos, pdf14_buf *nos, pdf14_buf *maskbuf,
3357 int x0, int x1, int y0, int y1, int n_chan, bool additive,
3358 const pdf14_nonseparable_blending_procs_t * pblend_procs,
3359 bool has_matte, bool overprint, gx_color_index drawn_comps,
3360 gs_memory_t *memory, gx_device *dev)
3361 {
3362 int num_spots = tos->num_spots;
3363 byte alpha = tos->alpha>>8;
3364 byte shape = tos->shape>>8;
3365 gs_blend_mode_t blend_mode = tos->blend_mode;
3366 byte *tos_ptr = tos->data + x0 - tos->rect.p.x +
3367 (y0 - tos->rect.p.y) * tos->rowstride;
3368 byte *nos_ptr = nos->data + x0 - nos->rect.p.x +
3369 (y0 - nos->rect.p.y) * nos->rowstride;
3370 byte *mask_row_ptr = NULL;
3371 int tos_planestride = tos->planestride;
3372 int nos_planestride = nos->planestride;
3373 byte mask_bg_alpha = 0; /* Quiet compiler. */
3374 bool tos_isolated = tos->isolated;
3375 bool nos_isolated = nos->isolated;
3376 bool nos_knockout = nos->knockout;
3377 byte *nos_alpha_g_ptr;
3378 byte *tos_alpha_g_ptr;
3379 int tos_shape_offset = n_chan * tos_planestride;
3380 int tos_alpha_g_offset = tos_shape_offset + (tos->has_shape ? tos_planestride : 0);
3381 bool tos_has_tag = tos->has_tags;
3382 int tos_tag_offset = tos_planestride * (tos->n_planes - 1);
3383 int nos_shape_offset = n_chan * nos_planestride;
3384 int nos_alpha_g_offset = nos_shape_offset + (nos->has_shape ? nos_planestride : 0);
3385 int nos_tag_offset = nos_planestride * (nos->n_planes - 1);
3386 byte *mask_tr_fn = NULL; /* Quiet compiler. */
3387 bool is_ident = true;
3388 bool has_mask = false;
3389 byte *backdrop_ptr = NULL;
3390 pdf14_device *pdev = (pdf14_device *)dev;
3391
3392
3393 #if RAW_DUMP
3394 byte *composed_ptr = NULL;
3395 int width = x1 - x0;
3396 #endif
3397 art_pdf_compose_group_fn fn;
3398
3399 if ((tos->n_chan == 0) || (nos->n_chan == 0))
3400 return;
3401 rect_merge(nos->dirty, tos->dirty);
3402 if (nos->has_tags)
3403 if_debug7m('v', memory,
3404 "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, tag = %d, bm = %d\n",
3405 y0, y1, x1 - x0, alpha, shape, dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS, blend_mode);
3406 else
3407 if_debug6m('v', memory,
3408 "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, bm = %d\n",
3409 y0, y1, x1 - x0, alpha, shape, blend_mode);
3410 if (!nos->has_shape)
3411 nos_shape_offset = 0;
3412 if (!nos->has_tags)
3413 nos_tag_offset = 0;
3414 if (nos->has_alpha_g) {
3415 nos_alpha_g_ptr = nos_ptr + nos_alpha_g_offset;
3416 } else
3417 nos_alpha_g_ptr = NULL;
3418 if (tos->has_alpha_g) {
3419 tos_alpha_g_ptr = tos_ptr + tos_alpha_g_offset;
3420 } else
3421 tos_alpha_g_ptr = NULL;
3422 if (nos->backdrop != NULL) {
3423 backdrop_ptr = nos->backdrop + x0 - nos->rect.p.x +
3424 (y0 - nos->rect.p.y) * nos->rowstride;
3425 }
3426 if (blend_mode != BLEND_MODE_Compatible && blend_mode != BLEND_MODE_Normal)
3427 overprint = false;
3428
3429 if (maskbuf != NULL) {
3430 int tmp;
3431
3432 mask_tr_fn = maskbuf->transfer_fn;
3433
3434 is_ident = maskbuf->is_ident;
3435 /* Make sure we are in the mask buffer */
3436 if (maskbuf->data != NULL) {
3437 mask_row_ptr = maskbuf->data + x0 - maskbuf->rect.p.x +
3438 (y0 - maskbuf->rect.p.y) * maskbuf->rowstride;
3439 has_mask = true;
3440 }
3441 /* We may have a case, where we are outside the maskbuf rect. */
3442 /* We would have avoided creating the maskbuf->data */
3443 /* In that case, we should use the background alpha value */
3444 /* See discussion on the BC entry in the PDF spec. */
3445 mask_bg_alpha = maskbuf->alpha>>8;
3446 /* Adjust alpha by the mask background alpha. This is only used
3447 if we are outside the soft mask rect during the filling operation */
3448 mask_bg_alpha = mask_tr_fn[mask_bg_alpha];
3449 tmp = alpha * mask_bg_alpha + 0x80;
3450 mask_bg_alpha = (tmp + (tmp >> 8)) >> 8;
3451 }
3452 n_chan--; /* Now the true number of colorants (i.e. not including alpha)*/
3453 #if RAW_DUMP
3454 composed_ptr = nos_ptr;
3455 dump_raw_buffer(memory, y1-y0, width, tos->n_planes, tos_planestride, tos->rowstride,
3456 "bImageTOS", tos_ptr, tos->deep);
3457 dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
3458 "cImageNOS", nos_ptr, tos->deep);
3459 if (maskbuf !=NULL && maskbuf->data != NULL) {
3460 dump_raw_buffer(memory, maskbuf->rect.q.y - maskbuf->rect.p.y,
3461 maskbuf->rect.q.x - maskbuf->rect.p.x, maskbuf->n_planes,
3462 maskbuf->planestride, maskbuf->rowstride, "dMask",
3463 maskbuf->data, maskbuf->deep);
3464 }
3465 #endif
3466
3467 /* You might hope that has_mask iff maskbuf != NULL, but this is
3468 * not the case. Certainly we can see cases where maskbuf != NULL
3469 * and has_mask = 0. What's more, treating such cases as being
3470 * has_mask = 0 causes diffs. */
3471 #ifdef TRACK_COMPOSE_GROUPS
3472 {
3473 int code = 0;
3474
3475 code += !!nos_knockout;
3476 code += (!!nos_isolated)<<1;
3477 code += (!!tos_isolated)<<2;
3478 code += (!!tos->has_shape)<<3;
3479 code += (!!tos_has_tag)<<4;
3480 code += (!!additive)<<5;
3481 code += (!!overprint)<<6;
3482 code += (!!has_mask || maskbuf != NULL)<<7;
3483 code += (!!has_matte)<<8;
3484 code += (backdrop_ptr != NULL)<<9;
3485 code += (num_spots != 0)<<10;
3486 code += blend_mode<<11;
3487
3488 if (track_compose_groups == 0)
3489 {
3490 atexit(dump_track_compose_groups);
3491 track_compose_groups = 1;
3492 }
3493 compose_groups[code]++;
3494 }
3495 #endif
3496
3497 /* We have tested the files on the cluster to see what percentage of
3498 * files/devices hit the different options. */
3499 if (nos_knockout)
3500 fn = &compose_group_knockout; /* Small %ages, nothing more than 1.1% */
3501 else if (blend_mode != 0)
3502 fn = &compose_group_nonknockout_blend; /* Small %ages, nothing more than 2% */
3503 else if (tos->has_shape == 0 && tos_has_tag == 0 && nos_isolated == 0 && nos_alpha_g_ptr == NULL &&
3504 nos_shape_offset == 0 && nos_tag_offset == 0 && backdrop_ptr == NULL && has_matte == 0 && num_spots == 0 &&
3505 overprint == 0 && tos_alpha_g_ptr == NULL) {
3506 /* Additive vs Subtractive makes no difference in normal blend mode with no spots */
3507 if (tos_isolated) {
3508 if (has_mask && maskbuf) {/* 7% */
3509 /* AirPrint test case hits this */
3510 if (maskbuf && maskbuf->rect.p.x <= x0 && maskbuf->rect.p.y <= y0 &&
3511 maskbuf->rect.q.x >= x1 && maskbuf->rect.q.y >= y1) {
3512 /* AVX and SSE accelerations only valid if maskbuf transfer
3513 function is identity and we have no matte color replacement */
3514 if (is_ident && !has_matte) {
3515 fn = compose_group_nonknockout_nonblend_isolated_allmask_common;
3516 #ifdef WITH_CAL
3517 fn = (art_pdf_compose_group_fn)cal_get_compose_group(
3518 memory->gs_lib_ctx->core->cal_ctx,
3519 (cal_composer_proc_t *)fn,
3520 tos->n_chan-1);
3521 #endif
3522 } else {
3523 fn = compose_group_nonknockout_nonblend_isolated_allmask_common;
3524 }
3525 } else
3526 fn = &compose_group_nonknockout_nonblend_isolated_mask_common;
3527 } else
3528 if (maskbuf) {
3529 /* Outside mask */
3530 fn = &compose_group_nonknockout_nonblend_isolated_mask_common;
3531 } else
3532 fn = &compose_group_nonknockout_nonblend_isolated_nomask_common;
3533 } else {
3534 if (has_mask || maskbuf) /* 4% */
3535 fn = &compose_group_nonknockout_nonblend_nonisolated_mask_common;
3536 else /* 15% */
3537 fn = &compose_group_nonknockout_nonblend_nonisolated_nomask_common;
3538 }
3539 } else
3540 fn = compose_group_nonknockout_noblend_general;
3541
3542 fn(tos_ptr, tos_isolated, tos_planestride, tos->rowstride, alpha, shape,
3543 blend_mode, tos->has_shape, tos_shape_offset, tos_alpha_g_offset,
3544 tos_tag_offset, tos_has_tag, tos_alpha_g_ptr, nos_ptr, nos_isolated, nos_planestride,
3545 nos->rowstride, nos_alpha_g_ptr, nos_knockout, nos_shape_offset,
3546 nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha,
3547 mask_tr_fn, backdrop_ptr, has_matte, n_chan, additive, num_spots,
3548 overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev);
3549
3550 #if RAW_DUMP
3551 dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
3552 "eComposed", composed_ptr, nos->deep);
3553 global_index++;
3554 #endif
3555 }
3556
3557 static inline uint16_t
interp16(const uint16_t * table,uint16_t idx)3558 interp16(const uint16_t *table, uint16_t idx)
3559 {
3560 byte top = idx>>8;
3561 uint16_t a = table[top];
3562 int b = table[top+1]-a;
3563
3564 return a + ((0x80 + b*(idx & 0xff))>>8);
3565 }
3566
3567 typedef void (*art_pdf_compose_group16_fn)(uint16_t *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
3568 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3569 int tos_shape_offset, int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag,
3570 uint16_t *tos_alpha_g_ptr,
3571 uint16_t *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride,
3572 uint16_t *nos_alpha_g_ptr, bool nos_knockout, int nos_shape_offset, int nos_tag_offset,
3573 uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn,
3574 uint16_t *backdrop_ptr, bool has_matte, int n_chan, bool additive, int num_spots, bool overprint,
3575 gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3576 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev);
3577
3578 static forceinline void
template_compose_group16(uint16_t * gs_restrict tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,uint16_t alpha,uint16_t shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,uint16_t * gs_restrict tos_alpha_g_ptr,uint16_t * gs_restrict nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,uint16_t * gs_restrict nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,uint16_t * gs_restrict mask_row_ptr,int has_mask,pdf14_buf * gs_restrict maskbuf,uint16_t mask_bg_alpha,const uint16_t * gs_restrict mask_tr_fn,uint16_t * gs_restrict backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev,int has_alpha,bool tos_is_be)3579 template_compose_group16(uint16_t *gs_restrict tos_ptr, bool tos_isolated,
3580 int tos_planestride, int tos_rowstride,
3581 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode,
3582 bool tos_has_shape, int tos_shape_offset,
3583 int tos_alpha_g_offset, int tos_tag_offset,
3584 bool tos_has_tag, uint16_t *gs_restrict tos_alpha_g_ptr,
3585 uint16_t *gs_restrict nos_ptr,
3586 bool nos_isolated, int nos_planestride,
3587 int nos_rowstride, uint16_t *gs_restrict nos_alpha_g_ptr,
3588 bool nos_knockout, int nos_shape_offset,
3589 int nos_tag_offset, uint16_t *gs_restrict mask_row_ptr,
3590 int has_mask, pdf14_buf *gs_restrict maskbuf,
3591 uint16_t mask_bg_alpha, const uint16_t *gs_restrict mask_tr_fn,
3592 uint16_t *gs_restrict backdrop_ptr, bool has_matte,
3593 int n_chan, bool additive, int num_spots,
3594 bool overprint, gx_color_index drawn_comps,
3595 int x0, int y0, int x1, int y1,
3596 const pdf14_nonseparable_blending_procs_t *pblend_procs,
3597 pdf14_device *pdev, int has_alpha, bool tos_is_be)
3598 {
3599 uint16_t *gs_restrict mask_curr_ptr = NULL;
3600 int width = x1 - x0;
3601 int x, y;
3602 int i;
3603 uint16_t tos_pixel[PDF14_MAX_PLANES];
3604 uint16_t nos_pixel[PDF14_MAX_PLANES];
3605 uint16_t back_drop[PDF14_MAX_PLANES];
3606 bool in_mask_rect_y;
3607 bool in_mask_rect;
3608 uint16_t pix_alpha;
3609 uint16_t matte_alpha = 0xffff;
3610 int first_spot = n_chan - num_spots;
3611 int first_blend_spot = n_chan;
3612 bool has_mask2 = has_mask;
3613 uint16_t *gs_restrict dst;
3614 uint16_t global_shape = (uint16_t)(65535 * pdev->shape + 0.5);
3615
3616 if (!nos_knockout && num_spots > 0 && !blend_valid_for_spot(blend_mode)) {
3617 first_blend_spot = first_spot;
3618 }
3619 if (blend_mode == BLEND_MODE_Normal)
3620 first_blend_spot = 0;
3621 if (!nos_isolated && backdrop_ptr != NULL)
3622 has_mask2 = false;
3623
3624 /* TOS data being passed to this routine is usually in native
3625 * endian format (i.e. if it's from another pdf14 buffer). Occasionally,
3626 * if it's being passed in from pdf_compose_alphaless_group16, it can be
3627 * from memory produced by another memory device (such as a pattern
3628 * cache device). That data is in big endian form. So we have a crufty
3629 * macro to get 16 bits of data from either native or bigendian into
3630 * a native value. This should resolve nicely at compile time. */
3631 #define GET16_2NATIVE(be, v) \
3632 ((be) ? ((((byte *)&v)[0]<<8) | (((byte *)&v)[1])) : v)
3633
3634 for (y = y1 - y0; y > 0; --y) {
3635 mask_curr_ptr = mask_row_ptr;
3636 in_mask_rect_y = (has_mask && y1 - y >= maskbuf->rect.p.y && y1 - y < maskbuf->rect.q.y);
3637 for (x = 0; x < width; x++) {
3638 in_mask_rect = (in_mask_rect_y && x0 + x >= maskbuf->rect.p.x && x0 + x < maskbuf->rect.q.x);
3639 pix_alpha = alpha;
3640 /* If we have a soft mask, then we have some special handling of the
3641 group alpha value */
3642 if (maskbuf != NULL) {
3643 if (!in_mask_rect) {
3644 /* Special case where we have a soft mask but are outside
3645 the range of the soft mask and must use the background
3646 alpha value */
3647 pix_alpha = mask_bg_alpha;
3648 matte_alpha = 0xffff;
3649 } else {
3650 if (has_matte)
3651 matte_alpha = interp16(mask_tr_fn, *mask_curr_ptr);
3652 }
3653 }
3654
3655 /* Matte present, need to undo premultiplied alpha prior to blend */
3656 if (has_matte && matte_alpha != 0 && matte_alpha != 0xffff) {
3657 for (i = 0; i < n_chan; i++) {
3658 /* undo */
3659 int val = GET16_2NATIVE(tos_is_be, tos_ptr[i * tos_planestride]) - maskbuf->matte[i];
3660 int temp = (((unsigned int)(val * 0xffff)) / matte_alpha) + maskbuf->matte[i];
3661
3662 /* clip */
3663 if (temp > 0xffff)
3664 tos_pixel[i] = 0xffff;
3665 else if (temp < 0)
3666 tos_pixel[i] = 0;
3667 else
3668 tos_pixel[i] = temp;
3669
3670 if (!additive) {
3671 /* Pure subtractive */
3672 tos_pixel[i] = 65535 - tos_pixel[i];
3673 nos_pixel[i] = 65535 - nos_ptr[i * nos_planestride];
3674 } else {
3675 /* additive or hybrid */
3676 if (i >= first_spot)
3677 nos_pixel[i] = 65535 - nos_ptr[i * nos_planestride];
3678 else
3679 nos_pixel[i] = nos_ptr[i * nos_planestride];
3680 }
3681 }
3682 } else {
3683 /* No matte present */
3684 if (!additive) {
3685 /* Pure subtractive */
3686 for (i = 0; i < n_chan; ++i) {
3687 tos_pixel[i] = 65535 - GET16_2NATIVE(tos_is_be, tos_ptr[i * tos_planestride]);
3688 nos_pixel[i] = 65535 - nos_ptr[i * nos_planestride];
3689 }
3690 } else {
3691 /* Additive or hybrid */
3692 for (i = 0; i < first_spot; ++i) {
3693 tos_pixel[i] = GET16_2NATIVE(tos_is_be, tos_ptr[i * tos_planestride]);
3694 nos_pixel[i] = nos_ptr[i * nos_planestride];
3695 }
3696 for (; i < n_chan; i++) {
3697 tos_pixel[i] = 65535 - GET16_2NATIVE(tos_is_be, tos_ptr[i * tos_planestride]);
3698 nos_pixel[i] = 65535 - nos_ptr[i * nos_planestride];
3699 }
3700 }
3701 }
3702 /* alpha */
3703 tos_pixel[n_chan] = has_alpha ? GET16_2NATIVE(tos_is_be, tos_ptr[n_chan * tos_planestride]) : 65535;
3704 nos_pixel[n_chan] = has_alpha ? nos_ptr[n_chan * nos_planestride] : 65535;
3705
3706 if (mask_curr_ptr != NULL) {
3707 if (in_mask_rect) {
3708 uint16_t mask = interp16(mask_tr_fn, *mask_curr_ptr++);
3709 int tmp = pix_alpha * (mask+(mask>>15)) + 0x8000;
3710 pix_alpha = (tmp >> 16);
3711 } else {
3712 mask_curr_ptr++;
3713 }
3714 }
3715
3716 dst = nos_pixel;
3717 if (nos_knockout) {
3718 /* We need to be knocking out what ever is on the nos, but may
3719 need to combine with it's backdrop */
3720 uint16_t tos_shape = 65535;
3721
3722 if (tos_has_shape)
3723 tos_shape = GET16_2NATIVE(tos_is_be, tos_ptr[tos_shape_offset]);
3724
3725 if (nos_isolated || backdrop_ptr == NULL) {
3726 /* We do not need to compose with the backdrop */
3727 back_drop[n_chan] = 0;
3728 /* FIXME: The blend here can be simplified */
3729 } else {
3730 /* Per the PDF spec, since the tos is not isolated and we are
3731 going onto a knock out group, we do the composition with
3732 the nos initial backdrop. */
3733 if (additive) {
3734 /* additive or hybrid */
3735 for (i = 0; i < first_spot; ++i) {
3736 back_drop[i] = backdrop_ptr[i * nos_planestride];
3737 }
3738 for (; i < n_chan; i++) {
3739 back_drop[i] = 65535 - backdrop_ptr[i * nos_planestride];
3740 }
3741 } else {
3742 /* pure subtractive */
3743 for (i = 0; i < n_chan; ++i) {
3744 back_drop[i] = 65535 - backdrop_ptr[i * nos_planestride];
3745 }
3746 }
3747 /* alpha */
3748 back_drop[n_chan] = backdrop_ptr[n_chan * nos_planestride];
3749 }
3750
3751 if (tos_isolated ?
3752 art_pdf_ko_composite_group_16(tos_shape, tos_alpha_g_ptr,
3753 nos_pixel, nos_alpha_g_ptr,
3754 tos_pixel, n_chan, pix_alpha,
3755 has_mask2) :
3756 art_pdf_ko_recomposite_group_16(tos_shape, has_alpha ? tos_ptr[tos_alpha_g_offset] : 65535,
3757 &dst, nos_alpha_g_ptr, tos_pixel, n_chan, pix_alpha,
3758 blend_mode, has_mask2)) {
3759 dst = art_pdf_knockout_composite_pixel_alpha_16(back_drop, tos_shape, nos_pixel, tos_pixel,
3760 n_chan, blend_mode, pblend_procs, pdev);
3761 }
3762 }
3763 else if (tos_isolated ?
3764 art_pdf_composite_group_16(nos_pixel, nos_alpha_g_ptr,
3765 tos_pixel, n_chan, pix_alpha) :
3766 art_pdf_recomposite_group_16(&dst, nos_alpha_g_ptr,
3767 tos_pixel,
3768 has_alpha ? GET16_2NATIVE(tos_is_be, tos_ptr[tos_alpha_g_offset]) : 65535,
3769 n_chan,
3770 pix_alpha, blend_mode)) {
3771 dst = art_pdf_composite_pixel_alpha_16_inline(nos_pixel, tos_pixel, n_chan,
3772 blend_mode, first_blend_spot,
3773 pblend_procs, pdev);
3774 }
3775 if (nos_shape_offset && pix_alpha != 0) {
3776 nos_ptr[nos_shape_offset] =
3777 art_pdf_union_mul_16(nos_ptr[nos_shape_offset],
3778 has_alpha ? GET16_2NATIVE(tos_is_be, tos_ptr[tos_shape_offset]) : global_shape,
3779 shape);
3780 }
3781 if (dst)
3782 {
3783 /* Complement the results for subtractive color spaces. Again,
3784 * if we are in an additive blending color space, we are not
3785 * going to be fooling with overprint of spot colors */
3786 if (additive) {
3787 /* additive or hybrid */
3788 for (i = 0; i < first_spot; ++i) {
3789 nos_ptr[i * nos_planestride] = dst[i];
3790 }
3791 for (; i < n_chan; i++) {
3792 nos_ptr[i * nos_planestride] = 65535 - dst[i];
3793 }
3794 } else {
3795 /* Pure subtractive */
3796 for (i = 0; i < n_chan; ++i)
3797 nos_ptr[i * nos_planestride] = 65535 - dst[i];
3798 }
3799 /* alpha */
3800 nos_ptr[n_chan * nos_planestride] = dst[n_chan];
3801 }
3802 /* tags */
3803 if (nos_tag_offset && tos_has_tag) {
3804 nos_ptr[nos_tag_offset] |= tos_ptr[tos_tag_offset];
3805 }
3806
3807 if (nos_alpha_g_ptr != NULL)
3808 ++nos_alpha_g_ptr;
3809 if (tos_alpha_g_ptr != NULL)
3810 ++tos_alpha_g_ptr;
3811 if (backdrop_ptr != NULL)
3812 ++backdrop_ptr;
3813 ++tos_ptr;
3814 ++nos_ptr;
3815 }
3816 tos_ptr += tos_rowstride - width;
3817 nos_ptr += nos_rowstride - width;
3818 if (tos_alpha_g_ptr != NULL)
3819 tos_alpha_g_ptr += tos_rowstride - width;
3820 if (nos_alpha_g_ptr != NULL)
3821 nos_alpha_g_ptr += nos_rowstride - width;
3822 if (mask_row_ptr != NULL)
3823 mask_row_ptr += maskbuf->rowstride>>1;
3824 if (backdrop_ptr != NULL)
3825 backdrop_ptr += nos_rowstride - width;
3826 }
3827 }
3828
3829 static void
compose_group16_knockout(uint16_t * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,uint16_t alpha,uint16_t shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,uint16_t * tos_alpha_g_ptr,uint16_t * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,uint16_t * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,uint16_t * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,uint16_t mask_bg_alpha,const uint16_t * mask_tr_fn,uint16_t * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3830 compose_group16_knockout(uint16_t *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
3831 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, int tos_shape_offset,
3832 int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr,
3833 uint16_t *nos_ptr, bool nos_isolated, int nos_planestride, int nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout,
3834 int nos_shape_offset, int nos_tag_offset,
3835 uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn,
3836 uint16_t *backdrop_ptr,
3837 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3838 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3839 {
3840 template_compose_group16(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, blend_mode, tos_has_shape,
3841 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3842 nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */1,
3843 nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3844 backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1, 0);
3845 }
3846
3847 static void
compose_group16_nonknockout_blend(uint16_t * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,uint16_t alpha,uint16_t shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,uint16_t * tos_alpha_g_ptr,uint16_t * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,uint16_t * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,uint16_t * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,uint16_t mask_bg_alpha,const uint16_t * mask_tr_fn,uint16_t * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3848 compose_group16_nonknockout_blend(uint16_t *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
3849 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, int tos_shape_offset, int tos_alpha_g_offset,
3850 int tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, int nos_planestride,
3851 int nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, int nos_shape_offset, int nos_tag_offset,
3852 uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn, uint16_t *backdrop_ptr,
3853 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3854 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3855 {
3856 template_compose_group16(tos_ptr, tos_isolated, tos_planestride, tos_rowstride,
3857 alpha, shape, blend_mode, tos_has_shape,
3858 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag,
3859 tos_alpha_g_ptr, nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
3860 nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3861 backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1, 0);
3862 }
3863
3864 static void
compose_group16_nonknockout_nonblend_isolated_allmask_common(uint16_t * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,uint16_t alpha,uint16_t shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,uint16_t * tos_alpha_g_ptr,uint16_t * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,uint16_t * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,uint16_t * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,uint16_t mask_bg_alpha,const uint16_t * mask_tr_fn,uint16_t * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3865 compose_group16_nonknockout_nonblend_isolated_allmask_common(uint16_t *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
3866 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, int tos_shape_offset, int tos_alpha_g_offset,
3867 int tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, int nos_planestride,
3868 int nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, int nos_shape_offset, int nos_tag_offset,
3869 uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn, uint16_t *backdrop_ptr,
3870 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3871 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3872 {
3873 int width = x1 - x0;
3874 int x, y;
3875 int i;
3876
3877 for (y = y1 - y0; y > 0; --y) {
3878 uint16_t *gs_restrict mask_curr_ptr = mask_row_ptr;
3879 for (x = 0; x < width; x++) {
3880 unsigned int mask = interp16(mask_tr_fn, *mask_curr_ptr++);
3881 uint16_t src_alpha = tos_ptr[n_chan * tos_planestride];
3882 if (src_alpha != 0) {
3883 uint16_t a_b;
3884 unsigned int pix_alpha;
3885
3886 mask += mask>>15;
3887 pix_alpha = (alpha * mask + 0x8000)>>16;
3888
3889 if (pix_alpha != 0xffff) {
3890 pix_alpha += pix_alpha>>15;
3891 src_alpha = (src_alpha * pix_alpha + 0x8000)>>16;
3892 }
3893
3894 a_b = nos_ptr[n_chan * nos_planestride];
3895 if (a_b == 0) {
3896 /* Simple copy of colors plus alpha. */
3897 for (i = 0; i < n_chan; i++) {
3898 nos_ptr[i * nos_planestride] = tos_ptr[i * tos_planestride];
3899 }
3900 nos_ptr[i * nos_planestride] = src_alpha;
3901 } else {
3902 unsigned int a_r;
3903 int src_scale;
3904 unsigned int tmp;
3905
3906 /* Result alpha is Union of backdrop and source alpha */
3907 tmp = (0xffff - a_b) * (0xffff - src_alpha) + 0x8000;
3908 tmp += tmp>>16;
3909 a_r = 0xffff - (tmp >> 16);
3910
3911 /* Compute src_alpha / a_r in 16.16 format */
3912 src_scale = ((src_alpha << 16) + (a_r >> 1)) / a_r;
3913
3914 nos_ptr[n_chan * nos_planestride] = a_r;
3915
3916 src_scale >>= 1; /* Will overflow unless we lose a bit */
3917 /* Do simple compositing of source over backdrop */
3918 for (i = 0; i < n_chan; i++) {
3919 int c_s = tos_ptr[i * tos_planestride];
3920 int c_b = nos_ptr[i * nos_planestride];
3921 nos_ptr[i * nos_planestride] = c_b + ((src_scale * (c_s - c_b) + 0x4000) >> 15);
3922 }
3923 }
3924 }
3925 ++tos_ptr;
3926 ++nos_ptr;
3927 }
3928 tos_ptr += tos_rowstride - width;
3929 nos_ptr += nos_rowstride - width;
3930 mask_row_ptr += maskbuf->rowstride>>1;
3931 }
3932 }
3933
3934 static void
compose_group16_nonknockout_nonblend_isolated_mask_common(uint16_t * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,uint16_t alpha,uint16_t shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,uint16_t * tos_alpha_g_ptr,uint16_t * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,uint16_t * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,uint16_t * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,uint16_t mask_bg_alpha,const uint16_t * mask_tr_fn,uint16_t * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)3935 compose_group16_nonknockout_nonblend_isolated_mask_common(uint16_t *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
3936 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, int tos_shape_offset, int tos_alpha_g_offset,
3937 int tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, int nos_planestride,
3938 int nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, int nos_shape_offset, int nos_tag_offset,
3939 uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn, uint16_t *backdrop_ptr,
3940 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3941 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3942 {
3943 uint16_t *gs_restrict mask_curr_ptr = NULL;
3944 int width = x1 - x0;
3945 int x, y;
3946 int i;
3947 bool in_mask_rect_y;
3948 bool in_mask_rect;
3949 uint16_t pix_alpha, src_alpha;
3950
3951 for (y = y1 - y0; y > 0; --y) {
3952 mask_curr_ptr = mask_row_ptr;
3953 in_mask_rect_y = (has_mask && y1 - y >= maskbuf->rect.p.y && y1 - y < maskbuf->rect.q.y);
3954 for (x = 0; x < width; x++) {
3955 in_mask_rect = (in_mask_rect_y && has_mask && x0 + x >= maskbuf->rect.p.x && x0 + x < maskbuf->rect.q.x);
3956 pix_alpha = alpha;
3957 /* If we have a soft mask, then we have some special handling of the
3958 group alpha value */
3959 if (maskbuf != NULL) {
3960 if (!in_mask_rect) {
3961 /* Special case where we have a soft mask but are outside
3962 the range of the soft mask and must use the background
3963 alpha value */
3964 pix_alpha = mask_bg_alpha;
3965 }
3966 }
3967
3968 if (mask_curr_ptr != NULL) {
3969 if (in_mask_rect) {
3970 unsigned int mask = interp16(mask_tr_fn, *mask_curr_ptr++);
3971 mask += mask>>15;
3972 pix_alpha = (pix_alpha * mask + 0x8000)>>16;
3973 } else {
3974 mask_curr_ptr++;
3975 }
3976 }
3977
3978 src_alpha = tos_ptr[n_chan * tos_planestride];
3979 if (src_alpha != 0) {
3980 uint16_t a_b;
3981
3982 if (pix_alpha != 65535) {
3983 pix_alpha += pix_alpha>>15;
3984 src_alpha = (src_alpha * pix_alpha + 0x8000)>>16;
3985 }
3986
3987 a_b = nos_ptr[n_chan * nos_planestride];
3988 if (a_b == 0) {
3989 /* Simple copy of colors plus alpha. */
3990 for (i = 0; i < n_chan; i++) {
3991 nos_ptr[i * nos_planestride] = tos_ptr[i * tos_planestride];
3992 }
3993 nos_ptr[i * nos_planestride] = src_alpha;
3994 } else {
3995 unsigned int a_r;
3996 int src_scale;
3997 unsigned int tmp;
3998
3999 /* Result alpha is Union of backdrop and source alpha */
4000 tmp = (0xffff - a_b) * (0xffff - src_alpha) + 0x8000;
4001 tmp += tmp>>16;
4002 a_r = 0xffff - (tmp >> 16);
4003
4004 /* Compute src_alpha / a_r in 16.16 format */
4005 src_scale = ((src_alpha << 16) + (a_r >> 1)) / a_r;
4006
4007 nos_ptr[n_chan * nos_planestride] = a_r;
4008
4009 src_scale >>= 1; /* Need to lose a bit to avoid overflow */
4010 /* Do simple compositing of source over backdrop */
4011 for (i = 0; i < n_chan; i++) {
4012 int c_s = tos_ptr[i * tos_planestride];
4013 int c_b = nos_ptr[i * nos_planestride];
4014 nos_ptr[i * nos_planestride] = c_b + ((src_scale * (c_s - c_b) + 0x4000) >> 15);
4015 }
4016 }
4017 }
4018 ++tos_ptr;
4019 ++nos_ptr;
4020 }
4021 tos_ptr += tos_rowstride - width;
4022 nos_ptr += nos_rowstride - width;
4023 if (mask_row_ptr != NULL)
4024 mask_row_ptr += maskbuf->rowstride>>1;
4025 }
4026 }
4027
4028 static void
compose_group16_nonknockout_nonblend_isolated_nomask_common(uint16_t * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,uint16_t alpha,uint16_t shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,uint16_t * tos_alpha_g_ptr,uint16_t * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,uint16_t * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,uint16_t * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,uint16_t mask_bg_alpha,const uint16_t * mask_tr_fn,uint16_t * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)4029 compose_group16_nonknockout_nonblend_isolated_nomask_common(uint16_t *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
4030 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, int tos_shape_offset, int tos_alpha_g_offset,
4031 int tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, int nos_planestride,
4032 int nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, int nos_shape_offset, int nos_tag_offset,
4033 uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn, uint16_t *backdrop_ptr,
4034 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
4035 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
4036 {
4037 template_compose_group16(tos_ptr, /*tos_isolated*/1, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
4038 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/ 0,
4039 nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
4040 /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, /*has_mask*/0, /*maskbuf*/NULL, mask_bg_alpha, mask_tr_fn,
4041 backdrop_ptr, /*has_matte*/0, n_chan, /*additive*/1, /*num_spots*/0, /*overprint*/0, /*drawn_comps*/0, x0, y0, x1, y1, pblend_procs, pdev, 1, 0);
4042 }
4043
4044 static void
compose_group16_nonknockout_nonblend_nonisolated_mask_common(uint16_t * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,uint16_t alpha,uint16_t shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,uint16_t * tos_alpha_g_ptr,uint16_t * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,uint16_t * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,uint16_t * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,uint16_t mask_bg_alpha,const uint16_t * mask_tr_fn,uint16_t * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)4045 compose_group16_nonknockout_nonblend_nonisolated_mask_common(uint16_t *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
4046 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, int tos_shape_offset, int tos_alpha_g_offset,
4047 int tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, int nos_planestride,
4048 int nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, int nos_shape_offset, int nos_tag_offset,
4049 uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn,
4050 uint16_t *backdrop_ptr,
4051 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
4052 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
4053 {
4054 template_compose_group16(tos_ptr, /*tos_isolated*/0, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
4055 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/0,
4056 nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
4057 /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
4058 backdrop_ptr, /*has_matte*/0, n_chan, /*additive*/1, /*num_spots*/0, /*overprint*/0, /*drawn_comps*/0, x0, y0, x1, y1, pblend_procs, pdev, 1, 0);
4059 }
4060
4061 static void
compose_group16_nonknockout_nonblend_nonisolated_nomask_common(uint16_t * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,uint16_t alpha,uint16_t shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,uint16_t * tos_alpha_g_ptr,uint16_t * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,uint16_t * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,uint16_t * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,uint16_t mask_bg_alpha,const uint16_t * mask_tr_fn,uint16_t * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)4062 compose_group16_nonknockout_nonblend_nonisolated_nomask_common(uint16_t *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
4063 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, int tos_shape_offset, int tos_alpha_g_offset,
4064 int tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, int nos_planestride,
4065 int nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, int nos_shape_offset, int nos_tag_offset,
4066 uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn, uint16_t *backdrop_ptr,
4067 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
4068 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
4069 {
4070 template_compose_group16(tos_ptr, /*tos_isolated*/0, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
4071 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/0,
4072 nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
4073 /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, /*has_mask*/0, /*maskbuf*/NULL, mask_bg_alpha, mask_tr_fn,
4074 backdrop_ptr, /*has_matte*/0, n_chan, /*additive*/1, /*num_spots*/0, /*overprint*/0, /*drawn_comps*/0, x0, y0, x1, y1, pblend_procs, pdev, 1, 0);
4075 }
4076
4077 static void
compose_group16_nonknockout_noblend_general(uint16_t * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,uint16_t alpha,uint16_t shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,uint16_t * tos_alpha_g_ptr,uint16_t * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,uint16_t * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,uint16_t * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,uint16_t mask_bg_alpha,const uint16_t * mask_tr_fn,uint16_t * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)4078 compose_group16_nonknockout_noblend_general(uint16_t *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
4079 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, int tos_shape_offset,
4080 int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr,
4081 bool nos_isolated, int nos_planestride, int nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout,
4082 int nos_shape_offset, int nos_tag_offset, uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf,
4083 uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn, uint16_t *backdrop_ptr, bool has_matte, int n_chan,
4084 bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
4085 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
4086 {
4087 template_compose_group16(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, tos_has_shape,
4088 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
4089 nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
4090 nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
4091 backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1, 0);
4092 }
4093
4094 static void
compose_group16_alphaless_knockout(uint16_t * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,uint16_t alpha,uint16_t shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,uint16_t * tos_alpha_g_ptr,uint16_t * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,uint16_t * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,uint16_t * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,uint16_t mask_bg_alpha,const uint16_t * mask_tr_fn,uint16_t * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)4095 compose_group16_alphaless_knockout(uint16_t *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
4096 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, int tos_shape_offset,
4097 int tos_alpha_g_offset, int tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr,
4098 bool nos_isolated, int nos_planestride, int nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout,
4099 int nos_shape_offset, int nos_tag_offset,
4100 uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn,
4101 uint16_t *backdrop_ptr,
4102 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
4103 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
4104 {
4105 template_compose_group16(tos_ptr, tos_isolated, tos_planestride, tos_rowstride,
4106 alpha, shape, blend_mode, tos_has_shape, tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
4107 nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */1,
4108 nos_shape_offset, nos_tag_offset, /* mask_row_ptr */ NULL, /* has_mask */ 0, /* maskbuf */ NULL, mask_bg_alpha, /* mask_tr_fn */ NULL,
4109 backdrop_ptr, /* has_matte */ false , n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 0, 1);
4110 }
4111
4112 static void
compose_group16_alphaless_nonknockout(uint16_t * tos_ptr,bool tos_isolated,int tos_planestride,int tos_rowstride,uint16_t alpha,uint16_t shape,gs_blend_mode_t blend_mode,bool tos_has_shape,int tos_shape_offset,int tos_alpha_g_offset,int tos_tag_offset,bool tos_has_tag,uint16_t * tos_alpha_g_ptr,uint16_t * nos_ptr,bool nos_isolated,int nos_planestride,int nos_rowstride,uint16_t * nos_alpha_g_ptr,bool nos_knockout,int nos_shape_offset,int nos_tag_offset,uint16_t * mask_row_ptr,int has_mask,pdf14_buf * maskbuf,uint16_t mask_bg_alpha,const uint16_t * mask_tr_fn,uint16_t * backdrop_ptr,bool has_matte,int n_chan,bool additive,int num_spots,bool overprint,gx_color_index drawn_comps,int x0,int y0,int x1,int y1,const pdf14_nonseparable_blending_procs_t * pblend_procs,pdf14_device * pdev)4113 compose_group16_alphaless_nonknockout(uint16_t *tos_ptr, bool tos_isolated, int tos_planestride, int tos_rowstride,
4114 uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, int tos_shape_offset, int tos_alpha_g_offset,
4115 int tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, int nos_planestride,
4116 int nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, int nos_shape_offset, int nos_tag_offset,
4117 uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn,
4118 uint16_t *backdrop_ptr,
4119 bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
4120 const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
4121 {
4122 template_compose_group16(tos_ptr, tos_isolated, tos_planestride, tos_rowstride,
4123 alpha, shape, blend_mode, tos_has_shape, tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag,
4124 tos_alpha_g_ptr, nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
4125 nos_shape_offset, nos_tag_offset, /* mask_row_ptr */ NULL, /* has_mask */ 0, /* maskbuf */ NULL, mask_bg_alpha, /* mask_tr_fn */ NULL,
4126 backdrop_ptr, /* has_matte */ false , n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 0, 1);
4127 }
4128
4129 static void
do_compose_group16(pdf14_buf * tos,pdf14_buf * nos,pdf14_buf * maskbuf,int x0,int x1,int y0,int y1,int n_chan,bool additive,const pdf14_nonseparable_blending_procs_t * pblend_procs,bool has_matte,bool overprint,gx_color_index drawn_comps,gs_memory_t * memory,gx_device * dev)4130 do_compose_group16(pdf14_buf *tos, pdf14_buf *nos, pdf14_buf *maskbuf,
4131 int x0, int x1, int y0, int y1, int n_chan, bool additive,
4132 const pdf14_nonseparable_blending_procs_t * pblend_procs,
4133 bool has_matte, bool overprint, gx_color_index drawn_comps,
4134 gs_memory_t *memory, gx_device *dev)
4135 {
4136 int num_spots = tos->num_spots;
4137 uint16_t alpha = tos->alpha;
4138 uint16_t shape = tos->shape;
4139 gs_blend_mode_t blend_mode = tos->blend_mode;
4140 uint16_t *tos_ptr =
4141 (uint16_t *)(void *)(tos->data + (x0 - tos->rect.p.x)*2 +
4142 (y0 - tos->rect.p.y) * tos->rowstride);
4143 uint16_t *nos_ptr =
4144 (uint16_t *)(void *)(nos->data + (x0 - nos->rect.p.x)*2 +
4145 (y0 - nos->rect.p.y) * nos->rowstride);
4146 uint16_t *mask_row_ptr = NULL;
4147 int tos_planestride = tos->planestride;
4148 int nos_planestride = nos->planestride;
4149 uint16_t mask_bg_alpha = 0; /* Quiet compiler. */
4150 bool tos_isolated = tos->isolated;
4151 bool nos_isolated = nos->isolated;
4152 bool nos_knockout = nos->knockout;
4153 uint16_t *nos_alpha_g_ptr;
4154 uint16_t *tos_alpha_g_ptr;
4155 int tos_shape_offset = n_chan * tos_planestride;
4156 int tos_alpha_g_offset = tos_shape_offset + (tos->has_shape ? tos_planestride : 0);
4157 bool tos_has_tag = tos->has_tags;
4158 int tos_tag_offset = tos_planestride * (tos->n_planes - 1);
4159 int nos_shape_offset = n_chan * nos_planestride;
4160 int nos_alpha_g_offset = nos_shape_offset + (nos->has_shape ? nos_planestride : 0);
4161 int nos_tag_offset = nos_planestride * (nos->n_planes - 1);
4162 const uint16_t *mask_tr_fn = NULL; /* Quiet compiler. */
4163 bool has_mask = false;
4164 uint16_t *backdrop_ptr = NULL;
4165 pdf14_device *pdev = (pdf14_device *)dev;
4166 #if RAW_DUMP
4167 uint16_t *composed_ptr = NULL;
4168 int width = x1 - x0;
4169 #endif
4170 art_pdf_compose_group16_fn fn;
4171
4172 if ((tos->n_chan == 0) || (nos->n_chan == 0))
4173 return;
4174 rect_merge(nos->dirty, tos->dirty);
4175 if (nos->has_tags)
4176 if_debug7m('v', memory,
4177 "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, tag = %d, bm = %d\n",
4178 y0, y1, x1 - x0, alpha, shape, dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS, blend_mode);
4179 else
4180 if_debug6m('v', memory,
4181 "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, bm = %d\n",
4182 y0, y1, x1 - x0, alpha, shape, blend_mode);
4183 if (!nos->has_shape)
4184 nos_shape_offset = 0;
4185 if (!nos->has_tags)
4186 nos_tag_offset = 0;
4187 if (nos->has_alpha_g) {
4188 nos_alpha_g_ptr = nos_ptr + (nos_alpha_g_offset>>1);
4189 } else
4190 nos_alpha_g_ptr = NULL;
4191 if (tos->has_alpha_g) {
4192 tos_alpha_g_ptr = tos_ptr + (tos_alpha_g_offset>>1);
4193 } else
4194 tos_alpha_g_ptr = NULL;
4195 if (nos->backdrop != NULL) {
4196 backdrop_ptr =
4197 (uint16_t *)(void *)(nos->backdrop + (x0 - nos->rect.p.x)*2 +
4198 (y0 - nos->rect.p.y) * nos->rowstride);
4199 }
4200 if (blend_mode != BLEND_MODE_Compatible && blend_mode != BLEND_MODE_Normal)
4201 overprint = false;
4202
4203 if (maskbuf != NULL) {
4204 unsigned int tmp;
4205 mask_tr_fn = (uint16_t *)maskbuf->transfer_fn;
4206 /* Make sure we are in the mask buffer */
4207 if (maskbuf->data != NULL) {
4208 mask_row_ptr =
4209 (uint16_t *)(void *)(maskbuf->data + (x0 - maskbuf->rect.p.x)*2 +
4210 (y0 - maskbuf->rect.p.y) * maskbuf->rowstride);
4211 has_mask = true;
4212 }
4213 /* We may have a case, where we are outside the maskbuf rect. */
4214 /* We would have avoided creating the maskbuf->data */
4215 /* In that case, we should use the background alpha value */
4216 /* See discussion on the BC entry in the PDF spec. */
4217 mask_bg_alpha = maskbuf->alpha;
4218 /* Adjust alpha by the mask background alpha. This is only used
4219 if we are outside the soft mask rect during the filling operation */
4220 mask_bg_alpha = interp16(mask_tr_fn, mask_bg_alpha);
4221 tmp = alpha * mask_bg_alpha + 0x8000;
4222 mask_bg_alpha = (tmp + (tmp >> 8)) >> 8;
4223 }
4224 n_chan--; /* Now the true number of colorants (i.e. not including alpha)*/
4225 #if RAW_DUMP
4226 composed_ptr = nos_ptr;
4227 dump_raw_buffer(memory, y1-y0, width, tos->n_planes, tos_planestride, tos->rowstride,
4228 "bImageTOS", (byte *)tos_ptr, tos->deep);
4229 dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
4230 "cImageNOS", (byte *)nos_ptr, tos->deep);
4231 if (maskbuf !=NULL && maskbuf->data != NULL) {
4232 dump_raw_buffer(memory, maskbuf->rect.q.y - maskbuf->rect.p.y,
4233 maskbuf->rect.q.x - maskbuf->rect.p.x, maskbuf->n_planes,
4234 maskbuf->planestride, maskbuf->rowstride, "dMask",
4235 maskbuf->data, maskbuf->deep);
4236 }
4237 #endif
4238
4239 /* You might hope that has_mask iff maskbuf != NULL, but this is
4240 * not the case. Certainly we can see cases where maskbuf != NULL
4241 * and has_mask = 0. What's more, treating such cases as being
4242 * has_mask = 0 causes diffs. */
4243 #ifdef TRACK_COMPOSE_GROUPS
4244 {
4245 int code = 0;
4246
4247 code += !!nos_knockout;
4248 code += (!!nos_isolated)<<1;
4249 code += (!!tos_isolated)<<2;
4250 code += (!!tos->has_shape)<<3;
4251 code += (!!tos_has_tag)<<4;
4252 code += (!!additive)<<5;
4253 code += (!!overprint)<<6;
4254 code += (!!has_mask || maskbuf != NULL)<<7;
4255 code += (!!has_matte)<<8;
4256 code += (backdrop_ptr != NULL)<<9;
4257 code += (num_spots != 0)<<10;
4258 code += blend_mode<<11;
4259
4260 if (track_compose_groups == 0)
4261 {
4262 atexit(dump_track_compose_groups);
4263 track_compose_groups = 1;
4264 }
4265 compose_groups[code]++;
4266 }
4267 #endif
4268
4269 /* We have tested the files on the cluster to see what percentage of
4270 * files/devices hit the different options. */
4271 if (nos_knockout)
4272 fn = &compose_group16_knockout; /* Small %ages, nothing more than 1.1% */
4273 else if (blend_mode != 0)
4274 fn = &compose_group16_nonknockout_blend; /* Small %ages, nothing more than 2% */
4275 else if (tos->has_shape == 0 && tos_has_tag == 0 && nos_isolated == 0 && nos_alpha_g_ptr == NULL &&
4276 nos_shape_offset == 0 && nos_tag_offset == 0 && backdrop_ptr == NULL && has_matte == 0 && num_spots == 0 &&
4277 overprint == 0 && tos_alpha_g_ptr == NULL) {
4278 /* Additive vs Subtractive makes no difference in normal blend mode with no spots */
4279 if (tos_isolated) {
4280 if (has_mask && maskbuf) {/* 7% */
4281 /* AirPrint test case hits this */
4282 if (maskbuf && maskbuf->rect.p.x <= x0 && maskbuf->rect.p.y <= y0 &&
4283 maskbuf->rect.q.x >= x1 && maskbuf->rect.q.y >= y1)
4284 fn = &compose_group16_nonknockout_nonblend_isolated_allmask_common;
4285 else
4286 fn = &compose_group16_nonknockout_nonblend_isolated_mask_common;
4287 } else
4288 if (maskbuf) {
4289 /* Outside mask data but still has mask */
4290 fn = &compose_group16_nonknockout_nonblend_isolated_mask_common;
4291 } else {
4292 fn = &compose_group16_nonknockout_nonblend_isolated_nomask_common;
4293 }
4294 } else {
4295 if (has_mask || maskbuf) /* 4% */
4296 fn = &compose_group16_nonknockout_nonblend_nonisolated_mask_common;
4297 else /* 15% */
4298 fn = &compose_group16_nonknockout_nonblend_nonisolated_nomask_common;
4299 }
4300 } else
4301 fn = compose_group16_nonknockout_noblend_general;
4302
4303 tos_planestride >>= 1;
4304 tos_shape_offset >>= 1;
4305 tos_alpha_g_offset >>= 1;
4306 tos_tag_offset >>= 1;
4307 nos_planestride >>= 1;
4308 nos_shape_offset >>= 1;
4309 nos_tag_offset >>= 1;
4310 fn(tos_ptr, tos_isolated, tos_planestride, tos->rowstride>>1, alpha, shape, blend_mode, tos->has_shape,
4311 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag,
4312 tos_alpha_g_ptr, nos_ptr, nos_isolated, nos_planestride, nos->rowstride>>1, nos_alpha_g_ptr, nos_knockout,
4313 nos_shape_offset, nos_tag_offset,
4314 mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
4315 backdrop_ptr,
4316 has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1,
4317 pblend_procs, pdev);
4318
4319 #if RAW_DUMP
4320 dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride<<1, nos->rowstride,
4321 "eComposed", (byte *)composed_ptr, nos->deep);
4322 global_index++;
4323 #endif
4324 }
4325
4326 void
pdf14_compose_group(pdf14_buf * tos,pdf14_buf * nos,pdf14_buf * maskbuf,int x0,int x1,int y0,int y1,int n_chan,bool additive,const pdf14_nonseparable_blending_procs_t * pblend_procs,bool has_matte,bool overprint,gx_color_index drawn_comps,gs_memory_t * memory,gx_device * dev)4327 pdf14_compose_group(pdf14_buf *tos, pdf14_buf *nos, pdf14_buf *maskbuf,
4328 int x0, int x1, int y0, int y1, int n_chan, bool additive,
4329 const pdf14_nonseparable_blending_procs_t * pblend_procs,
4330 bool has_matte, bool overprint, gx_color_index drawn_comps,
4331 gs_memory_t *memory, gx_device *dev)
4332 {
4333 if (tos->deep)
4334 do_compose_group16(tos, nos, maskbuf, x0, x1, y0, y1, n_chan,
4335 additive, pblend_procs, has_matte, overprint,
4336 drawn_comps, memory, dev);
4337 else
4338 do_compose_group(tos, nos, maskbuf, x0, x1, y0, y1, n_chan,
4339 additive, pblend_procs, has_matte, overprint,
4340 drawn_comps, memory, dev);
4341 }
4342
4343 static void
do_compose_alphaless_group(pdf14_buf * tos,pdf14_buf * nos,int x0,int x1,int y0,int y1,gs_memory_t * memory,gx_device * dev)4344 do_compose_alphaless_group(pdf14_buf *tos, pdf14_buf *nos,
4345 int x0, int x1, int y0, int y1,
4346 gs_memory_t *memory, gx_device *dev)
4347 {
4348 pdf14_device *pdev = (pdf14_device *)dev;
4349 bool overprint = pdev->op_state == PDF14_OP_STATE_FILL ? pdev->overprint : pdev->stroke_overprint;
4350 bool additive = pdev->ctx->additive;
4351 gx_color_index drawn_comps = pdev->op_state == PDF14_OP_STATE_FILL ?
4352 pdev->drawn_comps_fill : pdev->drawn_comps_stroke;
4353 int n_chan = nos->n_chan;
4354 int num_spots = tos->num_spots;
4355 byte alpha = tos->alpha>>8;
4356 byte shape = tos->shape>>8;
4357 gs_blend_mode_t blend_mode = tos->blend_mode;
4358 byte *tos_ptr = tos->data + x0 - tos->rect.p.x +
4359 (y0 - tos->rect.p.y) * tos->rowstride;
4360 byte *nos_ptr = nos->data + x0 - nos->rect.p.x +
4361 (y0 - nos->rect.p.y) * nos->rowstride;
4362 byte *mask_row_ptr = NULL;
4363 int tos_planestride = tos->planestride;
4364 int nos_planestride = nos->planestride;
4365 byte mask_bg_alpha = 0; /* Quiet compiler. */
4366 bool tos_isolated = false;
4367 bool nos_isolated = nos->isolated;
4368 bool nos_knockout = nos->knockout;
4369 byte *nos_alpha_g_ptr, *tos_alpha_g_ptr;
4370 int tos_shape_offset = n_chan * tos_planestride;
4371 int tos_alpha_g_offset = tos_shape_offset + (tos->has_shape ? tos_planestride : 0);
4372 bool tos_has_tag = tos->has_tags;
4373 int tos_tag_offset = tos_planestride * (tos->n_planes - 1);
4374 int nos_shape_offset = n_chan * nos_planestride;
4375 int nos_alpha_g_offset = nos_shape_offset + (nos->has_shape ? nos_planestride : 0);
4376 int nos_tag_offset = nos_planestride * (nos->n_planes - 1);
4377 const byte *mask_tr_fn = NULL; /* Quiet compiler. */
4378 bool has_mask = false;
4379 byte *backdrop_ptr = NULL;
4380 #if RAW_DUMP
4381 byte *composed_ptr = NULL;
4382 int width = x1 - x0;
4383 #endif
4384 art_pdf_compose_group_fn fn;
4385
4386 if ((tos->n_chan == 0) || (nos->n_chan == 0))
4387 return;
4388 rect_merge(nos->dirty, tos->dirty);
4389 if (nos->has_tags)
4390 if_debug7m('v', memory,
4391 "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, tag = %d, bm = %d\n",
4392 y0, y1, x1 - x0, alpha, shape, dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS, blend_mode);
4393 else
4394 if_debug6m('v', memory,
4395 "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, bm = %d\n",
4396 y0, y1, x1 - x0, alpha, shape, blend_mode);
4397 if (!nos->has_shape)
4398 nos_shape_offset = 0;
4399 if (!nos->has_tags)
4400 nos_tag_offset = 0;
4401 if (nos->has_alpha_g) {
4402 nos_alpha_g_ptr = nos_ptr + nos_alpha_g_offset;
4403 } else
4404 nos_alpha_g_ptr = NULL;
4405 if (tos->has_alpha_g) {
4406 tos_alpha_g_ptr = tos_ptr + tos_alpha_g_offset;
4407 } else
4408 tos_alpha_g_ptr = NULL;
4409 if (nos->backdrop != NULL) {
4410 backdrop_ptr = nos->backdrop + x0 - nos->rect.p.x +
4411 (y0 - nos->rect.p.y) * nos->rowstride;
4412 }
4413 if (blend_mode != BLEND_MODE_Compatible && blend_mode != BLEND_MODE_Normal)
4414 overprint = false;
4415
4416 n_chan--; /* Now the true number of colorants (i.e. not including alpha)*/
4417 #if RAW_DUMP
4418 composed_ptr = nos_ptr;
4419 dump_raw_buffer(memory, y1-y0, width, tos->n_planes, tos_planestride, tos->rowstride,
4420 "bImageTOS", tos_ptr, tos->deep);
4421 dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
4422 "cImageNOS", nos_ptr, nos->deep);
4423 /* maskbuf is NULL in here */
4424 #endif
4425
4426 /* You might hope that has_mask iff maskbuf != NULL, but this is
4427 * not the case. Certainly we can see cases where maskbuf != NULL
4428 * and has_mask = 0. What's more, treating such cases as being
4429 * has_mask = 0 causes diffs. */
4430 #ifdef TRACK_COMPOSE_GROUPS
4431 {
4432 int code = 0;
4433
4434 code += !!nos_knockout;
4435 code += (!!nos_isolated)<<1;
4436 code += (!!tos_isolated)<<2;
4437 code += (!!tos->has_shape)<<3;
4438 code += (!!tos_has_tag)<<4;
4439 code += (!!additive)<<5;
4440 code += (!!overprint)<<6;
4441 code += (!!has_mask)<<7;
4442 code += (backdrop_ptr != NULL)<<9;
4443 code += (num_spots != 0)<<10;
4444 code += blend_mode<<11;
4445
4446 if (track_compose_groups == 0)
4447 {
4448 atexit(dump_track_compose_groups);
4449 track_compose_groups = 1;
4450 }
4451 compose_groups[code]++;
4452 }
4453 #endif
4454
4455 /* We have tested the files on the cluster to see what percentage of
4456 * files/devices hit the different options. */
4457 if (nos_knockout)
4458 fn = &compose_group_alphaless_knockout;
4459 else
4460 fn = &compose_group_alphaless_nonknockout;
4461
4462 fn(tos_ptr, tos_isolated, tos_planestride, tos->rowstride, alpha, shape, blend_mode, tos->has_shape,
4463 tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
4464 nos_ptr, nos_isolated, nos_planestride, nos->rowstride, nos_alpha_g_ptr, nos_knockout,
4465 nos_shape_offset, nos_tag_offset,
4466 mask_row_ptr, has_mask, /* maskbuf */ NULL, mask_bg_alpha, mask_tr_fn,
4467 backdrop_ptr,
4468 /* has_matte */ 0, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1,
4469 pdev->blend_procs, pdev);
4470
4471 #if RAW_DUMP
4472 dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
4473 "eComposed", composed_ptr, nos->deep);
4474 global_index++;
4475 #endif
4476 }
4477
4478 static void
do_compose_alphaless_group16(pdf14_buf * tos,pdf14_buf * nos,int x0,int x1,int y0,int y1,gs_memory_t * memory,gx_device * dev)4479 do_compose_alphaless_group16(pdf14_buf *tos, pdf14_buf *nos,
4480 int x0, int x1, int y0, int y1,
4481 gs_memory_t *memory, gx_device *dev)
4482 {
4483 pdf14_device *pdev = (pdf14_device *)dev;
4484 bool overprint = pdev->op_state == PDF14_OP_STATE_FILL ? pdev->overprint : pdev->stroke_overprint;
4485 bool additive = pdev->ctx->additive;
4486 gx_color_index drawn_comps = pdev->op_state == PDF14_OP_STATE_FILL ?
4487 pdev->drawn_comps_fill : pdev->drawn_comps_stroke;
4488 int n_chan = nos->n_chan;
4489 int num_spots = tos->num_spots;
4490 uint16_t alpha = tos->alpha;
4491 uint16_t shape = tos->shape;
4492 gs_blend_mode_t blend_mode = tos->blend_mode;
4493 uint16_t *tos_ptr =
4494 (uint16_t *)(void *)(tos->data + (x0 - tos->rect.p.x)*2 +
4495 (y0 - tos->rect.p.y) * tos->rowstride);
4496 uint16_t *nos_ptr =
4497 (uint16_t *)(void *)(nos->data + (x0 - nos->rect.p.x)*2 +
4498 (y0 - nos->rect.p.y) * nos->rowstride);
4499 uint16_t *mask_row_ptr = NULL;
4500 int tos_planestride = tos->planestride;
4501 int nos_planestride = nos->planestride;
4502 uint16_t mask_bg_alpha = 0; /* Quiet compiler. */
4503 bool tos_isolated = false;
4504 bool nos_isolated = nos->isolated;
4505 bool nos_knockout = nos->knockout;
4506 uint16_t *nos_alpha_g_ptr;
4507 uint16_t *tos_alpha_g_ptr;
4508 int tos_shape_offset = n_chan * tos_planestride;
4509 int tos_alpha_g_offset = tos_shape_offset + (tos->has_shape ? tos_planestride : 0);
4510 bool tos_has_tag = tos->has_tags;
4511 int tos_tag_offset = tos_planestride * (tos->n_planes - 1);
4512 int nos_shape_offset = n_chan * nos_planestride;
4513 int nos_alpha_g_offset = nos_shape_offset + (nos->has_shape ? nos_planestride : 0);
4514 int nos_tag_offset = nos_planestride * (nos->n_planes - 1);
4515 bool has_mask = false;
4516 uint16_t *backdrop_ptr = NULL;
4517 #if RAW_DUMP
4518 uint16_t *composed_ptr = NULL;
4519 int width = x1 - x0;
4520 #endif
4521 art_pdf_compose_group16_fn fn;
4522
4523 if ((tos->n_chan == 0) || (nos->n_chan == 0))
4524 return;
4525 rect_merge(nos->dirty, tos->dirty);
4526 if (nos->has_tags)
4527 if_debug7m('v', memory,
4528 "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, tag = %d, bm = %d\n",
4529 y0, y1, x1 - x0, alpha, shape, dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS, blend_mode);
4530 else
4531 if_debug6m('v', memory,
4532 "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, bm = %d\n",
4533 y0, y1, x1 - x0, alpha, shape, blend_mode);
4534 if (!nos->has_shape)
4535 nos_shape_offset = 0;
4536 if (!nos->has_tags)
4537 nos_tag_offset = 0;
4538 if (nos->has_alpha_g) {
4539 nos_alpha_g_ptr = nos_ptr + (nos_alpha_g_offset>>1);
4540 } else
4541 nos_alpha_g_ptr = NULL;
4542 if (tos->has_alpha_g) {
4543 tos_alpha_g_ptr = tos_ptr + (tos_alpha_g_offset>>1);
4544 } else
4545 tos_alpha_g_ptr = NULL;
4546
4547 if (nos->backdrop != NULL) {
4548 backdrop_ptr =
4549 (uint16_t *)(void *)(nos->backdrop + (x0 - nos->rect.p.x)*2 +
4550 (y0 - nos->rect.p.y) * nos->rowstride);
4551 }
4552 if (blend_mode != BLEND_MODE_Compatible && blend_mode != BLEND_MODE_Normal)
4553 overprint = false;
4554
4555 n_chan--; /* Now the true number of colorants (i.e. not including alpha)*/
4556 #if RAW_DUMP
4557 composed_ptr = nos_ptr;
4558 dump_raw_buffer_be(memory, y1-y0, width, tos->n_planes, tos_planestride, tos->rowstride,
4559 "bImageTOS", (byte *)tos_ptr, tos->deep);
4560 dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
4561 "cImageNOS", (byte *)nos_ptr, nos->deep);
4562 /* maskbuf is NULL in here */
4563 #endif
4564
4565 /* You might hope that has_mask iff maskbuf != NULL, but this is
4566 * not the case. Certainly we can see cases where maskbuf != NULL
4567 * and has_mask = 0. What's more, treating such cases as being
4568 * has_mask = 0 causes diffs. */
4569 #ifdef TRACK_COMPOSE_GROUPS
4570 {
4571 int code = 0;
4572
4573 code += !!nos_knockout;
4574 code += (!!nos_isolated)<<1;
4575 code += (!!tos_isolated)<<2;
4576 code += (!!tos->has_shape)<<3;
4577 code += (!!tos_has_tag)<<4;
4578 code += (!!additive)<<5;
4579 code += (!!overprint)<<6;
4580 code += (!!has_mask)<<7;
4581 code += (backdrop_ptr != NULL)<<9;
4582 code += (num_spots != 0)<<10;
4583 code += blend_mode<<11;
4584
4585 if (track_compose_groups == 0)
4586 {
4587 atexit(dump_track_compose_groups);
4588 track_compose_groups = 1;
4589 }
4590 compose_groups[code]++;
4591 }
4592 #endif
4593
4594 /* We have tested the files on the cluster to see what percentage of
4595 * files/devices hit the different options. */
4596 if (nos_knockout)
4597 fn = &compose_group16_alphaless_knockout;
4598 else
4599 fn = &compose_group16_alphaless_nonknockout;
4600
4601 fn(tos_ptr, tos_isolated, tos_planestride>>1, tos->rowstride>>1, alpha, shape, blend_mode, tos->has_shape,
4602 tos_shape_offset>>1, tos_alpha_g_offset>>1, tos_tag_offset>>1, tos_has_tag, tos_alpha_g_ptr,
4603 nos_ptr, nos_isolated, nos_planestride>>1, nos->rowstride>>1, nos_alpha_g_ptr, nos_knockout,
4604 nos_shape_offset>>1, nos_tag_offset>>1,
4605 mask_row_ptr, has_mask, /* maskbuf */ NULL, mask_bg_alpha, NULL,
4606 backdrop_ptr,
4607 /* has_matte */ 0, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1,
4608 pdev->blend_procs, pdev);
4609
4610 #if RAW_DUMP
4611 dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
4612 "eComposed", (byte *)composed_ptr, nos->deep);
4613 global_index++;
4614 #endif
4615 }
4616
4617 void
pdf14_compose_alphaless_group(pdf14_buf * tos,pdf14_buf * nos,int x0,int x1,int y0,int y1,gs_memory_t * memory,gx_device * dev)4618 pdf14_compose_alphaless_group(pdf14_buf *tos, pdf14_buf *nos,
4619 int x0, int x1, int y0, int y1,
4620 gs_memory_t *memory, gx_device *dev)
4621 {
4622 if (tos->deep)
4623 do_compose_alphaless_group16(tos, nos, x0, x1, y0, y1, memory, dev);
4624 else
4625 do_compose_alphaless_group(tos, nos, x0, x1, y0, y1, memory, dev);
4626 }
4627
4628 typedef void (*pdf14_mark_fill_rect_fn)(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
4629 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4630 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4631 int alpha_g_off, int shape_off, byte shape);
4632
4633 static forceinline void
template_mark_fill_rect(int w,int h,byte * gs_restrict dst_ptr,byte * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,byte src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,byte shape)4634 template_mark_fill_rect(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
4635 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4636 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4637 int alpha_g_off, int shape_off, byte shape)
4638 {
4639 int i, j, k;
4640 byte dst[PDF14_MAX_PLANES] = { 0 };
4641 byte dest_alpha;
4642 bool tag_blend = blend_mode == BLEND_MODE_Normal ||
4643 blend_mode == BLEND_MODE_Compatible ||
4644 blend_mode == BLEND_MODE_CompatibleOverprint;
4645
4646 for (j = h; j > 0; --j) {
4647 for (i = w; i > 0; --i) {
4648 if ((blend_mode == BLEND_MODE_Normal && src[num_comp] == 0xff && !overprint) || dst_ptr[num_comp * planestride] == 0) {
4649 /* dest alpha is zero (or normal, and solid src) just use source. */
4650 if (additive) {
4651 /* Hybrid case */
4652 for (k = 0; k < (num_comp - num_spots); k++) {
4653 dst_ptr[k * planestride] = src[k];
4654 }
4655 for (k = 0; k < num_spots; k++) {
4656 dst_ptr[(k + num_comp - num_spots) * planestride] =
4657 255 - src[k + num_comp - num_spots];
4658 }
4659 } else {
4660 /* Pure subtractive */
4661 for (k = 0; k < num_comp; k++) {
4662 dst_ptr[k * planestride] = 255 - src[k];
4663 }
4664 }
4665 /* alpha */
4666 dst_ptr[num_comp * planestride] = src[num_comp];
4667 } else if (src[num_comp] != 0) {
4668 byte *pdst;
4669 /* Complement subtractive planes */
4670 if (!additive) {
4671 /* Pure subtractive */
4672 for (k = 0; k < num_comp; ++k)
4673 dst[k] = 255 - dst_ptr[k * planestride];
4674 } else {
4675 /* Hybrid case, additive with subtractive spots */
4676 for (k = 0; k < (num_comp - num_spots); k++) {
4677 dst[k] = dst_ptr[k * planestride];
4678 }
4679 for (k = 0; k < num_spots; k++) {
4680 dst[k + num_comp - num_spots] =
4681 255 - dst_ptr[(k + num_comp - num_spots) * planestride];
4682 }
4683 }
4684 dst[num_comp] = dst_ptr[num_comp * planestride];
4685 dest_alpha = dst[num_comp];
4686 pdst = art_pdf_composite_pixel_alpha_8_inline(dst, src, num_comp, blend_mode, first_blend_spot,
4687 pdev->blend_procs, pdev);
4688 /* Post blend complement for subtractive and handling of drawncomps
4689 if overprint. We will have already done the compatible overprint
4690 mode in the above composition */
4691 if (!additive && !overprint) {
4692 /* Pure subtractive */
4693 for (k = 0; k < num_comp; ++k)
4694 dst_ptr[k * planestride] = 255 - pdst[k];
4695 } else if (!additive && overprint) {
4696 int comps;
4697 /* If this is an overprint case, and alpha_r is different
4698 than alpha_d then we will need to adjust
4699 the colors of the non-drawn components here too */
4700 if (dest_alpha != pdst[num_comp] && pdst[num_comp] != 0) {
4701 /* dest_alpha > pdst[num_comp], and dst[num_comp] != 0.
4702 * Therefore dest_alpha / pdst[num_comp] <= 255 */
4703 uint32_t scale = 256 * dest_alpha / pdst[num_comp];
4704 for (k = 0, comps = drawn_comps; k < num_comp; ++k, comps >>= 1) {
4705 if ((comps & 0x1) != 0) {
4706 dst_ptr[k * planestride] = 255 - pdst[k];
4707 } else {
4708 /* We need val_new = (val_old * old_alpha) / new_alpha */
4709 uint32_t val = (scale * (255 - pdst[k]) + 128)>>8;
4710 if (val > 255)
4711 val = 255;
4712 dst_ptr[k * planestride] = val;
4713 }
4714 }
4715 } else {
4716 for (k = 0, comps = drawn_comps; k < num_comp; ++k, comps >>= 1) {
4717 if ((comps & 0x1) != 0) {
4718 dst_ptr[k * planestride] = 255 - pdst[k];
4719 }
4720 }
4721 }
4722 } else {
4723 /* Hybrid case, additive with subtractive spots */
4724 for (k = 0; k < (num_comp - num_spots); k++) {
4725 dst_ptr[k * planestride] = pdst[k];
4726 }
4727 for (k = 0; k < num_spots; k++) {
4728 dst_ptr[(k + num_comp - num_spots) * planestride] =
4729 255 - pdst[k + num_comp - num_spots];
4730 }
4731 }
4732 /* The alpha channel */
4733 dst_ptr[num_comp * planestride] = pdst[num_comp];
4734 }
4735 if (tag_off) {
4736 /* If src alpha is 100% then set to curr_tag, else or */
4737 /* other than Normal BM, we always OR */
4738 if (src[num_comp] == 255 && tag_blend) {
4739 dst_ptr[tag_off] = curr_tag;
4740 } else {
4741 dst_ptr[tag_off] |= curr_tag;
4742 }
4743 }
4744 if (alpha_g_off) {
4745 int tmp = (255 - dst_ptr[alpha_g_off]) * src_alpha + 0x80;
4746 dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4747 }
4748 if (shape_off) {
4749 int tmp = (255 - dst_ptr[shape_off]) * shape + 0x80;
4750 dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4751 }
4752 ++dst_ptr;
4753 }
4754 dst_ptr += rowstride;
4755 }
4756 }
4757
4758 static void
mark_fill_rect_alpha0(int w,int h,byte * gs_restrict dst_ptr,byte * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,byte src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,byte shape)4759 mark_fill_rect_alpha0(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
4760 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4761 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4762 int alpha_g_off, int shape_off, byte shape)
4763 {
4764 int i, j;
4765
4766 for (j = h; j > 0; --j) {
4767 for (i = w; i > 0; --i) {
4768 if (alpha_g_off) {
4769 int tmp = (255 - dst_ptr[alpha_g_off]) * src_alpha + 0x80;
4770 dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4771 }
4772 if (shape_off) {
4773 int tmp = (255 - dst_ptr[shape_off]) * shape + 0x80;
4774 dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4775 }
4776 ++dst_ptr;
4777 }
4778 dst_ptr += rowstride;
4779 }
4780 }
4781
4782 static void
mark_fill_rect(int w,int h,byte * gs_restrict dst_ptr,byte * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,byte src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,byte shape)4783 mark_fill_rect(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
4784 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4785 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4786 int alpha_g_off, int shape_off, byte shape)
4787 {
4788 template_mark_fill_rect(w, h, dst_ptr, src, num_comp, num_spots, first_blend_spot,
4789 src_alpha, rowstride, planestride, additive, pdev, blend_mode,
4790 overprint, drawn_comps, tag_off, curr_tag,
4791 alpha_g_off, shape_off, shape);
4792 }
4793
4794 static void
mark_fill_rect_sub4_fast(int w,int h,byte * gs_restrict dst_ptr,byte * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,byte src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,byte shape)4795 mark_fill_rect_sub4_fast(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
4796 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4797 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4798 int alpha_g_off, int shape_off, byte shape)
4799 {
4800 int i, j, k;
4801
4802 for (j = h; j > 0; --j) {
4803 for (i = w; i > 0; --i) {
4804 byte a_s = src[4];
4805 byte a_b = dst_ptr[4 * planestride];
4806 if ((a_s == 0xff) || a_b == 0) {
4807 /* dest alpha is zero (or normal, and solid src) just use source. */
4808 dst_ptr[0 * planestride] = 255 - src[0];
4809 dst_ptr[1 * planestride] = 255 - src[1];
4810 dst_ptr[2 * planestride] = 255 - src[2];
4811 dst_ptr[3 * planestride] = 255 - src[3];
4812 /* alpha */
4813 dst_ptr[4 * planestride] = a_s;
4814 } else if (a_s != 0) {
4815 /* Result alpha is Union of backdrop and source alpha */
4816 int tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
4817 unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
4818
4819 /* Compute a_s / a_r in 16.16 format */
4820 int src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
4821
4822 dst_ptr[4 * planestride] = a_r;
4823
4824 /* Do simple compositing of source over backdrop */
4825 for (k = 0; k < 4; k++) {
4826 int c_s = src[k];
4827 int c_b = 255 - dst_ptr[k * planestride];
4828 tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
4829 dst_ptr[k * planestride] = 255 - (tmp >> 16);
4830 }
4831 }
4832 ++dst_ptr;
4833 }
4834 dst_ptr += rowstride;
4835 }
4836 }
4837
4838 static void
mark_fill_rect_add_nospots(int w,int h,byte * gs_restrict dst_ptr,byte * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,byte src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,byte shape)4839 mark_fill_rect_add_nospots(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
4840 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4841 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4842 int alpha_g_off, int shape_off, byte shape)
4843 {
4844 template_mark_fill_rect(w, h, dst_ptr, src, num_comp, /*num_spots*/0, first_blend_spot,
4845 src_alpha, rowstride, planestride, /*additive*/1, pdev, blend_mode,
4846 /*overprint*/0, /*drawn_comps*/0, tag_off, curr_tag,
4847 alpha_g_off, shape_off, shape);
4848 }
4849
4850 static void
mark_fill_rect_add_nospots_common(int w,int h,byte * gs_restrict dst_ptr,byte * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,byte src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,byte shape)4851 mark_fill_rect_add_nospots_common(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
4852 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4853 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4854 int alpha_g_off, int shape_off, byte shape)
4855 {
4856 template_mark_fill_rect(w, h, dst_ptr, src, num_comp, /*num_spots*/0, /*first_blend_spot*/0,
4857 src_alpha, rowstride, planestride, /*additive*/1, pdev, /*blend_mode*/BLEND_MODE_Normal,
4858 /*overprint*/0, /*drawn_comps*/0, /*tag_off*/0, curr_tag,
4859 alpha_g_off, /*shape_off*/0, shape);
4860 }
4861
4862 static void
mark_fill_rect_add_nospots_common_no_alpha_g(int w,int h,byte * gs_restrict dst_ptr,byte * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,byte src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,byte shape)4863 mark_fill_rect_add_nospots_common_no_alpha_g(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
4864 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4865 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4866 int alpha_g_off, int shape_off, byte shape)
4867 {
4868 template_mark_fill_rect(w, h, dst_ptr, src, num_comp, /*num_spots*/0, /*first_blend_spot*/0,
4869 src_alpha, rowstride, planestride, /*additive*/1, pdev, /*blend_mode*/BLEND_MODE_Normal,
4870 /*overprint*/0, /*drawn_comps*/0, /*tag_off*/0, curr_tag,
4871 /*alpha_g_off*/0, /*shape_off*/0, shape);
4872 }
4873
4874 static void
mark_fill_rect_add3_common(int w,int h,byte * gs_restrict dst_ptr,byte * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,byte src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,byte shape)4875 mark_fill_rect_add3_common(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
4876 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4877 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4878 int alpha_g_off, int shape_off, byte shape)
4879 {
4880 int i, j, k;
4881
4882 for (j = h; j > 0; --j) {
4883 for (i = w; i > 0; --i) {
4884 byte a_s = src[3];
4885 byte a_b = dst_ptr[3 * planestride];
4886 if (a_s == 0xff || a_b == 0) {
4887 /* dest alpha is zero (or solid source) just use source. */
4888 dst_ptr[0 * planestride] = src[0];
4889 dst_ptr[1 * planestride] = src[1];
4890 dst_ptr[2 * planestride] = src[2];
4891 /* alpha */
4892 dst_ptr[3 * planestride] = a_s;
4893 } else if (a_s != 0) {
4894 /* Result alpha is Union of backdrop and source alpha */
4895 int tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
4896 unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
4897 /* todo: verify that a_r is nonzero in all cases */
4898
4899 /* Compute a_s / a_r in 16.16 format */
4900 int src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
4901
4902 dst_ptr[3 * planestride] = a_r;
4903
4904 /* Do simple compositing of source over backdrop */
4905 for (k = 0; k < 3; k++) {
4906 int c_s = src[k];
4907 int c_b = dst_ptr[k * planestride];
4908 tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
4909 dst_ptr[k * planestride] = tmp >> 16;
4910 }
4911 }
4912 ++dst_ptr;
4913 }
4914 dst_ptr += rowstride;
4915 }
4916 }
4917
4918 static void
mark_fill_rect_add1_no_spots(int w,int h,byte * gs_restrict dst_ptr,byte * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,byte src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,byte shape)4919 mark_fill_rect_add1_no_spots(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
4920 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4921 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4922 int alpha_g_off, int shape_off, byte shape)
4923 {
4924 int i;
4925 bool tag_blend = blend_mode == BLEND_MODE_Normal ||
4926 blend_mode == BLEND_MODE_Compatible ||
4927 blend_mode == BLEND_MODE_CompatibleOverprint;
4928
4929 for (; h > 0; --h) {
4930 for (i = w; i > 0; --i) {
4931 /* background empty, nothing to change, or solid source */
4932 byte a_s = src[1];
4933 if ((blend_mode == BLEND_MODE_Normal && a_s == 0xff) || dst_ptr[planestride] == 0) {
4934 dst_ptr[0] = src[0];
4935 dst_ptr[planestride] = a_s;
4936 } else {
4937 art_pdf_composite_pixel_alpha_8_fast_mono(dst_ptr, src,
4938 blend_mode, pdev->blend_procs,
4939 planestride, pdev);
4940 }
4941 if (tag_off) {
4942 /* If src alpha is 100% then set to curr_tag, else or */
4943 /* other than Normal BM, we always OR */
4944 if (tag_blend && a_s == 255) {
4945 dst_ptr[tag_off] = curr_tag;
4946 } else {
4947 dst_ptr[tag_off] |= curr_tag;
4948 }
4949 }
4950 if (alpha_g_off) {
4951 int tmp = (255 - dst_ptr[alpha_g_off]) * src_alpha + 0x80;
4952 dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4953 }
4954 if (shape_off) {
4955 int tmp = (255 - dst_ptr[shape_off]) * shape + 0x80;
4956 dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4957 }
4958 ++dst_ptr;
4959 }
4960 dst_ptr += rowstride;
4961 }
4962 }
4963
4964 static void
mark_fill_rect_add1_no_spots_normal(int w,int h,byte * gs_restrict dst_ptr,byte * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,byte src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,byte shape)4965 mark_fill_rect_add1_no_spots_normal(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
4966 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4967 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4968 int alpha_g_off, int shape_off, byte shape)
4969 {
4970 int i;
4971
4972 for (; h > 0; --h) {
4973 for (i = w; i > 0; --i) {
4974 /* background empty, nothing to change, or solid source */
4975 byte a_s = src[1];
4976 byte a_b = dst_ptr[planestride];
4977 if (a_s == 0xff || a_b == 0) {
4978 dst_ptr[0] = src[0];
4979 dst_ptr[planestride] = a_s;
4980 } else {
4981 /* Result alpha is Union of backdrop and source alpha */
4982 int tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
4983 unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
4984
4985 /* Compute a_s / a_r in 16.16 format */
4986 int src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
4987
4988 /* Do simple compositing of source over backdrop */
4989 int c_s = src[0];
4990 int c_b = dst_ptr[0];
4991 tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
4992 dst_ptr[0] = tmp >> 16;
4993 dst_ptr[planestride] = a_r;
4994 }
4995 if (tag_off) {
4996 /* If src alpha is 100% then set to curr_tag, else or */
4997 /* other than Normal BM, we always OR */
4998 if (a_s == 255) {
4999 dst_ptr[tag_off] = curr_tag;
5000 } else {
5001 dst_ptr[tag_off] |= curr_tag;
5002 }
5003 }
5004 if (alpha_g_off) {
5005 int tmp = (255 - dst_ptr[alpha_g_off]) * src_alpha + 0x80;
5006 dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
5007 }
5008 if (shape_off) {
5009 int tmp = (255 - dst_ptr[shape_off]) * shape + 0x80;
5010 dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
5011 }
5012 ++dst_ptr;
5013 }
5014 dst_ptr += rowstride;
5015 }
5016 }
5017
5018 static void
mark_fill_rect_add1_no_spots_fast(int w,int h,byte * gs_restrict dst_ptr,byte * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,byte src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,byte shape)5019 mark_fill_rect_add1_no_spots_fast(int w, int h, byte *gs_restrict dst_ptr, byte *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5020 byte src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5021 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5022 int alpha_g_off, int shape_off, byte shape)
5023 {
5024 int i;
5025
5026 for (; h > 0; --h) {
5027 for (i = w; i > 0; --i) {
5028 /* background empty, nothing to change, or solid source */
5029 byte a_s = src[1];
5030 byte a_b = dst_ptr[planestride];
5031 if (a_s == 0xff || a_b == 0) {
5032 dst_ptr[0] = src[0];
5033 dst_ptr[planestride] = a_s;
5034 } else if (a_s != 0) {
5035 /* Result alpha is Union of backdrop and source alpha */
5036 int tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
5037 unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
5038
5039 /* Compute a_s / a_r in 16.16 format */
5040 int src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
5041
5042 /* Do simple compositing of source over backdrop */
5043 int c_s = src[0];
5044 int c_b = dst_ptr[0];
5045 tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
5046 dst_ptr[0] = tmp >> 16;
5047 dst_ptr[planestride] = a_r;
5048 }
5049 ++dst_ptr;
5050 }
5051 dst_ptr += rowstride;
5052 }
5053 }
5054
5055 static int
do_mark_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color,const gx_device_color * pdc,bool devn)5056 do_mark_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
5057 gx_color_index color, const gx_device_color *pdc,
5058 bool devn)
5059 {
5060 pdf14_device *pdev = (pdf14_device *)dev;
5061 pdf14_buf *buf = pdev->ctx->stack;
5062 int j;
5063 byte *dst_ptr;
5064 byte src[PDF14_MAX_PLANES];
5065 gs_blend_mode_t blend_mode = pdev->blend_mode;
5066 bool additive = pdev->ctx->additive;
5067 int rowstride = buf->rowstride;
5068 int planestride = buf->planestride;
5069 gs_graphics_type_tag_t curr_tag = GS_UNKNOWN_TAG; /* Quite compiler */
5070 bool has_alpha_g = buf->has_alpha_g;
5071 bool has_shape = buf->has_shape;
5072 bool has_tags = buf->has_tags;
5073 int num_chan = buf->n_chan;
5074 int num_comp = num_chan - 1;
5075 int shape_off = num_chan * planestride;
5076 int alpha_g_off = shape_off + (has_shape ? planestride : 0);
5077 int tag_off = alpha_g_off + (has_alpha_g ? planestride : 0);
5078 bool overprint = pdev->op_state == PDF14_OP_STATE_FILL ? pdev->overprint : pdev->stroke_overprint;
5079 gx_color_index drawn_comps = pdev->op_state == PDF14_OP_STATE_FILL ?
5080 pdev->drawn_comps_fill : pdev->drawn_comps_stroke;
5081 byte shape = 0; /* Quiet compiler. */
5082 byte src_alpha;
5083 const gx_color_index mask = ((gx_color_index)1 << 8) - 1;
5084 const int shift = 8;
5085 int num_spots = buf->num_spots;
5086 int first_blend_spot = num_comp;
5087 pdf14_mark_fill_rect_fn fn;
5088
5089 if (num_spots > 0 && !blend_valid_for_spot(blend_mode))
5090 first_blend_spot = num_comp - num_spots;
5091 if (blend_mode == BLEND_MODE_Normal)
5092 first_blend_spot = 0;
5093
5094 if (buf->data == NULL)
5095 return 0;
5096 /* NB: gx_color_index is 4 or 8 bytes */
5097 #if 0
5098 if (sizeof(color) <= sizeof(ulong))
5099 if_debug8m('v', dev->memory,
5100 "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %lx bm %d, nc %d, overprint %d\n",
5101 x, y, w, h, (ulong)color, blend_mode, num_chan, overprint);
5102 else
5103 if_debug9m('v', dev->memory,
5104 "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %08lx%08lx bm %d, nc %d, overprint %d\n",
5105 x, y, w, h,
5106 (ulong)(color >> 8*(sizeof(color) - sizeof(ulong))), (ulong)color,
5107 blend_mode, num_chan, overprint);
5108 #endif
5109 /*
5110 * Unpack the gx_color_index values. Complement the components for subtractive
5111 * color spaces.
5112 */
5113 if (has_tags) {
5114 curr_tag = (color >> (num_comp*8)) & 0xff;
5115 }
5116 if (devn) {
5117 if (additive) {
5118 for (j = 0; j < (num_comp - num_spots); j++) {
5119 src[j] = ((pdc->colors.devn.values[j]) >> shift & mask);
5120 }
5121 for (j = 0; j < num_spots; j++) {
5122 src[j + num_comp - num_spots] =
5123 255 - ((pdc->colors.devn.values[j + num_comp - num_spots]) >> shift & mask);
5124 }
5125 } else {
5126 for (j = 0; j < num_comp; j++) {
5127 src[j] = 255 - ((pdc->colors.devn.values[j]) >> shift & mask);
5128 }
5129 }
5130 } else
5131 pdev->pdf14_procs->unpack_color(num_comp, color, pdev, src);
5132 src_alpha = src[num_comp] = (byte)floor (255 * pdev->alpha + 0.5);
5133 if (has_shape)
5134 shape = (byte)floor (255 * pdev->shape + 0.5);
5135 /* Fit the mark into the bounds of the buffer */
5136 if (x < buf->rect.p.x) {
5137 w += x - buf->rect.p.x;
5138 x = buf->rect.p.x;
5139 }
5140 if (y < buf->rect.p.y) {
5141 h += y - buf->rect.p.y;
5142 y = buf->rect.p.y;
5143 }
5144 if (x + w > buf->rect.q.x) w = buf->rect.q.x - x;
5145 if (y + h > buf->rect.q.y) h = buf->rect.q.y - y;
5146 /* Update the dirty rectangle with the mark */
5147 if (x < buf->dirty.p.x) buf->dirty.p.x = x;
5148 if (y < buf->dirty.p.y) buf->dirty.p.y = y;
5149 if (x + w > buf->dirty.q.x) buf->dirty.q.x = x + w;
5150 if (y + h > buf->dirty.q.y) buf->dirty.q.y = y + h;
5151 dst_ptr = buf->data + (x - buf->rect.p.x) + (y - buf->rect.p.y) * rowstride;
5152 src_alpha = 255-src_alpha;
5153 shape = 255-shape;
5154 if (!has_alpha_g)
5155 alpha_g_off = 0;
5156 if (!has_shape)
5157 shape_off = 0;
5158 if (!has_tags)
5159 tag_off = 0;
5160 rowstride -= w;
5161 /* The num_comp == 1 && additive case is very common (mono output
5162 * devices no spot support), so we optimise that specifically here. */
5163 if (src[num_comp] == 0)
5164 fn = mark_fill_rect_alpha0;
5165 else if (additive && num_spots == 0) {
5166 if (num_comp == 1) {
5167 if (blend_mode == BLEND_MODE_Normal) {
5168 if (tag_off == 0 && shape_off == 0 && alpha_g_off == 0)
5169 fn = mark_fill_rect_add1_no_spots_fast;
5170 else
5171 fn = mark_fill_rect_add1_no_spots_normal;
5172 } else
5173 fn = mark_fill_rect_add1_no_spots;
5174 } else if (tag_off == 0 && shape_off == 0 && blend_mode == BLEND_MODE_Normal) {
5175 if (alpha_g_off == 0) {
5176 if (num_comp == 3)
5177 fn = mark_fill_rect_add3_common;
5178 else
5179 fn = mark_fill_rect_add_nospots_common_no_alpha_g;
5180 } else
5181 fn = mark_fill_rect_add_nospots_common;
5182 } else
5183 fn = mark_fill_rect_add_nospots;
5184 } else if (!additive && num_spots == 0 && num_comp == 4 && num_spots == 0 &&
5185 first_blend_spot == 0 && blend_mode == BLEND_MODE_Normal &&
5186 !overprint && tag_off == 0 && alpha_g_off == 0 && shape_off == 0)
5187 fn = mark_fill_rect_sub4_fast;
5188 else
5189 fn = mark_fill_rect;
5190
5191 fn(w, h, dst_ptr, src, num_comp, num_spots, first_blend_spot, src_alpha,
5192 rowstride, planestride, additive, pdev, blend_mode, overprint,
5193 drawn_comps, tag_off, curr_tag, alpha_g_off, shape_off, shape);
5194
5195 #if 0
5196 /* #if RAW_DUMP */
5197 /* Dump the current buffer to see what we have. */
5198
5199 if(global_index/10.0 == (int) (global_index/10.0) )
5200 dump_raw_buffer(pdev->ctx->mem,
5201 pdev->ctx->stack->rect.q.y-pdev->ctx->stack->rect.p.y,
5202 pdev->ctx->stack->rect.q.x-pdev->ctx->stack->rect.p.x,
5203 pdev->ctx->stack->n_planes,
5204 pdev->ctx->stack->planestride, pdev->ctx->stack->rowstride,
5205 "Draw_Rect", pdev->ctx->stack->data, pdev->ctx->stack->deep);
5206
5207 global_index++;
5208 #endif
5209 return 0;
5210 }
5211
5212 typedef void (*pdf14_mark_fill_rect16_fn)(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5213 uint16_t src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5214 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5215 int alpha_g_off, int shape_off, uint16_t shape);
5216
5217 static forceinline void
template_mark_fill_rect16(int w,int h,uint16_t * gs_restrict dst_ptr,uint16_t * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,uint16_t src_alpha_,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,uint16_t shape_)5218 template_mark_fill_rect16(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5219 uint16_t src_alpha_, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5220 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5221 int alpha_g_off, int shape_off, uint16_t shape_)
5222 {
5223 int i, j, k;
5224 uint16_t dst[PDF14_MAX_PLANES] = { 0 };
5225 uint16_t dest_alpha;
5226 /* Expand src_alpha and shape to be 0...0x10000 rather than 0...0xffff */
5227 int src_alpha = src_alpha_ + (src_alpha_>>15);
5228 int shape = shape_ + (shape_>>15);
5229 bool tag_blend = blend_mode == BLEND_MODE_Normal ||
5230 blend_mode == BLEND_MODE_Compatible ||
5231 blend_mode == BLEND_MODE_CompatibleOverprint;
5232
5233 for (j = h; j > 0; --j) {
5234 for (i = w; i > 0; --i) {
5235 if ((blend_mode == BLEND_MODE_Normal && src[num_comp] == 0xffff && !overprint) || dst_ptr[num_comp * planestride] == 0) {
5236 /* dest alpha is zero (or normal, and solid src) just use source. */
5237 if (additive) {
5238 /* Hybrid case */
5239 for (k = 0; k < (num_comp - num_spots); k++) {
5240 dst_ptr[k * planestride] = src[k];
5241 }
5242 for (k = 0; k < num_spots; k++) {
5243 dst_ptr[(k + num_comp - num_spots) * planestride] =
5244 65535 - src[k + num_comp - num_spots];
5245 }
5246 } else {
5247 /* Pure subtractive */
5248 for (k = 0; k < num_comp; k++) {
5249 dst_ptr[k * planestride] = 65535 - src[k];
5250 }
5251 }
5252 /* alpha */
5253 dst_ptr[num_comp * planestride] = src[num_comp];
5254 } else if (src[num_comp] != 0) {
5255 uint16_t *pdst;
5256 /* Complement subtractive planes */
5257 if (!additive) {
5258 /* Pure subtractive */
5259 for (k = 0; k < num_comp; ++k)
5260 dst[k] = 65535 - dst_ptr[k * planestride];
5261 } else {
5262 /* Hybrid case, additive with subtractive spots */
5263 for (k = 0; k < (num_comp - num_spots); k++) {
5264 dst[k] = dst_ptr[k * planestride];
5265 }
5266 for (k = 0; k < num_spots; k++) {
5267 dst[k + num_comp - num_spots] =
5268 65535 - dst_ptr[(k + num_comp - num_spots) * planestride];
5269 }
5270 }
5271 dst[num_comp] = dst_ptr[num_comp * planestride];
5272 dest_alpha = dst[num_comp];
5273 pdst = art_pdf_composite_pixel_alpha_16_inline(dst, src, num_comp, blend_mode, first_blend_spot,
5274 pdev->blend_procs, pdev);
5275 /* Post blend complement for subtractive and handling of drawncomps
5276 if overprint. We will have already done the compatible overprint
5277 mode in the above composition */
5278 if (!additive && !overprint) {
5279 /* Pure subtractive */
5280 for (k = 0; k < num_comp; ++k)
5281 dst_ptr[k * planestride] = 65535 - pdst[k];
5282 } else if (!additive && overprint) {
5283 int comps;
5284 /* If this is an overprint case, and alpha_r is different
5285 than alpha_d then we will need to adjust
5286 the colors of the non-drawn components here too */
5287 if (dest_alpha != pdst[num_comp] && pdst[num_comp] != 0) {
5288 /* dest_alpha > pdst[num_comp], and dst[num_comp] != 0.
5289 * Therefore dest_alpha / pdst[num_comp] <= 65535 */
5290 uint64_t scale = (uint64_t)65536 * dest_alpha / pdst[num_comp];
5291 for (k = 0, comps = drawn_comps; comps != 0; ++k, comps >>= 1) {
5292 if ((comps & 0x1) != 0) {
5293 dst_ptr[k * planestride] = 65535 - pdst[k];
5294 } else {
5295 /* We need val_new = (val_old * old_alpha) / new_alpha */
5296 uint64_t val = (scale * (65535 - pdst[k]) + 32768)>>16;
5297 if (val > 65535)
5298 val = 65535;
5299 dst_ptr[k * planestride] = val;
5300 }
5301 }
5302 } else {
5303 for (k = 0, comps = drawn_comps; comps != 0; ++k, comps >>= 1) {
5304 if ((comps & 0x1) != 0) {
5305 dst_ptr[k * planestride] = 65535 - pdst[k];
5306 }
5307 }
5308 }
5309 } else {
5310 /* Hybrid case, additive with subtractive spots */
5311 for (k = 0; k < (num_comp - num_spots); k++) {
5312 dst_ptr[k * planestride] = pdst[k];
5313 }
5314 for (k = 0; k < num_spots; k++) {
5315 dst_ptr[(k + num_comp - num_spots) * planestride] =
5316 65535 - pdst[k + num_comp - num_spots];
5317 }
5318 }
5319 /* The alpha channel */
5320 dst_ptr[num_comp * planestride] = pdst[num_comp];
5321 }
5322 if (tag_off) {
5323 /* If src alpha is 100% then set to curr_tag, else or */
5324 /* other than Normal BM, we always OR */
5325 if (src[num_comp] == 65535 && tag_blend) {
5326 dst_ptr[tag_off] = curr_tag;
5327 } else {
5328 dst_ptr[tag_off] |= curr_tag;
5329 }
5330 }
5331 if (alpha_g_off) {
5332 int tmp = (65535 - dst_ptr[alpha_g_off]) * src_alpha + 0x8000;
5333 dst_ptr[alpha_g_off] = 65535 - (tmp >> 16);
5334 }
5335 if (shape_off) {
5336 int tmp = (65535 - dst_ptr[shape_off]) * shape + 0x8000;
5337 dst_ptr[shape_off] = 65535 - (tmp >> 16);
5338 }
5339 ++dst_ptr;
5340 }
5341 dst_ptr += rowstride;
5342 }
5343 }
5344
5345 static void
mark_fill_rect16_alpha0(int w,int h,uint16_t * gs_restrict dst_ptr,uint16_t * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,uint16_t src_alpha_,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,uint16_t shape_)5346 mark_fill_rect16_alpha0(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5347 uint16_t src_alpha_, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5348 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5349 int alpha_g_off, int shape_off, uint16_t shape_)
5350 {
5351 int i, j;
5352 int src_alpha = src_alpha_;
5353 int shape = shape_;
5354
5355 src_alpha += src_alpha>>15;
5356 shape += shape>>15;
5357 for (j = h; j > 0; --j) {
5358 for (i = w; i > 0; --i) {
5359 if (alpha_g_off) {
5360 int tmp = (65535 - dst_ptr[alpha_g_off]) * src_alpha + 0x8000;
5361 dst_ptr[alpha_g_off] = 65535 - (tmp >> 16);
5362 }
5363 if (shape_off) {
5364 int tmp = (65535 - dst_ptr[shape_off]) * shape + 0x8000;
5365 dst_ptr[shape_off] = 65535 - (tmp >> 16);
5366 }
5367 ++dst_ptr;
5368 }
5369 dst_ptr += rowstride;
5370 }
5371 }
5372
5373 static void
mark_fill_rect16(int w,int h,uint16_t * gs_restrict dst_ptr,uint16_t * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,uint16_t src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,uint16_t shape)5374 mark_fill_rect16(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5375 uint16_t src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5376 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5377 int alpha_g_off, int shape_off, uint16_t shape)
5378 {
5379 template_mark_fill_rect16(w, h, dst_ptr, src, num_comp, num_spots, first_blend_spot,
5380 src_alpha, rowstride, planestride, additive, pdev, blend_mode,
5381 overprint, drawn_comps, tag_off, curr_tag,
5382 alpha_g_off, shape_off, shape);
5383 }
5384
5385 static void
mark_fill_rect16_sub4_fast(int w,int h,uint16_t * gs_restrict dst_ptr,uint16_t * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,uint16_t src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,uint16_t shape)5386 mark_fill_rect16_sub4_fast(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5387 uint16_t src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5388 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5389 int alpha_g_off, int shape_off, uint16_t shape)
5390 {
5391 int i, j, k;
5392
5393 for (j = h; j > 0; --j) {
5394 for (i = w; i > 0; --i) {
5395 uint16_t a_s = src[4];
5396 int a_b = dst_ptr[4 * planestride];
5397 if ((a_s == 0xffff) || a_b == 0) {
5398 /* dest alpha is zero (or normal, and solid src) just use source. */
5399 dst_ptr[0 * planestride] = 65535 - src[0];
5400 dst_ptr[1 * planestride] = 65535 - src[1];
5401 dst_ptr[2 * planestride] = 65535 - src[2];
5402 dst_ptr[3 * planestride] = 65535 - src[3];
5403 /* alpha */
5404 dst_ptr[4 * planestride] = a_s;
5405 } else if (a_s != 0) {
5406 /* Result alpha is Union of backdrop and source alpha */
5407 unsigned int tmp, src_scale;
5408 unsigned int a_r;
5409
5410 a_b += a_b>>15;
5411 tmp = (0x10000 - a_b) * (0xffff - a_s) + 0x8000;
5412 a_r = 0xffff - (tmp >> 16);
5413
5414 /* Compute a_s / a_r in 16.16 format */
5415 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
5416
5417 dst_ptr[4 * planestride] = a_r;
5418
5419 src_scale >>= 1; /* Lose a bit to avoid overflow */
5420 /* Do simple compositing of source over backdrop */
5421 for (k = 0; k < 4; k++) {
5422 int c_s = src[k];
5423 int c_b = 65535 - dst_ptr[k * planestride];
5424 tmp = src_scale * (c_s - c_b) + 0x4000;
5425 dst_ptr[k * planestride] = 0xffff - c_b - (tmp >> 15);
5426 }
5427 }
5428 ++dst_ptr;
5429 }
5430 dst_ptr += rowstride;
5431 }
5432 }
5433
5434 static void
mark_fill_rect16_add_nospots(int w,int h,uint16_t * gs_restrict dst_ptr,uint16_t * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,uint16_t src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,uint16_t shape)5435 mark_fill_rect16_add_nospots(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5436 uint16_t src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5437 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5438 int alpha_g_off, int shape_off, uint16_t shape)
5439 {
5440 template_mark_fill_rect16(w, h, dst_ptr, src, num_comp, /*num_spots*/0, first_blend_spot,
5441 src_alpha, rowstride, planestride, /*additive*/1, pdev, blend_mode,
5442 /*overprint*/0, /*drawn_comps*/0, tag_off, curr_tag,
5443 alpha_g_off, shape_off, shape);
5444 }
5445
5446 static void
mark_fill_rect16_add_nospots_common(int w,int h,uint16_t * gs_restrict dst_ptr,uint16_t * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,uint16_t src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,uint16_t shape)5447 mark_fill_rect16_add_nospots_common(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5448 uint16_t src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5449 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5450 int alpha_g_off, int shape_off, uint16_t shape)
5451 {
5452 template_mark_fill_rect16(w, h, dst_ptr, src, num_comp, /*num_spots*/0, /*first_blend_spot*/0,
5453 src_alpha, rowstride, planestride, /*additive*/1, pdev, /*blend_mode*/BLEND_MODE_Normal,
5454 /*overprint*/0, /*drawn_comps*/0, /*tag_off*/0, curr_tag,
5455 alpha_g_off, /*shape_off*/0, shape);
5456 }
5457
5458 static void
mark_fill_rect16_add_nospots_common_no_alpha_g(int w,int h,uint16_t * gs_restrict dst_ptr,uint16_t * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,uint16_t src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,uint16_t shape)5459 mark_fill_rect16_add_nospots_common_no_alpha_g(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5460 uint16_t src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5461 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5462 int alpha_g_off, int shape_off, uint16_t shape)
5463 {
5464 template_mark_fill_rect16(w, h, dst_ptr, src, num_comp, /*num_spots*/0, /*first_blend_spot*/0,
5465 src_alpha, rowstride, planestride, /*additive*/1, pdev, /*blend_mode*/BLEND_MODE_Normal,
5466 /*overprint*/0, /*drawn_comps*/0, /*tag_off*/0, curr_tag,
5467 /*alpha_g_off*/0, /*shape_off*/0, shape);
5468 }
5469
5470 static void
mark_fill_rect16_add3_common(int w,int h,uint16_t * gs_restrict dst_ptr,uint16_t * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,uint16_t src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,uint16_t shape)5471 mark_fill_rect16_add3_common(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5472 uint16_t src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5473 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5474 int alpha_g_off, int shape_off, uint16_t shape)
5475 {
5476 int i, j, k;
5477
5478 for (j = h; j > 0; --j) {
5479 for (i = w; i > 0; --i) {
5480 uint16_t a_s = src[3];
5481 int a_b = dst_ptr[3 * planestride];
5482 if (a_s == 0xffff || a_b == 0) {
5483 /* dest alpha is zero (or solid source) just use source. */
5484 dst_ptr[0 * planestride] = src[0];
5485 dst_ptr[1 * planestride] = src[1];
5486 dst_ptr[2 * planestride] = src[2];
5487 /* alpha */
5488 dst_ptr[3 * planestride] = a_s;
5489 } else if (a_s != 0) {
5490 unsigned int tmp, src_scale;
5491 unsigned int a_r;
5492
5493 a_b += a_b >> 15;
5494 /* Result alpha is Union of backdrop and source alpha */
5495 tmp = (0x10000 - a_b) * (0xffff - a_s) + 0x8000;
5496 a_r = 0xffff - (tmp >> 16);
5497 /* todo: verify that a_r is nonzero in all cases */
5498
5499 /* Compute a_s / a_r in 16.16 format */
5500 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
5501
5502 dst_ptr[3 * planestride] = a_r;
5503
5504 src_scale >>= 1; /* Lose a bit to avoid overflow */
5505 /* Do simple compositing of source over backdrop */
5506 for (k = 0; k < 3; k++) {
5507 int c_s = src[k];
5508 int c_b = dst_ptr[k * planestride];
5509 tmp = src_scale * (c_s - c_b) + 0x4000;
5510 dst_ptr[k * planestride] = c_b + (tmp >> 15);
5511 }
5512 }
5513 ++dst_ptr;
5514 }
5515 dst_ptr += rowstride;
5516 }
5517 }
5518
5519 static void
mark_fill_rect16_add1_no_spots(int w,int h,uint16_t * gs_restrict dst_ptr,uint16_t * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,uint16_t src_alpha_,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,uint16_t shape_)5520 mark_fill_rect16_add1_no_spots(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5521 uint16_t src_alpha_, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5522 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5523 int alpha_g_off, int shape_off, uint16_t shape_)
5524 {
5525 int i;
5526 int src_alpha = src_alpha_;
5527 int shape = shape_;
5528 bool tag_blend = blend_mode == BLEND_MODE_Normal ||
5529 blend_mode == BLEND_MODE_Compatible ||
5530 blend_mode == BLEND_MODE_CompatibleOverprint;
5531
5532 src_alpha += src_alpha>>15;
5533 shape += shape>>15;
5534 for (; h > 0; --h) {
5535 for (i = w; i > 0; --i) {
5536 /* background empty, nothing to change, or solid source */
5537 uint16_t a_s = src[1];
5538 if ((blend_mode == BLEND_MODE_Normal && a_s == 0xffff) || dst_ptr[planestride] == 0) {
5539 dst_ptr[0] = src[0];
5540 dst_ptr[planestride] = a_s;
5541 } else {
5542 art_pdf_composite_pixel_alpha_16_fast_mono(dst_ptr, src,
5543 blend_mode, pdev->blend_procs,
5544 planestride, pdev);
5545 }
5546 if (tag_off) {
5547 /* If src alpha is 100% then set to curr_tag, else or */
5548 /* other than Normal BM, we always OR */
5549 if (tag_blend && a_s == 65535) {
5550 dst_ptr[tag_off] = curr_tag;
5551 } else {
5552 dst_ptr[tag_off] |= curr_tag;
5553 }
5554 }
5555 if (alpha_g_off) {
5556 int tmp = (65535 - dst_ptr[alpha_g_off]) * src_alpha + 0x8000;
5557 dst_ptr[alpha_g_off] = 65535 - (tmp >> 16);
5558 }
5559 if (shape_off) {
5560 int tmp = (65535 - dst_ptr[shape_off]) * shape + 0x8000;
5561 dst_ptr[shape_off] = 65535 - (tmp >> 16);
5562 }
5563 ++dst_ptr;
5564 }
5565 dst_ptr += rowstride;
5566 }
5567 }
5568
5569 static void
mark_fill_rect16_add1_no_spots_normal(int w,int h,uint16_t * gs_restrict dst_ptr,uint16_t * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,uint16_t src_alpha_,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,uint16_t shape_)5570 mark_fill_rect16_add1_no_spots_normal(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5571 uint16_t src_alpha_, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5572 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5573 int alpha_g_off, int shape_off, uint16_t shape_)
5574 {
5575 int i;
5576 int src_alpha = src_alpha_;
5577 int shape = shape_;
5578
5579 src_alpha += src_alpha>>15;
5580 shape += shape>>15;
5581
5582 for (; h > 0; --h) {
5583 for (i = w; i > 0; --i) {
5584 /* background empty, nothing to change, or solid source */
5585 uint16_t a_s = src[1];
5586 uint16_t a_b = dst_ptr[planestride];
5587 if (a_s == 0xffff || a_b == 0) {
5588 dst_ptr[0] = src[0];
5589 dst_ptr[planestride] = a_s;
5590 } else {
5591 /* Result alpha is Union of backdrop and source alpha */
5592 unsigned int tmp, src_scale;
5593 unsigned int a_r;
5594 int c_s, c_b;
5595
5596 a_b += a_b>>15;
5597 tmp = (0x10000 - a_b) * (0xffff - a_s) + 0x8000;
5598 a_r = 0xffff - (tmp >> 16);
5599
5600 /* Compute a_s / a_r in 16.16 format */
5601 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
5602
5603 src_scale >>= 1; /* Lose a bit to avoid overflow */
5604 /* Do simple compositing of source over backdrop */
5605 c_s = src[0];
5606 c_b = dst_ptr[0];
5607 tmp = src_scale * (c_s - c_b) + 0x4000;
5608 dst_ptr[0] = c_b + (tmp >> 15);
5609 dst_ptr[planestride] = a_r;
5610 }
5611 if (tag_off) {
5612 /* If src alpha is 100% then set to curr_tag, else or */
5613 /* other than Normal BM, we always OR */
5614 if (a_s == 65535) {
5615 dst_ptr[tag_off] = curr_tag;
5616 } else {
5617 dst_ptr[tag_off] |= curr_tag;
5618 }
5619 }
5620 if (alpha_g_off) {
5621 int tmp = (65535 - dst_ptr[alpha_g_off]) * src_alpha + 0x8000;
5622 dst_ptr[alpha_g_off] = 65535 - (tmp >> 16);
5623 }
5624 if (shape_off) {
5625 int tmp = (65535 - dst_ptr[shape_off]) * shape + 0x8000;
5626 dst_ptr[shape_off] = 65535 - (tmp >> 16);
5627 }
5628 ++dst_ptr;
5629 }
5630 dst_ptr += rowstride;
5631 }
5632 }
5633
5634 static void
mark_fill_rect16_add1_no_spots_fast(int w,int h,uint16_t * gs_restrict dst_ptr,uint16_t * gs_restrict src,int num_comp,int num_spots,int first_blend_spot,uint16_t src_alpha,int rowstride,int planestride,bool additive,pdf14_device * pdev,gs_blend_mode_t blend_mode,bool overprint,gx_color_index drawn_comps,int tag_off,gs_graphics_type_tag_t curr_tag,int alpha_g_off,int shape_off,uint16_t shape)5635 mark_fill_rect16_add1_no_spots_fast(int w, int h, uint16_t *gs_restrict dst_ptr, uint16_t *gs_restrict src, int num_comp, int num_spots, int first_blend_spot,
5636 uint16_t src_alpha, int rowstride, int planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5637 bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5638 int alpha_g_off, int shape_off, uint16_t shape)
5639 {
5640 int i;
5641
5642 for (; h > 0; --h) {
5643 for (i = w; i > 0; --i) {
5644 /* background empty, nothing to change, or solid source */
5645 uint16_t a_s = src[1];
5646 int a_b = dst_ptr[planestride];
5647 if (a_s == 0xffff || a_b == 0) {
5648 dst_ptr[0] = src[0];
5649 dst_ptr[planestride] = a_s;
5650 } else if (a_s != 0) {
5651 /* Result alpha is Union of backdrop and source alpha */
5652 unsigned int tmp, src_scale;
5653 unsigned int a_r;
5654 int c_s, c_b;
5655
5656 a_b += a_b>>15;
5657 tmp = (0x10000 - a_b) * (0xffff - a_s) + 0x8000;
5658 a_r = 0xffff - (tmp >> 16);
5659
5660 /* Compute a_s / a_r in 16.16 format */
5661 src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
5662
5663 src_scale >>= 1; /* Lose a bit to avoid overflow */
5664 /* Do simple compositing of source over backdrop */
5665 c_s = src[0];
5666 c_b = dst_ptr[0];
5667 tmp = src_scale * (c_s - c_b) + 0x4000;
5668 dst_ptr[0] = c_b + (tmp >> 15);
5669 dst_ptr[planestride] = a_r;
5670 }
5671 ++dst_ptr;
5672 }
5673 dst_ptr += rowstride;
5674 }
5675 }
5676
5677 static int
do_mark_fill_rectangle16(gx_device * dev,int x,int y,int w,int h,gx_color_index color,const gx_device_color * pdc,bool devn)5678 do_mark_fill_rectangle16(gx_device * dev, int x, int y, int w, int h,
5679 gx_color_index color, const gx_device_color *pdc,
5680 bool devn)
5681 {
5682 pdf14_device *pdev = (pdf14_device *)dev;
5683 pdf14_buf *buf = pdev->ctx->stack;
5684 int j;
5685 uint16_t *dst_ptr;
5686 uint16_t src[PDF14_MAX_PLANES];
5687 gs_blend_mode_t blend_mode = pdev->blend_mode;
5688 bool additive = pdev->ctx->additive;
5689 int rowstride = buf->rowstride;
5690 int planestride = buf->planestride;
5691 gs_graphics_type_tag_t curr_tag = GS_UNKNOWN_TAG; /* Quite compiler */
5692 bool has_alpha_g = buf->has_alpha_g;
5693 bool has_shape = buf->has_shape;
5694 bool has_tags = buf->has_tags;
5695 int num_chan = buf->n_chan;
5696 int num_comp = num_chan - 1;
5697 int shape_off = num_chan * planestride;
5698 int alpha_g_off = shape_off + (has_shape ? planestride : 0);
5699 int tag_off = alpha_g_off + (has_alpha_g ? planestride : 0);
5700 bool overprint = pdev->op_state == PDF14_OP_STATE_FILL ? pdev->overprint : pdev->stroke_overprint;
5701 gx_color_index drawn_comps = pdev->op_state == PDF14_OP_STATE_FILL ?
5702 pdev->drawn_comps_fill : pdev->drawn_comps_stroke;
5703 uint16_t shape = 0; /* Quiet compiler. */
5704 uint16_t src_alpha;
5705 int num_spots = buf->num_spots;
5706 int first_blend_spot = num_comp;
5707 pdf14_mark_fill_rect16_fn fn;
5708
5709 if (num_spots > 0 && !blend_valid_for_spot(blend_mode))
5710 first_blend_spot = num_comp - num_spots;
5711 if (blend_mode == BLEND_MODE_Normal)
5712 first_blend_spot = 0;
5713
5714 if (buf->data == NULL)
5715 return 0;
5716 /* NB: gx_color_index is 4 or 8 bytes */
5717 #if 0
5718 if (sizeof(color) <= sizeof(ulong))
5719 if_debug8m('v', dev->memory,
5720 "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %lx bm %d, nc %d, overprint %d\n",
5721 x, y, w, h, (ulong)color, blend_mode, num_chan, overprint);
5722 else
5723 if_debug9m('v', dev->memory,
5724 "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %08lx%08lx bm %d, nc %d, overprint %d\n",
5725 x, y, w, h,
5726 (ulong)(color >> 8*(sizeof(color) - sizeof(ulong))), (ulong)color,
5727 blend_mode, num_chan, overprint);
5728 #endif
5729 /*
5730 * Unpack the gx_color_index values. Complement the components for subtractive
5731 * color spaces.
5732 */
5733 if (has_tags) {
5734 curr_tag = (color >> (num_comp*16)) & 0xff;
5735 }
5736 if (devn) {
5737 if (additive) {
5738 for (j = 0; j < (num_comp - num_spots); j++) {
5739 src[j] = pdc->colors.devn.values[j];
5740 }
5741 for (j = 0; j < num_spots; j++) {
5742 src[j + num_comp - num_spots] =
5743 65535 - pdc->colors.devn.values[j + num_comp - num_spots];
5744 }
5745 } else {
5746 for (j = 0; j < num_comp; j++) {
5747 src[j] = 65535 - pdc->colors.devn.values[j];
5748 }
5749 }
5750 } else
5751 pdev->pdf14_procs->unpack_color16(num_comp, color, pdev, src);
5752 src_alpha = src[num_comp] = (uint16_t)floor (65535 * pdev->alpha + 0.5);
5753 if (has_shape)
5754 shape = (uint16_t)floor (65535 * pdev->shape + 0.5);
5755 /* Fit the mark into the bounds of the buffer */
5756 if (x < buf->rect.p.x) {
5757 w += x - buf->rect.p.x;
5758 x = buf->rect.p.x;
5759 }
5760 if (y < buf->rect.p.y) {
5761 h += y - buf->rect.p.y;
5762 y = buf->rect.p.y;
5763 }
5764 if (x + w > buf->rect.q.x) w = buf->rect.q.x - x;
5765 if (y + h > buf->rect.q.y) h = buf->rect.q.y - y;
5766 /* Update the dirty rectangle with the mark */
5767 if (x < buf->dirty.p.x) buf->dirty.p.x = x;
5768 if (y < buf->dirty.p.y) buf->dirty.p.y = y;
5769 if (x + w > buf->dirty.q.x) buf->dirty.q.x = x + w;
5770 if (y + h > buf->dirty.q.y) buf->dirty.q.y = y + h;
5771 dst_ptr = (uint16_t *)(buf->data + (x - buf->rect.p.x) * 2 + (y - buf->rect.p.y) * rowstride);
5772 src_alpha = 65535-src_alpha;
5773 shape = 65535-shape;
5774 if (!has_alpha_g)
5775 alpha_g_off = 0;
5776 if (!has_shape)
5777 shape_off = 0;
5778 if (!has_tags)
5779 tag_off = 0;
5780 rowstride -= w<<1;
5781 /* The num_comp == 1 && additive case is very common (mono output
5782 * devices no spot support), so we optimise that specifically here. */
5783 if (src[num_comp] == 0)
5784 fn = mark_fill_rect16_alpha0;
5785 else if (additive && num_spots == 0) {
5786 if (num_comp == 1) {
5787 if (blend_mode == BLEND_MODE_Normal) {
5788 if (tag_off == 0 && shape_off == 0 && alpha_g_off == 0)
5789 fn = mark_fill_rect16_add1_no_spots_fast;
5790 else
5791 fn = mark_fill_rect16_add1_no_spots_normal;
5792 } else
5793 fn = mark_fill_rect16_add1_no_spots;
5794 } else if (tag_off == 0 && shape_off == 0 && blend_mode == BLEND_MODE_Normal) {
5795 if (alpha_g_off == 0) {
5796 if (num_comp == 3)
5797 fn = mark_fill_rect16_add3_common;
5798 else
5799 fn = mark_fill_rect16_add_nospots_common_no_alpha_g;
5800 } else
5801 fn = mark_fill_rect16_add_nospots_common;
5802 } else
5803 fn = mark_fill_rect16_add_nospots;
5804 } else if (!additive && num_spots == 0 && num_comp == 4 && num_spots == 0 &&
5805 first_blend_spot == 0 && blend_mode == BLEND_MODE_Normal &&
5806 !overprint && tag_off == 0 && alpha_g_off == 0 && shape_off == 0)
5807 fn = mark_fill_rect16_sub4_fast;
5808 else
5809 fn = mark_fill_rect16;
5810
5811 /* Pass values as array offsets, not byte diffs */
5812 rowstride >>= 1;
5813 planestride >>= 1;
5814 tag_off >>= 1;
5815 alpha_g_off >>= 1;
5816 shape_off >>= 1;
5817 fn(w, h, dst_ptr, src, num_comp, num_spots, first_blend_spot, src_alpha,
5818 rowstride, planestride, additive, pdev, blend_mode, overprint,
5819 drawn_comps, tag_off, curr_tag, alpha_g_off, shape_off, shape);
5820
5821 #if 0
5822 /* #if RAW_DUMP */
5823 /* Dump the current buffer to see what we have. */
5824
5825 if(global_index/10.0 == (int) (global_index/10.0) )
5826 dump_raw_buffer(pdev->ctx->mem,
5827 pdev->ctx->stack->rect.q.y-pdev->ctx->stack->rect.p.y,
5828 pdev->ctx->stack->rect.q.x-pdev->ctx->stack->rect.p.x,
5829 pdev->ctx->stack->n_planes,
5830 pdev->ctx->stack->planestride, pdev->ctx->stack->rowstride,
5831 "Draw_Rect", pdev->ctx->stack->data, pdev->ctx->stack->deep);
5832
5833 global_index++;
5834 #endif
5835 return 0;
5836 }
5837
5838 int
pdf14_mark_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color,const gx_device_color * pdc,bool devn)5839 pdf14_mark_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
5840 gx_color_index color, const gx_device_color *pdc,
5841 bool devn)
5842 {
5843 pdf14_device *pdev = (pdf14_device *)dev;
5844 pdf14_buf *buf = pdev->ctx->stack;
5845
5846 if (buf->deep)
5847 return do_mark_fill_rectangle16(dev, x, y, w, h, color, pdc, devn);
5848 else
5849 return do_mark_fill_rectangle(dev, x, y, w, h, color, pdc, devn);
5850 }
5851
5852 /* Keep this at the end because of the #undef print */
5853
5854 #ifdef TRACK_COMPOSE_GROUPS
5855 static void
dump_track_compose_groups(void)5856 dump_track_compose_groups(void)
5857 {
5858 int i;
5859
5860 for (i = 0; i < (1<<17); i++)
5861 {
5862 if (compose_groups[i] == 0)
5863 continue;
5864 #undef printf
5865 printf("COMPOSE_GROUPS: %04x:%d\n", i, compose_groups[i]);
5866 }
5867 }
5868 #endif
5869