Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gximage3.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* ImageType 3 image implementation */
18
#include "math_.h"    /* for ceil, floor */
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsbitops.h"
23
#include "gscspace.h"
24
#include "gsstruct.h"
25
#include "gxdevice.h"
26
#include "gxdevmem.h"
27
#include "gxclipm.h"
28
#include "gximage3.h"
29
#include "gxgstate.h"
30
#include "gxdevsop.h"
31
#include <limits.h> /* For INT_MAX etc */
32
33
/* Forward references */
34
static dev_proc_begin_typed_image(gx_begin_image3);
35
static image_enum_proc_plane_data(gx_image3_plane_data);
36
static image_enum_proc_end_image(gx_image3_end_image);
37
static image_enum_proc_flush(gx_image3_flush);
38
static image_enum_proc_planes_wanted(gx_image3_planes_wanted);
39
40
/* GC descriptor */
41
private_st_gs_image3();
42
43
/* Define the image type for ImageType 3 images. */
44
const gx_image_type_t gs_image_type_3 = {
45
    &st_gs_image3, gx_begin_image3,
46
    gx_image_no_sput, gx_image_no_sget, gx_image_default_release, 3
47
};
48
static const gx_image_enum_procs_t image3_enum_procs = {
49
    gx_image3_plane_data, gx_image3_end_image,
50
    gx_image3_flush, gx_image3_planes_wanted
51
};
52
53
/* Initialize an ImageType 3 image. */
54
void
55
gs_image3_t_init(gs_image3_t * pim, gs_color_space * color_space,
56
                 gs_image3_interleave_type_t interleave_type)
57
481
{
58
481
    gs_pixel_image_t_init((gs_pixel_image_t *) pim, color_space);
59
481
    pim->type = &gs_image_type_3;
60
481
    pim->InterleaveType = interleave_type;
61
481
    gs_data_image_t_init(&pim->MaskDict, -1);
62
481
}
63
64
extern_st(st_gx_image_enum_common);
65
gs_private_st_suffix_add6(st_image3_enum, gx_image3_enum_t, "gx_image3_enum_t",
66
  image3_enum_enum_ptrs, image3_enum_reloc_ptrs, st_gx_image_enum_common,
67
  mdev, pcdev, pixel_info, mask_info, pixel_data, mask_data);
68
69
/* Define the default implementation of ImageType 3 processing. */
70
static IMAGE3_MAKE_MID_PROC(make_mid_default); /* check prototype */
71
static int
72
make_mid_default(gx_device **pmidev, gx_device *dev, int width, int height,
73
                 gs_memory_t *mem)
74
298
{
75
298
    gx_device_memory *midev =
76
298
        gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory,
77
298
                        "make_mid_default");
78
298
    int code;
79
80
298
    if (midev == 0)
81
0
        return_error(gs_error_VMerror);
82
298
    gs_make_mem_mono_device(midev, mem, NULL);
83
298
    midev->bitmap_memory = mem;
84
298
    midev->width = width;
85
298
    midev->height = height;
86
298
    midev->raster = gx_device_raster((gx_device *)midev, 1);
87
298
    check_device_separable((gx_device *)midev);
88
298
    gx_device_fill_in_procs((gx_device *)midev);
89
298
    code = dev_proc(midev, open_device)((gx_device *)midev);
90
298
    if (code < 0) {
91
0
        gs_free_object(mem, midev, "make_mid_default");
92
0
        return code;
93
0
    }
94
298
    midev->is_open = true;
95
298
    dev_proc(midev, fill_rectangle)
96
298
        ((gx_device *)midev, 0, 0, width, height, (gx_color_index)0);
97
298
    *pmidev = (gx_device *)midev;
98
298
    return 0;
99
298
}
100
static IMAGE3_MAKE_MCDE_PROC(make_mcde_default);  /* check prototype */
101
static int
102
make_mcde_default(gx_device *dev, const gs_gstate *pgs,
103
                  const gs_matrix *pmat, const gs_image_common_t *pic,
104
                  const gs_int_rect *prect, const gx_drawing_color *pdcolor,
105
                  const gx_clip_path *pcpath, gs_memory_t *mem,
106
                  gx_image_enum_common_t **pinfo,
107
                  gx_device **pmcdev, gx_device *midev,
108
                  gx_image_enum_common_t *pminfo,
109
                  const gs_int_point *origin)
110
298
{
111
298
    gx_device_memory *const mdev = (gx_device_memory *)midev;
112
298
    gx_device_mask_clip *mcdev = NULL;
113
298
    gx_strip_bitmap bits; /* only gx_bitmap */
114
298
    int code;
115
116
    /* The gx_strip_bitmap structure defines (via gs_tile_bitmap_common)
117
     * rep_width and rep_height as being of type 'ushort', device width and
118
     * height are of type 'int'. Make sure we don't overflow because that
119
     * will lead to memory corruption.
120
     */
121
298
    if (mdev->width > ARCH_MAX_USHORT || mdev->height > ARCH_MAX_USHORT)
122
1
        return_error(gs_error_rangecheck);
123
124
297
    mcdev = gs_alloc_struct(mem, gx_device_mask_clip, &st_device_mask_clip,
125
297
                        "make_mcde_default");
126
127
297
    if (mcdev == 0)
128
0
        return_error(gs_error_VMerror);
129
297
    bits.data = mdev->base;
130
297
    bits.raster = mdev->raster;
131
132
297
    bits.size.x = bits.rep_width = mdev->width;
133
297
    bits.size.y = bits.rep_height = mdev->height;
134
297
    bits.id = gx_no_bitmap_id;
135
297
    bits.num_planes = 1;
136
297
    bits.rep_shift = bits.shift = 0;
137
297
    code = gx_mask_clip_initialize(mcdev, &gs_mask_clip_device,
138
297
                                   (const gx_bitmap *)&bits, dev,
139
297
                                   origin->x, origin->y, mem);
140
297
    if (code < 0) {
141
0
        gs_free_object(mem, mcdev, "make_mcde_default");
142
0
        return code;
143
0
    }
144
297
    mcdev->tiles = bits;
145
297
    code = dev_proc(mcdev, begin_typed_image)
146
297
        ((gx_device *)mcdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem,
147
297
         pinfo);
148
297
    if (code < 0) {
149
0
        gs_free_object(mem, mcdev, "make_mcde_default");
150
0
        return code;
151
0
    }
152
297
    *pmcdev = (gx_device *)mcdev;
153
297
    return 0;
154
297
}
155
static int
156
gx_begin_image3(gx_device * dev,
157
                const gs_gstate * pgs, const gs_matrix * pmat,
158
                const gs_image_common_t * pic, const gs_int_rect * prect,
159
                const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
160
                gs_memory_t * mem, gx_image_enum_common_t ** pinfo)
161
304
{
162
304
    return gx_begin_image3_generic(dev, pgs, pmat, pic, prect, pdcolor,
163
304
                                   pcpath, mem, make_mid_default,
164
304
                                   make_mcde_default, pinfo);
165
304
}
166
167
/*
168
 * Begin a generic ImageType 3 image, with client handling the creation of
169
 * the mask image and mask clip devices.
170
 */
171
static bool check_image3_extent(double mask_coeff, double data_coeff);
172
int
173
gx_begin_image3_generic(gx_device * dev,
174
                        const gs_gstate *pgs, const gs_matrix *pmat,
175
                        const gs_image_common_t *pic, const gs_int_rect *prect,
176
                        const gx_drawing_color *pdcolor,
177
                        const gx_clip_path *pcpath, gs_memory_t *mem,
178
                        image3_make_mid_proc_t make_mid,
179
                        image3_make_mcde_proc_t make_mcde,
180
                        gx_image_enum_common_t **pinfo)
181
421
{
182
421
    const gs_image3_t *pim = (const gs_image3_t *)pic;
183
421
    gs_image3_t local_pim;
184
421
    gx_image3_enum_t *penum;
185
421
    gs_int_rect mask_rect, data_rect;
186
421
    gx_device *mdev = 0;
187
421
    gx_device *pcdev = 0;
188
421
    gs_image_t i_pixel, i_mask;
189
421
    gs_matrix mi_pixel, mi_mask, mat;
190
421
    gs_rect mrect;
191
421
    gs_int_point origin;
192
421
    int code;
193
194
    /* Validate the parameters. */
195
421
    if (pim->Width <= 0 || pim->MaskDict.Width <= 0 ||
196
419
        pim->Height <= 0 || pim->MaskDict.Height <= 0)
197
2
        return_error(gs_error_rangecheck);
198
419
    switch (pim->InterleaveType) {
199
0
        default:
200
0
            return_error(gs_error_rangecheck);
201
0
        case interleave_chunky:
202
0
            if (pim->MaskDict.Width != pim->Width ||
203
0
                pim->MaskDict.Height != pim->Height ||
204
0
                pim->MaskDict.BitsPerComponent != pim->BitsPerComponent ||
205
0
                pim->format != gs_image_format_chunky
206
0
                )
207
0
                return_error(gs_error_rangecheck);
208
0
            break;
209
0
        case interleave_scan_lines:
210
0
            if (pim->MaskDict.Height % pim->Height != 0 &&
211
0
                pim->Height % pim->MaskDict.Height != 0
212
0
                )
213
0
                return_error(gs_error_rangecheck);
214
            /* falls through */
215
419
        case interleave_separate_source:
216
419
            if (pim->MaskDict.BitsPerComponent != 1)
217
0
                return_error(gs_error_rangecheck);
218
419
    }
219
419
    if ((code = gs_matrix_invert(&pim->ImageMatrix, &mi_pixel)) < 0)
220
0
        return code;
221
    /* For Explicit Masking, we follow Acrobats example, and completely
222
     * ignore the supplied mask. Instead we generate a new one based on the
223
     * image mask, adjusted for any difference in width/height. */
224
419
    if (pim->InterleaveType == interleave_separate_source ||
225
419
        pim->InterleaveType == interleave_scan_lines) {
226
419
        memcpy(&local_pim, pim, sizeof(local_pim));
227
419
        pim = &local_pim;
228
419
        gs_matrix_scale(&mi_pixel,
229
419
                        ((double)pim->Width)  / pim->MaskDict.Width,
230
419
                        ((double)pim->Height) / pim->MaskDict.Height,
231
419
                        &mi_mask);
232
419
        if ((code = gs_matrix_invert(&mi_mask, &local_pim.MaskDict.ImageMatrix)) < 0)
233
0
            return code;
234
419
    } else {
235
0
        if ((code = gs_matrix_invert(&pim->MaskDict.ImageMatrix, &mi_mask)) < 0)
236
0
            return code;
237
238
0
        if (!check_image3_extent(pim->ImageMatrix.xx,
239
0
                                 pim->MaskDict.ImageMatrix.xx) ||
240
0
            !check_image3_extent(pim->ImageMatrix.xy,
241
0
                                 pim->MaskDict.ImageMatrix.xy) ||
242
0
            !check_image3_extent(pim->ImageMatrix.yx,
243
0
                                 pim->MaskDict.ImageMatrix.yx) ||
244
0
            !check_image3_extent(pim->ImageMatrix.yy,
245
0
                                 pim->MaskDict.ImageMatrix.yy)
246
0
            )
247
0
            return_error(gs_error_rangecheck);
248
0
    }
249
419
    if (fabs(mi_pixel.tx - mi_mask.tx) >= 0.5 ||
250
419
        fabs(mi_pixel.ty - mi_mask.ty) >= 0.5
251
419
        )
252
0
        return_error(gs_error_rangecheck);
253
#ifdef DEBUG
254
    {
255
        /* Although the PLRM says that the Mask and Image *must* be the same size,  */
256
        /* Adobe CPSI (and other RIPS) ignore this and process anyway. Note that we */
257
        /* are not compatible if the Mask Height than the Data (pixel) Height. CPSI */
258
        /* de-interleaves the mask from the data image and stops at the Mask Height */
259
        /* Problem detected with Genoa 468-03 (part of file 468-01.ps)              */
260
        /*****           fixme: When Data Image Height > Mask Height            *****/
261
        gs_point ep, em;
262
263
        if ((code = gs_point_transform(pim->Width, pim->Height, &mi_pixel,
264
                                       &ep)) < 0 ||
265
            (code = gs_point_transform(pim->MaskDict.Width,
266
                                       pim->MaskDict.Height, &mi_mask,
267
                                       &em)) < 0
268
            )
269
            return code;
270
        if (fabs(ep.x - em.x) >= 0.5 || fabs(ep.y - em.y) >= 0.5)
271
            code = gs_error_rangecheck; /* leave the check in for debug breakpoint */
272
    }
273
#endif /* DEBUG */
274
419
    penum = gs_alloc_struct(mem, gx_image3_enum_t, &st_image3_enum,
275
419
                            "gx_begin_image3");
276
419
    if (penum == 0)
277
0
        return_error(gs_error_VMerror);
278
419
    penum->num_components =
279
419
        gs_color_space_num_components(pim->ColorSpace);
280
419
    code = gx_image_enum_common_init((gx_image_enum_common_t *) penum,
281
419
                              (const gs_data_image_t *)pim,
282
419
                              &image3_enum_procs, dev,
283
419
                              1 + penum->num_components,
284
419
                              pim->format);
285
419
    if (code < 0) {
286
0
        gs_free_object(mem, penum, "gx_begin_image3");
287
0
        return code;
288
0
    }
289
    /* Initialize pointers now in case we bail out. */
290
419
    penum->mask_data = 0;
291
419
    penum->pixel_data = 0;
292
419
    if (prect) {
293
0
        long lmw = pim->MaskDict.Width, lmh = pim->MaskDict.Height;
294
295
0
        data_rect = *prect;
296
0
        mask_rect.p.x = (int)(data_rect.p.x * lmw / pim->Width);
297
0
        mask_rect.p.y = (int)(data_rect.p.y * lmh / pim->Height);
298
0
        mask_rect.q.x = (int)((data_rect.q.x + pim->Width - 1) * lmw /
299
0
                              pim->Width);
300
0
        mask_rect.q.y = (int)((data_rect.q.y + pim->Height - 1) * lmh /
301
0
                              pim->Height);
302
419
    } else {
303
419
        mask_rect.p.x = mask_rect.p.y = 0;
304
419
        mask_rect.q.x = pim->MaskDict.Width;
305
419
        mask_rect.q.y = pim->MaskDict.Height;
306
419
        data_rect.p.x = data_rect.p.y = 0;
307
419
        data_rect.q.x = pim->Width;
308
419
        data_rect.q.y = pim->Height;
309
419
    }
310
419
    penum->mask_width = mask_rect.q.x - mask_rect.p.x;
311
419
    penum->mask_height = mask_rect.q.y - mask_rect.p.y;
312
419
    penum->mask_full_height = pim->MaskDict.Height;
313
419
    penum->mask_y = 0;
314
419
    penum->mask_skip = 0;
315
419
    penum->pixel_width = data_rect.q.x - data_rect.p.x;
316
419
    penum->pixel_height = data_rect.q.y - data_rect.p.y;
317
419
    penum->pixel_full_height = pim->Height;
318
419
    penum->pixel_y = 0;
319
419
    penum->mask_info = 0;
320
419
    penum->pixel_info = 0;
321
419
    if (pim->InterleaveType == interleave_chunky) {
322
        /* Allocate row buffers for the mask and pixel data. */
323
0
        penum->pixel_data =
324
0
            gs_alloc_bytes(mem,
325
0
                           ((size_t)penum->pixel_width * pim->BitsPerComponent *
326
0
                            penum->num_components + 7) >> 3,
327
0
                           "gx_begin_image3(pixel_data)");
328
0
        penum->mask_data =
329
0
            gs_alloc_bytes(mem, (penum->mask_width + 7) >> 3,
330
0
                           "gx_begin_image3(mask_data)");
331
0
        if (penum->pixel_data == 0 || penum->mask_data == 0) {
332
0
            code = gs_note_error(gs_error_VMerror);
333
0
            goto out1;
334
0
        }
335
        /* Because the mask data is 1 BPC, if the width is not a multiple of 8
336
         * then we will not fill the last byte of mask_data completely. This
337
         * provokes valgrind when running to pdfwrite, because pdfwrite has to
338
         * write the full byte of mask data to the file. It also means (potentially)
339
         * that we could run the same input twice and get (slightly) different
340
         * PDF files produced. So we set the last byte to zero to ensure the bits
341
         * are fully initialised. See Bug #693814
342
         */
343
0
        penum->mask_data[((penum->mask_width + 7) >> 3) - 1] = 0x00;
344
0
    }
345
419
    penum->InterleaveType = pim->InterleaveType;
346
419
    penum->bpc = pim->BitsPerComponent;
347
419
    penum->memory = mem;
348
419
    mrect.p.x = mrect.p.y = 0;
349
419
    mrect.q.x = pim->MaskDict.Width;
350
419
    mrect.q.y = pim->MaskDict.Height;
351
419
    if (pmat == 0)
352
332
        pmat = &ctm_only(pgs);
353
419
    if ((code = gs_matrix_multiply(&mi_mask, pmat, &mat)) < 0 ||
354
419
        (code = gs_bbox_transform(&mrect, &mat, &mrect)) < 0
355
419
        )
356
0
        return code;
357
358
    /* Bug 700438: If the rectangle is out of range, bail */
359
419
    if (mrect.p.x >= (double)INT_MAX || mrect.q.x <= (double)INT_MIN ||
360
412
        mrect.p.y >= (double)INT_MAX || mrect.q.y <= (double)INT_MIN ||
361
412
        mrect.p.x <= (double)INT_MIN || mrect.q.x >= (double)INT_MAX ||
362
412
        mrect.p.y <= (double)INT_MIN || mrect.q.y >= (double)INT_MAX
363
419
  ) {
364
7
            code = gs_note_error(gs_error_rangecheck);
365
7
        goto out1;
366
7
    }
367
368
    /* This code was changed for bug 686843/687411, but in a way that
369
     * a) looked wrong, and b) doesn't appear to make a difference. Revert
370
     * it to the sane version until we have evidence why not. */
371
412
    origin.x = (int)floor(mrect.p.x);
372
412
    origin.y = (int)floor(mrect.p.y);
373
412
    code = make_mid(&mdev, dev, (int)ceil(mrect.q.x) - origin.x,
374
412
                    (int)ceil(mrect.q.y) - origin.y, mem);
375
412
    if (code < 0)
376
0
        goto out1;
377
412
    penum->mdev = mdev;
378
412
    gs_image_t_init_mask(&i_mask, false);
379
412
    i_mask.adjust = false;
380
412
    {
381
412
        const gx_image_type_t *type1 = i_mask.type;
382
383
412
        *(gs_data_image_t *)&i_mask = pim->MaskDict;
384
412
        i_mask.type = type1;
385
412
        i_mask.BitsPerComponent = 1;
386
412
        i_mask.image_parent_type = gs_image_type3;
387
412
    }
388
412
    {
389
412
        gx_drawing_color dcolor;
390
412
        gs_matrix m_mat;
391
392
412
        set_nonclient_dev_color(&dcolor, 1);
393
        /*
394
         * Adjust the translation for rendering the mask to include a
395
         * negative translation by origin.{x,y} in device space.
396
         */
397
412
        m_mat = *pmat;
398
412
        m_mat.tx -= origin.x;
399
412
        m_mat.ty -= origin.y;
400
412
        i_mask.override_in_smask = (dev_proc(dev, dev_spec_op)(dev, gxdso_in_smask, NULL, 0)) > 0;
401
        /*
402
         * Note that pgs = NULL here, since we don't want to have to
403
         * create another gs_gstate with default log_op, etc.
404
         */
405
412
        code = gx_device_begin_typed_image(mdev, NULL, &m_mat,
406
412
                                           (const gs_image_common_t *)&i_mask,
407
412
                                           &mask_rect, &dcolor, NULL, mem,
408
412
                                           &penum->mask_info);
409
412
        if (code < 0)
410
0
            goto out2;
411
412
    }
412
412
    gs_image_t_init(&i_pixel, pim->ColorSpace);
413
412
    {
414
412
        const gx_image_type_t *type1 = i_pixel.type;
415
416
412
        *(gs_pixel_image_t *)&i_pixel = *(const gs_pixel_image_t *)pim;
417
412
        i_pixel.type = type1;
418
412
        i_pixel.image_parent_type = gs_image_type3;
419
412
    }
420
412
    code = make_mcde(dev, pgs, pmat, (const gs_image_common_t *)&i_pixel,
421
412
                     prect, pdcolor, pcpath, mem, &penum->pixel_info,
422
412
                     &pcdev, mdev, penum->mask_info, &origin);
423
412
    if (code < 0)
424
1
        goto out3;
425
411
    penum->pcdev = pcdev;
426
    /*
427
     * Set num_planes, plane_widths, and plane_depths from the values in the
428
     * enumerators for the mask and the image data.
429
     */
430
411
    switch (pim->InterleaveType) {
431
0
    case interleave_chunky:
432
        /* Add the mask data to the depth of the image data. */
433
0
        penum->num_planes = 1;
434
0
        penum->plane_widths[0] = pim->Width;
435
0
        penum->plane_depths[0] =
436
0
            penum->pixel_info->plane_depths[0] *
437
0
            (penum->num_components + 1) / penum->num_components;
438
0
        break;
439
0
    case interleave_scan_lines:
440
        /*
441
         * There is only 1 plane, with dynamically changing width & depth.
442
         * Initialize it for the mask data, since that is what will be
443
         * read first.
444
         */
445
0
        penum->num_planes = 1;
446
0
        penum->plane_depths[0] = 1;
447
0
        penum->plane_widths[0] = pim->MaskDict.Width;
448
0
        break;
449
411
    case interleave_separate_source:
450
        /* Insert the mask data as a separate plane before the image data. */
451
411
        penum->num_planes = penum->pixel_info->num_planes + 1;
452
411
        penum->plane_widths[0] = pim->MaskDict.Width;
453
411
        penum->plane_depths[0] = 1;
454
411
        memcpy(&penum->plane_widths[1], &penum->pixel_info->plane_widths[0],
455
411
               (penum->num_planes - 1) * sizeof(penum->plane_widths[0]));
456
411
        memcpy(&penum->plane_depths[1], &penum->pixel_info->plane_depths[0],
457
411
               (penum->num_planes - 1) * sizeof(penum->plane_depths[0]));
458
411
        break;
459
411
    }
460
411
    gx_device_retain(mdev, true); /* will free explicitly */
461
411
    gx_device_retain(pcdev, true); /* ditto */
462
411
    *pinfo = (gx_image_enum_common_t *) penum;
463
411
    return 0;
464
1
  out3:
465
1
    gx_image_end(penum->mask_info, false);
466
1
  out2:
467
1
    gs_closedevice(mdev);
468
1
    gs_free_object(mem, mdev, "gx_begin_image3(mdev)");
469
8
  out1:
470
8
    gs_free_object(mem, penum->mask_data, "gx_begin_image3(mask_data)");
471
8
    gs_free_object(mem, penum->pixel_data, "gx_begin_image3(pixel_data)");
472
8
    gs_free_object(mem, penum, "gx_begin_image3");
473
8
    return code;
474
1
}
475
static bool
476
check_image3_extent(double mask_coeff, double data_coeff)
477
0
{
478
0
    if (mask_coeff == 0)
479
0
        return data_coeff == 0;
480
0
    if (data_coeff == 0 || (mask_coeff > 0) != (data_coeff > 0))
481
0
        return false;
482
0
    return true;
483
0
}
484
485
/*
486
 * Return > 0 if we want more mask now, < 0 if we want more data now,
487
 * 0 if we want both.
488
 */
489
static int
490
planes_next(const gx_image3_enum_t *penum)
491
79.4k
{
492
    /*
493
     * The invariant we need to maintain is that we always have at least as
494
     * much mask as pixel data, i.e., mask_y / mask_full_height >=
495
     * pixel_y / pixel_full_height, or, to avoid floating point,
496
     * mask_y * pixel_full_height >= pixel_y * mask_full_height.
497
     * We know this condition is true now;
498
     * return a value that indicates how to maintain it.
499
     */
500
79.4k
    int mask_h = penum->mask_full_height;
501
79.4k
    int pixel_h = penum->pixel_full_height;
502
79.4k
    long current = penum->pixel_y * (long)mask_h -
503
79.4k
        penum->mask_y * (long)pixel_h;
504
505
#ifdef DEBUG
506
    if (current > 0)
507
        lprintf4("planes_next invariant fails: %d/%d > %d/%d\n",
508
                 penum->pixel_y, penum->pixel_full_height,
509
                 penum->mask_y, penum->mask_full_height);
510
#endif
511
79.4k
    return ((current += mask_h) <= 0 ? -1 :
512
79.4k
            current - pixel_h <= 0 ? 0 : 1);
513
79.4k
}
514
515
/* Process the next piece of an ImageType 3 image. */
516
static int
517
gx_image3_plane_data(gx_image_enum_common_t * info,
518
                     const gx_image_plane_t * planes, int height,
519
                     int *rows_used)
520
79.0k
{
521
79.0k
    gx_image3_enum_t *penum = (gx_image3_enum_t *) info;
522
79.0k
    int pixel_height = penum->pixel_height;
523
79.0k
    int pixel_used = 0;
524
79.0k
    int mask_height = penum->mask_height;
525
79.0k
    int mask_used = 0;
526
79.0k
    int h1 = max(pixel_height - penum->pixel_y, mask_height - penum->mask_y);
527
79.0k
    int h = min(height, h1);
528
79.0k
    const gx_image_plane_t *pixel_planes;
529
79.0k
    gx_image_plane_t pixel_plane, mask_plane;
530
79.0k
    int code = 0;
531
532
    /* Initialized rows_used in case we get an error. */
533
79.0k
    *rows_used = 0;
534
79.0k
    switch (penum->InterleaveType) {
535
0
        case interleave_chunky:
536
0
            if (h <= 0)
537
0
                return 0;
538
0
            if (h > 1) {
539
                /* Do the operation one row at a time. */
540
0
                int h_orig = h;
541
542
0
                mask_plane = planes[0];
543
0
                do {
544
0
                    code = gx_image3_plane_data(info, &mask_plane, 1,
545
0
                                                rows_used);
546
0
                    h -= *rows_used;
547
0
                    if (code)
548
0
                        break;
549
0
                    mask_plane.data += mask_plane.raster;
550
0
                } while (h);
551
0
                *rows_used = h_orig - h;
552
0
                return code;
553
0
            } {
554
                /* Pull apart the source data and the mask data. */
555
0
                int bpc = penum->bpc;
556
0
                int num_components = penum->num_components;
557
0
                int width = penum->pixel_width;
558
559
                /* We do this in the simplest (not fastest) way for now. */
560
0
                uint bit_x = bpc * (num_components + 1) * planes[0].data_x;
561
562
0
                const byte *sptr = planes[0].data + (bit_x >> 3);
563
0
                int sbit = bit_x & 7;
564
565
0
                byte *mptr = penum->mask_data;
566
0
                int mbit = 0;
567
0
                byte mbbyte = 0;
568
0
                byte *pptr = penum->pixel_data;
569
0
                int pbit = 0;
570
0
                byte pbbyte = 0;
571
0
                int x;
572
573
0
                mask_plane.data = mptr;
574
0
                mask_plane.data_x = 0;
575
0
                mask_plane.raster = 0; /* raster doesn't matter, pacify Valgrind */
576
0
                pixel_plane.data = pptr;
577
0
                pixel_plane.data_x = 0;
578
0
                pixel_plane.raster = 0; /* raster doesn't matter, pacify Valgrind */
579
0
                pixel_planes = &pixel_plane;
580
0
                for (x = 0; x < width; ++x) {
581
0
                    uint value;
582
0
                    int i;
583
584
0
                    if (sample_load_next12(&value, &sptr, &sbit, bpc) < 0)
585
0
                        return_error(gs_error_rangecheck);
586
0
                    if (sample_store_next12(value != 0, &mptr, &mbit, 1, &mbbyte) < 0)
587
0
                        return_error(gs_error_rangecheck);
588
0
                    for (i = 0; i < num_components; ++i) {
589
0
                        if (sample_load_next12(&value, &sptr, &sbit, bpc) < 0)
590
0
                            return_error(gs_error_rangecheck);
591
0
                        if (sample_store_next12(value, &pptr, &pbit, bpc, &pbbyte) < 0)
592
0
                            return_error (gs_error_rangecheck);
593
0
                    }
594
0
                }
595
0
                sample_store_flush(mptr, mbit, mbbyte);
596
0
                sample_store_flush(pptr, pbit, pbbyte);
597
0
            }
598
0
            break;
599
0
        case interleave_scan_lines:
600
0
            if (planes_next(penum) >= 0) {
601
                /* This is mask data. */
602
0
                mask_plane = planes[0];
603
0
                pixel_planes = &pixel_plane;
604
0
                pixel_plane.data = 0;
605
0
            } else {
606
                /* This is pixel data. */
607
0
                mask_plane.data = 0;
608
0
                pixel_planes = planes;
609
0
            }
610
0
            break;
611
79.0k
        case interleave_separate_source:
612
            /*
613
             * In order to be able to recover from interruptions, we must
614
             * limit separate-source processing to 1 scan line at a time.
615
             */
616
79.0k
            if (h > 1)
617
0
                h = 1;
618
79.0k
            mask_plane = planes[0];
619
79.0k
            pixel_planes = planes + 1;
620
79.0k
            break;
621
0
        default:    /* not possible */
622
0
            return_error(gs_error_rangecheck);
623
79.0k
    }
624
    /*
625
     * Process the mask data first, so it will set up the mask
626
     * device for clipping the pixel data.
627
     */
628
79.0k
    if (mask_plane.data) {
629
        /*
630
         * If, on the last call, we processed some mask rows successfully
631
         * but processing the pixel rows was interrupted, we set rows_used
632
         * to indicate the number of pixel rows processed (since there is
633
         * no way to return two rows_used values).  If this happened, some
634
         * mask rows may get presented again.  We must skip over them
635
         * rather than processing them again.
636
         */
637
79.0k
        int skip = penum->mask_skip;
638
639
79.0k
        if (skip >= h) {
640
0
            penum->mask_skip = skip - (mask_used = h);
641
79.0k
        } else {
642
79.0k
            int mask_h = h - skip;
643
644
79.0k
            mask_plane.data += skip * mask_plane.raster;
645
79.0k
            penum->mask_skip = 0;
646
79.0k
            code = gx_image_plane_data_rows(penum->mask_info, &mask_plane,
647
79.0k
                                            mask_h, &mask_used);
648
79.0k
            mask_used += skip;
649
79.0k
        }
650
79.0k
        *rows_used = mask_used;
651
79.0k
        penum->mask_y += mask_used;
652
79.0k
        if (code < 0)
653
0
            return code;
654
79.0k
    }
655
79.0k
    if (pixel_planes[0].data) {
656
        /*
657
         * If necessary, flush any buffered mask data to the mask clipping
658
         * device.
659
         */
660
71.0k
        gx_image_flush(penum->mask_info);
661
71.0k
        code = gx_image_plane_data_rows(penum->pixel_info, pixel_planes, h,
662
71.0k
                                        &pixel_used);
663
        /*
664
         * There isn't any way to set rows_used if different amounts of
665
         * the mask and pixel data were used.  Fake it.
666
         */
667
71.0k
        *rows_used = pixel_used;
668
        /*
669
         * Don't return code yet: we must account for the fact that
670
         * some mask data may have been processed.
671
         */
672
71.0k
        penum->pixel_y += pixel_used;
673
71.0k
        if (code < 0) {
674
            /*
675
             * We must prevent the mask data from being processed again.
676
             * We rely on the fact that h > 1 is only possible if the
677
             * mask and pixel data have the same Y scaling.
678
             */
679
0
            if (mask_used > pixel_used) {
680
0
                int skip = mask_used - pixel_used;
681
682
0
                penum->mask_skip = skip;
683
0
                penum->mask_y -= skip;
684
0
                mask_used = pixel_used;
685
0
            }
686
0
        }
687
71.0k
    }
688
79.0k
    if_debug5m('b', penum->memory, "[b]image3 h=%d %smask_y=%d %spixel_y=%d\n",
689
79.0k
               h, (mask_plane.data ? "+" : ""), penum->mask_y,
690
79.0k
               (pixel_planes[0].data ? "+" : ""), penum->pixel_y);
691
79.0k
    if (penum->mask_y >= penum->mask_height &&
692
127
        penum->pixel_y >= penum->pixel_height)
693
127
        return 1;
694
78.8k
    if (penum->InterleaveType == interleave_scan_lines) {
695
        /* Update the width and depth in the enumerator. */
696
0
        if (planes_next(penum) >= 0) {  /* want mask data next */
697
0
            penum->plane_widths[0] = penum->mask_width;
698
0
            penum->plane_depths[0] = 1;
699
0
        } else {   /* want pixel data next */
700
0
            penum->plane_widths[0] = penum->pixel_width;
701
0
            penum->plane_depths[0] = penum->pixel_info->plane_depths[0];
702
0
        }
703
0
    }
704
    /*
705
     * The mask may be complete (gx_image_plane_data_rows returned 1),
706
     * but there may still be pixel rows to go, so don't return 1 here.
707
     */
708
78.8k
    return (code < 0 ? code : 0);
709
79.0k
}
710
711
/* Flush buffered data. */
712
static int
713
gx_image3_flush(gx_image_enum_common_t * info)
714
0
{
715
0
    gx_image3_enum_t * const penum = (gx_image3_enum_t *) info;
716
0
    int code = gx_image_flush(penum->mask_info);
717
718
0
    if (code >= 0)
719
0
        code = gx_image_flush(penum->pixel_info);
720
0
    return code;
721
0
}
722
723
/* Determine which data planes are wanted. */
724
static bool
725
gx_image3_planes_wanted(const gx_image_enum_common_t * info, byte *wanted)
726
79.4k
{
727
79.4k
    const gx_image3_enum_t * const penum = (const gx_image3_enum_t *) info;
728
729
79.4k
    switch (penum->InterleaveType) {
730
0
    case interleave_chunky: /* only 1 plane */
731
0
        wanted[0] = 0xff;
732
0
        return true;
733
0
    case interleave_scan_lines: /* only 1 plane, but varying width/depth */
734
0
        wanted[0] = 0xff;
735
0
        return false;
736
79.4k
    case interleave_separate_source: {
737
        /*
738
         * We always want at least as much of the mask to be filled as the
739
         * pixel data.  next > 0 iff we've processed more data than mask.
740
         * Plane 0 is the mask, planes [1 .. num_planes - 1] are pixel data.
741
         */
742
79.4k
        int next = planes_next(penum);
743
744
79.4k
        wanted[0] = (next >= 0 ? 0xff : 0);
745
79.4k
        memset(wanted + 1, (next <= 0 ? 0xff : 0), info->num_planes - 1);
746
        /*
747
         * In principle, wanted will always be true for both mask and pixel
748
         * data if the full_heights are equal.  Unfortunately, even in this
749
         * case, processing may be interrupted after a mask row has been
750
         * passed to the underlying image processor but before the data row
751
         * has been passed, in which case pixel data will be 'wanted', but
752
         * not mask data, for the next call.  Therefore, we must return
753
         * false.
754
         */
755
79.4k
        return false
756
            /*(next == 0 &&
757
0
              penum->mask_full_height == penum->pixel_full_height)*/;
758
0
    }
759
0
    default:      /* can't happen */
760
0
        memset(wanted, 0, info->num_planes);
761
0
        return false;
762
79.4k
    }
763
79.4k
}
764
765
/* Clean up after processing an ImageType 3 image. */
766
static int
767
gx_image3_end_image(gx_image_enum_common_t * info, bool draw_last)
768
411
{
769
411
    gx_image3_enum_t *penum = (gx_image3_enum_t *) info;
770
411
    gs_memory_t *mem = penum->memory;
771
411
    gx_device *mdev = penum->mdev;
772
411
    int mcode = gx_image_end(penum->mask_info, draw_last);
773
411
    gx_device *pcdev = penum->pcdev;
774
411
    int pcode = gx_image_end(penum->pixel_info, draw_last);
775
411
    int code1 = gs_closedevice(pcdev);
776
411
    int code2 = gs_closedevice(mdev);
777
778
411
    gs_free_object(mem, penum->mask_data,
779
411
                   "gx_image3_end_image(mask_data)");
780
411
    gs_free_object(mem, penum->pixel_data,
781
411
                   "gx_image3_end_image(pixel_data)");
782
411
    gs_free_object(mem, pcdev, "gx_image3_end_image(pcdev)");
783
411
    gs_free_object(mem, mdev, "gx_image3_end_image(mdev)");
784
411
    gx_image_free_enum(&info);
785
411
    return (pcode < 0 ? pcode : mcode < 0 ? mcode : code1 < 0 ? code1 : code2);
786
411
}