Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gximag3x.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
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
956
{
61
956
    pimm->InterleaveType = 0; /* not a valid type */
62
956
    pimm->has_Matte = false;
63
956
    gs_data_image_t_init(&pimm->MaskDict, 1);
64
956
    pimm->MaskDict.BitsPerComponent = 0;  /* not supplied */
65
956
}
66
void
67
gs_image3x_t_init(gs_image3x_t * pim, gs_color_space * color_space)
68
478
{
69
478
    gs_pixel_image_t_init((gs_pixel_image_t *) pim, color_space);
70
478
    pim->type = &gs_image_type_3x;
71
478
    gs_image3x_mask_init(&pim->Opacity);
72
478
    gs_image3x_mask_init(&pim->Shape);
73
478
}
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
850k
#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)
136
478
{
137
478
    const gs_image3x_t *pim = (const gs_image3x_t *)pic;
138
478
    gx_image3x_enum_t *penum;
139
478
    gx_device *pcdev = 0;
140
478
    image3x_channel_values_t mask[2], pixel;
141
478
    gs_matrix mat;
142
478
    gx_device *midev[2];
143
478
    gx_image_enum_common_t *minfo[2];
144
478
    gs_int_point origin[2];
145
478
    int code;
146
478
    int i;
147
478
    gs_color_space *pmcs = NULL;
148
149
    /* Validate the parameters. */
150
478
    if (pim->Height <= 0)
151
0
        return_error(gs_error_rangecheck);
152
478
    penum = gs_alloc_struct(mem, gx_image3x_enum_t, &st_image3x_enum,
153
478
                            "gx_begin_image3x");
154
478
    if (penum == 0)
155
0
        return_error(gs_error_VMerror);
156
    /* Initialize pointers now in case we bail out. */
157
478
    penum->mask[0].info = 0, penum->mask[0].mdev = 0, penum->mask[0].data = 0;
158
478
    penum->mask[1].info = 0, penum->mask[1].mdev = 0, penum->mask[1].data = 0;
159
478
    penum->pixel.info = 0, penum->pixel.data = 0;
160
478
    if (prect)
161
0
        pixel.rect = *prect;
162
478
    else {
163
478
        pixel.rect.p.x = pixel.rect.p.y = 0;
164
478
        pixel.rect.q.x = pim->Width;
165
478
        pixel.rect.q.y = pim->Height;
166
478
    }
167
478
    if ((code = gs_matrix_invert(&pim->ImageMatrix, &pixel.matrix)) < 0 ||
168
478
        (code = gs_point_transform(pim->Width, pim->Height, &pixel.matrix,
169
478
                                   &pixel.corner)) < 0 ||
170
478
        (code = check_image3x_mask(pim, &pim->Opacity, &pixel, &mask[0],
171
478
                                   &penum->mask[0], mem)) < 0 ||
172
478
        (code = check_image3x_mask(pim, &pim->Shape, &pixel, &mask[1],
173
478
                                   &penum->mask[1], mem)) < 0
174
478
        ) {
175
0
        goto out0;
176
0
    }
177
478
    penum->num_components =
178
478
        gs_color_space_num_components(pim->ColorSpace);
179
478
    gx_image_enum_common_init((gx_image_enum_common_t *) penum,
180
478
                              (const gs_data_image_t *)pim,
181
478
                              &image3x_enum_procs, dev,
182
478
                              1 + penum->num_components,
183
478
                              pim->format);
184
478
    penum->pixel.width = pixel.rect.q.x - pixel.rect.p.x;
185
478
    penum->pixel.height = pixel.rect.q.y - pixel.rect.p.y;
186
478
    penum->pixel.full_height = pim->Height;
187
478
    penum->pixel.y = 0;
188
478
    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
478
    penum->bpc = pim->BitsPerComponent;
201
478
    penum->memory = mem;
202
478
    if (pmat == 0)
203
478
        pmat = &ctm_only(pgs);
204
1.43k
    for (i = 0; i < NUM_MASKS; ++i) {
205
956
        gs_rect mrect;
206
956
        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
956
        if (penum->mask[i].depth == 0) { /* mask not supplied */
212
478
            midev[i] = 0;
213
478
            minfo[i] = 0;
214
478
            continue;
215
478
        }
216
478
        code = gs_cspace_new_DevicePixel(mem, &pmcs, penum->mask[i].depth);
217
478
        if (code < 0)
218
0
            goto out1;
219
478
        mrect.p.x = mrect.p.y = 0;
220
478
        mrect.q.x = penum->mask[i].width;
221
478
        mrect.q.y = penum->mask[i].height;
222
478
        if ((code = gs_matrix_multiply(&mask[i].matrix, pmat, &mat)) < 0 ||
223
478
            (code = gs_bbox_transform(&mrect, &mat, &mrect)) < 0
224
478
            )
225
0
            goto out1;
226
227
        /* Bug 700438: If the rectangle is out of range, bail */
228
478
        if (mrect.p.x >= (double)INT_MAX || mrect.q.x <= (double)INT_MIN ||
229
478
            mrect.p.y >= (double)INT_MAX || mrect.q.y <= (double)INT_MIN) {
230
0
            code = gs_note_error(gs_error_rangecheck);
231
0
            goto out1;
232
0
        }
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
478
        origin[i].x = (int)floor(mrect.p.x);
238
478
        origin[i].y = (int)floor(mrect.p.y);
239
478
        code = make_mid(&mdev, dev,
240
478
                        (int)ceil(mrect.q.x) - origin[i].x,
241
478
                        (int)ceil(mrect.q.y) - origin[i].y,
242
478
                        penum->mask[i].depth, mem);
243
478
        if (code < 0)
244
0
            goto out1;
245
478
        code = dev_proc(dev, get_profile)(dev, &mdev->icc_struct);
246
478
        if (code < 0)
247
0
            goto out1;  /* Device not yet open */
248
478
        rc_increment(mdev->icc_struct);
249
478
        penum->mask[i].mdev = mdev;
250
478
        gs_image_t_init(&mask[i].image, pmcs);
251
478
        mask[i].image.ColorSpace = pmcs;
252
478
        mask[i].image.adjust = false;
253
478
        mask[i].image.image_parent_type = gs_image_type3x;
254
478
        {
255
478
            const gx_image_type_t *type1 = mask[i].image.type;
256
478
            const gs_image3x_mask_t *pixm =
257
478
                (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
478
            memcpy(&mask[i].image, &pixm->MaskDict, sizeof(pixm->MaskDict));
262
478
            mask[i].image.type = type1;
263
478
            mask[i].image.BitsPerComponent = pixm->MaskDict.BitsPerComponent;
264
478
        }
265
478
        {
266
478
            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
478
            m_mat = *pmat;
273
478
            m_mat.tx -= origin[i].x;
274
478
            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
478
            code = gx_device_begin_typed_image(mdev, pgs, &m_mat,
285
478
                               (const gs_image_common_t *)&mask[i].image,
286
478
                                               &mask[i].rect, NULL, NULL,
287
478
                                               mem, &penum->mask[i].info);
288
478
            if (code < 0)
289
0
                goto out2;
290
478
        }
291
478
        midev[i] = mdev;
292
478
        minfo[i] = penum->mask[i].info;
293
478
        rc_decrement_only(pmcs, "gx_begin_image3x_generic(pmcs)");
294
478
        pmcs = NULL;
295
478
    }
296
478
    gs_image_t_init(&pixel.image, pim->ColorSpace);
297
478
    {
298
478
        const gx_image_type_t *type1 = pixel.image.type;
299
300
478
        *(gs_pixel_image_t *)&pixel.image = *(const gs_pixel_image_t *)pim;
301
478
        pixel.image.type = type1;
302
478
        pixel.image.image_parent_type = gs_image_type3x;
303
478
    }
304
478
    code = make_mcde(dev, pgs, pmat, (const gs_image_common_t *)&pixel.image,
305
478
                     prect, pdcolor, pcpath, mem, &penum->pixel.info,
306
478
                     &pcdev, midev, minfo, origin, pim);
307
478
    if (code < 0)
308
0
        goto out3;
309
478
    penum->pcdev = pcdev;
310
    /*
311
     * Set num_planes, plane_widths, and plane_depths from the values in the
312
     * enumerators for the mask(s) and the image data.
313
     */
314
478
    {
315
478
        int added_depth = 0;
316
478
        int pi = 0;
317
318
1.43k
        for (i = 0; i < NUM_MASKS; ++i) {
319
956
            if (penum->mask[i].depth == 0)  /* no mask */
320
478
                continue;
321
478
            switch (penum->mask[i].InterleaveType) {
322
0
            case interleave_chunky:
323
                /* Add the mask data to the depth of the image data. */
324
0
                added_depth += pim->BitsPerComponent;
325
0
                break;
326
478
            case interleave_separate_source:
327
                /* Insert the mask as a separate plane. */
328
478
                penum->plane_widths[pi] = penum->mask[i].width;
329
478
                penum->plane_depths[pi] = penum->mask[i].depth;
330
478
                ++pi;
331
478
                break;
332
0
            default:    /* can't happen */
333
0
                code = gs_note_error(gs_error_Fatal);
334
0
                goto out3;
335
478
            }
336
478
        }
337
478
        memcpy(&penum->plane_widths[pi], &penum->pixel.info->plane_widths[0],
338
478
               penum->pixel.info->num_planes * sizeof(penum->plane_widths[0]));
339
478
        memcpy(&penum->plane_depths[pi], &penum->pixel.info->plane_depths[0],
340
478
               penum->pixel.info->num_planes * sizeof(penum->plane_depths[0]));
341
478
        penum->plane_depths[pi] += added_depth;
342
478
        penum->num_planes = pi + penum->pixel.info->num_planes;
343
478
    }
344
478
    if (midev[0])
345
476
        gx_device_retain(midev[0], true); /* will free explicitly */
346
478
    if (midev[1])
347
2
        gx_device_retain(midev[1], true); /* ditto */
348
478
    gx_device_retain(pcdev, true); /* ditto */
349
478
    *pinfo = (gx_image_enum_common_t *) penum;
350
478
    return 0;
351
0
  out3:
352
0
    if (penum->mask[1].info)
353
0
        gx_image_end(penum->mask[1].info, false);
354
0
    if (penum->mask[0].info)
355
0
        gx_image_end(penum->mask[0].info, false);
356
0
  out2:
357
0
    if (penum->mask[1].mdev) {
358
0
        gs_closedevice(penum->mask[1].mdev);
359
0
        gs_free_object(mem, penum->mask[1].mdev,
360
0
                       "gx_begin_image3x(mask[1].mdev)");
361
0
    }
362
0
    if (penum->mask[0].mdev) {
363
0
        gs_closedevice(penum->mask[0].mdev);
364
0
        gs_free_object(mem, penum->mask[0].mdev,
365
0
                       "gx_begin_image3x(mask[0].mdev)");
366
0
    }
367
0
  out1:
368
0
    rc_decrement(pmcs, "gx_begin_image3x_generic(pmcs)");
369
0
    gs_free_object(mem, penum->mask[0].data, "gx_begin_image3x(mask[0].data)");
370
0
    gs_free_object(mem, penum->mask[1].data, "gx_begin_image3x(mask[1].data)");
371
0
    gs_free_object(mem, penum->pixel.data, "gx_begin_image3x(pixel.data)");
372
0
  out0:
373
0
    gs_free_object(mem, penum, "gx_begin_image3x");
374
0
    return code;
375
0
}
376
static bool
377
check_image3x_extent(double mask_coeff, double data_coeff)
378
1.91k
{
379
1.91k
    if (mask_coeff == 0)
380
956
        return data_coeff == 0;
381
956
    if (data_coeff == 0 || (mask_coeff > 0) != (data_coeff > 0))
382
0
        return false;
383
956
    return true;
384
956
}
385
/*
386
 * Check mask parameters.
387
 * Reads ppcv->{matrix,corner,rect}, sets pmcv->{matrix,corner,rect} and
388
 * pmcs->{InterleaveType,width,height,full_height,depth,data,y,skip}.
389
 * If the mask is omitted, sets pmcs->depth = 0 and returns normally.
390
 */
391
static bool
392
check_image3x_mask(const gs_image3x_t *pim, const gs_image3x_mask_t *pimm,
393
                   const image3x_channel_values_t *ppcv,
394
                   image3x_channel_values_t *pmcv,
395
                   image3x_channel_state_t *pmcs, gs_memory_t *mem)
396
956
{
397
956
    int mask_width = pimm->MaskDict.Width, mask_height = pimm->MaskDict.Height;
398
956
    int code;
399
400
956
    if (pimm->MaskDict.BitsPerComponent == 0) { /* mask missing */
401
478
        pmcs->depth = 0;
402
478
        pmcs->InterleaveType = 0; /* not a valid type */
403
478
        return 0;
404
478
    }
405
478
    if (mask_height <= 0)
406
0
        return_error(gs_error_rangecheck);
407
478
    switch (pimm->InterleaveType) {
408
        /*case interleave_scan_lines:*/ /* not supported */
409
0
        default:
410
0
            return_error(gs_error_rangecheck);
411
0
        case interleave_chunky:
412
0
            if (mask_width != pim->Width ||
413
0
                mask_height != pim->Height ||
414
0
                pimm->MaskDict.BitsPerComponent != pim->BitsPerComponent ||
415
0
                pim->format != gs_image_format_chunky
416
0
                )
417
0
                return_error(gs_error_rangecheck);
418
0
            break;
419
478
        case interleave_separate_source:
420
478
            switch (pimm->MaskDict.BitsPerComponent) {
421
478
                    case 1: case 2: case 4: case 8: case 12: case 16:
422
478
                break;
423
0
            default:
424
0
                return_error(gs_error_rangecheck);
425
478
            }
426
478
    }
427
478
    if (!check_image3x_extent(pim->ImageMatrix.xx,
428
478
                              pimm->MaskDict.ImageMatrix.xx) ||
429
478
        !check_image3x_extent(pim->ImageMatrix.xy,
430
478
                              pimm->MaskDict.ImageMatrix.xy) ||
431
478
        !check_image3x_extent(pim->ImageMatrix.yx,
432
478
                              pimm->MaskDict.ImageMatrix.yx) ||
433
478
        !check_image3x_extent(pim->ImageMatrix.yy,
434
478
                              pimm->MaskDict.ImageMatrix.yy)
435
478
        )
436
0
        return_error(gs_error_rangecheck);
437
478
    if ((code = gs_matrix_invert(&pimm->MaskDict.ImageMatrix, &pmcv->matrix)) < 0 ||
438
478
        (code = gs_point_transform(mask_width, mask_height,
439
478
                                   &pmcv->matrix, &pmcv->corner)) < 0
440
478
        )
441
0
        return code;
442
478
    if (fabs(ppcv->matrix.tx - pmcv->matrix.tx) >= 0.5 ||
443
478
        fabs(ppcv->matrix.ty - pmcv->matrix.ty) >= 0.5 ||
444
478
        fabs(ppcv->corner.x - pmcv->corner.x) >= 0.5 ||
445
478
        fabs(ppcv->corner.y - pmcv->corner.y) >= 0.5
446
478
        )
447
0
        return_error(gs_error_rangecheck);
448
478
    pmcv->rect.p.x = ppcv->rect.p.x * mask_width / pim->Width;
449
478
    pmcv->rect.p.y = ppcv->rect.p.y * mask_height / pim->Height;
450
478
    pmcv->rect.q.x = (ppcv->rect.q.x * mask_width + pim->Width - 1) /
451
478
        pim->Width;
452
478
    pmcv->rect.q.y = (ppcv->rect.q.y * mask_height + pim->Height - 1) /
453
478
        pim->Height;
454
    /* Initialize the channel state in the enumerator. */
455
478
    pmcs->InterleaveType = pimm->InterleaveType;
456
478
    pmcs->width = pmcv->rect.q.x - pmcv->rect.p.x;
457
478
    pmcs->height = pmcv->rect.q.y - pmcv->rect.p.y;
458
478
    pmcs->full_height = pimm->MaskDict.Height;
459
478
    pmcs->depth = pimm->MaskDict.BitsPerComponent;
460
478
    if (pmcs->InterleaveType == interleave_chunky) {
461
        /* Allocate a buffer for the data. */
462
0
        pmcs->data =
463
0
            gs_alloc_bytes(mem,
464
0
                           (pmcs->width * pimm->MaskDict.BitsPerComponent + 7) >> 3,
465
0
                           "gx_begin_image3x(mask data)");
466
0
        if (pmcs->data == 0)
467
0
            return_error(gs_error_VMerror);
468
0
    }
469
478
    pmcs->y = pmcs->skip = 0;
470
478
    return 0;
471
478
}
472
473
/*
474
 * Return > 0 if we want more data from channel 1 now, < 0 if we want more
475
 * from channel 2 now, 0 if we want both.
476
 */
477
static int
478
channel_next(const image3x_channel_state_t *pics1,
479
             const image3x_channel_state_t *pics2)
480
71.1k
{
481
    /*
482
     * The invariant we need to maintain is that we always have at least as
483
     * much channel N as channel N+1 data, where N = 0 = opacity, 1 = shape,
484
     * and 2 = pixel.  I.e., for any two consecutive channels c1 and c2, we
485
     * require c1.y / c1.full_height >= c2.y / c2.full_height, or, to avoid
486
     * floating point, c1.y * c2.full_height >= c2.y * c1.full_height.  We
487
     * know this condition is true now; return a value that indicates how to
488
     * maintain it.
489
     */
490
71.1k
    int h1 = pics1->full_height;
491
71.1k
    int h2 = pics2->full_height;
492
71.1k
    long current = pics1->y * (long)h2 - pics2->y * (long)h1;
493
494
#ifdef DEBUG
495
    if (current < 0)
496
        lprintf4("channel_next invariant fails: %d/%d < %d/%d\n",
497
                 pics1->y, pics1->full_height,
498
                 pics2->y, pics2->full_height);
499
#endif
500
71.1k
    return ((current -= h1) >= 0 ? -1 :
501
71.1k
            current + h2 >= 0 ? 0 : 1);
502
71.1k
}
503
504
/* Define the default implementation of ImageType 3 processing. */
505
static IMAGE3X_MAKE_MID_PROC(make_midx_default); /* check prototype */
506
static int
507
make_midx_default(gx_device **pmidev, gx_device *dev, int width, int height,
508
                 int depth, gs_memory_t *mem)
509
0
{
510
0
    const gx_device_memory *mdproto = gdev_mem_device_for_bits(depth);
511
0
    gx_device_memory *midev;
512
0
    int code;
513
514
0
    if (width != 0)
515
0
        if (height > max_ulong/width) /* protect against overflow in bitmap size */
516
0
            return_error(gs_error_VMerror);
517
0
    if (mdproto == 0)
518
0
        return_error(gs_error_rangecheck);
519
0
    midev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
520
0
                            "make_mid_default");
521
0
    if (midev == 0)
522
0
        return_error(gs_error_VMerror);
523
0
    gs_make_mem_device(midev, mdproto, mem, 0, NULL);
524
0
    midev->bitmap_memory = mem;
525
0
    midev->width = width;
526
0
    midev->height = height;
527
0
    check_device_separable((gx_device *)midev);
528
0
    gx_device_fill_in_procs((gx_device *)midev);
529
0
    code = dev_proc(midev, open_device)((gx_device *)midev);
530
0
    if (code < 0) {
531
0
        gs_free_object(mem, midev, "make_midx_default");
532
0
        return code;
533
0
    }
534
0
    midev->is_open = true;
535
0
    dev_proc(midev, fill_rectangle)
536
0
        ((gx_device *)midev, 0, 0, width, height, (gx_color_index)0);
537
0
    *pmidev = (gx_device *)midev;
538
0
    return 0;
539
0
}
540
static IMAGE3X_MAKE_MCDE_PROC(make_mcdex_default);  /* check prototype */
541
static int
542
make_mcdex_default(gx_device *dev, const gs_gstate *pgs,
543
                   const gs_matrix *pmat, const gs_image_common_t *pic,
544
                   const gs_int_rect *prect, const gx_drawing_color *pdcolor,
545
                   const gx_clip_path *pcpath, gs_memory_t *mem,
546
                   gx_image_enum_common_t **pinfo,
547
                   gx_device **pmcdev, gx_device *midev[2],
548
                   gx_image_enum_common_t *pminfo[2],
549
                   const gs_int_point origin[2],
550
                   const gs_image3x_t *pim)
551
0
{
552
    /**************** NYI ****************/
553
    /*
554
     * There is no soft-mask analogue of make_mcde_default, because
555
     * soft-mask clipping is a more complicated operation, implemented
556
     * by the general transparency code.  As a default, we simply ignore
557
     * the soft mask.  However, we have to create an intermediate device
558
     * that can be freed at the end and that simply forwards all calls.
559
     * The most convenient device for this purpose is the bbox device.
560
     */
561
0
    gx_device_bbox *bbdev;
562
0
    int code;
563
0
    cmm_dev_profile_t *icc_struct;
564
565
0
    code = dev_proc(dev, get_profile)(dev, &icc_struct);
566
0
    if (code < 0) {
567
0
        return(code);
568
0
    }
569
570
0
    bbdev = gs_alloc_struct_immovable(mem, gx_device_bbox, &st_device_bbox,
571
0
                                  "make_mcdex_default");
572
573
0
    if (bbdev == 0)
574
0
        return_error(gs_error_VMerror);
575
576
0
    gx_device_bbox_init(bbdev, dev, mem);
577
578
0
    bbdev->icc_struct = icc_struct;
579
0
    rc_increment(bbdev->icc_struct);
580
581
0
    gx_device_bbox_fwd_open_close(bbdev, false);
582
0
    code = dev_proc(bbdev, begin_typed_image)
583
0
        ((gx_device *)bbdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem,
584
0
         pinfo);
585
0
    if (code < 0) {
586
0
        gs_free_object(mem, bbdev, "make_mcdex_default");
587
0
        return code;
588
0
    }
589
0
    *pmcdev = (gx_device *)bbdev;
590
0
    return 0;
591
0
}
592
static int
593
gx_begin_image3x(gx_device * dev,
594
                const gs_gstate * pgs, const gs_matrix * pmat,
595
                const gs_image_common_t * pic, const gs_int_rect * prect,
596
                const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
597
                gs_memory_t * mem, gx_image_enum_common_t ** pinfo)
598
0
{
599
0
    return gx_begin_image3x_generic(dev, pgs, pmat, pic, prect, pdcolor,
600
0
                                    pcpath, mem, make_midx_default,
601
0
                                    make_mcdex_default, pinfo);
602
0
}
603
604
/* Process the next piece of an ImageType 3 image. */
605
static int
606
gx_image3x_plane_data(gx_image_enum_common_t * info,
607
                     const gx_image_plane_t * planes, int height,
608
                     int *rows_used)
609
70.6k
{
610
70.6k
    gx_image3x_enum_t *penum = (gx_image3x_enum_t *) info;
611
70.6k
    int pixel_height = penum->pixel.height;
612
70.6k
    int pixel_used = 0;
613
70.6k
    int mask_height[2];
614
70.6k
    int mask_used[2];
615
70.6k
    int h1 = pixel_height - penum->pixel.y;
616
70.6k
    int h;
617
70.6k
    const gx_image_plane_t *pixel_planes;
618
70.6k
    gx_image_plane_t pixel_plane, mask_plane[2];
619
70.6k
    int code = 0;
620
70.6k
    int i, pi = 0;
621
70.6k
    int num_chunky = 0;
622
623
211k
    for (i = 0; i < NUM_MASKS; ++i) {
624
141k
        int mh = mask_height[i] = penum->mask[i].height;
625
626
141k
        mask_plane[i].data = 0;
627
141k
        mask_plane[i].raster = 0;
628
141k
        mask_used[i] = 0;
629
141k
        if (!penum->mask[i].depth)
630
70.6k
            continue;
631
70.6k
        h1 = min(h1, ((mh > penum->mask[i].y) ? (mh - penum->mask[i].y) : mh));
632
70.6k
        if (penum->mask[i].InterleaveType == interleave_chunky)
633
0
            ++num_chunky;
634
70.6k
    }
635
70.6k
    h = min(height, h1);
636
    /* Initialized rows_used in case we get an error. */
637
70.6k
    *rows_used = 0;
638
639
70.6k
    if (h <= 0)
640
0
        return 0;
641
642
    /* Handle masks from separate sources. */
643
211k
    for (i = 0; i < NUM_MASKS; ++i)
644
141k
        if (penum->mask[i].InterleaveType == interleave_separate_source) {
645
            /*
646
             * In order to be able to recover from interruptions, we must
647
             * limit separate-source processing to 1 scan line at a time.
648
             */
649
70.6k
            if (h > 1)
650
0
                h = 1;
651
70.6k
            mask_plane[i] = planes[pi++];
652
70.6k
        }
653
70.6k
    pixel_planes = &planes[pi];
654
655
    /* Handle chunky masks. */
656
70.6k
    if (num_chunky) {
657
0
        int bpc = penum->bpc;
658
0
        int num_components = penum->num_components;
659
0
        int width = penum->pixel.width;
660
        /* Pull apart the source data and the mask data. */
661
        /* We do this in the simplest (not fastest) way for now. */
662
0
        uint bit_x = bpc * (num_components + num_chunky) * planes[pi].data_x;
663
0
        const byte *sptr = planes[0].data + (bit_x >> 3);
664
0
        int sbit = bit_x & 7;
665
0
        byte *pptr = penum->pixel.data;
666
0
        int pbit = 0;
667
0
        byte pbbyte = (pbit ? (byte)(*pptr & (0xff00 >> pbit)) : 0);
668
0
        byte *dptr[NUM_MASKS];
669
0
        int dbit[NUM_MASKS];
670
0
        byte dbbyte[NUM_MASKS];
671
0
        int depth[NUM_MASKS];
672
0
        int x;
673
674
0
        if (h > 1) {
675
            /* Do the operation one row at a time. */
676
0
            h = 1;
677
0
        }
678
0
        for (i = 0; i < NUM_MASKS; ++i)
679
0
            if (penum->mask[i].data) {
680
0
                depth[i] = penum->mask[i].depth;
681
0
                mask_plane[i].data = dptr[i] = penum->mask[i].data;
682
0
                mask_plane[i].data_x = 0;
683
                /* raster doesn't matter */
684
0
                dbit[i] = 0;
685
0
                dbbyte[i] = 0;
686
0
            } else
687
0
                depth[i] = 0;
688
0
        pixel_plane.data = pptr;
689
0
        pixel_plane.data_x = 0;
690
        /* raster doesn't matter */
691
0
        pixel_planes = &pixel_plane;
692
0
        for (x = 0; x < width; ++x) {
693
0
            uint value;
694
695
0
            for (i = 0; i < NUM_MASKS; ++i)
696
0
                if (depth[i]) {
697
0
                    if (sample_load_next12(&value, &sptr, &sbit, bpc) < 0)
698
0
                        return_error(gs_error_rangecheck);
699
0
                    if (sample_store_next12(value, &dptr[i], &dbit[i], depth[i],
700
0
                                        &dbbyte[i]) < 0)
701
0
                        return_error(gs_error_rangecheck);
702
0
                }
703
0
            for (i = 0; i < num_components; ++i) {
704
0
                if (sample_load_next12(&value, &sptr, &sbit, bpc) < 0)
705
0
                    return_error(gs_error_rangecheck);
706
0
                if (sample_store_next12(value, &pptr, &pbit, bpc, &pbbyte) < 0)
707
0
                    return_error(gs_error_rangecheck);
708
0
            }
709
0
        }
710
0
        for (i = 0; i < NUM_MASKS; ++i)
711
0
            if (penum->mask[i].data) {
712
0
                sample_store_flush(dptr[i], dbit[i], dbbyte[i]);
713
0
            }
714
0
        sample_store_flush(pptr, pbit, pbbyte);
715
0
        }
716
    /*
717
     * Process the mask data first, so it will set up the mask
718
     * device for clipping the pixel data.
719
     */
720
211k
    for (i = 0; i < NUM_MASKS; ++i)
721
141k
        if (mask_plane[i].data) {
722
            /*
723
             * If, on the last call, we processed some mask rows
724
             * successfully but processing the pixel rows was interrupted,
725
             * we set rows_used to indicate the number of pixel rows
726
             * processed (since there is no way to return two rows_used
727
             * values).  If this happened, some mask rows may get presented
728
             * again.  We must skip over them rather than processing them
729
             * again.
730
             */
731
70.6k
            int skip = penum->mask[i].skip;
732
733
70.6k
            if (skip >= h) {
734
0
                penum->mask[i].skip = skip - (mask_used[i] = h);
735
70.6k
            } else {
736
70.6k
                int mask_h = h - skip;
737
738
70.6k
                mask_plane[i].data += skip * mask_plane[i].raster;
739
70.6k
                penum->mask[i].skip = 0;
740
70.6k
                code = gx_image_plane_data_rows(penum->mask[i].info,
741
70.6k
                                                &mask_plane[i],
742
70.6k
                                                mask_h, &mask_used[i]);
743
70.6k
                mask_used[i] += skip;
744
70.6k
            }
745
70.6k
            *rows_used = mask_used[i];
746
70.6k
            penum->mask[i].y += mask_used[i];
747
70.6k
            if (code < 0)
748
0
                return code;
749
70.6k
        }
750
70.6k
    if (pixel_planes[0].data) {
751
        /*
752
         * If necessary, flush any buffered mask data to the mask clipping
753
         * device.
754
         */
755
211k
        for (i = 0; i < NUM_MASKS; ++i)
756
140k
            if (penum->mask[i].info)
757
70.4k
                gx_image_flush(penum->mask[i].info);
758
70.4k
        code = gx_image_plane_data_rows(penum->pixel.info, pixel_planes, h,
759
70.4k
                                        &pixel_used);
760
        /*
761
         * There isn't any way to set rows_used if different amounts of
762
         * the mask and pixel data were used.  Fake it.
763
         */
764
70.4k
        *rows_used = pixel_used;
765
        /*
766
         * Don't return code yet: we must account for the fact that
767
         * some mask data may have been processed.
768
         */
769
70.4k
        penum->pixel.y += pixel_used;
770
70.4k
        if (code < 0) {
771
            /*
772
             * We must prevent the mask data from being processed again.
773
             * We rely on the fact that h > 1 is only possible if the
774
             * mask and pixel data have the same Y scaling.
775
             */
776
0
            for (i = 0; i < NUM_MASKS; ++i)
777
0
                if (mask_used[i] > pixel_used) {
778
0
                    int skip = mask_used[i] - pixel_used;
779
780
0
                    penum->mask[i].skip = skip;
781
0
                    penum->mask[i].y -= skip;
782
0
                    mask_used[i] = pixel_used;
783
0
                }
784
0
        }
785
70.4k
    }
786
70.6k
    if_debug7m('b', penum->memory,
787
70.6k
               "[b]image3x h=%d %sopacity.y=%d %sopacity.y=%d %spixel.y=%d\n",
788
70.6k
               h, (mask_plane[0].data ? "+" : ""), penum->mask[0].y,
789
70.6k
               (mask_plane[1].data ? "+" : ""), penum->mask[1].y,
790
70.6k
               (pixel_planes[0].data ? "+" : ""), penum->pixel.y);
791
70.6k
    if (penum->mask[0].depth == 0 || penum->mask[0].y >= penum->mask[0].height) {
792
1.13k
        if (penum->mask[1].depth == 0 || penum->mask[1].y >= penum->mask[1].height) {
793
470
            if (penum->pixel.y >= penum->pixel.height) {
794
470
                return 1;
795
470
            }
796
470
        }
797
1.13k
    }
798
    /*
799
     * The mask may be complete (gx_image_plane_data_rows returned 1),
800
     * but there may still be pixel rows to go, so don't return 1 here.
801
     */
802
70.1k
    return (code < 0 ? code : 0);
803
70.6k
}
804
805
/* Flush buffered data. */
806
static int
807
gx_image3x_flush(gx_image_enum_common_t * info)
808
0
{
809
0
    gx_image3x_enum_t * const penum = (gx_image3x_enum_t *) info;
810
0
    int code = gx_image_flush(penum->mask[0].info);
811
812
0
    if (code >= 0)
813
0
        code = gx_image_flush(penum->mask[1].info);
814
0
    if (code >= 0)
815
0
        code = gx_image_flush(penum->pixel.info);
816
0
    return code;
817
0
}
818
819
/* Determine which data planes are wanted. */
820
static bool
821
gx_image3x_planes_wanted(const gx_image_enum_common_t * info, byte *wanted)
822
71.1k
{
823
71.1k
    const gx_image3x_enum_t * const penum = (const gx_image3x_enum_t *) info;
824
    /*
825
     * We always want at least as much of the mask(s) to be filled as the
826
     * pixel data.
827
     */
828
71.1k
    bool
829
71.1k
        sso = penum->mask[0].InterleaveType == interleave_separate_source,
830
71.1k
        sss = penum->mask[1].InterleaveType == interleave_separate_source;
831
832
71.1k
    if (sso & sss) {
833
        /* Both masks have separate sources. */
834
0
        int mask_next = channel_next(&penum->mask[1], &penum->pixel);
835
836
0
        memset(wanted + 2, (mask_next <= 0 ? 0xff : 0), info->num_planes - 2);
837
0
        wanted[1] = (mask_next >= 0 ? 0xff : 0);
838
0
        if (wanted[1]) {
839
0
            mask_next = channel_next(&penum->mask[0], &penum->mask[1]);
840
0
            wanted[0] = mask_next >= 0;
841
0
        } else
842
0
            wanted[0] = 0;
843
0
        return false;   /* see below */
844
71.1k
    } else if (sso | sss) {
845
        /* Only one separate source. */
846
71.1k
        const image3x_channel_state_t *pics =
847
71.1k
            (sso ? &penum->mask[0] : &penum->mask[1]);
848
71.1k
        int mask_next = channel_next(pics, &penum->pixel);
849
850
71.1k
        wanted[0] = (mask_next >= 0 ? 0xff : 0);
851
71.1k
        memset(wanted + 1, (mask_next <= 0 ? 0xff : 0), info->num_planes - 1);
852
        /*
853
         * In principle, wanted will always be true for both mask and pixel
854
         * data if the full_heights are equal.  Unfortunately, even in this
855
         * case, processing may be interrupted after a mask row has been
856
         * passed to the underlying image processor but before the data row
857
         * has been passed, in which case pixel data will be 'wanted', but
858
         * not mask data, for the next call.  Therefore, we must return
859
         * false.
860
         */
861
71.1k
        return false
862
            /*(next == 0 &&
863
71.1k
              pics->full_height == penum->pixel.full_height)*/;
864
71.1k
    } else {
865
        /* Everything is chunky, only 1 plane. */
866
0
        wanted[0] = 0xff;
867
0
        return true;
868
0
    }
869
71.1k
}
870
871
/* Clean up after processing an ImageType 3x image. */
872
static int
873
gx_image3x_end_image(gx_image_enum_common_t * info, bool draw_last)
874
478
{
875
478
    gx_image3x_enum_t *penum = (gx_image3x_enum_t *) info;
876
478
    gs_memory_t *mem = penum->memory;
877
478
    gx_device *mdev0 = penum->mask[0].mdev;
878
478
    int ocode =
879
478
        (penum->mask[0].info ? gx_image_end(penum->mask[0].info, draw_last) :
880
478
         0);
881
478
    gx_device *mdev1 = penum->mask[1].mdev;
882
478
    int scode =
883
478
        (penum->mask[1].info ? gx_image_end(penum->mask[1].info, draw_last) :
884
478
         0);
885
478
    gx_device *pcdev = penum->pcdev;
886
478
    int pcode = gx_image_end(penum->pixel.info, draw_last);
887
888
478
    rc_decrement(pcdev->icc_struct, "gx_image3x_end_image(pcdev->icc_struct)");
889
478
    pcdev->icc_struct = NULL;
890
891
478
    gs_closedevice(pcdev);
892
478
    if (mdev0)
893
476
        gs_closedevice(mdev0);
894
478
    if (mdev1)
895
2
        gs_closedevice(mdev1);
896
478
    gs_free_object(mem, penum->mask[0].data,
897
478
                   "gx_image3x_end_image(mask[0].data)");
898
478
    gs_free_object(mem, penum->mask[1].data,
899
478
                   "gx_image3x_end_image(mask[1].data)");
900
478
    gs_free_object(mem, penum->pixel.data,
901
478
                   "gx_image3x_end_image(pixel.data)");
902
478
    gs_free_object(mem, pcdev, "gx_image3x_end_image(pcdev)");
903
478
    gs_free_object(mem, mdev0, "gx_image3x_end_image(mask[0].mdev)");
904
478
    gs_free_object(mem, mdev1, "gx_image3x_end_image(mask[1].mdev)");
905
478
    gx_image_free_enum(&info);
906
478
    return (pcode < 0 ? pcode : scode < 0 ? scode : ocode);
907
478
}