Coverage Report

Created: 2025-06-10 07:17

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