Coverage Report

Created: 2022-10-31 07:00

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