Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gximag3x.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 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
17
/* ImageType 3x image implementation */
18
/****** THE REAL WORK IS NYI ******/
19
#include "math_.h"    /* for ceil, floor */
20
#include "memory_.h"
21
#include "gx.h"
22
#include "gserrors.h"
23
#include "gsbitops.h"
24
#include "gscspace.h"
25
#include "gscpixel.h"
26
#include "gsstruct.h"
27
#include "gxdevice.h"
28
#include "gxdevmem.h"
29
#include "gximag3x.h"
30
#include "gxgstate.h"
31
#include "gdevbbox.h"
32
#include <limits.h> /* For INT_MAX etc */
33
34
extern_st(st_color_space);
35
36
/* Forward references */
37
static dev_proc_begin_typed_image(gx_begin_image3x);
38
static image_enum_proc_plane_data(gx_image3x_plane_data);
39
static image_enum_proc_end_image(gx_image3x_end_image);
40
static image_enum_proc_flush(gx_image3x_flush);
41
static image_enum_proc_planes_wanted(gx_image3x_planes_wanted);
42
43
/* GC descriptor */
44
private_st_gs_image3x();
45
46
/* Define the image type for ImageType 3x images. */
47
const gx_image_type_t gs_image_type_3x = {
48
    &st_gs_image3x, gx_begin_image3x,
49
    gx_image_no_sput, gx_image_no_sget, gx_image_default_release,
50
    IMAGE3X_IMAGETYPE
51
};
52
static const gx_image_enum_procs_t image3x_enum_procs = {
53
    gx_image3x_plane_data, gx_image3x_end_image,
54
    gx_image3x_flush, gx_image3x_planes_wanted
55
};
56
57
/* Initialize an ImageType 3x image. */
58
static void
59
gs_image3x_mask_init(gs_image3x_mask_t *pimm)
60
6.27k
{
61
6.27k
    pimm->InterleaveType = 0; /* not a valid type */
62
6.27k
    pimm->has_Matte = false;
63
6.27k
    gs_data_image_t_init(&pimm->MaskDict, 1);
64
6.27k
    pimm->MaskDict.BitsPerComponent = 0;  /* not supplied */
65
6.27k
}
66
void
67
gs_image3x_t_init(gs_image3x_t * pim, gs_color_space * color_space)
68
3.13k
{
69
3.13k
    gs_pixel_image_t_init((gs_pixel_image_t *) pim, color_space);
70
3.13k
    pim->type = &gs_image_type_3x;
71
3.13k
    gs_image3x_mask_init(&pim->Opacity);
72
3.13k
    gs_image3x_mask_init(&pim->Shape);
73
3.13k
}
74
75
/*
76
 * We implement ImageType 3 images by interposing a mask clipper in
77
 * front of an ordinary ImageType 1 image.  Note that we build up the
78
 * mask row-by-row as we are processing the image.
79
 *
80
 * We export a generalized form of the begin_image procedure for use by
81
 * the PDF and PostScript writers.
82
 */
83
84
typedef struct image3x_channel_state_s {
85
    gx_image_enum_common_t *info;
86
    gx_device *mdev;    /* gx_device_memory in default impl. */
87
                                /* (only for masks) */
88
    gs_image3_interleave_type_t InterleaveType;
89
    int width, height, full_height, depth;
90
    byte *data;     /* (if chunky) */
91
    /* Only the following change dynamically. */
92
    int y;
93
    int skip;     /* only for masks, # of rows to skip, */
94
                                /* see below */
95
} image3x_channel_state_t;
96
typedef struct gx_image3x_enum_s {
97
    gx_image_enum_common;
98
    gx_device *pcdev;   /* gx_device_mask_clip in default impl. */
99
    int num_components;   /* (not counting masks) */
100
    int bpc;      /* pixel BitsPerComponent */
101
3.09M
#define NUM_MASKS 2    /* opacity, shape */
102
    image3x_channel_state_t mask[NUM_MASKS], pixel;
103
} gx_image3x_enum_t;
104
105
extern_st(st_gx_image_enum_common);
106
gs_private_st_suffix_add9(st_image3x_enum, gx_image3x_enum_t,
107
  "gx_image3x_enum_t", image3x_enum_enum_ptrs, image3x_enum_reloc_ptrs,
108
  st_gx_image_enum_common, pcdev, mask[0].info, mask[0].mdev, mask[0].data,
109
  mask[1].info, mask[1].mdev, mask[1].data, pixel.info, pixel.data);
110
111
/*
112
 * Begin a generic ImageType 3x image, with client handling the creation of
113
 * the mask image and mask clip devices.
114
 */
115
typedef struct image3x_channel_values_s {
116
    gs_matrix matrix;
117
    gs_point corner;
118
    gs_int_rect rect;
119
    gs_image_t image;
120
} image3x_channel_values_t;
121
static int check_image3x_mask(const gs_image3x_t *pim,
122
                               const gs_image3x_mask_t *pimm,
123
                               const image3x_channel_values_t *ppcv,
124
                               image3x_channel_values_t *pmcv,
125
                               image3x_channel_state_t *pmcs,
126
                               gs_memory_t *mem);
127
int
128
gx_begin_image3x_generic(gx_device * dev,
129
                        const gs_gstate *pgs, const gs_matrix *pmat,
130
                        const gs_image_common_t *pic, const gs_int_rect *prect,
131
                        const gx_drawing_color *pdcolor,
132
                        const gx_clip_path *pcpath, gs_memory_t *mem,
133
                        image3x_make_mid_proc_t make_mid,
134
                        image3x_make_mcde_proc_t make_mcde,
135
                        gx_image_enum_common_t **pinfo, char *OC)
136
3.07k
{
137
3.07k
    const gs_image3x_t *pim = (const gs_image3x_t *)pic;
138
3.07k
    gx_image3x_enum_t *penum;
139
3.07k
    gx_device *pcdev = 0;
140
3.07k
    image3x_channel_values_t mask[2], pixel;
141
3.07k
    gs_matrix mat;
142
3.07k
    gx_device *midev[2];
143
3.07k
    gx_image_enum_common_t *minfo[2];
144
3.07k
    gs_int_point origin[2];
145
3.07k
    int code;
146
3.07k
    int i;
147
3.07k
    gs_color_space *pmcs = NULL;
148
149
    /* Validate the parameters. */
150
3.07k
    if (pim->Height <= 0)
151
0
        return_error(gs_error_rangecheck);
152
3.07k
    penum = gs_alloc_struct(mem, gx_image3x_enum_t, &st_image3x_enum,
153
3.07k
                            "gx_begin_image3x");
154
3.07k
    if (penum == 0)
155
0
        return_error(gs_error_VMerror);
156
    /* Initialize pointers now in case we bail out. */
157
3.07k
    penum->mask[0].info = 0, penum->mask[0].mdev = 0, penum->mask[0].data = 0;
158
3.07k
    penum->mask[1].info = 0, penum->mask[1].mdev = 0, penum->mask[1].data = 0;
159
3.07k
    penum->pixel.info = 0, penum->pixel.data = 0;
160
3.07k
    if (prect)
161
0
        pixel.rect = *prect;
162
3.07k
    else {
163
3.07k
        pixel.rect.p.x = pixel.rect.p.y = 0;
164
3.07k
        pixel.rect.q.x = pim->Width;
165
3.07k
        pixel.rect.q.y = pim->Height;
166
3.07k
    }
167
3.07k
    if ((code = gs_matrix_invert(&pim->ImageMatrix, &pixel.matrix)) < 0 ||
168
3.07k
        (code = gs_point_transform(pim->Width, pim->Height, &pixel.matrix,
169
3.07k
                                   &pixel.corner)) < 0 ||
170
3.07k
        (code = check_image3x_mask(pim, &pim->Opacity, &pixel, &mask[0],
171
3.07k
                                   &penum->mask[0], mem)) < 0 ||
172
3.07k
        (code = check_image3x_mask(pim, &pim->Shape, &pixel, &mask[1],
173
3.06k
                                   &penum->mask[1], mem)) < 0
174
3.07k
        ) {
175
7
        goto out0;
176
7
    }
177
3.06k
    penum->num_components =
178
3.06k
        gs_color_space_num_components(pim->ColorSpace);
179
3.06k
    gx_image_enum_common_init((gx_image_enum_common_t *) penum,
180
3.06k
                              (const gs_data_image_t *)pim,
181
3.06k
                              &image3x_enum_procs, dev,
182
3.06k
                              1 + penum->num_components,
183
3.06k
                              pim->format);
184
3.06k
    penum->pixel.width = pixel.rect.q.x - pixel.rect.p.x;
185
3.06k
    penum->pixel.height = pixel.rect.q.y - pixel.rect.p.y;
186
3.06k
    penum->pixel.full_height = pim->Height;
187
3.06k
    penum->pixel.y = 0;
188
3.06k
    if (penum->mask[0].data || penum->mask[1].data) {
189
        /* Also allocate a row buffer for the pixel data. */
190
0
        penum->pixel.data =
191
0
            gs_alloc_bytes(mem,
192
0
                           (penum->pixel.width * pim->BitsPerComponent *
193
0
                            penum->num_components + 7) >> 3,
194
0
                           "gx_begin_image3x(pixel.data)");
195
0
        if (penum->pixel.data == 0) {
196
0
            code = gs_note_error(gs_error_VMerror);
197
0
            goto out1;
198
0
        }
199
0
    }
200
3.06k
    penum->bpc = pim->BitsPerComponent;
201
3.06k
    penum->memory = mem;
202
3.06k
    if (pmat == 0)
203
3.06k
        pmat = &ctm_only(pgs);
204
9.19k
    for (i = 0; i < NUM_MASKS; ++i) {
205
6.13k
        gs_rect mrect;
206
6.13k
        gx_device *mdev;
207
        /*
208
         * The mask data has to be defined in a DevicePixel color space
209
         * of the correct depth so that no color mapping will occur.
210
         */
211
6.13k
        if (penum->mask[i].depth == 0) { /* mask not supplied */
212
3.06k
            midev[i] = 0;
213
3.06k
            minfo[i] = 0;
214
3.06k
            continue;
215
3.06k
        }
216
3.06k
        code = gs_cspace_new_DevicePixel(mem, &pmcs, penum->mask[i].depth);
217
3.06k
        if (code < 0)
218
0
            goto out1;
219
3.06k
        mrect.p.x = mrect.p.y = 0;
220
3.06k
        mrect.q.x = penum->mask[i].width;
221
3.06k
        mrect.q.y = penum->mask[i].height;
222
3.06k
        if ((code = gs_matrix_multiply(&mask[i].matrix, pmat, &mat)) < 0 ||
223
3.06k
            (code = gs_bbox_transform(&mrect, &mat, &mrect)) < 0
224
3.06k
            )
225
0
            goto out1;
226
227
        /* Bug 700438: If the rectangle is out of range, bail */
228
3.06k
        if (mrect.p.x >= (double)INT_MAX || mrect.q.x <= (double)INT_MIN ||
229
3.06k
            mrect.p.y >= (double)INT_MAX || mrect.q.y <= (double)INT_MIN) {
230
2
            code = gs_note_error(gs_error_rangecheck);
231
2
            goto out1;
232
2
        }
233
234
        /* This code was changed for bug 686843/687411, but in a way that
235
         * a) looked wrong, and b) doesn't appear to make a difference. Revert
236
         * it to the sane version until we have evidence why not. */
237
3.06k
        origin[i].x = (int)floor(mrect.p.x);
238
3.06k
        origin[i].y = (int)floor(mrect.p.y);
239
3.06k
        code = make_mid(&mdev, dev,
240
3.06k
                        (int)ceil(mrect.q.x) - origin[i].x,
241
3.06k
                        (int)ceil(mrect.q.y) - origin[i].y,
242
3.06k
                        penum->mask[i].depth, mem);
243
3.06k
        if (code < 0)
244
0
            goto out1;
245
3.06k
        code = dev_proc(dev, get_profile)(dev, &mdev->icc_struct);
246
3.06k
        if (code < 0)
247
0
            goto out1;  /* Device not yet open */
248
3.06k
        rc_increment(mdev->icc_struct);
249
3.06k
        penum->mask[i].mdev = mdev;
250
3.06k
        gs_image_t_init(&mask[i].image, pmcs);
251
3.06k
        mask[i].image.ColorSpace = pmcs;
252
3.06k
        mask[i].image.adjust = false;
253
3.06k
        mask[i].image.image_parent_type = gs_image_type3x;
254
3.06k
        {
255
3.06k
            const gx_image_type_t *type1 = mask[i].image.type;
256
3.06k
            const gs_image3x_mask_t *pixm =
257
3.06k
                (i == 0 ? &pim->Opacity : &pim->Shape);
258
259
            /* Use memcpy because direct assignment breaks ANSI aliasing */
260
            /* rules and causes SEGV with gcc 4.5.1 */
261
3.06k
            memcpy(&mask[i].image, &pixm->MaskDict, sizeof(pixm->MaskDict));
262
3.06k
            mask[i].image.type = type1;
263
3.06k
            mask[i].image.BitsPerComponent = pixm->MaskDict.BitsPerComponent;
264
3.06k
        }
265
3.06k
        {
266
3.06k
            gs_matrix m_mat;
267
268
            /*
269
             * Adjust the translation for rendering the mask to include a
270
             * negative translation by origin.{x,y} in device space.
271
             */
272
3.06k
            m_mat = *pmat;
273
3.06k
            m_mat.tx -= origin[i].x;
274
3.06k
            m_mat.ty -= origin[i].y;
275
            /*
276
             * Peter put in a comment that said " Note that pgs = NULL here,
277
             * since we don't want to have to create another gs_gstate with
278
             * default log_op, etc." and passed NULL instead of pgs to this
279
             * routine.  However Image type 1 need the gs_gstate (see
280
             * bug 688348) thus his optimization was removed.
281
             * dcolor = NULL is OK because this is an opaque image with
282
             * CombineWithColor = false.
283
             */
284
3.06k
            code = gx_device_begin_typed_image(mdev, pgs, &m_mat,
285
3.06k
                               (const gs_image_common_t *)&mask[i].image,
286
3.06k
                                               &mask[i].rect, NULL, NULL,
287
3.06k
                                               mem, &penum->mask[i].info);
288
3.06k
            if (code < 0)
289
0
                goto out2;
290
3.06k
        }
291
3.06k
        midev[i] = mdev;
292
3.06k
        minfo[i] = penum->mask[i].info;
293
3.06k
        rc_decrement_only(pmcs, "gx_begin_image3x_generic(pmcs)");
294
3.06k
        pmcs = NULL;
295
3.06k
    }
296
3.06k
    gs_image_t_init(&pixel.image, pim->ColorSpace);
297
3.06k
    {
298
3.06k
        const gx_image_type_t *type1 = pixel.image.type;
299
300
3.06k
        *(gs_pixel_image_t *)&pixel.image = *(const gs_pixel_image_t *)pim;
301
3.06k
        pixel.image.type = type1;
302
3.06k
        pixel.image.image_parent_type = gs_image_type3x;
303
3.06k
    }
304
3.06k
    if (minfo[0] != NULL)
305
3.06k
        minfo[0]->OC = OC;
306
307
3.06k
    code = make_mcde(dev, pgs, pmat, (const gs_image_common_t *)&pixel.image,
308
3.06k
                     prect, pdcolor, pcpath, mem, &penum->pixel.info,
309
3.06k
                     &pcdev, midev, minfo, origin, pim);
310
3.06k
    if (code < 0)
311
0
        goto out3;
312
3.06k
    penum->pcdev = pcdev;
313
    /*
314
     * Set num_planes, plane_widths, and plane_depths from the values in the
315
     * enumerators for the mask(s) and the image data.
316
     */
317
3.06k
    {
318
3.06k
        int added_depth = 0;
319
3.06k
        int pi = 0;
320
321
9.19k
        for (i = 0; i < NUM_MASKS; ++i) {
322
6.13k
            if (penum->mask[i].depth == 0)  /* no mask */
323
3.06k
                continue;
324
3.06k
            switch (penum->mask[i].InterleaveType) {
325
0
            case interleave_chunky:
326
                /* Add the mask data to the depth of the image data. */
327
0
                added_depth += pim->BitsPerComponent;
328
0
                break;
329
3.06k
            case interleave_separate_source:
330
                /* Insert the mask as a separate plane. */
331
3.06k
                penum->plane_widths[pi] = penum->mask[i].width;
332
3.06k
                penum->plane_depths[pi] = penum->mask[i].depth;
333
3.06k
                ++pi;
334
3.06k
                break;
335
0
            default:    /* can't happen */
336
0
                code = gs_note_error(gs_error_Fatal);
337
0
                goto out3;
338
3.06k
            }
339
3.06k
        }
340
3.06k
        memcpy(&penum->plane_widths[pi], &penum->pixel.info->plane_widths[0],
341
3.06k
               penum->pixel.info->num_planes * sizeof(penum->plane_widths[0]));
342
3.06k
        memcpy(&penum->plane_depths[pi], &penum->pixel.info->plane_depths[0],
343
3.06k
               penum->pixel.info->num_planes * sizeof(penum->plane_depths[0]));
344
3.06k
        penum->plane_depths[pi] += added_depth;
345
3.06k
        penum->num_planes = pi + penum->pixel.info->num_planes;
346
3.06k
    }
347
3.06k
    if (midev[0])
348
3.06k
        gx_device_retain(midev[0], true); /* will free explicitly */
349
3.06k
    if (midev[1])
350
0
        gx_device_retain(midev[1], true); /* ditto */
351
3.06k
    gx_device_retain(pcdev, true); /* ditto */
352
3.06k
    *pinfo = (gx_image_enum_common_t *) penum;
353
3.06k
    return 0;
354
0
  out3:
355
0
    if (penum->mask[1].info)
356
0
        gx_image_end(penum->mask[1].info, false);
357
0
    if (penum->mask[0].info)
358
0
        gx_image_end(penum->mask[0].info, false);
359
0
  out2:
360
0
    if (penum->mask[1].mdev) {
361
0
        gs_closedevice(penum->mask[1].mdev);
362
0
        gs_free_object(mem, penum->mask[1].mdev,
363
0
                       "gx_begin_image3x(mask[1].mdev)");
364
0
    }
365
0
    if (penum->mask[0].mdev) {
366
0
        gs_closedevice(penum->mask[0].mdev);
367
0
        gs_free_object(mem, penum->mask[0].mdev,
368
0
                       "gx_begin_image3x(mask[0].mdev)");
369
0
    }
370
2
  out1:
371
2
    rc_decrement(pmcs, "gx_begin_image3x_generic(pmcs)");
372
2
    gs_free_object(mem, penum->mask[0].data, "gx_begin_image3x(mask[0].data)");
373
2
    gs_free_object(mem, penum->mask[1].data, "gx_begin_image3x(mask[1].data)");
374
2
    gs_free_object(mem, penum->pixel.data, "gx_begin_image3x(pixel.data)");
375
9
  out0:
376
9
    gs_free_object(mem, penum, "gx_begin_image3x");
377
9
    return code;
378
2
}
379
static bool
380
check_image3x_extent(double mask_coeff, double data_coeff)
381
12.2k
{
382
12.2k
    if (mask_coeff == 0)
383
6.13k
        return data_coeff == 0;
384
6.13k
    if (data_coeff == 0 || (mask_coeff > 0) != (data_coeff > 0))
385
0
        return false;
386
6.13k
    return true;
387
6.13k
}
388
/*
389
 * Check mask parameters.
390
 * Reads ppcv->{matrix,corner,rect}, sets pmcv->{matrix,corner,rect} and
391
 * pmcs->{InterleaveType,width,height,full_height,depth,data,y,skip}.
392
 * If the mask is omitted, sets pmcs->depth = 0 and returns normally.
393
 */
394
static int
395
check_image3x_mask(const gs_image3x_t *pim, const gs_image3x_mask_t *pimm,
396
                   const image3x_channel_values_t *ppcv,
397
                   image3x_channel_values_t *pmcv,
398
                   image3x_channel_state_t *pmcs, gs_memory_t *mem)
399
6.14k
{
400
6.14k
    int mask_width = pimm->MaskDict.Width, mask_height = pimm->MaskDict.Height;
401
6.14k
    int code;
402
403
6.14k
    if (pimm->MaskDict.BitsPerComponent == 0) { /* mask missing */
404
3.06k
        pmcs->depth = 0;
405
3.06k
        pmcs->InterleaveType = 0; /* not a valid type */
406
3.06k
        return 0;
407
3.06k
    }
408
3.07k
    if (mask_height <= 0)
409
7
        return_error(gs_error_rangecheck);
410
3.06k
    switch (pimm->InterleaveType) {
411
        /*case interleave_scan_lines:*/ /* not supported */
412
0
        default:
413
0
            return_error(gs_error_rangecheck);
414
0
        case interleave_chunky:
415
0
            if (mask_width != pim->Width ||
416
0
                mask_height != pim->Height ||
417
0
                pimm->MaskDict.BitsPerComponent != pim->BitsPerComponent ||
418
0
                pim->format != gs_image_format_chunky
419
0
                )
420
0
                return_error(gs_error_rangecheck);
421
0
            break;
422
3.06k
        case interleave_separate_source:
423
3.06k
            switch (pimm->MaskDict.BitsPerComponent) {
424
3.06k
                    case 1: case 2: case 4: case 8: case 12: case 16:
425
3.06k
                break;
426
0
            default:
427
0
                return_error(gs_error_rangecheck);
428
3.06k
            }
429
3.06k
    }
430
3.06k
    if (!check_image3x_extent(pim->ImageMatrix.xx,
431
3.06k
                              pimm->MaskDict.ImageMatrix.xx) ||
432
3.06k
        !check_image3x_extent(pim->ImageMatrix.xy,
433
3.06k
                              pimm->MaskDict.ImageMatrix.xy) ||
434
3.06k
        !check_image3x_extent(pim->ImageMatrix.yx,
435
3.06k
                              pimm->MaskDict.ImageMatrix.yx) ||
436
3.06k
        !check_image3x_extent(pim->ImageMatrix.yy,
437
3.06k
                              pimm->MaskDict.ImageMatrix.yy)
438
3.06k
        )
439
0
        return_error(gs_error_rangecheck);
440
3.06k
    if ((code = gs_matrix_invert(&pimm->MaskDict.ImageMatrix, &pmcv->matrix)) < 0 ||
441
3.06k
        (code = gs_point_transform(mask_width, mask_height,
442
3.06k
                                   &pmcv->matrix, &pmcv->corner)) < 0
443
3.06k
        )
444
0
        return code;
445
3.06k
    if (fabs(ppcv->matrix.tx - pmcv->matrix.tx) >= 0.5 ||
446
3.06k
        fabs(ppcv->matrix.ty - pmcv->matrix.ty) >= 0.5 ||
447
3.06k
        fabs(ppcv->corner.x - pmcv->corner.x) >= 0.5 ||
448
3.06k
        fabs(ppcv->corner.y - pmcv->corner.y) >= 0.5
449
3.06k
        )
450
0
        return_error(gs_error_rangecheck);
451
3.06k
    pmcv->rect.p.x = ppcv->rect.p.x * mask_width / pim->Width;
452
3.06k
    pmcv->rect.p.y = ppcv->rect.p.y * mask_height / pim->Height;
453
3.06k
    pmcv->rect.q.x = (ppcv->rect.q.x * mask_width + pim->Width - 1) /
454
3.06k
        pim->Width;
455
3.06k
    pmcv->rect.q.y = (ppcv->rect.q.y * mask_height + pim->Height - 1) /
456
3.06k
        pim->Height;
457
    /* Initialize the channel state in the enumerator. */
458
3.06k
    pmcs->InterleaveType = pimm->InterleaveType;
459
3.06k
    pmcs->width = pmcv->rect.q.x - pmcv->rect.p.x;
460
3.06k
    pmcs->height = pmcv->rect.q.y - pmcv->rect.p.y;
461
3.06k
    pmcs->full_height = pimm->MaskDict.Height;
462
3.06k
    pmcs->depth = pimm->MaskDict.BitsPerComponent;
463
3.06k
    if (pmcs->InterleaveType == interleave_chunky) {
464
        /* Allocate a buffer for the data. */
465
0
        pmcs->data =
466
0
            gs_alloc_bytes(mem,
467
0
                           (pmcs->width * pimm->MaskDict.BitsPerComponent + 7) >> 3,
468
0
                           "gx_begin_image3x(mask data)");
469
0
        if (pmcs->data == 0)
470
0
            return_error(gs_error_VMerror);
471
0
    }
472
3.06k
    pmcs->y = pmcs->skip = 0;
473
3.06k
    return 0;
474
3.06k
}
475
476
/*
477
 * Return > 0 if we want more data from channel 1 now, < 0 if we want more
478
 * from channel 2 now, 0 if we want both.
479
 */
480
static int
481
channel_next(const image3x_channel_state_t *pics1,
482
             const image3x_channel_state_t *pics2)
483
259k
{
484
    /*
485
     * The invariant we need to maintain is that we always have at least as
486
     * much channel N as channel N+1 data, where N = 0 = opacity, 1 = shape,
487
     * and 2 = pixel.  I.e., for any two consecutive channels c1 and c2, we
488
     * require c1.y / c1.full_height >= c2.y / c2.full_height, or, to avoid
489
     * floating point, c1.y * c2.full_height >= c2.y * c1.full_height.  We
490
     * know this condition is true now; return a value that indicates how to
491
     * maintain it.
492
     */
493
259k
    int h1 = pics1->full_height;
494
259k
    int h2 = pics2->full_height;
495
259k
    long current = pics1->y * (long)h2 - pics2->y * (long)h1;
496
497
#ifdef DEBUG
498
    if (current < 0)
499
        lprintf4("channel_next invariant fails: %d/%d < %d/%d\n",
500
                 pics1->y, pics1->full_height,
501
                 pics2->y, pics2->full_height);
502
#endif
503
259k
    return ((current -= h1) >= 0 ? -1 :
504
259k
            current + h2 >= 0 ? 0 : 1);
505
259k
}
506
507
/* Define the default implementation of ImageType 3 processing. */
508
static IMAGE3X_MAKE_MID_PROC(make_midx_default); /* check prototype */
509
static int
510
make_midx_default(gx_device **pmidev, gx_device *dev, int width, int height,
511
                 int depth, gs_memory_t *mem)
512
0
{
513
0
    const gx_device_memory *mdproto = gdev_mem_device_for_bits(depth);
514
0
    gx_device_memory *midev;
515
0
    int code;
516
517
0
    if (width != 0)
518
0
        if (height > max_ulong/width) /* protect against overflow in bitmap size */
519
0
            return_error(gs_error_VMerror);
520
0
    if (mdproto == 0)
521
0
        return_error(gs_error_rangecheck);
522
0
    midev = gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory,
523
0
                            "make_mid_default");
524
0
    if (midev == 0)
525
0
        return_error(gs_error_VMerror);
526
0
    gs_make_mem_device(midev, mdproto, mem, 0, NULL);
527
0
    midev->bitmap_memory = mem;
528
0
    midev->width = width;
529
0
    midev->height = height;
530
0
    check_device_separable((gx_device *)midev);
531
0
    gx_device_fill_in_procs((gx_device *)midev);
532
0
    code = dev_proc(midev, open_device)((gx_device *)midev);
533
0
    if (code < 0) {
534
0
        gs_free_object(mem, midev, "make_midx_default");
535
0
        return code;
536
0
    }
537
0
    midev->is_open = true;
538
0
    dev_proc(midev, fill_rectangle)
539
0
        ((gx_device *)midev, 0, 0, width, height, (gx_color_index)0);
540
0
    *pmidev = (gx_device *)midev;
541
0
    return 0;
542
0
}
543
static IMAGE3X_MAKE_MCDE_PROC(make_mcdex_default);  /* check prototype */
544
static int
545
make_mcdex_default(gx_device *dev, const gs_gstate *pgs,
546
                   const gs_matrix *pmat, const gs_image_common_t *pic,
547
                   const gs_int_rect *prect, const gx_drawing_color *pdcolor,
548
                   const gx_clip_path *pcpath, gs_memory_t *mem,
549
                   gx_image_enum_common_t **pinfo,
550
                   gx_device **pmcdev, gx_device *midev[2],
551
                   gx_image_enum_common_t *pminfo[2],
552
                   const gs_int_point origin[2],
553
                   const gs_image3x_t *pim)
554
0
{
555
    /**************** NYI ****************/
556
    /*
557
     * There is no soft-mask analogue of make_mcde_default, because
558
     * soft-mask clipping is a more complicated operation, implemented
559
     * by the general transparency code.  As a default, we simply ignore
560
     * the soft mask.  However, we have to create an intermediate device
561
     * that can be freed at the end and that simply forwards all calls.
562
     * The most convenient device for this purpose is the bbox device.
563
     */
564
0
    gx_device_bbox *bbdev;
565
0
    int code;
566
0
    cmm_dev_profile_t *icc_struct;
567
568
0
    code = dev_proc(dev, get_profile)(dev, &icc_struct);
569
0
    if (code < 0) {
570
0
        return(code);
571
0
    }
572
573
0
    bbdev = gs_alloc_struct_immovable(mem, gx_device_bbox, &st_device_bbox,
574
0
                                  "make_mcdex_default");
575
576
0
    if (bbdev == 0)
577
0
        return_error(gs_error_VMerror);
578
579
0
    gx_device_bbox_init(bbdev, dev, mem);
580
581
0
    bbdev->icc_struct = icc_struct;
582
0
    rc_increment(bbdev->icc_struct);
583
584
0
    gx_device_bbox_fwd_open_close(bbdev, false);
585
0
    code = dev_proc(bbdev, begin_typed_image)
586
0
        ((gx_device *)bbdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem,
587
0
         pinfo);
588
0
    if (code < 0) {
589
0
        gs_free_object(mem, bbdev, "make_mcdex_default");
590
0
        return code;
591
0
    }
592
0
    *pmcdev = (gx_device *)bbdev;
593
0
    return 0;
594
0
}
595
static int
596
gx_begin_image3x(gx_device * dev,
597
                const gs_gstate * pgs, const gs_matrix * pmat,
598
                const gs_image_common_t * pic, const gs_int_rect * prect,
599
                const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
600
                gs_memory_t * mem, gx_image_enum_common_t ** pinfo)
601
0
{
602
0
    return gx_begin_image3x_generic(dev, pgs, pmat, pic, prect, pdcolor,
603
0
                                    pcpath, mem, make_midx_default,
604
0
                                    make_mcdex_default, pinfo, 0);
605
0
}
606
607
/* Process the next piece of an ImageType 3 image. */
608
static int
609
gx_image3x_plane_data(gx_image_enum_common_t * info,
610
                     const gx_image_plane_t * planes, int height,
611
                     int *rows_used)
612
256k
{
613
256k
    gx_image3x_enum_t *penum = (gx_image3x_enum_t *) info;
614
256k
    int pixel_height = penum->pixel.height;
615
256k
    int pixel_used = 0;
616
256k
    int mask_height[2];
617
256k
    int mask_used[2];
618
256k
    int h1 = pixel_height - penum->pixel.y;
619
256k
    int h;
620
256k
    const gx_image_plane_t *pixel_planes;
621
256k
    gx_image_plane_t pixel_plane, mask_plane[2];
622
256k
    int code = 0;
623
256k
    int i, pi = 0;
624
256k
    int num_chunky = 0;
625
626
770k
    for (i = 0; i < NUM_MASKS; ++i) {
627
513k
        int mh = mask_height[i] = penum->mask[i].height;
628
629
513k
        mask_plane[i].data = 0;
630
513k
        mask_plane[i].raster = 0;
631
513k
        mask_used[i] = 0;
632
513k
        if (!penum->mask[i].depth)
633
256k
            continue;
634
256k
        h1 = min(h1, ((mh > penum->mask[i].y) ? (mh - penum->mask[i].y) : mh));
635
256k
        if (penum->mask[i].InterleaveType == interleave_chunky)
636
0
            ++num_chunky;
637
256k
    }
638
256k
    h = min(height, h1);
639
    /* Initialized rows_used in case we get an error. */
640
256k
    *rows_used = 0;
641
642
256k
    if (h <= 0)
643
0
        return 0;
644
645
    /* Handle masks from separate sources. */
646
770k
    for (i = 0; i < NUM_MASKS; ++i)
647
513k
        if (penum->mask[i].InterleaveType == interleave_separate_source) {
648
            /*
649
             * In order to be able to recover from interruptions, we must
650
             * limit separate-source processing to 1 scan line at a time.
651
             */
652
256k
            if (h > 1)
653
0
                h = 1;
654
256k
            mask_plane[i] = planes[pi++];
655
256k
        }
656
256k
    pixel_planes = &planes[pi];
657
658
    /* Handle chunky masks. */
659
256k
    if (num_chunky) {
660
0
        int bpc = penum->bpc;
661
0
        int num_components = penum->num_components;
662
0
        int width = penum->pixel.width;
663
        /* Pull apart the source data and the mask data. */
664
        /* We do this in the simplest (not fastest) way for now. */
665
0
        uint bit_x = bpc * (num_components + num_chunky) * planes[pi].data_x;
666
0
        const byte *sptr = planes[0].data + (bit_x >> 3);
667
0
        int sbit = bit_x & 7;
668
0
        byte *pptr = penum->pixel.data;
669
0
        int pbit = 0;
670
0
        byte pbbyte = (pbit ? (byte)(*pptr & (0xff00 >> pbit)) : 0);
671
0
        byte *dptr[NUM_MASKS];
672
0
        int dbit[NUM_MASKS];
673
0
        byte dbbyte[NUM_MASKS];
674
0
        int depth[NUM_MASKS];
675
0
        int x;
676
677
0
        if (h > 1) {
678
            /* Do the operation one row at a time. */
679
0
            h = 1;
680
0
        }
681
0
        for (i = 0; i < NUM_MASKS; ++i)
682
0
            if (penum->mask[i].data) {
683
0
                depth[i] = penum->mask[i].depth;
684
0
                mask_plane[i].data = dptr[i] = penum->mask[i].data;
685
0
                mask_plane[i].data_x = 0;
686
                /* raster doesn't matter */
687
0
                dbit[i] = 0;
688
0
                dbbyte[i] = 0;
689
0
            } else
690
0
                depth[i] = 0;
691
0
        pixel_plane.data = pptr;
692
0
        pixel_plane.data_x = 0;
693
        /* raster doesn't matter */
694
0
        pixel_planes = &pixel_plane;
695
0
        for (x = 0; x < width; ++x) {
696
0
            uint value;
697
698
0
            for (i = 0; i < NUM_MASKS; ++i)
699
0
                if (depth[i]) {
700
0
                    if (sample_load_next12(&value, &sptr, &sbit, bpc) < 0)
701
0
                        return_error(gs_error_rangecheck);
702
0
                    if (sample_store_next12(value, &dptr[i], &dbit[i], depth[i],
703
0
                                        &dbbyte[i]) < 0)
704
0
                        return_error(gs_error_rangecheck);
705
0
                }
706
0
            for (i = 0; i < num_components; ++i) {
707
0
                if (sample_load_next12(&value, &sptr, &sbit, bpc) < 0)
708
0
                    return_error(gs_error_rangecheck);
709
0
                if (sample_store_next12(value, &pptr, &pbit, bpc, &pbbyte) < 0)
710
0
                    return_error(gs_error_rangecheck);
711
0
            }
712
0
        }
713
0
        for (i = 0; i < NUM_MASKS; ++i)
714
0
            if (penum->mask[i].data) {
715
0
                sample_store_flush(dptr[i], dbit[i], dbbyte[i]);
716
0
            }
717
0
        sample_store_flush(pptr, pbit, pbbyte);
718
0
        }
719
    /*
720
     * Process the mask data first, so it will set up the mask
721
     * device for clipping the pixel data.
722
     */
723
770k
    for (i = 0; i < NUM_MASKS; ++i)
724
513k
        if (mask_plane[i].data) {
725
            /*
726
             * If, on the last call, we processed some mask rows
727
             * successfully but processing the pixel rows was interrupted,
728
             * we set rows_used to indicate the number of pixel rows
729
             * processed (since there is no way to return two rows_used
730
             * values).  If this happened, some mask rows may get presented
731
             * again.  We must skip over them rather than processing them
732
             * again.
733
             */
734
256k
            int skip = penum->mask[i].skip;
735
736
256k
            if (skip >= h) {
737
0
                penum->mask[i].skip = skip - (mask_used[i] = h);
738
256k
            } else {
739
256k
                int mask_h = h - skip;
740
741
256k
                mask_plane[i].data += skip * mask_plane[i].raster;
742
256k
                penum->mask[i].skip = 0;
743
256k
                code = gx_image_plane_data_rows(penum->mask[i].info,
744
256k
                                                &mask_plane[i],
745
256k
                                                mask_h, &mask_used[i]);
746
256k
                mask_used[i] += skip;
747
256k
            }
748
256k
            *rows_used = mask_used[i];
749
256k
            penum->mask[i].y += mask_used[i];
750
256k
            if (code < 0)
751
0
                return code;
752
256k
        }
753
256k
    if (pixel_planes[0].data) {
754
        /*
755
         * If necessary, flush any buffered mask data to the mask clipping
756
         * device.
757
         */
758
769k
        for (i = 0; i < NUM_MASKS; ++i)
759
512k
            if (penum->mask[i].info)
760
256k
                gx_image_flush(penum->mask[i].info);
761
256k
        code = gx_image_plane_data_rows(penum->pixel.info, pixel_planes, h,
762
256k
                                        &pixel_used);
763
        /*
764
         * There isn't any way to set rows_used if different amounts of
765
         * the mask and pixel data were used.  Fake it.
766
         */
767
256k
        *rows_used = pixel_used;
768
        /*
769
         * Don't return code yet: we must account for the fact that
770
         * some mask data may have been processed.
771
         */
772
256k
        penum->pixel.y += pixel_used;
773
256k
        if (code < 0) {
774
            /*
775
             * We must prevent the mask data from being processed again.
776
             * We rely on the fact that h > 1 is only possible if the
777
             * mask and pixel data have the same Y scaling.
778
             */
779
0
            for (i = 0; i < NUM_MASKS; ++i)
780
0
                if (mask_used[i] > pixel_used) {
781
0
                    int skip = mask_used[i] - pixel_used;
782
783
0
                    penum->mask[i].skip = skip;
784
0
                    penum->mask[i].y -= skip;
785
0
                    mask_used[i] = pixel_used;
786
0
                }
787
0
        }
788
256k
    }
789
256k
    if_debug7m('b', penum->memory,
790
256k
               "[b]image3x h=%d %sopacity.y=%d %sopacity.y=%d %spixel.y=%d\n",
791
256k
               h, (mask_plane[0].data ? "+" : ""), penum->mask[0].y,
792
256k
               (mask_plane[1].data ? "+" : ""), penum->mask[1].y,
793
256k
               (pixel_planes[0].data ? "+" : ""), penum->pixel.y);
794
256k
    if (penum->mask[0].depth == 0 || penum->mask[0].y >= penum->mask[0].height) {
795
2.65k
        if (penum->mask[1].depth == 0 || penum->mask[1].y >= penum->mask[1].height) {
796
2.65k
            if (penum->pixel.y >= penum->pixel.height) {
797
2.65k
                return 1;
798
2.65k
            }
799
2.65k
        }
800
2.65k
    }
801
    /*
802
     * The mask may be complete (gx_image_plane_data_rows returned 1),
803
     * but there may still be pixel rows to go, so don't return 1 here.
804
     */
805
254k
    return (code < 0 ? code : 0);
806
256k
}
807
808
/* Flush buffered data. */
809
static int
810
gx_image3x_flush(gx_image_enum_common_t * info)
811
0
{
812
0
    gx_image3x_enum_t * const penum = (gx_image3x_enum_t *) info;
813
0
    int code = gx_image_flush(penum->mask[0].info);
814
815
0
    if (code >= 0)
816
0
        code = gx_image_flush(penum->mask[1].info);
817
0
    if (code >= 0)
818
0
        code = gx_image_flush(penum->pixel.info);
819
0
    return code;
820
0
}
821
822
/* Determine which data planes are wanted. */
823
static bool
824
gx_image3x_planes_wanted(const gx_image_enum_common_t * info, byte *wanted)
825
259k
{
826
259k
    const gx_image3x_enum_t * const penum = (const gx_image3x_enum_t *) info;
827
    /*
828
     * We always want at least as much of the mask(s) to be filled as the
829
     * pixel data.
830
     */
831
259k
    bool
832
259k
        sso = penum->mask[0].InterleaveType == interleave_separate_source,
833
259k
        sss = penum->mask[1].InterleaveType == interleave_separate_source;
834
835
259k
    if (sso & sss) {
836
        /* Both masks have separate sources. */
837
0
        int mask_next = channel_next(&penum->mask[1], &penum->pixel);
838
839
0
        memset(wanted + 2, (mask_next <= 0 ? 0xff : 0), info->num_planes - 2);
840
0
        wanted[1] = (mask_next >= 0 ? 0xff : 0);
841
0
        if (wanted[1]) {
842
0
            mask_next = channel_next(&penum->mask[0], &penum->mask[1]);
843
0
            wanted[0] = mask_next >= 0;
844
0
        } else
845
0
            wanted[0] = 0;
846
0
        return false;   /* see below */
847
259k
    } else if (sso | sss) {
848
        /* Only one separate source. */
849
259k
        const image3x_channel_state_t *pics =
850
259k
            (sso ? &penum->mask[0] : &penum->mask[1]);
851
259k
        int mask_next = channel_next(pics, &penum->pixel);
852
853
259k
        wanted[0] = (mask_next >= 0 ? 0xff : 0);
854
259k
        memset(wanted + 1, (mask_next <= 0 ? 0xff : 0), info->num_planes - 1);
855
        /*
856
         * In principle, wanted will always be true for both mask and pixel
857
         * data if the full_heights are equal.  Unfortunately, even in this
858
         * case, processing may be interrupted after a mask row has been
859
         * passed to the underlying image processor but before the data row
860
         * has been passed, in which case pixel data will be 'wanted', but
861
         * not mask data, for the next call.  Therefore, we must return
862
         * false.
863
         */
864
259k
        return false
865
            /*(next == 0 &&
866
259k
              pics->full_height == penum->pixel.full_height)*/;
867
259k
    } else {
868
        /* Everything is chunky, only 1 plane. */
869
0
        wanted[0] = 0xff;
870
0
        return true;
871
0
    }
872
259k
}
873
874
/* Clean up after processing an ImageType 3x image. */
875
static int
876
gx_image3x_end_image(gx_image_enum_common_t * info, bool draw_last)
877
3.06k
{
878
3.06k
    gx_image3x_enum_t *penum = (gx_image3x_enum_t *) info;
879
3.06k
    gs_memory_t *mem = penum->memory;
880
3.06k
    gx_device *mdev0 = penum->mask[0].mdev;
881
3.06k
    int ocode =
882
3.06k
        (penum->mask[0].info ? gx_image_end(penum->mask[0].info, draw_last) :
883
3.06k
         0);
884
3.06k
    gx_device *mdev1 = penum->mask[1].mdev;
885
3.06k
    int scode =
886
3.06k
        (penum->mask[1].info ? gx_image_end(penum->mask[1].info, draw_last) :
887
3.06k
         0);
888
3.06k
    gx_device *pcdev = penum->pcdev;
889
3.06k
    int pcode = gx_image_end(penum->pixel.info, draw_last);
890
891
3.06k
    rc_decrement(pcdev->icc_struct, "gx_image3x_end_image(pcdev->icc_struct)");
892
3.06k
    pcdev->icc_struct = NULL;
893
894
3.06k
    gs_closedevice(pcdev);
895
3.06k
    if (mdev0)
896
3.06k
        gs_closedevice(mdev0);
897
3.06k
    if (mdev1)
898
0
        gs_closedevice(mdev1);
899
3.06k
    gs_free_object(mem, penum->mask[0].data,
900
3.06k
                   "gx_image3x_end_image(mask[0].data)");
901
3.06k
    gs_free_object(mem, penum->mask[1].data,
902
3.06k
                   "gx_image3x_end_image(mask[1].data)");
903
3.06k
    gs_free_object(mem, penum->pixel.data,
904
3.06k
                   "gx_image3x_end_image(pixel.data)");
905
3.06k
    gs_free_object(mem, pcdev, "gx_image3x_end_image(pcdev)");
906
3.06k
    gs_free_object(mem, mdev0, "gx_image3x_end_image(mask[0].mdev)");
907
3.06k
    gs_free_object(mem, mdev1, "gx_image3x_end_image(mask[1].mdev)");
908
3.06k
    gx_image_free_enum(&info);
909
3.06k
    return (pcode < 0 ? pcode : scode < 0 ? scode : ocode);
910
3.06k
}