Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/cmd/gs/src/gdevplnx.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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 */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
}