~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to base/gximag3x.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

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