Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gxblend.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, 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
2.32k
{
55
2.32k
    if (blend_mode == BLEND_MODE_Difference ||
56
2.32k
        blend_mode == BLEND_MODE_Exclusion ||
57
2.32k
        blend_mode == BLEND_MODE_Hue ||
58
2.32k
        blend_mode == BLEND_MODE_Saturation ||
59
2.32k
        blend_mode == BLEND_MODE_Color ||
60
2.32k
        blend_mode == BLEND_MODE_Luminosity)
61
0
        return false;
62
2.32k
    else
63
2.32k
        return true;
64
2.32k
}
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, intptr_t row_stride,
74
                            intptr_t 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
    intptr_t mask_alpha_offset,mask_C_offset,mask_M_offset,mask_Y_offset,mask_K_offset;
84
0
    intptr_t 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, intptr_t row_stride,
191
                               intptr_t 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
    intptr_t mask_alpha_offset,mask_C_offset,mask_M_offset,mask_Y_offset,mask_K_offset;
201
0
    intptr_t 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, intptr_t row_stride,
308
                         intptr_t 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, intptr_t rowstride,
339
            intptr_t planestride, bool deep)
340
210k
{
341
210k
    int x, y;
342
210k
    int position;
343
344
210k
    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
210k
    } else {
368
210k
        byte comp, a;
369
210k
        int tmp;
370
210k
        const byte bg = 0;
371
2.63M
        for (y = 0; y < height; y++) {
372
2.42M
            position = y * rowstride;
373
1.09G
            for (x = 0; x < width; x++) {
374
1.09G
                a = src[position + planestride];
375
1.09G
                if ((a + 1) & 0xfe) {
376
1.76M
                    a ^= 0xff;
377
1.76M
                    comp  = src[position];
378
1.76M
                    tmp = ((bg - comp) * a) + 0x80;
379
1.76M
                    comp += (tmp + (tmp >> 8)) >> 8;
380
1.76M
                    src[position] = comp;
381
1.09G
                } else if (a == 0) {
382
102M
                    src[position] = 0;
383
102M
                }
384
1.09G
                position+=1;
385
1.09G
            }
386
2.42M
        }
387
210k
    }
388
210k
}
389
390
void smask_copy(int num_rows, int num_cols, intptr_t row_stride,
391
                byte *gs_restrict src, const byte *gs_restrict dst)
392
247k
{
393
247k
    int y;
394
247k
    byte *dstptr,*srcptr;
395
396
247k
    dstptr = (byte *)dst;
397
247k
    srcptr = src;
398
3.10M
    for ( y = 0; y < num_rows; y++ ) {
399
2.86M
        memcpy(dstptr,srcptr,num_cols);
400
2.86M
        dstptr += row_stride;
401
2.86M
        srcptr += row_stride;
402
2.86M
    }
403
247k
}
404
405
int
406
smask_icc(gx_device *dev, int num_rows, int num_cols, int n_chan,
407
               intptr_t row_stride, intptr_t 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
2.79M
{
439
2.79M
    int rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
440
2.79M
    int rs = src[0], gs = src[1], bs = src[2];
441
2.79M
    int delta_y;
442
2.79M
    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
2.79M
    delta_y = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8;
449
2.79M
    r = rb + delta_y;
450
2.79M
    g = gb + delta_y;
451
2.79M
    b = bb + delta_y;
452
2.79M
    if ((r | g | b) & 0x100) {
453
257k
        int y;
454
257k
        int scale;
455
456
257k
        y = (rs * 77 + gs * 151 + bs * 28 + 0x80) >> 8;
457
257k
        if (delta_y > 0) {
458
93.1k
            int max;
459
460
93.1k
            max = r > g ? r : g;
461
93.1k
            max = b > max ? b : max;
462
93.1k
            scale = ((255 - y) << 16) / (max - y);
463
163k
        } else {
464
163k
            int min;
465
466
163k
            min = r < g ? r : g;
467
163k
            min = b < min ? b : min;
468
163k
            scale = (y << 16) / (y - min);
469
163k
        }
470
257k
        r = y + (((r - y) * scale + 0x8000) >> 16);
471
257k
        g = y + (((g - y) * scale + 0x8000) >> 16);
472
257k
        b = y + (((b - y) * scale + 0x8000) >> 16);
473
257k
    }
474
2.79M
    dst[0] = r;
475
2.79M
    dst[1] = g;
476
2.79M
    dst[2] = b;
477
2.79M
}
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
34.6k
{
654
34.6k
    int i;
655
656
    /* Treat CMY the same as RGB. */
657
34.6k
    art_blend_luminosity_rgb_8(3, dst, backdrop, src);
658
69.2k
    for (i = 3; i < n_chan; i++)
659
34.6k
        dst[i] = src[i];
660
34.6k
}
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
1.79M
{
714
1.79M
    int32_t rb = backdrop[0], gb = backdrop[1], bb = backdrop[2];
715
1.79M
    int rs = src[0], gs = src[1], bs = src[2];
716
1.79M
    int mins, maxs, minb, maxb;
717
1.79M
    int satCs, lumCb, lumC, d;
718
1.79M
    int scale;
719
720
1.79M
    if (rb == gb && gb == bb) {
721
        /* backdrop has zero saturation, no change. */
722
41.2k
        dst[0] = gb;
723
41.2k
        dst[1] = gb;
724
41.2k
        dst[2] = gb;
725
41.2k
        return;
726
41.2k
    }
727
728
    /* Lum(Cb) */
729
1.74M
    lumCb = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8;
730
731
1.74M
    mins = rs < gs ? rs : gs;
732
1.74M
    maxs = rs < gs ? gs : rs;
733
1.74M
    mins = mins < bs ? mins : bs;
734
1.74M
    maxs = maxs < bs ? bs : maxs;
735
736
    /* Sat(Cs) = maxs - mins */
737
1.74M
    satCs = maxs - mins;
738
739
    /* C = {rb, bb, gb} = SetSat(Cb, Sat(Cs)) */
740
1.74M
    minb = rb < gb ? rb : gb;
741
1.74M
    maxb = rb < gb ? gb : rb;
742
1.74M
    minb = minb < bb ? minb : bb;
743
1.74M
    maxb = maxb < bb ? bb : maxb;
744
1.74M
    scale = (satCs<<8) / (maxb - minb);
745
1.74M
    rb = ((rb - minb) * scale + 0x80)>>8;
746
1.74M
    gb = ((gb - minb) * scale + 0x80)>>8;
747
1.74M
    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
1.74M
    lumC = (rb * 77 + gb * 151 + bb * 28 + 0x80) >> 8;
753
1.74M
    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
1.74M
    if (d < 0) {
760
143k
        scale = (lumCb<<8) / lumC;
761
143k
        goto correct_overflow;
762
1.60M
    } else if (d + satCs > 255) {
763
20.3k
        scale = ((255 - lumCb)<<8) / (satCs - lumC);
764
163k
correct_overflow:
765
163k
        rb = lumCb + (((rb - lumC) * scale + 0x80)>>8);
766
163k
        gb = lumCb + (((gb - lumC) * scale + 0x80)>>8);
767
163k
        bb = lumCb + (((bb - lumC) * scale + 0x80)>>8);
768
1.58M
    } else {
769
        /* C += d */
770
1.58M
        rb += d;
771
1.58M
        gb += d;
772
1.58M
        bb += d;
773
1.58M
    }
774
775
1.74M
    dst[0] = rb;
776
1.74M
    dst[1] = gb;
777
1.74M
    dst[2] = bb;
778
1.74M
}
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
210M
{
1107
210M
    int i;
1108
210M
    byte b, s;
1109
210M
    bits32 t;
1110
1111
210M
    switch (blend_mode) {
1112
7.87k
        case BLEND_MODE_Normal:
1113
17.1M
        case BLEND_MODE_Compatible: /* todo */
1114
17.1M
            memcpy(dst, src, n_chan);
1115
17.1M
            break;
1116
170M
        case BLEND_MODE_Multiply:
1117
510M
            for (i = 0; i < n_chan; i++) {
1118
339M
                t = ((bits32) backdrop[i]) * ((bits32) src[i]);
1119
339M
                t += 0x80;
1120
339M
                t += (t >> 8);
1121
339M
                dst[i] = t >> 8;
1122
339M
            }
1123
170M
            break;
1124
6.22M
        case BLEND_MODE_Screen:
1125
25.8M
            for (i = 0; i < n_chan; i++) {
1126
19.6M
                t =
1127
19.6M
                    ((bits32) (0xff - backdrop[i])) *
1128
19.6M
                    ((bits32) (0xff - src[i]));
1129
19.6M
                t += 0x80;
1130
19.6M
                t += (t >> 8);
1131
19.6M
                dst[i] = 0xff - (t >> 8);
1132
19.6M
            }
1133
6.22M
            break;
1134
1.39M
        case BLEND_MODE_Overlay:
1135
5.56M
            for (i = 0; i < n_chan; i++) {
1136
4.17M
                b = backdrop[i];
1137
4.17M
                s = src[i];
1138
4.17M
                if (b < 0x80)
1139
3.55M
                    t = 2 * ((bits32) b) * ((bits32) s);
1140
620k
                else
1141
620k
                    t = 0xfe01 -
1142
620k
                        2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
1143
4.17M
                t += 0x80;
1144
4.17M
                t += (t >> 8);
1145
4.17M
                dst[i] = t >> 8;
1146
4.17M
            }
1147
1.39M
            break;
1148
1.66M
        case BLEND_MODE_SoftLight:
1149
6.13M
            for (i = 0; i < n_chan; i++) {
1150
4.47M
                b = backdrop[i];
1151
4.47M
                s = src[i];
1152
4.47M
                if (s < 0x80) {
1153
747k
                    t = (0xff - (s << 1)) * art_blend_sq_diff_8[b];
1154
747k
                    t += 0x8000;
1155
747k
                    dst[i] = b - (t >> 16);
1156
3.72M
                } else {
1157
3.72M
                    t =
1158
3.72M
                        ((s << 1) -
1159
3.72M
                         0xff) * ((bits32) (art_blend_soft_light_8[b]));
1160
3.72M
                    t += 0x80;
1161
3.72M
                    t += (t >> 8);
1162
3.72M
                    dst[i] = b + (t >> 8);
1163
3.72M
                }
1164
4.47M
            }
1165
1.66M
            break;
1166
957k
        case BLEND_MODE_HardLight:
1167
3.82M
            for (i = 0; i < n_chan; i++) {
1168
2.87M
                b = backdrop[i];
1169
2.87M
                s = src[i];
1170
2.87M
                if (s < 0x80)
1171
769k
                    t = 2 * ((bits32) b) * ((bits32) s);
1172
2.10M
                else
1173
2.10M
                    t = 0xfe01 -
1174
2.10M
                        2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
1175
2.87M
                t += 0x80;
1176
2.87M
                t += (t >> 8);
1177
2.87M
                dst[i] = t >> 8;
1178
2.87M
            }
1179
957k
            break;
1180
964k
        case BLEND_MODE_ColorDodge:
1181
3.85M
            for (i = 0; i < n_chan; i++) {
1182
2.89M
                b = backdrop[i];
1183
2.89M
                s = 0xff - src[i];
1184
2.89M
                if (b == 0)
1185
327k
                    dst[i] = 0;
1186
2.56M
                else if (b >= s)
1187
982k
                    dst[i] = 0xff;
1188
1.58M
                else
1189
1.58M
                    dst[i] = (0x1fe * b + s) / (s << 1);
1190
2.89M
            }
1191
964k
            break;
1192
855k
        case BLEND_MODE_ColorBurn:
1193
3.42M
            for (i = 0; i < n_chan; i++) {
1194
2.56M
                b = 0xff - backdrop[i];
1195
2.56M
                s = src[i];
1196
2.56M
                if (b == 0)
1197
1.23k
                    dst[i] = 0xff;
1198
2.56M
                else if (b >= s)
1199
1.73M
                    dst[i] = 0;
1200
828k
                else
1201
828k
                    dst[i] = 0xff - (0x1fe * b + s) / (s << 1);
1202
2.56M
            }
1203
855k
            break;
1204
1.35M
        case BLEND_MODE_Darken:
1205
5.37M
            for (i = 0; i < n_chan; i++) {
1206
4.02M
                b = backdrop[i];
1207
4.02M
                s = src[i];
1208
4.02M
                dst[i] = b < s ? b : s;
1209
4.02M
            }
1210
1.35M
            break;
1211
2.12M
        case BLEND_MODE_Lighten:
1212
8.48M
            for (i = 0; i < n_chan; i++) {
1213
6.36M
                b = backdrop[i];
1214
6.36M
                s = src[i];
1215
6.36M
                dst[i] = b > s ? b : s;
1216
6.36M
            }
1217
2.12M
            break;
1218
1.51M
        case BLEND_MODE_Difference:
1219
6.05M
            for (i = 0; i < n_chan; i++) {
1220
4.54M
                art_s32 tmp;
1221
1222
4.54M
                tmp = ((art_s32) backdrop[i]) - ((art_s32) src[i]);
1223
4.54M
                dst[i] = tmp < 0 ? -tmp : tmp;
1224
4.54M
            }
1225
1.51M
            break;
1226
937k
        case BLEND_MODE_Exclusion:
1227
3.75M
            for (i = 0; i < n_chan; i++) {
1228
2.81M
                b = backdrop[i];
1229
2.81M
                s = src[i];
1230
2.81M
                t = ((bits32) (0xff - b)) * ((bits32) s) +
1231
2.81M
                    ((bits32) b) * ((bits32) (0xff - s));
1232
2.81M
                t += 0x80;
1233
2.81M
                t += (t >> 8);
1234
2.81M
                dst[i] = t >> 8;
1235
2.81M
            }
1236
937k
            break;
1237
927k
        case BLEND_MODE_Luminosity:
1238
927k
            pblend_procs->blend_luminosity(n_chan, dst, backdrop, src);
1239
927k
            break;
1240
934k
        case BLEND_MODE_Color:
1241
934k
            pblend_procs->blend_luminosity(n_chan, dst, src, backdrop);
1242
934k
            break;
1243
856k
        case BLEND_MODE_Saturation:
1244
856k
            pblend_procs->blend_saturation(n_chan, dst, backdrop, src);
1245
856k
            break;
1246
934k
        case BLEND_MODE_Hue:
1247
934k
            {
1248
934k
                byte tmp[ART_MAX_CHAN];
1249
1250
934k
                pblend_procs->blend_luminosity(n_chan, tmp, src, backdrop);
1251
934k
                pblend_procs->blend_saturation(n_chan, dst, tmp, backdrop);
1252
934k
            }
1253
934k
            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
270k
        case BLEND_MODE_CompatibleOverprint:
1258
270k
            {
1259
270k
                gx_color_index drawn_comps = p14dev->op_state == GS_OP_STATE_FILL ?
1260
268k
                                             p14dev->drawn_comps_fill : p14dev->drawn_comps_stroke;
1261
270k
                bool opm = p14dev->op_state == GS_OP_STATE_FILL ?
1262
268k
                    p14dev->effective_overprint_mode : p14dev->stroke_effective_op_mode;
1263
270k
                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
270k
                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
270k
                } 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
1.35M
                    for (i = 0, comps = drawn_comps; i < n_chan; ++i, comps >>= 1) {
1338
1.08M
                        if ((comps & 0x1) != 0) {
1339
1.08M
                            dst[i] = src[i];
1340
1.08M
                        } else {
1341
51
                            dst[i] = backdrop[i];
1342
51
                        }
1343
1.08M
                    }
1344
270k
                }
1345
270k
                break;
1346
7.87k
            }
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
210M
    }
1353
210M
}
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
55.4M
{
1361
55.4M
    art_blend_pixel_8_inline(dst, backdrop, src, n_chan, blend_mode,
1362
55.4M
                             pblend_procs, p14dev);
1363
55.4M
}
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 == GS_OP_STATE_FILL ?
1518
0
                                             p14dev->drawn_comps_fill : p14dev->drawn_comps_stroke;
1519
0
                bool opm = p14dev->op_state == GS_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
1.91M
{
1592
1.91M
    byte a_b, a_s;
1593
1.91M
    unsigned int a_r;
1594
1.91M
    int tmp;
1595
1.91M
    int src_scale;
1596
1.91M
    int c_b, c_s;
1597
1.91M
    int i;
1598
1599
1.91M
    a_s = src[n_chan];
1600
1.91M
    a_b = backdrop[n_chan];
1601
1.91M
    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
121k
        if (tos_shape)
1605
121k
           return backdrop;
1606
0
        return NULL;
1607
121k
    }
1608
1609
    /* In this case a_s is not zero */
1610
1.79M
    if (a_b == 0) {
1611
        /* backdrop alpha is zero but not source alpha, just copy source pixels and
1612
           avoid computation. */
1613
1.13M
        return src;
1614
1.13M
    }
1615
1616
    /* Result alpha is Union of backdrop and source alpha */
1617
655k
    tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
1618
655k
    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
655k
    src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
1623
1624
655k
    if (blend_mode == BLEND_MODE_Normal) {
1625
        /* Do simple compositing of source over backdrop */
1626
2.48M
        for (i = 0; i < n_chan; i++) {
1627
1.86M
            c_s = src[i];
1628
1.86M
            c_b = backdrop[i];
1629
1.86M
            tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
1630
1.86M
            dst[i] = tmp >> 16;
1631
1.86M
        }
1632
620k
    } else {
1633
        /* Do compositing with blending */
1634
34.6k
        byte blend[ART_MAX_CHAN];
1635
1636
34.6k
        art_blend_pixel_8(blend, backdrop, src, n_chan, blend_mode, pblend_procs,
1637
34.6k
                        p14dev);
1638
173k
        for (i = 0; i < n_chan; i++) {
1639
138k
            int c_bl;   /* Result of blend function */
1640
138k
            int c_mix;    /* Blend result mixed with source color */
1641
1642
138k
            c_s = src[i];
1643
138k
            c_b = backdrop[i];
1644
138k
            c_bl = blend[i];
1645
138k
            tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
1646
138k
            c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
1647
138k
            tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
1648
138k
            dst[i] = tmp >> 16;
1649
138k
        }
1650
34.6k
    }
1651
655k
    dst[n_chan] = a_r;
1652
655k
    return dst;
1653
1.79M
}
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
10.1M
{
1732
10.1M
    byte a_b, a_s;
1733
10.1M
    unsigned int a_r;
1734
10.1M
    int tmp;
1735
10.1M
    int src_scale;
1736
10.1M
    int c_b, c_s;
1737
10.1M
    int i;
1738
1739
10.1M
    a_s = src[n_chan];
1740
10.1M
    if (a_s == 0) {
1741
        /* source alpha is zero, avoid all computations and possible
1742
           divide by zero errors. */
1743
10.1M
        return;
1744
10.1M
    }
1745
1746
8.00k
    a_b = dst[n_chan];
1747
8.00k
    if (a_b == 0) {
1748
        /* backdrop alpha is zero, just copy source pixels and avoid
1749
           computation. */
1750
1751
130
        memcpy (dst, src, n_chan + 1);
1752
1753
130
        return;
1754
130
    }
1755
1756
    /* Result alpha is Union of backdrop and source alpha */
1757
7.87k
    tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
1758
7.87k
    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
7.87k
    src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
1763
1764
7.87k
    if (first_spot != 0) {
1765
        /* Do compositing with blending */
1766
7.87k
        byte blend[ART_MAX_CHAN];
1767
1768
7.87k
        art_blend_pixel_8(blend, dst, src, first_spot, blend_mode, pblend_procs, p14dev);
1769
31.4k
        for (i = 0; i < first_spot; i++) {
1770
23.6k
            int c_bl;   /* Result of blend function */
1771
23.6k
            int c_mix;    /* Blend result mixed with source color */
1772
1773
23.6k
            c_s = src[i];
1774
23.6k
            c_b = dst[i];
1775
23.6k
            c_bl = blend[i];
1776
23.6k
            tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
1777
23.6k
            c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
1778
23.6k
            tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
1779
23.6k
            dst[i] = tmp >> 16;
1780
23.6k
        }
1781
7.87k
    }
1782
7.87k
    dst[n_chan] = a_r;
1783
1784
7.87k
    dst += first_spot;
1785
7.87k
    src += first_spot;
1786
7.87k
    n_chan -= first_spot;
1787
7.87k
    if (n_chan == 0)
1788
7.87k
        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
767M
{
1878
767M
    byte a_b, a_s;
1879
767M
    unsigned int a_r;
1880
767M
    int tmp;
1881
767M
    int src_scale;
1882
767M
    int c_b, c_s;
1883
767M
    int i;
1884
1885
767M
    a_s = src[n_chan];
1886
767M
    if (a_s == 0) {
1887
        /* source alpha is zero, avoid all computations and possible
1888
           divide by zero errors. */
1889
182M
        return NULL; /* No change to destination at all! */
1890
182M
    }
1891
1892
584M
    a_b = dst[n_chan];
1893
584M
    if (a_b == 0) {
1894
        /* backdrop alpha is zero, just copy source pixels and avoid
1895
           computation. */
1896
395M
        return src;
1897
395M
    }
1898
1899
    /* Result alpha is Union of backdrop and source alpha */
1900
189M
    tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
1901
189M
    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
189M
    src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
1906
1907
189M
    if (first_spot != 0) {
1908
        /* Do compositing with blending */
1909
154M
        byte blend[ART_MAX_CHAN];
1910
1911
154M
        art_blend_pixel_8_inline(blend, dst, src, first_spot, blend_mode, pblend_procs, p14dev);
1912
1913
154M
        if (blend_mode == BLEND_MODE_CompatibleOverprint) {
1914
1.35M
            for (i = 0; i < first_spot; i++) {
1915
                /* No mixing.  Blend[i] is backdrop or src */
1916
1.08M
                tmp = (dst[i] << 16) + src_scale * (blend[i] - dst[i]) + 0x8000;
1917
1.08M
                dst[i] = tmp >> 16;
1918
1.08M
            }
1919
154M
        } else {
1920
552M
            for (i = 0; i < first_spot; i++) {
1921
398M
                int c_bl;   /* Result of blend function */
1922
398M
                int c_mix;    /* Blend result mixed with source color */
1923
1924
398M
                c_s = src[i];
1925
398M
                c_b = dst[i];
1926
398M
                c_bl = blend[i];
1927
398M
                tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
1928
398M
                c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
1929
398M
                tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
1930
398M
                dst[i] = tmp >> 16;
1931
398M
            }
1932
154M
        }
1933
154M
    }
1934
189M
    dst[n_chan] = a_r;
1935
1936
189M
    n_chan -= first_spot;
1937
189M
    if (n_chan == 0)
1938
154M
        return dst;
1939
34.7M
    dst += first_spot;
1940
34.7M
    src += first_spot;
1941
1942
    /* Do simple compositing of source over backdrop */
1943
137M
    for (i = 0; i < n_chan; i++) {
1944
103M
        c_s = src[i];
1945
103M
        c_b = dst[i];
1946
103M
        tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
1947
103M
        dst[i] = tmp >> 16;
1948
103M
    }
1949
34.7M
    return dst - first_spot;
1950
189M
}
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
                                          intptr_t stride, pdf14_device *p14dev)
2045
48.6M
{
2046
48.6M
    byte a_b, a_s;
2047
48.6M
    unsigned int a_r;
2048
48.6M
    int tmp;
2049
48.6M
    int src_scale;
2050
48.6M
    int c_b, c_s;
2051
48.6M
    byte blend[ART_MAX_CHAN];
2052
2053
48.6M
    a_s = src[1];
2054
2055
48.6M
    a_b = dst[stride];
2056
2057
    /* Result alpha is Union of backdrop and source alpha */
2058
48.6M
    tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
2059
48.6M
    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
48.6M
    src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
2064
2065
    /* Do compositing with blending */
2066
48.6M
    art_blend_pixel_8(blend, dst, src, 1, blend_mode, pblend_procs, p14dev);
2067
48.6M
    {
2068
48.6M
        int c_bl;   /* Result of blend function */
2069
48.6M
        int c_mix;    /* Blend result mixed with source color */
2070
2071
48.6M
        c_s = src[0];
2072
48.6M
        c_b = dst[0];
2073
48.6M
        c_bl = blend[0];
2074
48.6M
        tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
2075
48.6M
        c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
2076
48.6M
        tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
2077
48.6M
        dst[0] = tmp >> 16;
2078
48.6M
    }
2079
48.6M
    dst[stride] = a_r;
2080
48.6M
}
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
                                           intptr_t 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
876M
{
2152
876M
    byte dst_alpha;
2153
876M
    int i;
2154
876M
    int tmp;
2155
876M
    int scale;
2156
876M
    byte *gs_restrict dst = *dstp;
2157
2158
876M
    if (src_alpha_g == 0)
2159
108M
        return 0;
2160
2161
768M
    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
356M
        if (dst_alpha_g != NULL) {
2168
13.2M
            tmp = (255 - *dst_alpha_g) * (255 - src_alpha_g) + 0x80;
2169
13.2M
            *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
2170
13.2M
        }
2171
356M
        *dstp = src;
2172
356M
        return 0;
2173
411M
    } else {
2174
        /* "interesting" blend mode */
2175
411M
        dst_alpha = dst[n_chan];
2176
411M
        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
663k
            scale = (dst_alpha * 255 * 2 + src_alpha_g) / (src_alpha_g << 1) -
2180
663k
                dst_alpha;
2181
3.13M
            for (i = 0; i < n_chan; i++) {
2182
2.47M
                int si, di;
2183
2184
2.47M
                si = src[i];
2185
2.47M
                di = dst[i];
2186
2.47M
                tmp = (si - di) * scale + 0x80;
2187
2.47M
                tmp = si + ((tmp + (tmp >> 8)) >> 8);
2188
2189
                /* todo: it should be possible to optimize these cond branches */
2190
2.47M
                if (tmp < 0)
2191
1.40k
                    tmp = 0;
2192
2.47M
                if (tmp > 255)
2193
298k
                    tmp = 255;
2194
2.47M
                src[i] = tmp;
2195
2.47M
            }
2196
663k
        }
2197
2198
411M
        tmp = src_alpha_g * alpha + 0x80;
2199
411M
        tmp = (tmp + (tmp >> 8)) >> 8;
2200
411M
        src[n_chan] = tmp;
2201
411M
        if (dst_alpha_g != NULL) {
2202
5.13M
            tmp = (255 - *dst_alpha_g) * (255 - tmp) + 0x80;
2203
5.13M
            *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
2204
5.13M
        }
2205
411M
    }
2206
411M
    return 1;
2207
    /* todo: optimize BLEND_MODE_Normal buf alpha != 255 case */
2208
768M
}
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
1.56M
{
2216
1.56M
    byte* gs_restrict dst = *dstp;
2217
2218
1.56M
    if (tos_shape == 0 || src_alpha_g == 0) {
2219
        /* If a softmask was present pass it along Bug 693548 */
2220
51.5k
        if (has_mask)
2221
0
            dst[n_chan] = alpha;
2222
51.5k
        return 0;
2223
51.5k
    }
2224
2225
1.50M
    return art_pdf_recomposite_group_8(dstp, dst_alpha_g, src, src_alpha_g,
2226
1.50M
                                       n_chan, alpha, blend_mode);
2227
1.56M
}
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
341M
{
2343
341M
    byte src_alpha = src[n_chan];   /* $\alpha g_n$ */
2344
2345
341M
    if (src_alpha == 0)
2346
47.5M
        return 0;
2347
2348
294M
    if (alpha != 255) {
2349
152M
        int tmp = src_alpha * alpha + 0x80;
2350
152M
        src[n_chan] = (tmp + (tmp >> 8)) >> 8;
2351
152M
    }
2352
2353
294M
    if (dst_alpha_g != NULL) {
2354
19.9M
        int tmp = (255 - *dst_alpha_g) * (255 - src[n_chan]) + 0x80;
2355
19.9M
        *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
2356
19.9M
    }
2357
2358
294M
    return 1;
2359
341M
}
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
1.41M
{
2367
1.41M
    byte src_alpha;   /* $\alpha g_n$ */
2368
1.41M
    int tmp;
2369
2370
1.41M
    if (tos_shape == 0 || (src_alpha_g != NULL && *src_alpha_g == 0)) {
2371
        /* If a softmask was present pass it along Bug 693548 */
2372
7.60k
        if (has_mask)
2373
0
            dst[n_chan] = alpha;
2374
7.60k
        return 0;
2375
7.60k
    }
2376
2377
1.40M
    if (alpha != 255) {
2378
37.4k
        if (tos_shape != 255)
2379
0
            return 0;
2380
37.4k
        src_alpha = src[n_chan];
2381
37.4k
        if (src_alpha == 0)
2382
0
            return 0;
2383
37.4k
        tmp = src_alpha * alpha + 0x80;
2384
37.4k
        src[n_chan] = (tmp + (tmp >> 8)) >> 8;
2385
37.4k
    }
2386
2387
1.40M
    if (dst_alpha_g != NULL) {
2388
620k
        tmp = (255 - *dst_alpha_g) * (255 - src[n_chan]) + 0x80;
2389
620k
        *dst_alpha_g = 255 - ((tmp + (tmp >> 8)) >> 8);
2390
620k
    }
2391
1.40M
    return 1;
2392
1.40M
}
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
5.08M
{
2458
5.08M
    byte src_alpha;
2459
2460
5.08M
    src_alpha = src[n_chan];
2461
5.08M
    if (src_alpha == 0)
2462
0
        return;
2463
2464
5.08M
    memcpy (dst, src, n_chan + 1);
2465
5.08M
}
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
105M
{
2528
105M
    byte src_shape = src[n_chan];
2529
105M
    int i, tmp;
2530
2531
105M
    if (blend_mode == BLEND_MODE_Normal) {
2532
        /* Do simple compositing of source over backdrop */
2533
98.8M
        if (src_shape == 0)
2534
2.66M
            return;
2535
96.1M
        else if (src_shape == 255) {
2536
46.4M
            memcpy (dst, src, n_chan + 1);
2537
46.4M
            return;
2538
49.7M
        } else {
2539
            /* Use src_shape to interpolate (in premultiplied alpha space)
2540
               between dst and (src, opacity). */
2541
49.7M
            int dst_alpha = dst[n_chan];
2542
49.7M
            byte result_alpha;
2543
2544
49.7M
            tmp = (255 - dst_alpha) * src_shape + 0x80;
2545
49.7M
            result_alpha = dst_alpha + ((tmp + (tmp >> 8)) >> 8);
2546
2547
49.7M
            if (result_alpha != 0)
2548
180M
                for (i = 0; i < n_chan; i++) {
2549
                    /* todo: optimize this - can strength-reduce so that
2550
                       inner loop is a single interpolation */
2551
131M
                    tmp = dst[i] * dst_alpha * (255 - src_shape) +
2552
131M
                        ((int)src[i]) * 255 * src_shape + (result_alpha << 7);
2553
131M
                    tmp = tmp / (result_alpha * 255);
2554
131M
                    if (tmp > 255) tmp = 255;
2555
131M
                    dst[i] = tmp;
2556
131M
                }
2557
49.7M
            dst[n_chan] = result_alpha;
2558
49.7M
        }
2559
98.8M
    } else {
2560
        /* Do compositing with blending */
2561
6.78M
        byte blend[ART_MAX_CHAN];
2562
6.78M
        byte a_b, a_s;
2563
6.78M
        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
6.78M
        volatile const unsigned int vzero = 0;
2570
6.78M
        int src_scale;
2571
6.78M
        int c_b, c_s;
2572
2573
6.78M
        a_s = src[n_chan];
2574
6.78M
        a_b = dst[n_chan];
2575
2576
        /* Result alpha is Union of backdrop and source alpha */
2577
6.78M
        tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
2578
6.78M
        a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
2579
2580
6.78M
        if (a_r != vzero) {
2581
            /* Compute a_s / a_r in 16.16 format */
2582
6.78M
            src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
2583
2584
6.78M
            art_blend_pixel_8(blend, dst, src, n_chan, blend_mode, pblend_procs, p14dev);
2585
22.0M
            for (i = 0; i < n_chan; i++) {
2586
15.2M
                int c_bl;   /* Result of blend function */
2587
15.2M
                int c_mix;    /* Blend result mixed with source color */
2588
2589
15.2M
                c_s = src[i];
2590
15.2M
                c_b = dst[i];
2591
15.2M
                c_bl = blend[i];
2592
15.2M
                tmp = a_b * (c_bl - ((int)c_s)) + 0x80;
2593
15.2M
                c_mix = c_s + (((tmp >> 8) + tmp) >> 8);
2594
15.2M
                tmp = (c_b << 16) + src_scale * (c_mix - c_b) + 0x8000;
2595
15.2M
                dst[i] = tmp >> 16;
2596
15.2M
            }
2597
6.78M
        }
2598
6.78M
        dst[n_chan] = a_r;
2599
6.78M
    }
2600
105M
}
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
                   intptr_t plane_stride, intptr_t rowstride,
2699
                   char filename[], const byte *Buffer, bool deep, bool be)
2700
{
2701
    char full_file_name[50];
2702
    gp_file *fid;
2703
    int x, y, z;
2704
    const byte *buff_ptr;
2705
2706
   /* clist_band_count is incremented at every pdf14putimage */
2707
   /* Useful for catching this thing and only dumping */
2708
   /* during a particular band if we have a large file */
2709
   /* if (clist_band_count != 65) return; */
2710
    buff_ptr = Buffer;
2711
    dlprintf2("%02d)%s.pam\n",global_index,filename);dflush();
2712
    gs_snprintf(full_file_name,sizeof(full_file_name),"%02d)%s.pam",global_index,filename);
2713
    fid = gp_fopen(mem,full_file_name,"wb");
2714
    if (fid == NULL) {
2715
        dlprintf("FAILED\n");dflush();
2716
        return;
2717
    }
2718
    gp_fprintf(fid, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n",
2719
               width, num_rows, n_chan, deep ? 65535 : 255,
2720
               n_chan == 1 ? "GRAYSCALE" :
2721
               n_chan == 2 ? "GRAYSCALE_ALPHA" :
2722
               n_chan == 3 ? "RGB" :
2723
               n_chan == 4 ? "CMYK" :
2724
               n_chan == 5 ? "CMYK_ALPHA" :
2725
                             "CMYK_SPOTS"
2726
    );
2727
    if (deep) {
2728
        for(y=0; y<num_rows; y++)
2729
            for(x=0; x<width; x++)
2730
                for(z=0; z<n_chan; z++) {
2731
                    gp_fputc(Buffer[z*plane_stride + y*rowstride + x*2 + be^1], fid);
2732
                    gp_fputc(Buffer[z*plane_stride + y*rowstride + x*2 + be  ], fid);
2733
                }
2734
    } else {
2735
        for(y=0; y<num_rows; y++)
2736
            for(x=0; x<width; x++)
2737
                for(z=0; z<n_chan; z++)
2738
                    gp_fputc(Buffer[z*plane_stride + y*rowstride + x], fid);
2739
    }
2740
    gp_fclose(fid);
2741
}
2742
2743
void
2744
dump_raw_buffer(const gs_memory_t *mem, int num_rows, int width, int n_chan,
2745
                intptr_t plane_stride, intptr_t rowstride,
2746
                char filename[],const byte *Buffer, bool deep)
2747
{
2748
    do_dump_raw_buffer(mem, num_rows, width, n_chan, plane_stride,
2749
                       rowstride, filename, Buffer, deep, 0);
2750
}
2751
2752
void
2753
dump_raw_buffer_be(const gs_memory_t *mem, int num_rows, int width, int n_chan,
2754
                   intptr_t plane_stride, intptr_t rowstride,
2755
                   char filename[],const byte *Buffer, bool deep)
2756
{
2757
    do_dump_raw_buffer(mem, num_rows, width, n_chan, plane_stride,
2758
                       rowstride, filename, Buffer, deep, 1);
2759
}
2760
#endif
2761
2762
typedef void (*art_pdf_compose_group_fn)(byte *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
2763
                                         byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
2764
                                         intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag,
2765
                                         byte *tos_alpha_g_ptr, byte *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride,
2766
                                         byte *nos_alpha_g_ptr, bool nos_knockout, intptr_t nos_shape_offset, intptr_t nos_tag_offset,
2767
                                         byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
2768
                                         byte *backdrop_ptr, bool has_matte, int n_chan, bool additive, int num_spots, bool overprint,
2769
                                         gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
2770
                                         const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev);
2771
2772
static forceinline void
2773
template_compose_group(byte *gs_restrict tos_ptr, bool tos_isolated,
2774
                       intptr_t tos_planestride, intptr_t tos_rowstride,
2775
                       byte alpha, byte shape, gs_blend_mode_t blend_mode,
2776
                       bool tos_has_shape, intptr_t tos_shape_offset,
2777
                       intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset,
2778
                       bool tos_has_tag, byte *gs_restrict tos_alpha_g_ptr,
2779
                       byte *gs_restrict nos_ptr,
2780
                       bool nos_isolated, intptr_t nos_planestride,
2781
                       intptr_t nos_rowstride, byte *gs_restrict nos_alpha_g_ptr,
2782
                       bool nos_knockout, int nos_shape_offset,
2783
                       intptr_t nos_tag_offset, byte *gs_restrict mask_row_ptr,
2784
                       int has_mask, pdf14_buf *gs_restrict maskbuf,
2785
                       byte mask_bg_alpha, const byte *gs_restrict mask_tr_fn,
2786
                       byte *gs_restrict backdrop_ptr, bool has_matte,
2787
                       int n_chan, bool additive, int num_spots,
2788
                       bool overprint, gx_color_index drawn_comps,
2789
                       int x0, int y0, int x1, int y1,
2790
                       const pdf14_nonseparable_blending_procs_t *pblend_procs,
2791
                       pdf14_device *pdev, int has_alpha)
2792
265k
{
2793
265k
    byte *gs_restrict mask_curr_ptr = NULL;
2794
265k
    int width = x1 - x0;
2795
265k
    int x, y;
2796
265k
    int i;
2797
265k
    byte tos_pixel[PDF14_MAX_PLANES];
2798
265k
    byte nos_pixel[PDF14_MAX_PLANES];
2799
265k
    byte back_drop[PDF14_MAX_PLANES];
2800
265k
    bool in_mask_rect_y;
2801
265k
    bool in_mask_rect;
2802
265k
    byte pix_alpha;
2803
265k
    byte matte_alpha = 0xff;
2804
265k
    int first_spot = n_chan - num_spots;
2805
265k
    int first_blend_spot = n_chan;
2806
265k
    bool has_mask2 = has_mask;
2807
265k
    byte *gs_restrict dst;
2808
265k
    byte group_shape = (byte)(255 * pdev->shape + 0.5);
2809
2810
265k
    if (!nos_knockout && num_spots > 0 && !blend_valid_for_spot(blend_mode)) {
2811
0
        first_blend_spot = first_spot;
2812
0
    }
2813
265k
    if (blend_mode == BLEND_MODE_Normal)
2814
194k
        first_blend_spot = 0;
2815
265k
    if (!nos_isolated && backdrop_ptr != NULL)
2816
284
        has_mask2 = false;
2817
2818
2.99M
    for (y = y1 - y0; y > 0; --y) {
2819
2.72M
        mask_curr_ptr = mask_row_ptr;
2820
2.72M
        in_mask_rect_y = (has_mask && y1 - y >= maskbuf->rect.p.y && y1 - y < maskbuf->rect.q.y);
2821
1.22G
        for (x = 0; x < width; x++) {
2822
1.22G
            in_mask_rect = (in_mask_rect_y && x0 + x >= maskbuf->rect.p.x && x0 + x < maskbuf->rect.q.x);
2823
1.22G
            pix_alpha = alpha;
2824
            /* If we have a soft mask, then we have some special handling of the
2825
               group alpha value */
2826
1.22G
            if (maskbuf != NULL) {
2827
393M
                if (!in_mask_rect) {
2828
                    /* Special case where we have a soft mask but are outside
2829
                       the range of the soft mask and must use the background
2830
                       alpha value */
2831
91.5M
                    pix_alpha = mask_bg_alpha;
2832
91.5M
                    matte_alpha = 0xff;
2833
302M
                } else {
2834
302M
                    if (has_matte)
2835
27.5M
                        matte_alpha = mask_tr_fn[*mask_curr_ptr];
2836
302M
                }
2837
393M
            }
2838
2839
            /* Matte present, need to undo premultiplied alpha prior to blend */
2840
1.22G
            if (has_matte && matte_alpha != 0 && matte_alpha < 0xff) {
2841
9.78M
                for (i = 0; i < n_chan; i++) {
2842
                    /* undo */
2843
7.34M
                    byte matte = i >= maskbuf->matte_num_comps ? 0 : maskbuf->matte[i]>>8;
2844
7.34M
                    int val = tos_ptr[i * tos_planestride] - matte;
2845
7.34M
                    int temp = ((((val * 0xff) << 8) / matte_alpha) >> 8) + matte;
2846
2847
                    /* clip */
2848
7.34M
                    if (temp > 0xff)
2849
3.51M
                        tos_pixel[i] = 0xff;
2850
3.82M
                    else if (temp < 0)
2851
0
                        tos_pixel[i] = 0;
2852
3.82M
                    else
2853
3.82M
                        tos_pixel[i] = temp;
2854
2855
7.34M
                    if (!additive) {
2856
                        /* Pure subtractive */
2857
0
                        tos_pixel[i] = 255 - tos_pixel[i];
2858
0
                        nos_pixel[i] = 255 - nos_ptr[i * nos_planestride];
2859
7.34M
                    } else {
2860
                        /* additive or hybrid */
2861
7.34M
                        if (i >= first_spot)
2862
0
                            nos_pixel[i] = 255 - nos_ptr[i * nos_planestride];
2863
7.34M
                        else
2864
7.34M
                            nos_pixel[i] = nos_ptr[i * nos_planestride];
2865
7.34M
                    }
2866
7.34M
                }
2867
1.21G
            } else {
2868
                /* No matte present */
2869
1.21G
                if (!additive) {
2870
                    /* Pure subtractive */
2871
196M
                    for (i = 0; i < n_chan; ++i) {
2872
156M
                        tos_pixel[i] = 255 - tos_ptr[i * tos_planestride];
2873
156M
                        nos_pixel[i] = 255 - nos_ptr[i * nos_planestride];
2874
156M
                    }
2875
1.17G
                } else {
2876
                    /* Additive or hybrid */
2877
4.10G
                    for (i = 0; i < first_spot; ++i) {
2878
2.92G
                        tos_pixel[i] = tos_ptr[i * tos_planestride];
2879
2.92G
                        nos_pixel[i] = nos_ptr[i * nos_planestride];
2880
2.92G
                    }
2881
1.17G
                    for (; i < n_chan; i++) {
2882
0
                        tos_pixel[i] = 255 - tos_ptr[i * tos_planestride];
2883
0
                        nos_pixel[i] = 255 - nos_ptr[i * nos_planestride];
2884
0
                    }
2885
1.17G
                }
2886
1.21G
            }
2887
            /* alpha */
2888
1.22G
            tos_pixel[n_chan] = has_alpha ? tos_ptr[n_chan * tos_planestride] : 255;
2889
1.22G
            nos_pixel[n_chan] = has_alpha ? nos_ptr[n_chan * nos_planestride] : 255;
2890
2891
1.22G
            if (mask_curr_ptr != NULL) {
2892
305M
                if (in_mask_rect) {
2893
302M
                    byte mask = mask_tr_fn[*mask_curr_ptr++];
2894
302M
                    int tmp = pix_alpha * mask + 0x80;
2895
302M
                    pix_alpha = (tmp + (tmp >> 8)) >> 8;
2896
302M
                } else {
2897
2.98M
                    mask_curr_ptr++;
2898
2.98M
                }
2899
305M
            }
2900
2901
1.22G
            dst = nos_pixel;
2902
1.22G
            if (nos_knockout) {
2903
                /* We need to be knocking out what ever is on the nos, but may
2904
                   need to combine with its backdrop */
2905
2.97M
                byte tos_shape = 255;
2906
2907
2.97M
                if (tos_has_shape)
2908
2.97M
                    tos_shape = tos_ptr[tos_shape_offset];
2909
2910
2.97M
                if (nos_isolated || backdrop_ptr == NULL) {
2911
                    /* We do not need to compose with the backdrop */
2912
1.63M
                    back_drop[n_chan] = 0;
2913
                    /* FIXME: The blend here can be simplified */
2914
1.63M
                } else {
2915
                    /* Per the PDF spec, since the tos is not isolated and we are
2916
                       going onto a knock out group, we do the composition with
2917
                       the nos initial backdrop. */
2918
1.34M
                    if (additive) {
2919
                        /* additive or hybrid */
2920
3.81M
                        for (i = 0; i < first_spot; ++i) {
2921
2.86M
                            back_drop[i] = backdrop_ptr[i * nos_planestride];
2922
2.86M
                        }
2923
953k
                        for (; i < n_chan; i++) {
2924
0
                            back_drop[i] = 255 - backdrop_ptr[i * nos_planestride];
2925
0
                        }
2926
953k
                    } else {
2927
                        /* pure subtractive */
2928
1.93M
                        for (i = 0; i < n_chan; ++i) {
2929
1.54M
                            back_drop[i] = 255 - backdrop_ptr[i * nos_planestride];
2930
1.54M
                        }
2931
386k
                    }
2932
                    /* alpha */
2933
1.34M
                    back_drop[n_chan] = backdrop_ptr[n_chan * nos_planestride];
2934
1.34M
                }
2935
2.97M
                if (tos_isolated ?
2936
1.41M
                    art_pdf_ko_composite_group_8(tos_shape, tos_alpha_g_ptr,
2937
1.41M
                                                 nos_pixel, nos_alpha_g_ptr,
2938
1.41M
                                                 tos_pixel, n_chan, pix_alpha,
2939
1.41M
                                                 has_mask2) :
2940
2.97M
                    art_pdf_ko_recomposite_group_8(tos_shape, has_alpha ? tos_ptr[tos_alpha_g_offset] : 255,
2941
1.56M
                                                   &dst, nos_alpha_g_ptr, tos_pixel, n_chan, pix_alpha,
2942
1.56M
                                                   blend_mode, has_mask2))
2943
1.91M
                    dst = art_pdf_knockout_composite_pixel_alpha_8(back_drop, tos_shape,
2944
1.91M
                                                                   nos_pixel, tos_pixel,
2945
1.91M
                                                                   n_chan, blend_mode,
2946
1.91M
                                                                   pblend_procs, pdev);
2947
1.21G
            } else if (tos_isolated ?
2948
341M
                       art_pdf_composite_group_8(nos_pixel, nos_alpha_g_ptr,
2949
341M
                                                 tos_pixel, n_chan, pix_alpha) :
2950
1.21G
                       art_pdf_recomposite_group_8(&dst, nos_alpha_g_ptr,
2951
875M
                           tos_pixel, has_alpha ? tos_ptr[tos_alpha_g_offset] : 255, n_chan,
2952
875M
                                                   pix_alpha, blend_mode)) {
2953
705M
                dst = art_pdf_composite_pixel_alpha_8_inline(nos_pixel, tos_pixel, n_chan,
2954
705M
                                                blend_mode, first_blend_spot,
2955
705M
                                                pblend_procs, pdev);
2956
705M
            }
2957
1.22G
            if (nos_shape_offset && pix_alpha != 0) {
2958
792
                nos_ptr[nos_shape_offset] =
2959
792
                    art_pdf_union_mul_8(nos_ptr[nos_shape_offset],
2960
792
                                        has_alpha ? tos_ptr[tos_shape_offset] : group_shape,
2961
792
                                        shape);
2962
792
            }
2963
1.22G
            if (dst && dst[n_chan] != 0)
2964
900M
            {
2965
                /* Complement the results for subtractive color spaces.  Again,
2966
                 * if we are in an additive blending color space, we are not
2967
                 * going to be fooling with overprint of spot colors */
2968
900M
                if (additive) {
2969
                    /* additive or hybrid */
2970
2.97G
                    for (i = 0; i < first_spot; ++i) {
2971
2.10G
                        nos_ptr[i * nos_planestride] = dst[i];
2972
2.10G
                    }
2973
870M
                    for (; i < n_chan; i++) {
2974
0
                        nos_ptr[i * nos_planestride] = 255 - dst[i];
2975
0
                    }
2976
870M
                } else {
2977
                    /* Pure subtractive */
2978
151M
                    for (i = 0; i < n_chan; ++i)
2979
121M
                        nos_ptr[i * nos_planestride] = 255 - dst[i];
2980
30.3M
                }
2981
                /* alpha */
2982
900M
                nos_ptr[n_chan * nos_planestride] = dst[n_chan];
2983
900M
            }
2984
            /* tags */
2985
1.22G
            if (nos_tag_offset && tos_has_tag) {
2986
0
                nos_ptr[nos_tag_offset] |= tos_ptr[tos_tag_offset];
2987
0
             }
2988
2989
1.22G
            if (nos_alpha_g_ptr != NULL)
2990
43.8M
                ++nos_alpha_g_ptr;
2991
1.22G
            if (tos_alpha_g_ptr != NULL)
2992
877M
                ++tos_alpha_g_ptr;
2993
1.22G
            if (backdrop_ptr != NULL)
2994
1.34M
                ++backdrop_ptr;
2995
1.22G
            ++tos_ptr;
2996
1.22G
            ++nos_ptr;
2997
1.22G
        }
2998
2.72M
        tos_ptr += tos_rowstride - width;
2999
2.72M
        nos_ptr += nos_rowstride - width;
3000
2.72M
        if (tos_alpha_g_ptr != NULL)
3001
1.91M
            tos_alpha_g_ptr += tos_rowstride - width;
3002
2.72M
        if (nos_alpha_g_ptr != NULL)
3003
69.3k
            nos_alpha_g_ptr += nos_rowstride - width;
3004
2.72M
        if (mask_row_ptr != NULL)
3005
645k
            mask_row_ptr += maskbuf->rowstride;
3006
2.72M
        if (backdrop_ptr != NULL)
3007
2.68k
            backdrop_ptr += nos_rowstride - width;
3008
2.72M
    }
3009
265k
}
3010
3011
static void
3012
compose_group_knockout(byte *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3013
              intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3014
              byte *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3015
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3016
              byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3017
              byte *backdrop_ptr,
3018
              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,
3019
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3020
483
{
3021
483
    template_compose_group(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, blend_mode, tos_has_shape,
3022
483
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3023
483
        nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */1,
3024
483
        nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3025
483
        backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1);
3026
483
}
3027
3028
static void
3029
compose_group_nonknockout_blend(byte *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3030
              intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3031
              byte *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3032
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3033
              byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3034
              byte *backdrop_ptr,
3035
              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,
3036
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3037
69.1k
{
3038
69.1k
    template_compose_group(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, blend_mode, tos_has_shape,
3039
69.1k
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3040
69.1k
        nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
3041
69.1k
        nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3042
69.1k
        backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1);
3043
69.1k
}
3044
3045
static void
3046
compose_group_nonknockout_nonblend_isolated_allmask_common(byte *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3047
              intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3048
              byte *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3049
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3050
              byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3051
              byte *backdrop_ptr,
3052
              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,
3053
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3054
53.8k
{
3055
53.8k
    int width = x1 - x0;
3056
53.8k
    int x, y;
3057
53.8k
    int i;
3058
3059
693k
    for (y = y1 - y0; y > 0; --y) {
3060
639k
        byte *gs_restrict mask_curr_ptr = mask_row_ptr;
3061
375M
        for (x = 0; x < width; x++) {
3062
374M
            byte mask = mask_tr_fn[*mask_curr_ptr++];
3063
374M
            byte src_alpha = tos_ptr[n_chan * tos_planestride];
3064
374M
            if (src_alpha != 0) {
3065
374M
                byte a_b;
3066
3067
374M
                int tmp = alpha * mask + 0x80;
3068
374M
                byte pix_alpha = (tmp + (tmp >> 8)) >> 8;
3069
3070
374M
                if (pix_alpha != 255) {
3071
366M
                    int tmp = src_alpha * pix_alpha + 0x80;
3072
366M
                    src_alpha = (tmp + (tmp >> 8)) >> 8;
3073
366M
                }
3074
3075
374M
                a_b = nos_ptr[n_chan * nos_planestride];
3076
374M
                if (a_b == 0) {
3077
                    /* Simple copy of colors plus alpha. */
3078
560M
                    for (i = 0; i < n_chan; i++) {
3079
397M
                        nos_ptr[i * nos_planestride] = tos_ptr[i * tos_planestride];
3080
397M
                    }
3081
162M
                    nos_ptr[i * nos_planestride] = src_alpha;
3082
212M
                } else {
3083
                    /* Result alpha is Union of backdrop and source alpha */
3084
212M
                    int tmp = (0xff - a_b) * (0xff - src_alpha) + 0x80;
3085
212M
                    unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
3086
3087
                    /* Compute src_alpha / a_r in 16.16 format */
3088
212M
                    int src_scale = ((src_alpha << 16) + (a_r >> 1)) / a_r;
3089
3090
212M
                    nos_ptr[n_chan * nos_planestride] = a_r;
3091
3092
                    /* Do simple compositing of source over backdrop */
3093
742M
                    for (i = 0; i < n_chan; i++) {
3094
530M
                        int c_s = tos_ptr[i * tos_planestride];
3095
530M
                        int c_b = nos_ptr[i * nos_planestride];
3096
530M
                        tmp = src_scale * (c_s - c_b) + 0x8000;
3097
530M
                        nos_ptr[i * nos_planestride] = c_b + (tmp >> 16);
3098
530M
                    }
3099
212M
                }
3100
374M
            }
3101
374M
            ++tos_ptr;
3102
374M
            ++nos_ptr;
3103
374M
        }
3104
639k
        tos_ptr += tos_rowstride - width;
3105
639k
        nos_ptr += nos_rowstride - width;
3106
639k
        mask_row_ptr += maskbuf->rowstride;
3107
639k
    }
3108
53.8k
}
3109
3110
static void
3111
compose_group_nonknockout_nonblend_isolated_mask_common(byte *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3112
              intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3113
              byte *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3114
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3115
              byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3116
              byte *backdrop_ptr,
3117
              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,
3118
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3119
786
{
3120
786
    byte *gs_restrict mask_curr_ptr = NULL;
3121
786
    int width = x1 - x0;
3122
786
    int x, y;
3123
786
    int i;
3124
786
    bool in_mask_rect_y;
3125
786
    bool in_mask_rect;
3126
786
    byte pix_alpha, src_alpha;
3127
3128
9.37k
    for (y = y1 - y0; y > 0; --y) {
3129
8.58k
        mask_curr_ptr = mask_row_ptr;
3130
8.58k
        in_mask_rect_y = (has_mask && y1 - y >= maskbuf->rect.p.y && y1 - y < maskbuf->rect.q.y);
3131
5.69M
        for (x = 0; x < width; x++) {
3132
5.68M
            in_mask_rect = (in_mask_rect_y && has_mask && x0 + x >= maskbuf->rect.p.x && x0 + x < maskbuf->rect.q.x);
3133
5.68M
            pix_alpha = alpha;
3134
            /* If we have a soft mask, then we have some special handling of the
3135
               group alpha value */
3136
5.68M
            if (maskbuf != NULL) {
3137
5.68M
                if (!in_mask_rect) {
3138
                    /* Special case where we have a soft mask but are outside
3139
                       the range of the soft mask and must use the background
3140
                       alpha value */
3141
5.68M
                    pix_alpha = mask_bg_alpha;
3142
5.68M
                }
3143
5.68M
            }
3144
3145
5.68M
            if (mask_curr_ptr != NULL) {
3146
0
                if (in_mask_rect) {
3147
0
                    byte mask = mask_tr_fn[*mask_curr_ptr++];
3148
0
                    int tmp = pix_alpha * mask + 0x80;
3149
0
                    pix_alpha = (tmp + (tmp >> 8)) >> 8;
3150
0
                } else {
3151
0
                    mask_curr_ptr++;
3152
0
                }
3153
0
            }
3154
3155
5.68M
            src_alpha = tos_ptr[n_chan * tos_planestride];
3156
5.68M
            if (src_alpha != 0) {
3157
5.48M
                byte a_b;
3158
3159
5.48M
                if (pix_alpha != 255) {
3160
5.48M
                    int tmp = src_alpha * pix_alpha + 0x80;
3161
5.48M
                    src_alpha = (tmp + (tmp >> 8)) >> 8;
3162
5.48M
                }
3163
3164
5.48M
                a_b = nos_ptr[n_chan * nos_planestride];
3165
5.48M
                if (a_b == 0) {
3166
                    /* Simple copy of colors plus alpha. */
3167
14.4M
                    for (i = 0; i < n_chan; i++) {
3168
9.24M
                        nos_ptr[i * nos_planestride] = tos_ptr[i * tos_planestride];
3169
9.24M
                    }
3170
5.24M
                    nos_ptr[i * nos_planestride] = src_alpha;
3171
5.24M
                } else {
3172
                    /* Result alpha is Union of backdrop and source alpha */
3173
247k
                    int tmp = (0xff - a_b) * (0xff - src_alpha) + 0x80;
3174
247k
                    unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
3175
3176
                    /* Compute src_alpha / a_r in 16.16 format */
3177
247k
                    int src_scale = ((src_alpha << 16) + (a_r >> 1)) / a_r;
3178
3179
247k
                    nos_ptr[n_chan * nos_planestride] = a_r;
3180
3181
                    /* Do simple compositing of source over backdrop */
3182
710k
                    for (i = 0; i < n_chan; i++) {
3183
463k
                        int c_s = tos_ptr[i * tos_planestride];
3184
463k
                        int c_b = nos_ptr[i * nos_planestride];
3185
463k
                        tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
3186
463k
                        nos_ptr[i * nos_planestride] = tmp >> 16;
3187
463k
                    }
3188
247k
                }
3189
5.48M
            }
3190
5.68M
            ++tos_ptr;
3191
5.68M
            ++nos_ptr;
3192
5.68M
        }
3193
8.58k
        tos_ptr += tos_rowstride - width;
3194
8.58k
        nos_ptr += nos_rowstride - width;
3195
8.58k
        if (mask_row_ptr != NULL)
3196
0
            mask_row_ptr += maskbuf->rowstride;
3197
8.58k
    }
3198
786
}
3199
3200
static void
3201
compose_group_nonknockout_nonblend_isolated_nomask_common(byte *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3202
              intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3203
              byte *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3204
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3205
              byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3206
              byte *backdrop_ptr,
3207
              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,
3208
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3209
11.7k
{
3210
11.7k
    template_compose_group(tos_ptr, /*tos_isolated*/1, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
3211
11.7k
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/0,
3212
11.7k
        nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
3213
11.7k
        /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, /*has_mask*/0, /*maskbuf*/NULL, mask_bg_alpha, mask_tr_fn,
3214
11.7k
        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);
3215
11.7k
}
3216
3217
static void
3218
compose_group_nonknockout_nonblend_nonisolated_mask_common(byte *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3219
              intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3220
              byte *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3221
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3222
              byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3223
              byte *backdrop_ptr,
3224
              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,
3225
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3226
0
{
3227
0
    template_compose_group(tos_ptr, /*tos_isolated*/0, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
3228
0
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/0,
3229
0
        nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
3230
0
        /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3231
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);
3232
0
}
3233
3234
static void
3235
compose_group_nonknockout_nonblend_nonisolated_nomask_common(byte *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3236
              intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3237
              byte *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3238
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3239
              byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3240
              byte *backdrop_ptr,
3241
              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,
3242
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3243
0
{
3244
0
    template_compose_group(tos_ptr, /*tos_isolated*/0, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
3245
0
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/0,
3246
0
        nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
3247
0
        /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, /*has_mask*/0, /*maskbuf*/NULL, mask_bg_alpha, mask_tr_fn,
3248
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);
3249
0
}
3250
3251
static void
3252
compose_group_nonknockout_noblend_general(byte *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3253
              intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3254
              byte *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3255
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3256
              byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3257
              byte *backdrop_ptr,
3258
              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,
3259
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3260
181k
{
3261
181k
    template_compose_group(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, tos_has_shape,
3262
181k
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3263
181k
        nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
3264
181k
        nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3265
181k
        backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1);
3266
181k
}
3267
3268
static void
3269
compose_group_alphaless_knockout(byte *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3270
              intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3271
              byte *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3272
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3273
              byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3274
              byte *backdrop_ptr,
3275
              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,
3276
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3277
0
{
3278
0
    template_compose_group(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, blend_mode, tos_has_shape,
3279
0
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3280
0
        nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */1,
3281
0
        nos_shape_offset, nos_tag_offset, /* mask_row_ptr */ NULL, /* has_mask */ 0, /* maskbuf */ NULL, mask_bg_alpha, /* mask_tr_fn */ NULL,
3282
0
        backdrop_ptr, /* has_matte */ false , n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 0);
3283
0
}
3284
3285
static void
3286
compose_group_alphaless_nonknockout(byte *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride, byte alpha, byte shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3287
              intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, byte *tos_alpha_g_ptr,
3288
              byte *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, byte *nos_alpha_g_ptr, bool nos_knockout,
3289
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3290
              byte *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, byte mask_bg_alpha, const byte *mask_tr_fn,
3291
              byte *backdrop_ptr,
3292
              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,
3293
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3294
2.45k
{
3295
2.45k
    template_compose_group(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, blend_mode, tos_has_shape,
3296
2.45k
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3297
2.45k
        nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
3298
2.45k
        nos_shape_offset, nos_tag_offset, /* mask_row_ptr */ NULL, /* has_mask */ 0, /* maskbuf */ NULL, mask_bg_alpha, /* mask_tr_fn */ NULL,
3299
2.45k
        backdrop_ptr, /* has_matte */ false , n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 0);
3300
2.45k
}
3301
3302
static void
3303
do_compose_group(pdf14_buf *tos, pdf14_buf *nos, pdf14_buf *maskbuf,
3304
              int x0, int x1, int y0, int y1, int n_chan, bool additive,
3305
              const pdf14_nonseparable_blending_procs_t * pblend_procs,
3306
              bool has_matte, bool overprint, gx_color_index drawn_comps,
3307
              gs_memory_t *memory, gx_device *dev)
3308
317k
{
3309
317k
    int num_spots = tos->num_spots;
3310
317k
    byte alpha = tos->alpha>>8;
3311
317k
    byte shape = tos->shape>>8;
3312
317k
    gs_blend_mode_t blend_mode = tos->blend_mode;
3313
317k
    byte *tos_ptr = tos->data + x0 - tos->rect.p.x +
3314
317k
        (y0 - tos->rect.p.y) * tos->rowstride;
3315
317k
    byte *nos_ptr = nos->data + x0 - nos->rect.p.x +
3316
317k
        (y0 - nos->rect.p.y) * nos->rowstride;
3317
317k
    byte *mask_row_ptr = NULL;
3318
317k
    intptr_t tos_planestride = tos->planestride;
3319
317k
    intptr_t nos_planestride = nos->planestride;
3320
317k
    byte mask_bg_alpha = 0; /* Quiet compiler. */
3321
317k
    bool tos_isolated = tos->isolated;
3322
317k
    bool nos_isolated = nos->isolated;
3323
317k
    bool nos_knockout = nos->knockout;
3324
317k
    byte *nos_alpha_g_ptr;
3325
317k
    byte *tos_alpha_g_ptr;
3326
317k
    intptr_t tos_shape_offset = n_chan * tos_planestride;
3327
317k
    intptr_t tos_alpha_g_offset = tos_shape_offset + (tos->has_shape ? tos_planestride : 0);
3328
317k
    bool tos_has_tag = tos->has_tags;
3329
317k
    intptr_t tos_tag_offset = tos_planestride * (tos->n_planes - 1);
3330
317k
    intptr_t nos_shape_offset = n_chan * nos_planestride;
3331
317k
    intptr_t nos_alpha_g_offset = nos_shape_offset + (nos->has_shape ? nos_planestride : 0);
3332
317k
    intptr_t nos_tag_offset = nos_planestride * (nos->n_planes - 1);
3333
317k
    byte *mask_tr_fn = NULL; /* Quiet compiler. */
3334
317k
    bool is_ident = true;
3335
317k
    bool has_mask = false;
3336
317k
    byte *backdrop_ptr = NULL;
3337
317k
    pdf14_device *pdev = (pdf14_device *)dev;
3338
3339
3340
#if RAW_DUMP
3341
    byte *composed_ptr = NULL;
3342
    int width = x1 - x0;
3343
#endif
3344
317k
    art_pdf_compose_group_fn fn;
3345
3346
317k
    if ((tos->n_chan == 0) || (nos->n_chan == 0))
3347
0
        return;
3348
317k
    rect_merge(nos->dirty, tos->dirty);
3349
317k
    if (nos->has_tags)
3350
317k
        if_debug7m('v', memory,
3351
317k
                   "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, tag = %d, bm = %d\n",
3352
317k
                   y0, y1, x1 - x0, alpha, shape, dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS, blend_mode);
3353
317k
    else
3354
317k
        if_debug6m('v', memory,
3355
317k
                   "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, bm = %d\n",
3356
317k
                   y0, y1, x1 - x0, alpha, shape, blend_mode);
3357
317k
    if (!nos->has_shape)
3358
317k
        nos_shape_offset = 0;
3359
317k
    if (!nos->has_tags)
3360
317k
        nos_tag_offset = 0;
3361
317k
    if (nos->has_alpha_g) {
3362
4.81k
        nos_alpha_g_ptr = nos_ptr + nos_alpha_g_offset;
3363
4.81k
    } else
3364
312k
        nos_alpha_g_ptr = NULL;
3365
317k
    if (tos->has_alpha_g) {
3366
181k
        tos_alpha_g_ptr = tos_ptr + tos_alpha_g_offset;
3367
181k
    } else
3368
136k
        tos_alpha_g_ptr = NULL;
3369
317k
    if (nos->backdrop != NULL) {
3370
284
        backdrop_ptr = nos->backdrop + x0 - nos->rect.p.x +
3371
284
                       (y0 - nos->rect.p.y) * nos->rowstride;
3372
284
    }
3373
317k
    if (blend_mode != BLEND_MODE_Compatible && blend_mode != BLEND_MODE_Normal)
3374
69.1k
        overprint = false;
3375
3376
317k
    if (maskbuf != NULL) {
3377
130k
        int tmp;
3378
3379
130k
        mask_tr_fn = maskbuf->transfer_fn;
3380
3381
130k
        is_ident = maskbuf->is_ident;
3382
        /* Make sure we are in the mask buffer */
3383
130k
        if (maskbuf->data != NULL) {
3384
115k
            mask_row_ptr = maskbuf->data + x0 - maskbuf->rect.p.x +
3385
115k
                    (y0 - maskbuf->rect.p.y) * maskbuf->rowstride;
3386
115k
            has_mask = true;
3387
115k
        }
3388
        /* We may have a case, where we are outside the maskbuf rect. */
3389
        /* We would have avoided creating the maskbuf->data */
3390
        /* In that case, we should use the background alpha value */
3391
        /* See discussion on the BC entry in the PDF spec.   */
3392
130k
        mask_bg_alpha = maskbuf->alpha>>8;
3393
        /* Adjust alpha by the mask background alpha.   This is only used
3394
           if we are outside the soft mask rect during the filling operation */
3395
130k
        mask_bg_alpha = mask_tr_fn[mask_bg_alpha];
3396
130k
        tmp = alpha * mask_bg_alpha + 0x80;
3397
130k
        mask_bg_alpha = (tmp + (tmp >> 8)) >> 8;
3398
130k
    }
3399
317k
    n_chan--; /* Now the true number of colorants (i.e. not including alpha)*/
3400
#if RAW_DUMP
3401
    composed_ptr = nos_ptr;
3402
    dump_raw_buffer(memory, y1-y0, width, tos->n_planes, tos_planestride, tos->rowstride,
3403
                    "bImageTOS", tos_ptr, tos->deep);
3404
    dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
3405
                    "cImageNOS", nos_ptr, tos->deep);
3406
    if (maskbuf !=NULL && maskbuf->data != NULL) {
3407
        dump_raw_buffer(memory, maskbuf->rect.q.y - maskbuf->rect.p.y,
3408
                        maskbuf->rect.q.x - maskbuf->rect.p.x, maskbuf->n_planes,
3409
                        maskbuf->planestride, maskbuf->rowstride, "dMask",
3410
                        maskbuf->data, maskbuf->deep);
3411
    }
3412
#endif
3413
3414
    /* You might hope that has_mask iff maskbuf != NULL, but this is
3415
     * not the case. Certainly we can see cases where maskbuf != NULL
3416
     * and has_mask = 0. What's more, treating such cases as being
3417
     * has_mask = 0 causes diffs. */
3418
#ifdef TRACK_COMPOSE_GROUPS
3419
    {
3420
        int code = 0;
3421
3422
        code += !!nos_knockout;
3423
        code += (!!nos_isolated)<<1;
3424
        code += (!!tos_isolated)<<2;
3425
        code += (!!tos->has_shape)<<3;
3426
        code += (!!tos_has_tag)<<4;
3427
        code += (!!additive)<<5;
3428
        code += (!!overprint)<<6;
3429
        code += (!!has_mask || maskbuf != NULL)<<7;
3430
        code += (!!has_matte)<<8;
3431
        code += (backdrop_ptr != NULL)<<9;
3432
        code += (num_spots != 0)<<10;
3433
        code += blend_mode<<11;
3434
3435
        if (track_compose_groups == 0)
3436
        {
3437
            atexit(dump_track_compose_groups);
3438
            track_compose_groups = 1;
3439
        }
3440
        compose_groups[code]++;
3441
    }
3442
#endif
3443
3444
    /* We have tested the files on the cluster to see what percentage of
3445
     * files/devices hit the different options. */
3446
317k
    if (nos_knockout)
3447
483
        fn = &compose_group_knockout; /* Small %ages, nothing more than 1.1% */
3448
317k
    else if (blend_mode != 0)
3449
69.1k
        fn = &compose_group_nonknockout_blend; /* Small %ages, nothing more than 2% */
3450
247k
    else if (tos->has_shape == 0 && tos_has_tag == 0 && nos_isolated == 0 && nos_alpha_g_ptr == NULL &&
3451
101k
             nos_shape_offset == 0 && nos_tag_offset == 0 && backdrop_ptr == NULL && has_matte == 0 && num_spots == 0 &&
3452
99.1k
             overprint == 0 && tos_alpha_g_ptr == NULL) {
3453
             /* Additive vs Subtractive makes no difference in normal blend mode with no spots */
3454
66.3k
        if (tos_isolated) {
3455
66.3k
            if (has_mask && maskbuf) {/* 7% */
3456
                /* AirPrint test case hits this */
3457
53.8k
                if (maskbuf && maskbuf->rect.p.x <= x0 && maskbuf->rect.p.y <= y0 &&
3458
53.8k
                    maskbuf->rect.q.x >= x1 && maskbuf->rect.q.y >= y1) {
3459
                    /* AVX and SSE accelerations only valid if maskbuf transfer
3460
                       function is identity and we have no matte color replacement */
3461
53.8k
                    if (is_ident && !has_matte) {
3462
53.8k
                        fn = compose_group_nonknockout_nonblend_isolated_allmask_common;
3463
#ifdef WITH_CAL
3464
      fn = (art_pdf_compose_group_fn)cal_get_compose_group(
3465
           memory->gs_lib_ctx->core->cal_ctx,
3466
           (cal_composer_proc_t *)fn,
3467
           tos->n_chan-1);
3468
#endif
3469
53.8k
                    } else {
3470
0
                        fn = compose_group_nonknockout_nonblend_isolated_allmask_common;
3471
0
                    }
3472
53.8k
                } else
3473
0
                    fn = &compose_group_nonknockout_nonblend_isolated_mask_common;
3474
53.8k
            } else
3475
12.5k
                if (maskbuf) {
3476
                    /* Outside mask */
3477
786
                    fn = &compose_group_nonknockout_nonblend_isolated_mask_common;
3478
786
                } else
3479
11.7k
                    fn = &compose_group_nonknockout_nonblend_isolated_nomask_common;
3480
66.3k
        } else {
3481
0
            if (has_mask || maskbuf) /* 4% */
3482
0
                fn = &compose_group_nonknockout_nonblend_nonisolated_mask_common;
3483
0
            else /* 15% */
3484
0
                fn = &compose_group_nonknockout_nonblend_nonisolated_nomask_common;
3485
0
        }
3486
66.3k
    } else
3487
181k
        fn = compose_group_nonknockout_noblend_general;
3488
3489
317k
    fn(tos_ptr, tos_isolated, tos_planestride, tos->rowstride, alpha, shape,
3490
317k
        blend_mode, tos->has_shape, tos_shape_offset, tos_alpha_g_offset,
3491
317k
        tos_tag_offset, tos_has_tag, tos_alpha_g_ptr, nos_ptr, nos_isolated, nos_planestride,
3492
317k
        nos->rowstride, nos_alpha_g_ptr, nos_knockout, nos_shape_offset,
3493
317k
        nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha,
3494
317k
        mask_tr_fn, backdrop_ptr, has_matte, n_chan, additive, num_spots,
3495
317k
        overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev);
3496
3497
#if RAW_DUMP
3498
    dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
3499
                    "eComposed", composed_ptr, nos->deep);
3500
    global_index++;
3501
#endif
3502
317k
}
3503
3504
static inline uint16_t
3505
interp16(const uint16_t *table, uint16_t idx)
3506
0
{
3507
0
    byte     top = idx>>8;
3508
0
    uint16_t a   = table[top];
3509
0
    int      b   = table[top+1]-a;
3510
3511
0
    return a + ((0x80 + b*(idx & 0xff))>>8);
3512
0
}
3513
3514
typedef void (*art_pdf_compose_group16_fn)(uint16_t *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
3515
                                         uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape,
3516
                                         intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag,
3517
                                         uint16_t *tos_alpha_g_ptr,
3518
                                         uint16_t *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride,
3519
                                         uint16_t *nos_alpha_g_ptr, bool nos_knockout, intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3520
                                         uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn,
3521
                                         uint16_t *backdrop_ptr, bool has_matte, int n_chan, bool additive, int num_spots, bool overprint,
3522
                                         gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
3523
                                         const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev);
3524
3525
static forceinline void
3526
template_compose_group16(uint16_t *gs_restrict tos_ptr, bool tos_isolated,
3527
                         intptr_t tos_planestride, intptr_t tos_rowstride,
3528
                         uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode,
3529
                         bool tos_has_shape, intptr_t tos_shape_offset,
3530
                         intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset,
3531
                         bool tos_has_tag,  uint16_t *gs_restrict tos_alpha_g_ptr,
3532
                         uint16_t *gs_restrict nos_ptr,
3533
                         bool nos_isolated, intptr_t nos_planestride,
3534
                         intptr_t nos_rowstride, uint16_t *gs_restrict nos_alpha_g_ptr,
3535
                         bool nos_knockout, intptr_t nos_shape_offset,
3536
                         intptr_t nos_tag_offset, uint16_t *gs_restrict mask_row_ptr,
3537
                         int has_mask, pdf14_buf *gs_restrict maskbuf,
3538
                         uint16_t mask_bg_alpha, const uint16_t *gs_restrict mask_tr_fn,
3539
                         uint16_t *gs_restrict backdrop_ptr, bool has_matte,
3540
                         int n_chan, bool additive, int num_spots,
3541
                         bool overprint, gx_color_index drawn_comps,
3542
                         int x0, int y0, int x1, int y1,
3543
                         const pdf14_nonseparable_blending_procs_t *pblend_procs,
3544
                         pdf14_device *pdev, int has_alpha, bool tos_is_be)
3545
0
{
3546
0
    uint16_t *gs_restrict mask_curr_ptr = NULL;
3547
0
    int width = x1 - x0;
3548
0
    int x, y;
3549
0
    int i;
3550
0
    uint16_t tos_pixel[PDF14_MAX_PLANES];
3551
0
    uint16_t nos_pixel[PDF14_MAX_PLANES];
3552
0
    uint16_t back_drop[PDF14_MAX_PLANES];
3553
0
    bool in_mask_rect_y;
3554
0
    bool in_mask_rect;
3555
0
    uint16_t pix_alpha;
3556
0
    uint16_t matte_alpha = 0xffff;
3557
0
    int first_spot = n_chan - num_spots;
3558
0
    int first_blend_spot = n_chan;
3559
0
    bool has_mask2 = has_mask;
3560
0
    uint16_t *gs_restrict dst;
3561
0
    uint16_t group_shape = (uint16_t)(65535 * pdev->shape + 0.5);
3562
3563
0
    if (!nos_knockout && num_spots > 0 && !blend_valid_for_spot(blend_mode)) {
3564
0
        first_blend_spot = first_spot;
3565
0
    }
3566
0
    if (blend_mode == BLEND_MODE_Normal)
3567
0
        first_blend_spot = 0;
3568
0
    if (!nos_isolated && backdrop_ptr != NULL)
3569
0
        has_mask2 = false;
3570
3571
/* TOS data being passed to this routine is usually in native
3572
 * endian format (i.e. if it's from another pdf14 buffer). Occasionally,
3573
 * if it's being passed in from pdf_compose_alphaless_group16, it can be
3574
 * from memory produced by another memory device (such as a pattern
3575
 * cache device). That data is in big endian form. So we have a crufty
3576
 * macro to get 16 bits of data from either native or bigendian into
3577
 * a native value. This should resolve nicely at compile time. */
3578
0
#define GET16_2NATIVE(be, v) \
3579
0
    ((be) ? ((((byte *)&v)[0]<<8) | (((byte *)&v)[1])) : v)
3580
3581
0
    for (y = y1 - y0; y > 0; --y) {
3582
0
        mask_curr_ptr = mask_row_ptr;
3583
0
        in_mask_rect_y = (has_mask && y1 - y >= maskbuf->rect.p.y && y1 - y < maskbuf->rect.q.y);
3584
0
        for (x = 0; x < width; x++) {
3585
0
            in_mask_rect = (in_mask_rect_y && x0 + x >= maskbuf->rect.p.x && x0 + x < maskbuf->rect.q.x);
3586
0
            pix_alpha = alpha;
3587
            /* If we have a soft mask, then we have some special handling of the
3588
               group alpha value */
3589
0
            if (maskbuf != NULL) {
3590
0
                if (!in_mask_rect) {
3591
                    /* Special case where we have a soft mask but are outside
3592
                       the range of the soft mask and must use the background
3593
                       alpha value */
3594
0
                    pix_alpha = mask_bg_alpha;
3595
0
                    matte_alpha = 0xffff;
3596
0
                } else {
3597
0
                    if (has_matte)
3598
0
                        matte_alpha = interp16(mask_tr_fn, *mask_curr_ptr);
3599
0
                }
3600
0
            }
3601
3602
            /* Matte present, need to undo premultiplied alpha prior to blend */
3603
0
            if (has_matte && matte_alpha != 0 && matte_alpha != 0xffff) {
3604
0
                for (i = 0; i < n_chan; i++) {
3605
                    /* undo */
3606
0
                    uint16_t matte = i >= maskbuf->matte_num_comps ? 0 : maskbuf->matte[i];
3607
0
                    int val = GET16_2NATIVE(tos_is_be, tos_ptr[i * tos_planestride]) - matte;
3608
0
                    int temp = (((unsigned int)(val * 0xffff)) / matte_alpha) + matte;
3609
3610
                    /* clip */
3611
0
                    if (temp > 0xffff)
3612
0
                        tos_pixel[i] = 0xffff;
3613
0
                    else if (temp < 0)
3614
0
                        tos_pixel[i] = 0;
3615
0
                    else
3616
0
                        tos_pixel[i] = temp;
3617
3618
0
                    if (!additive) {
3619
                        /* Pure subtractive */
3620
0
                        tos_pixel[i] = 65535 - tos_pixel[i];
3621
0
                        nos_pixel[i] = 65535 - nos_ptr[i * nos_planestride];
3622
0
                    } else {
3623
                        /* additive or hybrid */
3624
0
                        if (i >= first_spot)
3625
0
                            nos_pixel[i] = 65535 - nos_ptr[i * nos_planestride];
3626
0
                        else
3627
0
                            nos_pixel[i] = nos_ptr[i * nos_planestride];
3628
0
                    }
3629
0
                }
3630
0
            } else {
3631
                /* No matte present */
3632
0
                if (!additive) {
3633
                    /* Pure subtractive */
3634
0
                    for (i = 0; i < n_chan; ++i) {
3635
0
                        tos_pixel[i] = 65535 - GET16_2NATIVE(tos_is_be, tos_ptr[i * tos_planestride]);
3636
0
                        nos_pixel[i] = 65535 - nos_ptr[i * nos_planestride];
3637
0
                    }
3638
0
                } else {
3639
                    /* Additive or hybrid */
3640
0
                    for (i = 0; i < first_spot; ++i) {
3641
0
                        tos_pixel[i] = GET16_2NATIVE(tos_is_be, tos_ptr[i * tos_planestride]);
3642
0
                        nos_pixel[i] = nos_ptr[i * nos_planestride];
3643
0
                    }
3644
0
                    for (; i < n_chan; i++) {
3645
0
                        tos_pixel[i] = 65535 - GET16_2NATIVE(tos_is_be, tos_ptr[i * tos_planestride]);
3646
0
                        nos_pixel[i] = 65535 - nos_ptr[i * nos_planestride];
3647
0
                    }
3648
0
                }
3649
0
            }
3650
            /* alpha */
3651
0
            tos_pixel[n_chan] = has_alpha ? GET16_2NATIVE(tos_is_be, tos_ptr[n_chan * tos_planestride]) : 65535;
3652
0
            nos_pixel[n_chan] = has_alpha ? nos_ptr[n_chan * nos_planestride] : 65535;
3653
3654
0
            if (mask_curr_ptr != NULL) {
3655
0
                if (in_mask_rect) {
3656
0
                    uint16_t mask = interp16(mask_tr_fn, *mask_curr_ptr++);
3657
0
                    int tmp = pix_alpha * (mask+(mask>>15)) + 0x8000;
3658
0
                    pix_alpha = (tmp >> 16);
3659
0
                } else {
3660
0
                    mask_curr_ptr++;
3661
0
                }
3662
0
            }
3663
3664
0
            dst = nos_pixel;
3665
0
            if (nos_knockout) {
3666
                /* We need to be knocking out what ever is on the nos, but may
3667
                   need to combine with its backdrop */
3668
0
                uint16_t tos_shape = 65535;
3669
3670
0
                if (tos_has_shape)
3671
0
                    tos_shape = GET16_2NATIVE(tos_is_be, tos_ptr[tos_shape_offset]);
3672
3673
0
                if (nos_isolated || backdrop_ptr == NULL) {
3674
                    /* We do not need to compose with the backdrop */
3675
0
                    back_drop[n_chan] = 0;
3676
                    /* FIXME: The blend here can be simplified */
3677
0
                } else {
3678
                    /* Per the PDF spec, since the tos is not isolated and we are
3679
                       going onto a knock out group, we do the composition with
3680
                       the nos initial backdrop. */
3681
0
                    if (additive) {
3682
                        /* additive or hybrid */
3683
0
                        for (i = 0; i < first_spot; ++i) {
3684
0
                            back_drop[i] = backdrop_ptr[i * nos_planestride];
3685
0
                        }
3686
0
                        for (; i < n_chan; i++) {
3687
0
                            back_drop[i] = 65535 - backdrop_ptr[i * nos_planestride];
3688
0
                        }
3689
0
                    } else {
3690
                        /* pure subtractive */
3691
0
                        for (i = 0; i < n_chan; ++i) {
3692
0
                            back_drop[i] = 65535 - backdrop_ptr[i * nos_planestride];
3693
0
                        }
3694
0
                    }
3695
                    /* alpha */
3696
0
                    back_drop[n_chan] = backdrop_ptr[n_chan * nos_planestride];
3697
0
                }
3698
3699
0
                if (tos_isolated ?
3700
0
                    art_pdf_ko_composite_group_16(tos_shape, tos_alpha_g_ptr,
3701
0
                        nos_pixel, nos_alpha_g_ptr,
3702
0
                        tos_pixel, n_chan, pix_alpha,
3703
0
                        has_mask2) :
3704
0
                    art_pdf_ko_recomposite_group_16(tos_shape, has_alpha ? tos_ptr[tos_alpha_g_offset] : 65535,
3705
0
                        &dst, nos_alpha_g_ptr, tos_pixel, n_chan, pix_alpha,
3706
0
                        blend_mode, has_mask2)) {
3707
0
                    dst = art_pdf_knockout_composite_pixel_alpha_16(back_drop, tos_shape, nos_pixel, tos_pixel,
3708
0
                        n_chan, blend_mode, pblend_procs, pdev);
3709
0
                }
3710
0
            }
3711
0
            else if (tos_isolated ?
3712
0
                       art_pdf_composite_group_16(nos_pixel, nos_alpha_g_ptr,
3713
0
                                                  tos_pixel, n_chan, pix_alpha) :
3714
0
                       art_pdf_recomposite_group_16(&dst, nos_alpha_g_ptr,
3715
0
                                                    tos_pixel,
3716
0
                                                    has_alpha ? GET16_2NATIVE(tos_is_be, tos_ptr[tos_alpha_g_offset]) : 65535,
3717
0
                                                    n_chan,
3718
0
                                                    pix_alpha, blend_mode)) {
3719
0
                dst = art_pdf_composite_pixel_alpha_16_inline(nos_pixel, tos_pixel, n_chan,
3720
0
                                                blend_mode, first_blend_spot,
3721
0
                                                pblend_procs, pdev);
3722
0
            }
3723
0
            if (nos_shape_offset && pix_alpha != 0) {
3724
0
                nos_ptr[nos_shape_offset] =
3725
0
                    art_pdf_union_mul_16(nos_ptr[nos_shape_offset],
3726
0
                                         has_alpha ? GET16_2NATIVE(tos_is_be, tos_ptr[tos_shape_offset]) : group_shape,
3727
0
                                         shape);
3728
0
            }
3729
0
            if (dst)
3730
0
            {
3731
                /* Complement the results for subtractive color spaces.  Again,
3732
                 * if we are in an additive blending color space, we are not
3733
                 * going to be fooling with overprint of spot colors */
3734
0
                if (additive) {
3735
                    /* additive or hybrid */
3736
0
                    for (i = 0; i < first_spot; ++i) {
3737
0
                        nos_ptr[i * nos_planestride] = dst[i];
3738
0
                    }
3739
0
                    for (; i < n_chan; i++) {
3740
0
                        nos_ptr[i * nos_planestride] = 65535 - dst[i];
3741
0
                    }
3742
0
                } else {
3743
                    /* Pure subtractive */
3744
0
                    for (i = 0; i < n_chan; ++i)
3745
0
                        nos_ptr[i * nos_planestride] = 65535 - dst[i];
3746
0
                }
3747
                /* alpha */
3748
0
                nos_ptr[n_chan * nos_planestride] = dst[n_chan];
3749
0
            }
3750
            /* tags */
3751
0
            if (nos_tag_offset && tos_has_tag) {
3752
0
                nos_ptr[nos_tag_offset] |= tos_ptr[tos_tag_offset];
3753
0
             }
3754
3755
0
            if (nos_alpha_g_ptr != NULL)
3756
0
                ++nos_alpha_g_ptr;
3757
0
            if (tos_alpha_g_ptr != NULL)
3758
0
                ++tos_alpha_g_ptr;
3759
0
            if (backdrop_ptr != NULL)
3760
0
                ++backdrop_ptr;
3761
0
            ++tos_ptr;
3762
0
            ++nos_ptr;
3763
0
        }
3764
0
        tos_ptr += tos_rowstride - width;
3765
0
        nos_ptr += nos_rowstride - width;
3766
0
        if (tos_alpha_g_ptr != NULL)
3767
0
            tos_alpha_g_ptr += tos_rowstride - width;
3768
0
        if (nos_alpha_g_ptr != NULL)
3769
0
            nos_alpha_g_ptr += nos_rowstride - width;
3770
0
        if (mask_row_ptr != NULL)
3771
0
            mask_row_ptr += maskbuf->rowstride>>1;
3772
0
        if (backdrop_ptr != NULL)
3773
0
            backdrop_ptr += nos_rowstride - width;
3774
0
    }
3775
0
}
3776
3777
static void
3778
compose_group16_knockout(uint16_t *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
3779
              uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, intptr_t tos_shape_offset,
3780
              intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr,
3781
              uint16_t *nos_ptr, bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout,
3782
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3783
              uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn,
3784
              uint16_t *backdrop_ptr,
3785
              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,
3786
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3787
0
{
3788
0
    template_compose_group16(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, blend_mode, tos_has_shape,
3789
0
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
3790
0
        nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */1,
3791
0
        nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3792
0
        backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1, 0);
3793
0
}
3794
3795
static void
3796
compose_group16_nonknockout_blend(uint16_t *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
3797
              uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset,
3798
              intptr_t tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, intptr_t nos_planestride,
3799
              intptr_t nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3800
              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,
3801
              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,
3802
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3803
0
{
3804
0
    template_compose_group16(tos_ptr, tos_isolated, tos_planestride, tos_rowstride,
3805
0
        alpha, shape, blend_mode, tos_has_shape,
3806
0
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag,
3807
0
        tos_alpha_g_ptr, nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
3808
0
        nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
3809
0
        backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1, 0);
3810
0
}
3811
3812
static void
3813
compose_group16_nonknockout_nonblend_isolated_allmask_common(uint16_t *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
3814
              uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset,
3815
              intptr_t tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, intptr_t nos_planestride,
3816
              intptr_t nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3817
              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,
3818
              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,
3819
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3820
0
{
3821
0
    int width = x1 - x0;
3822
0
    int x, y;
3823
0
    int i;
3824
3825
0
    for (y = y1 - y0; y > 0; --y) {
3826
0
        uint16_t *gs_restrict mask_curr_ptr = mask_row_ptr;
3827
0
        for (x = 0; x < width; x++) {
3828
0
            unsigned int mask = interp16(mask_tr_fn, *mask_curr_ptr++);
3829
0
            uint16_t src_alpha = tos_ptr[n_chan * tos_planestride];
3830
0
            if (src_alpha != 0) {
3831
0
                uint16_t a_b;
3832
0
                unsigned int pix_alpha;
3833
3834
0
                mask += mask>>15;
3835
0
                pix_alpha = (alpha * mask + 0x8000)>>16;
3836
3837
0
                if (pix_alpha != 0xffff) {
3838
0
                    pix_alpha += pix_alpha>>15;
3839
0
                    src_alpha = (src_alpha * pix_alpha + 0x8000)>>16;
3840
0
                }
3841
3842
0
                a_b = nos_ptr[n_chan * nos_planestride];
3843
0
                if (a_b == 0) {
3844
                    /* Simple copy of colors plus alpha. */
3845
0
                    for (i = 0; i < n_chan; i++) {
3846
0
                        nos_ptr[i * nos_planestride] = tos_ptr[i * tos_planestride];
3847
0
                    }
3848
0
                    nos_ptr[i * nos_planestride] = src_alpha;
3849
0
                } else {
3850
0
                    unsigned int a_r;
3851
0
                    int src_scale;
3852
0
                    unsigned int tmp;
3853
3854
                    /* Result alpha is Union of backdrop and source alpha */
3855
0
                    tmp = (0xffff - a_b) * (0xffff - src_alpha) + 0x8000;
3856
0
                    tmp += tmp>>16;
3857
0
                    a_r = 0xffff - (tmp >> 16);
3858
3859
                    /* Compute src_alpha / a_r in 16.16 format */
3860
0
                    src_scale = ((src_alpha << 16) + (a_r >> 1)) / a_r;
3861
3862
0
                    nos_ptr[n_chan * nos_planestride] = a_r;
3863
3864
0
                    src_scale >>= 1; /* Will overflow unless we lose a bit */
3865
                    /* Do simple compositing of source over backdrop */
3866
0
                    for (i = 0; i < n_chan; i++) {
3867
0
                        int c_s = tos_ptr[i * tos_planestride];
3868
0
                        int c_b = nos_ptr[i * nos_planestride];
3869
0
                        nos_ptr[i * nos_planestride] = c_b + ((src_scale * (c_s - c_b) + 0x4000) >> 15);
3870
0
                    }
3871
0
                }
3872
0
            }
3873
0
            ++tos_ptr;
3874
0
            ++nos_ptr;
3875
0
        }
3876
0
        tos_ptr += tos_rowstride - width;
3877
0
        nos_ptr += nos_rowstride - width;
3878
0
        mask_row_ptr += maskbuf->rowstride>>1;
3879
0
    }
3880
0
}
3881
3882
static void
3883
compose_group16_nonknockout_nonblend_isolated_mask_common(uint16_t *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
3884
              uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset,
3885
              intptr_t tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, intptr_t nos_planestride,
3886
              intptr_t nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3887
              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,
3888
              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,
3889
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3890
0
{
3891
0
    uint16_t *gs_restrict mask_curr_ptr = NULL;
3892
0
    int width = x1 - x0;
3893
0
    int x, y;
3894
0
    int i;
3895
0
    bool in_mask_rect_y;
3896
0
    bool in_mask_rect;
3897
0
    uint16_t pix_alpha, src_alpha;
3898
3899
0
    for (y = y1 - y0; y > 0; --y) {
3900
0
        mask_curr_ptr = mask_row_ptr;
3901
0
        in_mask_rect_y = (has_mask && y1 - y >= maskbuf->rect.p.y && y1 - y < maskbuf->rect.q.y);
3902
0
        for (x = 0; x < width; x++) {
3903
0
            in_mask_rect = (in_mask_rect_y && has_mask && x0 + x >= maskbuf->rect.p.x && x0 + x < maskbuf->rect.q.x);
3904
0
            pix_alpha = alpha;
3905
            /* If we have a soft mask, then we have some special handling of the
3906
               group alpha value */
3907
0
            if (maskbuf != NULL) {
3908
0
                if (!in_mask_rect) {
3909
                    /* Special case where we have a soft mask but are outside
3910
                       the range of the soft mask and must use the background
3911
                       alpha value */
3912
0
                    pix_alpha = mask_bg_alpha;
3913
0
                }
3914
0
            }
3915
3916
0
            if (mask_curr_ptr != NULL) {
3917
0
                if (in_mask_rect) {
3918
0
                    unsigned int mask = interp16(mask_tr_fn, *mask_curr_ptr++);
3919
0
                    mask += mask>>15;
3920
0
                    pix_alpha = (pix_alpha * mask + 0x8000)>>16;
3921
0
                } else {
3922
0
                    mask_curr_ptr++;
3923
0
                }
3924
0
            }
3925
3926
0
            src_alpha = tos_ptr[n_chan * tos_planestride];
3927
0
            if (src_alpha != 0) {
3928
0
                uint16_t a_b;
3929
3930
0
                if (pix_alpha != 65535) {
3931
0
                    pix_alpha += pix_alpha>>15;
3932
0
                    src_alpha = (src_alpha * pix_alpha + 0x8000)>>16;
3933
0
                }
3934
3935
0
                a_b = nos_ptr[n_chan * nos_planestride];
3936
0
                if (a_b == 0) {
3937
                    /* Simple copy of colors plus alpha. */
3938
0
                    for (i = 0; i < n_chan; i++) {
3939
0
                        nos_ptr[i * nos_planestride] = tos_ptr[i * tos_planestride];
3940
0
                    }
3941
0
                    nos_ptr[i * nos_planestride] = src_alpha;
3942
0
                } else {
3943
0
                    unsigned int a_r;
3944
0
                    int src_scale;
3945
0
                    unsigned int tmp;
3946
3947
                    /* Result alpha is Union of backdrop and source alpha */
3948
0
                    tmp = (0xffff - a_b) * (0xffff - src_alpha) + 0x8000;
3949
0
                    tmp += tmp>>16;
3950
0
                    a_r = 0xffff - (tmp >> 16);
3951
3952
                    /* Compute src_alpha / a_r in 16.16 format */
3953
0
                    src_scale = ((src_alpha << 16) + (a_r >> 1)) / a_r;
3954
3955
0
                    nos_ptr[n_chan * nos_planestride] = a_r;
3956
3957
0
                    src_scale >>= 1; /* Need to lose a bit to avoid overflow */
3958
                    /* Do simple compositing of source over backdrop */
3959
0
                    for (i = 0; i < n_chan; i++) {
3960
0
                        int c_s = tos_ptr[i * tos_planestride];
3961
0
                        int c_b = nos_ptr[i * nos_planestride];
3962
0
                        nos_ptr[i * nos_planestride] = c_b + ((src_scale * (c_s - c_b) + 0x4000) >> 15);
3963
0
                    }
3964
0
                }
3965
0
            }
3966
0
            ++tos_ptr;
3967
0
            ++nos_ptr;
3968
0
        }
3969
0
        tos_ptr += tos_rowstride - width;
3970
0
        nos_ptr += nos_rowstride - width;
3971
0
        if (mask_row_ptr != NULL)
3972
0
            mask_row_ptr += maskbuf->rowstride>>1;
3973
0
    }
3974
0
}
3975
3976
static void
3977
compose_group16_nonknockout_nonblend_isolated_nomask_common(uint16_t *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
3978
              uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset,
3979
              intptr_t tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, intptr_t nos_planestride,
3980
              intptr_t nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3981
              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,
3982
              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,
3983
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
3984
0
{
3985
0
    template_compose_group16(tos_ptr, /*tos_isolated*/1, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
3986
0
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/ 0,
3987
0
        nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
3988
0
        /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, /*has_mask*/0, /*maskbuf*/NULL, mask_bg_alpha, mask_tr_fn,
3989
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);
3990
0
}
3991
3992
static void
3993
compose_group16_nonknockout_nonblend_nonisolated_mask_common(uint16_t *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
3994
              uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset,
3995
              intptr_t tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, intptr_t nos_planestride,
3996
              intptr_t nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, intptr_t nos_shape_offset, intptr_t nos_tag_offset,
3997
              uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn,
3998
              uint16_t *backdrop_ptr,
3999
              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,
4000
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
4001
0
{
4002
0
    template_compose_group16(tos_ptr, /*tos_isolated*/0, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
4003
0
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/0,
4004
0
        nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
4005
0
        /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
4006
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);
4007
0
}
4008
4009
static void
4010
compose_group16_nonknockout_nonblend_nonisolated_nomask_common(uint16_t *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
4011
              uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset,
4012
              intptr_t tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, intptr_t nos_planestride,
4013
              intptr_t nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, intptr_t nos_shape_offset, intptr_t nos_tag_offset,
4014
              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,
4015
              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,
4016
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
4017
0
{
4018
0
    template_compose_group16(tos_ptr, /*tos_isolated*/0, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, /*tos_has_shape*/0,
4019
0
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, /*tos_has_tag*/0, /*tos_alpha_g_ptr*/0,
4020
0
        nos_ptr, /*nos_isolated*/0, nos_planestride, nos_rowstride, /*nos_alpha_g_ptr*/0, /* nos_knockout = */0,
4021
0
        /*nos_shape_offset*/0, /*nos_tag_offset*/0, mask_row_ptr, /*has_mask*/0, /*maskbuf*/NULL, mask_bg_alpha, mask_tr_fn,
4022
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);
4023
0
}
4024
4025
static void
4026
compose_group16_nonknockout_noblend_general(uint16_t *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
4027
              uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, intptr_t tos_shape_offset,
4028
              intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr,
4029
              bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout,
4030
              intptr_t nos_shape_offset, intptr_t nos_tag_offset, uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf,
4031
              uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn, uint16_t *backdrop_ptr, bool has_matte, int n_chan,
4032
              bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
4033
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
4034
0
{
4035
0
    template_compose_group16(tos_ptr, tos_isolated, tos_planestride, tos_rowstride, alpha, shape, BLEND_MODE_Normal, tos_has_shape,
4036
0
        tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
4037
0
        nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
4038
0
        nos_shape_offset, nos_tag_offset, mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
4039
0
        backdrop_ptr, has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 1, 0);
4040
0
}
4041
4042
static void
4043
compose_group16_alphaless_knockout(uint16_t *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
4044
              uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, intptr_t tos_shape_offset,
4045
              intptr_t tos_alpha_g_offset, intptr_t tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr,
4046
              bool nos_isolated, intptr_t nos_planestride, intptr_t nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout,
4047
              intptr_t nos_shape_offset, intptr_t nos_tag_offset,
4048
              uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn,
4049
              uint16_t *backdrop_ptr,
4050
              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,
4051
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
4052
0
{
4053
0
    template_compose_group16(tos_ptr, tos_isolated, tos_planestride, tos_rowstride,
4054
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,
4055
0
        nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */1,
4056
0
        nos_shape_offset, nos_tag_offset, /* mask_row_ptr */ NULL, /* has_mask */ 0, /* maskbuf */ NULL, mask_bg_alpha, /* mask_tr_fn */ NULL,
4057
0
        backdrop_ptr, /* has_matte */ false , n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 0, 1);
4058
0
}
4059
4060
static void
4061
compose_group16_alphaless_nonknockout(uint16_t *tos_ptr, bool tos_isolated, intptr_t tos_planestride, intptr_t tos_rowstride,
4062
              uint16_t alpha, uint16_t shape, gs_blend_mode_t blend_mode, bool tos_has_shape, intptr_t tos_shape_offset, intptr_t tos_alpha_g_offset,
4063
              intptr_t tos_tag_offset, bool tos_has_tag, uint16_t *tos_alpha_g_ptr, uint16_t *nos_ptr, bool nos_isolated, intptr_t nos_planestride,
4064
              intptr_t nos_rowstride, uint16_t *nos_alpha_g_ptr, bool nos_knockout, intptr_t nos_shape_offset, intptr_t nos_tag_offset,
4065
              uint16_t *mask_row_ptr, int has_mask, pdf14_buf *maskbuf, uint16_t mask_bg_alpha, const uint16_t *mask_tr_fn,
4066
              uint16_t *backdrop_ptr,
4067
              bool has_matte, int n_chan, bool additive, int num_spots, bool overprint, gx_color_index drawn_comps, int x0, int y0, int x1, int y1,
4068
              const pdf14_nonseparable_blending_procs_t *pblend_procs, pdf14_device *pdev)
4069
0
{
4070
0
    template_compose_group16(tos_ptr, tos_isolated, tos_planestride, tos_rowstride,
4071
0
        alpha, shape, blend_mode, tos_has_shape, tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag,
4072
0
        tos_alpha_g_ptr, nos_ptr, nos_isolated, nos_planestride, nos_rowstride, nos_alpha_g_ptr, /* nos_knockout = */0,
4073
0
        nos_shape_offset, nos_tag_offset, /* mask_row_ptr */ NULL, /* has_mask */ 0, /* maskbuf */ NULL, mask_bg_alpha, /* mask_tr_fn */ NULL,
4074
0
        backdrop_ptr, /* has_matte */ false , n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1, pblend_procs, pdev, 0, 1);
4075
0
}
4076
4077
static void
4078
do_compose_group16(pdf14_buf *tos, pdf14_buf *nos, pdf14_buf *maskbuf,
4079
                   int x0, int x1, int y0, int y1, int n_chan, bool additive,
4080
                   const pdf14_nonseparable_blending_procs_t * pblend_procs,
4081
                   bool has_matte, bool overprint, gx_color_index drawn_comps,
4082
                   gs_memory_t *memory, gx_device *dev)
4083
0
{
4084
0
    int num_spots = tos->num_spots;
4085
0
    uint16_t alpha = tos->alpha;
4086
0
    uint16_t shape = tos->shape;
4087
0
    gs_blend_mode_t blend_mode = tos->blend_mode;
4088
0
    uint16_t *tos_ptr =
4089
0
        (uint16_t *)(void *)(tos->data + (x0 - tos->rect.p.x)*2 +
4090
0
                             (y0 - tos->rect.p.y) * tos->rowstride);
4091
0
    uint16_t *nos_ptr =
4092
0
        (uint16_t *)(void *)(nos->data + (x0 - nos->rect.p.x)*2 +
4093
0
                             (y0 - nos->rect.p.y) * nos->rowstride);
4094
0
    uint16_t *mask_row_ptr = NULL;
4095
0
    intptr_t tos_planestride = tos->planestride;
4096
0
    intptr_t nos_planestride = nos->planestride;
4097
0
    uint16_t mask_bg_alpha = 0; /* Quiet compiler. */
4098
0
    bool tos_isolated = tos->isolated;
4099
0
    bool nos_isolated = nos->isolated;
4100
0
    bool nos_knockout = nos->knockout;
4101
0
    uint16_t *nos_alpha_g_ptr;
4102
0
    uint16_t *tos_alpha_g_ptr;
4103
0
    intptr_t tos_shape_offset = n_chan * tos_planestride;
4104
0
    intptr_t tos_alpha_g_offset = tos_shape_offset + (tos->has_shape ? tos_planestride : 0);
4105
0
    bool tos_has_tag = tos->has_tags;
4106
0
    intptr_t tos_tag_offset = tos_planestride * (tos->n_planes - 1);
4107
0
    intptr_t nos_shape_offset = n_chan * nos_planestride;
4108
0
    intptr_t nos_alpha_g_offset = nos_shape_offset + (nos->has_shape ? nos_planestride : 0);
4109
0
    intptr_t nos_tag_offset = nos_planestride * (nos->n_planes - 1);
4110
0
    const uint16_t *mask_tr_fn = NULL; /* Quiet compiler. */
4111
0
    bool has_mask = false;
4112
0
    uint16_t *backdrop_ptr = NULL;
4113
0
    pdf14_device *pdev = (pdf14_device *)dev;
4114
#if RAW_DUMP
4115
    uint16_t *composed_ptr = NULL;
4116
    int width = x1 - x0;
4117
#endif
4118
0
    art_pdf_compose_group16_fn fn;
4119
4120
0
    if ((tos->n_chan == 0) || (nos->n_chan == 0))
4121
0
        return;
4122
0
    rect_merge(nos->dirty, tos->dirty);
4123
0
    if (nos->has_tags)
4124
0
        if_debug7m('v', memory,
4125
0
                   "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, tag = %d, bm = %d\n",
4126
0
                   y0, y1, x1 - x0, alpha, shape, dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS, blend_mode);
4127
0
    else
4128
0
        if_debug6m('v', memory,
4129
0
                   "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, bm = %d\n",
4130
0
                   y0, y1, x1 - x0, alpha, shape, blend_mode);
4131
0
    if (!nos->has_shape)
4132
0
        nos_shape_offset = 0;
4133
0
    if (!nos->has_tags)
4134
0
        nos_tag_offset = 0;
4135
0
    if (nos->has_alpha_g) {
4136
0
        nos_alpha_g_ptr = nos_ptr + (nos_alpha_g_offset>>1);
4137
0
    } else
4138
0
        nos_alpha_g_ptr = NULL;
4139
0
    if (tos->has_alpha_g) {
4140
0
        tos_alpha_g_ptr = tos_ptr + (tos_alpha_g_offset>>1);
4141
0
    } else
4142
0
        tos_alpha_g_ptr = NULL;
4143
0
    if (nos->backdrop != NULL) {
4144
0
        backdrop_ptr =
4145
0
            (uint16_t *)(void *)(nos->backdrop + (x0 - nos->rect.p.x)*2 +
4146
0
                                 (y0 - nos->rect.p.y) * nos->rowstride);
4147
0
    }
4148
0
    if (blend_mode != BLEND_MODE_Compatible && blend_mode != BLEND_MODE_Normal)
4149
0
        overprint = false;
4150
4151
0
    if (maskbuf != NULL) {
4152
0
        unsigned int tmp;
4153
0
        mask_tr_fn = (uint16_t *)maskbuf->transfer_fn;
4154
        /* Make sure we are in the mask buffer */
4155
0
        if (maskbuf->data != NULL) {
4156
0
            mask_row_ptr =
4157
0
                (uint16_t *)(void *)(maskbuf->data + (x0 - maskbuf->rect.p.x)*2 +
4158
0
                                     (y0 - maskbuf->rect.p.y) * maskbuf->rowstride);
4159
0
            has_mask = true;
4160
0
        }
4161
        /* We may have a case, where we are outside the maskbuf rect. */
4162
        /* We would have avoided creating the maskbuf->data */
4163
        /* In that case, we should use the background alpha value */
4164
        /* See discussion on the BC entry in the PDF spec.   */
4165
0
        mask_bg_alpha = maskbuf->alpha;
4166
        /* Adjust alpha by the mask background alpha.   This is only used
4167
           if we are outside the soft mask rect during the filling operation */
4168
0
        mask_bg_alpha = interp16(mask_tr_fn, mask_bg_alpha);
4169
0
        tmp = alpha * mask_bg_alpha + 0x8000;
4170
0
        mask_bg_alpha = (tmp + (tmp >> 8)) >> 8;
4171
0
    }
4172
0
    n_chan--; /* Now the true number of colorants (i.e. not including alpha)*/
4173
#if RAW_DUMP
4174
    composed_ptr = nos_ptr;
4175
    dump_raw_buffer(memory, y1-y0, width, tos->n_planes, tos_planestride, tos->rowstride,
4176
                    "bImageTOS", (byte *)tos_ptr, tos->deep);
4177
    dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
4178
                    "cImageNOS", (byte *)nos_ptr, tos->deep);
4179
    if (maskbuf !=NULL && maskbuf->data != NULL) {
4180
        dump_raw_buffer(memory, maskbuf->rect.q.y - maskbuf->rect.p.y,
4181
                        maskbuf->rect.q.x - maskbuf->rect.p.x, maskbuf->n_planes,
4182
                        maskbuf->planestride, maskbuf->rowstride, "dMask",
4183
                        maskbuf->data, maskbuf->deep);
4184
    }
4185
#endif
4186
4187
    /* You might hope that has_mask iff maskbuf != NULL, but this is
4188
     * not the case. Certainly we can see cases where maskbuf != NULL
4189
     * and has_mask = 0. What's more, treating such cases as being
4190
     * has_mask = 0 causes diffs. */
4191
#ifdef TRACK_COMPOSE_GROUPS
4192
    {
4193
        int code = 0;
4194
4195
        code += !!nos_knockout;
4196
        code += (!!nos_isolated)<<1;
4197
        code += (!!tos_isolated)<<2;
4198
        code += (!!tos->has_shape)<<3;
4199
        code += (!!tos_has_tag)<<4;
4200
        code += (!!additive)<<5;
4201
        code += (!!overprint)<<6;
4202
        code += (!!has_mask || maskbuf != NULL)<<7;
4203
        code += (!!has_matte)<<8;
4204
        code += (backdrop_ptr != NULL)<<9;
4205
        code += (num_spots != 0)<<10;
4206
        code += blend_mode<<11;
4207
4208
        if (track_compose_groups == 0)
4209
        {
4210
            atexit(dump_track_compose_groups);
4211
            track_compose_groups = 1;
4212
        }
4213
        compose_groups[code]++;
4214
    }
4215
#endif
4216
4217
    /* We have tested the files on the cluster to see what percentage of
4218
     * files/devices hit the different options. */
4219
0
    if (nos_knockout)
4220
0
        fn = &compose_group16_knockout; /* Small %ages, nothing more than 1.1% */
4221
0
    else if (blend_mode != 0)
4222
0
        fn = &compose_group16_nonknockout_blend; /* Small %ages, nothing more than 2% */
4223
0
    else if (tos->has_shape == 0 && tos_has_tag == 0 && nos_isolated == 0 && nos_alpha_g_ptr == NULL &&
4224
0
             nos_shape_offset == 0 && nos_tag_offset == 0 && backdrop_ptr == NULL && has_matte == 0 && num_spots == 0 &&
4225
0
             overprint == 0 && tos_alpha_g_ptr == NULL) {
4226
             /* Additive vs Subtractive makes no difference in normal blend mode with no spots */
4227
0
        if (tos_isolated) {
4228
0
            if (has_mask && maskbuf) {/* 7% */
4229
                /* AirPrint test case hits this */
4230
0
                if (maskbuf && maskbuf->rect.p.x <= x0 && maskbuf->rect.p.y <= y0 &&
4231
0
                    maskbuf->rect.q.x >= x1 && maskbuf->rect.q.y >= y1)
4232
0
                    fn = &compose_group16_nonknockout_nonblend_isolated_allmask_common;
4233
0
                else
4234
0
                    fn = &compose_group16_nonknockout_nonblend_isolated_mask_common;
4235
0
            } else
4236
0
                if (maskbuf) {
4237
                    /* Outside mask data but still has mask */
4238
0
                    fn = &compose_group16_nonknockout_nonblend_isolated_mask_common;
4239
0
                } else {
4240
0
                    fn = &compose_group16_nonknockout_nonblend_isolated_nomask_common;
4241
0
                }
4242
0
        } else {
4243
0
            if (has_mask || maskbuf) /* 4% */
4244
0
                fn = &compose_group16_nonknockout_nonblend_nonisolated_mask_common;
4245
0
            else /* 15% */
4246
0
                fn = &compose_group16_nonknockout_nonblend_nonisolated_nomask_common;
4247
0
        }
4248
0
    } else
4249
0
        fn = compose_group16_nonknockout_noblend_general;
4250
4251
0
    tos_planestride >>= 1;
4252
0
    tos_shape_offset >>= 1;
4253
0
    tos_alpha_g_offset >>= 1;
4254
0
    tos_tag_offset >>= 1;
4255
0
    nos_planestride >>= 1;
4256
0
    nos_shape_offset >>= 1;
4257
0
    nos_tag_offset >>= 1;
4258
0
    fn(tos_ptr, tos_isolated, tos_planestride, tos->rowstride>>1, alpha, shape, blend_mode, tos->has_shape,
4259
0
                  tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag,
4260
0
                  tos_alpha_g_ptr, nos_ptr, nos_isolated, nos_planestride, nos->rowstride>>1, nos_alpha_g_ptr, nos_knockout,
4261
0
                  nos_shape_offset, nos_tag_offset,
4262
0
                  mask_row_ptr, has_mask, maskbuf, mask_bg_alpha, mask_tr_fn,
4263
0
                  backdrop_ptr,
4264
0
                  has_matte, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1,
4265
0
                  pblend_procs, pdev);
4266
4267
#if RAW_DUMP
4268
    dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride<<1, nos->rowstride,
4269
                    "eComposed", (byte *)composed_ptr, nos->deep);
4270
    global_index++;
4271
#endif
4272
0
}
4273
4274
void
4275
pdf14_compose_group(pdf14_buf *tos, pdf14_buf *nos, pdf14_buf *maskbuf,
4276
              int x0, int x1, int y0, int y1, int n_chan, bool additive,
4277
              const pdf14_nonseparable_blending_procs_t * pblend_procs,
4278
              bool has_matte, bool overprint, gx_color_index drawn_comps,
4279
              gs_memory_t *memory, gx_device *dev)
4280
317k
{
4281
317k
    if (tos->deep)
4282
0
        do_compose_group16(tos, nos, maskbuf, x0, x1, y0, y1, n_chan,
4283
0
                           additive, pblend_procs, has_matte, overprint,
4284
0
                           drawn_comps, memory, dev);
4285
317k
    else
4286
317k
        do_compose_group(tos, nos, maskbuf, x0, x1, y0, y1, n_chan,
4287
317k
                         additive, pblend_procs, has_matte, overprint,
4288
317k
                         drawn_comps, memory, dev);
4289
317k
}
4290
4291
static void
4292
do_compose_alphaless_group(pdf14_buf *tos, pdf14_buf *nos,
4293
                           int x0, int x1, int y0, int y1,
4294
                           gs_memory_t *memory, gx_device *dev)
4295
2.45k
{
4296
2.45k
    pdf14_device *pdev = (pdf14_device *)dev;
4297
2.45k
    bool overprint = pdev->op_state == GS_OP_STATE_FILL ? pdev->overprint : pdev->stroke_overprint;
4298
2.45k
    bool additive = pdev->ctx->additive;
4299
2.45k
    gx_color_index drawn_comps = pdev->op_state == GS_OP_STATE_FILL ?
4300
2.45k
                                     pdev->drawn_comps_fill : pdev->drawn_comps_stroke;
4301
2.45k
    int n_chan = nos->n_chan;
4302
2.45k
    int num_spots = tos->num_spots;
4303
2.45k
    byte alpha = tos->alpha>>8;
4304
2.45k
    byte shape = tos->shape>>8;
4305
2.45k
    gs_blend_mode_t blend_mode = tos->blend_mode;
4306
2.45k
    byte *tos_ptr = tos->data + x0 - tos->rect.p.x +
4307
2.45k
        (y0 - tos->rect.p.y) * tos->rowstride;
4308
2.45k
    byte *nos_ptr = nos->data + x0 - nos->rect.p.x +
4309
2.45k
        (y0 - nos->rect.p.y) * nos->rowstride;
4310
2.45k
    byte *mask_row_ptr = NULL;
4311
2.45k
    intptr_t tos_planestride = tos->planestride;
4312
2.45k
    intptr_t nos_planestride = nos->planestride;
4313
2.45k
    byte mask_bg_alpha = 0; /* Quiet compiler. */
4314
2.45k
    bool tos_isolated = false;
4315
2.45k
    bool nos_isolated = nos->isolated;
4316
2.45k
    bool nos_knockout = nos->knockout;
4317
2.45k
    byte *nos_alpha_g_ptr, *tos_alpha_g_ptr;
4318
2.45k
    intptr_t tos_shape_offset = n_chan * tos_planestride;
4319
2.45k
    intptr_t tos_alpha_g_offset = tos_shape_offset + (tos->has_shape ? tos_planestride : 0);
4320
2.45k
    bool tos_has_tag = tos->has_tags;
4321
2.45k
    intptr_t tos_tag_offset = tos_planestride * (tos->n_planes - 1);
4322
2.45k
    intptr_t nos_shape_offset = n_chan * nos_planestride;
4323
2.45k
    intptr_t nos_alpha_g_offset = nos_shape_offset + (nos->has_shape ? nos_planestride : 0);
4324
2.45k
    intptr_t nos_tag_offset = nos_planestride * (nos->n_planes - 1);
4325
2.45k
    const byte *mask_tr_fn = NULL; /* Quiet compiler. */
4326
2.45k
    bool has_mask = false;
4327
2.45k
    byte *backdrop_ptr = NULL;
4328
#if RAW_DUMP
4329
    byte *composed_ptr = NULL;
4330
    int width = x1 - x0;
4331
#endif
4332
2.45k
    art_pdf_compose_group_fn fn;
4333
4334
2.45k
    if ((tos->n_chan == 0) || (nos->n_chan == 0))
4335
0
        return;
4336
2.45k
    rect_merge(nos->dirty, tos->dirty);
4337
2.45k
    if (nos->has_tags)
4338
2.45k
        if_debug7m('v', memory,
4339
2.45k
                   "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, tag = %d, bm = %d\n",
4340
2.45k
                   y0, y1, x1 - x0, alpha, shape, dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS, blend_mode);
4341
2.45k
    else
4342
2.45k
        if_debug6m('v', memory,
4343
2.45k
                   "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, bm = %d\n",
4344
2.45k
                   y0, y1, x1 - x0, alpha, shape, blend_mode);
4345
2.45k
    if (!nos->has_shape)
4346
2.45k
        nos_shape_offset = 0;
4347
2.45k
    if (!nos->has_tags)
4348
2.45k
        nos_tag_offset = 0;
4349
2.45k
    if (nos->has_alpha_g) {
4350
0
        nos_alpha_g_ptr = nos_ptr + nos_alpha_g_offset;
4351
0
    } else
4352
2.45k
        nos_alpha_g_ptr = NULL;
4353
2.45k
    if (tos->has_alpha_g) {
4354
0
        tos_alpha_g_ptr = tos_ptr + tos_alpha_g_offset;
4355
0
    } else
4356
2.45k
        tos_alpha_g_ptr = NULL;
4357
2.45k
    if (nos->backdrop != NULL) {
4358
0
        backdrop_ptr = nos->backdrop + x0 - nos->rect.p.x +
4359
0
                       (y0 - nos->rect.p.y) * nos->rowstride;
4360
0
    }
4361
2.45k
    if (blend_mode != BLEND_MODE_Compatible && blend_mode != BLEND_MODE_Normal)
4362
0
        overprint = false;
4363
4364
2.45k
    n_chan--; /* Now the true number of colorants (i.e. not including alpha)*/
4365
#if RAW_DUMP
4366
    composed_ptr = nos_ptr;
4367
    dump_raw_buffer(memory, y1-y0, width, tos->n_planes, tos_planestride, tos->rowstride,
4368
                    "bImageTOS", tos_ptr, tos->deep);
4369
    dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
4370
                    "cImageNOS", nos_ptr, nos->deep);
4371
    /* maskbuf is NULL in here */
4372
#endif
4373
4374
    /* You might hope that has_mask iff maskbuf != NULL, but this is
4375
     * not the case. Certainly we can see cases where maskbuf != NULL
4376
     * and has_mask = 0. What's more, treating such cases as being
4377
     * has_mask = 0 causes diffs. */
4378
#ifdef TRACK_COMPOSE_GROUPS
4379
    {
4380
        int code = 0;
4381
4382
        code += !!nos_knockout;
4383
        code += (!!nos_isolated)<<1;
4384
        code += (!!tos_isolated)<<2;
4385
        code += (!!tos->has_shape)<<3;
4386
        code += (!!tos_has_tag)<<4;
4387
        code += (!!additive)<<5;
4388
        code += (!!overprint)<<6;
4389
        code += (!!has_mask)<<7;
4390
        code += (backdrop_ptr != NULL)<<9;
4391
        code += (num_spots != 0)<<10;
4392
        code += blend_mode<<11;
4393
4394
        if (track_compose_groups == 0)
4395
        {
4396
            atexit(dump_track_compose_groups);
4397
            track_compose_groups = 1;
4398
        }
4399
        compose_groups[code]++;
4400
    }
4401
#endif
4402
4403
    /* We have tested the files on the cluster to see what percentage of
4404
     * files/devices hit the different options. */
4405
2.45k
    if (nos_knockout)
4406
0
        fn = &compose_group_alphaless_knockout;
4407
2.45k
    else
4408
2.45k
        fn = &compose_group_alphaless_nonknockout;
4409
4410
2.45k
    fn(tos_ptr, tos_isolated, tos_planestride, tos->rowstride, alpha, shape, blend_mode, tos->has_shape,
4411
2.45k
                  tos_shape_offset, tos_alpha_g_offset, tos_tag_offset, tos_has_tag, tos_alpha_g_ptr,
4412
2.45k
                  nos_ptr, nos_isolated, nos_planestride, nos->rowstride, nos_alpha_g_ptr, nos_knockout,
4413
2.45k
                  nos_shape_offset, nos_tag_offset,
4414
2.45k
                  mask_row_ptr, has_mask, /* maskbuf */ NULL, mask_bg_alpha, mask_tr_fn,
4415
2.45k
                  backdrop_ptr,
4416
2.45k
                  /* has_matte */ 0, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1,
4417
2.45k
                  pdev->blend_procs, pdev);
4418
4419
#if RAW_DUMP
4420
    dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
4421
                    "eComposed", composed_ptr, nos->deep);
4422
    global_index++;
4423
#endif
4424
2.45k
}
4425
4426
static void
4427
do_compose_alphaless_group16(pdf14_buf *tos, pdf14_buf *nos,
4428
                             int x0, int x1, int y0, int y1,
4429
                             gs_memory_t *memory, gx_device *dev)
4430
0
{
4431
0
    pdf14_device *pdev = (pdf14_device *)dev;
4432
0
    bool overprint = pdev->op_state == GS_OP_STATE_FILL ? pdev->overprint : pdev->stroke_overprint;
4433
0
    bool additive = pdev->ctx->additive;
4434
0
    gx_color_index drawn_comps = pdev->op_state == GS_OP_STATE_FILL ?
4435
0
                                     pdev->drawn_comps_fill : pdev->drawn_comps_stroke;
4436
0
    int n_chan = nos->n_chan;
4437
0
    int num_spots = tos->num_spots;
4438
0
    uint16_t alpha = tos->alpha;
4439
0
    uint16_t shape = tos->shape;
4440
0
    gs_blend_mode_t blend_mode = tos->blend_mode;
4441
0
    uint16_t *tos_ptr =
4442
0
        (uint16_t *)(void *)(tos->data + (x0 - tos->rect.p.x)*2 +
4443
0
                             (y0 - tos->rect.p.y) * tos->rowstride);
4444
0
    uint16_t *nos_ptr =
4445
0
        (uint16_t *)(void *)(nos->data + (x0 - nos->rect.p.x)*2 +
4446
0
                             (y0 - nos->rect.p.y) * nos->rowstride);
4447
0
    uint16_t *mask_row_ptr = NULL;
4448
0
    intptr_t tos_planestride = tos->planestride;
4449
0
    intptr_t nos_planestride = nos->planestride;
4450
0
    uint16_t mask_bg_alpha = 0; /* Quiet compiler. */
4451
0
    bool tos_isolated = false;
4452
0
    bool nos_isolated = nos->isolated;
4453
0
    bool nos_knockout = nos->knockout;
4454
0
    uint16_t *nos_alpha_g_ptr;
4455
0
    uint16_t *tos_alpha_g_ptr;
4456
0
    intptr_t tos_shape_offset = n_chan * tos_planestride;
4457
0
    intptr_t tos_alpha_g_offset = tos_shape_offset + (tos->has_shape ? tos_planestride : 0);
4458
0
    bool tos_has_tag = tos->has_tags;
4459
0
    intptr_t tos_tag_offset = tos_planestride * (tos->n_planes - 1);
4460
0
    intptr_t nos_shape_offset = n_chan * nos_planestride;
4461
0
    intptr_t nos_alpha_g_offset = nos_shape_offset + (nos->has_shape ? nos_planestride : 0);
4462
0
    intptr_t nos_tag_offset = nos_planestride * (nos->n_planes - 1);
4463
0
    bool has_mask = false;
4464
0
    uint16_t *backdrop_ptr = NULL;
4465
#if RAW_DUMP
4466
    uint16_t *composed_ptr = NULL;
4467
    int width = x1 - x0;
4468
#endif
4469
0
    art_pdf_compose_group16_fn fn;
4470
4471
0
    if ((tos->n_chan == 0) || (nos->n_chan == 0))
4472
0
        return;
4473
0
    rect_merge(nos->dirty, tos->dirty);
4474
0
    if (nos->has_tags)
4475
0
        if_debug7m('v', memory,
4476
0
                   "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, tag = %d, bm = %d\n",
4477
0
                   y0, y1, x1 - x0, alpha, shape, dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS, blend_mode);
4478
0
    else
4479
0
        if_debug6m('v', memory,
4480
0
                   "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, bm = %d\n",
4481
0
                   y0, y1, x1 - x0, alpha, shape, blend_mode);
4482
0
    if (!nos->has_shape)
4483
0
        nos_shape_offset = 0;
4484
0
    if (!nos->has_tags)
4485
0
        nos_tag_offset = 0;
4486
0
    if (nos->has_alpha_g) {
4487
0
        nos_alpha_g_ptr = nos_ptr + (nos_alpha_g_offset>>1);
4488
0
    } else
4489
0
        nos_alpha_g_ptr = NULL;
4490
0
    if (tos->has_alpha_g) {
4491
0
        tos_alpha_g_ptr = tos_ptr + (tos_alpha_g_offset>>1);
4492
0
    } else
4493
0
        tos_alpha_g_ptr = NULL;
4494
4495
0
    if (nos->backdrop != NULL) {
4496
0
        backdrop_ptr =
4497
0
            (uint16_t *)(void *)(nos->backdrop + (x0 - nos->rect.p.x)*2 +
4498
0
                                 (y0 - nos->rect.p.y) * nos->rowstride);
4499
0
    }
4500
0
    if (blend_mode != BLEND_MODE_Compatible && blend_mode != BLEND_MODE_Normal)
4501
0
        overprint = false;
4502
4503
0
    n_chan--; /* Now the true number of colorants (i.e. not including alpha)*/
4504
#if RAW_DUMP
4505
    composed_ptr = nos_ptr;
4506
    dump_raw_buffer_be(memory, y1-y0, width, tos->n_planes, tos_planestride, tos->rowstride,
4507
                       "bImageTOS", (byte *)tos_ptr, tos->deep);
4508
    dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
4509
                    "cImageNOS", (byte *)nos_ptr, nos->deep);
4510
    /* maskbuf is NULL in here */
4511
#endif
4512
4513
    /* You might hope that has_mask iff maskbuf != NULL, but this is
4514
     * not the case. Certainly we can see cases where maskbuf != NULL
4515
     * and has_mask = 0. What's more, treating such cases as being
4516
     * has_mask = 0 causes diffs. */
4517
#ifdef TRACK_COMPOSE_GROUPS
4518
    {
4519
        int code = 0;
4520
4521
        code += !!nos_knockout;
4522
        code += (!!nos_isolated)<<1;
4523
        code += (!!tos_isolated)<<2;
4524
        code += (!!tos->has_shape)<<3;
4525
        code += (!!tos_has_tag)<<4;
4526
        code += (!!additive)<<5;
4527
        code += (!!overprint)<<6;
4528
        code += (!!has_mask)<<7;
4529
        code += (backdrop_ptr != NULL)<<9;
4530
        code += (num_spots != 0)<<10;
4531
        code += blend_mode<<11;
4532
4533
        if (track_compose_groups == 0)
4534
        {
4535
            atexit(dump_track_compose_groups);
4536
            track_compose_groups = 1;
4537
        }
4538
        compose_groups[code]++;
4539
    }
4540
#endif
4541
4542
    /* We have tested the files on the cluster to see what percentage of
4543
     * files/devices hit the different options. */
4544
0
    if (nos_knockout)
4545
0
        fn = &compose_group16_alphaless_knockout;
4546
0
    else
4547
0
        fn = &compose_group16_alphaless_nonknockout;
4548
4549
0
    fn(tos_ptr, tos_isolated, tos_planestride>>1, tos->rowstride>>1, alpha, shape, blend_mode, tos->has_shape,
4550
0
                  tos_shape_offset>>1, tos_alpha_g_offset>>1, tos_tag_offset>>1, tos_has_tag, tos_alpha_g_ptr,
4551
0
                  nos_ptr, nos_isolated, nos_planestride>>1, nos->rowstride>>1, nos_alpha_g_ptr, nos_knockout,
4552
0
                  nos_shape_offset>>1, nos_tag_offset>>1,
4553
0
                  mask_row_ptr, has_mask, /* maskbuf */ NULL, mask_bg_alpha, NULL,
4554
0
                  backdrop_ptr,
4555
0
                  /* has_matte */ 0, n_chan, additive, num_spots, overprint, drawn_comps, x0, y0, x1, y1,
4556
0
                  pdev->blend_procs, pdev);
4557
4558
#if RAW_DUMP
4559
    dump_raw_buffer(memory, y1-y0, width, nos->n_planes, nos_planestride, nos->rowstride,
4560
                    "eComposed", (byte *)composed_ptr, nos->deep);
4561
    global_index++;
4562
#endif
4563
0
}
4564
4565
void
4566
pdf14_compose_alphaless_group(pdf14_buf *tos, pdf14_buf *nos,
4567
                              int x0, int x1, int y0, int y1,
4568
                              gs_memory_t *memory, gx_device *dev)
4569
2.45k
{
4570
2.45k
    if (tos->deep)
4571
0
        do_compose_alphaless_group16(tos, nos, x0, x1, y0, y1, memory, dev);
4572
2.45k
    else
4573
2.45k
        do_compose_alphaless_group(tos, nos, x0, x1, y0, y1, memory, dev);
4574
2.45k
}
4575
4576
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,
4577
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4578
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4579
               int alpha_g_off, int shape_off, byte shape);
4580
4581
static forceinline void
4582
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,
4583
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4584
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4585
               int alpha_g_off, int shape_off, byte shape)
4586
91.7M
{
4587
91.7M
    int i, j, k;
4588
91.7M
    byte dst[PDF14_MAX_PLANES] = { 0 };
4589
91.7M
    byte dest_alpha;
4590
91.7M
    bool tag_blend = blend_mode == BLEND_MODE_Normal ||
4591
86.5M
        blend_mode == BLEND_MODE_Compatible ||
4592
9.03M
        blend_mode == BLEND_MODE_CompatibleOverprint;
4593
4594
193M
    for (j = h; j > 0; --j) {
4595
878M
        for (i = w; i > 0; --i) {
4596
776M
            if ((blend_mode == BLEND_MODE_Normal && src[num_comp] == 0xff && !overprint) || dst_ptr[num_comp * planestride] == 0) {
4597
                /* dest alpha is zero (or normal, and solid src) just use source. */
4598
714M
                if (additive) {
4599
                    /* Hybrid case */
4600
2.69G
                    for (k = 0; k < (num_comp - num_spots); k++) {
4601
2.02G
                        dst_ptr[k * planestride] = src[k];
4602
2.02G
                    }
4603
674M
                    for (k = 0; k < num_spots; k++) {
4604
147k
                        dst_ptr[(k + num_comp - num_spots) * planestride] =
4605
147k
                                255 - src[k + num_comp - num_spots];
4606
147k
                    }
4607
673M
                } else {
4608
                    /* Pure subtractive */
4609
203M
                    for (k = 0; k < num_comp; k++) {
4610
163M
                        dst_ptr[k * planestride] = 255 - src[k];
4611
163M
                    }
4612
40.7M
                }
4613
                /* alpha */
4614
714M
                dst_ptr[num_comp * planestride] = src[num_comp];
4615
714M
            } else if (src[num_comp] != 0) {
4616
62.1M
                byte *pdst;
4617
                /* Complement subtractive planes */
4618
62.1M
                if (!additive) {
4619
                    /* Pure subtractive */
4620
78.1M
                    for (k = 0; k < num_comp; ++k)
4621
62.4M
                        dst[k] = 255 - dst_ptr[k * planestride];
4622
46.5M
                } else {
4623
                    /* Hybrid case, additive with subtractive spots */
4624
186M
                    for (k = 0; k < (num_comp - num_spots); k++) {
4625
139M
                        dst[k] = dst_ptr[k * planestride];
4626
139M
                    }
4627
46.8M
                    for (k = 0; k < num_spots; k++) {
4628
289k
                        dst[k + num_comp - num_spots] =
4629
289k
                            255 - dst_ptr[(k + num_comp - num_spots) * planestride];
4630
289k
                    }
4631
46.5M
                }
4632
62.1M
                dst[num_comp] = dst_ptr[num_comp * planestride];
4633
62.1M
                dest_alpha = dst[num_comp];
4634
62.1M
                pdst = art_pdf_composite_pixel_alpha_8_inline(dst, src, num_comp, blend_mode, first_blend_spot,
4635
62.1M
                            pdev->blend_procs, pdev);
4636
                /* Post blend complement for subtractive and handling of drawncomps
4637
                   if overprint.  We will have already done the compatible overprint
4638
                   mode in the above composition */
4639
62.1M
                if (!additive && !overprint) {
4640
                    /* Pure subtractive */
4641
66.1M
                    for (k = 0; k < num_comp; ++k)
4642
52.9M
                        dst_ptr[k * planestride] = 255 - pdst[k];
4643
48.9M
                } else if (!additive && overprint) {
4644
2.38M
                    int comps;
4645
                    /* If this is an overprint case, and alpha_r is different
4646
                       than alpha_d then we will need to adjust
4647
                       the colors of the non-drawn components here too */
4648
2.38M
                    if (dest_alpha != pdst[num_comp] && pdst[num_comp] != 0) {
4649
                        /* dest_alpha > pdst[num_comp], and dst[num_comp] != 0.
4650
                         * Therefore dest_alpha / pdst[num_comp] <= 255 */
4651
0
                        uint32_t scale = 256 * dest_alpha / pdst[num_comp];
4652
0
                        for (k = 0, comps = drawn_comps; k < num_comp; ++k, comps >>= 1) {
4653
0
                            if ((comps & 0x1) != 0) {
4654
0
                                dst_ptr[k * planestride] = 255 - pdst[k];
4655
0
                            } else {
4656
                                /* We need val_new = (val_old * old_alpha) / new_alpha */
4657
0
                                uint32_t val = (scale * dst_ptr[k * planestride] + 128)>>8;
4658
0
                                if (val > 255)
4659
0
                                    val = 255;
4660
0
                                dst_ptr[k * planestride] = val;
4661
0
                            }
4662
0
                        }
4663
2.38M
                    } else {
4664
11.9M
                        for (k = 0, comps = drawn_comps; k < num_comp; ++k, comps >>= 1) {
4665
9.54M
                            if ((comps & 0x1) != 0) {
4666
9.54M
                                dst_ptr[k * planestride] = 255 - pdst[k];
4667
9.54M
                            }
4668
9.54M
                        }
4669
2.38M
                    }
4670
46.5M
                } else {
4671
                    /* Hybrid case, additive with subtractive spots */
4672
186M
                    for (k = 0; k < (num_comp - num_spots); k++) {
4673
139M
                        dst_ptr[k * planestride] = pdst[k];
4674
139M
                    }
4675
46.8M
                    for (k = 0; k < num_spots; k++) {
4676
289k
                        dst_ptr[(k + num_comp - num_spots) * planestride] =
4677
289k
                                255 - pdst[k + num_comp - num_spots];
4678
289k
                    }
4679
46.5M
                }
4680
                /* The alpha channel */
4681
62.1M
                dst_ptr[num_comp * planestride] = pdst[num_comp];
4682
62.1M
            }
4683
776M
            if (tag_off) {
4684
                /* If src alpha is 100% then set to curr_tag, else or */
4685
                /* other than Normal BM, we always OR */
4686
0
                if (src[num_comp] == 255 && tag_blend) {
4687
0
                    dst_ptr[tag_off] = curr_tag;
4688
0
                } else {
4689
0
                    dst_ptr[tag_off] |= curr_tag;
4690
0
                }
4691
0
            }
4692
776M
            if (alpha_g_off) {
4693
410M
                int tmp = (255 - dst_ptr[alpha_g_off]) * src_alpha + 0x80;
4694
410M
                dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4695
410M
            }
4696
776M
            if (shape_off) {
4697
3.50M
                int tmp = (255 - dst_ptr[shape_off]) * shape + 0x80;
4698
3.50M
                dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4699
3.50M
            }
4700
776M
            ++dst_ptr;
4701
776M
        }
4702
101M
        dst_ptr += rowstride;
4703
101M
    }
4704
91.7M
}
4705
4706
static void
4707
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,
4708
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4709
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4710
               int alpha_g_off, int shape_off, byte shape)
4711
473k
{
4712
473k
    int i, j;
4713
4714
1.05M
    for (j = h; j > 0; --j) {
4715
73.2M
        for (i = w; i > 0; --i) {
4716
72.7M
            if (alpha_g_off) {
4717
0
                int tmp = (255 - dst_ptr[alpha_g_off]) * src_alpha + 0x80;
4718
0
                dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4719
0
            }
4720
72.7M
            if (shape_off) {
4721
0
                int tmp = (255 - dst_ptr[shape_off]) * shape + 0x80;
4722
0
                dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4723
0
            }
4724
72.7M
            ++dst_ptr;
4725
72.7M
        }
4726
581k
        dst_ptr += rowstride;
4727
581k
    }
4728
473k
}
4729
4730
static void
4731
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,
4732
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4733
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4734
               int alpha_g_off, int shape_off, byte shape)
4735
18.4M
{
4736
18.4M
    template_mark_fill_rect(w, h, dst_ptr, src, num_comp, num_spots, first_blend_spot,
4737
18.4M
               src_alpha, rowstride, planestride, additive, pdev, blend_mode,
4738
18.4M
               overprint, drawn_comps, tag_off, curr_tag,
4739
18.4M
               alpha_g_off, shape_off, shape);
4740
18.4M
}
4741
4742
static void
4743
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,
4744
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4745
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4746
               int alpha_g_off, int shape_off, byte shape)
4747
7.03M
{
4748
7.03M
    int i, j, k;
4749
4750
15.3M
    for (j = h; j > 0; --j) {
4751
300M
        for (i = w; i > 0; --i) {
4752
291M
            byte a_s = src[4];
4753
291M
            byte a_b = dst_ptr[4 * planestride];
4754
291M
            if ((a_s == 0xff) || a_b == 0) {
4755
                /* dest alpha is zero (or normal, and solid src) just use source. */
4756
291M
                dst_ptr[0 * planestride] = 255 - src[0];
4757
291M
                dst_ptr[1 * planestride] = 255 - src[1];
4758
291M
                dst_ptr[2 * planestride] = 255 - src[2];
4759
291M
                dst_ptr[3 * planestride] = 255 - src[3];
4760
                /* alpha */
4761
291M
                dst_ptr[4 * planestride] = a_s;
4762
291M
            } else if (a_s != 0) {
4763
                /* Result alpha is Union of backdrop and source alpha */
4764
94.4k
                int tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
4765
94.4k
                unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
4766
4767
                /* Compute a_s / a_r in 16.16 format */
4768
94.4k
                int src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
4769
4770
94.4k
                dst_ptr[4 * planestride] = a_r;
4771
4772
                /* Do simple compositing of source over backdrop */
4773
472k
                for (k = 0; k < 4; k++) {
4774
377k
                    int c_s = src[k];
4775
377k
                    int c_b = 255 - dst_ptr[k * planestride];
4776
377k
                    tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
4777
377k
                    dst_ptr[k * planestride] = 255 - (tmp >> 16);
4778
377k
                }
4779
94.4k
            }
4780
291M
            ++dst_ptr;
4781
291M
        }
4782
8.32M
        dst_ptr += rowstride;
4783
8.32M
    }
4784
7.03M
}
4785
4786
static void
4787
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,
4788
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4789
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4790
               int alpha_g_off, int shape_off, byte shape)
4791
68.6M
{
4792
68.6M
    template_mark_fill_rect(w, h, dst_ptr, src, num_comp, /*num_spots*/0, first_blend_spot,
4793
68.6M
               src_alpha, rowstride, planestride, /*additive*/1, pdev, blend_mode,
4794
68.6M
               /*overprint*/0, /*drawn_comps*/0, tag_off, curr_tag,
4795
68.6M
               alpha_g_off, shape_off, shape);
4796
68.6M
}
4797
4798
static void
4799
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,
4800
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4801
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4802
               int alpha_g_off, int shape_off, byte shape)
4803
4.71M
{
4804
4.71M
    template_mark_fill_rect(w, h, dst_ptr, src, num_comp, /*num_spots*/0, /*first_blend_spot*/0,
4805
4.71M
               src_alpha, rowstride, planestride, /*additive*/1, pdev, /*blend_mode*/BLEND_MODE_Normal,
4806
4.71M
               /*overprint*/0, /*drawn_comps*/0, /*tag_off*/0, curr_tag,
4807
4.71M
               alpha_g_off, /*shape_off*/0, shape);
4808
4.71M
}
4809
4810
static void
4811
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,
4812
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4813
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4814
               int alpha_g_off, int shape_off, byte shape)
4815
0
{
4816
0
    template_mark_fill_rect(w, h, dst_ptr, src, num_comp, /*num_spots*/0, /*first_blend_spot*/0,
4817
0
               src_alpha, rowstride, planestride, /*additive*/1, pdev, /*blend_mode*/BLEND_MODE_Normal,
4818
0
               /*overprint*/0, /*drawn_comps*/0, /*tag_off*/0, curr_tag,
4819
0
               /*alpha_g_off*/0, /*shape_off*/0, shape);
4820
0
}
4821
4822
static void
4823
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,
4824
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4825
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4826
               int alpha_g_off, int shape_off, byte shape)
4827
159M
{
4828
159M
    int i, j, k;
4829
4830
391M
    for (j = h; j > 0; --j) {
4831
6.46G
        for (i = w; i > 0; --i) {
4832
6.23G
            byte a_s = src[3];
4833
6.23G
            byte a_b = dst_ptr[3 * planestride];
4834
6.23G
            if (a_s == 0xff || a_b == 0) {
4835
                /* dest alpha is zero (or solid source) just use source. */
4836
6.11G
                dst_ptr[0 * planestride] = src[0];
4837
6.11G
                dst_ptr[1 * planestride] = src[1];
4838
6.11G
                dst_ptr[2 * planestride] = src[2];
4839
                /* alpha */
4840
6.11G
                dst_ptr[3 * planestride] = a_s;
4841
6.11G
            } else if (a_s != 0) {
4842
                /* Result alpha is Union of backdrop and source alpha */
4843
118M
                int tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
4844
118M
                unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
4845
                /* todo: verify that a_r is nonzero in all cases */
4846
4847
                /* Compute a_s / a_r in 16.16 format */
4848
118M
                int src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
4849
4850
118M
                dst_ptr[3 * planestride] = a_r;
4851
4852
                /* Do simple compositing of source over backdrop */
4853
475M
                for (k = 0; k < 3; k++) {
4854
356M
                    int c_s = src[k];
4855
356M
                    int c_b = dst_ptr[k * planestride];
4856
356M
                    tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
4857
356M
                    dst_ptr[k * planestride] = tmp >> 16;
4858
356M
                }
4859
118M
            }
4860
6.23G
            ++dst_ptr;
4861
6.23G
        }
4862
232M
        dst_ptr += rowstride;
4863
232M
    }
4864
159M
}
4865
4866
static void
4867
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,
4868
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4869
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4870
               int alpha_g_off, int shape_off, byte shape)
4871
39.0M
{
4872
39.0M
    int i;
4873
39.0M
    bool tag_blend = blend_mode == BLEND_MODE_Normal ||
4874
39.0M
        blend_mode == BLEND_MODE_Compatible ||
4875
270k
        blend_mode == BLEND_MODE_CompatibleOverprint;
4876
4877
78.2M
    for (; h > 0; --h) {
4878
450M
        for (i = w; i > 0; --i) {
4879
            /* background empty, nothing to change, or solid source */
4880
410M
            byte a_s = src[1];
4881
410M
            if ((blend_mode == BLEND_MODE_Normal && a_s == 0xff) || dst_ptr[planestride] == 0) {
4882
362M
                dst_ptr[0] = src[0];
4883
362M
                dst_ptr[planestride] = a_s;
4884
362M
            } else {
4885
48.6M
                art_pdf_composite_pixel_alpha_8_fast_mono(dst_ptr, src,
4886
48.6M
                                                blend_mode, pdev->blend_procs,
4887
48.6M
                                                planestride, pdev);
4888
48.6M
            }
4889
410M
            if (tag_off) {
4890
                /* If src alpha is 100% then set to curr_tag, else or */
4891
                /* other than Normal BM, we always OR */
4892
0
                if (tag_blend && a_s == 255) {
4893
0
                     dst_ptr[tag_off] = curr_tag;
4894
0
                } else {
4895
0
                    dst_ptr[tag_off] |= curr_tag;
4896
0
                }
4897
0
            }
4898
410M
            if (alpha_g_off) {
4899
180M
                int tmp = (255 - dst_ptr[alpha_g_off]) * src_alpha + 0x80;
4900
180M
                dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4901
180M
            }
4902
410M
            if (shape_off) {
4903
0
                int tmp = (255 - dst_ptr[shape_off]) * shape + 0x80;
4904
0
                dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4905
0
            }
4906
410M
            ++dst_ptr;
4907
410M
        }
4908
39.2M
        dst_ptr += rowstride;
4909
39.2M
    }
4910
39.0M
}
4911
4912
static void
4913
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,
4914
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4915
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4916
               int alpha_g_off, int shape_off, byte shape)
4917
941k
{
4918
941k
    int i;
4919
4920
1.98M
    for (; h > 0; --h) {
4921
56.5M
        for (i = w; i > 0; --i) {
4922
            /* background empty, nothing to change, or solid source */
4923
55.5M
            byte a_s = src[1];
4924
55.5M
            byte a_b = dst_ptr[planestride];
4925
55.5M
            if (a_s == 0xff || a_b == 0) {
4926
55.5M
                dst_ptr[0] = src[0];
4927
55.5M
                dst_ptr[planestride] = a_s;
4928
55.5M
            } else {
4929
                /* Result alpha is Union of backdrop and source alpha */
4930
274
                int tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
4931
274
                unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
4932
4933
                /* Compute a_s / a_r in 16.16 format */
4934
274
                int src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
4935
4936
                /* Do simple compositing of source over backdrop */
4937
274
                int c_s = src[0];
4938
274
                int c_b = dst_ptr[0];
4939
274
                tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
4940
274
                dst_ptr[0] = tmp >> 16;
4941
274
                dst_ptr[planestride] = a_r;
4942
274
            }
4943
55.5M
            if (tag_off) {
4944
                /* If src alpha is 100% then set to curr_tag, else or */
4945
                /* other than Normal BM, we always OR */
4946
0
                if (a_s == 255) {
4947
0
                     dst_ptr[tag_off] = curr_tag;
4948
0
                } else {
4949
0
                    dst_ptr[tag_off] |= curr_tag;
4950
0
                }
4951
0
            }
4952
55.5M
            if (alpha_g_off) {
4953
55.5M
                int tmp = (255 - dst_ptr[alpha_g_off]) * src_alpha + 0x80;
4954
55.5M
                dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4955
55.5M
            }
4956
55.5M
            if (shape_off) {
4957
0
                int tmp = (255 - dst_ptr[shape_off]) * shape + 0x80;
4958
0
                dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
4959
0
            }
4960
55.5M
            ++dst_ptr;
4961
55.5M
        }
4962
1.04M
        dst_ptr += rowstride;
4963
1.04M
    }
4964
941k
}
4965
4966
static void
4967
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,
4968
               byte src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
4969
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
4970
               int alpha_g_off, int shape_off, byte shape)
4971
35.4M
{
4972
35.4M
    int i;
4973
4974
83.8M
    for (; h > 0; --h) {
4975
1.52G
        for (i = w; i > 0; --i) {
4976
            /* background empty, nothing to change, or solid source */
4977
1.47G
            byte a_s = src[1];
4978
1.47G
            byte a_b = dst_ptr[planestride];
4979
1.47G
            if (a_s == 0xff || a_b == 0) {
4980
1.45G
                dst_ptr[0] = src[0];
4981
1.45G
                dst_ptr[planestride] = a_s;
4982
1.45G
            } else if (a_s != 0) {
4983
                /* Result alpha is Union of backdrop and source alpha */
4984
18.9M
                int tmp = (0xff - a_b) * (0xff - a_s) + 0x80;
4985
18.9M
                unsigned int a_r = 0xff - (((tmp >> 8) + tmp) >> 8);
4986
4987
                /* Compute a_s / a_r in 16.16 format */
4988
18.9M
                int src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
4989
4990
                /* Do simple compositing of source over backdrop */
4991
18.9M
                int c_s = src[0];
4992
18.9M
                int c_b = dst_ptr[0];
4993
18.9M
                tmp = (c_b << 16) + src_scale * (c_s - c_b) + 0x8000;
4994
18.9M
                dst_ptr[0] = tmp >> 16;
4995
18.9M
                dst_ptr[planestride] = a_r;
4996
18.9M
            }
4997
1.47G
            ++dst_ptr;
4998
1.47G
        }
4999
48.3M
        dst_ptr += rowstride;
5000
48.3M
    }
5001
35.4M
}
5002
5003
static int
5004
do_mark_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
5005
                       gx_color_index color, const gx_device_color *pdc,
5006
                       bool devn)
5007
336M
{
5008
336M
    pdf14_device *pdev = (pdf14_device *)dev;
5009
336M
    pdf14_buf *buf = pdev->ctx->stack;
5010
336M
    int j;
5011
336M
    byte *dst_ptr;
5012
336M
    byte src[PDF14_MAX_PLANES];
5013
336M
    gs_blend_mode_t blend_mode = pdev->blend_mode;
5014
336M
    bool additive = pdev->ctx->additive;
5015
336M
    intptr_t rowstride = buf->rowstride;
5016
336M
    intptr_t planestride = buf->planestride;
5017
336M
    gs_graphics_type_tag_t curr_tag = GS_UNKNOWN_TAG; /* Quite compiler */
5018
336M
    bool has_alpha_g = buf->has_alpha_g;
5019
336M
    bool has_shape = buf->has_shape;
5020
336M
    bool has_tags = buf->has_tags;
5021
336M
    int num_chan = buf->n_chan;
5022
336M
    int num_comp = num_chan - 1;
5023
336M
    intptr_t shape_off = num_chan * planestride;
5024
336M
    intptr_t alpha_g_off = shape_off + (has_shape ? planestride : 0);
5025
336M
    intptr_t tag_off = alpha_g_off + (has_alpha_g ? planestride : 0);
5026
336M
    bool overprint = pdev->op_state == GS_OP_STATE_FILL ? pdev->overprint : pdev->stroke_overprint;
5027
336M
    gx_color_index drawn_comps = pdev->op_state == GS_OP_STATE_FILL ?
5028
328M
                                     pdev->drawn_comps_fill : pdev->drawn_comps_stroke;
5029
336M
    byte shape = 0; /* Quiet compiler. */
5030
336M
    byte src_alpha;
5031
336M
    const gx_color_index mask = ((gx_color_index)1 << 8) - 1;
5032
336M
    const int shift = 8;
5033
336M
    int num_spots = buf->num_spots;
5034
336M
    int first_blend_spot = num_comp;
5035
336M
    pdf14_mark_fill_rect_fn fn;
5036
5037
    /* If we are going out to a CMYK or CMYK + spots pdf14 device (i.e.
5038
       subtractive) and we are doing overprint with drawn_comps == 0
5039
       then this is a no-operation */
5040
336M
    if (overprint && drawn_comps == 0 && !buf->group_color_info->isadditive)
5041
0
        return 0;
5042
5043
    /* This is a fix to handle the odd case where overprint is active
5044
       but drawn comps is zero due to the colorants that are present
5045
       in the sep or devicen color space.  For example, if the color
5046
       fill was cyan in a sep color space but we are drawing in a
5047
       RGB blend space.  In this case the drawn comps is 0 and we should
5048
       not be using compatible overprint mode here. */
5049
336M
    if (drawn_comps == 0 && blend_mode == BLEND_MODE_CompatibleOverprint &&
5050
0
        buf->group_color_info->isadditive) {
5051
0
        blend_mode = BLEND_MODE_Normal;
5052
0
    }
5053
5054
336M
    if (num_spots > 0 && !blend_valid_for_spot(blend_mode))
5055
0
        first_blend_spot = num_comp - num_spots;
5056
336M
    if (blend_mode == BLEND_MODE_Normal)
5057
211M
        first_blend_spot = 0;
5058
5059
336M
    if (buf->data == NULL)
5060
2.69M
        return 0;
5061
    /* NB: gx_color_index is 4 or 8 bytes */
5062
#if 0
5063
    if (sizeof(color) <= sizeof(ulong))
5064
        if_debug8m('v', dev->memory,
5065
                   "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %lx  bm %d, nc %d, overprint %d\n",
5066
                   x, y, w, h, (ulong)color, blend_mode, num_chan, overprint);
5067
    else
5068
        if_debug9m('v', dev->memory,
5069
                   "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %08lx%08lx  bm %d, nc %d, overprint %d\n",
5070
                   x, y, w, h,
5071
                   (ulong)(color >> 8*(sizeof(color) - sizeof(ulong))), (ulong)color,
5072
                   blend_mode, num_chan, overprint);
5073
#endif
5074
    /*
5075
     * Unpack the gx_color_index values.  Complement the components for subtractive
5076
     * color spaces.
5077
     */
5078
5079
333M
    if (devn) {
5080
15.7M
        if (has_tags) {
5081
0
            curr_tag = pdc->tag;
5082
0
        }
5083
15.7M
        if (additive) {
5084
9.60M
            for (j = 0; j < (num_comp - num_spots); j++) {
5085
6.79M
                src[j] = ((pdc->colors.devn.values[j]) >> shift & mask);
5086
6.79M
            }
5087
2.81M
            for (j = 0; j < num_spots; j++) {
5088
2.29k
                src[j + num_comp - num_spots] =
5089
2.29k
                    255 - ((pdc->colors.devn.values[j + num_comp - num_spots]) >> shift & mask);
5090
2.29k
            }
5091
12.9M
        } else {
5092
64.8M
            for (j = 0; j < num_comp; j++) {
5093
51.8M
                src[j] = 255 - ((pdc->colors.devn.values[j]) >> shift & mask);
5094
51.8M
            }
5095
12.9M
        }
5096
318M
    } else {
5097
318M
        if (has_tags) {
5098
0
            curr_tag = (color >> (num_comp * 8)) & 0xff;
5099
0
        }
5100
318M
        pdev->pdf14_procs->unpack_color(num_comp, color, pdev, src);
5101
318M
    }
5102
333M
    src_alpha = src[num_comp] = (byte)floor (255 * pdev->alpha + 0.5);
5103
333M
    if (has_shape)
5104
3.64k
        shape = (byte)floor (255 * pdev->shape + 0.5);
5105
    /* Fit the mark into the bounds of the buffer */
5106
333M
    if (x < buf->rect.p.x) {
5107
7.64k
        w += x - buf->rect.p.x;
5108
7.64k
        x = buf->rect.p.x;
5109
7.64k
    }
5110
333M
    if (y < buf->rect.p.y) {
5111
88.2k
      h += y - buf->rect.p.y;
5112
88.2k
      y = buf->rect.p.y;
5113
88.2k
    }
5114
333M
    if (x + w > buf->rect.q.x) w = buf->rect.q.x - x;
5115
333M
    if (y + h > buf->rect.q.y) h = buf->rect.q.y - y;
5116
    /* Update the dirty rectangle with the mark */
5117
333M
    if (x < buf->dirty.p.x) buf->dirty.p.x = x;
5118
333M
    if (y < buf->dirty.p.y) buf->dirty.p.y = y;
5119
333M
    if (x + w > buf->dirty.q.x) buf->dirty.q.x = x + w;
5120
333M
    if (y + h > buf->dirty.q.y) buf->dirty.q.y = y + h;
5121
333M
    dst_ptr = buf->data + (x - buf->rect.p.x) + (y - buf->rect.p.y) * rowstride;
5122
333M
    src_alpha = 255-src_alpha;
5123
333M
    shape = 255-shape;
5124
333M
    if (!has_alpha_g)
5125
324M
        alpha_g_off = 0;
5126
333M
    if (!has_shape)
5127
333M
        shape_off = 0;
5128
333M
    if (!has_tags)
5129
333M
        tag_off = 0;
5130
333M
    rowstride -= w;
5131
    /* The num_comp == 1 && additive case is very common (mono output
5132
     * devices no spot support), so we optimise that specifically here. */
5133
333M
    if (src[num_comp] == 0)
5134
473k
        fn = mark_fill_rect_alpha0;
5135
333M
    else if (additive && num_spots == 0) {
5136
308M
        if (num_comp == 1) {
5137
75.4M
            if (blend_mode == BLEND_MODE_Normal) {
5138
36.4M
                if (tag_off == 0 && shape_off == 0 &&  alpha_g_off == 0)
5139
35.4M
                    fn = mark_fill_rect_add1_no_spots_fast;
5140
941k
                else
5141
941k
                    fn = mark_fill_rect_add1_no_spots_normal;
5142
36.4M
            } else
5143
39.0M
                fn = mark_fill_rect_add1_no_spots;
5144
232M
        } else if (tag_off == 0 && shape_off == 0 && blend_mode == BLEND_MODE_Normal) {
5145
163M
            if (alpha_g_off == 0) {
5146
159M
                if (num_comp == 3)
5147
159M
                    fn = mark_fill_rect_add3_common;
5148
0
                else
5149
0
                    fn = mark_fill_rect_add_nospots_common_no_alpha_g;
5150
159M
            } else
5151
4.71M
                fn = mark_fill_rect_add_nospots_common;
5152
163M
        } else
5153
68.6M
            fn = mark_fill_rect_add_nospots;
5154
308M
    } else if (!additive && num_spots == 0 && num_comp == 4 &&
5155
25.4M
        first_blend_spot == 0 && blend_mode == BLEND_MODE_Normal &&
5156
7.51M
        !overprint && tag_off == 0 && alpha_g_off == 0 && shape_off == 0)
5157
7.03M
        fn = mark_fill_rect_sub4_fast;
5158
18.4M
    else
5159
18.4M
        fn = mark_fill_rect;
5160
5161
333M
    fn(w, h, dst_ptr, src, num_comp, num_spots, first_blend_spot, src_alpha,
5162
333M
       rowstride, planestride, additive, pdev, blend_mode, overprint,
5163
333M
       drawn_comps, tag_off, curr_tag, alpha_g_off, shape_off, shape);
5164
5165
#if 0
5166
/* #if RAW_DUMP */
5167
    /* Dump the current buffer to see what we have. */
5168
5169
    if(global_index/10.0 == (int) (global_index/10.0) )
5170
        dump_raw_buffer(pdev->ctx->mem,
5171
                        pdev->ctx->stack->rect.q.y-pdev->ctx->stack->rect.p.y,
5172
                        pdev->ctx->stack->rect.q.x-pdev->ctx->stack->rect.p.x,
5173
                        pdev->ctx->stack->n_planes,
5174
                        pdev->ctx->stack->planestride, pdev->ctx->stack->rowstride,
5175
                        "Draw_Rect", pdev->ctx->stack->data, pdev->ctx->stack->deep);
5176
5177
    global_index++;
5178
#endif
5179
333M
    return 0;
5180
336M
}
5181
5182
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,
5183
               uint16_t src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5184
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5185
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape);
5186
5187
static forceinline void
5188
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,
5189
               uint16_t src_alpha_, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5190
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5191
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape_)
5192
0
{
5193
0
    int i, j, k;
5194
0
    uint16_t dst[PDF14_MAX_PLANES] = { 0 };
5195
0
    uint16_t dest_alpha;
5196
    /* Expand src_alpha and shape to be 0...0x10000 rather than 0...0xffff */
5197
0
    int src_alpha = src_alpha_ + (src_alpha_>>15);
5198
0
    int shape = shape_ + (shape_>>15);
5199
0
    bool tag_blend = blend_mode == BLEND_MODE_Normal ||
5200
0
        blend_mode == BLEND_MODE_Compatible ||
5201
0
        blend_mode == BLEND_MODE_CompatibleOverprint;
5202
5203
0
    for (j = h; j > 0; --j) {
5204
0
        for (i = w; i > 0; --i) {
5205
0
            if ((blend_mode == BLEND_MODE_Normal && src[num_comp] == 0xffff && !overprint) || dst_ptr[num_comp * planestride] == 0) {
5206
                /* dest alpha is zero (or normal, and solid src) just use source. */
5207
0
                if (additive) {
5208
                    /* Hybrid case */
5209
0
                    for (k = 0; k < (num_comp - num_spots); k++) {
5210
0
                        dst_ptr[k * planestride] = src[k];
5211
0
                    }
5212
0
                    for (k = 0; k < num_spots; k++) {
5213
0
                        dst_ptr[(k + num_comp - num_spots) * planestride] =
5214
0
                                65535 - src[k + num_comp - num_spots];
5215
0
                    }
5216
0
                } else {
5217
                    /* Pure subtractive */
5218
0
                    for (k = 0; k < num_comp; k++) {
5219
0
                        dst_ptr[k * planestride] = 65535 - src[k];
5220
0
                    }
5221
0
                }
5222
                /* alpha */
5223
0
                dst_ptr[num_comp * planestride] = src[num_comp];
5224
0
            } else if (src[num_comp] != 0) {
5225
0
                uint16_t *pdst;
5226
                /* Complement subtractive planes */
5227
0
                if (!additive) {
5228
                    /* Pure subtractive */
5229
0
                    for (k = 0; k < num_comp; ++k)
5230
0
                        dst[k] = 65535 - dst_ptr[k * planestride];
5231
0
                } else {
5232
                    /* Hybrid case, additive with subtractive spots */
5233
0
                    for (k = 0; k < (num_comp - num_spots); k++) {
5234
0
                        dst[k] = dst_ptr[k * planestride];
5235
0
                    }
5236
0
                    for (k = 0; k < num_spots; k++) {
5237
0
                        dst[k + num_comp - num_spots] =
5238
0
                            65535 - dst_ptr[(k + num_comp - num_spots) * planestride];
5239
0
                    }
5240
0
                }
5241
0
                dst[num_comp] = dst_ptr[num_comp * planestride];
5242
0
                dest_alpha = dst[num_comp];
5243
0
                pdst = art_pdf_composite_pixel_alpha_16_inline(dst, src, num_comp, blend_mode, first_blend_spot,
5244
0
                            pdev->blend_procs, pdev);
5245
                /* Post blend complement for subtractive and handling of drawncomps
5246
                   if overprint.  We will have already done the compatible overprint
5247
                   mode in the above composition */
5248
0
                if (!additive && !overprint) {
5249
                    /* Pure subtractive */
5250
0
                    for (k = 0; k < num_comp; ++k)
5251
0
                        dst_ptr[k * planestride] = 65535 - pdst[k];
5252
0
                } else if (!additive && overprint) {
5253
0
                    int comps;
5254
                    /* If this is an overprint case, and alpha_r is different
5255
                       than alpha_d then we will need to adjust
5256
                       the colors of the non-drawn components here too */
5257
0
                    if (dest_alpha != pdst[num_comp] && pdst[num_comp] != 0) {
5258
                        /* dest_alpha > pdst[num_comp], and dst[num_comp] != 0.
5259
                         * Therefore dest_alpha / pdst[num_comp] <= 65535 */
5260
0
                        uint64_t scale = (uint64_t)65536 * dest_alpha / pdst[num_comp];
5261
0
                        for (k = 0, comps = drawn_comps; comps != 0; ++k, comps >>= 1) {
5262
0
                            if ((comps & 0x1) != 0) {
5263
0
                                dst_ptr[k * planestride] = 65535 - pdst[k];
5264
0
                            } else  {
5265
                                /* We need val_new = (val_old * old_alpha) / new_alpha */
5266
0
                                uint64_t val = (scale * dst_ptr[k * planestride] + 32768)>>16;
5267
0
                                if (val > 65535)
5268
0
                                    val = 65535;
5269
0
                                dst_ptr[k * planestride] = val;
5270
0
                            }
5271
0
                        }
5272
0
                    } else {
5273
0
                        for (k = 0, comps = drawn_comps; comps != 0; ++k, comps >>= 1) {
5274
0
                            if ((comps & 0x1) != 0) {
5275
0
                                dst_ptr[k * planestride] = 65535 - pdst[k];
5276
0
                            }
5277
0
                        }
5278
0
                    }
5279
0
                } else {
5280
                    /* Hybrid case, additive with subtractive spots */
5281
0
                    for (k = 0; k < (num_comp - num_spots); k++) {
5282
0
                        dst_ptr[k * planestride] = pdst[k];
5283
0
                    }
5284
0
                    for (k = 0; k < num_spots; k++) {
5285
0
                        dst_ptr[(k + num_comp - num_spots) * planestride] =
5286
0
                            65535 - pdst[k + num_comp - num_spots];
5287
0
                    }
5288
0
                }
5289
                /* The alpha channel */
5290
0
                dst_ptr[num_comp * planestride] = pdst[num_comp];
5291
0
            }
5292
0
            if (tag_off) {
5293
                /* If src alpha is 100% then set to curr_tag, else or */
5294
                /* other than Normal BM, we always OR */
5295
0
                if (src[num_comp] == 65535 && tag_blend) {
5296
0
                    dst_ptr[tag_off] = curr_tag;
5297
0
                } else {
5298
0
                    dst_ptr[tag_off] |= curr_tag;
5299
0
                }
5300
0
            }
5301
0
            if (alpha_g_off) {
5302
0
                int tmp = (65535 - dst_ptr[alpha_g_off]) * src_alpha + 0x8000;
5303
0
                dst_ptr[alpha_g_off] = 65535 - (tmp >> 16);
5304
0
            }
5305
0
            if (shape_off) {
5306
0
                int tmp = (65535 - dst_ptr[shape_off]) * shape + 0x8000;
5307
0
                dst_ptr[shape_off] = 65535 - (tmp >> 16);
5308
0
            }
5309
0
            ++dst_ptr;
5310
0
        }
5311
0
        dst_ptr += rowstride;
5312
0
    }
5313
0
}
5314
5315
static void
5316
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,
5317
               uint16_t src_alpha_, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5318
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5319
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape_)
5320
0
{
5321
0
    int i, j;
5322
0
    int src_alpha = src_alpha_;
5323
0
    int shape = shape_;
5324
5325
0
    src_alpha += src_alpha>>15;
5326
0
    shape += shape>>15;
5327
0
    for (j = h; j > 0; --j) {
5328
0
        for (i = w; i > 0; --i) {
5329
0
            if (alpha_g_off) {
5330
0
                int tmp = (65535 - dst_ptr[alpha_g_off]) * src_alpha + 0x8000;
5331
0
                dst_ptr[alpha_g_off] = 65535 - (tmp >> 16);
5332
0
            }
5333
0
            if (shape_off) {
5334
0
                int tmp = (65535 - dst_ptr[shape_off]) * shape + 0x8000;
5335
0
                dst_ptr[shape_off] = 65535 - (tmp >> 16);
5336
0
            }
5337
0
            ++dst_ptr;
5338
0
        }
5339
0
        dst_ptr += rowstride;
5340
0
    }
5341
0
}
5342
5343
static void
5344
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,
5345
               uint16_t src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5346
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5347
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape)
5348
0
{
5349
0
    template_mark_fill_rect16(w, h, dst_ptr, src, num_comp, num_spots, first_blend_spot,
5350
0
               src_alpha, rowstride, planestride, additive, pdev, blend_mode,
5351
0
               overprint, drawn_comps, tag_off, curr_tag,
5352
0
               alpha_g_off, shape_off, shape);
5353
0
}
5354
5355
static void
5356
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,
5357
               uint16_t src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5358
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5359
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape)
5360
0
{
5361
0
    int i, j, k;
5362
5363
0
    for (j = h; j > 0; --j) {
5364
0
        for (i = w; i > 0; --i) {
5365
0
            uint16_t a_s = src[4];
5366
0
            int a_b = dst_ptr[4 * planestride];
5367
0
            if ((a_s == 0xffff) || a_b == 0) {
5368
                /* dest alpha is zero (or normal, and solid src) just use source. */
5369
0
                dst_ptr[0 * planestride] = 65535 - src[0];
5370
0
                dst_ptr[1 * planestride] = 65535 - src[1];
5371
0
                dst_ptr[2 * planestride] = 65535 - src[2];
5372
0
                dst_ptr[3 * planestride] = 65535 - src[3];
5373
                /* alpha */
5374
0
                dst_ptr[4 * planestride] = a_s;
5375
0
            } else if (a_s != 0) {
5376
                /* Result alpha is Union of backdrop and source alpha */
5377
0
                unsigned int tmp, src_scale;
5378
0
                unsigned int a_r;
5379
5380
0
                a_b += a_b>>15;
5381
0
                tmp = (0x10000 - a_b) * (0xffff - a_s) + 0x8000;
5382
0
                a_r = 0xffff - (tmp >> 16);
5383
5384
                /* Compute a_s / a_r in 16.16 format */
5385
0
                src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
5386
5387
0
                dst_ptr[4 * planestride] = a_r;
5388
5389
0
                src_scale >>= 1; /* Lose a bit to avoid overflow */
5390
                /* Do simple compositing of source over backdrop */
5391
0
                for (k = 0; k < 4; k++) {
5392
0
                    int c_s = src[k];
5393
0
                    int c_b = 65535 - dst_ptr[k * planestride];
5394
0
                    tmp = src_scale * (c_s - c_b) + 0x4000;
5395
0
                    dst_ptr[k * planestride] = 0xffff - c_b - (tmp >> 15);
5396
0
                }
5397
0
            }
5398
0
            ++dst_ptr;
5399
0
        }
5400
0
        dst_ptr += rowstride;
5401
0
    }
5402
0
}
5403
5404
static void
5405
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,
5406
               uint16_t src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5407
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5408
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape)
5409
0
{
5410
0
    template_mark_fill_rect16(w, h, dst_ptr, src, num_comp, /*num_spots*/0, first_blend_spot,
5411
0
               src_alpha, rowstride, planestride, /*additive*/1, pdev, blend_mode,
5412
0
               /*overprint*/0, /*drawn_comps*/0, tag_off, curr_tag,
5413
0
               alpha_g_off, shape_off, shape);
5414
0
}
5415
5416
static void
5417
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,
5418
               uint16_t src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5419
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5420
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape)
5421
0
{
5422
0
    template_mark_fill_rect16(w, h, dst_ptr, src, num_comp, /*num_spots*/0, /*first_blend_spot*/0,
5423
0
               src_alpha, rowstride, planestride, /*additive*/1, pdev, /*blend_mode*/BLEND_MODE_Normal,
5424
0
               /*overprint*/0, /*drawn_comps*/0, /*tag_off*/0, curr_tag,
5425
0
               alpha_g_off, /*shape_off*/0, shape);
5426
0
}
5427
5428
static void
5429
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,
5430
               uint16_t src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5431
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5432
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape)
5433
0
{
5434
0
    template_mark_fill_rect16(w, h, dst_ptr, src, num_comp, /*num_spots*/0, /*first_blend_spot*/0,
5435
0
               src_alpha, rowstride, planestride, /*additive*/1, pdev, /*blend_mode*/BLEND_MODE_Normal,
5436
0
               /*overprint*/0, /*drawn_comps*/0, /*tag_off*/0, curr_tag,
5437
0
               /*alpha_g_off*/0, /*shape_off*/0, shape);
5438
0
}
5439
5440
static void
5441
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,
5442
               uint16_t src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5443
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5444
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape)
5445
0
{
5446
0
    int i, j, k;
5447
5448
0
    for (j = h; j > 0; --j) {
5449
0
        for (i = w; i > 0; --i) {
5450
0
            uint16_t a_s = src[3];
5451
0
            int a_b = dst_ptr[3 * planestride];
5452
0
            if (a_s == 0xffff || a_b == 0) {
5453
                /* dest alpha is zero (or solid source) just use source. */
5454
0
                dst_ptr[0 * planestride] = src[0];
5455
0
                dst_ptr[1 * planestride] = src[1];
5456
0
                dst_ptr[2 * planestride] = src[2];
5457
                /* alpha */
5458
0
                dst_ptr[3 * planestride] = a_s;
5459
0
            } else if (a_s != 0) {
5460
0
                unsigned int tmp, src_scale;
5461
0
                unsigned int a_r;
5462
5463
0
                a_b += a_b >> 15;
5464
                /* Result alpha is Union of backdrop and source alpha */
5465
0
                tmp = (0x10000 - a_b) * (0xffff - a_s) + 0x8000;
5466
0
                a_r = 0xffff - (tmp >> 16);
5467
                /* todo: verify that a_r is nonzero in all cases */
5468
5469
                /* Compute a_s / a_r in 16.16 format */
5470
0
                src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
5471
5472
0
                dst_ptr[3 * planestride] = a_r;
5473
5474
0
                src_scale >>= 1; /* Lose a bit to avoid overflow */
5475
                /* Do simple compositing of source over backdrop */
5476
0
                for (k = 0; k < 3; k++) {
5477
0
                    int c_s = src[k];
5478
0
                    int c_b = dst_ptr[k * planestride];
5479
0
                    tmp = src_scale * (c_s - c_b) + 0x4000;
5480
0
                    dst_ptr[k * planestride] = c_b + (tmp >> 15);
5481
0
                }
5482
0
            }
5483
0
            ++dst_ptr;
5484
0
        }
5485
0
        dst_ptr += rowstride;
5486
0
    }
5487
0
}
5488
5489
static void
5490
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,
5491
               uint16_t src_alpha_, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5492
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5493
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape_)
5494
0
{
5495
0
    int i;
5496
0
    int src_alpha = src_alpha_;
5497
0
    int shape = shape_;
5498
0
    bool tag_blend = blend_mode == BLEND_MODE_Normal ||
5499
0
        blend_mode == BLEND_MODE_Compatible ||
5500
0
        blend_mode == BLEND_MODE_CompatibleOverprint;
5501
5502
0
    src_alpha += src_alpha>>15;
5503
0
    shape += shape>>15;
5504
0
    for (; h > 0; --h) {
5505
0
        for (i = w; i > 0; --i) {
5506
            /* background empty, nothing to change, or solid source */
5507
0
            uint16_t a_s = src[1];
5508
0
            if ((blend_mode == BLEND_MODE_Normal && a_s == 0xffff) || dst_ptr[planestride] == 0) {
5509
0
                dst_ptr[0] = src[0];
5510
0
                dst_ptr[planestride] = a_s;
5511
0
            } else {
5512
0
                art_pdf_composite_pixel_alpha_16_fast_mono(dst_ptr, src,
5513
0
                                                blend_mode, pdev->blend_procs,
5514
0
                                                planestride, pdev);
5515
0
            }
5516
0
            if (tag_off) {
5517
                /* If src alpha is 100% then set to curr_tag, else or */
5518
                /* other than Normal BM, we always OR */
5519
0
                if (tag_blend && a_s == 65535) {
5520
0
                     dst_ptr[tag_off] = curr_tag;
5521
0
                } else {
5522
0
                    dst_ptr[tag_off] |= curr_tag;
5523
0
                }
5524
0
            }
5525
0
            if (alpha_g_off) {
5526
0
                int tmp = (65535 - dst_ptr[alpha_g_off]) * src_alpha + 0x8000;
5527
0
                dst_ptr[alpha_g_off] = 65535 - (tmp >> 16);
5528
0
            }
5529
0
            if (shape_off) {
5530
0
                int tmp = (65535 - dst_ptr[shape_off]) * shape + 0x8000;
5531
0
                dst_ptr[shape_off] = 65535 - (tmp >> 16);
5532
0
            }
5533
0
            ++dst_ptr;
5534
0
        }
5535
0
        dst_ptr += rowstride;
5536
0
    }
5537
0
}
5538
5539
static void
5540
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,
5541
               uint16_t src_alpha_, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5542
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5543
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape_)
5544
0
{
5545
0
    int i;
5546
0
    int src_alpha = src_alpha_;
5547
0
    int shape = shape_;
5548
5549
0
    src_alpha += src_alpha>>15;
5550
0
    shape += shape>>15;
5551
5552
0
    for (; h > 0; --h) {
5553
0
        for (i = w; i > 0; --i) {
5554
            /* background empty, nothing to change, or solid source */
5555
0
            uint16_t a_s = src[1];
5556
0
            uint16_t a_b = dst_ptr[planestride];
5557
0
            if (a_s == 0xffff || a_b == 0) {
5558
0
                dst_ptr[0] = src[0];
5559
0
                dst_ptr[planestride] = a_s;
5560
0
            } else {
5561
                /* Result alpha is Union of backdrop and source alpha */
5562
0
                unsigned int tmp, src_scale;
5563
0
                unsigned int a_r;
5564
0
                int c_s, c_b;
5565
5566
0
                a_b += a_b>>15;
5567
0
                tmp = (0x10000 - a_b) * (0xffff - a_s) + 0x8000;
5568
0
                a_r = 0xffff - (tmp >> 16);
5569
5570
                /* Compute a_s / a_r in 16.16 format */
5571
0
                src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
5572
5573
0
                src_scale >>= 1; /* Lose a bit to avoid overflow */
5574
                /* Do simple compositing of source over backdrop */
5575
0
                c_s = src[0];
5576
0
                c_b = dst_ptr[0];
5577
0
                tmp = src_scale * (c_s - c_b) + 0x4000;
5578
0
                dst_ptr[0] = c_b + (tmp >> 15);
5579
0
                dst_ptr[planestride] = a_r;
5580
0
            }
5581
0
            if (tag_off) {
5582
                /* If src alpha is 100% then set to curr_tag, else or */
5583
                /* other than Normal BM, we always OR */
5584
0
                if (a_s == 65535) {
5585
0
                     dst_ptr[tag_off] = curr_tag;
5586
0
                } else {
5587
0
                    dst_ptr[tag_off] |= curr_tag;
5588
0
                }
5589
0
            }
5590
0
            if (alpha_g_off) {
5591
0
                int tmp = (65535 - dst_ptr[alpha_g_off]) * src_alpha + 0x8000;
5592
0
                dst_ptr[alpha_g_off] = 65535 - (tmp >> 16);
5593
0
            }
5594
0
            if (shape_off) {
5595
0
                int tmp = (65535 - dst_ptr[shape_off]) * shape + 0x8000;
5596
0
                dst_ptr[shape_off] = 65535 - (tmp >> 16);
5597
0
            }
5598
0
            ++dst_ptr;
5599
0
        }
5600
0
        dst_ptr += rowstride;
5601
0
    }
5602
0
}
5603
5604
static void
5605
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,
5606
               uint16_t src_alpha, intptr_t rowstride, intptr_t planestride, bool additive, pdf14_device *pdev, gs_blend_mode_t blend_mode,
5607
               bool overprint, gx_color_index drawn_comps, int tag_off, gs_graphics_type_tag_t curr_tag,
5608
               intptr_t alpha_g_off, intptr_t shape_off, uint16_t shape)
5609
0
{
5610
0
    int i;
5611
5612
0
    for (; h > 0; --h) {
5613
0
        for (i = w; i > 0; --i) {
5614
            /* background empty, nothing to change, or solid source */
5615
0
            uint16_t a_s = src[1];
5616
0
            int a_b = dst_ptr[planestride];
5617
0
            if (a_s == 0xffff || a_b == 0) {
5618
0
                dst_ptr[0] = src[0];
5619
0
                dst_ptr[planestride] = a_s;
5620
0
            } else if (a_s != 0) {
5621
                /* Result alpha is Union of backdrop and source alpha */
5622
0
                unsigned int tmp, src_scale;
5623
0
                unsigned int a_r;
5624
0
                int c_s, c_b;
5625
5626
0
                a_b += a_b>>15;
5627
0
                tmp = (0x10000 - a_b) * (0xffff - a_s) + 0x8000;
5628
0
                a_r = 0xffff - (tmp >> 16);
5629
5630
                /* Compute a_s / a_r in 16.16 format */
5631
0
                src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
5632
5633
0
                src_scale >>= 1; /* Lose a bit to avoid overflow */
5634
                /* Do simple compositing of source over backdrop */
5635
0
                c_s = src[0];
5636
0
                c_b = dst_ptr[0];
5637
0
                tmp = src_scale * (c_s - c_b) + 0x4000;
5638
0
                dst_ptr[0] = c_b + (tmp >> 15);
5639
0
                dst_ptr[planestride] = a_r;
5640
0
            }
5641
0
            ++dst_ptr;
5642
0
        }
5643
0
        dst_ptr += rowstride;
5644
0
    }
5645
0
}
5646
5647
static int
5648
do_mark_fill_rectangle16(gx_device * dev, int x, int y, int w, int h,
5649
                         gx_color_index color, const gx_device_color *pdc,
5650
                         bool devn)
5651
0
{
5652
0
    pdf14_device *pdev = (pdf14_device *)dev;
5653
0
    pdf14_buf *buf = pdev->ctx->stack;
5654
0
    int j;
5655
0
    uint16_t *dst_ptr;
5656
0
    uint16_t src[PDF14_MAX_PLANES];
5657
0
    gs_blend_mode_t blend_mode = pdev->blend_mode;
5658
0
    bool additive = pdev->ctx->additive;
5659
0
    intptr_t rowstride = buf->rowstride;
5660
0
    intptr_t planestride = buf->planestride;
5661
0
    gs_graphics_type_tag_t curr_tag = GS_UNKNOWN_TAG; /* Quite compiler */
5662
0
    bool has_alpha_g = buf->has_alpha_g;
5663
0
    bool has_shape = buf->has_shape;
5664
0
    bool has_tags = buf->has_tags;
5665
0
    int num_chan = buf->n_chan;
5666
0
    int num_comp = num_chan - 1;
5667
0
    intptr_t shape_off = num_chan * planestride;
5668
0
    intptr_t alpha_g_off = shape_off + (has_shape ? planestride : 0);
5669
0
    intptr_t tag_off = alpha_g_off + (has_alpha_g ? planestride : 0);
5670
0
    bool overprint = pdev->op_state == GS_OP_STATE_FILL ? pdev->overprint : pdev->stroke_overprint;
5671
0
    gx_color_index drawn_comps = pdev->op_state == GS_OP_STATE_FILL ?
5672
0
                                 pdev->drawn_comps_fill : pdev->drawn_comps_stroke;
5673
0
    uint16_t shape = 0; /* Quiet compiler. */
5674
0
    uint16_t src_alpha;
5675
0
    int num_spots = buf->num_spots;
5676
0
    int first_blend_spot = num_comp;
5677
0
    pdf14_mark_fill_rect16_fn fn;
5678
5679
   /* If we are going out to a CMYK or CMYK + spots pdf14 device (i.e.
5680
   subtractive) and we are doing overprint with drawn_comps == 0
5681
   then this is a no-operation */
5682
0
    if (overprint && drawn_comps == 0 && !buf->group_color_info->isadditive)
5683
0
        return 0;
5684
5685
  /* This is a fix to handle the odd case where overprint is active
5686
   but drawn comps is zero due to the colorants that are present
5687
   in the sep or devicen color space.  For example, if the color
5688
   fill was cyan in a sep color space but we are drawing in a
5689
   RGB blend space.  In this case the drawn comps is 0 and we should
5690
   not be using compatible overprint mode here. */
5691
0
    if (drawn_comps == 0 && blend_mode == BLEND_MODE_CompatibleOverprint &&
5692
0
        buf->group_color_info->isadditive) {
5693
0
        blend_mode = BLEND_MODE_Normal;
5694
0
    }
5695
5696
0
    if (num_spots > 0 && !blend_valid_for_spot(blend_mode))
5697
0
        first_blend_spot = num_comp - num_spots;
5698
0
    if (blend_mode == BLEND_MODE_Normal)
5699
0
        first_blend_spot = 0;
5700
5701
0
    if (buf->data == NULL)
5702
0
        return 0;
5703
    /* NB: gx_color_index is 4 or 8 bytes */
5704
#if 0
5705
    if (sizeof(color) <= sizeof(ulong))
5706
        if_debug8m('v', dev->memory,
5707
                   "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %lx  bm %d, nc %d, overprint %d\n",
5708
                   x, y, w, h, (ulong)color, blend_mode, num_chan, overprint);
5709
    else
5710
        if_debug9m('v', dev->memory,
5711
                   "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %08lx%08lx  bm %d, nc %d, overprint %d\n",
5712
                   x, y, w, h,
5713
                   (ulong)(color >> 8*(sizeof(color) - sizeof(ulong))), (ulong)color,
5714
                   blend_mode, num_chan, overprint);
5715
#endif
5716
    /*
5717
     * Unpack the gx_color_index values.  Complement the components for subtractive
5718
     * color spaces.
5719
     */
5720
0
    if (devn) {
5721
0
        if (has_tags) {
5722
0
            curr_tag = pdc->tag;
5723
0
        }
5724
0
        if (additive) {
5725
0
            for (j = 0; j < (num_comp - num_spots); j++) {
5726
0
                src[j] = pdc->colors.devn.values[j];
5727
0
            }
5728
0
            for (j = 0; j < num_spots; j++) {
5729
0
                src[j + num_comp - num_spots] =
5730
0
                    65535 - pdc->colors.devn.values[j + num_comp - num_spots];
5731
0
            }
5732
0
        } else {
5733
0
            for (j = 0; j < num_comp; j++) {
5734
0
                src[j] = 65535 - pdc->colors.devn.values[j];
5735
0
            }
5736
0
        }
5737
0
    } else {
5738
0
        if (has_tags) {
5739
0
            curr_tag = (color >> (num_comp * 16)) & 0xff;
5740
0
        }
5741
0
        pdev->pdf14_procs->unpack_color16(num_comp, color, pdev, src);
5742
0
    }
5743
0
    src_alpha = src[num_comp] = (uint16_t)floor (65535 * pdev->alpha + 0.5);
5744
0
    if (has_shape)
5745
0
        shape = (uint16_t)floor (65535 * pdev->shape + 0.5);
5746
    /* Fit the mark into the bounds of the buffer */
5747
0
    if (x < buf->rect.p.x) {
5748
0
        w += x - buf->rect.p.x;
5749
0
        x = buf->rect.p.x;
5750
0
    }
5751
0
    if (y < buf->rect.p.y) {
5752
0
      h += y - buf->rect.p.y;
5753
0
      y = buf->rect.p.y;
5754
0
    }
5755
0
    if (x + w > buf->rect.q.x) w = buf->rect.q.x - x;
5756
0
    if (y + h > buf->rect.q.y) h = buf->rect.q.y - y;
5757
    /* Update the dirty rectangle with the mark */
5758
0
    if (x < buf->dirty.p.x) buf->dirty.p.x = x;
5759
0
    if (y < buf->dirty.p.y) buf->dirty.p.y = y;
5760
0
    if (x + w > buf->dirty.q.x) buf->dirty.q.x = x + w;
5761
0
    if (y + h > buf->dirty.q.y) buf->dirty.q.y = y + h;
5762
0
    dst_ptr = (uint16_t *)(buf->data + (x - buf->rect.p.x) * 2 + (y - buf->rect.p.y) * rowstride);
5763
0
    src_alpha = 65535-src_alpha;
5764
0
    shape = 65535-shape;
5765
0
    if (!has_alpha_g)
5766
0
        alpha_g_off = 0;
5767
0
    if (!has_shape)
5768
0
        shape_off = 0;
5769
0
    if (!has_tags)
5770
0
        tag_off = 0;
5771
0
    rowstride -= w<<1;
5772
    /* The num_comp == 1 && additive case is very common (mono output
5773
     * devices no spot support), so we optimise that specifically here. */
5774
0
    if (src[num_comp] == 0)
5775
0
        fn = mark_fill_rect16_alpha0;
5776
0
    else if (additive && num_spots == 0) {
5777
0
        if (num_comp == 1) {
5778
0
            if (blend_mode == BLEND_MODE_Normal) {
5779
0
                if (tag_off == 0 && shape_off == 0 &&  alpha_g_off == 0)
5780
0
                    fn = mark_fill_rect16_add1_no_spots_fast;
5781
0
                else
5782
0
                    fn = mark_fill_rect16_add1_no_spots_normal;
5783
0
            } else
5784
0
                fn = mark_fill_rect16_add1_no_spots;
5785
0
        } else if (tag_off == 0 && shape_off == 0 && blend_mode == BLEND_MODE_Normal) {
5786
0
            if (alpha_g_off == 0) {
5787
0
                if (num_comp == 3)
5788
0
                    fn = mark_fill_rect16_add3_common;
5789
0
                else
5790
0
                    fn = mark_fill_rect16_add_nospots_common_no_alpha_g;
5791
0
            } else
5792
0
                fn = mark_fill_rect16_add_nospots_common;
5793
0
        } else
5794
0
            fn = mark_fill_rect16_add_nospots;
5795
0
    } else if (!additive && num_spots == 0 && num_comp == 4 && num_spots == 0 &&
5796
0
        first_blend_spot == 0 && blend_mode == BLEND_MODE_Normal &&
5797
0
        !overprint && tag_off == 0 && alpha_g_off == 0 && shape_off == 0)
5798
0
        fn = mark_fill_rect16_sub4_fast;
5799
0
    else
5800
0
        fn = mark_fill_rect16;
5801
5802
    /* Pass values as array offsets, not byte diffs */
5803
0
    rowstride >>= 1;
5804
0
    planestride >>= 1;
5805
0
    tag_off >>= 1;
5806
0
    alpha_g_off >>= 1;
5807
0
    shape_off >>= 1;
5808
0
    fn(w, h, dst_ptr, src, num_comp, num_spots, first_blend_spot, src_alpha,
5809
0
       rowstride, planestride, additive, pdev, blend_mode, overprint,
5810
0
       drawn_comps, tag_off, curr_tag, alpha_g_off, shape_off, shape);
5811
5812
#if 0
5813
/* #if RAW_DUMP */
5814
    /* Dump the current buffer to see what we have. */
5815
5816
    if(global_index/10.0 == (int) (global_index/10.0) )
5817
        dump_raw_buffer(pdev->ctx->mem,
5818
                        pdev->ctx->stack->rect.q.y-pdev->ctx->stack->rect.p.y,
5819
                        pdev->ctx->stack->rect.q.x-pdev->ctx->stack->rect.p.x,
5820
                        pdev->ctx->stack->n_planes,
5821
                        pdev->ctx->stack->planestride, pdev->ctx->stack->rowstride,
5822
                        "Draw_Rect", pdev->ctx->stack->data, pdev->ctx->stack->deep);
5823
5824
    global_index++;
5825
#endif
5826
0
    return 0;
5827
0
}
5828
5829
int
5830
pdf14_mark_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
5831
                          gx_color_index color, const gx_device_color *pdc,
5832
                          bool devn)
5833
336M
{
5834
336M
    pdf14_device *pdev = (pdf14_device *)dev;
5835
336M
    pdf14_buf *buf = pdev->ctx->stack;
5836
5837
336M
    if (buf->deep)
5838
0
        return do_mark_fill_rectangle16(dev, x, y, w, h, color, pdc, devn);
5839
336M
    else
5840
336M
        return do_mark_fill_rectangle(dev, x, y, w, h, color, pdc, devn);
5841
336M
}
5842
5843
/* Keep this at the end because of the #undef print */
5844
5845
#ifdef TRACK_COMPOSE_GROUPS
5846
static void
5847
dump_track_compose_groups(void)
5848
{
5849
    int i;
5850
5851
    for (i = 0; i < (1<<17); i++)
5852
    {
5853
        if (compose_groups[i] == 0)
5854
            continue;
5855
#undef printf
5856
        printf("COMPOSE_GROUPS: %04x:%d\n", i, compose_groups[i]);
5857
    }
5858
}
5859
#endif