xref: /plan9/sys/src/cmd/gs/src/gdevplnx.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1998, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gdevplnx.c,v 1.10 2004/08/04 19:36:12 stefan Exp $*/
187dd7cddfSDavid du Colombier /* Plane extraction device */
197dd7cddfSDavid du Colombier #include "gx.h"
207dd7cddfSDavid du Colombier #include "gserrors.h"
217dd7cddfSDavid du Colombier #include "gsbitops.h"
227dd7cddfSDavid du Colombier #include "gsrop.h"		/* for logical op access */
237dd7cddfSDavid du Colombier #include "gsstruct.h"
247dd7cddfSDavid du Colombier #include "gsutil.h"
257dd7cddfSDavid du Colombier #include "gxdcolor.h"
267dd7cddfSDavid du Colombier #include "gxcmap.h"		/* requires gxdcolor.h */
277dd7cddfSDavid du Colombier #include "gxdevice.h"
287dd7cddfSDavid du Colombier #include "gxdevmem.h"
297dd7cddfSDavid du Colombier #include "gxdither.h"
307dd7cddfSDavid du Colombier #include "gxgetbit.h"
317dd7cddfSDavid du Colombier #include "gxiparam.h"
327dd7cddfSDavid du Colombier #include "gxistate.h"
337dd7cddfSDavid du Colombier #include "gdevplnx.h"
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier /* Define the size of the locally allocated bitmap buffers. */
367dd7cddfSDavid du Colombier #define COPY_COLOR_BUF_SIZE 100
377dd7cddfSDavid du Colombier #define TILE_RECTANGLE_BUF_SIZE 100
387dd7cddfSDavid du Colombier #define COPY_ROP_SOURCE_BUF_SIZE 100
397dd7cddfSDavid du Colombier #define COPY_ROP_TEXTURE_BUF_SIZE 100
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier /* GC procedures */
427dd7cddfSDavid du Colombier private
437dd7cddfSDavid du Colombier ENUM_PTRS_WITH(device_plane_extract_enum_ptrs, gx_device_plane_extract *edev)
447dd7cddfSDavid du Colombier     ENUM_PREFIX(st_device_forward, 1);
457dd7cddfSDavid du Colombier case 0: ENUM_RETURN(gx_device_enum_ptr(edev->target));
467dd7cddfSDavid du Colombier ENUM_PTRS_END
RELOC_PTRS_WITH(device_plane_extract_reloc_ptrs,gx_device_plane_extract * edev)477dd7cddfSDavid du Colombier private RELOC_PTRS_WITH(device_plane_extract_reloc_ptrs, gx_device_plane_extract *edev)
487dd7cddfSDavid du Colombier {
497dd7cddfSDavid du Colombier     RELOC_PREFIX(st_device_forward);
507dd7cddfSDavid du Colombier     edev->plane_dev = gx_device_reloc_ptr(edev->plane_dev, gcst);
517dd7cddfSDavid du Colombier }
527dd7cddfSDavid du Colombier RELOC_PTRS_END
537dd7cddfSDavid du Colombier public_st_device_plane_extract();
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier /* Driver procedures */
567dd7cddfSDavid du Colombier private dev_proc_open_device(plane_open_device);
577dd7cddfSDavid du Colombier private dev_proc_fill_rectangle(plane_fill_rectangle);
587dd7cddfSDavid du Colombier private dev_proc_copy_mono(plane_copy_mono);
597dd7cddfSDavid du Colombier private dev_proc_copy_color(plane_copy_color);
607dd7cddfSDavid du Colombier private dev_proc_copy_alpha(plane_copy_alpha);
617dd7cddfSDavid du Colombier private dev_proc_fill_path(plane_fill_path);
627dd7cddfSDavid du Colombier private dev_proc_stroke_path(plane_stroke_path);
637dd7cddfSDavid du Colombier private dev_proc_fill_mask(plane_fill_mask);
647dd7cddfSDavid du Colombier private dev_proc_fill_parallelogram(plane_fill_parallelogram);
657dd7cddfSDavid du Colombier private dev_proc_fill_triangle(plane_fill_triangle);
667dd7cddfSDavid du Colombier private dev_proc_strip_tile_rectangle(plane_strip_tile_rectangle);
677dd7cddfSDavid du Colombier private dev_proc_strip_copy_rop(plane_strip_copy_rop);
687dd7cddfSDavid du Colombier private dev_proc_begin_typed_image(plane_begin_typed_image);
697dd7cddfSDavid du Colombier private dev_proc_get_bits_rectangle(plane_get_bits_rectangle);
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier /* Device prototype */
727dd7cddfSDavid du Colombier private const gx_device_plane_extract gs_plane_extract_device = {
737dd7cddfSDavid du Colombier     std_device_std_body(gx_device_plane_extract, 0, "plane_extract",
747dd7cddfSDavid du Colombier 			0, 0, 72, 72),
757dd7cddfSDavid du Colombier     {
767dd7cddfSDavid du Colombier 	plane_open_device,
777dd7cddfSDavid du Colombier 	NULL,
787dd7cddfSDavid du Colombier 	NULL,
797dd7cddfSDavid du Colombier 	NULL,
807dd7cddfSDavid du Colombier 	gx_default_close_device,
817dd7cddfSDavid du Colombier 	NULL,
827dd7cddfSDavid du Colombier 	NULL,
837dd7cddfSDavid du Colombier 	plane_fill_rectangle,
847dd7cddfSDavid du Colombier 	gx_default_tile_rectangle,
857dd7cddfSDavid du Colombier 	plane_copy_mono,
867dd7cddfSDavid du Colombier 	plane_copy_color,
877dd7cddfSDavid du Colombier 	gx_default_draw_line,
887dd7cddfSDavid du Colombier 	gx_default_get_bits,
897dd7cddfSDavid du Colombier 	NULL,
907dd7cddfSDavid du Colombier 	NULL,
917dd7cddfSDavid du Colombier 	NULL,
927dd7cddfSDavid du Colombier 	NULL,
937dd7cddfSDavid du Colombier 	NULL,
947dd7cddfSDavid du Colombier 	NULL,
957dd7cddfSDavid du Colombier 	NULL,
967dd7cddfSDavid du Colombier 	NULL,
977dd7cddfSDavid du Colombier 	plane_copy_alpha,
987dd7cddfSDavid du Colombier 	NULL,
997dd7cddfSDavid du Colombier 	gx_default_copy_rop,
1007dd7cddfSDavid du Colombier 	plane_fill_path,
1017dd7cddfSDavid du Colombier 	plane_stroke_path,
1027dd7cddfSDavid du Colombier 	plane_fill_mask,
1037dd7cddfSDavid du Colombier 	gx_default_fill_trapezoid,
1047dd7cddfSDavid du Colombier 	plane_fill_parallelogram,
1057dd7cddfSDavid du Colombier 	plane_fill_triangle,
1067dd7cddfSDavid du Colombier 	gx_default_draw_thin_line,
1077dd7cddfSDavid du Colombier 	gx_default_begin_image,
1087dd7cddfSDavid du Colombier 	gx_default_image_data,
1097dd7cddfSDavid du Colombier 	gx_default_end_image,
1107dd7cddfSDavid du Colombier 	plane_strip_tile_rectangle,
1117dd7cddfSDavid du Colombier 	plane_strip_copy_rop,
1127dd7cddfSDavid du Colombier 	NULL,
1137dd7cddfSDavid du Colombier 	plane_begin_typed_image,
1147dd7cddfSDavid du Colombier 	plane_get_bits_rectangle,
1157dd7cddfSDavid du Colombier 	NULL,
1167dd7cddfSDavid du Colombier 	gx_no_create_compositor, /* WRONG */
1177dd7cddfSDavid du Colombier 	NULL,
1187dd7cddfSDavid du Colombier 	gx_default_text_begin
1197dd7cddfSDavid du Colombier     },
1207dd7cddfSDavid du Colombier     /* device-specific members */
1217dd7cddfSDavid du Colombier     NULL,				/* target */
1227dd7cddfSDavid du Colombier     NULL,				/* plane_dev */
1237dd7cddfSDavid du Colombier     { 0 },				/* plane */
1247dd7cddfSDavid du Colombier     0,					/* plane_white */
1257dd7cddfSDavid du Colombier     0,					/* plane_mask */
1267dd7cddfSDavid du Colombier     0,					/* plane_dev_is_memory */
1277dd7cddfSDavid du Colombier     1 /*true*/				/* any_marks */
1287dd7cddfSDavid du Colombier };
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier /* ---------------- Utilities ---------------- */
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier /* Extract the selected plane from a color (gx_color_index). */
1337dd7cddfSDavid du Colombier #define COLOR_PIXEL(edev, color)\
1347dd7cddfSDavid du Colombier   ( ((color) >> (edev)->plane.shift) & (edev)->plane_mask )
1357dd7cddfSDavid du Colombier /* Do the same if the color might be transparent. */
1367dd7cddfSDavid du Colombier #define TRANS_COLOR_PIXEL(edev, color)\
1377dd7cddfSDavid du Colombier  ((color) == gx_no_color_index ? gx_no_color_index : COLOR_PIXEL(edev, color))
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier /*
1407dd7cddfSDavid du Colombier  * Reduce the drawing color to one for the selected plane.
1417dd7cddfSDavid du Colombier  * All we care about is whether the drawing operation should be skipped.
1427dd7cddfSDavid du Colombier  */
1437dd7cddfSDavid du Colombier typedef enum {
1447dd7cddfSDavid du Colombier     REDUCE_SKIP,
1457dd7cddfSDavid du Colombier     REDUCE_DRAW,
1467dd7cddfSDavid du Colombier     REDUCE_FAILED			/* couldn't reduce */
1477dd7cddfSDavid du Colombier } reduced_color_t;
1487dd7cddfSDavid du Colombier #define REDUCE_PURE(edev, pixel)\
1497dd7cddfSDavid du Colombier   ((pixel) == (edev)->plane_white && !(edev)->any_marks ?  REDUCE_SKIP :\
1507dd7cddfSDavid du Colombier    ((edev)->any_marks = true, REDUCE_DRAW))
1517dd7cddfSDavid du Colombier private reduced_color_t
reduce_drawing_color(gx_device_color * ppdc,gx_device_plane_extract * edev,const gx_drawing_color * pdevc,gs_logical_operation_t * plop)1527dd7cddfSDavid du Colombier reduce_drawing_color(gx_device_color *ppdc, gx_device_plane_extract *edev,
1537dd7cddfSDavid du Colombier 		     const gx_drawing_color *pdevc,
1547dd7cddfSDavid du Colombier 		     gs_logical_operation_t *plop)
1557dd7cddfSDavid du Colombier {
1567dd7cddfSDavid du Colombier     reduced_color_t reduced;
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier     if (gx_dc_is_pure(pdevc)) {
1597dd7cddfSDavid du Colombier 	gx_color_index pixel = COLOR_PIXEL(edev, gx_dc_pure_color(pdevc));
1607dd7cddfSDavid du Colombier 
161*593dc095SDavid du Colombier 	set_nonclient_dev_color(ppdc, pixel);
1627dd7cddfSDavid du Colombier 	reduced = REDUCE_PURE(edev, pixel);
1637dd7cddfSDavid du Colombier     } else if (gx_dc_is_binary_halftone(pdevc)) {
1647dd7cddfSDavid du Colombier 	gx_color_index pixel0 =
1657dd7cddfSDavid du Colombier 	    TRANS_COLOR_PIXEL(edev, gx_dc_binary_color0(pdevc));
1667dd7cddfSDavid du Colombier 	gx_color_index pixel1 =
1677dd7cddfSDavid du Colombier 	    TRANS_COLOR_PIXEL(edev, gx_dc_binary_color1(pdevc));
1687dd7cddfSDavid du Colombier 
1697dd7cddfSDavid du Colombier 	if (pixel0 == pixel1) {
170*593dc095SDavid du Colombier 	    set_nonclient_dev_color(ppdc, pixel0);
1717dd7cddfSDavid du Colombier 	    reduced = REDUCE_PURE(edev, pixel0);
1727dd7cddfSDavid du Colombier 	} else {
1737dd7cddfSDavid du Colombier 	    *ppdc = *pdevc;
1747dd7cddfSDavid du Colombier 	    ppdc->colors.binary.color[0] = pixel0;
1757dd7cddfSDavid du Colombier 	    ppdc->colors.binary.color[1] = pixel1;
1767dd7cddfSDavid du Colombier 	    edev->any_marks = true;
1777dd7cddfSDavid du Colombier 	    reduced = REDUCE_DRAW;
1787dd7cddfSDavid du Colombier 	}
1797dd7cddfSDavid du Colombier     } else if (color_is_colored_halftone(pdevc)) {
1807dd7cddfSDavid du Colombier 	int plane = edev->plane.index;
1817dd7cddfSDavid du Colombier 	int i;
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier 	*ppdc = *pdevc;
1847dd7cddfSDavid du Colombier 	for (i = 0; i < countof(ppdc->colors.colored.c_base); ++i)
1857dd7cddfSDavid du Colombier 	    if (i != edev->plane.index) {
1867dd7cddfSDavid du Colombier 		ppdc->colors.colored.c_base[i] = 0;
1877dd7cddfSDavid du Colombier 		ppdc->colors.colored.c_level[i] = 0;
1887dd7cddfSDavid du Colombier 	    }
1897dd7cddfSDavid du Colombier 	ppdc->colors.colored.plane_mask &= 1 << plane;
1907dd7cddfSDavid du Colombier 	if (ppdc->colors.colored.c_level[plane] == 0) {
191*593dc095SDavid du Colombier 	    gx_devn_reduce_colored_halftone(ppdc, (gx_device *)edev);
1927dd7cddfSDavid du Colombier 	    ppdc->colors.pure = COLOR_PIXEL(edev, ppdc->colors.pure);
1937dd7cddfSDavid du Colombier 	    reduced = REDUCE_PURE(edev, gx_dc_pure_color(ppdc));
1947dd7cddfSDavid du Colombier 	} else if (ppdc->colors.colored.alpha != gx_max_color_value)
1957dd7cddfSDavid du Colombier 	    return REDUCE_FAILED; /* can't reduce */
1967dd7cddfSDavid du Colombier 	else {
197*593dc095SDavid du Colombier 	    gx_devn_reduce_colored_halftone(ppdc, (gx_device *)edev);
1987dd7cddfSDavid du Colombier 	    ppdc->colors.binary.color[0] =
1997dd7cddfSDavid du Colombier 		COLOR_PIXEL(edev, ppdc->colors.binary.color[0]);
2007dd7cddfSDavid du Colombier 	    ppdc->colors.binary.color[1] =
2017dd7cddfSDavid du Colombier 		COLOR_PIXEL(edev, ppdc->colors.binary.color[1]);
2027dd7cddfSDavid du Colombier 	    gx_color_load(ppdc, NULL, (gx_device *)edev);
2037dd7cddfSDavid du Colombier 	    edev->any_marks = true;
2047dd7cddfSDavid du Colombier 	    reduced = REDUCE_DRAW;
2057dd7cddfSDavid du Colombier 	}
2067dd7cddfSDavid du Colombier     } else
2077dd7cddfSDavid du Colombier 	return REDUCE_FAILED;		/* can't handle it */
2087dd7cddfSDavid du Colombier     if (*plop & lop_T_transparent) {
2097dd7cddfSDavid du Colombier 	/*
2107dd7cddfSDavid du Colombier 	 * If the logical operation invokes transparency for the texture, we
2117dd7cddfSDavid du Colombier 	 * must do some extra work, since a color that was originally opaque
2127dd7cddfSDavid du Colombier 	 * may become transparent (white) if reduced to a single plane.  If
2137dd7cddfSDavid du Colombier 	 * RasterOp transparency were calculated before halftoning, life
2147dd7cddfSDavid du Colombier 	 * would be easy: we would simply turn off texture transparency in
2157dd7cddfSDavid du Colombier 	 * the logical operation iff the original (not reduced) color was
2167dd7cddfSDavid du Colombier 	 * not white.  Unfortunately, RasterOp transparency is calculated
2177dd7cddfSDavid du Colombier 	 * after halftoning.  (This is arguably wrong, but it's how we've
2187dd7cddfSDavid du Colombier 	 * defined it.)  Therefore, if transparency is involved with a
2197dd7cddfSDavid du Colombier 	 * white color or a halftone that can include white, we must keep
2207dd7cddfSDavid du Colombier 	 * the entire pixel together for the RasterOp.
2217dd7cddfSDavid du Colombier 	 */
2227dd7cddfSDavid du Colombier 	gx_color_index white = gx_device_white((gx_device *)edev);
2237dd7cddfSDavid du Colombier 
2247dd7cddfSDavid du Colombier 	/*
2257dd7cddfSDavid du Colombier 	 * Given that we haven't failed, the only possible colors at this
2267dd7cddfSDavid du Colombier 	 * point are pure or binary halftone.
2277dd7cddfSDavid du Colombier 	 */
2287dd7cddfSDavid du Colombier 	if (gx_dc_is_pure(ppdc)) {
2297dd7cddfSDavid du Colombier 	    if (gx_dc_pure_color(pdevc) != white)
2307dd7cddfSDavid du Colombier 		*plop &= ~lop_T_transparent;
2317dd7cddfSDavid du Colombier 	    else if (!gx_dc_is_pure(pdevc))
2327dd7cddfSDavid du Colombier 		return REDUCE_FAILED;
2337dd7cddfSDavid du Colombier 	} else {
2347dd7cddfSDavid du Colombier 	    if (gx_dc_binary_color0(pdevc) != white &&
2357dd7cddfSDavid du Colombier 		gx_dc_binary_color1(pdevc) != white) {
2367dd7cddfSDavid du Colombier 		*plop &= ~lop_T_transparent;
2377dd7cddfSDavid du Colombier 	    } else
2387dd7cddfSDavid du Colombier 		return REDUCE_FAILED;
2397dd7cddfSDavid du Colombier 	}
2407dd7cddfSDavid du Colombier     }
2417dd7cddfSDavid du Colombier     return reduced;
2427dd7cddfSDavid du Colombier }
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier /*
2457dd7cddfSDavid du Colombier  * Set up to create the plane-extracted bitmap corresponding to a
2467dd7cddfSDavid du Colombier  * source or halftone pixmap.  If the bitmap doesn't fit in the locally
2477dd7cddfSDavid du Colombier  * allocated buffer, we may either do the operation in pieces, or allocate
2487dd7cddfSDavid du Colombier  * a buffer on the heap.  The control structure is:
2497dd7cddfSDavid du Colombier  *	begin_tiling(&state, ...);
2507dd7cddfSDavid du Colombier  *	do {
2517dd7cddfSDavid du Colombier  *	    extract_partial_tile(&state);
2527dd7cddfSDavid du Colombier  *	    ... process tile in buffer ...
2537dd7cddfSDavid du Colombier  *	} while (next_tile(&state));
2547dd7cddfSDavid du Colombier  *	end_tiling(&state);
2557dd7cddfSDavid du Colombier  * If partial_ok is false, there is only a single tile, so the do ... while
2567dd7cddfSDavid du Colombier  * is not used.
2577dd7cddfSDavid du Colombier  */
2587dd7cddfSDavid du Colombier typedef struct tiling_state_s {
2597dd7cddfSDavid du Colombier 	/* Save the original operands. */
2607dd7cddfSDavid du Colombier     const gx_device_plane_extract *edev;
2617dd7cddfSDavid du Colombier     const byte *data;
2627dd7cddfSDavid du Colombier     int data_x;
2637dd7cddfSDavid du Colombier     uint raster;
2647dd7cddfSDavid du Colombier     int width, height;
2657dd7cddfSDavid du Colombier     int dest_x;			/* only for copy_color, defaults to 0 */
2667dd7cddfSDavid du Colombier 	/* Define the (aligned) buffer for doing the operation. */
2677dd7cddfSDavid du Colombier     struct tsb_ {
2687dd7cddfSDavid du Colombier 	byte *data;
2697dd7cddfSDavid du Colombier 	uint size;
2707dd7cddfSDavid du Colombier 	uint raster;
2717dd7cddfSDavid du Colombier 	bool on_heap;
2727dd7cddfSDavid du Colombier     } buffer;
2737dd7cddfSDavid du Colombier 	/* Record the current tile available for processing. */
2747dd7cddfSDavid du Colombier 	/* The client may read these out. */
2757dd7cddfSDavid du Colombier     gs_int_point offset;
2767dd7cddfSDavid du Colombier     gs_int_point size;
2777dd7cddfSDavid du Colombier 	/* Record private tiling parameters. */
2787dd7cddfSDavid du Colombier     int per_tile_width;
2797dd7cddfSDavid du Colombier } tiling_state_t;
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier /*
2827dd7cddfSDavid du Colombier  * Extract the plane's data from one subrectangle of a source tile.
2837dd7cddfSDavid du Colombier  */
2847dd7cddfSDavid du Colombier inline private int /* ignore the return value */
extract_partial_tile(const tiling_state_t * pts)2857dd7cddfSDavid du Colombier extract_partial_tile(const tiling_state_t *pts)
2867dd7cddfSDavid du Colombier {
2877dd7cddfSDavid du Colombier     const gx_device_plane_extract * const edev = pts->edev;
2887dd7cddfSDavid du Colombier     bits_plane_t dest, source;
2897dd7cddfSDavid du Colombier 
2907dd7cddfSDavid du Colombier     dest.data.write = pts->buffer.data + pts->offset.y * pts->buffer.raster;
2917dd7cddfSDavid du Colombier     dest.raster = pts->buffer.raster;
2927dd7cddfSDavid du Colombier     dest.depth = edev->plane.depth;
2937dd7cddfSDavid du Colombier     dest.x = pts->dest_x;
2947dd7cddfSDavid du Colombier 
2957dd7cddfSDavid du Colombier     source.data.read = pts->data + pts->offset.y * pts->raster;
2967dd7cddfSDavid du Colombier     source.raster = pts->raster;
2977dd7cddfSDavid du Colombier     source.depth = edev->color_info.depth;
2987dd7cddfSDavid du Colombier     source.x = pts->data_x + pts->offset.x;
2997dd7cddfSDavid du Colombier 
3007dd7cddfSDavid du Colombier     bits_extract_plane(&dest, &source, edev->plane.shift,
3017dd7cddfSDavid du Colombier 		       pts->size.x, pts->size.y);
3027dd7cddfSDavid du Colombier     return 0;
3037dd7cddfSDavid du Colombier }
3047dd7cddfSDavid du Colombier 
3057dd7cddfSDavid du Colombier /*
3067dd7cddfSDavid du Colombier  * Set up to start (possibly) tiling.  Return 0 if the entire tile fit,
3077dd7cddfSDavid du Colombier  * 1 if a partial tile fit, or a negative error code.
3087dd7cddfSDavid du Colombier  */
3097dd7cddfSDavid du Colombier private int
begin_tiling(tiling_state_t * pts,gx_device_plane_extract * edev,const byte * data,int data_x,uint raster,int width,int height,byte * local_buffer,uint buffer_size,bool partial_ok)3107dd7cddfSDavid du Colombier begin_tiling(tiling_state_t *pts, gx_device_plane_extract *edev,
3117dd7cddfSDavid du Colombier     const byte *data, int data_x, uint raster, int width, int height,
3127dd7cddfSDavid du Colombier     byte *local_buffer, uint buffer_size, bool partial_ok)
3137dd7cddfSDavid du Colombier {
3147dd7cddfSDavid du Colombier     uint width_raster =
3157dd7cddfSDavid du Colombier 	bitmap_raster(width * edev->plane_dev->color_info.depth);
3167dd7cddfSDavid du Colombier     uint full_size = width_raster * height;
3177dd7cddfSDavid du Colombier 
3187dd7cddfSDavid du Colombier     pts->edev = edev;
3197dd7cddfSDavid du Colombier     pts->data = data, pts->data_x = data_x, pts->raster = raster;
3207dd7cddfSDavid du Colombier     pts->width = width, pts->height = height;
3217dd7cddfSDavid du Colombier     pts->dest_x = 0;
3227dd7cddfSDavid du Colombier     if (full_size <= buffer_size) {
3237dd7cddfSDavid du Colombier 	pts->buffer.data = local_buffer;
3247dd7cddfSDavid du Colombier 	pts->buffer.size = buffer_size;
3257dd7cddfSDavid du Colombier 	pts->buffer.raster = width_raster;
3267dd7cddfSDavid du Colombier 	pts->buffer.on_heap = false;
3277dd7cddfSDavid du Colombier 	pts->size.x = width, pts->size.y = height;
3287dd7cddfSDavid du Colombier     } else if (partial_ok) {
3297dd7cddfSDavid du Colombier 	pts->buffer.data = local_buffer;
3307dd7cddfSDavid du Colombier 	pts->buffer.size = buffer_size;
3317dd7cddfSDavid du Colombier 	pts->buffer.on_heap = false;
3327dd7cddfSDavid du Colombier 	if (buffer_size >= width_raster) {
3337dd7cddfSDavid du Colombier 	    pts->buffer.raster = width_raster;
3347dd7cddfSDavid du Colombier 	    pts->size.x = width;
3357dd7cddfSDavid du Colombier 	    pts->size.y = buffer_size / width_raster;
3367dd7cddfSDavid du Colombier 	} else {
3377dd7cddfSDavid du Colombier 	    pts->buffer.raster = buffer_size & -align_bitmap_mod;
3387dd7cddfSDavid du Colombier 	    pts->size.x =
3397dd7cddfSDavid du Colombier 		pts->buffer.raster * (8 / edev->plane_dev->color_info.depth);
3407dd7cddfSDavid du Colombier 	    pts->size.y = 1;
3417dd7cddfSDavid du Colombier 	}
3427dd7cddfSDavid du Colombier     } else {
3437dd7cddfSDavid du Colombier 	pts->buffer.data =
3447dd7cddfSDavid du Colombier 	    gs_alloc_bytes(edev->memory, full_size, "begin_tiling");
3457dd7cddfSDavid du Colombier 	if (!pts->buffer.data)
3467dd7cddfSDavid du Colombier 	    return_error(gs_error_VMerror);
3477dd7cddfSDavid du Colombier 	pts->buffer.size = full_size;
3487dd7cddfSDavid du Colombier 	pts->buffer.raster = width_raster;
3497dd7cddfSDavid du Colombier 	pts->buffer.on_heap = true;
3507dd7cddfSDavid du Colombier 	pts->size.x = width, pts->size.y = height;
3517dd7cddfSDavid du Colombier     }
3527dd7cddfSDavid du Colombier     pts->buffer.raster = width_raster;
3537dd7cddfSDavid du Colombier     pts->offset.x = pts->offset.y = 0;
3547dd7cddfSDavid du Colombier     pts->per_tile_width = pts->size.x;
3557dd7cddfSDavid du Colombier     return pts->buffer.size < full_size;
3567dd7cddfSDavid du Colombier }
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier /*
3597dd7cddfSDavid du Colombier  * Advance to the next tile.  Return true if there are more tiles to do.
3607dd7cddfSDavid du Colombier  */
3617dd7cddfSDavid du Colombier private bool
next_tile(tiling_state_t * pts)3627dd7cddfSDavid du Colombier next_tile(tiling_state_t *pts)
3637dd7cddfSDavid du Colombier {
3647dd7cddfSDavid du Colombier     if ((pts->offset.x += pts->size.x) >= pts->width) {
3657dd7cddfSDavid du Colombier 	if ((pts->offset.y += pts->size.y) >= pts->height)
3667dd7cddfSDavid du Colombier 	    return false;
3677dd7cddfSDavid du Colombier 	pts->offset.x = 0;
3687dd7cddfSDavid du Colombier 	pts->size.x = pts->per_tile_width;
3697dd7cddfSDavid du Colombier 	if (pts->offset.y + pts->size.y >= pts->height)
3707dd7cddfSDavid du Colombier 	    pts->size.y = pts->height - pts->offset.y;
3717dd7cddfSDavid du Colombier     } else if (pts->offset.x + pts->size.x >= pts->width)
3727dd7cddfSDavid du Colombier 	pts->size.x = pts->width - pts->offset.x;
3737dd7cddfSDavid du Colombier     return true;
3747dd7cddfSDavid du Colombier }
3757dd7cddfSDavid du Colombier 
3767dd7cddfSDavid du Colombier /*
3777dd7cddfSDavid du Colombier  * Finish tiling by freeing the buffer if necessary.
3787dd7cddfSDavid du Colombier  */
3797dd7cddfSDavid du Colombier private void
end_tiling(tiling_state_t * pts)3807dd7cddfSDavid du Colombier end_tiling(tiling_state_t *pts)
3817dd7cddfSDavid du Colombier {
3827dd7cddfSDavid du Colombier     if (pts->buffer.on_heap)
3837dd7cddfSDavid du Colombier 	gs_free_object(pts->edev->memory, pts->buffer.data, "end_tiling");
3847dd7cddfSDavid du Colombier }
3857dd7cddfSDavid du Colombier 
3867dd7cddfSDavid du Colombier /* ---------------- Initialization ---------------- */
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier 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)3897dd7cddfSDavid du Colombier plane_device_init(gx_device_plane_extract *edev, gx_device *target,
3907dd7cddfSDavid du Colombier     gx_device *plane_dev, const gx_render_plane_t *render_plane, bool clear)
3917dd7cddfSDavid du Colombier {
3927dd7cddfSDavid du Colombier     /* Check for compatibility of the plane specification. */
3937dd7cddfSDavid du Colombier     if (render_plane->depth > plane_dev->color_info.depth)
3947dd7cddfSDavid du Colombier 	return_error(gs_error_rangecheck);
3957dd7cddfSDavid du Colombier     gx_device_init((gx_device *)edev,
3967dd7cddfSDavid du Colombier 		   (const gx_device *)&gs_plane_extract_device,
3977dd7cddfSDavid du Colombier 		   edev->memory, true);
398*593dc095SDavid du Colombier     check_device_separable((gx_device *)edev);
3997dd7cddfSDavid du Colombier     gx_device_forward_fill_in_procs((gx_device_forward *)edev);
4007dd7cddfSDavid du Colombier     gx_device_set_target((gx_device_forward *)edev, target);
4017dd7cddfSDavid du Colombier     gx_device_copy_params((gx_device *)edev, target);
4027dd7cddfSDavid du Colombier     edev->plane_dev = plane_dev;
4037dd7cddfSDavid du Colombier     edev->plane = *render_plane;
4047dd7cddfSDavid du Colombier     plane_open_device((gx_device *)edev);
4057dd7cddfSDavid du Colombier     if (clear) {
4067dd7cddfSDavid du Colombier 	dev_proc(plane_dev, fill_rectangle)
4077dd7cddfSDavid du Colombier 	    (plane_dev, 0, 0, plane_dev->width, plane_dev->height,
4087dd7cddfSDavid du Colombier 	     edev->plane_white);
4097dd7cddfSDavid du Colombier 	edev->any_marks = false;
4107dd7cddfSDavid du Colombier     }
4117dd7cddfSDavid du Colombier     return 0;
4127dd7cddfSDavid du Colombier }
4137dd7cddfSDavid du Colombier 
4147dd7cddfSDavid du Colombier /* ---------------- Driver procedures ---------------- */
4157dd7cddfSDavid du Colombier 
4167dd7cddfSDavid du Colombier private int
plane_open_device(gx_device * dev)4177dd7cddfSDavid du Colombier plane_open_device(gx_device *dev)
4187dd7cddfSDavid du Colombier {
4197dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
4207dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
4217dd7cddfSDavid du Colombier     int plane_depth = plane_dev->color_info.depth;
4227dd7cddfSDavid du Colombier     const gx_device_memory * const mdproto =
4237dd7cddfSDavid du Colombier 	gdev_mem_device_for_bits(plane_depth);
4247dd7cddfSDavid du Colombier 
4257dd7cddfSDavid du Colombier     edev->plane_white = gx_device_white(plane_dev);
4267dd7cddfSDavid du Colombier     edev->plane_mask = (1 << plane_depth) - 1;
4277dd7cddfSDavid du Colombier     edev->plane_dev_is_memory = mdproto != 0 &&
4287dd7cddfSDavid du Colombier 	dev_proc(plane_dev, copy_color) == dev_proc(mdproto, copy_color);
4297dd7cddfSDavid du Colombier     /* We don't set or clear any_marks here: see ...init above. */
4307dd7cddfSDavid du Colombier     return 0;
4317dd7cddfSDavid du Colombier }
4327dd7cddfSDavid du Colombier 
4337dd7cddfSDavid du Colombier private int
plane_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)4347dd7cddfSDavid du Colombier plane_fill_rectangle(gx_device *dev,
4357dd7cddfSDavid du Colombier     int x, int y, int w, int h, gx_color_index color)
4367dd7cddfSDavid du Colombier {
4377dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
4387dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
4397dd7cddfSDavid du Colombier     gx_color_index pixel = COLOR_PIXEL(edev, color);
4407dd7cddfSDavid du Colombier 
4417dd7cddfSDavid du Colombier     if (pixel != edev->plane_white)
4427dd7cddfSDavid du Colombier 	edev->any_marks = true;
4437dd7cddfSDavid du Colombier     else if (!edev->any_marks)
4447dd7cddfSDavid du Colombier 	return 0;
4457dd7cddfSDavid du Colombier     return dev_proc(plane_dev, fill_rectangle)
4467dd7cddfSDavid du Colombier 	(plane_dev, x, y, w, h, pixel);
4477dd7cddfSDavid du Colombier }
4487dd7cddfSDavid du Colombier 
4497dd7cddfSDavid du Colombier private int
plane_copy_mono(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1)4507dd7cddfSDavid du Colombier plane_copy_mono(gx_device *dev,
4517dd7cddfSDavid du Colombier     const byte *data, int data_x, int raster, gx_bitmap_id id,
4527dd7cddfSDavid du Colombier     int x, int y, int w, int h,
4537dd7cddfSDavid du Colombier     gx_color_index color0, gx_color_index color1)
4547dd7cddfSDavid du Colombier {
4557dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
4567dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
4577dd7cddfSDavid du Colombier     gx_color_index pixel0 = TRANS_COLOR_PIXEL(edev, color0);
4587dd7cddfSDavid du Colombier     gx_color_index pixel1 = TRANS_COLOR_PIXEL(edev, color1);
4597dd7cddfSDavid du Colombier 
4607dd7cddfSDavid du Colombier     if (pixel0 == pixel1)
4617dd7cddfSDavid du Colombier 	return plane_fill_rectangle(dev, x, y, w, h, color0);
4627dd7cddfSDavid du Colombier     if ((pixel0 == edev->plane_white || pixel0 == gx_no_color_index) &&
4637dd7cddfSDavid du Colombier 	(pixel1 == edev->plane_white || pixel1 == gx_no_color_index)) {
4647dd7cddfSDavid du Colombier 	/* This operation will only write white. */
4657dd7cddfSDavid du Colombier 	if (!edev->any_marks)
4667dd7cddfSDavid du Colombier 	    return 0;
4677dd7cddfSDavid du Colombier     } else
4687dd7cddfSDavid du Colombier 	edev->any_marks = true;
4697dd7cddfSDavid du Colombier     return dev_proc(plane_dev, copy_mono)
4707dd7cddfSDavid du Colombier 	(plane_dev, data, data_x, raster, id, x, y, w, h, pixel0, pixel1);
4717dd7cddfSDavid du Colombier }
4727dd7cddfSDavid du Colombier 
4737dd7cddfSDavid du Colombier private int
plane_copy_color(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int w,int h)4747dd7cddfSDavid du Colombier plane_copy_color(gx_device *dev,
4757dd7cddfSDavid du Colombier     const byte *data, int data_x, int raster, gx_bitmap_id id,
4767dd7cddfSDavid du Colombier     int x, int y, int w, int h)
4777dd7cddfSDavid du Colombier {
4787dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
4797dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
4807dd7cddfSDavid du Colombier     tiling_state_t state;
4817dd7cddfSDavid du Colombier     long buf[COPY_COLOR_BUF_SIZE / sizeof(long)];
4827dd7cddfSDavid du Colombier     int code;
4837dd7cddfSDavid du Colombier 
4847dd7cddfSDavid du Colombier     if (edev->plane_dev_is_memory) {
4857dd7cddfSDavid du Colombier 	/* Reduce the source directly into the plane device. */
4867dd7cddfSDavid du Colombier 	gx_device_memory * const mdev = (gx_device_memory *)plane_dev;
4877dd7cddfSDavid du Colombier 
4887dd7cddfSDavid du Colombier 	fit_copy(edev, data, data_x, raster, id, x, y, w, h);
4897dd7cddfSDavid du Colombier 	code = begin_tiling(&state, edev, data, data_x, raster, w, h,
4907dd7cddfSDavid du Colombier 			    scan_line_base(mdev, y), max_uint, false);
4917dd7cddfSDavid du Colombier 	if (code < 0)
4927dd7cddfSDavid du Colombier 	    return code;
4937dd7cddfSDavid du Colombier 	state.dest_x = x;
4947dd7cddfSDavid du Colombier 	state.buffer.raster = mdev->raster;
4957dd7cddfSDavid du Colombier 	extract_partial_tile(&state);
4967dd7cddfSDavid du Colombier 	end_tiling(&state);
4977dd7cddfSDavid du Colombier 	edev->any_marks = true;
4987dd7cddfSDavid du Colombier 	return 0;
4997dd7cddfSDavid du Colombier     }
5007dd7cddfSDavid du Colombier     code = begin_tiling(&state, edev, data, data_x, raster,
5017dd7cddfSDavid du Colombier 			w, h, (byte *)buf, sizeof(buf), true);
5027dd7cddfSDavid du Colombier     if (code < 0)
5037dd7cddfSDavid du Colombier 	return code;
5047dd7cddfSDavid du Colombier     do {
5057dd7cddfSDavid du Colombier 	extract_partial_tile(&state);
5067dd7cddfSDavid du Colombier 	code = dev_proc(plane_dev, copy_color)
5077dd7cddfSDavid du Colombier 	    (plane_dev, state.buffer.data, 0, state.buffer.raster,
5087dd7cddfSDavid du Colombier 	     gx_no_bitmap_id, x + state.offset.x, y + state.offset.y,
5097dd7cddfSDavid du Colombier 	     state.size.x, state.size.y);
5107dd7cddfSDavid du Colombier     } while (code >= 0 && next_tile(&state));
5117dd7cddfSDavid du Colombier     end_tiling(&state);
5127dd7cddfSDavid du Colombier     edev->any_marks = true;
5137dd7cddfSDavid du Colombier     return code;
5147dd7cddfSDavid du Colombier }
5157dd7cddfSDavid du Colombier 
5167dd7cddfSDavid du Colombier private int
plane_copy_alpha(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color,int depth)5177dd7cddfSDavid du Colombier plane_copy_alpha(gx_device *dev, const byte *data, int data_x,
5187dd7cddfSDavid du Colombier     int raster, gx_bitmap_id id, int x, int y, int w, int h,
5197dd7cddfSDavid du Colombier     gx_color_index color, int depth)
5207dd7cddfSDavid du Colombier {
5217dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
5227dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
5237dd7cddfSDavid du Colombier     gx_color_index pixel = COLOR_PIXEL(edev, color);
5247dd7cddfSDavid du Colombier 
5257dd7cddfSDavid du Colombier     if (pixel != edev->plane_white)
5267dd7cddfSDavid du Colombier 	edev->any_marks = true;
5277dd7cddfSDavid du Colombier     else if (!edev->any_marks)
5287dd7cddfSDavid du Colombier 	return 0;
5297dd7cddfSDavid du Colombier     return dev_proc(plane_dev, copy_alpha)
5307dd7cddfSDavid du Colombier 	(plane_dev, data, data_x, raster, id, x, y, w, h, pixel, depth);
5317dd7cddfSDavid du Colombier }
5327dd7cddfSDavid du Colombier 
5337dd7cddfSDavid du Colombier private int
plane_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdevc,const gx_clip_path * pcpath)5347dd7cddfSDavid du Colombier plane_fill_path(gx_device *dev,
5357dd7cddfSDavid du Colombier     const gs_imager_state *pis, gx_path *ppath,
5367dd7cddfSDavid du Colombier     const gx_fill_params *params,
5377dd7cddfSDavid du Colombier     const gx_drawing_color *pdevc, const gx_clip_path *pcpath)
5387dd7cddfSDavid du Colombier {
5397dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
5407dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
5417dd7cddfSDavid du Colombier     gs_logical_operation_t lop_orig =
5427dd7cddfSDavid du Colombier 	gs_current_logical_op((const gs_state *)pis);
5437dd7cddfSDavid du Colombier     gs_logical_operation_t lop = lop_orig;
5447dd7cddfSDavid du Colombier     gx_device_color dcolor;
5457dd7cddfSDavid du Colombier 
5467dd7cddfSDavid du Colombier     switch (reduce_drawing_color(&dcolor, edev, pdevc, &lop)) {
5477dd7cddfSDavid du Colombier     case REDUCE_SKIP:
5487dd7cddfSDavid du Colombier 	return 0;
5497dd7cddfSDavid du Colombier     case REDUCE_DRAW: {
5507dd7cddfSDavid du Colombier 	gs_imager_state lopis;
5517dd7cddfSDavid du Colombier 	const gs_imager_state *pis_draw = pis;
5527dd7cddfSDavid du Colombier 
5537dd7cddfSDavid du Colombier 	if (lop != lop_orig) {
5547dd7cddfSDavid du Colombier 	    lopis = *pis;
5557dd7cddfSDavid du Colombier 	    gs_set_logical_op((gs_state *)&lopis, lop);
5567dd7cddfSDavid du Colombier 	    pis_draw = &lopis;
5577dd7cddfSDavid du Colombier 	}
5587dd7cddfSDavid du Colombier 	return dev_proc(plane_dev, fill_path)
5597dd7cddfSDavid du Colombier 	    (plane_dev, pis_draw, ppath, params, &dcolor, pcpath);
5607dd7cddfSDavid du Colombier     }
5617dd7cddfSDavid du Colombier     default /*REDUCE_FAILED*/:
5627dd7cddfSDavid du Colombier 	return gx_default_fill_path(dev, pis, ppath, params, pdevc, pcpath);
5637dd7cddfSDavid du Colombier     }
5647dd7cddfSDavid du Colombier }
5657dd7cddfSDavid du Colombier 
5667dd7cddfSDavid du Colombier private int
plane_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdevc,const gx_clip_path * pcpath)5677dd7cddfSDavid du Colombier plane_stroke_path(gx_device *dev,
5687dd7cddfSDavid du Colombier     const gs_imager_state *pis, gx_path *ppath,
5697dd7cddfSDavid du Colombier     const gx_stroke_params *params,
5707dd7cddfSDavid du Colombier     const gx_drawing_color *pdevc, const gx_clip_path *pcpath)
5717dd7cddfSDavid du Colombier {
5727dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
5737dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
5747dd7cddfSDavid du Colombier     gs_logical_operation_t lop_orig =
5757dd7cddfSDavid du Colombier 	gs_current_logical_op((const gs_state *)pis);
5767dd7cddfSDavid du Colombier     gs_logical_operation_t lop = lop_orig;
5777dd7cddfSDavid du Colombier     gx_device_color dcolor;
5787dd7cddfSDavid du Colombier 
5797dd7cddfSDavid du Colombier     switch (reduce_drawing_color(&dcolor, edev, pdevc, &lop)) {
5807dd7cddfSDavid du Colombier     case REDUCE_SKIP:
5817dd7cddfSDavid du Colombier 	return 0;
5827dd7cddfSDavid du Colombier     case REDUCE_DRAW: {
5837dd7cddfSDavid du Colombier 	gs_imager_state lopis;
5847dd7cddfSDavid du Colombier 	const gs_imager_state *pis_draw = pis;
5857dd7cddfSDavid du Colombier 
5867dd7cddfSDavid du Colombier 	if (lop != lop_orig) {
5877dd7cddfSDavid du Colombier 	    lopis = *pis;
5887dd7cddfSDavid du Colombier 	    gs_set_logical_op((gs_state *)&lopis, lop);
5897dd7cddfSDavid du Colombier 	    pis_draw = &lopis;
5907dd7cddfSDavid du Colombier 	}
5917dd7cddfSDavid du Colombier 	return dev_proc(plane_dev, stroke_path)
5927dd7cddfSDavid du Colombier 	    (plane_dev, pis_draw, ppath, params, &dcolor, pcpath);
5937dd7cddfSDavid du Colombier     }
5947dd7cddfSDavid du Colombier     default /*REDUCE_FAILED*/:
5957dd7cddfSDavid du Colombier 	return gx_default_stroke_path(dev, pis, ppath, params, pdevc, pcpath);
5967dd7cddfSDavid du Colombier     }
5977dd7cddfSDavid du Colombier }
5987dd7cddfSDavid du Colombier 
5997dd7cddfSDavid du Colombier private int
plane_fill_mask(gx_device * dev,const byte * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int w,int h,const gx_drawing_color * pdcolor,int depth,gs_logical_operation_t lop,const gx_clip_path * pcpath)6007dd7cddfSDavid du Colombier plane_fill_mask(gx_device *dev,
6017dd7cddfSDavid du Colombier     const byte *data, int data_x, int raster, gx_bitmap_id id,
6027dd7cddfSDavid du Colombier     int x, int y, int w, int h,
6037dd7cddfSDavid du Colombier     const gx_drawing_color *pdcolor, int depth,
6047dd7cddfSDavid du Colombier     gs_logical_operation_t lop, const gx_clip_path *pcpath)
6057dd7cddfSDavid du Colombier {
6067dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
6077dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
6087dd7cddfSDavid du Colombier     gx_device_color dcolor;
6097dd7cddfSDavid du Colombier 
6107dd7cddfSDavid du Colombier     switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) {
6117dd7cddfSDavid du Colombier     case REDUCE_SKIP:
6127dd7cddfSDavid du Colombier 	return 0;
6137dd7cddfSDavid du Colombier     case REDUCE_DRAW:
6147dd7cddfSDavid du Colombier 	return dev_proc(plane_dev, fill_mask)
6157dd7cddfSDavid du Colombier 	    (plane_dev, data, data_x, raster, gx_no_bitmap_id, x, y, w, h,
6167dd7cddfSDavid du Colombier 	     &dcolor, depth, lop, pcpath);
6177dd7cddfSDavid du Colombier     default /*REDUCE_FAILED*/:
6187dd7cddfSDavid du Colombier 	return gx_default_fill_mask(dev, data, data_x, raster, gx_no_bitmap_id,
6197dd7cddfSDavid du Colombier 				    x, y, w, h, &dcolor, depth, lop, pcpath);
6207dd7cddfSDavid du Colombier     }
6217dd7cddfSDavid du Colombier }
6227dd7cddfSDavid du Colombier 
6237dd7cddfSDavid du Colombier private int
plane_fill_parallelogram(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)6247dd7cddfSDavid du Colombier plane_fill_parallelogram(gx_device * dev,
6257dd7cddfSDavid du Colombier     fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
6267dd7cddfSDavid du Colombier     const gx_drawing_color * pdcolor, gs_logical_operation_t lop)
6277dd7cddfSDavid du Colombier {
6287dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
6297dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
6307dd7cddfSDavid du Colombier     gx_device_color dcolor;
6317dd7cddfSDavid du Colombier 
6327dd7cddfSDavid du Colombier     switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) {
6337dd7cddfSDavid du Colombier     case REDUCE_SKIP:
6347dd7cddfSDavid du Colombier 	return 0;
6357dd7cddfSDavid du Colombier     case REDUCE_DRAW:
6367dd7cddfSDavid du Colombier 	return dev_proc(plane_dev, fill_parallelogram)
6377dd7cddfSDavid du Colombier 	    (plane_dev, px, py, ax, ay, bx, by, &dcolor, lop);
6387dd7cddfSDavid du Colombier     default /*REDUCE_FAILED*/:
6397dd7cddfSDavid du Colombier 	return gx_default_fill_parallelogram(dev, px, py, ax, ay, bx, by,
6407dd7cddfSDavid du Colombier 					     pdcolor, lop);
6417dd7cddfSDavid du Colombier     }
6427dd7cddfSDavid du Colombier }
6437dd7cddfSDavid du Colombier 
6447dd7cddfSDavid du Colombier private int
plane_fill_triangle(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)6457dd7cddfSDavid du Colombier plane_fill_triangle(gx_device * dev,
6467dd7cddfSDavid du Colombier     fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
6477dd7cddfSDavid du Colombier     const gx_drawing_color * pdcolor, gs_logical_operation_t lop)
6487dd7cddfSDavid du Colombier {
6497dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
6507dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
6517dd7cddfSDavid du Colombier     gx_device_color dcolor;
6527dd7cddfSDavid du Colombier 
6537dd7cddfSDavid du Colombier     switch (reduce_drawing_color(&dcolor, edev, pdcolor, &lop)) {
6547dd7cddfSDavid du Colombier     case REDUCE_SKIP:
6557dd7cddfSDavid du Colombier 	return 0;
6567dd7cddfSDavid du Colombier     case REDUCE_DRAW:
6577dd7cddfSDavid du Colombier 	return dev_proc(plane_dev, fill_triangle)
6587dd7cddfSDavid du Colombier 	    (plane_dev, px, py, ax, ay, bx, by, &dcolor, lop);
6597dd7cddfSDavid du Colombier     default /*REDUCE_FAILED*/:
6607dd7cddfSDavid du Colombier 	return gx_default_fill_triangle(dev, px, py, ax, ay, bx, by,
6617dd7cddfSDavid du Colombier 					pdcolor, lop);
6627dd7cddfSDavid du Colombier     }
6637dd7cddfSDavid du Colombier }
6647dd7cddfSDavid du Colombier 
6657dd7cddfSDavid du Colombier private int
plane_strip_tile_rectangle(gx_device * dev,const gx_strip_bitmap * tiles,int x,int y,int w,int h,gx_color_index color0,gx_color_index color1,int phase_x,int phase_y)6667dd7cddfSDavid du Colombier plane_strip_tile_rectangle(gx_device *dev,
6677dd7cddfSDavid du Colombier     const gx_strip_bitmap *tiles, int x, int y, int w, int h,
6687dd7cddfSDavid du Colombier     gx_color_index color0, gx_color_index color1,
6697dd7cddfSDavid du Colombier     int phase_x, int phase_y)
6707dd7cddfSDavid du Colombier {
6717dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
6727dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
6737dd7cddfSDavid du Colombier     gx_color_index pixel0 = TRANS_COLOR_PIXEL(edev, color0);
6747dd7cddfSDavid du Colombier     gx_color_index pixel1 = TRANS_COLOR_PIXEL(edev, color1);
6757dd7cddfSDavid du Colombier 
6767dd7cddfSDavid du Colombier     if (pixel0 == pixel1) {
6777dd7cddfSDavid du Colombier 	if (pixel0 != gx_no_color_index)
6787dd7cddfSDavid du Colombier 	    return plane_fill_rectangle(dev, x, y, w, h, color0);
6797dd7cddfSDavid du Colombier 	/* The tile is a pixmap rather than a bitmap. */
6807dd7cddfSDavid du Colombier 	/* We should use the default implementation if it is small.... */
6817dd7cddfSDavid du Colombier 	{
6827dd7cddfSDavid du Colombier 	    gx_strip_bitmap plane_tile;
6837dd7cddfSDavid du Colombier 	    tiling_state_t state;
6847dd7cddfSDavid du Colombier 	    long buf[TILE_RECTANGLE_BUF_SIZE / sizeof(long)];
6857dd7cddfSDavid du Colombier 	    int code = begin_tiling(&state, edev, tiles->data, 0, tiles->raster,
6867dd7cddfSDavid du Colombier 			tiles->size.x, tiles->size.y,
6877dd7cddfSDavid du Colombier 				(byte *)buf, sizeof(buf), false);
6887dd7cddfSDavid du Colombier 
6897dd7cddfSDavid du Colombier 	    if (code < 0)
6907dd7cddfSDavid du Colombier 		return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h,
6917dd7cddfSDavid du Colombier 					color0, color1, phase_x, phase_y);
6927dd7cddfSDavid du Colombier 	    extract_partial_tile(&state);
6937dd7cddfSDavid du Colombier 	    plane_tile = *tiles;
6947dd7cddfSDavid du Colombier 	    plane_tile.data = state.buffer.data;
6957dd7cddfSDavid du Colombier 	    plane_tile.raster = state.buffer.raster;
6967dd7cddfSDavid du Colombier 	    plane_tile.id = gx_no_bitmap_id;
6977dd7cddfSDavid du Colombier 	    code = dev_proc(plane_dev, strip_tile_rectangle)
6987dd7cddfSDavid du Colombier 		(plane_dev, &plane_tile, x, y, w, h, pixel0, pixel1,
6997dd7cddfSDavid du Colombier 		 phase_x, phase_y);
7007dd7cddfSDavid du Colombier 	    end_tiling(&state);
7017dd7cddfSDavid du Colombier 	    edev->any_marks = true;
7027dd7cddfSDavid du Colombier 	    return code;
7037dd7cddfSDavid du Colombier 	}
7047dd7cddfSDavid du Colombier     }
7057dd7cddfSDavid du Colombier     if ((pixel0 == edev->plane_white || pixel0 == gx_no_color_index) &&
7067dd7cddfSDavid du Colombier 	(pixel1 == edev->plane_white || pixel1 == gx_no_color_index)) {
7077dd7cddfSDavid du Colombier 	/* This operation will only write white. */
7087dd7cddfSDavid du Colombier 	if (!edev->any_marks)
7097dd7cddfSDavid du Colombier 	    return 0;
7107dd7cddfSDavid du Colombier     } else
7117dd7cddfSDavid du Colombier 	edev->any_marks = true;
7127dd7cddfSDavid du Colombier     return dev_proc(plane_dev, strip_tile_rectangle)
7137dd7cddfSDavid du Colombier 	(plane_dev, tiles, x, y, w, h, pixel0, pixel1, phase_x, phase_y);
7147dd7cddfSDavid du Colombier }
7157dd7cddfSDavid du Colombier 
7167dd7cddfSDavid du Colombier private int
plane_strip_copy_rop(gx_device * dev,const byte * sdata,int sourcex,uint sraster,gx_bitmap_id id,const gx_color_index * scolors,const gx_strip_bitmap * textures,const gx_color_index * tcolors,int x,int y,int w,int h,int phase_x,int phase_y,gs_logical_operation_t lop)7177dd7cddfSDavid du Colombier plane_strip_copy_rop(gx_device *dev,
7187dd7cddfSDavid du Colombier     const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
7197dd7cddfSDavid du Colombier     const gx_color_index *scolors,
7207dd7cddfSDavid du Colombier     const gx_strip_bitmap *textures, const gx_color_index *tcolors,
7217dd7cddfSDavid du Colombier     int x, int y, int w, int h,
7227dd7cddfSDavid du Colombier     int phase_x, int phase_y, gs_logical_operation_t lop)
7237dd7cddfSDavid du Colombier {
7247dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
7257dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
7267dd7cddfSDavid du Colombier     gs_rop3_t rop = lop_rop(lop);
7277dd7cddfSDavid du Colombier     struct crp_ {
7287dd7cddfSDavid du Colombier 	gx_color_index pixels[2];
7297dd7cddfSDavid du Colombier 	gx_color_index *colors;
7307dd7cddfSDavid du Colombier 	tiling_state_t state;
7317dd7cddfSDavid du Colombier     } source, texture;
7327dd7cddfSDavid du Colombier     long sbuf[COPY_ROP_SOURCE_BUF_SIZE / sizeof(long)];
7337dd7cddfSDavid du Colombier     long tbuf[COPY_ROP_TEXTURE_BUF_SIZE / sizeof(long)];
7347dd7cddfSDavid du Colombier     const byte *plane_source;
735*593dc095SDavid du Colombier     uint plane_raster = 0xbaadf00d; /* Initialize against indeterminizm. */
7367dd7cddfSDavid du Colombier     gx_strip_bitmap plane_texture;
737*593dc095SDavid du Colombier     const gx_strip_bitmap *plane_textures = NULL;
7387dd7cddfSDavid du Colombier     int code;
7397dd7cddfSDavid du Colombier 
7407dd7cddfSDavid du Colombier     /* We should do better than this on transparency.... */
7417dd7cddfSDavid du Colombier     if (lop & (lop_S_transparent | lop_T_transparent))
7427dd7cddfSDavid du Colombier 	return gx_default_strip_copy_rop(dev, sdata, sourcex, sraster, id,
7437dd7cddfSDavid du Colombier 					 scolors, textures, tcolors,
7447dd7cddfSDavid du Colombier 					 x, y, w, h, phase_x, phase_y, lop);
7457dd7cddfSDavid du Colombier     if (!rop3_uses_S(rop)) {
7467dd7cddfSDavid du Colombier 	sdata = 0;
7477dd7cddfSDavid du Colombier 	source.colors = 0;
7487dd7cddfSDavid du Colombier     } else if (scolors) {
7497dd7cddfSDavid du Colombier 	source.pixels[0] = COLOR_PIXEL(edev, scolors[0]);
7507dd7cddfSDavid du Colombier 	source.pixels[1] = COLOR_PIXEL(edev, scolors[1]);
7517dd7cddfSDavid du Colombier 	if (source.pixels[0] == source.pixels[1])
7527dd7cddfSDavid du Colombier 	    sdata = 0;
7537dd7cddfSDavid du Colombier 	source.colors = source.pixels;
7547dd7cddfSDavid du Colombier     }
7557dd7cddfSDavid du Colombier     else
7567dd7cddfSDavid du Colombier 	source.colors = 0;
7577dd7cddfSDavid du Colombier     if (!rop3_uses_T(rop)) {
7587dd7cddfSDavid du Colombier 	textures = 0;
7597dd7cddfSDavid du Colombier 	texture.colors = 0;
7607dd7cddfSDavid du Colombier     } else if (tcolors) {
7617dd7cddfSDavid du Colombier 	texture.pixels[0] = COLOR_PIXEL(edev, tcolors[0]);
7627dd7cddfSDavid du Colombier 	texture.pixels[1] = COLOR_PIXEL(edev, tcolors[1]);
7637dd7cddfSDavid du Colombier 	if (texture.pixels[0] == texture.pixels[1])
7647dd7cddfSDavid du Colombier 	    textures = 0;
7657dd7cddfSDavid du Colombier 	texture.colors = texture.pixels;
7667dd7cddfSDavid du Colombier     }
7677dd7cddfSDavid du Colombier     else
7687dd7cddfSDavid du Colombier 	texture.colors = 0;
7697dd7cddfSDavid du Colombier     if (sdata) {
7707dd7cddfSDavid du Colombier 	code = begin_tiling(&source.state, edev, sdata, sourcex, sraster, w, y,
7717dd7cddfSDavid du Colombier 			    (byte *)sbuf, sizeof(sbuf), true);
7727dd7cddfSDavid du Colombier 	if (code < 0)
7737dd7cddfSDavid du Colombier 	    return gx_default_strip_copy_rop(dev, sdata, sourcex, sraster, id,
7747dd7cddfSDavid du Colombier 					     scolors, textures, tcolors,
7757dd7cddfSDavid du Colombier 					     x, y, w, h, phase_x, phase_y, lop);
7767dd7cddfSDavid du Colombier 	plane_source = source.state.buffer.data;
7777dd7cddfSDavid du Colombier 	plane_raster = source.state.buffer.raster;
7787dd7cddfSDavid du Colombier     } else
7797dd7cddfSDavid du Colombier 	plane_source = 0;
7807dd7cddfSDavid du Colombier     if (textures) {
7817dd7cddfSDavid du Colombier 	code = begin_tiling(&texture.state, edev, textures->data, 0,
7827dd7cddfSDavid du Colombier 			    textures->raster, textures->size.x,
7837dd7cddfSDavid du Colombier 			    textures->size.y, (byte *)tbuf, sizeof(tbuf),
7847dd7cddfSDavid du Colombier 			    false);
7857dd7cddfSDavid du Colombier 	if (code < 0) {
7867dd7cddfSDavid du Colombier 	    if (plane_source)
7877dd7cddfSDavid du Colombier 		end_tiling(&source.state);
7887dd7cddfSDavid du Colombier 	    return code;
7897dd7cddfSDavid du Colombier 	}
7907dd7cddfSDavid du Colombier 	plane_texture = *textures;
7917dd7cddfSDavid du Colombier 	plane_texture.data = texture.state.buffer.data;
7927dd7cddfSDavid du Colombier 	plane_texture.raster = texture.state.buffer.raster;
7937dd7cddfSDavid du Colombier 	plane_textures = &plane_texture;
7947dd7cddfSDavid du Colombier     }
7957dd7cddfSDavid du Colombier     if (textures)
7967dd7cddfSDavid du Colombier 	extract_partial_tile(&texture.state);
7977dd7cddfSDavid du Colombier     do {
7987dd7cddfSDavid du Colombier 	if (sdata)
7997dd7cddfSDavid du Colombier 	    extract_partial_tile(&source.state);
8007dd7cddfSDavid du Colombier 	code = dev_proc(plane_dev, strip_copy_rop)
8017dd7cddfSDavid du Colombier 	    (plane_dev, plane_source, sourcex, plane_raster, gx_no_bitmap_id,
8027dd7cddfSDavid du Colombier 	     source.colors, plane_textures, texture.colors,
8037dd7cddfSDavid du Colombier 	     x, y, w, h, phase_x, phase_y, lop);
8047dd7cddfSDavid du Colombier     } while (code >= 0 && sdata && next_tile(&source.state));
8057dd7cddfSDavid du Colombier     if (textures)
8067dd7cddfSDavid du Colombier 	end_tiling(&texture.state);
8077dd7cddfSDavid du Colombier     if (sdata)
8087dd7cddfSDavid du Colombier 	end_tiling(&source.state);
8097dd7cddfSDavid du Colombier     return code;
8107dd7cddfSDavid du Colombier }
8117dd7cddfSDavid du Colombier 
8127dd7cddfSDavid du Colombier /* ---------------- Images ---------------- */
8137dd7cddfSDavid du Colombier 
8147dd7cddfSDavid du Colombier /* Define the state for image rendering. */
8157dd7cddfSDavid du Colombier typedef struct plane_image_enum_s {
8167dd7cddfSDavid du Colombier     gx_image_enum_common;
8177dd7cddfSDavid du Colombier     gs_memory_t *memory;
8187dd7cddfSDavid du Colombier     gx_image_enum_common_t *info; /* plane device enumerator */
8197dd7cddfSDavid du Colombier     const gs_imager_state *pis;	/* original imager state */
8207dd7cddfSDavid du Colombier     gs_imager_state *pis_image;	/* modified imager state */
8217dd7cddfSDavid du Colombier } plane_image_enum_t;
8227dd7cddfSDavid du Colombier gs_private_st_suffix_add3(st_plane_image_enum, plane_image_enum_t,
8237dd7cddfSDavid du Colombier   "plane_image_enum_t", plane_image_enum_enum_ptrs,
8247dd7cddfSDavid du Colombier   plane_image_enum_reloc_ptrs, st_gx_image_enum_common, info, pis, pis_image);
8257dd7cddfSDavid du Colombier 
8267dd7cddfSDavid du Colombier /*
8277dd7cddfSDavid du Colombier  * Reduce drawing colors returned by color mapping.  Note that these
8287dd7cddfSDavid du Colombier  * assume that the call of reduce_drawing_color will not fail:
8297dd7cddfSDavid du Colombier  * plane_begin_typed_image must ensure this.
8307dd7cddfSDavid du Colombier  *
8317dd7cddfSDavid du Colombier  * In the imager state passed to these procedures, the client data is
8327dd7cddfSDavid du Colombier  * the plane_image_enum_t.
8337dd7cddfSDavid du Colombier  */
8347dd7cddfSDavid du Colombier 
8357dd7cddfSDavid du Colombier private void
plane_cmap_gray(frac gray,gx_device_color * pdc,const gs_imager_state * pis_image,gx_device * dev,gs_color_select_t select)8367dd7cddfSDavid du Colombier plane_cmap_gray(frac gray, gx_device_color * pdc,
8377dd7cddfSDavid du Colombier     const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select)
8387dd7cddfSDavid du Colombier {
8397dd7cddfSDavid du Colombier     const plane_image_enum_t *ppie =
8407dd7cddfSDavid du Colombier 	(const plane_image_enum_t *)pis_image->client_data;
8417dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev =
8427dd7cddfSDavid du Colombier 	(gx_device_plane_extract *)ppie->dev;
8437dd7cddfSDavid du Colombier     gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image);
8447dd7cddfSDavid du Colombier     gx_device_color dcolor;
8457dd7cddfSDavid du Colombier 
8467dd7cddfSDavid du Colombier     gx_remap_concrete_gray(gray, &dcolor, ppie->pis,
8477dd7cddfSDavid du Colombier 			   (gx_device *)edev, select);
8487dd7cddfSDavid du Colombier     reduce_drawing_color(pdc, edev, &dcolor, &lop);
8497dd7cddfSDavid du Colombier }
8507dd7cddfSDavid du Colombier private void
plane_cmap_rgb(frac r,frac g,frac b,gx_device_color * pdc,const gs_imager_state * pis_image,gx_device * dev,gs_color_select_t select)8517dd7cddfSDavid du Colombier plane_cmap_rgb(frac r, frac g, frac b, gx_device_color * pdc,
8527dd7cddfSDavid du Colombier     const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select)
8537dd7cddfSDavid du Colombier {
8547dd7cddfSDavid du Colombier     const plane_image_enum_t *ppie =
8557dd7cddfSDavid du Colombier 	(const plane_image_enum_t *)pis_image->client_data;
8567dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev =
8577dd7cddfSDavid du Colombier 	(gx_device_plane_extract *)ppie->dev;
8587dd7cddfSDavid du Colombier     gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image);
8597dd7cddfSDavid du Colombier     gx_device_color dcolor;
8607dd7cddfSDavid du Colombier 
8617dd7cddfSDavid du Colombier     gx_remap_concrete_rgb(r, g, b, &dcolor, ppie->pis,
8627dd7cddfSDavid du Colombier 			  (gx_device *)edev, select);
8637dd7cddfSDavid du Colombier     reduce_drawing_color(pdc, edev, &dcolor, &lop);
8647dd7cddfSDavid du Colombier }
8657dd7cddfSDavid du Colombier private void
plane_cmap_cmyk(frac c,frac m,frac y,frac k,gx_device_color * pdc,const gs_imager_state * pis_image,gx_device * dev,gs_color_select_t select)8667dd7cddfSDavid du Colombier plane_cmap_cmyk(frac c, frac m, frac y, frac k, gx_device_color * pdc,
8677dd7cddfSDavid du Colombier     const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select)
8687dd7cddfSDavid du Colombier {
8697dd7cddfSDavid du Colombier     const plane_image_enum_t *ppie =
8707dd7cddfSDavid du Colombier 	(const plane_image_enum_t *)pis_image->client_data;
8717dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev =
8727dd7cddfSDavid du Colombier 	(gx_device_plane_extract *)ppie->dev;
8737dd7cddfSDavid du Colombier     gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image);
8747dd7cddfSDavid du Colombier     gx_device_color dcolor;
8757dd7cddfSDavid du Colombier 
8767dd7cddfSDavid du Colombier     gx_remap_concrete_cmyk(c, m, y, k, &dcolor, ppie->pis,
8777dd7cddfSDavid du Colombier 			   (gx_device *)edev, select);
8787dd7cddfSDavid du Colombier     reduce_drawing_color(pdc, edev, &dcolor, &lop);
8797dd7cddfSDavid du Colombier }
8807dd7cddfSDavid du Colombier private void
plane_cmap_rgb_alpha(frac r,frac g,frac b,frac alpha,gx_device_color * pdc,const gs_imager_state * pis_image,gx_device * dev,gs_color_select_t select)8817dd7cddfSDavid du Colombier plane_cmap_rgb_alpha(frac r, frac g, frac b, frac alpha, gx_device_color * pdc,
8827dd7cddfSDavid du Colombier     const gs_imager_state *pis_image, gx_device *dev, gs_color_select_t select)
8837dd7cddfSDavid du Colombier {
8847dd7cddfSDavid du Colombier     const plane_image_enum_t *ppie =
8857dd7cddfSDavid du Colombier 	(const plane_image_enum_t *)pis_image->client_data;
8867dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev =
8877dd7cddfSDavid du Colombier 	(gx_device_plane_extract *)ppie->dev;
8887dd7cddfSDavid du Colombier     gs_logical_operation_t lop = gs_current_logical_op_inline(pis_image);
8897dd7cddfSDavid du Colombier     gx_device_color dcolor;
8907dd7cddfSDavid du Colombier 
8917dd7cddfSDavid du Colombier     gx_remap_concrete_rgb_alpha(r, g, b, alpha, &dcolor, ppie->pis,
8927dd7cddfSDavid du Colombier 				(gx_device *)edev, select);
8937dd7cddfSDavid du Colombier     reduce_drawing_color(pdc, edev, &dcolor, &lop);
8947dd7cddfSDavid du Colombier }
895*593dc095SDavid du Colombier private bool
plane_cmap_is_halftoned(const gs_imager_state * pis_image,gx_device * dev)896*593dc095SDavid du Colombier plane_cmap_is_halftoned(const gs_imager_state *pis_image, gx_device *dev)
897*593dc095SDavid du Colombier {
898*593dc095SDavid du Colombier     return false;
899*593dc095SDavid du Colombier }
900*593dc095SDavid du Colombier 
9017dd7cddfSDavid du Colombier private const gx_color_map_procs plane_color_map_procs = {
902*593dc095SDavid du Colombier     plane_cmap_gray, plane_cmap_rgb, plane_cmap_cmyk, plane_cmap_rgb_alpha,
903*593dc095SDavid du Colombier     NULL, NULL, plane_cmap_is_halftoned
9047dd7cddfSDavid du Colombier };
9057dd7cddfSDavid du Colombier private const gx_color_map_procs *
plane_get_cmap_procs(const gs_imager_state * pis,const gx_device * dev)9067dd7cddfSDavid du Colombier plane_get_cmap_procs(const gs_imager_state *pis, const gx_device *dev)
9077dd7cddfSDavid du Colombier {
9087dd7cddfSDavid du Colombier     return &plane_color_map_procs;
9097dd7cddfSDavid du Colombier }
9107dd7cddfSDavid du Colombier 
9117dd7cddfSDavid du Colombier /* Define the image processing procedures. */
9127dd7cddfSDavid du Colombier private image_enum_proc_plane_data(plane_image_plane_data);
9137dd7cddfSDavid du Colombier private image_enum_proc_end_image(plane_image_end_image);
9147dd7cddfSDavid du Colombier private const gx_image_enum_procs_t plane_image_enum_procs = {
9157dd7cddfSDavid du Colombier     plane_image_plane_data, plane_image_end_image
9167dd7cddfSDavid du Colombier };
9177dd7cddfSDavid du Colombier 
9187dd7cddfSDavid du Colombier private int
plane_begin_typed_image(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gx_image_enum_common_t ** pinfo)9197dd7cddfSDavid du Colombier plane_begin_typed_image(gx_device * dev,
9207dd7cddfSDavid du Colombier 			const gs_imager_state * pis, const gs_matrix * pmat,
9217dd7cddfSDavid du Colombier 		   const gs_image_common_t * pic, const gs_int_rect * prect,
9227dd7cddfSDavid du Colombier 	      const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
9237dd7cddfSDavid du Colombier 		      gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
9247dd7cddfSDavid du Colombier {
9257dd7cddfSDavid du Colombier     /*
9267dd7cddfSDavid du Colombier      * For images, we intercept the imager state's cmap_procs and apply
9277dd7cddfSDavid du Colombier      * reduce_drawing_color to the colors as they are returned to the image
9287dd7cddfSDavid du Colombier      * processing code.  For reasons explained above, we can't do this in
9297dd7cddfSDavid du Colombier      * some cases of RasterOp that include transparency.
9307dd7cddfSDavid du Colombier      */
9317dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
9327dd7cddfSDavid du Colombier     gs_logical_operation_t lop = gs_current_logical_op((const gs_state *)pis);
9337dd7cddfSDavid du Colombier     const gs_pixel_image_t *pim;
9347dd7cddfSDavid du Colombier     plane_image_enum_t *info = 0;
9357dd7cddfSDavid du Colombier     gs_imager_state *pis_image = 0;
9367dd7cddfSDavid du Colombier     gx_device_color dcolor;
9377dd7cddfSDavid du Colombier     bool uses_color = false;
9387dd7cddfSDavid du Colombier     int code;
9397dd7cddfSDavid du Colombier 
9407dd7cddfSDavid du Colombier     /* We can only handle a limited set of image types. */
9417dd7cddfSDavid du Colombier     switch (pic->type->index) {
9427dd7cddfSDavid du Colombier     case 1: {
9437dd7cddfSDavid du Colombier 	const gs_image1_t * const pim1 = (const gs_image1_t *)pic;
9447dd7cddfSDavid du Colombier 
9457dd7cddfSDavid du Colombier 	if (pim1->Alpha != gs_image_alpha_none)
9467dd7cddfSDavid du Colombier 	    goto fail;
9477dd7cddfSDavid du Colombier 	uses_color = pim1->ImageMask;
9487dd7cddfSDavid du Colombier 	break;
9497dd7cddfSDavid du Colombier 	}
9507dd7cddfSDavid du Colombier     case 3:
9517dd7cddfSDavid du Colombier     case 4:
9527dd7cddfSDavid du Colombier 	break;
9537dd7cddfSDavid du Colombier     default:
9547dd7cddfSDavid du Colombier 	goto fail;
9557dd7cddfSDavid du Colombier     }
9567dd7cddfSDavid du Colombier     pim = (const gs_pixel_image_t *)pic;
9577dd7cddfSDavid du Colombier     if ((lop & lop_S_transparent) ||
9587dd7cddfSDavid du Colombier 	((uses_color || pim->CombineWithColor) && (lop & lop_T_transparent))
9597dd7cddfSDavid du Colombier 	)
9607dd7cddfSDavid du Colombier 	goto fail;
9617dd7cddfSDavid du Colombier     if (uses_color || (pim->CombineWithColor && lop_uses_T(lop))) {
9627dd7cddfSDavid du Colombier 	if (reduce_drawing_color(&dcolor, edev, pdcolor, &lop) ==
9637dd7cddfSDavid du Colombier 	    REDUCE_FAILED)
9647dd7cddfSDavid du Colombier 	    goto fail;
9657dd7cddfSDavid du Colombier     } else {
9667dd7cddfSDavid du Colombier 	/*
9677dd7cddfSDavid du Colombier 	 * The drawing color won't be used, but if RasterOp is involved,
9687dd7cddfSDavid du Colombier 	 * it may still be accessed in some anomalous cases.
9697dd7cddfSDavid du Colombier 	 */
970*593dc095SDavid du Colombier 	set_nonclient_dev_color(&dcolor, (gx_color_index)0);
9717dd7cddfSDavid du Colombier     }
9727dd7cddfSDavid du Colombier     info = gs_alloc_struct(memory, plane_image_enum_t, &st_plane_image_enum,
9737dd7cddfSDavid du Colombier 			   "plane_image_begin_typed(info)");
9747dd7cddfSDavid du Colombier     pis_image = gs_imager_state_copy(pis, memory);
9757dd7cddfSDavid du Colombier     if (pis_image == 0 || info == 0)
9767dd7cddfSDavid du Colombier 	goto fail;
9777dd7cddfSDavid du Colombier     *pis_image = *pis;
9787dd7cddfSDavid du Colombier     pis_image->client_data = info;
9797dd7cddfSDavid du Colombier     pis_image->get_cmap_procs = plane_get_cmap_procs;
9807dd7cddfSDavid du Colombier     code = dev_proc(edev->plane_dev, begin_typed_image)
9817dd7cddfSDavid du Colombier 	(edev->plane_dev, pis_image, pmat, pic, prect,
9827dd7cddfSDavid du Colombier 	 &dcolor, pcpath, memory, &info->info);
9837dd7cddfSDavid du Colombier     if (code < 0)
9847dd7cddfSDavid du Colombier 	goto fail;
9857dd7cddfSDavid du Colombier     *((gx_image_enum_common_t *)info) = *info->info;
9867dd7cddfSDavid du Colombier     info->procs = &plane_image_enum_procs;
9877dd7cddfSDavid du Colombier     info->dev = (gx_device *)edev;
988*593dc095SDavid du Colombier     info->id = gs_next_ids(memory, 1);
9897dd7cddfSDavid du Colombier     info->memory = memory;
9907dd7cddfSDavid du Colombier     info->pis = pis;
9917dd7cddfSDavid du Colombier     info->pis_image = pis_image;
9927dd7cddfSDavid du Colombier     *pinfo = (gx_image_enum_common_t *)info;
9937dd7cddfSDavid du Colombier     return code;
9947dd7cddfSDavid du Colombier fail:
9957dd7cddfSDavid du Colombier     gs_free_object(memory, pis_image, "plane_image_begin_typed(pis_image)");
9967dd7cddfSDavid du Colombier     gs_free_object(memory, info, "plane_image_begin_typed(info)");
9977dd7cddfSDavid du Colombier     return gx_default_begin_typed_image(dev, pis, pmat, pic, prect,
9987dd7cddfSDavid du Colombier 					pdcolor, pcpath, memory, pinfo);
9997dd7cddfSDavid du Colombier }
10007dd7cddfSDavid du Colombier 
10017dd7cddfSDavid du Colombier private int
plane_image_plane_data(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height,int * rows_used)10027dd7cddfSDavid du Colombier plane_image_plane_data(gx_image_enum_common_t * info,
10037dd7cddfSDavid du Colombier 		       const gx_image_plane_t * planes, int height,
10047dd7cddfSDavid du Colombier 		       int *rows_used)
10057dd7cddfSDavid du Colombier {
10067dd7cddfSDavid du Colombier     plane_image_enum_t * const ppie = (plane_image_enum_t *)info;
10077dd7cddfSDavid du Colombier 
10087dd7cddfSDavid du Colombier     return gx_image_plane_data_rows(ppie->info, planes, height, rows_used);
10097dd7cddfSDavid du Colombier }
10107dd7cddfSDavid du Colombier 
10117dd7cddfSDavid du Colombier private int
plane_image_end_image(gx_image_enum_common_t * info,bool draw_last)10127dd7cddfSDavid du Colombier plane_image_end_image(gx_image_enum_common_t * info, bool draw_last)
10137dd7cddfSDavid du Colombier {
10147dd7cddfSDavid du Colombier     plane_image_enum_t * const ppie = (plane_image_enum_t *)info;
10157dd7cddfSDavid du Colombier     int code = gx_image_end(ppie->info, draw_last);
10167dd7cddfSDavid du Colombier 
10177dd7cddfSDavid du Colombier     gs_free_object(ppie->memory, ppie->pis_image,
10187dd7cddfSDavid du Colombier 		   "plane_image_end_image(pis_image)");
10197dd7cddfSDavid du Colombier     gs_free_object(ppie->memory, info, "plane_image_end_image(info)");
10207dd7cddfSDavid du Colombier     return code;
10217dd7cddfSDavid du Colombier }
10227dd7cddfSDavid du Colombier 
10237dd7cddfSDavid du Colombier /* ---------------- Reading back bits ---------------- */
10247dd7cddfSDavid du Colombier 
10257dd7cddfSDavid du Colombier private int
plane_get_bits_rectangle(gx_device * dev,const gs_int_rect * prect,gs_get_bits_params_t * params,gs_int_rect ** unread)10267dd7cddfSDavid du Colombier plane_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
10277dd7cddfSDavid du Colombier 			 gs_get_bits_params_t * params, gs_int_rect ** unread)
10287dd7cddfSDavid du Colombier {
10297dd7cddfSDavid du Colombier     gx_device_plane_extract * const edev = (gx_device_plane_extract *)dev;
10307dd7cddfSDavid du Colombier     gx_device * const plane_dev = edev->plane_dev;
10317dd7cddfSDavid du Colombier     int plane_index = edev->plane.index;
10327dd7cddfSDavid du Colombier     gs_get_bits_options_t options = params->options;
10337dd7cddfSDavid du Colombier     gs_get_bits_params_t plane_params;
10347dd7cddfSDavid du Colombier     int plane;
10357dd7cddfSDavid du Colombier     int code;
10367dd7cddfSDavid du Colombier 
10377dd7cddfSDavid du Colombier     /*
10387dd7cddfSDavid du Colombier      * The only real option that this device supports is single-plane
10397dd7cddfSDavid du Colombier      * retrieval.  However, for the default case of RasterOp, it must be
10407dd7cddfSDavid du Colombier      * able to return chunky pixels in which the other components are
10417dd7cddfSDavid du Colombier      * arbitrary (but might as well be zero).
10427dd7cddfSDavid du Colombier      */
10437dd7cddfSDavid du Colombier     if ((options & GB_PACKING_PLANAR) && (options & GB_SELECT_PLANES)) {
10447dd7cddfSDavid du Colombier 	if (params->data[plane_index] == 0)
10457dd7cddfSDavid du Colombier 	    return gx_default_get_bits_rectangle(dev, prect, params, unread);
10467dd7cddfSDavid du Colombier 	/* If the caller wants any other plane(s), punt. */
10477dd7cddfSDavid du Colombier 	for (plane = 0; plane < dev->color_info.num_components; ++plane)
10487dd7cddfSDavid du Colombier 	    if (plane != plane_index && params->data[plane] != 0)
10497dd7cddfSDavid du Colombier 		return gx_default_get_bits_rectangle(dev, prect, params, unread);
10507dd7cddfSDavid du Colombier 	/* Pass the request on to the plane device. */
10517dd7cddfSDavid du Colombier 	plane_params = *params;
10527dd7cddfSDavid du Colombier 	plane_params.options =
10537dd7cddfSDavid du Colombier 	    (options & ~(GB_PACKING_ALL | GB_SELECT_PLANES)) |
10547dd7cddfSDavid du Colombier 	    GB_PACKING_CHUNKY;
10557dd7cddfSDavid du Colombier 	plane_params.data[0] = params->data[plane_index];
10567dd7cddfSDavid du Colombier 	code = dev_proc(plane_dev, get_bits_rectangle)
10577dd7cddfSDavid du Colombier 	    (plane_dev, prect, &plane_params, unread);
10587dd7cddfSDavid du Colombier 	if (code >= 0) {
10597dd7cddfSDavid du Colombier 	    *params = plane_params;
10607dd7cddfSDavid du Colombier 	    params->options = (params->options & ~GB_PACKING_ALL) |
10617dd7cddfSDavid du Colombier 		(GB_PACKING_PLANAR | GB_SELECT_PLANES);
10627dd7cddfSDavid du Colombier 	    params->data[plane_index] = params->data[0];
10637dd7cddfSDavid du Colombier 	    for (plane = 0; plane < dev->color_info.num_components; ++plane)
10647dd7cddfSDavid du Colombier 		if (plane != plane_index)
10657dd7cddfSDavid du Colombier 		    params->data[plane] = 0;
10667dd7cddfSDavid du Colombier 	}
10677dd7cddfSDavid du Colombier     } else if (!(~options & (GB_COLORS_NATIVE | GB_ALPHA_NONE |
10687dd7cddfSDavid du Colombier 			     GB_PACKING_CHUNKY | GB_RETURN_COPY |
10697dd7cddfSDavid du Colombier 			     GB_ALIGN_STANDARD | GB_OFFSET_0 |
10707dd7cddfSDavid du Colombier 			     GB_RASTER_STANDARD))) {
10717dd7cddfSDavid du Colombier 	/* Expand the plane into chunky pixels. */
10727dd7cddfSDavid du Colombier 	bits_plane_t dest, source;
10737dd7cddfSDavid du Colombier 
10747dd7cddfSDavid du Colombier 	dest.data.write = params->data[0];
10757dd7cddfSDavid du Colombier 	dest.raster =
10767dd7cddfSDavid du Colombier 	    bitmap_raster((prect->q.x - prect->p.x) * dev->color_info.depth);
10777dd7cddfSDavid du Colombier 	dest.depth = edev->color_info.depth;
10787dd7cddfSDavid du Colombier 	dest.x = 0;
10797dd7cddfSDavid du Colombier 
10807dd7cddfSDavid du Colombier 	/* not source.data, source.raster, source.x */
10817dd7cddfSDavid du Colombier 	source.depth = plane_dev->color_info.depth;
10827dd7cddfSDavid du Colombier 
10837dd7cddfSDavid du Colombier 	plane_params = *params;
10847dd7cddfSDavid du Colombier 	plane_params.options = options &=
10857dd7cddfSDavid du Colombier 	    (~(GB_COLORS_ALL | GB_ALPHA_ALL | GB_PACKING_ALL |
10867dd7cddfSDavid du Colombier 	       GB_RETURN_ALL | GB_ALIGN_ALL | GB_OFFSET_ALL | GB_RASTER_ALL) |
10877dd7cddfSDavid du Colombier 	     GB_COLORS_NATIVE | GB_ALPHA_NONE | GB_PACKING_CHUNKY |
10887dd7cddfSDavid du Colombier 	     /* Try for a pointer return the first time. */
10897dd7cddfSDavid du Colombier 	     GB_RETURN_POINTER |
10907dd7cddfSDavid du Colombier 	     GB_ALIGN_STANDARD |
10917dd7cddfSDavid du Colombier 	     (GB_OFFSET_0 | GB_OFFSET_ANY) |
10927dd7cddfSDavid du Colombier 	     (GB_RASTER_STANDARD | GB_RASTER_ANY));
10937dd7cddfSDavid du Colombier 	plane_params.raster = gx_device_raster(plane_dev, true);
10947dd7cddfSDavid du Colombier 	code = dev_proc(plane_dev, get_bits_rectangle)
10957dd7cddfSDavid du Colombier 	    (plane_dev, prect, &plane_params, unread);
10967dd7cddfSDavid du Colombier 	if (code >= 0) {
10977dd7cddfSDavid du Colombier 	    /* Success, expand the plane into pixels. */
10987dd7cddfSDavid du Colombier 	    source.data.read = plane_params.data[0];
10997dd7cddfSDavid du Colombier 	    source.raster = plane_params.raster;
11007dd7cddfSDavid du Colombier 	    source.x = params->x_offset;
11017dd7cddfSDavid du Colombier 	    code = bits_expand_plane(&dest, &source, edev->plane.shift,
11027dd7cddfSDavid du Colombier 				     prect->q.x - prect->p.x,
11037dd7cddfSDavid du Colombier 				     prect->q.y - prect->p.y);
11047dd7cddfSDavid du Colombier 	}
11057dd7cddfSDavid du Colombier 	params->options = (options & ~GB_RETURN_POINTER) | GB_RETURN_COPY;
11067dd7cddfSDavid du Colombier     } else
11077dd7cddfSDavid du Colombier 	return gx_default_get_bits_rectangle(dev, prect, params, unread);
11087dd7cddfSDavid du Colombier     return code;
11097dd7cddfSDavid du Colombier }
1110