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