1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
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.
14
/* $Id: gdevplnx.c 8803 2008-06-24 14:16:29Z leonardo $*/
15
/* Plane extraction device */
19
#include "gsrop.h" /* for logical op access */
23
#include "gxcmap.h" /* requires gxdcolor.h */
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
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));
44
static RELOC_PTRS_WITH(device_plane_extract_reloc_ptrs, gx_device_plane_extract *edev)
46
RELOC_PREFIX(st_device_forward);
47
edev->plane_dev = gx_device_reloc_ptr(edev->plane_dev, gcst);
50
public_st_device_plane_extract();
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);
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",
77
gx_default_close_device,
81
gx_default_tile_rectangle,
100
gx_default_fill_trapezoid,
101
plane_fill_parallelogram,
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,
110
plane_begin_typed_image,
111
plane_get_bits_rectangle,
113
gx_no_create_compositor, /* WRONG */
115
gx_default_text_begin
117
/* device-specific members */
119
NULL, /* plane_dev */
123
0, /* plane_dev_is_memory */
124
1 /*true*/ /* any_marks */
127
/* ---------------- Utilities ---------------- */
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))
137
* Reduce the drawing color to one for the selected plane.
138
* All we care about is whether the drawing operation should be skipped.
143
REDUCE_FAILED /* couldn't reduce */
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
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)
153
reduced_color_t reduced;
155
if (gx_dc_is_pure(pdevc)) {
156
gx_color_index pixel = COLOR_PIXEL(edev, gx_dc_pure_color(pdevc));
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));
166
if (pixel0 == pixel1) {
167
set_nonclient_dev_color(ppdc, pixel0);
168
reduced = REDUCE_PURE(edev, pixel0);
171
ppdc->colors.binary.color[0] = pixel0;
172
ppdc->colors.binary.color[1] = pixel1;
173
edev->any_marks = true;
174
reduced = REDUCE_DRAW;
176
} else if (color_is_colored_halftone(pdevc)) {
177
int plane = edev->plane.index;
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;
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 */
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;
204
return REDUCE_FAILED; /* can't handle it */
205
if (*plop & lop_T_transparent) {
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.
219
gx_color_index white = gx_device_white((gx_device *)edev);
222
* Given that we haven't failed, the only possible colors at this
223
* point are pure or binary halftone.
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;
231
if (gx_dc_binary_color0(pdevc) != white &&
232
gx_dc_binary_color1(pdevc) != white) {
233
*plop &= ~lop_T_transparent;
235
return REDUCE_FAILED;
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, ...);
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
255
typedef struct tiling_state_s {
256
/* Save the original operands. */
257
const gx_device_plane_extract *edev;
262
int dest_x; /* only for copy_color, defaults to 0 */
263
/* Define the (aligned) buffer for doing the operation. */
270
/* Record the current tile available for processing. */
271
/* The client may read these out. */
274
/* Record private tiling parameters. */
279
* Extract the plane's data from one subrectangle of a source tile.
281
static inline int /* ignore the return value */
282
extract_partial_tile(const tiling_state_t *pts)
284
const gx_device_plane_extract * const edev = pts->edev;
285
bits_plane_t dest, source;
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;
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;
297
bits_extract_plane(&dest, &source, edev->plane.shift,
298
pts->size.x, pts->size.y);
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.
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)
312
bitmap_raster(width * edev->plane_dev->color_info.depth);
313
uint full_size = width_raster * height;
316
pts->data = data, pts->data_x = data_x, pts->raster = raster;
317
pts->width = width, pts->height = height;
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;
332
pts->size.y = buffer_size / width_raster;
334
pts->buffer.raster = buffer_size & -align_bitmap_mod;
336
pts->buffer.raster * (8 / edev->plane_dev->color_info.depth);
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;
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;
356
* Advance to the next tile. Return true if there are more tiles to do.
359
next_tile(tiling_state_t *pts)
361
if ((pts->offset.x += pts->size.x) >= pts->width) {
362
if ((pts->offset.y += pts->size.y) >= pts->height)
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;
374
* Finish tiling by freeing the buffer if necessary.
377
end_tiling(tiling_state_t *pts)
379
if (pts->buffer.on_heap)
380
gs_free_object(pts->edev->memory, pts->buffer.data, "end_tiling");
383
/* ---------------- Initialization ---------------- */
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)
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,
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);
403
dev_proc(plane_dev, fill_rectangle)
404
(plane_dev, 0, 0, plane_dev->width, plane_dev->height,
406
edev->any_marks = false;
411
/* ---------------- Driver procedures ---------------- */
414
plane_open_device(gx_device *dev)
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);
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. */
431
plane_fill_rectangle(gx_device *dev,
432
int x, int y, int w, int h, gx_color_index color)
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);
438
if (pixel != edev->plane_white)
439
edev->any_marks = true;
440
else if (!edev->any_marks)
442
return dev_proc(plane_dev, fill_rectangle)
443
(plane_dev, x, y, w, h, pixel);
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)
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);
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)
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);
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)
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)];
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;
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);
491
state.buffer.raster = mdev->raster;
492
extract_partial_tile(&state);
494
edev->any_marks = true;
497
code = begin_tiling(&state, edev, data, data_x, raster,
498
w, h, (byte *)buf, sizeof(buf), true);
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));
509
edev->any_marks = true;
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)
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);
522
if (pixel != edev->plane_white)
523
edev->any_marks = true;
524
else if (!edev->any_marks)
526
return dev_proc(plane_dev, copy_alpha)
527
(plane_dev, data, data_x, raster, id, x, y, w, h, pixel, depth);
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)
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;
543
switch (reduce_drawing_color(&dcolor, edev, pdevc, &lop)) {
547
gs_imager_state lopis;
548
const gs_imager_state *pis_draw = pis;
550
if (lop != lop_orig) {
552
gs_set_logical_op((gs_state *)&lopis, lop);
555
return dev_proc(plane_dev, fill_path)
556
(plane_dev, pis_draw, ppath, params, &dcolor, pcpath);
558
default /*REDUCE_FAILED*/:
559
return gx_default_fill_path(dev, pis, ppath, params, pdevc, 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)
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;
576
switch (reduce_drawing_color(&dcolor, edev, pdevc, &lop)) {
580
gs_imager_state lopis;
581
const gs_imager_state *pis_draw = pis;
583
if (lop != lop_orig) {
585
gs_set_logical_op((gs_state *)&lopis, lop);
588
return dev_proc(plane_dev, stroke_path)
589
(plane_dev, pis_draw, ppath, params, &dcolor, pcpath);
591
default /*REDUCE_FAILED*/:
592
return gx_default_stroke_path(dev, pis, ppath, params, pdevc, 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)
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;
607
switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) {
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);
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)
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;
629
switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) {
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,
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)
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;
650
switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) {
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,
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)
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);
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.... */
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);
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);
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,
698
edev->any_marks = true;
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)
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);
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)
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);
725
gx_color_index pixels[2];
726
gx_color_index *colors;
727
tiling_state_t state;
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;
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)) {
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])
750
source.colors = source.pixels;
754
if (!rop3_uses_T(rop)) {
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])
762
texture.colors = texture.pixels;
767
code = begin_tiling(&source.state, edev, sdata, sourcex, sraster, w, y,
768
(byte *)sbuf, sizeof(sbuf), true);
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;
778
code = begin_tiling(&texture.state, edev, textures->data, 0,
779
textures->raster, textures->size.x,
780
textures->size.y, (byte *)tbuf, sizeof(tbuf),
784
end_tiling(&source.state);
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;
793
extract_partial_tile(&texture.state);
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));
803
end_tiling(&texture.state);
805
end_tiling(&source.state);
809
/* ---------------- Images ---------------- */
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);
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.
827
* In the imager state passed to these procedures, the client data is
828
* the plane_image_enum_t.
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)
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;
842
gx_remap_concrete_gray(gray, &dcolor, ppie->pis,
843
(gx_device *)edev, select);
844
reduce_drawing_color(pdc, edev, &dcolor, &lop);
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)
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;
857
gx_remap_concrete_rgb(r, g, b, &dcolor, ppie->pis,
858
(gx_device *)edev, select);
859
reduce_drawing_color(pdc, edev, &dcolor, &lop);
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)
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;
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);
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)
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;
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);
892
plane_cmap_is_halftoned(const gs_imager_state *pis_image, gx_device *dev)
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
901
static const gx_color_map_procs *
902
plane_get_cmap_procs(const gs_imager_state *pis, const gx_device *dev)
904
return &plane_color_map_procs;
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
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)
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.
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;
936
/* We can only handle a limited set of image types. */
937
switch (pic->type->index) {
939
const gs_image1_t * const pim1 = (const gs_image1_t *)pic;
941
if (pim1->Alpha != gs_image_alpha_none)
943
uses_color = pim1->ImageMask;
952
pim = (const gs_pixel_image_t *)pic;
953
if ((lop & lop_S_transparent) ||
954
((uses_color || pim->CombineWithColor) && (lop & lop_T_transparent))
957
if (uses_color || (pim->CombineWithColor && lop_uses_T(lop))) {
958
if (reduce_drawing_color(&dcolor, edev, pdcolor, &lop) ==
963
* The drawing color won't be used, but if RasterOp is involved,
964
* it may still be accessed in some anomalous cases.
966
set_nonclient_dev_color(&dcolor, (gx_color_index)0);
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)
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);
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;
987
info->pis_image = pis_image;
988
*pinfo = (gx_image_enum_common_t *)info;
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);
998
plane_image_plane_data(gx_image_enum_common_t * info,
999
const gx_image_plane_t * planes, int height,
1002
plane_image_enum_t * const ppie = (plane_image_enum_t *)info;
1004
return gx_image_plane_data_rows(ppie->info, planes, height, rows_used);
1008
plane_image_end_image(gx_image_enum_common_t * info, bool draw_last)
1010
plane_image_enum_t * const ppie = (plane_image_enum_t *)info;
1011
int code = gx_image_end(ppie->info, draw_last);
1013
gs_free_object(ppie->memory, ppie->pis_image,
1014
"plane_image_end_image(pis_image)");
1015
gx_image_free_enum(&info);
1019
/* ---------------- Reading back bits ---------------- */
1022
plane_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
1023
gs_get_bits_params_t * params, gs_int_rect ** unread)
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;
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).
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)) |
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);
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;
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;
1070
dest.data.write = params->data[0];
1072
bitmap_raster((prect->q.x - prect->p.x) * dev->color_info.depth);
1073
dest.depth = edev->color_info.depth;
1076
/* not source.data, source.raster, source.x */
1077
source.depth = plane_dev->color_info.depth;
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. */
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);
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);
1101
params->options = (options & ~GB_RETURN_POINTER) | GB_RETURN_COPY;
1103
return gx_default_get_bits_rectangle(dev, prect, params, unread);