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