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