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