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: gdevplnx.c 8803 2008-06-24 14:16:29Z leonardo $*/
15 /* Plane extraction device */
16 #include "gx.h"
17 #include "gserrors.h"
18 #include "gsbitops.h"
19 #include "gsrop.h"		/* for logical op access */
20 #include "gsstruct.h"
21 #include "gsutil.h"
22 #include "gxdcolor.h"
23 #include "gxcmap.h"		/* requires gxdcolor.h */
24 #include "gxdevice.h"
25 #include "gxdevmem.h"
26 #include "gxdither.h"
27 #include "gxgetbit.h"
28 #include "gxiparam.h"
29 #include "gxistate.h"
30 #include "gdevplnx.h"
31 
32 /* Define the size of the locally allocated bitmap buffers. */
33 #define COPY_COLOR_BUF_SIZE 100
34 #define TILE_RECTANGLE_BUF_SIZE 100
35 #define COPY_ROP_SOURCE_BUF_SIZE 100
36 #define COPY_ROP_TEXTURE_BUF_SIZE 100
37 
38 /* GC procedures */
39 static
40 ENUM_PTRS_WITH(device_plane_extract_enum_ptrs, gx_device_plane_extract *edev)
41     ENUM_PREFIX(st_device_forward, 1);
42 case 0: ENUM_RETURN(gx_device_enum_ptr(edev->target));
43 ENUM_PTRS_END
RELOC_PTRS_WITH(device_plane_extract_reloc_ptrs,gx_device_plane_extract * edev)44 static RELOC_PTRS_WITH(device_plane_extract_reloc_ptrs, gx_device_plane_extract *edev)
45 {
46     RELOC_PREFIX(st_device_forward);
47     edev->plane_dev = gx_device_reloc_ptr(edev->plane_dev, gcst);
48 }
49 RELOC_PTRS_END
50 public_st_device_plane_extract();
51 
52 /* Driver procedures */
53 static dev_proc_open_device(plane_open_device);
54 static dev_proc_fill_rectangle(plane_fill_rectangle);
55 static dev_proc_copy_mono(plane_copy_mono);
56 static dev_proc_copy_color(plane_copy_color);
57 static dev_proc_copy_alpha(plane_copy_alpha);
58 static dev_proc_fill_path(plane_fill_path);
59 static dev_proc_stroke_path(plane_stroke_path);
60 static dev_proc_fill_mask(plane_fill_mask);
61 static dev_proc_fill_parallelogram(plane_fill_parallelogram);
62 static dev_proc_fill_triangle(plane_fill_triangle);
63 static dev_proc_strip_tile_rectangle(plane_strip_tile_rectangle);
64 static dev_proc_strip_copy_rop(plane_strip_copy_rop);
65 static dev_proc_begin_typed_image(plane_begin_typed_image);
66 static dev_proc_get_bits_rectangle(plane_get_bits_rectangle);
67 
68 /* Device prototype */
69 static const gx_device_plane_extract gs_plane_extract_device = {
70     std_device_std_body(gx_device_plane_extract, 0, "plane_extract",
71 			0, 0, 72, 72),
72     {
73 	plane_open_device,
74 	NULL,
75 	NULL,
76 	NULL,
77 	gx_default_close_device,
78 	NULL,
79 	NULL,
80 	plane_fill_rectangle,
81 	gx_default_tile_rectangle,
82 	plane_copy_mono,
83 	plane_copy_color,
84 	gx_default_draw_line,
85 	gx_default_get_bits,
86 	NULL,
87 	NULL,
88 	NULL,
89 	NULL,
90 	NULL,
91 	NULL,
92 	NULL,
93 	NULL,
94 	plane_copy_alpha,
95 	NULL,
96 	gx_default_copy_rop,
97 	plane_fill_path,
98 	plane_stroke_path,
99 	plane_fill_mask,
100 	gx_default_fill_trapezoid,
101 	plane_fill_parallelogram,
102 	plane_fill_triangle,
103 	gx_default_draw_thin_line,
104 	gx_default_begin_image,
105 	gx_default_image_data,
106 	gx_default_end_image,
107 	plane_strip_tile_rectangle,
108 	plane_strip_copy_rop,
109 	NULL,
110 	plane_begin_typed_image,
111 	plane_get_bits_rectangle,
112 	NULL,
113 	gx_no_create_compositor, /* WRONG */
114 	NULL,
115 	gx_default_text_begin
116     },
117     /* device-specific members */
118     NULL,				/* target */
119     NULL,				/* plane_dev */
120     { 0 },				/* plane */
121     0,					/* plane_white */
122     0,					/* plane_mask */
123     0,					/* plane_dev_is_memory */
124     1 /*true*/				/* any_marks */
125 };
126 
127 /* ---------------- Utilities ---------------- */
128 
129 /* Extract the selected plane from a color (gx_color_index). */
130 #define COLOR_PIXEL(edev, color)\
131   ( ((color) >> (edev)->plane.shift) & (edev)->plane_mask )
132 /* Do the same if the color might be transparent. */
133 #define TRANS_COLOR_PIXEL(edev, color)\
134  ((color) == gx_no_color_index ? gx_no_color_index : COLOR_PIXEL(edev, color))
135 
136 /*
137  * Reduce the drawing color to one for the selected plane.
138  * All we care about is whether the drawing operation should be skipped.
139  */
140 typedef enum {
141     REDUCE_SKIP,
142     REDUCE_DRAW,
143     REDUCE_FAILED			/* couldn't reduce */
144 } reduced_color_t;
145 #define REDUCE_PURE(edev, pixel)\
146   ((pixel) == (edev)->plane_white && !(edev)->any_marks ?  REDUCE_SKIP :\
147    ((edev)->any_marks = true, REDUCE_DRAW))
148 static reduced_color_t
reduce_drawing_color(gx_device_color * ppdc,gx_device_plane_extract * edev,const gx_drawing_color * pdevc,gs_logical_operation_t * plop)149 reduce_drawing_color(gx_device_color *ppdc, gx_device_plane_extract *edev,
150 		     const gx_drawing_color *pdevc,
151 		     gs_logical_operation_t *plop)
152 {
153     reduced_color_t reduced;
154 
155     if (gx_dc_is_pure(pdevc)) {
156 	gx_color_index pixel = COLOR_PIXEL(edev, gx_dc_pure_color(pdevc));
157 
158 	set_nonclient_dev_color(ppdc, pixel);
159 	reduced = REDUCE_PURE(edev, pixel);
160     } else if (gx_dc_is_binary_halftone(pdevc)) {
161 	gx_color_index pixel0 =
162 	    TRANS_COLOR_PIXEL(edev, gx_dc_binary_color0(pdevc));
163 	gx_color_index pixel1 =
164 	    TRANS_COLOR_PIXEL(edev, gx_dc_binary_color1(pdevc));
165 
166 	if (pixel0 == pixel1) {
167 	    set_nonclient_dev_color(ppdc, pixel0);
168 	    reduced = REDUCE_PURE(edev, pixel0);
169 	} else {
170 	    *ppdc = *pdevc;
171 	    ppdc->colors.binary.color[0] = pixel0;
172 	    ppdc->colors.binary.color[1] = pixel1;
173 	    edev->any_marks = true;
174 	    reduced = REDUCE_DRAW;
175 	}
176     } else if (color_is_colored_halftone(pdevc)) {
177 	int plane = edev->plane.index;
178 	int i;
179 
180 	*ppdc = *pdevc;
181 	for (i = 0; i < countof(ppdc->colors.colored.c_base); ++i)
182 	    if (i != edev->plane.index) {
183 		ppdc->colors.colored.c_base[i] = 0;
184 		ppdc->colors.colored.c_level[i] = 0;
185 	    }
186 	ppdc->colors.colored.plane_mask &= 1 << plane;
187 	if (ppdc->colors.colored.c_level[plane] == 0) {
188 	    gx_devn_reduce_colored_halftone(ppdc, (gx_device *)edev);
189 	    ppdc->colors.pure = COLOR_PIXEL(edev, ppdc->colors.pure);
190 	    reduced = REDUCE_PURE(edev, gx_dc_pure_color(ppdc));
191 	} else if (ppdc->colors.colored.alpha != gx_max_color_value)
192 	    return REDUCE_FAILED; /* can't reduce */
193 	else {
194 	    gx_devn_reduce_colored_halftone(ppdc, (gx_device *)edev);
195 	    ppdc->colors.binary.color[0] =
196 		COLOR_PIXEL(edev, ppdc->colors.binary.color[0]);
197 	    ppdc->colors.binary.color[1] =
198 		COLOR_PIXEL(edev, ppdc->colors.binary.color[1]);
199 	    gx_color_load(ppdc, NULL, (gx_device *)edev);
200 	    edev->any_marks = true;
201 	    reduced = REDUCE_DRAW;
202 	}
203     } else
204 	return REDUCE_FAILED;		/* can't handle it */
205     if (*plop & lop_T_transparent) {
206 	/*
207 	 * If the logical operation invokes transparency for the texture, we
208 	 * must do some extra work, since a color that was originally opaque
209 	 * may become transparent (white) if reduced to a single plane.  If
210 	 * RasterOp transparency were calculated before halftoning, life
211 	 * would be easy: we would simply turn off texture transparency in
212 	 * the logical operation iff the original (not reduced) color was
213 	 * not white.  Unfortunately, RasterOp transparency is calculated
214 	 * after halftoning.  (This is arguably wrong, but it's how we've
215 	 * defined it.)  Therefore, if transparency is involved with a
216 	 * white color or a halftone that can include white, we must keep
217 	 * the entire pixel together for the RasterOp.
218 	 */
219 	gx_color_index white = gx_device_white((gx_device *)edev);
220 
221 	/*
222 	 * Given that we haven't failed, the only possible colors at this
223 	 * point are pure or binary halftone.
224 	 */
225 	if (gx_dc_is_pure(ppdc)) {
226 	    if (gx_dc_pure_color(pdevc) != white)
227 		*plop &= ~lop_T_transparent;
228 	    else if (!gx_dc_is_pure(pdevc))
229 		return REDUCE_FAILED;
230 	} else {
231 	    if (gx_dc_binary_color0(pdevc) != white &&
232 		gx_dc_binary_color1(pdevc) != white) {
233 		*plop &= ~lop_T_transparent;
234 	    } else
235 		return REDUCE_FAILED;
236 	}
237     }
238     return reduced;
239 }
240 
241 /*
242  * Set up to create the plane-extracted bitmap corresponding to a
243  * source or halftone pixmap.  If the bitmap doesn't fit in the locally
244  * allocated buffer, we may either do the operation in pieces, or allocate
245  * a buffer on the heap.  The control structure is:
246  *	begin_tiling(&state, ...);
247  *	do {
248  *	    extract_partial_tile(&state);
249  *	    ... process tile in buffer ...
250  *	} while (next_tile(&state));
251  *	end_tiling(&state);
252  * If partial_ok is false, there is only a single tile, so the do ... while
253  * is not used.
254  */
255 typedef struct tiling_state_s {
256 	/* Save the original operands. */
257     const gx_device_plane_extract *edev;
258     const byte *data;
259     int data_x;
260     uint raster;
261     int width, height;
262     int dest_x;			/* only for copy_color, defaults to 0 */
263 	/* Define the (aligned) buffer for doing the operation. */
264     struct tsb_ {
265 	byte *data;
266 	uint size;
267 	uint raster;
268 	bool on_heap;
269     } buffer;
270 	/* Record the current tile available for processing. */
271 	/* The client may read these out. */
272     gs_int_point offset;
273     gs_int_point size;
274 	/* Record private tiling parameters. */
275     int per_tile_width;
276 } tiling_state_t;
277 
278 /*
279  * Extract the plane's data from one subrectangle of a source tile.
280  */
281 static inline int /* ignore the return value */
extract_partial_tile(const tiling_state_t * pts)282 extract_partial_tile(const tiling_state_t *pts)
283 {
284     const gx_device_plane_extract * const edev = pts->edev;
285     bits_plane_t dest, source;
286 
287     dest.data.write = pts->buffer.data + pts->offset.y * pts->buffer.raster;
288     dest.raster = pts->buffer.raster;
289     dest.depth = edev->plane.depth;
290     dest.x = pts->dest_x;
291 
292     source.data.read = pts->data + pts->offset.y * pts->raster;
293     source.raster = pts->raster;
294     source.depth = edev->color_info.depth;
295     source.x = pts->data_x + pts->offset.x;
296 
297     bits_extract_plane(&dest, &source, edev->plane.shift,
298 		       pts->size.x, pts->size.y);
299     return 0;
300 }
301 
302 /*
303  * Set up to start (possibly) tiling.  Return 0 if the entire tile fit,
304  * 1 if a partial tile fit, or a negative error code.
305  */
306 static int
begin_tiling(tiling_state_t * pts,gx_device_plane_extract * edev,const byte * data,int data_x,uint raster,int width,int height,byte * local_buffer,uint buffer_size,bool partial_ok)307 begin_tiling(tiling_state_t *pts, gx_device_plane_extract *edev,
308     const byte *data, int data_x, uint raster, int width, int height,
309     byte *local_buffer, uint buffer_size, bool partial_ok)
310 {
311     uint width_raster =
312 	bitmap_raster(width * edev->plane_dev->color_info.depth);
313     uint full_size = width_raster * height;
314 
315     pts->edev = edev;
316     pts->data = data, pts->data_x = data_x, pts->raster = raster;
317     pts->width = width, pts->height = height;
318     pts->dest_x = 0;
319     if (full_size <= buffer_size) {
320 	pts->buffer.data = local_buffer;
321 	pts->buffer.size = buffer_size;
322 	pts->buffer.raster = width_raster;
323 	pts->buffer.on_heap = false;
324 	pts->size.x = width, pts->size.y = height;
325     } else if (partial_ok) {
326 	pts->buffer.data = local_buffer;
327 	pts->buffer.size = buffer_size;
328 	pts->buffer.on_heap = false;
329 	if (buffer_size >= width_raster) {
330 	    pts->buffer.raster = width_raster;
331 	    pts->size.x = width;
332 	    pts->size.y = buffer_size / width_raster;
333 	} else {
334 	    pts->buffer.raster = buffer_size & -align_bitmap_mod;
335 	    pts->size.x =
336 		pts->buffer.raster * (8 / edev->plane_dev->color_info.depth);
337 	    pts->size.y = 1;
338 	}
339     } else {
340 	pts->buffer.data =
341 	    gs_alloc_bytes(edev->memory, full_size, "begin_tiling");
342 	if (!pts->buffer.data)
343 	    return_error(gs_error_VMerror);
344 	pts->buffer.size = full_size;
345 	pts->buffer.raster = width_raster;
346 	pts->buffer.on_heap = true;
347 	pts->size.x = width, pts->size.y = height;
348     }
349     pts->buffer.raster = width_raster;
350     pts->offset.x = pts->offset.y = 0;
351     pts->per_tile_width = pts->size.x;
352     return pts->buffer.size < full_size;
353 }
354 
355 /*
356  * Advance to the next tile.  Return true if there are more tiles to do.
357  */
358 static bool
next_tile(tiling_state_t * pts)359 next_tile(tiling_state_t *pts)
360 {
361     if ((pts->offset.x += pts->size.x) >= pts->width) {
362 	if ((pts->offset.y += pts->size.y) >= pts->height)
363 	    return false;
364 	pts->offset.x = 0;
365 	pts->size.x = pts->per_tile_width;
366 	if (pts->offset.y + pts->size.y >= pts->height)
367 	    pts->size.y = pts->height - pts->offset.y;
368     } else if (pts->offset.x + pts->size.x >= pts->width)
369 	pts->size.x = pts->width - pts->offset.x;
370     return true;
371 }
372 
373 /*
374  * Finish tiling by freeing the buffer if necessary.
375  */
376 static void
end_tiling(tiling_state_t * pts)377 end_tiling(tiling_state_t *pts)
378 {
379     if (pts->buffer.on_heap)
380 	gs_free_object(pts->edev->memory, pts->buffer.data, "end_tiling");
381 }
382 
383 /* ---------------- Initialization ---------------- */
384 
385 int
plane_device_init(gx_device_plane_extract * edev,gx_device * target,gx_device * plane_dev,const gx_render_plane_t * render_plane,bool clear)386 plane_device_init(gx_device_plane_extract *edev, gx_device *target,
387     gx_device *plane_dev, const gx_render_plane_t *render_plane, bool clear)
388 {
389     /* Check for compatibility of the plane specification. */
390     if (render_plane->depth > plane_dev->color_info.depth)
391 	return_error(gs_error_rangecheck);
392     gx_device_init((gx_device *)edev,
393 		   (const gx_device *)&gs_plane_extract_device,
394 		   edev->memory, true);
395     check_device_separable((gx_device *)edev);
396     gx_device_forward_fill_in_procs((gx_device_forward *)edev);
397     gx_device_set_target((gx_device_forward *)edev, target);
398     gx_device_copy_params((gx_device *)edev, target);
399     edev->plane_dev = plane_dev;
400     edev->plane = *render_plane;
401     plane_open_device((gx_device *)edev);
402     if (clear) {
403 	dev_proc(plane_dev, fill_rectangle)
404 	    (plane_dev, 0, 0, plane_dev->width, plane_dev->height,
405 	     edev->plane_white);
406 	edev->any_marks = false;
407     }
408     return 0;
409 }
410 
411 /* ---------------- Driver procedures ---------------- */
412 
413 static int
plane_open_device(gx_device * dev)414 plane_open_device(gx_device *dev)
415 {
416     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
417     gx_device * const plane_dev = edev->plane_dev;
418     int plane_depth = plane_dev->color_info.depth;
419     const gx_device_memory * const mdproto =
420 	gdev_mem_device_for_bits(plane_depth);
421 
422     edev->plane_white = gx_device_white(plane_dev);
423     edev->plane_mask = (1 << plane_depth) - 1;
424     edev->plane_dev_is_memory = mdproto != 0 &&
425 	dev_proc(plane_dev, copy_color) == dev_proc(mdproto, copy_color);
426     /* We don't set or clear any_marks here: see ...init above. */
427     return 0;
428 }
429 
430 static int
plane_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)431 plane_fill_rectangle(gx_device *dev,
432     int x, int y, int w, int h, gx_color_index color)
433 {
434     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
435     gx_device * const plane_dev = edev->plane_dev;
436     gx_color_index pixel = COLOR_PIXEL(edev, color);
437 
438     if (pixel != edev->plane_white)
439 	edev->any_marks = true;
440     else if (!edev->any_marks)
441 	return 0;
442     return dev_proc(plane_dev, fill_rectangle)
443 	(plane_dev, x, y, w, h, pixel);
444 }
445 
446 static int
plane_copy_mono(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1)447 plane_copy_mono(gx_device *dev,
448     const byte *data, int data_x, int raster, gx_bitmap_id id,
449     int x, int y, int w, int h,
450     gx_color_index color0, gx_color_index color1)
451 {
452     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
453     gx_device * const plane_dev = edev->plane_dev;
454     gx_color_index pixel0 = TRANS_COLOR_PIXEL(edev, color0);
455     gx_color_index pixel1 = TRANS_COLOR_PIXEL(edev, color1);
456 
457     if (pixel0 == pixel1)
458 	return plane_fill_rectangle(dev, x, y, w, h, color0);
459     if ((pixel0 == edev->plane_white || pixel0 == gx_no_color_index) &&
460 	(pixel1 == edev->plane_white || pixel1 == gx_no_color_index)) {
461 	/* This operation will only write white. */
462 	if (!edev->any_marks)
463 	    return 0;
464     } else
465 	edev->any_marks = true;
466     return dev_proc(plane_dev, copy_mono)
467 	(plane_dev, data, data_x, raster, id, x, y, w, h, pixel0, pixel1);
468 }
469 
470 static int
plane_copy_color(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int w,int h)471 plane_copy_color(gx_device *dev,
472     const byte *data, int data_x, int raster, gx_bitmap_id id,
473     int x, int y, int w, int h)
474 {
475     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
476     gx_device * const plane_dev = edev->plane_dev;
477     tiling_state_t state;
478     long buf[COPY_COLOR_BUF_SIZE / sizeof(long)];
479     int code;
480 
481     if (edev->plane_dev_is_memory) {
482 	/* Reduce the source directly into the plane device. */
483 	gx_device_memory * const mdev = (gx_device_memory *)plane_dev;
484 
485 	fit_copy(edev, data, data_x, raster, id, x, y, w, h);
486 	code = begin_tiling(&state, edev, data, data_x, raster, w, h,
487 			    scan_line_base(mdev, y), max_uint, false);
488 	if (code < 0)
489 	    return code;
490 	state.dest_x = x;
491 	state.buffer.raster = mdev->raster;
492 	extract_partial_tile(&state);
493 	end_tiling(&state);
494 	edev->any_marks = true;
495 	return 0;
496     }
497     code = begin_tiling(&state, edev, data, data_x, raster,
498 			w, h, (byte *)buf, sizeof(buf), true);
499     if (code < 0)
500 	return code;
501     do {
502 	extract_partial_tile(&state);
503 	code = dev_proc(plane_dev, copy_color)
504 	    (plane_dev, state.buffer.data, 0, state.buffer.raster,
505 	     gx_no_bitmap_id, x + state.offset.x, y + state.offset.y,
506 	     state.size.x, state.size.y);
507     } while (code >= 0 && next_tile(&state));
508     end_tiling(&state);
509     edev->any_marks = true;
510     return code;
511 }
512 
513 static int
plane_copy_alpha(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color,int depth)514 plane_copy_alpha(gx_device *dev, const byte *data, int data_x,
515     int raster, gx_bitmap_id id, int x, int y, int w, int h,
516     gx_color_index color, int depth)
517 {
518     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
519     gx_device * const plane_dev = edev->plane_dev;
520     gx_color_index pixel = COLOR_PIXEL(edev, color);
521 
522     if (pixel != edev->plane_white)
523 	edev->any_marks = true;
524     else if (!edev->any_marks)
525 	return 0;
526     return dev_proc(plane_dev, copy_alpha)
527 	(plane_dev, data, data_x, raster, id, x, y, w, h, pixel, depth);
528 }
529 
530 static int
plane_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdevc,const gx_clip_path * pcpath)531 plane_fill_path(gx_device *dev,
532     const gs_imager_state *pis, gx_path *ppath,
533     const gx_fill_params *params,
534     const gx_drawing_color *pdevc, const gx_clip_path *pcpath)
535 {
536     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
537     gx_device * const plane_dev = edev->plane_dev;
538     gs_logical_operation_t lop_orig =
539 	gs_current_logical_op((const gs_state *)pis);
540     gs_logical_operation_t lop = lop_orig;
541     gx_device_color dcolor;
542 
543     switch (reduce_drawing_color(&dcolor, edev, pdevc, &lop)) {
544     case REDUCE_SKIP:
545 	return 0;
546     case REDUCE_DRAW: {
547 	gs_imager_state lopis;
548 	const gs_imager_state *pis_draw = pis;
549 
550 	if (lop != lop_orig) {
551 	    lopis = *pis;
552 	    gs_set_logical_op((gs_state *)&lopis, lop);
553 	    pis_draw = &lopis;
554 	}
555 	return dev_proc(plane_dev, fill_path)
556 	    (plane_dev, pis_draw, ppath, params, &dcolor, pcpath);
557     }
558     default /*REDUCE_FAILED*/:
559 	return gx_default_fill_path(dev, pis, ppath, params, pdevc, pcpath);
560     }
561 }
562 
563 static int
plane_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdevc,const gx_clip_path * pcpath)564 plane_stroke_path(gx_device *dev,
565     const gs_imager_state *pis, gx_path *ppath,
566     const gx_stroke_params *params,
567     const gx_drawing_color *pdevc, const gx_clip_path *pcpath)
568 {
569     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
570     gx_device * const plane_dev = edev->plane_dev;
571     gs_logical_operation_t lop_orig =
572 	gs_current_logical_op((const gs_state *)pis);
573     gs_logical_operation_t lop = lop_orig;
574     gx_device_color dcolor;
575 
576     switch (reduce_drawing_color(&dcolor, edev, pdevc, &lop)) {
577     case REDUCE_SKIP:
578 	return 0;
579     case REDUCE_DRAW: {
580 	gs_imager_state lopis;
581 	const gs_imager_state *pis_draw = pis;
582 
583 	if (lop != lop_orig) {
584 	    lopis = *pis;
585 	    gs_set_logical_op((gs_state *)&lopis, lop);
586 	    pis_draw = &lopis;
587 	}
588 	return dev_proc(plane_dev, stroke_path)
589 	    (plane_dev, pis_draw, ppath, params, &dcolor, pcpath);
590     }
591     default /*REDUCE_FAILED*/:
592 	return gx_default_stroke_path(dev, pis, ppath, params, pdevc, pcpath);
593     }
594 }
595 
596 static int
plane_fill_mask(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int w,int h,const gx_drawing_color * pdcolor,int depth,gs_logical_operation_t lop,const gx_clip_path * pcpath)597 plane_fill_mask(gx_device *dev,
598     const byte *data, int data_x, int raster, gx_bitmap_id id,
599     int x, int y, int w, int h,
600     const gx_drawing_color *pdcolor, int depth,
601     gs_logical_operation_t lop, const gx_clip_path *pcpath)
602 {
603     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
604     gx_device * const plane_dev = edev->plane_dev;
605     gx_device_color dcolor;
606 
607     switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) {
608     case REDUCE_SKIP:
609 	return 0;
610     case REDUCE_DRAW:
611 	return dev_proc(plane_dev, fill_mask)
612 	    (plane_dev, data, data_x, raster, gx_no_bitmap_id, x, y, w, h,
613 	     &dcolor, depth, lop, pcpath);
614     default /*REDUCE_FAILED*/:
615 	return gx_default_fill_mask(dev, data, data_x, raster, gx_no_bitmap_id,
616 				    x, y, w, h, &dcolor, depth, lop, pcpath);
617     }
618 }
619 
620 static int
plane_fill_parallelogram(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)621 plane_fill_parallelogram(gx_device * dev,
622     fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
623     const gx_drawing_color * pdcolor, gs_logical_operation_t lop)
624 {
625     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
626     gx_device * const plane_dev = edev->plane_dev;
627     gx_device_color dcolor;
628 
629     switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) {
630     case REDUCE_SKIP:
631 	return 0;
632     case REDUCE_DRAW:
633 	return dev_proc(plane_dev, fill_parallelogram)
634 	    (plane_dev, px, py, ax, ay, bx, by, &dcolor, lop);
635     default /*REDUCE_FAILED*/:
636 	return gx_default_fill_parallelogram(dev, px, py, ax, ay, bx, by,
637 					     pdcolor, lop);
638     }
639 }
640 
641 static int
plane_fill_triangle(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)642 plane_fill_triangle(gx_device * dev,
643     fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
644     const gx_drawing_color * pdcolor, gs_logical_operation_t lop)
645 {
646     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
647     gx_device * const plane_dev = edev->plane_dev;
648     gx_device_color dcolor;
649 
650     switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) {
651     case REDUCE_SKIP:
652 	return 0;
653     case REDUCE_DRAW:
654 	return dev_proc(plane_dev, fill_triangle)
655 	    (plane_dev, px, py, ax, ay, bx, by, &dcolor, lop);
656     default /*REDUCE_FAILED*/:
657 	return gx_default_fill_triangle(dev, px, py, ax, ay, bx, by,
658 					pdcolor, lop);
659     }
660 }
661 
662 static int
plane_strip_tile_rectangle(gx_device * dev,const gx_strip_bitmap * tiles,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1,int phase_x,int phase_y)663 plane_strip_tile_rectangle(gx_device *dev,
664     const gx_strip_bitmap *tiles, int x, int y, int w, int h,
665     gx_color_index color0, gx_color_index color1,
666     int phase_x, int phase_y)
667 {
668     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
669     gx_device * const plane_dev = edev->plane_dev;
670     gx_color_index pixel0 = TRANS_COLOR_PIXEL(edev, color0);
671     gx_color_index pixel1 = TRANS_COLOR_PIXEL(edev, color1);
672 
673     if (pixel0 == pixel1) {
674 	if (pixel0 != gx_no_color_index)
675 	    return plane_fill_rectangle(dev, x, y, w, h, color0);
676 	/* The tile is a pixmap rather than a bitmap. */
677 	/* We should use the default implementation if it is small.... */
678 	{
679 	    gx_strip_bitmap plane_tile;
680 	    tiling_state_t state;
681 	    long buf[TILE_RECTANGLE_BUF_SIZE / sizeof(long)];
682 	    int code = begin_tiling(&state, edev, tiles->data, 0, tiles->raster,
683 			tiles->size.x, tiles->size.y,
684 				(byte *)buf, sizeof(buf), false);
685 
686 	    if (code < 0)
687 		return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h,
688 					color0, color1, phase_x, phase_y);
689 	    extract_partial_tile(&state);
690 	    plane_tile = *tiles;
691 	    plane_tile.data = state.buffer.data;
692 	    plane_tile.raster = state.buffer.raster;
693 	    plane_tile.id = gx_no_bitmap_id;
694 	    code = dev_proc(plane_dev, strip_tile_rectangle)
695 		(plane_dev, &plane_tile, x, y, w, h, pixel0, pixel1,
696 		 phase_x, phase_y);
697 	    end_tiling(&state);
698 	    edev->any_marks = true;
699 	    return code;
700 	}
701     }
702     if ((pixel0 == edev->plane_white || pixel0 == gx_no_color_index) &&
703 	(pixel1 == edev->plane_white || pixel1 == gx_no_color_index)) {
704 	/* This operation will only write white. */
705 	if (!edev->any_marks)
706 	    return 0;
707     } else
708 	edev->any_marks = true;
709     return dev_proc(plane_dev, strip_tile_rectangle)
710 	(plane_dev, tiles, x, y, w, h, pixel0, pixel1, phase_x, phase_y);
711 }
712 
713 static int
plane_strip_copy_rop(gx_device * dev,const byte * sdata,int sourcex,uint sraster,gx_bitmap_id id,const gx_color_index * scolors,const gx_strip_bitmap * textures,const gx_color_index * tcolors,int x,int y,int w,int h,int phase_x,int phase_y,gs_logical_operation_t lop)714 plane_strip_copy_rop(gx_device *dev,
715     const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
716     const gx_color_index *scolors,
717     const gx_strip_bitmap *textures, const gx_color_index *tcolors,
718     int x, int y, int w, int h,
719     int phase_x, int phase_y, gs_logical_operation_t lop)
720 {
721     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
722     gx_device * const plane_dev = edev->plane_dev;
723     gs_rop3_t rop = lop_rop(lop);
724     struct crp_ {
725 	gx_color_index pixels[2];
726 	gx_color_index *colors;
727 	tiling_state_t state;
728     } source, texture;
729     long sbuf[COPY_ROP_SOURCE_BUF_SIZE / sizeof(long)];
730     long tbuf[COPY_ROP_TEXTURE_BUF_SIZE / sizeof(long)];
731     const byte *plane_source;
732     uint plane_raster = 0xbaadf00d; /* Initialize against indeterminizm. */
733     gx_strip_bitmap plane_texture;
734     const gx_strip_bitmap *plane_textures = NULL;
735     int code;
736 
737     /* We should do better than this on transparency.... */
738     if (lop & (lop_S_transparent | lop_T_transparent))
739 	return gx_default_strip_copy_rop(dev, sdata, sourcex, sraster, id,
740 					 scolors, textures, tcolors,
741 					 x, y, w, h, phase_x, phase_y, lop);
742     if (!rop3_uses_S(rop)) {
743 	sdata = 0;
744 	source.colors = 0;
745     } else if (scolors) {
746 	source.pixels[0] = COLOR_PIXEL(edev, scolors[0]);
747 	source.pixels[1] = COLOR_PIXEL(edev, scolors[1]);
748 	if (source.pixels[0] == source.pixels[1])
749 	    sdata = 0;
750 	source.colors = source.pixels;
751     }
752     else
753 	source.colors = 0;
754     if (!rop3_uses_T(rop)) {
755 	textures = 0;
756 	texture.colors = 0;
757     } else if (tcolors) {
758 	texture.pixels[0] = COLOR_PIXEL(edev, tcolors[0]);
759 	texture.pixels[1] = COLOR_PIXEL(edev, tcolors[1]);
760 	if (texture.pixels[0] == texture.pixels[1])
761 	    textures = 0;
762 	texture.colors = texture.pixels;
763     }
764     else
765 	texture.colors = 0;
766     if (sdata) {
767 	code = begin_tiling(&source.state, edev, sdata, sourcex, sraster, w, y,
768 			    (byte *)sbuf, sizeof(sbuf), true);
769 	if (code < 0)
770 	    return gx_default_strip_copy_rop(dev, sdata, sourcex, sraster, id,
771 					     scolors, textures, tcolors,
772 					     x, y, w, h, phase_x, phase_y, lop);
773 	plane_source = source.state.buffer.data;
774 	plane_raster = source.state.buffer.raster;
775     } else
776 	plane_source = 0;
777     if (textures) {
778 	code = begin_tiling(&texture.state, edev, textures->data, 0,
779 			    textures->raster, textures->size.x,
780 			    textures->size.y, (byte *)tbuf, sizeof(tbuf),
781 			    false);
782 	if (code < 0) {
783 	    if (plane_source)
784 		end_tiling(&source.state);
785 	    return code;
786 	}
787 	plane_texture = *textures;
788 	plane_texture.data = texture.state.buffer.data;
789 	plane_texture.raster = texture.state.buffer.raster;
790 	plane_textures = &plane_texture;
791     }
792     if (textures)
793 	extract_partial_tile(&texture.state);
794     do {
795 	if (sdata)
796 	    extract_partial_tile(&source.state);
797 	code = dev_proc(plane_dev, strip_copy_rop)
798 	    (plane_dev, plane_source, sourcex, plane_raster, gx_no_bitmap_id,
799 	     source.colors, plane_textures, texture.colors,
800 	     x, y, w, h, phase_x, phase_y, lop);
801     } while (code >= 0 && sdata && next_tile(&source.state));
802     if (textures)
803 	end_tiling(&texture.state);
804     if (sdata)
805 	end_tiling(&source.state);
806     return code;
807 }
808 
809 /* ---------------- Images ---------------- */
810 
811 /* Define the state for image rendering. */
812 typedef struct plane_image_enum_s {
813     gx_image_enum_common;
814     gx_image_enum_common_t *info; /* plane device enumerator */
815     const gs_imager_state *pis;	/* original imager state */
816     gs_imager_state *pis_image;	/* modified imager state */
817 } plane_image_enum_t;
818 gs_private_st_suffix_add3(st_plane_image_enum, plane_image_enum_t,
819   "plane_image_enum_t", plane_image_enum_enum_ptrs,
820   plane_image_enum_reloc_ptrs, st_gx_image_enum_common, info, pis, pis_image);
821 
822 /*
823  * Reduce drawing colors returned by color mapping.  Note that these
824  * assume that the call of reduce_drawing_color will not fail:
825  * plane_begin_typed_image must ensure this.
826  *
827  * In the imager state passed to these procedures, the client data is
828  * the plane_image_enum_t.
829  */
830 
831 static void
plane_cmap_gray(frac gray,gx_device_color * pdc,const gs_imager_state * pis_image,gx_device * dev,gs_color_select_t select)832 plane_cmap_gray(frac gray, gx_device_color * pdc,
833     const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select)
834 {
835     const plane_image_enum_t *ppie =
836 	(const plane_image_enum_t *)pis_image->client_data;
837     gx_device_plane_extract * const edev =
838 	(gx_device_plane_extract *)ppie->dev;
839     gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image);
840     gx_device_color dcolor;
841 
842     gx_remap_concrete_gray(gray, &dcolor, ppie->pis,
843 			   (gx_device *)edev, select);
844     reduce_drawing_color(pdc, edev, &dcolor, &lop);
845 }
846 static void
plane_cmap_rgb(frac r,frac g,frac b,gx_device_color * pdc,const gs_imager_state * pis_image,gx_device * dev,gs_color_select_t select)847 plane_cmap_rgb(frac r, frac g, frac b, gx_device_color * pdc,
848     const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select)
849 {
850     const plane_image_enum_t *ppie =
851 	(const plane_image_enum_t *)pis_image->client_data;
852     gx_device_plane_extract * const edev =
853 	(gx_device_plane_extract *)ppie->dev;
854     gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image);
855     gx_device_color dcolor;
856 
857     gx_remap_concrete_rgb(r, g, b, &dcolor, ppie->pis,
858 			  (gx_device *)edev, select);
859     reduce_drawing_color(pdc, edev, &dcolor, &lop);
860 }
861 static void
plane_cmap_cmyk(frac c,frac m,frac y,frac k,gx_device_color * pdc,const gs_imager_state * pis_image,gx_device * dev,gs_color_select_t select)862 plane_cmap_cmyk(frac c, frac m, frac y, frac k, gx_device_color * pdc,
863     const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select)
864 {
865     const plane_image_enum_t *ppie =
866 	(const plane_image_enum_t *)pis_image->client_data;
867     gx_device_plane_extract * const edev =
868 	(gx_device_plane_extract *)ppie->dev;
869     gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image);
870     gx_device_color dcolor;
871 
872     gx_remap_concrete_cmyk(c, m, y, k, &dcolor, ppie->pis,
873 			   (gx_device *)edev, select);
874     reduce_drawing_color(pdc, edev, &dcolor, &lop);
875 }
876 static void
plane_cmap_rgb_alpha(frac r,frac g,frac b,frac alpha,gx_device_color * pdc,const gs_imager_state * pis_image,gx_device * dev,gs_color_select_t select)877 plane_cmap_rgb_alpha(frac r, frac g, frac b, frac alpha, gx_device_color * pdc,
878     const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select)
879 {
880     const plane_image_enum_t *ppie =
881 	(const plane_image_enum_t *)pis_image->client_data;
882     gx_device_plane_extract * const edev =
883 	(gx_device_plane_extract *)ppie->dev;
884     gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image);
885     gx_device_color dcolor;
886 
887     gx_remap_concrete_rgb_alpha(r, g, b, alpha, &dcolor, ppie->pis,
888 				(gx_device *)edev, select);
889     reduce_drawing_color(pdc, edev, &dcolor, &lop);
890 }
891 static bool
plane_cmap_is_halftoned(const gs_imager_state * pis_image,gx_device * dev)892 plane_cmap_is_halftoned(const gs_imager_state *pis_image, gx_device *dev)
893 {
894     return false;
895 }
896 
897 static const gx_color_map_procs plane_color_map_procs = {
898     plane_cmap_gray, plane_cmap_rgb, plane_cmap_cmyk, plane_cmap_rgb_alpha,
899     NULL, NULL, plane_cmap_is_halftoned
900 };
901 static const gx_color_map_procs *
plane_get_cmap_procs(const gs_imager_state * pis,const gx_device * dev)902 plane_get_cmap_procs(const gs_imager_state *pis, const gx_device *dev)
903 {
904     return &plane_color_map_procs;
905 }
906 
907 /* Define the image processing procedures. */
908 static image_enum_proc_plane_data(plane_image_plane_data);
909 static image_enum_proc_end_image(plane_image_end_image);
910 static const gx_image_enum_procs_t plane_image_enum_procs = {
911     plane_image_plane_data, plane_image_end_image
912 };
913 
914 static int
plane_begin_typed_image(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 * memory,gx_image_enum_common_t ** pinfo)915 plane_begin_typed_image(gx_device * dev,
916 			const gs_imager_state * pis, const gs_matrix * pmat,
917 		   const gs_image_common_t * pic, const gs_int_rect * prect,
918 	      const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
919 		      gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
920 {
921     /*
922      * For images, we intercept the imager state's cmap_procs and apply
923      * reduce_drawing_color to the colors as they are returned to the image
924      * processing code.  For reasons explained above, we can't do this in
925      * some cases of RasterOp that include transparency.
926      */
927     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
928     gs_logical_operation_t lop = gs_current_logical_op((const gs_state *)pis);
929     const gs_pixel_image_t *pim;
930     plane_image_enum_t *info = 0;
931     gs_imager_state *pis_image = 0;
932     gx_device_color dcolor;
933     bool uses_color = false;
934     int code;
935 
936     /* We can only handle a limited set of image types. */
937     switch (pic->type->index) {
938     case 1: {
939 	const gs_image1_t * const pim1 = (const gs_image1_t *)pic;
940 
941 	if (pim1->Alpha != gs_image_alpha_none)
942 	    goto fail;
943 	uses_color = pim1->ImageMask;
944 	break;
945 	}
946     case 3:
947     case 4:
948 	break;
949     default:
950 	goto fail;
951     }
952     pim = (const gs_pixel_image_t *)pic;
953     if ((lop & lop_S_transparent) ||
954 	((uses_color || pim->CombineWithColor) && (lop & lop_T_transparent))
955 	)
956 	goto fail;
957     if (uses_color || (pim->CombineWithColor && lop_uses_T(lop))) {
958 	if (reduce_drawing_color(&dcolor, edev, pdcolor, &lop) ==
959 	    REDUCE_FAILED)
960 	    goto fail;
961     } else {
962 	/*
963 	 * The drawing color won't be used, but if RasterOp is involved,
964 	 * it may still be accessed in some anomalous cases.
965 	 */
966 	set_nonclient_dev_color(&dcolor, (gx_color_index)0);
967     }
968     info = gs_alloc_struct(memory, plane_image_enum_t, &st_plane_image_enum,
969 			   "plane_image_begin_typed(info)");
970     pis_image = gs_imager_state_copy(pis, memory);
971     if (pis_image == 0 || info == 0)
972 	goto fail;
973     *pis_image = *pis;
974     pis_image->client_data = info;
975     pis_image->get_cmap_procs = plane_get_cmap_procs;
976     code = dev_proc(edev->plane_dev, begin_typed_image)
977 	(edev->plane_dev, pis_image, pmat, pic, prect,
978 	 &dcolor, pcpath, memory, &info->info);
979     if (code < 0)
980 	goto fail;
981     *((gx_image_enum_common_t *)info) = *info->info;
982     info->procs = &plane_image_enum_procs;
983     info->dev = (gx_device *)edev;
984     info->id = gs_next_ids(memory, 1);
985     info->memory = memory;
986     info->pis = pis;
987     info->pis_image = pis_image;
988     *pinfo = (gx_image_enum_common_t *)info;
989     return code;
990 fail:
991     gs_free_object(memory, pis_image, "plane_image_begin_typed(pis_image)");
992     gs_free_object(memory, info, "plane_image_begin_typed(info)");
993     return gx_default_begin_typed_image(dev, pis, pmat, pic, prect,
994 					pdcolor, pcpath, memory, pinfo);
995 }
996 
997 static int
plane_image_plane_data(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height,int * rows_used)998 plane_image_plane_data(gx_image_enum_common_t * info,
999 		       const gx_image_plane_t * planes, int height,
1000 		       int *rows_used)
1001 {
1002     plane_image_enum_t * const ppie = (plane_image_enum_t *)info;
1003 
1004     return gx_image_plane_data_rows(ppie->info, planes, height, rows_used);
1005 }
1006 
1007 static int
plane_image_end_image(gx_image_enum_common_t * info,bool draw_last)1008 plane_image_end_image(gx_image_enum_common_t * info, bool draw_last)
1009 {
1010     plane_image_enum_t * const ppie = (plane_image_enum_t *)info;
1011     int code = gx_image_end(ppie->info, draw_last);
1012 
1013     gs_free_object(ppie->memory, ppie->pis_image,
1014 		   "plane_image_end_image(pis_image)");
1015     gx_image_free_enum(&info);
1016     return code;
1017 }
1018 
1019 /* ---------------- Reading back bits ---------------- */
1020 
1021 static int
plane_get_bits_rectangle(gx_device * dev,const gs_int_rect * prect,gs_get_bits_params_t * params,gs_int_rect ** unread)1022 plane_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
1023 			 gs_get_bits_params_t * params, gs_int_rect ** unread)
1024 {
1025     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
1026     gx_device * const plane_dev = edev->plane_dev;
1027     int plane_index = edev->plane.index;
1028     gs_get_bits_options_t options = params->options;
1029     gs_get_bits_params_t plane_params;
1030     int plane;
1031     int code;
1032 
1033     /*
1034      * The only real option that this device supports is single-plane
1035      * retrieval.  However, for the default case of RasterOp, it must be
1036      * able to return chunky pixels in which the other components are
1037      * arbitrary (but might as well be zero).
1038      */
1039     if ((options & GB_PACKING_PLANAR) && (options & GB_SELECT_PLANES)) {
1040 	if (params->data[plane_index] == 0)
1041 	    return gx_default_get_bits_rectangle(dev, prect, params, unread);
1042 	/* If the caller wants any other plane(s), punt. */
1043 	for (plane = 0; plane < dev->color_info.num_components; ++plane)
1044 	    if (plane != plane_index && params->data[plane] != 0)
1045 		return gx_default_get_bits_rectangle(dev, prect, params, unread);
1046 	/* Pass the request on to the plane device. */
1047 	plane_params = *params;
1048 	plane_params.options =
1049 	    (options & ~(GB_PACKING_ALL | GB_SELECT_PLANES)) |
1050 	    GB_PACKING_CHUNKY;
1051 	plane_params.data[0] = params->data[plane_index];
1052 	code = dev_proc(plane_dev, get_bits_rectangle)
1053 	    (plane_dev, prect, &plane_params, unread);
1054 	if (code >= 0) {
1055 	    *params = plane_params;
1056 	    params->options = (params->options & ~GB_PACKING_ALL) |
1057 		(GB_PACKING_PLANAR | GB_SELECT_PLANES);
1058 	    params->data[plane_index] = params->data[0];
1059 	    for (plane = 0; plane < dev->color_info.num_components; ++plane)
1060 		if (plane != plane_index)
1061 		    params->data[plane] = 0;
1062 	}
1063     } else if (!(~options & (GB_COLORS_NATIVE | GB_ALPHA_NONE |
1064 			     GB_PACKING_CHUNKY | GB_RETURN_COPY |
1065 			     GB_ALIGN_STANDARD | GB_OFFSET_0 |
1066 			     GB_RASTER_STANDARD))) {
1067 	/* Expand the plane into chunky pixels. */
1068 	bits_plane_t dest, source;
1069 
1070 	dest.data.write = params->data[0];
1071 	dest.raster =
1072 	    bitmap_raster((prect->q.x - prect->p.x) * dev->color_info.depth);
1073 	dest.depth = edev->color_info.depth;
1074 	dest.x = 0;
1075 
1076 	/* not source.data, source.raster, source.x */
1077 	source.depth = plane_dev->color_info.depth;
1078 
1079 	plane_params = *params;
1080 	plane_params.options = options &=
1081 	    (~(GB_COLORS_ALL | GB_ALPHA_ALL | GB_PACKING_ALL |
1082 	       GB_RETURN_ALL | GB_ALIGN_ALL | GB_OFFSET_ALL | GB_RASTER_ALL) |
1083 	     GB_COLORS_NATIVE | GB_ALPHA_NONE | GB_PACKING_CHUNKY |
1084 	     /* Try for a pointer return the first time. */
1085 	     GB_RETURN_POINTER |
1086 	     GB_ALIGN_STANDARD |
1087 	     (GB_OFFSET_0 | GB_OFFSET_ANY) |
1088 	     (GB_RASTER_STANDARD | GB_RASTER_ANY));
1089 	plane_params.raster = gx_device_raster(plane_dev, true);
1090 	code = dev_proc(plane_dev, get_bits_rectangle)
1091 	    (plane_dev, prect, &plane_params, unread);
1092 	if (code >= 0) {
1093 	    /* Success, expand the plane into pixels. */
1094 	    source.data.read = plane_params.data[0];
1095 	    source.raster = plane_params.raster;
1096 	    source.x = params->x_offset;
1097 	    code = bits_expand_plane(&dest, &source, edev->plane.shift,
1098 				     prect->q.x - prect->p.x,
1099 				     prect->q.y - prect->p.y);
1100 	}
1101 	params->options = (options & ~GB_RETURN_POINTER) | GB_RETURN_COPY;
1102     } else
1103 	return gx_default_get_bits_rectangle(dev, prect, params, unread);
1104     return code;
1105 }
1106