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 9666 2009-04-20 19:16:24Z mvrhel $ */
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
gs_image3x_mask_init(gs_image3x_mask_t * pimm)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
gs_image3x_t_init(gs_image3x_t * pim,gs_color_space * color_space)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
gx_begin_image3x_generic(gx_device * dev,const gs_imager_state * pis,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)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
check_image3x_extent(floatp mask_coeff,floatp data_coeff)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
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)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
channel_next(const image3x_channel_state_t * pics1,const image3x_channel_state_t * pics2)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
make_midx_default(gx_device ** pmidev,gx_device * dev,int width,int height,int depth,gs_memory_t * mem)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
make_mcdex_default(gx_device * dev,const gs_imager_state * pis,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)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
gx_begin_image3x(gx_device * dev,const gs_imager_state * pis,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)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
gx_image3x_plane_data(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height,int * rows_used)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 
603 /* FIX_ME.  In the soft mask branch
604    the file associated with bug 689290
605    gets into an endless loop.  This
606    is related to the size mismatch of the
607    soft mask which is 1x1 and the
608    image size */
609 
610     if (h <= 0)
611 #ifdef ENDLESS_LOOP
612 	return 0;
613 #else
614         return 1;
615 #endif
616 
617     /* Handle masks from separate sources. */
618     for (i = 0; i < NUM_MASKS; ++i)
619 	if (penum->mask[i].InterleaveType == interleave_separate_source) {
620 	    /*
621 	     * In order to be able to recover from interruptions, we must
622 	     * limit separate-source processing to 1 scan line at a time.
623 	     */
624 	    if (h > 1)
625 		h = 1;
626 	    mask_plane[i] = planes[pi++];
627 	}
628     pixel_planes = &planes[pi];
629 
630     /* Handle chunky masks. */
631     if (num_chunky) {
632 	int bpc = penum->bpc;
633 	int num_components = penum->num_components;
634 	int width = penum->pixel.width;
635 	/* Pull apart the source data and the mask data. */
636 	/* We do this in the simplest (not fastest) way for now. */
637 	uint bit_x = bpc * (num_components + num_chunky) * planes[pi].data_x;
638 	sample_load_declare_setup(sptr, sbit, planes[0].data + (bit_x >> 3),
639 				  bit_x & 7, bpc);
640 	sample_store_declare_setup(pptr, pbit, pbbyte,
641 				   penum->pixel.data, 0, bpc);
642 	sample_store_declare(dptr[NUM_MASKS], dbit[NUM_MASKS],
643 			     dbbyte[NUM_MASKS]);
644 	int depth[NUM_MASKS];
645 	int x;
646 
647 	if (h > 1) {
648 	    /* Do the operation one row at a time. */
649 	    h = 1;
650 	}
651 	for (i = 0; i < NUM_MASKS; ++i)
652 	    if (penum->mask[i].data) {
653 		depth[i] = penum->mask[i].depth;
654 		mask_plane[i].data = dptr[i] = penum->mask[i].data;
655 		mask_plane[i].data_x = 0;
656 		/* raster doesn't matter */
657 		sample_store_setup(dbit[i], 0, depth[i]);
658 		sample_store_preload(dbbyte[i], dptr[i], 0, depth[i]);
659 	    } else
660 		depth[i] = 0;
661 	pixel_plane.data = pptr;
662 	pixel_plane.data_x = 0;
663 	/* raster doesn't matter */
664 	pixel_planes = &pixel_plane;
665 	for (x = 0; x < width; ++x) {
666 	    uint value;
667 
668 	    for (i = 0; i < NUM_MASKS; ++i)
669 		if (depth[i]) {
670 		    sample_load_next12(value, sptr, sbit, bpc);
671 		    sample_store_next12(value, dptr[i], dbit[i], depth[i],
672 					dbbyte[i]);
673 		}
674 	    for (i = 0; i < num_components; ++i) {
675 		sample_load_next12(value, sptr, sbit, bpc);
676 		sample_store_next12(value, pptr, pbit, bpc, pbbyte);
677 	    }
678 	}
679 	for (i = 0; i < NUM_MASKS; ++i)
680 	    if (penum->mask[i].data)
681 		sample_store_flush(dptr[i], dbit[i], depth[i], dbbyte[i]);
682 	sample_store_flush(pptr, pbit, bpc, pbbyte);
683 	}
684     /*
685      * Process the mask data first, so it will set up the mask
686      * device for clipping the pixel data.
687      */
688     for (i = 0; i < NUM_MASKS; ++i)
689 	if (mask_plane[i].data) {
690 	    /*
691 	     * If, on the last call, we processed some mask rows
692 	     * successfully but processing the pixel rows was interrupted,
693 	     * we set rows_used to indicate the number of pixel rows
694 	     * processed (since there is no way to return two rows_used
695 	     * values).  If this happened, some mask rows may get presented
696 	     * again.  We must skip over them rather than processing them
697 	     * again.
698 	     */
699 	    int skip = penum->mask[i].skip;
700 
701 	    if (skip >= h) {
702 		penum->mask[i].skip = skip - (mask_used[i] = h);
703 	    } else {
704 		int mask_h = h - skip;
705 
706 		mask_plane[i].data += skip * mask_plane[i].raster;
707 		penum->mask[i].skip = 0;
708 		code = gx_image_plane_data_rows(penum->mask[i].info,
709 						&mask_plane[i],
710 						mask_h, &mask_used[i]);
711 		mask_used[i] += skip;
712 	    }
713 	    *rows_used = mask_used[i];
714 	    penum->mask[i].y += mask_used[i];
715 	    if (code < 0)
716 		return code;
717 	}
718     if (pixel_planes[0].data) {
719 	/*
720 	 * If necessary, flush any buffered mask data to the mask clipping
721 	 * device.
722 	 */
723 	for (i = 0; i < NUM_MASKS; ++i)
724 	    if (penum->mask[i].info)
725 		gx_image_flush(penum->mask[i].info);
726 	code = gx_image_plane_data_rows(penum->pixel.info, pixel_planes, h,
727 					&pixel_used);
728 	/*
729 	 * There isn't any way to set rows_used if different amounts of
730 	 * the mask and pixel data were used.  Fake it.
731 	 */
732 	*rows_used = pixel_used;
733 	/*
734 	 * Don't return code yet: we must account for the fact that
735 	 * some mask data may have been processed.
736 	 */
737 	penum->pixel.y += pixel_used;
738 	if (code < 0) {
739 	    /*
740 	     * We must prevent the mask data from being processed again.
741 	     * We rely on the fact that h > 1 is only possible if the
742 	     * mask and pixel data have the same Y scaling.
743 	     */
744 	    for (i = 0; i < NUM_MASKS; ++i)
745 		if (mask_used[i] > pixel_used) {
746 		    int skip = mask_used[i] - pixel_used;
747 
748 		    penum->mask[i].skip = skip;
749 		    penum->mask[i].y -= skip;
750 		    mask_used[i] = pixel_used;
751 		}
752 	}
753     }
754     if_debug7('b', "[b]image3x h=%d %sopacity.y=%d %sopacity.y=%d %spixel.y=%d\n",
755 	      h, (mask_plane[0].data ? "+" : ""), penum->mask[0].y,
756 	      (mask_plane[1].data ? "+" : ""), penum->mask[1].y,
757 	      (pixel_planes[0].data ? "+" : ""), penum->pixel.y);
758     if (penum->mask[0].depth == 0 || penum->mask[0].y >= penum->mask[0].height) {
759         if (penum->mask[1].depth == 0 || penum->mask[1].y >= penum->mask[1].height) {
760 	    if (penum->pixel.y >= penum->pixel.height) {
761 	        return 1;
762             }
763         }
764     }
765     /*
766      * The mask may be complete (gx_image_plane_data_rows returned 1),
767      * but there may still be pixel rows to go, so don't return 1 here.
768      */
769     return (code < 0 ? code : 0);
770 }
771 
772 /* Flush buffered data. */
773 static int
gx_image3x_flush(gx_image_enum_common_t * info)774 gx_image3x_flush(gx_image_enum_common_t * info)
775 {
776     gx_image3x_enum_t * const penum = (gx_image3x_enum_t *) info;
777     int code = gx_image_flush(penum->mask[0].info);
778 
779     if (code >= 0)
780 	code = gx_image_flush(penum->mask[1].info);
781     if (code >= 0)
782 	code = gx_image_flush(penum->pixel.info);
783     return code;
784 }
785 
786 /* Determine which data planes are wanted. */
787 static bool
gx_image3x_planes_wanted(const gx_image_enum_common_t * info,byte * wanted)788 gx_image3x_planes_wanted(const gx_image_enum_common_t * info, byte *wanted)
789 {
790     const gx_image3x_enum_t * const penum = (const gx_image3x_enum_t *) info;
791     /*
792      * We always want at least as much of the mask(s) to be filled as the
793      * pixel data.
794      */
795     bool
796 	sso = penum->mask[0].InterleaveType == interleave_separate_source,
797 	sss = penum->mask[1].InterleaveType == interleave_separate_source;
798 
799     if (sso & sss) {
800 	/* Both masks have separate sources. */
801 	int mask_next = channel_next(&penum->mask[1], &penum->pixel);
802 
803 	memset(wanted + 2, (mask_next <= 0 ? 0xff : 0), info->num_planes - 2);
804 	wanted[1] = (mask_next >= 0 ? 0xff : 0);
805 	if (wanted[1]) {
806 	    mask_next = channel_next(&penum->mask[0], &penum->mask[1]);
807 	    wanted[0] = mask_next >= 0;
808 	} else
809 	    wanted[0] = 0;
810 	return false;		/* see below */
811     } else if (sso | sss) {
812 	/* Only one separate source. */
813 	const image3x_channel_state_t *pics =
814 	    (sso ? &penum->mask[0] : &penum->mask[1]);
815 	int mask_next = channel_next(pics, &penum->pixel);
816 
817 	wanted[0] = (mask_next >= 0 ? 0xff : 0);
818 	memset(wanted + 1, (mask_next <= 0 ? 0xff : 0), info->num_planes - 1);
819 	/*
820 	 * In principle, wanted will always be true for both mask and pixel
821 	 * data if the full_heights are equal.  Unfortunately, even in this
822 	 * case, processing may be interrupted after a mask row has been
823 	 * passed to the underlying image processor but before the data row
824 	 * has been passed, in which case pixel data will be 'wanted', but
825 	 * not mask data, for the next call.  Therefore, we must return
826 	 * false.
827 	 */
828 	return false
829 	    /*(next == 0 &&
830 	      pics->full_height == penum->pixel.full_height)*/;
831     } else {
832 	/* Everything is chunky, only 1 plane. */
833 	wanted[0] = 0xff;
834 	return true;
835     }
836 }
837 
838 /* Clean up after processing an ImageType 3x image. */
839 static int
gx_image3x_end_image(gx_image_enum_common_t * info,bool draw_last)840 gx_image3x_end_image(gx_image_enum_common_t * info, bool draw_last)
841 {
842     gx_image3x_enum_t *penum = (gx_image3x_enum_t *) info;
843     gs_memory_t *mem = penum->memory;
844     gx_device *mdev0 = penum->mask[0].mdev;
845     int ocode =
846 	(penum->mask[0].info ? gx_image_end(penum->mask[0].info, draw_last) :
847 	 0);
848     gx_device *mdev1 = penum->mask[1].mdev;
849     int scode =
850 	(penum->mask[1].info ? gx_image_end(penum->mask[1].info, draw_last) :
851 	 0);
852     gx_device *pcdev = penum->pcdev;
853     int pcode = gx_image_end(penum->pixel.info, draw_last);
854 
855     gs_closedevice(pcdev);
856     if (mdev0)
857 	gs_closedevice(mdev0);
858     if (mdev1)
859 	gs_closedevice(mdev1);
860     gs_free_object(mem, penum->mask[0].data,
861 		   "gx_image3x_end_image(mask[0].data)");
862     gs_free_object(mem, penum->mask[1].data,
863 		   "gx_image3x_end_image(mask[1].data)");
864     gs_free_object(mem, penum->pixel.data,
865 		   "gx_image3x_end_image(pixel.data)");
866     gs_free_object(mem, pcdev, "gx_image3x_end_image(pcdev)");
867     gs_free_object(mem, mdev0, "gx_image3x_end_image(mask[0].mdev)");
868     gs_free_object(mem, mdev1, "gx_image3x_end_image(mask[1].mdev)");
869     gx_image_free_enum(&info);
870     return (pcode < 0 ? pcode : scode < 0 ? scode : ocode);
871 }
872