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