Coverage Report

Created: 2025-11-16 07:40

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