xref: /plan9-contrib/sys/src/cmd/gs/src/gdevp14.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /*
2*593dc095SDavid du Colombier   Copyright (C) 2001-2004 artofcode LLC.
33ff48bf5SDavid du Colombier 
4*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
5*593dc095SDavid du Colombier   implied.
63ff48bf5SDavid du Colombier 
7*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
8*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
9*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
103ff48bf5SDavid du Colombier 
11*593dc095SDavid du Colombier   For more information about licensing, please refer to
12*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
13*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
14*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
15*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
163ff48bf5SDavid du Colombier 
173ff48bf5SDavid du Colombier   Author: Raph Levien <raph@artofcode.com>
183ff48bf5SDavid du Colombier */
19*593dc095SDavid du Colombier /* $Id: gdevp14.c,v 1.35 2005/10/10 18:58:18 leonardo Exp $	*/
20*593dc095SDavid du Colombier /* Compositing devices for implementing	PDF 1.4	imaging	model */
213ff48bf5SDavid du Colombier 
223ff48bf5SDavid du Colombier #include "math_.h"
233ff48bf5SDavid du Colombier #include "memory_.h"
243ff48bf5SDavid du Colombier #include "gx.h"
253ff48bf5SDavid du Colombier #include "gserrors.h"
263ff48bf5SDavid du Colombier #include "gscdefs.h"
273ff48bf5SDavid du Colombier #include "gxdevice.h"
283ff48bf5SDavid du Colombier #include "gsdevice.h"
293ff48bf5SDavid du Colombier #include "gsstruct.h"
303ff48bf5SDavid du Colombier #include "gxistate.h"
313ff48bf5SDavid du Colombier #include "gxdcolor.h"
323ff48bf5SDavid du Colombier #include "gxiparam.h"
333ff48bf5SDavid du Colombier #include "gstparam.h"
343ff48bf5SDavid du Colombier #include "gxblend.h"
353ff48bf5SDavid du Colombier #include "gxtext.h"
363ff48bf5SDavid du Colombier #include "gsdfilt.h"
373ff48bf5SDavid du Colombier #include "gsimage.h"
38*593dc095SDavid du Colombier #include "gsrect.h"
393ff48bf5SDavid du Colombier #include "gzstate.h"
403ff48bf5SDavid du Colombier #include "gdevp14.h"
41*593dc095SDavid du Colombier #include "gsovrc.h"
42*593dc095SDavid du Colombier #include "gxcmap.h"
43*593dc095SDavid du Colombier #include "gscolor1.h"
44*593dc095SDavid du Colombier #include "gstrans.h"
45*593dc095SDavid du Colombier #include "gsutil.h"
46*593dc095SDavid du Colombier #include "gxcldev.h"
47*593dc095SDavid du Colombier 
48*593dc095SDavid du Colombier /* #define DUMP_TO_PNG */
49*593dc095SDavid du Colombier 
50*593dc095SDavid du Colombier #ifdef DUMP_TO_PNG
51*593dc095SDavid du Colombier #include "png_.h"
52*593dc095SDavid du Colombier #endif
533ff48bf5SDavid du Colombier 
543ff48bf5SDavid du Colombier # define INCR(v) DO_NOTHING
553ff48bf5SDavid du Colombier 
563ff48bf5SDavid du Colombier /* Buffer stack	data structure */
573ff48bf5SDavid du Colombier 
583ff48bf5SDavid du Colombier #define	PDF14_MAX_PLANES 16
593ff48bf5SDavid du Colombier 
603ff48bf5SDavid du Colombier /* GC procedures for buffer stack */
613ff48bf5SDavid du Colombier 
623ff48bf5SDavid du Colombier private
633ff48bf5SDavid du Colombier ENUM_PTRS_WITH(pdf14_buf_enum_ptrs, pdf14_buf *buf)
643ff48bf5SDavid du Colombier     return 0;
653ff48bf5SDavid du Colombier     case 0: return ENUM_OBJ(buf->saved);
663ff48bf5SDavid du Colombier     case 1: return ENUM_OBJ(buf->data);
67*593dc095SDavid du Colombier     case 2: return ENUM_OBJ(buf->transfer_fn);
683ff48bf5SDavid du Colombier ENUM_PTRS_END
693ff48bf5SDavid du Colombier 
703ff48bf5SDavid du Colombier private
RELOC_PTRS_WITH(pdf14_buf_reloc_ptrs,pdf14_buf * buf)713ff48bf5SDavid du Colombier RELOC_PTRS_WITH(pdf14_buf_reloc_ptrs, pdf14_buf	*buf)
723ff48bf5SDavid du Colombier {
733ff48bf5SDavid du Colombier     RELOC_VAR(buf->saved);
743ff48bf5SDavid du Colombier     RELOC_VAR(buf->data);
75*593dc095SDavid du Colombier     RELOC_VAR(buf->transfer_fn);
763ff48bf5SDavid du Colombier }
773ff48bf5SDavid du Colombier RELOC_PTRS_END
783ff48bf5SDavid du Colombier 
793ff48bf5SDavid du Colombier gs_private_st_composite(st_pdf14_buf, pdf14_buf, "pdf14_buf",
803ff48bf5SDavid du Colombier 			pdf14_buf_enum_ptrs, pdf14_buf_reloc_ptrs);
813ff48bf5SDavid du Colombier 
82*593dc095SDavid du Colombier gs_private_st_ptrs2(st_pdf14_ctx, pdf14_ctx, "pdf14_ctx",
833ff48bf5SDavid du Colombier 		    pdf14_ctx_enum_ptrs, pdf14_ctx_reloc_ptrs,
84*593dc095SDavid du Colombier 		    stack, maskbuf);
853ff48bf5SDavid du Colombier 
863ff48bf5SDavid du Colombier /* ------ The device descriptors ------	*/
873ff48bf5SDavid du Colombier 
883ff48bf5SDavid du Colombier /*
893ff48bf5SDavid du Colombier  * Default X and Y resolution.
903ff48bf5SDavid du Colombier  */
913ff48bf5SDavid du Colombier #define	X_DPI 72
923ff48bf5SDavid du Colombier #define	Y_DPI 72
933ff48bf5SDavid du Colombier 
943ff48bf5SDavid du Colombier private	int pdf14_open(gx_device * pdev);
953ff48bf5SDavid du Colombier private	dev_proc_close_device(pdf14_close);
963ff48bf5SDavid du Colombier private	int pdf14_output_page(gx_device	* pdev,	int num_copies,	int flush);
97*593dc095SDavid du Colombier private	dev_proc_put_params(pdf14_put_params);
98*593dc095SDavid du Colombier private	dev_proc_encode_color(pdf14_encode_color);
99*593dc095SDavid du Colombier private	dev_proc_decode_color(pdf14_decode_color);
1003ff48bf5SDavid du Colombier private	dev_proc_fill_rectangle(pdf14_fill_rectangle);
101*593dc095SDavid du Colombier private	dev_proc_fill_rectangle(pdf14_mark_fill_rectangle);
102*593dc095SDavid du Colombier private	dev_proc_fill_rectangle(pdf14_mark_fill_rectangle_ko_simple);
1033ff48bf5SDavid du Colombier private	dev_proc_fill_path(pdf14_fill_path);
1043ff48bf5SDavid du Colombier private	dev_proc_stroke_path(pdf14_stroke_path);
1053ff48bf5SDavid du Colombier private	dev_proc_begin_typed_image(pdf14_begin_typed_image);
1063ff48bf5SDavid du Colombier private	dev_proc_text_begin(pdf14_text_begin);
107*593dc095SDavid du Colombier private	dev_proc_create_compositor(pdf14_create_compositor);
108*593dc095SDavid du Colombier private	dev_proc_create_compositor(pdf14_forward_create_compositor);
1093ff48bf5SDavid du Colombier private	dev_proc_begin_transparency_group(pdf14_begin_transparency_group);
1103ff48bf5SDavid du Colombier private	dev_proc_end_transparency_group(pdf14_end_transparency_group);
111*593dc095SDavid du Colombier private	dev_proc_begin_transparency_mask(pdf14_begin_transparency_mask);
112*593dc095SDavid du Colombier private	dev_proc_end_transparency_mask(pdf14_end_transparency_mask);
1133ff48bf5SDavid du Colombier 
114*593dc095SDavid du Colombier private	const gx_color_map_procs *
115*593dc095SDavid du Colombier     pdf14_get_cmap_procs(const gs_imager_state *, const gx_device *);
116*593dc095SDavid du Colombier 
117*593dc095SDavid du Colombier #define	XSIZE (int)(8.5	* X_DPI)	/* 8.5 x 11 inch page, by default */
118*593dc095SDavid du Colombier #define	YSIZE (int)(11 * Y_DPI)
1193ff48bf5SDavid du Colombier 
1203ff48bf5SDavid du Colombier /* 24-bit color. */
1213ff48bf5SDavid du Colombier 
122*593dc095SDavid du Colombier #define	pdf14_procs(get_color_mapping_procs, get_color_comp_index) \
123*593dc095SDavid du Colombier {\
124*593dc095SDavid du Colombier 	pdf14_open,			/* open */\
125*593dc095SDavid du Colombier 	NULL,				/* get_initial_matrix */\
126*593dc095SDavid du Colombier 	NULL,				/* sync_output */\
127*593dc095SDavid du Colombier 	pdf14_output_page,		/* output_page */\
128*593dc095SDavid du Colombier 	pdf14_close,			/* close */\
129*593dc095SDavid du Colombier 	pdf14_encode_color,		/* rgb_map_rgb_color */\
130*593dc095SDavid du Colombier 	pdf14_decode_color,		/* gx_default_rgb_map_color_rgb */\
131*593dc095SDavid du Colombier 	pdf14_fill_rectangle,		/* fill_rectangle */\
132*593dc095SDavid du Colombier 	NULL,				/* tile_rectangle */\
133*593dc095SDavid du Colombier 	NULL,				/* copy_mono */\
134*593dc095SDavid du Colombier 	NULL,				/* copy_color */\
135*593dc095SDavid du Colombier 	NULL,				/* draw_line */\
136*593dc095SDavid du Colombier 	NULL,				/* get_bits */\
137*593dc095SDavid du Colombier 	NULL,				/* get_params */\
138*593dc095SDavid du Colombier 	pdf14_put_params,		/* put_params */\
139*593dc095SDavid du Colombier 	NULL,				/* map_cmyk_color */\
140*593dc095SDavid du Colombier 	NULL,				/* get_xfont_procs */\
141*593dc095SDavid du Colombier 	NULL,				/* get_xfont_device */\
142*593dc095SDavid du Colombier 	NULL,				/* map_rgb_alpha_color */\
143*593dc095SDavid du Colombier 	NULL,				/* get_page_device */\
144*593dc095SDavid du Colombier 	NULL,				/* get_alpha_bits */\
145*593dc095SDavid du Colombier 	NULL,				/* copy_alpha */\
146*593dc095SDavid du Colombier 	NULL,				/* get_band */\
147*593dc095SDavid du Colombier 	NULL,				/* copy_rop */\
148*593dc095SDavid du Colombier 	pdf14_fill_path,		/* fill_path */\
149*593dc095SDavid du Colombier 	pdf14_stroke_path,		/* stroke_path */\
150*593dc095SDavid du Colombier 	NULL,				/* fill_mask */\
151*593dc095SDavid du Colombier 	NULL,				/* fill_trapezoid */\
152*593dc095SDavid du Colombier 	NULL,				/* fill_parallelogram */\
153*593dc095SDavid du Colombier 	NULL,				/* fill_triangle */\
154*593dc095SDavid du Colombier 	NULL,				/* draw_thin_line */\
155*593dc095SDavid du Colombier 	NULL,				/* begin_image */\
156*593dc095SDavid du Colombier 	NULL,				/* image_data */\
157*593dc095SDavid du Colombier 	NULL,				/* end_image */\
158*593dc095SDavid du Colombier 	NULL,				/* strip_tile_rectangle */\
159*593dc095SDavid du Colombier 	NULL,				/* strip_copy_rop, */\
160*593dc095SDavid du Colombier 	NULL,				/* get_clipping_box */\
161*593dc095SDavid du Colombier 	pdf14_begin_typed_image,	/* begin_typed_image */\
162*593dc095SDavid du Colombier 	NULL,				/* get_bits_rectangle */\
163*593dc095SDavid du Colombier 	NULL,				/* map_color_rgb_alpha */\
164*593dc095SDavid du Colombier 	pdf14_create_compositor,	/* create_compositor */\
165*593dc095SDavid du Colombier 	NULL,				/* get_hardware_params */\
166*593dc095SDavid du Colombier 	pdf14_text_begin,		/* text_begin */\
167*593dc095SDavid du Colombier 	NULL,				/* finish_copydevice */\
168*593dc095SDavid du Colombier 	pdf14_begin_transparency_group,\
169*593dc095SDavid du Colombier 	pdf14_end_transparency_group,\
170*593dc095SDavid du Colombier 	pdf14_begin_transparency_mask,\
171*593dc095SDavid du Colombier 	pdf14_end_transparency_mask,\
172*593dc095SDavid du Colombier 	NULL,				/* discard_transparency_layer */\
173*593dc095SDavid du Colombier 	get_color_mapping_procs,	/* get_color_mapping_procs */\
174*593dc095SDavid du Colombier 	get_color_comp_index,		/* get_color_comp_index */\
175*593dc095SDavid du Colombier 	pdf14_encode_color,		/* encode_color */\
176*593dc095SDavid du Colombier 	pdf14_decode_color		/* decode_color */\
177*593dc095SDavid du Colombier }
1783ff48bf5SDavid du Colombier 
179*593dc095SDavid du Colombier private	const gx_device_procs pdf14_Gray_procs =
180*593dc095SDavid du Colombier 	pdf14_procs(gx_default_DevGray_get_color_mapping_procs,
181*593dc095SDavid du Colombier 			gx_default_DevGray_get_color_comp_index);
1823ff48bf5SDavid du Colombier 
183*593dc095SDavid du Colombier private	const gx_device_procs pdf14_RGB_procs =
184*593dc095SDavid du Colombier 	pdf14_procs(gx_default_DevRGB_get_color_mapping_procs,
185*593dc095SDavid du Colombier 			gx_default_DevRGB_get_color_comp_index);
1863ff48bf5SDavid du Colombier 
187*593dc095SDavid du Colombier private	const gx_device_procs pdf14_CMYK_procs =
188*593dc095SDavid du Colombier 	pdf14_procs(gx_default_DevCMYK_get_color_mapping_procs,
189*593dc095SDavid du Colombier 			gx_default_DevCMYK_get_color_comp_index);
1903ff48bf5SDavid du Colombier 
1913ff48bf5SDavid du Colombier gs_private_st_composite_use_final(st_pdf14_device, pdf14_device, "pdf14_device",
1923ff48bf5SDavid du Colombier 				  pdf14_device_enum_ptrs, pdf14_device_reloc_ptrs,
1933ff48bf5SDavid du Colombier 			  gx_device_finalize);
1943ff48bf5SDavid du Colombier 
195*593dc095SDavid du Colombier const pdf14_device gs_pdf14_Gray_device	= {
196*593dc095SDavid du Colombier     std_device_color_stype_body(pdf14_device, &pdf14_Gray_procs, "pdf14gray",
1973ff48bf5SDavid du Colombier 				&st_pdf14_device,
198*593dc095SDavid du Colombier 				XSIZE, YSIZE, X_DPI, Y_DPI, 8, 255, 256),
199*593dc095SDavid du Colombier     { 0 }
200*593dc095SDavid du Colombier };
201*593dc095SDavid du Colombier 
202*593dc095SDavid du Colombier const pdf14_device gs_pdf14_RGB_device = {
203*593dc095SDavid du Colombier     std_device_color_stype_body(pdf14_device, &pdf14_RGB_procs, "pdf14RGB",
204*593dc095SDavid du Colombier 				&st_pdf14_device,
205*593dc095SDavid du Colombier 				XSIZE, YSIZE, X_DPI, Y_DPI, 24, 255, 256),
206*593dc095SDavid du Colombier     { 0 }
207*593dc095SDavid du Colombier };
208*593dc095SDavid du Colombier 
209*593dc095SDavid du Colombier const pdf14_device gs_pdf14_CMYK_device	= {
210*593dc095SDavid du Colombier     std_device_std_color_full_body_type(pdf14_device, &pdf14_CMYK_procs,
211*593dc095SDavid du Colombier 	"PDF14cmyk", &st_pdf14_device, XSIZE, YSIZE, X_DPI, Y_DPI, 32,
212*593dc095SDavid du Colombier 	0, 0, 0, 0, 0, 0),
2133ff48bf5SDavid du Colombier     { 0 }
2143ff48bf5SDavid du Colombier };
2153ff48bf5SDavid du Colombier 
2163ff48bf5SDavid du Colombier /* GC procedures */
2173ff48bf5SDavid du Colombier private
2183ff48bf5SDavid du Colombier ENUM_PTRS_WITH(pdf14_device_enum_ptrs, pdf14_device *pdev) return 0;
2193ff48bf5SDavid du Colombier case 0:	return ENUM_OBJ(pdev->ctx);
2203ff48bf5SDavid du Colombier case 1:	ENUM_RETURN(gx_device_enum_ptr(pdev->target));
2213ff48bf5SDavid du Colombier ENUM_PTRS_END
RELOC_PTRS_WITH(pdf14_device_reloc_ptrs,pdf14_device * pdev)2223ff48bf5SDavid du Colombier private	RELOC_PTRS_WITH(pdf14_device_reloc_ptrs, pdf14_device *pdev)
2233ff48bf5SDavid du Colombier {
2243ff48bf5SDavid du Colombier     RELOC_VAR(pdev->ctx);
2253ff48bf5SDavid du Colombier     pdev->target = gx_device_reloc_ptr(pdev->target, gcst);
2263ff48bf5SDavid du Colombier }
2273ff48bf5SDavid du Colombier RELOC_PTRS_END
2283ff48bf5SDavid du Colombier 
2293ff48bf5SDavid du Colombier /* ------ Private definitions ------ */
2303ff48bf5SDavid du Colombier 
2313ff48bf5SDavid du Colombier /**
2323ff48bf5SDavid du Colombier  * pdf14_buf_new: Allocate a new PDF 1.4 buffer.
2333ff48bf5SDavid du Colombier  * @n_chan: Number of pixel channels including alpha.
2343ff48bf5SDavid du Colombier  *
2353ff48bf5SDavid du Colombier  * Return value: Newly allocated buffer, or NULL on failure.
2363ff48bf5SDavid du Colombier  **/
2373ff48bf5SDavid du Colombier private	pdf14_buf *
pdf14_buf_new(gs_int_rect * rect,bool has_alpha_g,bool has_shape,int n_chan,gs_memory_t * memory)2383ff48bf5SDavid du Colombier pdf14_buf_new(gs_int_rect *rect, bool has_alpha_g, bool	has_shape,
2393ff48bf5SDavid du Colombier 	       int n_chan,
2403ff48bf5SDavid du Colombier 	       gs_memory_t *memory)
2413ff48bf5SDavid du Colombier {
2423ff48bf5SDavid du Colombier     pdf14_buf *result;
2433ff48bf5SDavid du Colombier     int rowstride = (rect->q.x - rect->p.x + 3) & -4;
244*593dc095SDavid du Colombier     int height = (rect->q.y - rect->p.y);
2453ff48bf5SDavid du Colombier     int n_planes = n_chan + (has_shape ? 1 : 0) + (has_alpha_g ? 1 : 0);
246*593dc095SDavid du Colombier     int planestride;
247*593dc095SDavid du Colombier     double dsize = (((double) rowstride) * height) * n_planes;
248*593dc095SDavid du Colombier 
249*593dc095SDavid du Colombier     if (dsize > (double)max_uint)
250*593dc095SDavid du Colombier       return NULL;
2513ff48bf5SDavid du Colombier 
2523ff48bf5SDavid du Colombier     result = gs_alloc_struct(memory, pdf14_buf, &st_pdf14_buf,
2533ff48bf5SDavid du Colombier 			     "pdf14_buf_new");
2543ff48bf5SDavid du Colombier     if (result == NULL)
2553ff48bf5SDavid du Colombier 	return result;
2563ff48bf5SDavid du Colombier 
2573ff48bf5SDavid du Colombier     result->isolated = false;
2583ff48bf5SDavid du Colombier     result->knockout = false;
2593ff48bf5SDavid du Colombier     result->has_alpha_g = has_alpha_g;
2603ff48bf5SDavid du Colombier     result->has_shape = has_shape;
2613ff48bf5SDavid du Colombier     result->rect = *rect;
2623ff48bf5SDavid du Colombier     result->n_chan = n_chan;
2633ff48bf5SDavid du Colombier     result->n_planes = n_planes;
2643ff48bf5SDavid du Colombier     result->rowstride = rowstride;
265*593dc095SDavid du Colombier     result->transfer_fn = NULL;
266*593dc095SDavid du Colombier 
267*593dc095SDavid du Colombier     if (height < 0) {
268*593dc095SDavid du Colombier 	/* Empty clipping - will skip all drawings. */
269*593dc095SDavid du Colombier 	result->planestride = 0;
270*593dc095SDavid du Colombier 	result->data = 0;
271*593dc095SDavid du Colombier     } else {
272*593dc095SDavid du Colombier 	planestride = rowstride * height;
2733ff48bf5SDavid du Colombier 	result->planestride = planestride;
2743ff48bf5SDavid du Colombier 	result->data = gs_alloc_bytes(memory, planestride * n_planes,
2753ff48bf5SDavid du Colombier 					"pdf14_buf_new");
2763ff48bf5SDavid du Colombier 	if (result->data == NULL) {
2773ff48bf5SDavid du Colombier 	    gs_free_object(memory, result, "pdf_buf_new");
2783ff48bf5SDavid du Colombier 	    return NULL;
2793ff48bf5SDavid du Colombier 	}
2803ff48bf5SDavid du Colombier 	if (has_alpha_g) {
2813ff48bf5SDavid du Colombier 	    int alpha_g_plane = n_chan + (has_shape ? 1 : 0);
2823ff48bf5SDavid du Colombier 	    memset (result->data + alpha_g_plane * planestride, 0, planestride);
2833ff48bf5SDavid du Colombier 	}
284*593dc095SDavid du Colombier     }
285*593dc095SDavid du Colombier     result->bbox.p.x = max_int;
286*593dc095SDavid du Colombier     result->bbox.p.y = max_int;
287*593dc095SDavid du Colombier     result->bbox.q.x = min_int;
288*593dc095SDavid du Colombier     result->bbox.q.y = min_int;
2893ff48bf5SDavid du Colombier     return result;
2903ff48bf5SDavid du Colombier }
2913ff48bf5SDavid du Colombier 
2923ff48bf5SDavid du Colombier private	void
pdf14_buf_free(pdf14_buf * buf,gs_memory_t * memory)2933ff48bf5SDavid du Colombier pdf14_buf_free(pdf14_buf *buf, gs_memory_t *memory)
2943ff48bf5SDavid du Colombier {
295*593dc095SDavid du Colombier     gs_free_object(memory, buf->transfer_fn, "pdf14_buf_free");
2963ff48bf5SDavid du Colombier     gs_free_object(memory, buf->data, "pdf14_buf_free");
2973ff48bf5SDavid du Colombier     gs_free_object(memory, buf, "pdf14_buf_free");
2983ff48bf5SDavid du Colombier }
2993ff48bf5SDavid du Colombier 
3003ff48bf5SDavid du Colombier private	pdf14_ctx *
pdf14_ctx_new(gs_int_rect * rect,int n_chan,bool additive,gs_memory_t * memory)301*593dc095SDavid du Colombier pdf14_ctx_new(gs_int_rect *rect, int n_chan, bool additive, gs_memory_t	*memory)
3023ff48bf5SDavid du Colombier {
3033ff48bf5SDavid du Colombier     pdf14_ctx *result;
3043ff48bf5SDavid du Colombier     pdf14_buf *buf;
3053ff48bf5SDavid du Colombier 
3063ff48bf5SDavid du Colombier     result = gs_alloc_struct(memory, pdf14_ctx, &st_pdf14_ctx,
3073ff48bf5SDavid du Colombier 			     "pdf14_ctx_new");
308*593dc095SDavid du Colombier     if (result == NULL)
309*593dc095SDavid du Colombier 	return result;
3103ff48bf5SDavid du Colombier 
3113ff48bf5SDavid du Colombier     buf = pdf14_buf_new(rect, false, false, n_chan, memory);
3123ff48bf5SDavid du Colombier     if (buf == NULL) {
3133ff48bf5SDavid du Colombier 	gs_free_object(memory, result, "pdf14_ctx_new");
3143ff48bf5SDavid du Colombier 	return NULL;
3153ff48bf5SDavid du Colombier     }
316*593dc095SDavid du Colombier     if_debug3('v', "[v]base buf: %d x %d, %d channels\n",
317*593dc095SDavid du Colombier 	      buf->rect.q.x, buf->rect.q.y, buf->n_chan);
318*593dc095SDavid du Colombier     memset(buf->data, 0, buf->planestride * buf->n_planes);
3193ff48bf5SDavid du Colombier     buf->saved = NULL;
3203ff48bf5SDavid du Colombier     result->stack = buf;
321*593dc095SDavid du Colombier     result->maskbuf = NULL;
3223ff48bf5SDavid du Colombier     result->n_chan = n_chan;
3233ff48bf5SDavid du Colombier     result->memory = memory;
3243ff48bf5SDavid du Colombier     result->rect = *rect;
325*593dc095SDavid du Colombier     result->additive = additive;
3263ff48bf5SDavid du Colombier     return result;
3273ff48bf5SDavid du Colombier }
3283ff48bf5SDavid du Colombier 
3293ff48bf5SDavid du Colombier private	void
pdf14_ctx_free(pdf14_ctx * ctx)3303ff48bf5SDavid du Colombier pdf14_ctx_free(pdf14_ctx *ctx)
3313ff48bf5SDavid du Colombier {
3323ff48bf5SDavid du Colombier     pdf14_buf *buf, *next;
3333ff48bf5SDavid du Colombier 
3343ff48bf5SDavid du Colombier     for (buf = ctx->stack; buf != NULL; buf = next) {
3353ff48bf5SDavid du Colombier 	next = buf->saved;
3363ff48bf5SDavid du Colombier 	pdf14_buf_free(buf, ctx->memory);
3373ff48bf5SDavid du Colombier     }
3383ff48bf5SDavid du Colombier     gs_free_object (ctx->memory, ctx, "pdf14_ctx_free");
3393ff48bf5SDavid du Colombier }
3403ff48bf5SDavid du Colombier 
3413ff48bf5SDavid du Colombier /**
3423ff48bf5SDavid du Colombier  * pdf14_find_backdrop_buf: Find backdrop buffer.
3433ff48bf5SDavid du Colombier  *
3443ff48bf5SDavid du Colombier  * Return value: Backdrop buffer for current group operation, or NULL
3453ff48bf5SDavid du Colombier  * if backdrop is fully transparent.
3463ff48bf5SDavid du Colombier  **/
3473ff48bf5SDavid du Colombier private	pdf14_buf *
pdf14_find_backdrop_buf(pdf14_ctx * ctx)3483ff48bf5SDavid du Colombier pdf14_find_backdrop_buf(pdf14_ctx *ctx)
3493ff48bf5SDavid du Colombier {
3503ff48bf5SDavid du Colombier     pdf14_buf *buf = ctx->stack;
3513ff48bf5SDavid du Colombier 
3523ff48bf5SDavid du Colombier     while (buf != NULL) {
3533ff48bf5SDavid du Colombier 	if (buf->isolated) return NULL;
3543ff48bf5SDavid du Colombier 	if (!buf->knockout) return buf->saved;
3553ff48bf5SDavid du Colombier 	buf = buf->saved;
3563ff48bf5SDavid du Colombier     }
3573ff48bf5SDavid du Colombier     /* this really shouldn't happen, as bottom-most buf should be
3583ff48bf5SDavid du Colombier        non-knockout */
3593ff48bf5SDavid du Colombier     return NULL;
3603ff48bf5SDavid du Colombier }
3613ff48bf5SDavid du Colombier 
3623ff48bf5SDavid du Colombier private	int
pdf14_push_transparency_group(pdf14_ctx * ctx,gs_int_rect * rect,bool isolated,bool knockout,byte alpha,byte shape,gs_blend_mode_t blend_mode)3633ff48bf5SDavid du Colombier pdf14_push_transparency_group(pdf14_ctx	*ctx, gs_int_rect *rect,
3643ff48bf5SDavid du Colombier 			      bool isolated, bool knockout,
3653ff48bf5SDavid du Colombier 			      byte alpha, byte shape,
3663ff48bf5SDavid du Colombier 			      gs_blend_mode_t blend_mode)
3673ff48bf5SDavid du Colombier {
3683ff48bf5SDavid du Colombier     pdf14_buf *tos = ctx->stack;
3693ff48bf5SDavid du Colombier     pdf14_buf *buf, *backdrop;
3703ff48bf5SDavid du Colombier     bool has_shape;
3713ff48bf5SDavid du Colombier 
3723ff48bf5SDavid du Colombier     /* todo: fix this hack, which makes all knockout groups isolated.
3733ff48bf5SDavid du Colombier        For the vast majority of files, there won't be any visible
3743ff48bf5SDavid du Colombier        effects, but it still isn't correct. The pixel compositing code
3753ff48bf5SDavid du Colombier        for non-isolated knockout groups gets pretty hairy, which is
3763ff48bf5SDavid du Colombier        why this is here. */
377*593dc095SDavid du Colombier     if (knockout)
378*593dc095SDavid du Colombier 	isolated = true;
3793ff48bf5SDavid du Colombier 
3803ff48bf5SDavid du Colombier     has_shape = tos->has_shape || tos->knockout;
3813ff48bf5SDavid du Colombier 
3823ff48bf5SDavid du Colombier     buf = pdf14_buf_new(rect, !isolated, has_shape, ctx->n_chan, ctx->memory);
383*593dc095SDavid du Colombier     if_debug3('v', "[v]push buf: %d x %d, %d channels\n", buf->rect.p.x, buf->rect.p.y, buf->n_chan);
3843ff48bf5SDavid du Colombier     if (buf == NULL)
3853ff48bf5SDavid du Colombier 	return_error(gs_error_VMerror);
3863ff48bf5SDavid du Colombier     buf->isolated = isolated;
3873ff48bf5SDavid du Colombier     buf->knockout = knockout;
3883ff48bf5SDavid du Colombier     buf->alpha = alpha;
3893ff48bf5SDavid du Colombier     buf->shape = shape;
3903ff48bf5SDavid du Colombier     buf->blend_mode = blend_mode;
3913ff48bf5SDavid du Colombier 
3923ff48bf5SDavid du Colombier     buf->saved = tos;
3933ff48bf5SDavid du Colombier     ctx->stack = buf;
3943ff48bf5SDavid du Colombier 
3953ff48bf5SDavid du Colombier     backdrop = pdf14_find_backdrop_buf(ctx);
3963ff48bf5SDavid du Colombier     if (backdrop == NULL) {
3973ff48bf5SDavid du Colombier 	memset(buf->data, 0, buf->planestride * (buf->n_chan +
3983ff48bf5SDavid du Colombier 						 (buf->has_shape ? 1 : 0)));
3993ff48bf5SDavid du Colombier     } else {
4003ff48bf5SDavid du Colombier 	/* make copy of backdrop for compositing */
4013ff48bf5SDavid du Colombier 	byte *buf_plane = buf->data;
4023ff48bf5SDavid du Colombier 	byte *tos_plane = tos->data + buf->rect.p.x - tos->rect.p.x +
4033ff48bf5SDavid du Colombier 	    (buf->rect.p.y - tos->rect.p.y) * tos->rowstride;
4043ff48bf5SDavid du Colombier 	int width = buf->rect.q.x - buf->rect.p.x;
4053ff48bf5SDavid du Colombier 	int y0 = buf->rect.p.y;
4063ff48bf5SDavid du Colombier 	int y1 = buf->rect.q.y;
4073ff48bf5SDavid du Colombier 	int i;
4083ff48bf5SDavid du Colombier 	int n_chan_copy = buf->n_chan + (tos->has_shape ? 1 : 0);
4093ff48bf5SDavid du Colombier 
4103ff48bf5SDavid du Colombier 	for (i = 0; i < n_chan_copy; i++) {
4113ff48bf5SDavid du Colombier 	    byte *buf_ptr = buf_plane;
4123ff48bf5SDavid du Colombier 	    byte *tos_ptr = tos_plane;
4133ff48bf5SDavid du Colombier 	    int y;
4143ff48bf5SDavid du Colombier 
4153ff48bf5SDavid du Colombier 	    for (y = y0; y < y1; ++y) {
4163ff48bf5SDavid du Colombier 		memcpy (buf_ptr, tos_ptr, width);
4173ff48bf5SDavid du Colombier 		buf_ptr += buf->rowstride;
4183ff48bf5SDavid du Colombier 		tos_ptr += tos->rowstride;
4193ff48bf5SDavid du Colombier 	    }
4203ff48bf5SDavid du Colombier 	    buf_plane += buf->planestride;
4213ff48bf5SDavid du Colombier 	    tos_plane += tos->planestride;
4223ff48bf5SDavid du Colombier 	}
4233ff48bf5SDavid du Colombier 	if (has_shape && !tos->has_shape)
4243ff48bf5SDavid du Colombier 	    memset (buf_plane, 0, buf->planestride);
4253ff48bf5SDavid du Colombier     }
4263ff48bf5SDavid du Colombier 
4273ff48bf5SDavid du Colombier     return 0;
4283ff48bf5SDavid du Colombier }
4293ff48bf5SDavid du Colombier 
4303ff48bf5SDavid du Colombier private	int
pdf14_pop_transparency_group(pdf14_ctx * ctx)4313ff48bf5SDavid du Colombier pdf14_pop_transparency_group(pdf14_ctx *ctx)
4323ff48bf5SDavid du Colombier {
4333ff48bf5SDavid du Colombier     pdf14_buf *tos = ctx->stack;
4343ff48bf5SDavid du Colombier     pdf14_buf *nos = tos->saved;
435*593dc095SDavid du Colombier     pdf14_buf *maskbuf = ctx->maskbuf;
436*593dc095SDavid du Colombier     int y0 = tos->rect.p.y;
437*593dc095SDavid du Colombier     int y1 = tos->rect.q.y;
438*593dc095SDavid du Colombier     if (y0 < y1) {
439*593dc095SDavid du Colombier 	int x0 = tos->rect.p.x;
440*593dc095SDavid du Colombier 	int x1 = tos->rect.q.x;
4413ff48bf5SDavid du Colombier 	int n_chan = ctx->n_chan;
442*593dc095SDavid du Colombier 	int num_comp = n_chan - 1;
4433ff48bf5SDavid du Colombier 	byte alpha = tos->alpha;
4443ff48bf5SDavid du Colombier 	byte shape = tos->shape;
4453ff48bf5SDavid du Colombier 	byte blend_mode = tos->blend_mode;
4463ff48bf5SDavid du Colombier 	byte *tos_ptr = tos->data;
4473ff48bf5SDavid du Colombier 	byte *nos_ptr = nos->data + x0 - nos->rect.p.x +
4483ff48bf5SDavid du Colombier 	    (y0 - nos->rect.p.y) * nos->rowstride;
449*593dc095SDavid du Colombier 	byte *mask_ptr = NULL;
4503ff48bf5SDavid du Colombier 	int tos_planestride = tos->planestride;
4513ff48bf5SDavid du Colombier 	int nos_planestride = nos->planestride;
452*593dc095SDavid du Colombier 	int mask_planestride = 0x0badf00d; /* Quiet compiler. */
453*593dc095SDavid du Colombier 	byte mask_bg_alpha = 0; /* Quiet compiler. */
4543ff48bf5SDavid du Colombier 	int width = x1 - x0;
4553ff48bf5SDavid du Colombier 	int x, y;
4563ff48bf5SDavid du Colombier 	int i;
4573ff48bf5SDavid du Colombier 	byte tos_pixel[PDF14_MAX_PLANES];
4583ff48bf5SDavid du Colombier 	byte nos_pixel[PDF14_MAX_PLANES];
4593ff48bf5SDavid du Colombier 	bool tos_isolated = tos->isolated;
4603ff48bf5SDavid du Colombier 	bool nos_knockout = nos->knockout;
4613ff48bf5SDavid du Colombier 	byte *nos_alpha_g_ptr;
4623ff48bf5SDavid du Colombier 	int tos_shape_offset = n_chan * tos_planestride;
4633ff48bf5SDavid du Colombier 	int tos_alpha_g_offset = tos_shape_offset +
4643ff48bf5SDavid du Colombier 	(tos->has_shape ? tos_planestride : 0);
4653ff48bf5SDavid du Colombier 	int nos_shape_offset = n_chan * nos_planestride;
4663ff48bf5SDavid du Colombier 	bool nos_has_shape = nos->has_shape;
467*593dc095SDavid du Colombier 	byte *mask_tr_fn = NULL; /* Quiet compiler. */
468*593dc095SDavid du Colombier 	bool additive = ctx->additive;
4693ff48bf5SDavid du Colombier 
4703ff48bf5SDavid du Colombier 	if (nos == NULL)
4713ff48bf5SDavid du Colombier 	    return_error(gs_error_rangecheck);
4723ff48bf5SDavid du Colombier 
473*593dc095SDavid du Colombier 	rect_merge(nos->bbox, tos->bbox);
4743ff48bf5SDavid du Colombier 
475*593dc095SDavid du Colombier 	if_debug6('v', "pdf14_pop_transparency_group y0 = %d, y1 = %d, w = %d, alpha = %d, shape = %d, bm = %d\n",
476*593dc095SDavid du Colombier 			    y0, y1, width, alpha, shape, blend_mode);
4773ff48bf5SDavid du Colombier 	if (nos->has_alpha_g)
4783ff48bf5SDavid du Colombier 	    nos_alpha_g_ptr = nos_ptr + n_chan * nos_planestride;
4793ff48bf5SDavid du Colombier 	else
4803ff48bf5SDavid du Colombier 	    nos_alpha_g_ptr = NULL;
4813ff48bf5SDavid du Colombier 
482*593dc095SDavid du Colombier 	if (maskbuf != NULL) {
483*593dc095SDavid du Colombier 	    mask_ptr = maskbuf->data + x0 - maskbuf->rect.p.x +
484*593dc095SDavid du Colombier 		    (y0 - maskbuf->rect.p.y) * maskbuf->rowstride;
485*593dc095SDavid du Colombier 	    mask_planestride = maskbuf->planestride;
486*593dc095SDavid du Colombier 	    mask_bg_alpha = maskbuf->alpha;
487*593dc095SDavid du Colombier 	    mask_tr_fn = maskbuf->transfer_fn;
488*593dc095SDavid du Colombier 	}
489*593dc095SDavid du Colombier 
4903ff48bf5SDavid du Colombier 	for (y = y0; y < y1; ++y) {
4913ff48bf5SDavid du Colombier 	    for (x = 0; x < width; ++x) {
492*593dc095SDavid du Colombier 		byte pix_alpha = alpha;
493*593dc095SDavid du Colombier 
494*593dc095SDavid du Colombier 		/* Complement the components for subtractive color spaces */
495*593dc095SDavid du Colombier 		if (additive) {
4963ff48bf5SDavid du Colombier 		    for (i = 0; i < n_chan; ++i) {
4973ff48bf5SDavid du Colombier 			tos_pixel[i] = tos_ptr[x + i * tos_planestride];
4983ff48bf5SDavid du Colombier 			nos_pixel[i] = nos_ptr[x + i * nos_planestride];
4993ff48bf5SDavid du Colombier 		    }
500*593dc095SDavid du Colombier 		} else {
501*593dc095SDavid du Colombier 		    for (i = 0; i < num_comp; ++i) {
502*593dc095SDavid du Colombier 			tos_pixel[i] = 255 - tos_ptr[x + i * tos_planestride];
503*593dc095SDavid du Colombier 			nos_pixel[i] = 255 - nos_ptr[x + i * nos_planestride];
504*593dc095SDavid du Colombier 		    }
505*593dc095SDavid du Colombier 		    tos_pixel[num_comp] = tos_ptr[x + num_comp * tos_planestride];
506*593dc095SDavid du Colombier 		    nos_pixel[num_comp] = nos_ptr[x + num_comp * nos_planestride];
507*593dc095SDavid du Colombier 		}
508*593dc095SDavid du Colombier 
509*593dc095SDavid du Colombier 		if (mask_ptr != NULL) {
510*593dc095SDavid du Colombier 		    int mask_alpha = mask_ptr[x + num_comp * mask_planestride];
511*593dc095SDavid du Colombier 		    int tmp;
512*593dc095SDavid du Colombier 		    byte mask;
513*593dc095SDavid du Colombier 
514*593dc095SDavid du Colombier 			/*
515*593dc095SDavid du Colombier 			* The mask data is really monochrome.  Thus for additive (RGB)
516*593dc095SDavid du Colombier 			* we use the R channel for alpha since R = G = B.  For
517*593dc095SDavid du Colombier 			* subtractive (CMYK) we use the K channel.
518*593dc095SDavid du Colombier 			*/
519*593dc095SDavid du Colombier 		    if (mask_alpha == 255) {
520*593dc095SDavid du Colombier 			/* todo: rgba->mask */
521*593dc095SDavid du Colombier 			mask = additive ? mask_ptr[x]
522*593dc095SDavid du Colombier 					: 255 - mask_ptr[x + 3 * mask_planestride];
523*593dc095SDavid du Colombier 		    } else if (mask_alpha == 0)
524*593dc095SDavid du Colombier 			mask = mask_bg_alpha;
525*593dc095SDavid du Colombier 		    else {
526*593dc095SDavid du Colombier 			int t2 = additive ? mask_ptr[x]
527*593dc095SDavid du Colombier 					: 255 - mask_ptr[x + 3 * mask_planestride];
528*593dc095SDavid du Colombier 
529*593dc095SDavid du Colombier 			t2 = (t2 - mask_bg_alpha) * mask_alpha + 0x80;
530*593dc095SDavid du Colombier 			mask = mask_bg_alpha + ((t2 + (t2 >> 8)) >> 8);
531*593dc095SDavid du Colombier 		    }
532*593dc095SDavid du Colombier 		    mask = mask_tr_fn[mask];
533*593dc095SDavid du Colombier 		    tmp = pix_alpha * mask + 0x80;
534*593dc095SDavid du Colombier 		    pix_alpha = (tmp + (tmp >> 8)) >> 8;
535*593dc095SDavid du Colombier 		}
5363ff48bf5SDavid du Colombier 
5373ff48bf5SDavid du Colombier 		if (nos_knockout) {
5383ff48bf5SDavid du Colombier 		    byte *nos_shape_ptr = nos_has_shape ?
5393ff48bf5SDavid du Colombier 			&nos_ptr[x + nos_shape_offset] : NULL;
5403ff48bf5SDavid du Colombier 		    byte tos_shape = tos_ptr[x + tos_shape_offset];
5413ff48bf5SDavid du Colombier 
5423ff48bf5SDavid du Colombier 		    art_pdf_composite_knockout_isolated_8(nos_pixel,
5433ff48bf5SDavid du Colombier 							nos_shape_ptr,
5443ff48bf5SDavid du Colombier 							tos_pixel,
5453ff48bf5SDavid du Colombier 							n_chan - 1,
5463ff48bf5SDavid du Colombier 							tos_shape,
547*593dc095SDavid du Colombier 							pix_alpha, shape);
5483ff48bf5SDavid du Colombier 		} else if (tos_isolated) {
5493ff48bf5SDavid du Colombier 		    art_pdf_composite_group_8(nos_pixel, nos_alpha_g_ptr,
5503ff48bf5SDavid du Colombier 						tos_pixel,
5513ff48bf5SDavid du Colombier 						n_chan - 1,
552*593dc095SDavid du Colombier 						pix_alpha, blend_mode);
5533ff48bf5SDavid du Colombier 		} else {
5543ff48bf5SDavid du Colombier 		    byte tos_alpha_g = tos_ptr[x + tos_alpha_g_offset];
5553ff48bf5SDavid du Colombier 		    art_pdf_recomposite_group_8(nos_pixel, nos_alpha_g_ptr,
5563ff48bf5SDavid du Colombier 						tos_pixel, tos_alpha_g,
5573ff48bf5SDavid du Colombier 						n_chan - 1,
558*593dc095SDavid du Colombier 						pix_alpha, blend_mode);
5593ff48bf5SDavid du Colombier 		}
5603ff48bf5SDavid du Colombier 		if (nos_has_shape) {
5613ff48bf5SDavid du Colombier 		    nos_ptr[x + nos_shape_offset] =
5623ff48bf5SDavid du Colombier 			art_pdf_union_mul_8 (nos_ptr[x + nos_shape_offset],
5633ff48bf5SDavid du Colombier 						tos_ptr[x + tos_shape_offset],
5643ff48bf5SDavid du Colombier 						shape);
5653ff48bf5SDavid du Colombier 		}
5663ff48bf5SDavid du Colombier 
567*593dc095SDavid du Colombier 		/* Complement the results for subtractive color spaces */
568*593dc095SDavid du Colombier 		if (additive) {
5693ff48bf5SDavid du Colombier 		    for (i = 0; i < n_chan; ++i) {
5703ff48bf5SDavid du Colombier 			nos_ptr[x + i * nos_planestride] = nos_pixel[i];
5713ff48bf5SDavid du Colombier 		    }
572*593dc095SDavid du Colombier 		} else {
573*593dc095SDavid du Colombier 		    for (i = 0; i < num_comp; ++i)
574*593dc095SDavid du Colombier 			nos_ptr[x + i * nos_planestride] = 255 - nos_pixel[i];
575*593dc095SDavid du Colombier 		    nos_ptr[x + num_comp * nos_planestride] = nos_pixel[num_comp];
576*593dc095SDavid du Colombier 		}
5773ff48bf5SDavid du Colombier 		if (nos_alpha_g_ptr != NULL)
5783ff48bf5SDavid du Colombier 		    ++nos_alpha_g_ptr;
5793ff48bf5SDavid du Colombier 	    }
5803ff48bf5SDavid du Colombier 	    tos_ptr += tos->rowstride;
5813ff48bf5SDavid du Colombier 	    nos_ptr += nos->rowstride;
5823ff48bf5SDavid du Colombier 	    if (nos_alpha_g_ptr != NULL)
5833ff48bf5SDavid du Colombier 		nos_alpha_g_ptr += nos->rowstride - width;
584*593dc095SDavid du Colombier 	    if (mask_ptr != NULL)
585*593dc095SDavid du Colombier 		mask_ptr += maskbuf->rowstride;
586*593dc095SDavid du Colombier 	}
5873ff48bf5SDavid du Colombier     }
5883ff48bf5SDavid du Colombier 
5893ff48bf5SDavid du Colombier     ctx->stack = nos;
590*593dc095SDavid du Colombier     if_debug0('v', "[v]pop buf\n");
5913ff48bf5SDavid du Colombier     pdf14_buf_free(tos, ctx->memory);
592*593dc095SDavid du Colombier     if (maskbuf != NULL) {
593*593dc095SDavid du Colombier 	pdf14_buf_free(maskbuf, ctx->memory);
594*593dc095SDavid du Colombier 	ctx->maskbuf = NULL;
595*593dc095SDavid du Colombier     }
596*593dc095SDavid du Colombier     return 0;
597*593dc095SDavid du Colombier }
598*593dc095SDavid du Colombier 
599*593dc095SDavid du Colombier private	int
pdf14_push_transparency_mask(pdf14_ctx * ctx,gs_int_rect * rect,byte bg_alpha,byte * transfer_fn)600*593dc095SDavid du Colombier pdf14_push_transparency_mask(pdf14_ctx *ctx, gs_int_rect *rect,	byte bg_alpha,
601*593dc095SDavid du Colombier 			     byte *transfer_fn)
602*593dc095SDavid du Colombier {
603*593dc095SDavid du Colombier     pdf14_buf *buf;
604*593dc095SDavid du Colombier 
605*593dc095SDavid du Colombier     if_debug0('v', "[v]pdf_push_transparency_mask\n");
606*593dc095SDavid du Colombier     buf = pdf14_buf_new(rect, false, false, ctx->n_chan, ctx->memory);
607*593dc095SDavid du Colombier     if (buf == NULL)
608*593dc095SDavid du Colombier 	return_error(gs_error_VMerror);
609*593dc095SDavid du Colombier 
610*593dc095SDavid du Colombier     /* fill in, but these values aren't really used */
611*593dc095SDavid du Colombier     buf->isolated = true;
612*593dc095SDavid du Colombier     buf->knockout = false;
613*593dc095SDavid du Colombier     buf->alpha = bg_alpha;
614*593dc095SDavid du Colombier     buf->shape = 0xff;
615*593dc095SDavid du Colombier     buf->blend_mode = BLEND_MODE_Normal;
616*593dc095SDavid du Colombier     buf->transfer_fn = transfer_fn;
617*593dc095SDavid du Colombier 
618*593dc095SDavid du Colombier     buf->saved = ctx->stack;
619*593dc095SDavid du Colombier     ctx->stack = buf;
620*593dc095SDavid du Colombier     memset(buf->data, 0, buf->planestride * buf->n_chan);
621*593dc095SDavid du Colombier     return 0;
622*593dc095SDavid du Colombier }
623*593dc095SDavid du Colombier 
624*593dc095SDavid du Colombier private	int
pdf14_pop_transparency_mask(pdf14_ctx * ctx)625*593dc095SDavid du Colombier pdf14_pop_transparency_mask(pdf14_ctx *ctx)
626*593dc095SDavid du Colombier {
627*593dc095SDavid du Colombier     pdf14_buf *tos = ctx->stack;
628*593dc095SDavid du Colombier 
629*593dc095SDavid du Colombier     ctx->stack = tos->saved;
630*593dc095SDavid du Colombier     ctx->maskbuf = tos;
6313ff48bf5SDavid du Colombier     return 0;
6323ff48bf5SDavid du Colombier }
6333ff48bf5SDavid du Colombier 
6343ff48bf5SDavid du Colombier private	int
pdf14_open(gx_device * dev)6353ff48bf5SDavid du Colombier pdf14_open(gx_device *dev)
6363ff48bf5SDavid du Colombier {
6373ff48bf5SDavid du Colombier     pdf14_device *pdev = (pdf14_device *)dev;
6383ff48bf5SDavid du Colombier     gs_int_rect rect;
6393ff48bf5SDavid du Colombier 
6403ff48bf5SDavid du Colombier     if_debug2('v', "[v]pdf14_open: width = %d, height = %d\n",
6413ff48bf5SDavid du Colombier 	     dev->width, dev->height);
6423ff48bf5SDavid du Colombier 
6433ff48bf5SDavid du Colombier     rect.p.x = 0;
6443ff48bf5SDavid du Colombier     rect.p.y = 0;
6453ff48bf5SDavid du Colombier     rect.q.x = dev->width;
6463ff48bf5SDavid du Colombier     rect.q.y = dev->height;
647*593dc095SDavid du Colombier     pdev->ctx = pdf14_ctx_new(&rect, dev->color_info.num_components + 1,
648*593dc095SDavid du Colombier 	pdev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, dev->memory);
6493ff48bf5SDavid du Colombier     if (pdev->ctx == NULL)
6503ff48bf5SDavid du Colombier 	return_error(gs_error_VMerror);
6513ff48bf5SDavid du Colombier     return 0;
6523ff48bf5SDavid du Colombier }
6533ff48bf5SDavid du Colombier 
654*593dc095SDavid du Colombier /*
655*593dc095SDavid du Colombier  * Encode a list of colorant values into a gx_color_index_value.
656*593dc095SDavid du Colombier  */
657*593dc095SDavid du Colombier private	gx_color_index
pdf14_encode_color(gx_device * dev,const gx_color_value colors[])658*593dc095SDavid du Colombier pdf14_encode_color(gx_device *dev, const gx_color_value	colors[])
659*593dc095SDavid du Colombier {
660*593dc095SDavid du Colombier     int drop = sizeof(gx_color_value) * 8 - 8;
661*593dc095SDavid du Colombier     gx_color_index color = 0;
662*593dc095SDavid du Colombier     int i;
663*593dc095SDavid du Colombier     int ncomp = dev->color_info.num_components;
664*593dc095SDavid du Colombier 
665*593dc095SDavid du Colombier     for (i = 0; i < ncomp; i++) {
666*593dc095SDavid du Colombier 	color <<= 8;
667*593dc095SDavid du Colombier 	color |= (colors[i] >> drop);
668*593dc095SDavid du Colombier     }
669*593dc095SDavid du Colombier     return (color == gx_no_color_index ? color ^ 1 : color);
670*593dc095SDavid du Colombier }
671*593dc095SDavid du Colombier 
672*593dc095SDavid du Colombier /*
673*593dc095SDavid du Colombier  * Decode a gx_color_index value back to a list of colorant values.
674*593dc095SDavid du Colombier  */
675*593dc095SDavid du Colombier private	int
pdf14_decode_color(gx_device * dev,gx_color_index color,gx_color_value * out)676*593dc095SDavid du Colombier pdf14_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out)
677*593dc095SDavid du Colombier {
678*593dc095SDavid du Colombier     int i;
679*593dc095SDavid du Colombier     int ncomp = dev->color_info.num_components;
680*593dc095SDavid du Colombier 
681*593dc095SDavid du Colombier     for (i = 0; i < ncomp; i++) {
682*593dc095SDavid du Colombier 	out[ncomp - i - 1] = (gx_color_value) ((color & 0xff) * 0x101);
683*593dc095SDavid du Colombier 	color >>= 8;
684*593dc095SDavid du Colombier     }
685*593dc095SDavid du Colombier     return 0;
686*593dc095SDavid du Colombier }
687*593dc095SDavid du Colombier 
688*593dc095SDavid du Colombier #ifdef DUMP_TO_PNG
689*593dc095SDavid du Colombier /* Dumps a planar RGBA image to	a PNG file. */
690*593dc095SDavid du Colombier private	int
dump_planar_rgba(gs_memory_t * mem,const byte * buf,int width,int height,int rowstride,int planestride)691*593dc095SDavid du Colombier dump_planar_rgba(gs_memory_t *mem,
692*593dc095SDavid du Colombier 		 const byte *buf, int width, int height, int rowstride, int planestride)
693*593dc095SDavid du Colombier {
694*593dc095SDavid du Colombier     int rowbytes = width << 2;
695*593dc095SDavid du Colombier     byte *row = gs_malloc(mem, rowbytes, 1, "png raster buffer");
696*593dc095SDavid du Colombier     png_struct *png_ptr =
697*593dc095SDavid du Colombier     png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
698*593dc095SDavid du Colombier     png_info *info_ptr =
699*593dc095SDavid du Colombier     png_create_info_struct(png_ptr);
700*593dc095SDavid du Colombier     const char *software_key = "Software";
701*593dc095SDavid du Colombier     char software_text[256];
702*593dc095SDavid du Colombier     png_text text_png;
703*593dc095SDavid du Colombier     const byte *buf_ptr = buf;
704*593dc095SDavid du Colombier     FILE *file;
705*593dc095SDavid du Colombier     int code;
706*593dc095SDavid du Colombier     int y;
707*593dc095SDavid du Colombier 
708*593dc095SDavid du Colombier 	file = fopen ("c:\\temp\\tmp.png", "wb");
709*593dc095SDavid du Colombier 
710*593dc095SDavid du Colombier     if_debug0('v', "[v]pnga_output_page\n");
711*593dc095SDavid du Colombier 
712*593dc095SDavid du Colombier     if (row == 0 || png_ptr == 0 || info_ptr == 0) {
713*593dc095SDavid du Colombier 	code = gs_note_error(gs_error_VMerror);
714*593dc095SDavid du Colombier 	goto done;
715*593dc095SDavid du Colombier     }
716*593dc095SDavid du Colombier     /* set error handling */
717*593dc095SDavid du Colombier     if (setjmp(png_ptr->jmpbuf)) {
718*593dc095SDavid du Colombier 	/* If we get here, we had a problem reading the file */
719*593dc095SDavid du Colombier 	code = gs_note_error(gs_error_VMerror);
720*593dc095SDavid du Colombier 	goto done;
721*593dc095SDavid du Colombier     }
722*593dc095SDavid du Colombier 
723*593dc095SDavid du Colombier     code = 0;			/* for normal path */
724*593dc095SDavid du Colombier     /* set up the output control */
725*593dc095SDavid du Colombier     png_init_io(png_ptr, file);
726*593dc095SDavid du Colombier 
727*593dc095SDavid du Colombier     /* set the file information here */
728*593dc095SDavid du Colombier     info_ptr->width = width;
729*593dc095SDavid du Colombier     info_ptr->height = height;
730*593dc095SDavid du Colombier     /* resolution is in pixels per meter vs. dpi */
731*593dc095SDavid du Colombier     info_ptr->x_pixels_per_unit =
732*593dc095SDavid du Colombier 	(png_uint_32) (96.0 * (100.0 / 2.54));
733*593dc095SDavid du Colombier     info_ptr->y_pixels_per_unit =
734*593dc095SDavid du Colombier 	(png_uint_32) (96.0 * (100.0 / 2.54));
735*593dc095SDavid du Colombier     info_ptr->phys_unit_type = PNG_RESOLUTION_METER;
736*593dc095SDavid du Colombier     info_ptr->valid |= PNG_INFO_pHYs;
737*593dc095SDavid du Colombier 
738*593dc095SDavid du Colombier     /* At present, only supporting 32-bit rgba */
739*593dc095SDavid du Colombier     info_ptr->bit_depth = 8;
740*593dc095SDavid du Colombier     info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
741*593dc095SDavid du Colombier 
742*593dc095SDavid du Colombier     /* add comment */
743*593dc095SDavid du Colombier     sprintf(software_text, "%s %d.%02d", gs_product,
744*593dc095SDavid du Colombier 	    (int)(gs_revision / 100), (int)(gs_revision % 100));
745*593dc095SDavid du Colombier     text_png.compression = -1;	/* uncompressed */
746*593dc095SDavid du Colombier     text_png.key = (char *)software_key;	/* not const, unfortunately */
747*593dc095SDavid du Colombier     text_png.text = software_text;
748*593dc095SDavid du Colombier     text_png.text_length = strlen(software_text);
749*593dc095SDavid du Colombier     info_ptr->text = &text_png;
750*593dc095SDavid du Colombier     info_ptr->num_text = 1;
751*593dc095SDavid du Colombier 
752*593dc095SDavid du Colombier     /* write the file information */
753*593dc095SDavid du Colombier     png_write_info(png_ptr, info_ptr);
754*593dc095SDavid du Colombier 
755*593dc095SDavid du Colombier     /* don't write the comments twice */
756*593dc095SDavid du Colombier     info_ptr->num_text = 0;
757*593dc095SDavid du Colombier     info_ptr->text = NULL;
758*593dc095SDavid du Colombier 
759*593dc095SDavid du Colombier     /* Write the contents of the image. */
760*593dc095SDavid du Colombier     for (y = 0; y < height; ++y) {
761*593dc095SDavid du Colombier 	int x;
762*593dc095SDavid du Colombier 
763*593dc095SDavid du Colombier 	for (x = 0; x < width; ++x) {
764*593dc095SDavid du Colombier 	    row[(x << 2)] = buf_ptr[x];
765*593dc095SDavid du Colombier 	    row[(x << 2) + 1] = buf_ptr[x + planestride];
766*593dc095SDavid du Colombier 	    row[(x << 2) + 2] = buf_ptr[x + planestride * 2];
767*593dc095SDavid du Colombier 	    row[(x << 2) + 3] = buf_ptr[x + planestride * 3];
768*593dc095SDavid du Colombier 	}
769*593dc095SDavid du Colombier 	png_write_row(png_ptr, row);
770*593dc095SDavid du Colombier 	buf_ptr += rowstride;
771*593dc095SDavid du Colombier     }
772*593dc095SDavid du Colombier 
773*593dc095SDavid du Colombier     /* write the rest of the file */
774*593dc095SDavid du Colombier     png_write_end(png_ptr, info_ptr);
775*593dc095SDavid du Colombier 
776*593dc095SDavid du Colombier   done:
777*593dc095SDavid du Colombier     /* free the structures */
778*593dc095SDavid du Colombier     png_destroy_write_struct(&png_ptr, &info_ptr);
779*593dc095SDavid du Colombier     gs_free(mem, row, rowbytes, 1, "png raster buffer");
780*593dc095SDavid du Colombier 
781*593dc095SDavid du Colombier     fclose (file);
782*593dc095SDavid du Colombier     return code;
783*593dc095SDavid du Colombier }
784*593dc095SDavid du Colombier #endif
785*593dc095SDavid du Colombier 
786*593dc095SDavid du Colombier 
7873ff48bf5SDavid du Colombier /**
7883ff48bf5SDavid du Colombier  * pdf14_put_image: Put rendered image to target device.
7893ff48bf5SDavid du Colombier  * @pdev: The PDF 1.4 rendering device.
7903ff48bf5SDavid du Colombier  * @pgs: State for image draw operation.
7913ff48bf5SDavid du Colombier  * @target: The target device.
7923ff48bf5SDavid du Colombier  *
7933ff48bf5SDavid du Colombier  * Puts the rendered image in @pdev's buffer to @target. This is called
7943ff48bf5SDavid du Colombier  * as part of the sequence of popping the PDF 1.4 device filter.
7953ff48bf5SDavid du Colombier  *
7963ff48bf5SDavid du Colombier  * Return code: negative on error.
7973ff48bf5SDavid du Colombier  **/
7983ff48bf5SDavid du Colombier private	int
pdf14_put_image(pdf14_device * pdev,gs_imager_state * pis,gx_device * target)799*593dc095SDavid du Colombier pdf14_put_image(pdf14_device *pdev, gs_imager_state *pis, gx_device *target)
8003ff48bf5SDavid du Colombier {
8013ff48bf5SDavid du Colombier     int code;
8023ff48bf5SDavid du Colombier     gs_image1_t image;
8033ff48bf5SDavid du Colombier     gs_matrix pmat;
8043ff48bf5SDavid du Colombier     gx_image_enum_common_t *info;
8053ff48bf5SDavid du Colombier     int width = pdev->width;
8063ff48bf5SDavid du Colombier     int height = pdev->height;
8073ff48bf5SDavid du Colombier     int y;
8083ff48bf5SDavid du Colombier     pdf14_buf *buf = pdev->ctx->stack;
8093ff48bf5SDavid du Colombier     int planestride = buf->planestride;
810*593dc095SDavid du Colombier     int num_comp = buf->n_chan - 1;
8113ff48bf5SDavid du Colombier     byte *buf_ptr = buf->data;
8123ff48bf5SDavid du Colombier     byte *linebuf;
813*593dc095SDavid du Colombier     gs_color_space cs;
814*593dc095SDavid du Colombier     const byte bg = pdev->ctx->additive ? 255 : 0;
8153ff48bf5SDavid du Colombier 
816*593dc095SDavid du Colombier #ifdef DUMP_TO_PNG
817*593dc095SDavid du Colombier     dump_planar_rgba(pdev->memory, buf_ptr, width, height,
818*593dc095SDavid du Colombier 		     buf->rowstride, buf->planestride);
8193ff48bf5SDavid du Colombier #endif
8203ff48bf5SDavid du Colombier 
821*593dc095SDavid du Colombier #if 0
822*593dc095SDavid du Colombier     /* Set graphics state device to target, so that image can set up
823*593dc095SDavid du Colombier        the color mapping properly. */
824*593dc095SDavid du Colombier     rc_increment(pdev);
825*593dc095SDavid du Colombier     gs_setdevice_no_init(pgs, target);
826*593dc095SDavid du Colombier #endif
827*593dc095SDavid du Colombier 
828*593dc095SDavid du Colombier     if_debug0('v', "[v]pdf14_put_image\n");
829*593dc095SDavid du Colombier     /*
830*593dc095SDavid du Colombier      * Set color space to either Gray, RGB, or CMYK in preparation for sending
831*593dc095SDavid du Colombier      * an image.
832*593dc095SDavid du Colombier      */
833*593dc095SDavid du Colombier     switch (num_comp) {
834*593dc095SDavid du Colombier 	case 1:				/* DeviceGray */
835*593dc095SDavid du Colombier 	    gs_cspace_init_DeviceGray(pis->memory, &cs);
836*593dc095SDavid du Colombier 	    break;
837*593dc095SDavid du Colombier 	case 3:				/* DeviceRGB */
838*593dc095SDavid du Colombier 	    gs_cspace_init_DeviceRGB(pis->memory, &cs);
839*593dc095SDavid du Colombier 	    break;
840*593dc095SDavid du Colombier 	case 4:				/* DeviceCMYK */
841*593dc095SDavid du Colombier 	    gs_cspace_init_DeviceCMYK(pis->memory, &cs);
842*593dc095SDavid du Colombier 	    break;
843*593dc095SDavid du Colombier 	default:			/* Should never occur */
844*593dc095SDavid du Colombier 	    return_error(gs_error_rangecheck);
845*593dc095SDavid du Colombier 	    break;
846*593dc095SDavid du Colombier     }
847*593dc095SDavid du Colombier     gs_image_t_init_adjust(&image, &cs, false);
848*593dc095SDavid du Colombier     image.ImageMatrix.xx = (float)width;
849*593dc095SDavid du Colombier     image.ImageMatrix.yy = (float)height;
8503ff48bf5SDavid du Colombier     image.Width = width;
8513ff48bf5SDavid du Colombier     image.Height = height;
8523ff48bf5SDavid du Colombier     image.BitsPerComponent = 8;
853*593dc095SDavid du Colombier     pmat.xx = (float)width;
8543ff48bf5SDavid du Colombier     pmat.xy = 0;
8553ff48bf5SDavid du Colombier     pmat.yx = 0;
856*593dc095SDavid du Colombier     pmat.yy = (float)height;
8573ff48bf5SDavid du Colombier     pmat.tx = 0;
8583ff48bf5SDavid du Colombier     pmat.ty = 0;
8593ff48bf5SDavid du Colombier     code = dev_proc(target, begin_typed_image) (target,
8603ff48bf5SDavid du Colombier 						pis, &pmat,
8613ff48bf5SDavid du Colombier 						(gs_image_common_t *)&image,
8623ff48bf5SDavid du Colombier 						NULL, NULL, NULL,
863*593dc095SDavid du Colombier 						pis->memory, &info);
8643ff48bf5SDavid du Colombier     if (code < 0)
8653ff48bf5SDavid du Colombier 	return code;
8663ff48bf5SDavid du Colombier 
867*593dc095SDavid du Colombier     linebuf = gs_alloc_bytes(pdev->memory, width * num_comp, "pdf14_put_image");
8683ff48bf5SDavid du Colombier     for (y = 0; y < height; y++) {
8693ff48bf5SDavid du Colombier 	gx_image_plane_t planes;
8703ff48bf5SDavid du Colombier 	int x;
8713ff48bf5SDavid du Colombier 	int rows_used;
8723ff48bf5SDavid du Colombier 
8733ff48bf5SDavid du Colombier 	for (x = 0; x < width; x++) {
874*593dc095SDavid du Colombier 	    byte comp, a;
875*593dc095SDavid du Colombier 	    int tmp, comp_num;
8763ff48bf5SDavid du Colombier 
877*593dc095SDavid du Colombier 	    /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
878*593dc095SDavid du Colombier 	    a = buf_ptr[x + planestride * num_comp];
8793ff48bf5SDavid du Colombier 
8803ff48bf5SDavid du Colombier 	    if ((a + 1) & 0xfe) {
8813ff48bf5SDavid du Colombier 		a ^= 0xff;
882*593dc095SDavid du Colombier 		for (comp_num = 0; comp_num < num_comp; comp_num++) {
883*593dc095SDavid du Colombier 		    comp  = buf_ptr[x + planestride * comp_num];
884*593dc095SDavid du Colombier 		    tmp = ((bg - comp) * a) + 0x80;
885*593dc095SDavid du Colombier 		    comp += (tmp + (tmp >> 8)) >> 8;
886*593dc095SDavid du Colombier 		    linebuf[x * num_comp + comp_num] = comp;
887*593dc095SDavid du Colombier 		}
8883ff48bf5SDavid du Colombier 	    } else if (a == 0) {
889*593dc095SDavid du Colombier 		for (comp_num = 0; comp_num < num_comp; comp_num++) {
890*593dc095SDavid du Colombier 		    linebuf[x * num_comp + comp_num] = bg;
891*593dc095SDavid du Colombier 		}
8923ff48bf5SDavid du Colombier 	    } else {
893*593dc095SDavid du Colombier 		for (comp_num = 0; comp_num < num_comp; comp_num++) {
894*593dc095SDavid du Colombier 		    comp = buf_ptr[x + planestride * comp_num];
895*593dc095SDavid du Colombier 		    linebuf[x * num_comp + comp_num] = comp;
896*593dc095SDavid du Colombier 		}
8973ff48bf5SDavid du Colombier 	    }
8983ff48bf5SDavid du Colombier 	}
8993ff48bf5SDavid du Colombier 
9003ff48bf5SDavid du Colombier 	planes.data = linebuf;
9013ff48bf5SDavid du Colombier 	planes.data_x = 0;
902*593dc095SDavid du Colombier 	planes.raster = width * num_comp;
9033ff48bf5SDavid du Colombier 	info->procs->plane_data(info, &planes, 1, &rows_used);
9043ff48bf5SDavid du Colombier 	/* todo: check return value */
9053ff48bf5SDavid du Colombier 
9063ff48bf5SDavid du Colombier 	buf_ptr += buf->rowstride;
9073ff48bf5SDavid du Colombier     }
9083ff48bf5SDavid du Colombier     gs_free_object(pdev->memory, linebuf, "pdf14_put_image");
9093ff48bf5SDavid du Colombier 
9103ff48bf5SDavid du Colombier     info->procs->end_image(info, true);
911*593dc095SDavid du Colombier 
912*593dc095SDavid du Colombier #if 0
913*593dc095SDavid du Colombier     /* Restore device in graphics state.*/
914*593dc095SDavid du Colombier     gs_setdevice_no_init(pgs, (gx_device*) pdev);
915*593dc095SDavid du Colombier     rc_decrement_only(pdev, "pdf_14_put_image");
916*593dc095SDavid du Colombier #endif
917*593dc095SDavid du Colombier 
9183ff48bf5SDavid du Colombier     return code;
9193ff48bf5SDavid du Colombier }
9203ff48bf5SDavid du Colombier 
9213ff48bf5SDavid du Colombier private	int
pdf14_close(gx_device * dev)9223ff48bf5SDavid du Colombier pdf14_close(gx_device *dev)
9233ff48bf5SDavid du Colombier {
9243ff48bf5SDavid du Colombier     pdf14_device *pdev = (pdf14_device *)dev;
9253ff48bf5SDavid du Colombier 
926*593dc095SDavid du Colombier     if (pdev->ctx) {
9273ff48bf5SDavid du Colombier 	pdf14_ctx_free(pdev->ctx);
928*593dc095SDavid du Colombier 	pdev->ctx = NULL;
929*593dc095SDavid du Colombier     }
9303ff48bf5SDavid du Colombier     return 0;
9313ff48bf5SDavid du Colombier }
9323ff48bf5SDavid du Colombier 
9333ff48bf5SDavid du Colombier private	int
pdf14_output_page(gx_device * dev,int num_copies,int flush)9343ff48bf5SDavid du Colombier pdf14_output_page(gx_device * dev, int num_copies, int flush)
9353ff48bf5SDavid du Colombier {
936*593dc095SDavid du Colombier     pdf14_device * pdev = (pdf14_device *)dev;
9373ff48bf5SDavid du Colombier 
938*593dc095SDavid du Colombier     if (pdev->target != NULL)
939*593dc095SDavid du Colombier 	return (*dev_proc(pdev->target, output_page)) (pdev->target, num_copies, flush);
9403ff48bf5SDavid du Colombier     return 0;
9413ff48bf5SDavid du Colombier }
9423ff48bf5SDavid du Colombier 
9433ff48bf5SDavid du Colombier #define	COPY_PARAM(p) dev->p = target->p
9443ff48bf5SDavid du Colombier #define	COPY_ARRAY_PARAM(p) memcpy(dev->p, target->p, sizeof(dev->p))
9453ff48bf5SDavid du Colombier 
9463ff48bf5SDavid du Colombier /*
9473ff48bf5SDavid du Colombier  * Copy device parameters back from a target.  This copies all standard
9483ff48bf5SDavid du Colombier  * parameters related to page size and resolution, but not any of the
9493ff48bf5SDavid du Colombier  * color-related parameters, as the pdf14 device retains its own color
9503ff48bf5SDavid du Colombier  * handling. This routine is parallel to gx_device_copy_params().
9513ff48bf5SDavid du Colombier  */
9523ff48bf5SDavid du Colombier private	void
gs_pdf14_device_copy_params(gx_device * dev,const gx_device * target)9533ff48bf5SDavid du Colombier gs_pdf14_device_copy_params(gx_device *dev, const gx_device *target)
9543ff48bf5SDavid du Colombier {
9553ff48bf5SDavid du Colombier 	COPY_PARAM(width);
9563ff48bf5SDavid du Colombier 	COPY_PARAM(height);
9573ff48bf5SDavid du Colombier 	COPY_ARRAY_PARAM(MediaSize);
9583ff48bf5SDavid du Colombier 	COPY_ARRAY_PARAM(ImagingBBox);
9593ff48bf5SDavid du Colombier 	COPY_PARAM(ImagingBBox_set);
9603ff48bf5SDavid du Colombier 	COPY_ARRAY_PARAM(HWResolution);
9613ff48bf5SDavid du Colombier 	COPY_ARRAY_PARAM(MarginsHWResolution);
9623ff48bf5SDavid du Colombier 	COPY_ARRAY_PARAM(Margins);
9633ff48bf5SDavid du Colombier 	COPY_ARRAY_PARAM(HWMargins);
9643ff48bf5SDavid du Colombier 	COPY_PARAM(PageCount);
9653ff48bf5SDavid du Colombier #undef COPY_ARRAY_PARAM
9663ff48bf5SDavid du Colombier #undef COPY_PARAM
9673ff48bf5SDavid du Colombier }
9683ff48bf5SDavid du Colombier 
969*593dc095SDavid du Colombier /*
970*593dc095SDavid du Colombier  * This is a forwarding version of the put_params device proc.  It is only
971*593dc095SDavid du Colombier  * used when the PDF 1.4 compositor devices are closed.  The routine will
972*593dc095SDavid du Colombier  * check if the target device has closed and, if so, close itself.  The routine
973*593dc095SDavid du Colombier  * also sync the device parameters.
974*593dc095SDavid du Colombier  */
975*593dc095SDavid du Colombier private	int
pdf14_forward_put_params(gx_device * dev,gs_param_list * plist)976*593dc095SDavid du Colombier pdf14_forward_put_params(gx_device * dev, gs_param_list	* plist)
9773ff48bf5SDavid du Colombier {
9783ff48bf5SDavid du Colombier     pdf14_device * pdev = (pdf14_device *)dev;
979*593dc095SDavid du Colombier     gx_device * tdev = pdev->target;
980*593dc095SDavid du Colombier     int code = 0;
9813ff48bf5SDavid du Colombier 
982*593dc095SDavid du Colombier     if (tdev != 0 && (code = dev_proc(tdev, put_params)(tdev, plist)) >= 0) {
983*593dc095SDavid du Colombier 	gx_device_decache_colors(dev);
984*593dc095SDavid du Colombier 	if (!tdev->is_open)
985*593dc095SDavid du Colombier 	    code = gs_closedevice(dev);
986*593dc095SDavid du Colombier 	gx_device_copy_params(dev, tdev);
987*593dc095SDavid du Colombier     }
988*593dc095SDavid du Colombier     return code;
9893ff48bf5SDavid du Colombier }
9903ff48bf5SDavid du Colombier 
991*593dc095SDavid du Colombier /*
992*593dc095SDavid du Colombier  * The put_params method for the PDF 1.4 device will check if the
993*593dc095SDavid du Colombier  * target device has closed and, if so, close itself.  Note:  This routine is
994*593dc095SDavid du Colombier  * currently being used by both the pdf14_clist_device and the pdf_device.
995*593dc095SDavid du Colombier  * Please make sure that any changes are either applicable to both devices
996*593dc095SDavid du Colombier  * or clone the routine for each device.
997*593dc095SDavid du Colombier  */
998*593dc095SDavid du Colombier private	int
pdf14_put_params(gx_device * dev,gs_param_list * plist)999*593dc095SDavid du Colombier pdf14_put_params(gx_device * dev, gs_param_list	* plist)
10003ff48bf5SDavid du Colombier {
1001*593dc095SDavid du Colombier     pdf14_device * pdev = (pdf14_device *)dev;
1002*593dc095SDavid du Colombier     gx_device * tdev = pdev->target;
1003*593dc095SDavid du Colombier     int code = 0;
1004*593dc095SDavid du Colombier 
1005*593dc095SDavid du Colombier     if (tdev != 0 && (code = dev_proc(tdev, put_params)(tdev, plist)) >= 0) {
1006*593dc095SDavid du Colombier 	gx_device_decache_colors(dev);
1007*593dc095SDavid du Colombier 	if (!tdev->is_open)
1008*593dc095SDavid du Colombier 	    code = gs_closedevice(dev);
1009*593dc095SDavid du Colombier 	gs_pdf14_device_copy_params(dev, tdev);
1010*593dc095SDavid du Colombier     }
1011*593dc095SDavid du Colombier     return code;
1012*593dc095SDavid du Colombier }
1013*593dc095SDavid du Colombier 
1014*593dc095SDavid du Colombier /*
1015*593dc095SDavid du Colombier  * Copy marking related parameters into the PDF 1.4 device structure for use
1016*593dc095SDavid du Colombier  * by pdf14_fill_rrectangle.
1017*593dc095SDavid du Colombier  */
1018*593dc095SDavid du Colombier private	void
pdf14_set_marking_params(gx_device * dev,const gs_imager_state * pis)1019*593dc095SDavid du Colombier pdf14_set_marking_params(gx_device *dev, const gs_imager_state *pis)
1020*593dc095SDavid du Colombier {
1021*593dc095SDavid du Colombier     pdf14_device * pdev = (pdf14_device *)dev;
1022*593dc095SDavid du Colombier 
1023*593dc095SDavid du Colombier     pdev->opacity = pis->opacity.alpha;
1024*593dc095SDavid du Colombier     pdev->shape = pis->shape.alpha;
1025*593dc095SDavid du Colombier     pdev->alpha = pis->opacity.alpha * pis->shape.alpha;
1026*593dc095SDavid du Colombier     pdev->blend_mode = pis->blend_mode;
1027*593dc095SDavid du Colombier     if_debug3('v', "[v]set_marking_params, opacity = %g, shape = %g, bm = %d\n",
1028*593dc095SDavid du Colombier 	      pdev->opacity, pdev->shape, pis->blend_mode);
10293ff48bf5SDavid du Colombier }
10303ff48bf5SDavid du Colombier 
10313ff48bf5SDavid du Colombier private	int
pdf14_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)10323ff48bf5SDavid du Colombier pdf14_fill_path(gx_device *dev,	const gs_imager_state *pis,
10333ff48bf5SDavid du Colombier 			   gx_path *ppath, const gx_fill_params *params,
10343ff48bf5SDavid du Colombier 			   const gx_drawing_color *pdcolor,
10353ff48bf5SDavid du Colombier 			   const gx_clip_path *pcpath)
10363ff48bf5SDavid du Colombier {
10373ff48bf5SDavid du Colombier     gs_imager_state new_is = *pis;
10383ff48bf5SDavid du Colombier 
1039*593dc095SDavid du Colombier     /*
1040*593dc095SDavid du Colombier      * The blend operations are not idempotent.  Force non-idempotent
1041*593dc095SDavid du Colombier      * filling and stroking operations.
1042*593dc095SDavid du Colombier      */
10433ff48bf5SDavid du Colombier     new_is.log_op |= lop_pdf14;
1044*593dc095SDavid du Colombier     pdf14_set_marking_params(dev, pis);
1045*593dc095SDavid du Colombier     return gx_default_fill_path(dev, &new_is, ppath, params, pdcolor, pcpath);
10463ff48bf5SDavid du Colombier }
10473ff48bf5SDavid du Colombier 
10483ff48bf5SDavid du Colombier private	int
pdf14_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)10493ff48bf5SDavid du Colombier pdf14_stroke_path(gx_device *dev, const	gs_imager_state	*pis,
10503ff48bf5SDavid du Colombier 			     gx_path *ppath, const gx_stroke_params *params,
10513ff48bf5SDavid du Colombier 			     const gx_drawing_color *pdcolor,
10523ff48bf5SDavid du Colombier 			     const gx_clip_path *pcpath)
10533ff48bf5SDavid du Colombier {
10543ff48bf5SDavid du Colombier     gs_imager_state new_is = *pis;
10553ff48bf5SDavid du Colombier 
1056*593dc095SDavid du Colombier     /*
1057*593dc095SDavid du Colombier      * The blend operations are not idempotent.  Force non-idempotent
1058*593dc095SDavid du Colombier      * filling and stroking operations.
1059*593dc095SDavid du Colombier      */
10603ff48bf5SDavid du Colombier     new_is.log_op |= lop_pdf14;
1061*593dc095SDavid du Colombier     pdf14_set_marking_params(dev, pis);
1062*593dc095SDavid du Colombier     return gx_default_stroke_path(dev, &new_is, ppath, params, pdcolor,
10633ff48bf5SDavid du Colombier 				  pcpath);
10643ff48bf5SDavid du Colombier }
10653ff48bf5SDavid du Colombier 
10663ff48bf5SDavid du Colombier private	int
pdf14_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 * mem,gx_image_enum_common_t ** pinfo)10673ff48bf5SDavid du Colombier pdf14_begin_typed_image(gx_device * dev, const gs_imager_state * pis,
10683ff48bf5SDavid du Colombier 			   const gs_matrix *pmat, const gs_image_common_t *pic,
10693ff48bf5SDavid du Colombier 			   const gs_int_rect * prect,
10703ff48bf5SDavid du Colombier 			   const gx_drawing_color * pdcolor,
10713ff48bf5SDavid du Colombier 			   const gx_clip_path * pcpath, gs_memory_t * mem,
10723ff48bf5SDavid du Colombier 			   gx_image_enum_common_t ** pinfo)
10733ff48bf5SDavid du Colombier {
1074*593dc095SDavid du Colombier     pdf14_set_marking_params(dev, pis);
1075*593dc095SDavid du Colombier     return gx_default_begin_typed_image(dev, pis, pmat, pic, prect, pdcolor,
10763ff48bf5SDavid du Colombier 					pcpath, mem, pinfo);
10773ff48bf5SDavid du Colombier }
10783ff48bf5SDavid du Colombier 
10793ff48bf5SDavid du Colombier private	void
pdf14_set_params(gs_imager_state * pis,gx_device * dev,const gs_pdf14trans_params_t * pparams)1080*593dc095SDavid du Colombier pdf14_set_params(gs_imager_state * pis,	gx_device * dev,
1081*593dc095SDavid du Colombier 				const gs_pdf14trans_params_t * pparams)
10823ff48bf5SDavid du Colombier {
1083*593dc095SDavid du Colombier     if (pparams->changed & PDF14_SET_BLEND_MODE)
1084*593dc095SDavid du Colombier 	pis->blend_mode = pparams->blend_mode;
1085*593dc095SDavid du Colombier     if (pparams->changed & PDF14_SET_TEXT_KNOCKOUT)
1086*593dc095SDavid du Colombier 	pis->text_knockout = pparams->text_knockout;
1087*593dc095SDavid du Colombier     if (pparams->changed & PDF14_SET_SHAPE_ALPHA)
1088*593dc095SDavid du Colombier 	pis->shape.alpha = pparams->shape.alpha;
1089*593dc095SDavid du Colombier     if (pparams->changed & PDF14_SET_OPACITY_ALPHA)
1090*593dc095SDavid du Colombier 	pis->opacity.alpha = pparams->opacity.alpha;
1091*593dc095SDavid du Colombier     pdf14_set_marking_params(dev, pis);
10923ff48bf5SDavid du Colombier }
10933ff48bf5SDavid du Colombier 
1094*593dc095SDavid du Colombier /*
1095*593dc095SDavid du Colombier  * This open_device method for the PDF 1.4 compositor devices is only used
1096*593dc095SDavid du Colombier  * when these devices are disabled.  This routine is about as close to
1097*593dc095SDavid du Colombier  * a pure "forwarding" open_device operation as is possible. Its only
1098*593dc095SDavid du Colombier  * significant function is to ensure that the is_open field of the
1099*593dc095SDavid du Colombier  * PDF 1.4 compositor devices matches that of the target device.
1100*593dc095SDavid du Colombier  *
1101*593dc095SDavid du Colombier  * We assume this procedure is called only if the device is not already
1102*593dc095SDavid du Colombier  * open, and that gs_opendevice will take care of the is_open flag.
1103*593dc095SDavid du Colombier  */
1104*593dc095SDavid du Colombier private	int
pdf14_forward_open_device(gx_device * dev)1105*593dc095SDavid du Colombier pdf14_forward_open_device(gx_device * dev)
1106*593dc095SDavid du Colombier {
1107*593dc095SDavid du Colombier     gx_device_forward * pdev = (gx_device_forward *)dev;
1108*593dc095SDavid du Colombier     gx_device * tdev = pdev->target;
1109*593dc095SDavid du Colombier     int code = 0;
1110*593dc095SDavid du Colombier 
1111*593dc095SDavid du Colombier     /* The PDF 1.4 compositing devices must have a target */
1112*593dc095SDavid du Colombier     if (tdev == 0)
1113*593dc095SDavid du Colombier 	return_error(gs_error_unknownerror);
1114*593dc095SDavid du Colombier     if ((code = gs_opendevice(tdev)) >= 0)
1115*593dc095SDavid du Colombier 	gx_device_copy_params(dev, tdev);
1116*593dc095SDavid du Colombier     return code;
1117*593dc095SDavid du Colombier }
1118*593dc095SDavid du Colombier 
1119*593dc095SDavid du Colombier /*
1120*593dc095SDavid du Colombier  * Convert all device procs to be 'forwarding'.  The caller is responsible
1121*593dc095SDavid du Colombier  * for setting any device procs that should not be forwarded.
1122*593dc095SDavid du Colombier  */
1123*593dc095SDavid du Colombier private	void
pdf14_forward_device_procs(gx_device * dev)1124*593dc095SDavid du Colombier pdf14_forward_device_procs(gx_device * dev)
1125*593dc095SDavid du Colombier {
1126*593dc095SDavid du Colombier     gx_device_forward * pdev = (gx_device_forward *)dev;
1127*593dc095SDavid du Colombier 
1128*593dc095SDavid du Colombier     /*
1129*593dc095SDavid du Colombier      * We are using gx_device_forward_fill_in_procs to set the various procs.
1130*593dc095SDavid du Colombier      * This will ensure that any new device procs are also set.  However that
1131*593dc095SDavid du Colombier      * routine only changes procs which are NULL.  Thus we start by setting all
1132*593dc095SDavid du Colombier      * procs to NULL.
1133*593dc095SDavid du Colombier      */
1134*593dc095SDavid du Colombier     memset(&(pdev->procs), 0, size_of(pdev->procs));
1135*593dc095SDavid du Colombier     gx_device_forward_fill_in_procs(pdev);
1136*593dc095SDavid du Colombier     /*
1137*593dc095SDavid du Colombier      * gx_device_forward_fill_in_procs does not forward all procs.
1138*593dc095SDavid du Colombier      * Set the remainding procs to also forward.
1139*593dc095SDavid du Colombier      */
1140*593dc095SDavid du Colombier     set_dev_proc(dev, close_device, gx_forward_close_device);
1141*593dc095SDavid du Colombier     set_dev_proc(dev, fill_rectangle, gx_forward_fill_rectangle);
1142*593dc095SDavid du Colombier     set_dev_proc(dev, tile_rectangle, gx_forward_tile_rectangle);
1143*593dc095SDavid du Colombier     set_dev_proc(dev, copy_mono, gx_forward_copy_mono);
1144*593dc095SDavid du Colombier     set_dev_proc(dev, copy_color, gx_forward_copy_color);
1145*593dc095SDavid du Colombier     set_dev_proc(dev, get_page_device, gx_forward_get_page_device);
1146*593dc095SDavid du Colombier     set_dev_proc(dev, strip_tile_rectangle, gx_forward_strip_tile_rectangle);
1147*593dc095SDavid du Colombier     set_dev_proc(dev, copy_alpha, gx_forward_copy_alpha);
1148*593dc095SDavid du Colombier     /* These are forwarding devices with minor tweaks. */
1149*593dc095SDavid du Colombier     set_dev_proc(dev, open_device, pdf14_forward_open_device);
1150*593dc095SDavid du Colombier     set_dev_proc(dev, put_params, pdf14_forward_put_params);
1151*593dc095SDavid du Colombier }
1152*593dc095SDavid du Colombier 
1153*593dc095SDavid du Colombier /*
1154*593dc095SDavid du Colombier  * Disable the PDF 1.4 compositor device.  Once created, the PDF 1.4
1155*593dc095SDavid du Colombier  * compositor device is never removed.  (We do not have a remove compositor
1156*593dc095SDavid du Colombier  * method.)  However it is no-op'ed when the PDF 1.4 device is popped.  This
1157*593dc095SDavid du Colombier  * routine implements that action.
1158*593dc095SDavid du Colombier  */
1159*593dc095SDavid du Colombier private	int
pdf14_disable_device(gx_device * dev)1160*593dc095SDavid du Colombier pdf14_disable_device(gx_device * dev)
1161*593dc095SDavid du Colombier {
1162*593dc095SDavid du Colombier     gx_device_forward * pdev = (gx_device_forward *)dev;
1163*593dc095SDavid du Colombier 
1164*593dc095SDavid du Colombier     if_debug0('v', "[v]pdf14_disable_device\n");
1165*593dc095SDavid du Colombier     dev->color_info = pdev->target->color_info;
1166*593dc095SDavid du Colombier     pdf14_forward_device_procs(dev);
1167*593dc095SDavid du Colombier     set_dev_proc(dev, create_compositor, pdf14_forward_create_compositor);
1168*593dc095SDavid du Colombier     return 0;
1169*593dc095SDavid du Colombier }
1170*593dc095SDavid du Colombier 
1171*593dc095SDavid du Colombier /*
1172*593dc095SDavid du Colombier  * The default color space for PDF 1.4 blend modes is based upon the process
1173*593dc095SDavid du Colombier  * color model of the output device.
1174*593dc095SDavid du Colombier  */
1175*593dc095SDavid du Colombier private	pdf14_default_colorspace_t
pdf14_determine_default_blend_cs(gx_device * pdev)1176*593dc095SDavid du Colombier pdf14_determine_default_blend_cs(gx_device * pdev)
1177*593dc095SDavid du Colombier {
1178*593dc095SDavid du Colombier     if (pdev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE)
1179*593dc095SDavid du Colombier 	/* Use DeviceCMYK for all subrtactive process color models. */
1180*593dc095SDavid du Colombier 	return DeviceCMYK;
1181*593dc095SDavid du Colombier     else {
1182*593dc095SDavid du Colombier 	/*
1183*593dc095SDavid du Colombier 	 * Note:  We do not allow the SeparationOrder device parameter for
1184*593dc095SDavid du Colombier 	 * additive devices.  Thus we always have 1 colorant for DeviceGray
1185*593dc095SDavid du Colombier 	 * and 3 colorants for DeviceRGB.  We do not currently support
1186*593dc095SDavid du Colombier 	 * blending in a DeviceGray color space.  Thus we oniy use DeviceRGB.
1187*593dc095SDavid du Colombier 	 */
1188*593dc095SDavid du Colombier 	return DeviceRGB;
1189*593dc095SDavid du Colombier     }
1190*593dc095SDavid du Colombier }
1191*593dc095SDavid du Colombier 
1192*593dc095SDavid du Colombier /*
1193*593dc095SDavid du Colombier  * the PDF 1.4 transparency spec says that color space for blending
1194*593dc095SDavid du Colombier  * operations can be based upon either a color space specified in the
1195*593dc095SDavid du Colombier  * group or a default value based upon the output device.  We are
1196*593dc095SDavid du Colombier  * currently only using a color space based upon the device.
1197*593dc095SDavid du Colombier  */
1198*593dc095SDavid du Colombier private	int
get_pdf14_device_proto(gx_device * dev,const pdf14_device ** pdevproto)1199*593dc095SDavid du Colombier get_pdf14_device_proto(gx_device * dev,
1200*593dc095SDavid du Colombier 		const pdf14_device ** pdevproto)
1201*593dc095SDavid du Colombier {
1202*593dc095SDavid du Colombier     pdf14_default_colorspace_t dev_cs =
1203*593dc095SDavid du Colombier 		pdf14_determine_default_blend_cs(dev);
1204*593dc095SDavid du Colombier 
1205*593dc095SDavid du Colombier     switch (dev_cs) {
1206*593dc095SDavid du Colombier 	case DeviceGray:
1207*593dc095SDavid du Colombier 	    *pdevproto = &gs_pdf14_Gray_device;
1208*593dc095SDavid du Colombier 	    break;
1209*593dc095SDavid du Colombier 	case DeviceRGB:
1210*593dc095SDavid du Colombier 	    *pdevproto = &gs_pdf14_RGB_device;
1211*593dc095SDavid du Colombier 	    break;
1212*593dc095SDavid du Colombier 	case DeviceCMYK:
1213*593dc095SDavid du Colombier 	    *pdevproto = &gs_pdf14_CMYK_device;
1214*593dc095SDavid du Colombier 	    break;
1215*593dc095SDavid du Colombier 	default:			/* Should not occur */
1216*593dc095SDavid du Colombier 	    return_error(gs_error_rangecheck);
1217*593dc095SDavid du Colombier     }
1218*593dc095SDavid du Colombier     return 0;
1219*593dc095SDavid du Colombier }
1220*593dc095SDavid du Colombier 
1221*593dc095SDavid du Colombier /*
1222*593dc095SDavid du Colombier  * Recreate the PDF 1.4 compositor device.  Once created, the PDF 1.4
1223*593dc095SDavid du Colombier  * compositor device is never removed.  (We do not have a remove compositor
1224*593dc095SDavid du Colombier  * method.)  However it is no-op'ed when the PDF 1.4 device is popped.  This
1225*593dc095SDavid du Colombier  * routine will re-enable the compositor if the PDF 1.4 device is pushed
1226*593dc095SDavid du Colombier  * again.
1227*593dc095SDavid du Colombier  */
1228*593dc095SDavid du Colombier private	int
pdf14_recreate_device(gs_memory_t * mem,gs_imager_state * pis,gx_device * dev)1229*593dc095SDavid du Colombier pdf14_recreate_device(gs_memory_t *mem,	gs_imager_state	* pis,
1230*593dc095SDavid du Colombier 				gx_device * dev)
1231*593dc095SDavid du Colombier {
1232*593dc095SDavid du Colombier     pdf14_device * pdev = (pdf14_device *)dev;
1233*593dc095SDavid du Colombier     gx_device * target = pdev->target;
1234*593dc095SDavid du Colombier     const pdf14_device * dev_proto;
1235*593dc095SDavid du Colombier     int code;
1236*593dc095SDavid du Colombier 
1237*593dc095SDavid du Colombier     if_debug0('v', "[v]pdf14_recreate_device\n");
1238*593dc095SDavid du Colombier 
1239*593dc095SDavid du Colombier     /*
1240*593dc095SDavid du Colombier      * We will not use the entire prototype device but we will set the
1241*593dc095SDavid du Colombier      * color related info and the device procs to match the prototype.
1242*593dc095SDavid du Colombier      */
1243*593dc095SDavid du Colombier     code = get_pdf14_device_proto(target, &dev_proto);
1244*593dc095SDavid du Colombier     if (code < 0)
1245*593dc095SDavid du Colombier 	return code;
1246*593dc095SDavid du Colombier     pdev->color_info = dev_proto->color_info;
1247*593dc095SDavid du Colombier     pdev->procs = dev_proto->procs;
1248*593dc095SDavid du Colombier     gx_device_fill_in_procs(dev);
1249*593dc095SDavid du Colombier     check_device_separable((gx_device *)pdev);
1250*593dc095SDavid du Colombier 
1251*593dc095SDavid du Colombier     return code;
1252*593dc095SDavid du Colombier }
1253*593dc095SDavid du Colombier 
1254*593dc095SDavid du Colombier /*
1255*593dc095SDavid du Colombier  * Implement the various operations that can be specified via the PDF 1.4
1256*593dc095SDavid du Colombier  * create compositor request.
1257*593dc095SDavid du Colombier  */
1258*593dc095SDavid du Colombier private	int
gx_update_pdf14_compositor(gx_device * pdev,gs_imager_state * pis,const gs_pdf14trans_t * pdf14pct,gs_memory_t * mem)1259*593dc095SDavid du Colombier gx_update_pdf14_compositor(gx_device * pdev, gs_imager_state * pis,
1260*593dc095SDavid du Colombier     const gs_pdf14trans_t * pdf14pct, gs_memory_t * mem )
1261*593dc095SDavid du Colombier {
1262*593dc095SDavid du Colombier     pdf14_device *p14dev = (pdf14_device *)pdev;
1263*593dc095SDavid du Colombier     int code = 0;
1264*593dc095SDavid du Colombier 
1265*593dc095SDavid du Colombier     switch (pdf14pct->params.pdf14_op) {
1266*593dc095SDavid du Colombier 	default:			/* Should not occur. */
1267*593dc095SDavid du Colombier 	    break;
1268*593dc095SDavid du Colombier 	case PDF14_PUSH_DEVICE:
1269*593dc095SDavid du Colombier 	    p14dev->blend_mode = 0;
1270*593dc095SDavid du Colombier 	    p14dev->opacity = p14dev->shape = 0.0;
1271*593dc095SDavid du Colombier 	    pdf14_recreate_device(mem, pis, pdev);
1272*593dc095SDavid du Colombier 	    break;
1273*593dc095SDavid du Colombier 	case PDF14_POP_DEVICE:
1274*593dc095SDavid du Colombier 	    pis->get_cmap_procs = p14dev->save_get_cmap_procs;
1275*593dc095SDavid du Colombier 	    gx_set_cmap_procs(pis, p14dev->target);
1276*593dc095SDavid du Colombier 	    code = pdf14_put_image(p14dev, pis, p14dev->target);
1277*593dc095SDavid du Colombier 	    pdf14_disable_device(pdev);
1278*593dc095SDavid du Colombier 	    pdf14_close(pdev);
1279*593dc095SDavid du Colombier 	    break;
1280*593dc095SDavid du Colombier 	case PDF14_BEGIN_TRANS_GROUP:
1281*593dc095SDavid du Colombier 	    code = gx_begin_transparency_group(pis, pdev, &pdf14pct->params);
1282*593dc095SDavid du Colombier 	    break;
1283*593dc095SDavid du Colombier 	case PDF14_END_TRANS_GROUP:
1284*593dc095SDavid du Colombier 	    code = gx_end_transparency_group(pis, pdev);
1285*593dc095SDavid du Colombier 	    break;
1286*593dc095SDavid du Colombier 	case PDF14_INIT_TRANS_MASK:
1287*593dc095SDavid du Colombier 	    code = gx_init_transparency_mask(pis, &pdf14pct->params);
1288*593dc095SDavid du Colombier 	    break;
1289*593dc095SDavid du Colombier 	case PDF14_BEGIN_TRANS_MASK:
1290*593dc095SDavid du Colombier 	    code = gx_begin_transparency_mask(pis, pdev, &pdf14pct->params);
1291*593dc095SDavid du Colombier 	    break;
1292*593dc095SDavid du Colombier 	case PDF14_END_TRANS_MASK:
1293*593dc095SDavid du Colombier 	    code = gx_end_transparency_mask(pis, pdev, &pdf14pct->params);
1294*593dc095SDavid du Colombier 	    break;
1295*593dc095SDavid du Colombier 	case PDF14_SET_BLEND_PARAMS:
1296*593dc095SDavid du Colombier 	    pdf14_set_params(pis, pdev, &pdf14pct->params);
1297*593dc095SDavid du Colombier 	    break;
1298*593dc095SDavid du Colombier     }
1299*593dc095SDavid du Colombier     return code;
1300*593dc095SDavid du Colombier }
1301*593dc095SDavid du Colombier 
1302*593dc095SDavid du Colombier /*
1303*593dc095SDavid du Colombier  * The PDF 1.4 compositor is never removed.  (We do not have a 'remove
1304*593dc095SDavid du Colombier  * compositor' method.  However the compositor is disabled when we are not
1305*593dc095SDavid du Colombier  * doing a page which uses PDF 1.4 transparency.  This routine is only active
1306*593dc095SDavid du Colombier  * when the PDF 1.4 compositor is 'disabled'.  It checks for reenabling the
1307*593dc095SDavid du Colombier  * PDF 1.4 compositor.  Otherwise it simply passes create compositor requests
1308*593dc095SDavid du Colombier  * to the targer.
1309*593dc095SDavid du Colombier  */
1310*593dc095SDavid du Colombier private	int
pdf14_forward_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pct,gs_imager_state * pis,gs_memory_t * mem)1311*593dc095SDavid du Colombier pdf14_forward_create_compositor(gx_device * dev, gx_device * * pcdev,
1312*593dc095SDavid du Colombier 	const gs_composite_t * pct, gs_imager_state * pis,
1313*593dc095SDavid du Colombier 	gs_memory_t * mem)
1314*593dc095SDavid du Colombier {
1315*593dc095SDavid du Colombier     pdf14_device *pdev = (pdf14_device *)dev;
1316*593dc095SDavid du Colombier     gx_device * tdev = pdev->target;
1317*593dc095SDavid du Colombier     gx_device * ndev;
1318*593dc095SDavid du Colombier     int code = 0;
1319*593dc095SDavid du Colombier 
1320*593dc095SDavid du Colombier     *pcdev = dev;
1321*593dc095SDavid du Colombier     if (gs_is_pdf14trans_compositor(pct)) {
1322*593dc095SDavid du Colombier 	const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pct;
1323*593dc095SDavid du Colombier 
1324*593dc095SDavid du Colombier 	if (pdf14pct->params.pdf14_op == PDF14_PUSH_DEVICE)
1325*593dc095SDavid du Colombier 	    return gx_update_pdf14_compositor(dev, pis, pdf14pct, mem);
1326*593dc095SDavid du Colombier 	return 0;
1327*593dc095SDavid du Colombier     }
1328*593dc095SDavid du Colombier     code = dev_proc(tdev, create_compositor)(tdev, &ndev, pct, pis, mem);
1329*593dc095SDavid du Colombier     if (code < 0)
1330*593dc095SDavid du Colombier 	return code;
1331*593dc095SDavid du Colombier     pdev->target = ndev;
1332*593dc095SDavid du Colombier     return 0;
1333*593dc095SDavid du Colombier }
1334*593dc095SDavid du Colombier 
1335*593dc095SDavid du Colombier /*
1336*593dc095SDavid du Colombier  * The PDF 1.4 compositor can be handled directly, so just set *pcdev = dev
1337*593dc095SDavid du Colombier  * and return. Since the gs_pdf14_device only supports the high-level routines
1338*593dc095SDavid du Colombier  * of the interface, don't bother trying to handle any other compositor.
1339*593dc095SDavid du Colombier  */
1340*593dc095SDavid du Colombier private	int
pdf14_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pct,gs_imager_state * pis,gs_memory_t * mem)1341*593dc095SDavid du Colombier pdf14_create_compositor(gx_device * dev, gx_device * * pcdev,
1342*593dc095SDavid du Colombier 	const gs_composite_t * pct, gs_imager_state * pis,
1343*593dc095SDavid du Colombier 	gs_memory_t * mem)
1344*593dc095SDavid du Colombier {
1345*593dc095SDavid du Colombier     if (gs_is_pdf14trans_compositor(pct)) {
1346*593dc095SDavid du Colombier 	const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pct;
1347*593dc095SDavid du Colombier 
1348*593dc095SDavid du Colombier 	*pcdev = dev;
1349*593dc095SDavid du Colombier 	return gx_update_pdf14_compositor(dev, pis, pdf14pct, mem);
1350*593dc095SDavid du Colombier     } else if (gs_is_overprint_compositor(pct)) {
1351*593dc095SDavid du Colombier 	*pcdev = dev;
1352*593dc095SDavid du Colombier 	return 0;
1353*593dc095SDavid du Colombier     } else
1354*593dc095SDavid du Colombier 	return gx_no_create_compositor(dev, pcdev, pct, pis, mem);
1355*593dc095SDavid du Colombier }
13563ff48bf5SDavid du Colombier 
13573ff48bf5SDavid du Colombier private	int
pdf14_text_begin(gx_device * dev,gs_imager_state * pis,const gs_text_params_t * text,gs_font * font,gx_path * path,const gx_device_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gs_text_enum_t ** ppenum)13583ff48bf5SDavid du Colombier pdf14_text_begin(gx_device * dev, gs_imager_state * pis,
13593ff48bf5SDavid du Colombier 		 const gs_text_params_t * text, gs_font * font,
13603ff48bf5SDavid du Colombier 		 gx_path * path, const gx_device_color * pdcolor,
13613ff48bf5SDavid du Colombier 		 const gx_clip_path * pcpath, gs_memory_t * memory,
13623ff48bf5SDavid du Colombier 		 gs_text_enum_t ** ppenum)
13633ff48bf5SDavid du Colombier {
13643ff48bf5SDavid du Colombier     int code;
1365*593dc095SDavid du Colombier     gs_text_enum_t *penum;
13663ff48bf5SDavid du Colombier 
13673ff48bf5SDavid du Colombier     if_debug0('v', "[v]pdf14_text_begin\n");
1368*593dc095SDavid du Colombier     pdf14_set_marking_params(dev, pis);
1369*593dc095SDavid du Colombier     code = gx_default_text_begin(dev, pis, text, font, path, pdcolor, pcpath,
1370*593dc095SDavid du Colombier 				 memory, &penum);
1371*593dc095SDavid du Colombier     if (code < 0)
13723ff48bf5SDavid du Colombier 	return code;
13733ff48bf5SDavid du Colombier     *ppenum = (gs_text_enum_t *)penum;
13743ff48bf5SDavid du Colombier     return code;
13753ff48bf5SDavid du Colombier }
13763ff48bf5SDavid du Colombier 
13773ff48bf5SDavid du Colombier private	int
pdf14_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)13783ff48bf5SDavid du Colombier pdf14_fill_rectangle(gx_device * dev,
13793ff48bf5SDavid du Colombier 		    int x, int y, int w, int h, gx_color_index color)
13803ff48bf5SDavid du Colombier {
1381*593dc095SDavid du Colombier     pdf14_device *pdev = (pdf14_device *)dev;
1382*593dc095SDavid du Colombier     pdf14_buf *buf = pdev->ctx->stack;
13833ff48bf5SDavid du Colombier 
1384*593dc095SDavid du Colombier     fit_fill_xywh(dev, x, y, w, h);
1385*593dc095SDavid du Colombier     if (w <= 0 || h <= 0)
1386*593dc095SDavid du Colombier 	return 0;
1387*593dc095SDavid du Colombier     if (buf->knockout)
1388*593dc095SDavid du Colombier 	return pdf14_mark_fill_rectangle_ko_simple(dev, x, y, w, h, color);
1389*593dc095SDavid du Colombier     else
1390*593dc095SDavid du Colombier 	return pdf14_mark_fill_rectangle(dev, x, y, w, h, color);
1391*593dc095SDavid du Colombier }
13923ff48bf5SDavid du Colombier 
13933ff48bf5SDavid du Colombier private	int
pdf14_begin_transparency_group(gx_device * dev,const gs_transparency_group_params_t * ptgp,const gs_rect * pbbox,gs_imager_state * pis,gs_transparency_state_t ** ppts,gs_memory_t * mem)13943ff48bf5SDavid du Colombier pdf14_begin_transparency_group(gx_device *dev,
13953ff48bf5SDavid du Colombier 			      const gs_transparency_group_params_t *ptgp,
13963ff48bf5SDavid du Colombier 			      const gs_rect *pbbox,
13973ff48bf5SDavid du Colombier 			      gs_imager_state *pis,
13983ff48bf5SDavid du Colombier 			      gs_transparency_state_t **ppts,
13993ff48bf5SDavid du Colombier 			      gs_memory_t *mem)
14003ff48bf5SDavid du Colombier {
14013ff48bf5SDavid du Colombier     pdf14_device *pdev = (pdf14_device *)dev;
14023ff48bf5SDavid du Colombier     double alpha = pis->opacity.alpha * pis->shape.alpha;
1403*593dc095SDavid du Colombier     gs_rect dev_bbox;
1404*593dc095SDavid du Colombier     gs_int_rect rect;
14053ff48bf5SDavid du Colombier     int code;
14063ff48bf5SDavid du Colombier 
1407*593dc095SDavid du Colombier     code = gs_bbox_transform(pbbox, &ctm_only(pis), &dev_bbox);
1408*593dc095SDavid du Colombier     if (code < 0)
1409*593dc095SDavid du Colombier 	return code;
1410*593dc095SDavid du Colombier     rect.p.x = (int)floor(dev_bbox.p.x);
1411*593dc095SDavid du Colombier     rect.p.y = (int)floor(dev_bbox.p.y);
1412*593dc095SDavid du Colombier     rect.q.x = (int)ceil(dev_bbox.q.x);
1413*593dc095SDavid du Colombier     rect.q.y = (int)ceil(dev_bbox.q.y);
1414*593dc095SDavid du Colombier     rect_intersect(rect, pdev->ctx->rect);
14153ff48bf5SDavid du Colombier     if_debug4('v', "[v]begin_transparency_group, I = %d, K = %d, alpha = %g, bm = %d\n",
14163ff48bf5SDavid du Colombier 	      ptgp->Isolated, ptgp->Knockout, alpha, pis->blend_mode);
1417*593dc095SDavid du Colombier     code = pdf14_push_transparency_group(pdev->ctx, &rect,
14183ff48bf5SDavid du Colombier 					 ptgp->Isolated, ptgp->Knockout,
1419*593dc095SDavid du Colombier 					 (byte)floor (255 * alpha + 0.5),
1420*593dc095SDavid du Colombier 					 (byte)floor (255 * pis->shape.alpha + 0.5),
14213ff48bf5SDavid du Colombier 					 pis->blend_mode);
14223ff48bf5SDavid du Colombier     return code;
14233ff48bf5SDavid du Colombier }
14243ff48bf5SDavid du Colombier 
14253ff48bf5SDavid du Colombier private	int
pdf14_end_transparency_group(gx_device * dev,gs_imager_state * pis,gs_transparency_state_t ** ppts)14263ff48bf5SDavid du Colombier pdf14_end_transparency_group(gx_device *dev,
14273ff48bf5SDavid du Colombier 			      gs_imager_state *pis,
14283ff48bf5SDavid du Colombier 			      gs_transparency_state_t **ppts)
14293ff48bf5SDavid du Colombier {
14303ff48bf5SDavid du Colombier     pdf14_device *pdev = (pdf14_device *)dev;
14313ff48bf5SDavid du Colombier     int code;
14323ff48bf5SDavid du Colombier 
14333ff48bf5SDavid du Colombier     if_debug0('v', "[v]end_transparency_group\n");
14343ff48bf5SDavid du Colombier     code = pdf14_pop_transparency_group(pdev->ctx);
14353ff48bf5SDavid du Colombier     return code;
14363ff48bf5SDavid du Colombier }
14373ff48bf5SDavid du Colombier 
14383ff48bf5SDavid du Colombier private	int
pdf14_begin_transparency_mask(gx_device * dev,const gx_transparency_mask_params_t * ptmp,const gs_rect * pbbox,gs_imager_state * pis,gs_transparency_state_t ** ppts,gs_memory_t * mem)1439*593dc095SDavid du Colombier pdf14_begin_transparency_mask(gx_device	*dev,
1440*593dc095SDavid du Colombier 			      const gx_transparency_mask_params_t *ptmp,
1441*593dc095SDavid du Colombier 			      const gs_rect *pbbox,
1442*593dc095SDavid du Colombier 			      gs_imager_state *pis,
1443*593dc095SDavid du Colombier 			      gs_transparency_state_t **ppts,
1444*593dc095SDavid du Colombier 			      gs_memory_t *mem)
1445*593dc095SDavid du Colombier {
1446*593dc095SDavid du Colombier     pdf14_device *pdev = (pdf14_device *)dev;
1447*593dc095SDavid du Colombier     byte bg_alpha = 0;
1448*593dc095SDavid du Colombier     byte *transfer_fn = (byte *)gs_alloc_bytes(pdev->ctx->memory, 256,
1449*593dc095SDavid du Colombier 					       "pdf14_push_transparency_mask");
1450*593dc095SDavid du Colombier 
1451*593dc095SDavid du Colombier     if (ptmp->Background_components)
1452*593dc095SDavid du Colombier 	bg_alpha = (int)(255 * ptmp->Background[0] + 0.5);
1453*593dc095SDavid du Colombier     if_debug1('v', "begin transparency mask, bg_alpha = %d\n", bg_alpha);
1454*593dc095SDavid du Colombier     memcpy(transfer_fn, ptmp->transfer_fn, size_of(ptmp->transfer_fn));
1455*593dc095SDavid du Colombier     return pdf14_push_transparency_mask(pdev->ctx, &pdev->ctx->rect, bg_alpha,
1456*593dc095SDavid du Colombier 					transfer_fn);
1457*593dc095SDavid du Colombier }
1458*593dc095SDavid du Colombier 
1459*593dc095SDavid du Colombier private	int
pdf14_end_transparency_mask(gx_device * dev,gs_transparency_mask_t ** pptm)1460*593dc095SDavid du Colombier pdf14_end_transparency_mask(gx_device *dev,
1461*593dc095SDavid du Colombier 			  gs_transparency_mask_t **pptm)
1462*593dc095SDavid du Colombier {
1463*593dc095SDavid du Colombier     pdf14_device *pdev = (pdf14_device *)dev;
1464*593dc095SDavid du Colombier 
1465*593dc095SDavid du Colombier     if_debug0('v', "end transparency mask!\n");
1466*593dc095SDavid du Colombier     return pdf14_pop_transparency_mask(pdev->ctx);
1467*593dc095SDavid du Colombier }
1468*593dc095SDavid du Colombier 
1469*593dc095SDavid du Colombier private	int
pdf14_mark_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)14703ff48bf5SDavid du Colombier pdf14_mark_fill_rectangle(gx_device * dev,
14713ff48bf5SDavid du Colombier 			 int x, int y, int w, int h, gx_color_index color)
14723ff48bf5SDavid du Colombier {
1473*593dc095SDavid du Colombier     pdf14_device *pdev = (pdf14_device *)dev;
14743ff48bf5SDavid du Colombier     pdf14_buf *buf = pdev->ctx->stack;
14753ff48bf5SDavid du Colombier     int i, j, k;
14763ff48bf5SDavid du Colombier     byte *line, *dst_ptr;
14773ff48bf5SDavid du Colombier     byte src[PDF14_MAX_PLANES];
14783ff48bf5SDavid du Colombier     byte dst[PDF14_MAX_PLANES];
1479*593dc095SDavid du Colombier     gs_blend_mode_t blend_mode = pdev->blend_mode;
1480*593dc095SDavid du Colombier     bool additive = pdev->ctx->additive;
14813ff48bf5SDavid du Colombier     int rowstride = buf->rowstride;
14823ff48bf5SDavid du Colombier     int planestride = buf->planestride;
14833ff48bf5SDavid du Colombier     bool has_alpha_g = buf->has_alpha_g;
14843ff48bf5SDavid du Colombier     bool has_shape = buf->has_shape;
1485*593dc095SDavid du Colombier     int num_chan = buf->n_chan;
1486*593dc095SDavid du Colombier     int num_comp = num_chan - 1;
1487*593dc095SDavid du Colombier     int shape_off = num_chan * planestride;
14883ff48bf5SDavid du Colombier     int alpha_g_off = shape_off + (has_shape ? planestride : 0);
1489*593dc095SDavid du Colombier     byte shape = 0; /* Quiet compiler. */
1490*593dc095SDavid du Colombier     byte src_alpha;
14913ff48bf5SDavid du Colombier 
1492*593dc095SDavid du Colombier     if_debug7('v', "[v]pdf14_mark_fill_rectangle, (%d, %d), %d x %d color = %lx  bm %d, nc %d,\n", x, y, w, h, color, blend_mode, num_chan);
1493*593dc095SDavid du Colombier 
1494*593dc095SDavid du Colombier     /* Complement the components for subtractive color spaces */
1495*593dc095SDavid du Colombier     if (additive) {
1496*593dc095SDavid du Colombier 	for (i = num_comp - 1; i >= 0; i--) {
1497*593dc095SDavid du Colombier 	    src[i] = (byte)(color & 0xff);
1498*593dc095SDavid du Colombier 	    color >>= 8;
1499*593dc095SDavid du Colombier 	}
1500*593dc095SDavid du Colombier     }
1501*593dc095SDavid du Colombier     else {
1502*593dc095SDavid du Colombier 	for (i = num_comp - 1; i >= 0; i--) {
1503*593dc095SDavid du Colombier 	    src[i] = (byte)(0xff - (color & 0xff));
1504*593dc095SDavid du Colombier 	    color >>= 8;
1505*593dc095SDavid du Colombier 	}
1506*593dc095SDavid du Colombier     }
1507*593dc095SDavid du Colombier     src_alpha = src[num_comp] = (byte)floor (255 * pdev->alpha + 0.5);
15083ff48bf5SDavid du Colombier     if (has_shape)
1509*593dc095SDavid du Colombier 	shape = (byte)floor (255 * pdev->shape + 0.5);
15103ff48bf5SDavid du Colombier 
15113ff48bf5SDavid du Colombier     if (x < buf->rect.p.x) x = buf->rect.p.x;
1512*593dc095SDavid du Colombier     if (y < buf->rect.p.y) y = buf->rect.p.y;
15133ff48bf5SDavid du Colombier     if (x + w > buf->rect.q.x) w = buf->rect.q.x - x;
15143ff48bf5SDavid du Colombier     if (y + h > buf->rect.q.y) h = buf->rect.q.y - y;
15153ff48bf5SDavid du Colombier 
1516*593dc095SDavid du Colombier     if (x < buf->bbox.p.x) buf->bbox.p.x = x;
1517*593dc095SDavid du Colombier     if (y < buf->bbox.p.y) buf->bbox.p.y = y;
1518*593dc095SDavid du Colombier     if (x + w > buf->bbox.q.x) buf->bbox.q.x = x + w;
1519*593dc095SDavid du Colombier     if (y + h > buf->bbox.q.y) buf->bbox.q.y = y + h;
1520*593dc095SDavid du Colombier 
15213ff48bf5SDavid du Colombier     line = buf->data + (x - buf->rect.p.x) + (y - buf->rect.p.y) * rowstride;
15223ff48bf5SDavid du Colombier 
15233ff48bf5SDavid du Colombier     for (j = 0; j < h; ++j) {
15243ff48bf5SDavid du Colombier 	dst_ptr = line;
15253ff48bf5SDavid du Colombier 	for (i = 0; i < w; ++i) {
1526*593dc095SDavid du Colombier 	    /* Complement the components for subtractive color spaces */
1527*593dc095SDavid du Colombier 	    if (additive) {
1528*593dc095SDavid du Colombier 		for (k = 0; k < num_chan; ++k)
15293ff48bf5SDavid du Colombier 		    dst[k] = dst_ptr[k * planestride];
1530*593dc095SDavid du Colombier 	    }
1531*593dc095SDavid du Colombier 	    else { /* Complement the components for subtractive color spaces */
1532*593dc095SDavid du Colombier 		for (k = 0; k < num_comp; ++k)
1533*593dc095SDavid du Colombier 		    dst[k] = 255 - dst_ptr[k * planestride];
1534*593dc095SDavid du Colombier 		dst[num_comp] = dst_ptr[num_comp * planestride];
1535*593dc095SDavid du Colombier 	    }
1536*593dc095SDavid du Colombier 	    art_pdf_composite_pixel_alpha_8(dst, src, num_comp, blend_mode);
1537*593dc095SDavid du Colombier 	    /* Complement the results for subtractive color spaces */
1538*593dc095SDavid du Colombier 	    if (additive) {
1539*593dc095SDavid du Colombier 		for (k = 0; k < num_chan; ++k)
15403ff48bf5SDavid du Colombier 		    dst_ptr[k * planestride] = dst[k];
1541*593dc095SDavid du Colombier 	    }
1542*593dc095SDavid du Colombier 	    else {
1543*593dc095SDavid du Colombier 		for (k = 0; k < num_comp; ++k)
1544*593dc095SDavid du Colombier 		    dst_ptr[k * planestride] = 255 - dst[k];
1545*593dc095SDavid du Colombier 		dst_ptr[num_comp * planestride] = dst[num_comp];
1546*593dc095SDavid du Colombier 	    }
15473ff48bf5SDavid du Colombier 	    if (has_alpha_g) {
1548*593dc095SDavid du Colombier 		int tmp = (255 - dst_ptr[alpha_g_off]) * (255 - src_alpha) + 0x80;
15493ff48bf5SDavid du Colombier 		dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
15503ff48bf5SDavid du Colombier 	    }
15513ff48bf5SDavid du Colombier 	    if (has_shape) {
15523ff48bf5SDavid du Colombier 		int tmp = (255 - dst_ptr[shape_off]) * (255 - shape) + 0x80;
15533ff48bf5SDavid du Colombier 		dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
15543ff48bf5SDavid du Colombier 	    }
15553ff48bf5SDavid du Colombier 	    ++dst_ptr;
15563ff48bf5SDavid du Colombier 	}
15573ff48bf5SDavid du Colombier 	line += rowstride;
15583ff48bf5SDavid du Colombier     }
15593ff48bf5SDavid du Colombier     return 0;
15603ff48bf5SDavid du Colombier }
15613ff48bf5SDavid du Colombier 
15623ff48bf5SDavid du Colombier private	int
pdf14_mark_fill_rectangle_ko_simple(gx_device * dev,int x,int y,int w,int h,gx_color_index color)15633ff48bf5SDavid du Colombier pdf14_mark_fill_rectangle_ko_simple(gx_device *	dev,
15643ff48bf5SDavid du Colombier 				   int x, int y, int w, int h, gx_color_index color)
15653ff48bf5SDavid du Colombier {
1566*593dc095SDavid du Colombier     pdf14_device *pdev = (pdf14_device *)dev;
15673ff48bf5SDavid du Colombier     pdf14_buf *buf = pdev->ctx->stack;
15683ff48bf5SDavid du Colombier     int i, j, k;
15693ff48bf5SDavid du Colombier     byte *line, *dst_ptr;
15703ff48bf5SDavid du Colombier     byte src[PDF14_MAX_PLANES];
15713ff48bf5SDavid du Colombier     byte dst[PDF14_MAX_PLANES];
15723ff48bf5SDavid du Colombier     int rowstride = buf->rowstride;
15733ff48bf5SDavid du Colombier     int planestride = buf->planestride;
1574*593dc095SDavid du Colombier     int num_chan = buf->n_chan;
1575*593dc095SDavid du Colombier     int num_comp = num_chan - 1;
1576*593dc095SDavid du Colombier     int shape_off = num_chan * planestride;
15773ff48bf5SDavid du Colombier     bool has_shape = buf->has_shape;
15783ff48bf5SDavid du Colombier     byte opacity;
1579*593dc095SDavid du Colombier     bool additive = pdev->ctx->additive;
15803ff48bf5SDavid du Colombier 
1581*593dc095SDavid du Colombier     if_debug6('v', "[v]pdf14_mark_fill_rectangle_ko_simple, (%d, %d), %d x %d color = %lx  bm %d, nc %d,\n", x, y, w, h, color, num_chan);
1582*593dc095SDavid du Colombier 
1583*593dc095SDavid du Colombier     /* Complement the components for subtractive color spaces */
1584*593dc095SDavid du Colombier     if (additive) {
1585*593dc095SDavid du Colombier 	for (i = num_comp - 1; i >= 0; i--) {
1586*593dc095SDavid du Colombier 	    src[i] = (byte)(color & 0xff);
1587*593dc095SDavid du Colombier 	    color >>= 8;
1588*593dc095SDavid du Colombier 	}
1589*593dc095SDavid du Colombier     }
1590*593dc095SDavid du Colombier     else {
1591*593dc095SDavid du Colombier 	for (i = num_comp - 1; i >= 0; i--) {
1592*593dc095SDavid du Colombier 	    src[i] = (byte)(0xff - (color & 0xff));
1593*593dc095SDavid du Colombier 	    color >>= 8;
1594*593dc095SDavid du Colombier 	}
1595*593dc095SDavid du Colombier     }
1596*593dc095SDavid du Colombier     src[num_comp] = (byte)floor (255 * pdev->alpha + 0.5);
1597*593dc095SDavid du Colombier     opacity = (byte)floor (255 * pdev->opacity + 0.5);
15983ff48bf5SDavid du Colombier 
15993ff48bf5SDavid du Colombier     if (x < buf->rect.p.x) x = buf->rect.p.x;
1600*593dc095SDavid du Colombier     if (y < buf->rect.p.y) y = buf->rect.p.y;
16013ff48bf5SDavid du Colombier     if (x + w > buf->rect.q.x) w = buf->rect.q.x - x;
16023ff48bf5SDavid du Colombier     if (y + h > buf->rect.q.y) h = buf->rect.q.y - y;
16033ff48bf5SDavid du Colombier 
1604*593dc095SDavid du Colombier     if (x < buf->bbox.p.x) buf->bbox.p.x = x;
1605*593dc095SDavid du Colombier     if (y < buf->bbox.p.y) buf->bbox.p.y = y;
1606*593dc095SDavid du Colombier     if (x + w > buf->bbox.q.x) buf->bbox.q.x = x + w;
1607*593dc095SDavid du Colombier     if (y + h > buf->bbox.q.y) buf->bbox.q.y = y + h;
1608*593dc095SDavid du Colombier 
16093ff48bf5SDavid du Colombier     line = buf->data + (x - buf->rect.p.x) + (y - buf->rect.p.y) * rowstride;
16103ff48bf5SDavid du Colombier 
16113ff48bf5SDavid du Colombier     for (j = 0; j < h; ++j) {
16123ff48bf5SDavid du Colombier 	dst_ptr = line;
16133ff48bf5SDavid du Colombier 	for (i = 0; i < w; ++i) {
1614*593dc095SDavid du Colombier 	    /* Complement the components for subtractive color spaces */
1615*593dc095SDavid du Colombier 	    if (additive) {
1616*593dc095SDavid du Colombier 		for (k = 0; k < num_chan; ++k)
16173ff48bf5SDavid du Colombier 		    dst[k] = dst_ptr[k * planestride];
1618*593dc095SDavid du Colombier 	    }
1619*593dc095SDavid du Colombier 	    else {
1620*593dc095SDavid du Colombier 		for (k = 0; k < num_comp; ++k)
1621*593dc095SDavid du Colombier 		    dst[k] = 255 - dst_ptr[k * planestride];
1622*593dc095SDavid du Colombier 		dst[num_comp] = dst_ptr[num_comp * planestride];
1623*593dc095SDavid du Colombier 	    }
1624*593dc095SDavid du Colombier 	    art_pdf_composite_knockout_simple_8(dst,
1625*593dc095SDavid du Colombier 		has_shape ? dst_ptr + shape_off : NULL, src, num_comp, opacity);
1626*593dc095SDavid du Colombier 	    /* Complement the results for subtractive color spaces */
1627*593dc095SDavid du Colombier 	    if (additive) {
1628*593dc095SDavid du Colombier 		for (k = 0; k < num_chan; ++k)
16293ff48bf5SDavid du Colombier 		    dst_ptr[k * planestride] = dst[k];
1630*593dc095SDavid du Colombier 	    }
1631*593dc095SDavid du Colombier 	    else {
1632*593dc095SDavid du Colombier 		for (k = 0; k < num_comp; ++k)
1633*593dc095SDavid du Colombier 		    dst_ptr[k * planestride] = 255 - dst[k];
1634*593dc095SDavid du Colombier 		dst_ptr[num_comp * planestride] = dst[num_comp];
1635*593dc095SDavid du Colombier 	    }
16363ff48bf5SDavid du Colombier 	    ++dst_ptr;
16373ff48bf5SDavid du Colombier 	}
16383ff48bf5SDavid du Colombier 	line += rowstride;
16393ff48bf5SDavid du Colombier     }
16403ff48bf5SDavid du Colombier     return 0;
16413ff48bf5SDavid du Colombier }
16423ff48bf5SDavid du Colombier 
1643*593dc095SDavid du Colombier /**
1644*593dc095SDavid du Colombier  * Here we have logic to override the cmap_procs with versions that
1645*593dc095SDavid du Colombier  * do not apply the transfer function. These copies should track the
1646*593dc095SDavid du Colombier  * versions in gxcmap.c.
1647*593dc095SDavid du Colombier  **/
1648*593dc095SDavid du Colombier 
1649*593dc095SDavid du Colombier private	cmap_proc_gray(pdf14_cmap_gray_direct);
1650*593dc095SDavid du Colombier private	cmap_proc_rgb(pdf14_cmap_rgb_direct);
1651*593dc095SDavid du Colombier private	cmap_proc_cmyk(pdf14_cmap_cmyk_direct);
1652*593dc095SDavid du Colombier private	cmap_proc_rgb_alpha(pdf14_cmap_rgb_alpha_direct);
1653*593dc095SDavid du Colombier private	cmap_proc_separation(pdf14_cmap_separation_direct);
1654*593dc095SDavid du Colombier private	cmap_proc_devicen(pdf14_cmap_devicen_direct);
1655*593dc095SDavid du Colombier private	cmap_proc_is_halftoned(pdf14_cmap_is_halftoned);
1656*593dc095SDavid du Colombier 
1657*593dc095SDavid du Colombier private	const gx_color_map_procs pdf14_cmap_many = {
1658*593dc095SDavid du Colombier      pdf14_cmap_gray_direct,
1659*593dc095SDavid du Colombier      pdf14_cmap_rgb_direct,
1660*593dc095SDavid du Colombier      pdf14_cmap_cmyk_direct,
1661*593dc095SDavid du Colombier      pdf14_cmap_rgb_alpha_direct,
1662*593dc095SDavid du Colombier      pdf14_cmap_separation_direct,
1663*593dc095SDavid du Colombier      pdf14_cmap_devicen_direct,
1664*593dc095SDavid du Colombier      pdf14_cmap_is_halftoned
1665*593dc095SDavid du Colombier     };
1666*593dc095SDavid du Colombier 
1667*593dc095SDavid du Colombier /**
1668*593dc095SDavid du Colombier  * Note: copied from gxcmap.c because it's inlined.
1669*593dc095SDavid du Colombier  **/
1670*593dc095SDavid du Colombier private	inline void
map_components_to_colorants(const frac * pcc,const gs_devicen_color_map * pcolor_component_map,frac * plist)1671*593dc095SDavid du Colombier map_components_to_colorants(const frac * pcc,
1672*593dc095SDavid du Colombier 	const gs_devicen_color_map * pcolor_component_map, frac * plist)
1673*593dc095SDavid du Colombier {
1674*593dc095SDavid du Colombier     int i = pcolor_component_map->num_colorants - 1;
1675*593dc095SDavid du Colombier     int pos;
1676*593dc095SDavid du Colombier 
1677*593dc095SDavid du Colombier     /* Clear all output colorants first */
1678*593dc095SDavid du Colombier     for (; i >= 0; i--) {
1679*593dc095SDavid du Colombier 	plist[i] = frac_0;
1680*593dc095SDavid du Colombier     }
1681*593dc095SDavid du Colombier 
1682*593dc095SDavid du Colombier     /* Map color components into output list */
1683*593dc095SDavid du Colombier     for (i = pcolor_component_map->num_components - 1; i >= 0; i--) {
1684*593dc095SDavid du Colombier 	pos = pcolor_component_map->color_map[i];
1685*593dc095SDavid du Colombier 	if (pos >= 0)
1686*593dc095SDavid du Colombier 	    plist[pos] = pcc[i];
1687*593dc095SDavid du Colombier     }
1688*593dc095SDavid du Colombier }
1689*593dc095SDavid du Colombier 
1690*593dc095SDavid du Colombier private	void
pdf14_cmap_gray_direct(frac gray,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1691*593dc095SDavid du Colombier pdf14_cmap_gray_direct(frac gray, gx_device_color * pdc, const gs_imager_state * pis,
1692*593dc095SDavid du Colombier 		 gx_device * dev, gs_color_select_t select)
1693*593dc095SDavid du Colombier {
1694*593dc095SDavid du Colombier     int i, ncomps = dev->color_info.num_components;
1695*593dc095SDavid du Colombier     frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1696*593dc095SDavid du Colombier     gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1697*593dc095SDavid du Colombier     gx_color_index color;
1698*593dc095SDavid du Colombier 
1699*593dc095SDavid du Colombier     /* map to the color model */
1700*593dc095SDavid du Colombier     dev_proc(dev, get_color_mapping_procs)(dev)->map_gray(dev, gray, cm_comps);
1701*593dc095SDavid du Colombier 
1702*593dc095SDavid du Colombier     for (i = 0; i < ncomps; i++)
1703*593dc095SDavid du Colombier 	cv[i] = frac2cv(cm_comps[i]);
1704*593dc095SDavid du Colombier 
1705*593dc095SDavid du Colombier     /* encode as a color index */
1706*593dc095SDavid du Colombier     color = dev_proc(dev, encode_color)(dev, cv);
1707*593dc095SDavid du Colombier 
1708*593dc095SDavid du Colombier     /* check if the encoding was successful; we presume failure is rare */
1709*593dc095SDavid du Colombier     if (color != gx_no_color_index)
1710*593dc095SDavid du Colombier 	color_set_pure(pdc, color);
1711*593dc095SDavid du Colombier }
1712*593dc095SDavid du Colombier 
1713*593dc095SDavid du Colombier 
1714*593dc095SDavid du Colombier private	void
pdf14_cmap_rgb_direct(frac r,frac g,frac b,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1715*593dc095SDavid du Colombier pdf14_cmap_rgb_direct(frac r, frac g, frac b, gx_device_color *	pdc,
1716*593dc095SDavid du Colombier      const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
1717*593dc095SDavid du Colombier {
1718*593dc095SDavid du Colombier     int i, ncomps = dev->color_info.num_components;
1719*593dc095SDavid du Colombier     frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1720*593dc095SDavid du Colombier     gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1721*593dc095SDavid du Colombier     gx_color_index color;
1722*593dc095SDavid du Colombier 
1723*593dc095SDavid du Colombier     /* map to the color model */
1724*593dc095SDavid du Colombier     dev_proc(dev, get_color_mapping_procs)(dev)->map_rgb(dev, pis, r, g, b, cm_comps);
1725*593dc095SDavid du Colombier 
1726*593dc095SDavid du Colombier     for (i = 0; i < ncomps; i++)
1727*593dc095SDavid du Colombier 	cv[i] = frac2cv(cm_comps[i]);
1728*593dc095SDavid du Colombier 
1729*593dc095SDavid du Colombier     /* encode as a color index */
1730*593dc095SDavid du Colombier     color = dev_proc(dev, encode_color)(dev, cv);
1731*593dc095SDavid du Colombier 
1732*593dc095SDavid du Colombier     /* check if the encoding was successful; we presume failure is rare */
1733*593dc095SDavid du Colombier     if (color != gx_no_color_index)
1734*593dc095SDavid du Colombier 	color_set_pure(pdc, color);
1735*593dc095SDavid du Colombier }
1736*593dc095SDavid du Colombier 
1737*593dc095SDavid du Colombier private	void
pdf14_cmap_cmyk_direct(frac c,frac m,frac y,frac k,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1738*593dc095SDavid du Colombier pdf14_cmap_cmyk_direct(frac c, frac m, frac y, frac k, gx_device_color * pdc,
1739*593dc095SDavid du Colombier      const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
1740*593dc095SDavid du Colombier {
1741*593dc095SDavid du Colombier     int i, ncomps = dev->color_info.num_components;
1742*593dc095SDavid du Colombier     frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1743*593dc095SDavid du Colombier     gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1744*593dc095SDavid du Colombier     gx_color_index color;
1745*593dc095SDavid du Colombier 
1746*593dc095SDavid du Colombier     /* map to the color model */
1747*593dc095SDavid du Colombier     dev_proc(dev, get_color_mapping_procs)(dev)->map_cmyk(dev, c, m, y, k, cm_comps);
1748*593dc095SDavid du Colombier 
1749*593dc095SDavid du Colombier     for (i = 0; i < ncomps; i++)
1750*593dc095SDavid du Colombier 	cv[i] = frac2cv(cm_comps[i]);
1751*593dc095SDavid du Colombier 
1752*593dc095SDavid du Colombier     color = dev_proc(dev, encode_color)(dev, cv);
1753*593dc095SDavid du Colombier     if (color != gx_no_color_index)
1754*593dc095SDavid du Colombier 	color_set_pure(pdc, color);
1755*593dc095SDavid du Colombier }
1756*593dc095SDavid du Colombier 
1757*593dc095SDavid du Colombier private	void
pdf14_cmap_rgb_alpha_direct(frac r,frac g,frac b,frac alpha,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1758*593dc095SDavid du Colombier pdf14_cmap_rgb_alpha_direct(frac r, frac g, frac b, frac alpha,	gx_device_color	* pdc,
1759*593dc095SDavid du Colombier      const gs_imager_state * pis, gx_device * dev, gs_color_select_t select)
1760*593dc095SDavid du Colombier {
1761*593dc095SDavid du Colombier     int i, ncomps = dev->color_info.num_components;
1762*593dc095SDavid du Colombier     frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1763*593dc095SDavid du Colombier     gx_color_value cv_alpha, cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1764*593dc095SDavid du Colombier     gx_color_index color;
1765*593dc095SDavid du Colombier 
1766*593dc095SDavid du Colombier     /* map to the color model */
1767*593dc095SDavid du Colombier     dev_proc(dev, get_color_mapping_procs)(dev)->map_rgb(dev, pis, r, g, b, cm_comps);
1768*593dc095SDavid du Colombier 
1769*593dc095SDavid du Colombier     /* pre-multiply to account for the alpha weighting */
1770*593dc095SDavid du Colombier     if (alpha != frac_1) {
1771*593dc095SDavid du Colombier #ifdef PREMULTIPLY_TOWARDS_WHITE
1772*593dc095SDavid du Colombier 	frac alpha_bias = frac_1 - alpha;
1773*593dc095SDavid du Colombier #else
1774*593dc095SDavid du Colombier 	frac alpha_bias = 0;
1775*593dc095SDavid du Colombier #endif
1776*593dc095SDavid du Colombier 
1777*593dc095SDavid du Colombier 	for (i = 0; i < ncomps; i++)
1778*593dc095SDavid du Colombier 	    cm_comps[i] = (frac)((long)cm_comps[i] * alpha) / frac_1 + alpha_bias;
1779*593dc095SDavid du Colombier     }
1780*593dc095SDavid du Colombier 
1781*593dc095SDavid du Colombier     for (i = 0; i < ncomps; i++)
1782*593dc095SDavid du Colombier 	cv[i] = frac2cv(cm_comps[i]);
1783*593dc095SDavid du Colombier 
1784*593dc095SDavid du Colombier     /* encode as a color index */
1785*593dc095SDavid du Colombier     if (dev_proc(dev, map_rgb_alpha_color) != gx_default_map_rgb_alpha_color &&
1786*593dc095SDavid du Colombier 	 (cv_alpha = frac2cv(alpha)) != gx_max_color_value)
1787*593dc095SDavid du Colombier 	color = dev_proc(dev, map_rgb_alpha_color)(dev, cv[0], cv[1], cv[2], cv_alpha);
1788*593dc095SDavid du Colombier     else
1789*593dc095SDavid du Colombier 	color = dev_proc(dev, encode_color)(dev, cv);
1790*593dc095SDavid du Colombier 
1791*593dc095SDavid du Colombier     /* check if the encoding was successful; we presume failure is rare */
1792*593dc095SDavid du Colombier     if (color != gx_no_color_index)
1793*593dc095SDavid du Colombier 	color_set_pure(pdc, color);
1794*593dc095SDavid du Colombier }
1795*593dc095SDavid du Colombier 
1796*593dc095SDavid du Colombier 
1797*593dc095SDavid du Colombier private	void
pdf14_cmap_separation_direct(frac all,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1798*593dc095SDavid du Colombier pdf14_cmap_separation_direct(frac all, gx_device_color * pdc, const gs_imager_state * pis,
1799*593dc095SDavid du Colombier 		 gx_device * dev, gs_color_select_t select)
1800*593dc095SDavid du Colombier {
1801*593dc095SDavid du Colombier     int i, ncomps = dev->color_info.num_components;
1802*593dc095SDavid du Colombier     bool additive = dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE;
1803*593dc095SDavid du Colombier     frac comp_value = all;
1804*593dc095SDavid du Colombier     frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1805*593dc095SDavid du Colombier     gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1806*593dc095SDavid du Colombier     gx_color_index color;
1807*593dc095SDavid du Colombier 
1808*593dc095SDavid du Colombier     if (pis->color_component_map.sep_type == SEP_ALL) {
1809*593dc095SDavid du Colombier 	/*
1810*593dc095SDavid du Colombier 	 * Invert the photometric interpretation for additive
1811*593dc095SDavid du Colombier 	 * color spaces because separations are always subtractive.
1812*593dc095SDavid du Colombier 	 */
1813*593dc095SDavid du Colombier 	if (additive)
1814*593dc095SDavid du Colombier 	    comp_value = frac_1 - comp_value;
1815*593dc095SDavid du Colombier 
1816*593dc095SDavid du Colombier 	/* Use the "all" value for all components */
1817*593dc095SDavid du Colombier 	i = pis->color_component_map.num_colorants - 1;
1818*593dc095SDavid du Colombier 	for (; i >= 0; i--)
1819*593dc095SDavid du Colombier 	    cm_comps[i] = comp_value;
1820*593dc095SDavid du Colombier     }
1821*593dc095SDavid du Colombier     else {
1822*593dc095SDavid du Colombier 	/* map to the color model */
1823*593dc095SDavid du Colombier 	map_components_to_colorants(&comp_value, &(pis->color_component_map), cm_comps);
1824*593dc095SDavid du Colombier     }
1825*593dc095SDavid du Colombier 
1826*593dc095SDavid du Colombier     /* apply the transfer function(s); convert to color values */
1827*593dc095SDavid du Colombier     if (additive)
1828*593dc095SDavid du Colombier 	for (i = 0; i < ncomps; i++)
1829*593dc095SDavid du Colombier 	    cv[i] = frac2cv(gx_map_color_frac(pis,
1830*593dc095SDavid du Colombier 				cm_comps[i], effective_transfer[i]));
1831*593dc095SDavid du Colombier     else
1832*593dc095SDavid du Colombier 	for (i = 0; i < ncomps; i++)
1833*593dc095SDavid du Colombier 	    cv[i] = frac2cv(frac_1 - gx_map_color_frac(pis,
1834*593dc095SDavid du Colombier 			(frac)(frac_1 - cm_comps[i]), effective_transfer[i]));
1835*593dc095SDavid du Colombier 
1836*593dc095SDavid du Colombier     /* encode as a color index */
1837*593dc095SDavid du Colombier     color = dev_proc(dev, encode_color)(dev, cv);
1838*593dc095SDavid du Colombier 
1839*593dc095SDavid du Colombier     /* check if the encoding was successful; we presume failure is rare */
1840*593dc095SDavid du Colombier     if (color != gx_no_color_index)
1841*593dc095SDavid du Colombier 	color_set_pure(pdc, color);
1842*593dc095SDavid du Colombier }
1843*593dc095SDavid du Colombier 
1844*593dc095SDavid du Colombier 
1845*593dc095SDavid du Colombier private	void
pdf14_cmap_devicen_direct(const frac * pcc,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)1846*593dc095SDavid du Colombier pdf14_cmap_devicen_direct(const	frac * pcc,
1847*593dc095SDavid du Colombier     gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
1848*593dc095SDavid du Colombier     gs_color_select_t select)
1849*593dc095SDavid du Colombier {
1850*593dc095SDavid du Colombier     int i, ncomps = dev->color_info.num_components;
1851*593dc095SDavid du Colombier     frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
1852*593dc095SDavid du Colombier     gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1853*593dc095SDavid du Colombier     gx_color_index color;
1854*593dc095SDavid du Colombier 
1855*593dc095SDavid du Colombier     /* map to the color model */
1856*593dc095SDavid du Colombier     map_components_to_colorants(pcc, &(pis->color_component_map), cm_comps);;
1857*593dc095SDavid du Colombier 
1858*593dc095SDavid du Colombier     /* apply the transfer function(s); convert to color values */
1859*593dc095SDavid du Colombier     if (dev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE)
1860*593dc095SDavid du Colombier 	for (i = 0; i < ncomps; i++)
1861*593dc095SDavid du Colombier 	    cv[i] = frac2cv(gx_map_color_frac(pis,
1862*593dc095SDavid du Colombier 				cm_comps[i], effective_transfer[i]));
1863*593dc095SDavid du Colombier     else
1864*593dc095SDavid du Colombier 	for (i = 0; i < ncomps; i++)
1865*593dc095SDavid du Colombier 	    cv[i] = frac2cv(frac_1 - gx_map_color_frac(pis,
1866*593dc095SDavid du Colombier 			(frac)(frac_1 - cm_comps[i]), effective_transfer[i]));
1867*593dc095SDavid du Colombier 
1868*593dc095SDavid du Colombier     /* encode as a color index */
1869*593dc095SDavid du Colombier     color = dev_proc(dev, encode_color)(dev, cv);
1870*593dc095SDavid du Colombier 
1871*593dc095SDavid du Colombier     /* check if the encoding was successful; we presume failure is rare */
1872*593dc095SDavid du Colombier     if (color != gx_no_color_index)
1873*593dc095SDavid du Colombier 	color_set_pure(pdc, color);
1874*593dc095SDavid du Colombier }
1875*593dc095SDavid du Colombier 
1876*593dc095SDavid du Colombier private	bool
pdf14_cmap_is_halftoned(const gs_imager_state * pis,gx_device * dev)1877*593dc095SDavid du Colombier pdf14_cmap_is_halftoned(const gs_imager_state *	pis, gx_device * dev)
1878*593dc095SDavid du Colombier {
1879*593dc095SDavid du Colombier     return false;
1880*593dc095SDavid du Colombier }
1881*593dc095SDavid du Colombier 
1882*593dc095SDavid du Colombier private	const gx_color_map_procs *
pdf14_get_cmap_procs(const gs_imager_state * pis,const gx_device * dev)1883*593dc095SDavid du Colombier pdf14_get_cmap_procs(const gs_imager_state *pis, const gx_device * dev)
1884*593dc095SDavid du Colombier {
1885*593dc095SDavid du Colombier     /* The pdf14 marking device itself is always continuous tone. */
1886*593dc095SDavid du Colombier     return &pdf14_cmap_many;
1887*593dc095SDavid du Colombier }
1888*593dc095SDavid du Colombier 
1889*593dc095SDavid du Colombier 
1890*593dc095SDavid du Colombier int
gs_pdf14_device_push(gs_memory_t * mem,gs_imager_state * pis,gx_device ** pdev,gx_device * target)1891*593dc095SDavid du Colombier gs_pdf14_device_push(gs_memory_t *mem, gs_imager_state * pis,
18923ff48bf5SDavid du Colombier 				gx_device ** pdev, gx_device * target)
18933ff48bf5SDavid du Colombier {
1894*593dc095SDavid du Colombier     const pdf14_device * dev_proto;
18953ff48bf5SDavid du Colombier     pdf14_device *p14dev;
18963ff48bf5SDavid du Colombier     int code;
18973ff48bf5SDavid du Colombier 
1898*593dc095SDavid du Colombier     if_debug0('v', "[v]gs_pdf14_device_push\n");
1899*593dc095SDavid du Colombier 
1900*593dc095SDavid du Colombier     code = get_pdf14_device_proto(target, &dev_proto);
1901*593dc095SDavid du Colombier     if (code < 0)
1902*593dc095SDavid du Colombier 	return code;
19033ff48bf5SDavid du Colombier     code = gs_copydevice((gx_device **) &p14dev,
1904*593dc095SDavid du Colombier 			 (const gx_device *) dev_proto, mem);
19053ff48bf5SDavid du Colombier     if (code < 0)
19063ff48bf5SDavid du Colombier 	return code;
19073ff48bf5SDavid du Colombier 
1908*593dc095SDavid du Colombier     check_device_separable((gx_device *)p14dev);
19093ff48bf5SDavid du Colombier     gx_device_fill_in_procs((gx_device *)p14dev);
19103ff48bf5SDavid du Colombier 
19113ff48bf5SDavid du Colombier     gs_pdf14_device_copy_params((gx_device *)p14dev, target);
19123ff48bf5SDavid du Colombier 
1913*593dc095SDavid du Colombier     rc_assign(p14dev->target, target, "gs_pdf14_device_push");
19143ff48bf5SDavid du Colombier 
1915*593dc095SDavid du Colombier     p14dev->save_get_cmap_procs = pis->get_cmap_procs;
1916*593dc095SDavid du Colombier     pis->get_cmap_procs = pdf14_get_cmap_procs;
1917*593dc095SDavid du Colombier     gx_set_cmap_procs(pis, (gx_device *)p14dev);
1918*593dc095SDavid du Colombier 
1919*593dc095SDavid du Colombier     code = dev_proc((gx_device *) p14dev, open_device) ((gx_device *) p14dev);
19203ff48bf5SDavid du Colombier     *pdev = (gx_device *) p14dev;
1921*593dc095SDavid du Colombier     pdf14_set_marking_params((gx_device *)p14dev, pis);
1922*593dc095SDavid du Colombier     return code;
1923*593dc095SDavid du Colombier }
1924*593dc095SDavid du Colombier 
1925*593dc095SDavid du Colombier /*
1926*593dc095SDavid du Colombier  * In a modest violation of good coding practice, the gs_composite_common
1927*593dc095SDavid du Colombier  * fields are "known" to be simple (contain no pointers to garbage
1928*593dc095SDavid du Colombier  * collected memory), and we also know the gs_pdf14trans_params_t structure
1929*593dc095SDavid du Colombier  * to be simple, so we just create a trivial structure descriptor for the
1930*593dc095SDavid du Colombier  * entire gs_pdf14trans_s structure.
1931*593dc095SDavid du Colombier  */
1932*593dc095SDavid du Colombier #define	private_st_gs_pdf14trans_t()\
1933*593dc095SDavid du Colombier   gs_private_st_ptrs1(st_pdf14trans, gs_pdf14trans_t, "gs_pdf14trans_t",\
1934*593dc095SDavid du Colombier       st_pdf14trans_enum_ptrs, st_pdf14trans_reloc_ptrs, params.transfer_function)
1935*593dc095SDavid du Colombier 
1936*593dc095SDavid du Colombier /* GC descriptor for gs_pdf14trans_t */
1937*593dc095SDavid du Colombier private_st_gs_pdf14trans_t();
1938*593dc095SDavid du Colombier 
1939*593dc095SDavid du Colombier /*
1940*593dc095SDavid du Colombier  * Check for equality of two PDF 1.4 transparency compositor objects.
1941*593dc095SDavid du Colombier  *
1942*593dc095SDavid du Colombier  * We are currently always indicating that PDF 1.4 transparency compositors are
1943*593dc095SDavid du Colombier  * equal.  Two transparency compositors may have teh same data but still
1944*593dc095SDavid du Colombier  * represent separate actions.  (E.g. two PDF14_BEGIN_TRANS_GROUP compositor
1945*593dc095SDavid du Colombier  * operations in a row mean that we are creating a group inside of a group.
1946*593dc095SDavid du Colombier  */
1947*593dc095SDavid du Colombier private	bool
c_pdf14trans_equal(const gs_composite_t * pct0,const gs_composite_t * pct1)1948*593dc095SDavid du Colombier c_pdf14trans_equal(const gs_composite_t	* pct0,	const gs_composite_t * pct1)
1949*593dc095SDavid du Colombier {
1950*593dc095SDavid du Colombier     return false;
1951*593dc095SDavid du Colombier }
1952*593dc095SDavid du Colombier 
1953*593dc095SDavid du Colombier #ifdef DEBUG
1954*593dc095SDavid du Colombier static char * pdf14_opcode_names[] = PDF14_OPCODE_NAMES;
1955*593dc095SDavid du Colombier #endif
1956*593dc095SDavid du Colombier 
1957*593dc095SDavid du Colombier #define	put_value(dp, value)\
1958*593dc095SDavid du Colombier     memcpy(dp, &value, sizeof(value));\
1959*593dc095SDavid du Colombier     dp += sizeof(value)
1960*593dc095SDavid du Colombier 
1961*593dc095SDavid du Colombier /*
1962*593dc095SDavid du Colombier  * Convert a PDF 1.4 transparency compositor to string form for use by the command
1963*593dc095SDavid du Colombier  * list device.
1964*593dc095SDavid du Colombier  */
1965*593dc095SDavid du Colombier private	int
c_pdf14trans_write(const gs_composite_t * pct,byte * data,uint * psize)1966*593dc095SDavid du Colombier c_pdf14trans_write(const gs_composite_t	* pct, byte * data, uint * psize)
1967*593dc095SDavid du Colombier {
1968*593dc095SDavid du Colombier     const gs_pdf14trans_params_t * pparams = &((const gs_pdf14trans_t *)pct)->params;
1969*593dc095SDavid du Colombier     int need, avail = *psize;
1970*593dc095SDavid du Colombier 	/* Must be large enough for largest data struct */
1971*593dc095SDavid du Colombier     byte buf[21 + sizeof(pparams->Background)
1972*593dc095SDavid du Colombier 		+ sizeof(pparams->GrayBackground) + sizeof(pparams->bbox)];
1973*593dc095SDavid du Colombier     byte * pbuf = buf;
1974*593dc095SDavid du Colombier     int opcode = pparams->pdf14_op;
1975*593dc095SDavid du Colombier     int mask_size = 0;
1976*593dc095SDavid du Colombier 
1977*593dc095SDavid du Colombier     /* Write PDF 1.4 compositor data into the clist */
1978*593dc095SDavid du Colombier 
1979*593dc095SDavid du Colombier     *pbuf++ = opcode;			/* 1 byte */
1980*593dc095SDavid du Colombier     switch (opcode) {
1981*593dc095SDavid du Colombier 	default:			/* Should not occur. */
1982*593dc095SDavid du Colombier 	    break;
1983*593dc095SDavid du Colombier 	case PDF14_PUSH_DEVICE:
1984*593dc095SDavid du Colombier 	case PDF14_POP_DEVICE:
1985*593dc095SDavid du Colombier 	case PDF14_END_TRANS_GROUP:
1986*593dc095SDavid du Colombier 	case PDF14_END_TRANS_MASK:
1987*593dc095SDavid du Colombier 	    break;			/* No data */
1988*593dc095SDavid du Colombier 	case PDF14_BEGIN_TRANS_GROUP:
1989*593dc095SDavid du Colombier 	    /*
1990*593dc095SDavid du Colombier 	     * The bbox data is floating point.  We are not currently using it.
1991*593dc095SDavid du Colombier 	     * So we are not currently putting it into the clist.  We are also
1992*593dc095SDavid du Colombier 	     * not using the color space.
1993*593dc095SDavid du Colombier 	     */
1994*593dc095SDavid du Colombier 	    *pbuf++ = (pparams->Isolated & 1) + ((pparams->Knockout & 1) << 1);
1995*593dc095SDavid du Colombier 	    *pbuf++ = pparams->blend_mode;
1996*593dc095SDavid du Colombier 	    put_value(pbuf, pparams->opacity.alpha);
1997*593dc095SDavid du Colombier 	    put_value(pbuf, pparams->shape.alpha);
1998*593dc095SDavid du Colombier 	    put_value(pbuf, pparams->bbox);
1999*593dc095SDavid du Colombier 	    break;
2000*593dc095SDavid du Colombier 	case PDF14_INIT_TRANS_MASK:
2001*593dc095SDavid du Colombier 	    *pbuf++ = pparams->csel;
2002*593dc095SDavid du Colombier 	    break;
2003*593dc095SDavid du Colombier 	case PDF14_BEGIN_TRANS_MASK:
2004*593dc095SDavid du Colombier 	    put_value(pbuf, pparams->subtype);
2005*593dc095SDavid du Colombier 	    *pbuf++ = pparams->function_is_identity;
2006*593dc095SDavid du Colombier 	    *pbuf++ = pparams->Background_components;
2007*593dc095SDavid du Colombier 	    if (pparams->Background_components) {
2008*593dc095SDavid du Colombier 		const int l = sizeof(pparams->Background[0]) * pparams->Background_components;
2009*593dc095SDavid du Colombier 
2010*593dc095SDavid du Colombier 		memcpy(pbuf, pparams->Background, l);
2011*593dc095SDavid du Colombier 		pbuf += l;
2012*593dc095SDavid du Colombier 		memcpy(pbuf, &pparams->GrayBackground, sizeof(pparams->GrayBackground));
2013*593dc095SDavid du Colombier 		pbuf += sizeof(pparams->GrayBackground);
2014*593dc095SDavid du Colombier 	    }
2015*593dc095SDavid du Colombier 	    if (!pparams->function_is_identity)
2016*593dc095SDavid du Colombier 		mask_size = sizeof(pparams->transfer_fn);
2017*593dc095SDavid du Colombier 	    break;
2018*593dc095SDavid du Colombier 	case PDF14_SET_BLEND_PARAMS:
2019*593dc095SDavid du Colombier 	    *pbuf++ = pparams->changed;
2020*593dc095SDavid du Colombier 	    if (pparams->changed & PDF14_SET_BLEND_MODE)
2021*593dc095SDavid du Colombier 		*pbuf++ = pparams->blend_mode;
2022*593dc095SDavid du Colombier 	    if (pparams->changed & PDF14_SET_TEXT_KNOCKOUT)
2023*593dc095SDavid du Colombier 		*pbuf++ = pparams->text_knockout;
2024*593dc095SDavid du Colombier 	    if (pparams->changed & PDF14_SET_OPACITY_ALPHA)
2025*593dc095SDavid du Colombier 		put_value(pbuf, pparams->opacity.alpha);
2026*593dc095SDavid du Colombier 	    if (pparams->changed & PDF14_SET_SHAPE_ALPHA)
2027*593dc095SDavid du Colombier 		put_value(pbuf, pparams->shape.alpha);
2028*593dc095SDavid du Colombier 	    break;
2029*593dc095SDavid du Colombier     }
2030*593dc095SDavid du Colombier #undef put_value
2031*593dc095SDavid du Colombier 
2032*593dc095SDavid du Colombier     /* check for fit */
2033*593dc095SDavid du Colombier     need = (pbuf - buf) + mask_size;
2034*593dc095SDavid du Colombier     *psize = need;
2035*593dc095SDavid du Colombier     if (need > avail)
2036*593dc095SDavid du Colombier 	return_error(gs_error_rangecheck);
2037*593dc095SDavid du Colombier     /* Copy our serialzed data into the output buffer */
2038*593dc095SDavid du Colombier     memcpy(data, buf, need - mask_size);
2039*593dc095SDavid du Colombier     if (mask_size)	/* Include the transfer mask data if present */
2040*593dc095SDavid du Colombier 	memcpy(data + need - mask_size, pparams->transfer_fn, mask_size);
2041*593dc095SDavid du Colombier     if_debug2('v', "[v] c_pdf14trans_write: opcode = %s need = %d\n",
2042*593dc095SDavid du Colombier 				pdf14_opcode_names[opcode], need);
2043*593dc095SDavid du Colombier     return 0;
2044*593dc095SDavid du Colombier }
2045*593dc095SDavid du Colombier 
2046*593dc095SDavid du Colombier /* Function prototypes */
2047*593dc095SDavid du Colombier int gs_create_pdf14trans( gs_composite_t ** ppct,
2048*593dc095SDavid du Colombier 		const gs_pdf14trans_params_t * pparams,
2049*593dc095SDavid du Colombier 		gs_memory_t * mem );
2050*593dc095SDavid du Colombier 
2051*593dc095SDavid du Colombier #define	read_value(dp, value)\
2052*593dc095SDavid du Colombier     memcpy(&value, dp, sizeof(value));\
2053*593dc095SDavid du Colombier     dp += sizeof(value)
2054*593dc095SDavid du Colombier 
2055*593dc095SDavid du Colombier /*
2056*593dc095SDavid du Colombier  * Convert the string representation of the PDF 1.4 tranparency  parameter
2057*593dc095SDavid du Colombier  * into the full compositor.
2058*593dc095SDavid du Colombier  */
2059*593dc095SDavid du Colombier private	int
c_pdf14trans_read(gs_composite_t ** ppct,const byte * data,uint size,gs_memory_t * mem)2060*593dc095SDavid du Colombier c_pdf14trans_read(gs_composite_t * * ppct, const byte *	data,
2061*593dc095SDavid du Colombier 				uint size, gs_memory_t * mem )
2062*593dc095SDavid du Colombier {
2063*593dc095SDavid du Colombier     gs_pdf14trans_params_t params = {0};
2064*593dc095SDavid du Colombier     const byte * start = data;
2065*593dc095SDavid du Colombier     int used, code = 0;
2066*593dc095SDavid du Colombier 
2067*593dc095SDavid du Colombier     if (size < 1)
2068*593dc095SDavid du Colombier 	return_error(gs_error_rangecheck);
2069*593dc095SDavid du Colombier 
2070*593dc095SDavid du Colombier     /* Read PDF 1.4 compositor data from the clist */
2071*593dc095SDavid du Colombier     params.pdf14_op = *data++;
2072*593dc095SDavid du Colombier     if_debug2('v', "[v] c_pdf14trans_read: opcode = %s  avail = %d",
2073*593dc095SDavid du Colombier 				pdf14_opcode_names[params.pdf14_op], size);
2074*593dc095SDavid du Colombier     switch (params.pdf14_op) {
2075*593dc095SDavid du Colombier 	default:			/* Should not occur. */
2076*593dc095SDavid du Colombier 	    break;
2077*593dc095SDavid du Colombier 	case PDF14_PUSH_DEVICE:
2078*593dc095SDavid du Colombier 	case PDF14_POP_DEVICE:
2079*593dc095SDavid du Colombier 	case PDF14_END_TRANS_GROUP:
2080*593dc095SDavid du Colombier 	    break;			/* No data */
2081*593dc095SDavid du Colombier 	case PDF14_BEGIN_TRANS_GROUP:
2082*593dc095SDavid du Colombier 	    /*
2083*593dc095SDavid du Colombier 	     * We are currently not using the bbox or the colorspace so they were
2084*593dc095SDavid du Colombier 	     * not placed in the clist
2085*593dc095SDavid du Colombier 	     */
2086*593dc095SDavid du Colombier 	    params.Isolated = (*data) & 1;
2087*593dc095SDavid du Colombier 	    params.Knockout = (*data++ >> 1) & 1;
2088*593dc095SDavid du Colombier 	    params.blend_mode = *data++;
2089*593dc095SDavid du Colombier 	    read_value(data, params.opacity.alpha);
2090*593dc095SDavid du Colombier 	    read_value(data, params.shape.alpha);
2091*593dc095SDavid du Colombier 	    read_value(data, params.bbox);
2092*593dc095SDavid du Colombier 	    break;
2093*593dc095SDavid du Colombier 	case PDF14_INIT_TRANS_MASK:
2094*593dc095SDavid du Colombier 	    params.csel = *data++;
2095*593dc095SDavid du Colombier 	    break;
2096*593dc095SDavid du Colombier 	case PDF14_BEGIN_TRANS_MASK:
2097*593dc095SDavid du Colombier 	    read_value(data, params.subtype);
2098*593dc095SDavid du Colombier 	    params.function_is_identity = *data++;
2099*593dc095SDavid du Colombier 	    params.Background_components = *data++;
2100*593dc095SDavid du Colombier 	    if (params.Background_components) {
2101*593dc095SDavid du Colombier 		const int l = sizeof(params.Background[0]) * params.Background_components;
2102*593dc095SDavid du Colombier 
2103*593dc095SDavid du Colombier 		memcpy(params.Background, data, l);
2104*593dc095SDavid du Colombier 		data += l;
2105*593dc095SDavid du Colombier 		memcpy(&params.GrayBackground, data, sizeof(params.GrayBackground));
2106*593dc095SDavid du Colombier 		data += sizeof(params.GrayBackground);
2107*593dc095SDavid du Colombier 	    }
2108*593dc095SDavid du Colombier 	    if (params.function_is_identity) {
2109*593dc095SDavid du Colombier 		int i;
2110*593dc095SDavid du Colombier 
2111*593dc095SDavid du Colombier 		for (i = 0; i < MASK_TRANSFER_FUNCTION_SIZE; i++) {
2112*593dc095SDavid du Colombier 		    params.transfer_fn[i] = (byte)floor(i *
2113*593dc095SDavid du Colombier 			(255.0 / (MASK_TRANSFER_FUNCTION_SIZE - 1)) + 0.5);
2114*593dc095SDavid du Colombier 		}
2115*593dc095SDavid du Colombier 	    } else {
2116*593dc095SDavid du Colombier 		read_value(data, params.transfer_fn);
2117*593dc095SDavid du Colombier 	    }
2118*593dc095SDavid du Colombier 	    break;
2119*593dc095SDavid du Colombier 	case PDF14_END_TRANS_MASK:
2120*593dc095SDavid du Colombier 	    break;			/* No data */
2121*593dc095SDavid du Colombier 	case PDF14_SET_BLEND_PARAMS:
2122*593dc095SDavid du Colombier 	    params.changed = *data++;
2123*593dc095SDavid du Colombier 	    if (params.changed & PDF14_SET_BLEND_MODE)
2124*593dc095SDavid du Colombier 		params.blend_mode = *data++;
2125*593dc095SDavid du Colombier 	    if (params.changed & PDF14_SET_TEXT_KNOCKOUT)
2126*593dc095SDavid du Colombier 		params.text_knockout = *data++;
2127*593dc095SDavid du Colombier 	    if (params.changed & PDF14_SET_OPACITY_ALPHA)
2128*593dc095SDavid du Colombier 		read_value(data, params.opacity.alpha);
2129*593dc095SDavid du Colombier 	    if (params.changed & PDF14_SET_SHAPE_ALPHA)
2130*593dc095SDavid du Colombier 		read_value(data, params.shape.alpha);
2131*593dc095SDavid du Colombier 	    break;
2132*593dc095SDavid du Colombier     }
2133*593dc095SDavid du Colombier     code = gs_create_pdf14trans(ppct, &params, mem);
2134*593dc095SDavid du Colombier     if (code < 0)
2135*593dc095SDavid du Colombier 	return code;
2136*593dc095SDavid du Colombier     used = data - start;
2137*593dc095SDavid du Colombier     if_debug1('v', "  used = %d\n", used);
2138*593dc095SDavid du Colombier     return used;
2139*593dc095SDavid du Colombier }
2140*593dc095SDavid du Colombier 
2141*593dc095SDavid du Colombier /*
2142*593dc095SDavid du Colombier  * Create a PDF 1.4 transparency compositor.
2143*593dc095SDavid du Colombier  *
2144*593dc095SDavid du Colombier  * Note that this routine will be called only if the device is not already
2145*593dc095SDavid du Colombier  * a PDF 1.4 transparency compositor.
2146*593dc095SDavid du Colombier  */
2147*593dc095SDavid du Colombier private	int
c_pdf14trans_create_default_compositor(const gs_composite_t * pct,gx_device ** pp14dev,gx_device * tdev,gs_imager_state * pis,gs_memory_t * mem)2148*593dc095SDavid du Colombier c_pdf14trans_create_default_compositor(const gs_composite_t * pct,
2149*593dc095SDavid du Colombier     gx_device ** pp14dev, gx_device * tdev, gs_imager_state * pis,
2150*593dc095SDavid du Colombier     gs_memory_t * mem)
2151*593dc095SDavid du Colombier {
2152*593dc095SDavid du Colombier     const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pct;
2153*593dc095SDavid du Colombier     gx_device * p14dev = NULL;
2154*593dc095SDavid du Colombier     int code = 0;
2155*593dc095SDavid du Colombier 
2156*593dc095SDavid du Colombier     /*
2157*593dc095SDavid du Colombier      * We only handle the push operation.  All other operations are ignored.
2158*593dc095SDavid du Colombier      */
2159*593dc095SDavid du Colombier     switch (pdf14pct->params.pdf14_op) {
2160*593dc095SDavid du Colombier 	case PDF14_PUSH_DEVICE:
2161*593dc095SDavid du Colombier 	    code = gs_pdf14_device_push(mem, pis, &p14dev, tdev);
2162*593dc095SDavid du Colombier 	    *pp14dev = p14dev;
2163*593dc095SDavid du Colombier 	    break;
2164*593dc095SDavid du Colombier 	default:
2165*593dc095SDavid du Colombier 	    *pp14dev = tdev;
2166*593dc095SDavid du Colombier 	    break;
2167*593dc095SDavid du Colombier     }
2168*593dc095SDavid du Colombier     return code;
2169*593dc095SDavid du Colombier }
2170*593dc095SDavid du Colombier 
2171*593dc095SDavid du Colombier private	composite_clist_write_update(c_pdf14trans_clist_write_update);
2172*593dc095SDavid du Colombier private	composite_clist_read_update(c_pdf14trans_clist_read_update);
2173*593dc095SDavid du Colombier 
2174*593dc095SDavid du Colombier /*
2175*593dc095SDavid du Colombier  * Methods for the PDF 1.4 transparency compositor
2176*593dc095SDavid du Colombier  *
2177*593dc095SDavid du Colombier  * Note:  We have two set of methods.  They are the same except for the
2178*593dc095SDavid du Colombier  * composite_clist_write_update method.  Once the clist write device is created,
2179*593dc095SDavid du Colombier  * we use the second set of procedures.  This prevents the creation of multiple
2180*593dc095SDavid du Colombier  * PDF 1.4 clist write compositor devices being chained together.
2181*593dc095SDavid du Colombier  */
2182*593dc095SDavid du Colombier const gs_composite_type_t   gs_composite_pdf14trans_type = {
2183*593dc095SDavid du Colombier     GX_COMPOSITOR_PDF14_TRANS,
2184*593dc095SDavid du Colombier     {
2185*593dc095SDavid du Colombier 	c_pdf14trans_create_default_compositor, /* procs.create_default_compositor */
2186*593dc095SDavid du Colombier 	c_pdf14trans_equal,                      /* procs.equal */
2187*593dc095SDavid du Colombier 	c_pdf14trans_write,                      /* procs.write */
2188*593dc095SDavid du Colombier 	c_pdf14trans_read,                       /* procs.read */
2189*593dc095SDavid du Colombier 		/* Create a PDF 1.4 clist write device */
2190*593dc095SDavid du Colombier 	c_pdf14trans_clist_write_update,   /* procs.composite_clist_write_update */
2191*593dc095SDavid du Colombier 	c_pdf14trans_clist_read_update	   /* procs.composite_clist_reade_update */
2192*593dc095SDavid du Colombier     }                                            /* procs */
2193*593dc095SDavid du Colombier };
2194*593dc095SDavid du Colombier 
2195*593dc095SDavid du Colombier const gs_composite_type_t   gs_composite_pdf14trans_no_clist_writer_type = {
2196*593dc095SDavid du Colombier     GX_COMPOSITOR_PDF14_TRANS,
2197*593dc095SDavid du Colombier     {
2198*593dc095SDavid du Colombier 	c_pdf14trans_create_default_compositor, /* procs.create_default_compositor */
2199*593dc095SDavid du Colombier 	c_pdf14trans_equal,                      /* procs.equal */
2200*593dc095SDavid du Colombier 	c_pdf14trans_write,                      /* procs.write */
2201*593dc095SDavid du Colombier 	c_pdf14trans_read,                       /* procs.read */
2202*593dc095SDavid du Colombier 		/* The PDF 1.4 clist writer already exists, Do not create it. */
2203*593dc095SDavid du Colombier 	gx_default_composite_clist_write_update, /* procs.composite_clist_write_update */
2204*593dc095SDavid du Colombier 	c_pdf14trans_clist_read_update	   /* procs.composite_clist_reade_update */
2205*593dc095SDavid du Colombier     }                                            /* procs */
2206*593dc095SDavid du Colombier };
2207*593dc095SDavid du Colombier 
2208*593dc095SDavid du Colombier /*
2209*593dc095SDavid du Colombier  * Verify that a compositor data structure is for the PDF 1.4 compositor.
2210*593dc095SDavid du Colombier  */
2211*593dc095SDavid du Colombier int
gs_is_pdf14trans_compositor(const gs_composite_t * pct)2212*593dc095SDavid du Colombier gs_is_pdf14trans_compositor(const gs_composite_t * pct)
2213*593dc095SDavid du Colombier {
2214*593dc095SDavid du Colombier     return (pct->type == &gs_composite_pdf14trans_type
2215*593dc095SDavid du Colombier 		|| pct->type == &gs_composite_pdf14trans_no_clist_writer_type);
2216*593dc095SDavid du Colombier }
2217*593dc095SDavid du Colombier 
2218*593dc095SDavid du Colombier /*
2219*593dc095SDavid du Colombier  * Create a PDF 1.4 transparency compositor data structure.
2220*593dc095SDavid du Colombier  */
2221*593dc095SDavid du Colombier int
gs_create_pdf14trans(gs_composite_t ** ppct,const gs_pdf14trans_params_t * pparams,gs_memory_t * mem)2222*593dc095SDavid du Colombier gs_create_pdf14trans(
2223*593dc095SDavid du Colombier     gs_composite_t **               ppct,
2224*593dc095SDavid du Colombier     const gs_pdf14trans_params_t *  pparams,
2225*593dc095SDavid du Colombier     gs_memory_t *                   mem )
2226*593dc095SDavid du Colombier {
2227*593dc095SDavid du Colombier     gs_pdf14trans_t *                pct;
2228*593dc095SDavid du Colombier 
2229*593dc095SDavid du Colombier     rc_alloc_struct_0( pct,
2230*593dc095SDavid du Colombier 		       gs_pdf14trans_t,
2231*593dc095SDavid du Colombier 		       &st_pdf14trans,
2232*593dc095SDavid du Colombier 		       mem,
2233*593dc095SDavid du Colombier 		       return_error(gs_error_VMerror),
2234*593dc095SDavid du Colombier 		       "gs_create_pdf14trans" );
2235*593dc095SDavid du Colombier     pct->type = &gs_composite_pdf14trans_type;
2236*593dc095SDavid du Colombier     pct->id = gs_next_ids(mem, 1);
2237*593dc095SDavid du Colombier     pct->params = *pparams;
2238*593dc095SDavid du Colombier     *ppct = (gs_composite_t *)pct;
2239*593dc095SDavid du Colombier     return 0;
2240*593dc095SDavid du Colombier }
2241*593dc095SDavid du Colombier 
2242*593dc095SDavid du Colombier /*
2243*593dc095SDavid du Colombier  * Send a PDF 1.4 transparency compositor action to the specified device.
2244*593dc095SDavid du Colombier  */
2245*593dc095SDavid du Colombier int
send_pdf14trans(gs_imager_state * pis,gx_device * dev,gx_device ** pcdev,gs_pdf14trans_params_t * pparams,gs_memory_t * mem)2246*593dc095SDavid du Colombier send_pdf14trans(gs_imager_state	* pis, gx_device * dev,
2247*593dc095SDavid du Colombier     gx_device * * pcdev, gs_pdf14trans_params_t * pparams, gs_memory_t * mem)
2248*593dc095SDavid du Colombier {
2249*593dc095SDavid du Colombier     gs_composite_t * pct = NULL;
2250*593dc095SDavid du Colombier     int code;
2251*593dc095SDavid du Colombier 
2252*593dc095SDavid du Colombier     code = gs_create_pdf14trans(&pct, pparams, mem);
2253*593dc095SDavid du Colombier     if (code < 0)
2254*593dc095SDavid du Colombier 	return code;
2255*593dc095SDavid du Colombier     code = dev_proc(dev, create_compositor) (dev, pcdev, pct, pis, mem);
2256*593dc095SDavid du Colombier 
2257*593dc095SDavid du Colombier     gs_free_object(pis->memory, pct, "send_pdf14trans");
2258*593dc095SDavid du Colombier 
2259*593dc095SDavid du Colombier     return code;
2260*593dc095SDavid du Colombier }
2261*593dc095SDavid du Colombier 
2262*593dc095SDavid du Colombier /* ------------- PDF 1.4 transparency device for clist writing ------------- */
2263*593dc095SDavid du Colombier 
2264*593dc095SDavid du Colombier /*
2265*593dc095SDavid du Colombier  * The PDF 1.4 transparency compositor device may have a different process
2266*593dc095SDavid du Colombier  * color model than the output device.  If we are banding then we need to
2267*593dc095SDavid du Colombier  * create two compositor devices.  The output side (clist reader) needs a
2268*593dc095SDavid du Colombier  * compositor to actually composite the output.  We also need a compositor
2269*593dc095SDavid du Colombier  * device before the clist writer.  This is needed to provide a process color
2270*593dc095SDavid du Colombier  * model which matches the PDF 1.4 blending space.
2271*593dc095SDavid du Colombier  *
2272*593dc095SDavid du Colombier  * This section provides support for this device.
2273*593dc095SDavid du Colombier  */
2274*593dc095SDavid du Colombier 
2275*593dc095SDavid du Colombier /* Define the default alpha-compositing	device.	*/
2276*593dc095SDavid du Colombier typedef	struct pdf14_clist_device_s {
2277*593dc095SDavid du Colombier     gx_device_forward_common;
2278*593dc095SDavid du Colombier     const gx_color_map_procs *(*save_get_cmap_procs)(const gs_imager_state *,
2279*593dc095SDavid du Colombier 						     const gx_device *);
2280*593dc095SDavid du Colombier     gx_device_color_info saved_target_color_info;
2281*593dc095SDavid du Colombier     float opacity;
2282*593dc095SDavid du Colombier     float shape;
2283*593dc095SDavid du Colombier     gs_blend_mode_t blend_mode;
2284*593dc095SDavid du Colombier     bool text_knockout;
2285*593dc095SDavid du Colombier } pdf14_clist_device;
2286*593dc095SDavid du Colombier 
2287*593dc095SDavid du Colombier gs_private_st_suffix_add0_final(st_pdf14_clist_device,
2288*593dc095SDavid du Colombier     pdf14_clist_device, "pdf14_clist_device",
2289*593dc095SDavid du Colombier     device_c_pdf14_clist_enum_ptrs, device_c_pdf14_clist_reloc_ptrs,
2290*593dc095SDavid du Colombier     gx_device_finalize, st_device_forward);
2291*593dc095SDavid du Colombier 
2292*593dc095SDavid du Colombier #define	pdf14_clist_procs(get_color_mapping_procs, get_color_comp_index,\
2293*593dc095SDavid du Colombier 						encode_color, decode_color) \
2294*593dc095SDavid du Colombier {\
2295*593dc095SDavid du Colombier 	NULL,				/* open */\
2296*593dc095SDavid du Colombier 	gx_forward_get_initial_matrix,	/* get_initial_matrix */\
2297*593dc095SDavid du Colombier 	gx_forward_sync_output,		/* sync_output */\
2298*593dc095SDavid du Colombier 	gx_forward_output_page,		/* output_page */\
2299*593dc095SDavid du Colombier 	gx_forward_close_device,	/* close_device */\
2300*593dc095SDavid du Colombier 	encode_color,			/* rgb_map_rgb_color */\
2301*593dc095SDavid du Colombier 	decode_color,			/* map_color_rgb */\
2302*593dc095SDavid du Colombier 	gx_forward_fill_rectangle,	/* fill_rectangle */\
2303*593dc095SDavid du Colombier 	gx_forward_tile_rectangle,	/* tile_rectangle */\
2304*593dc095SDavid du Colombier 	gx_forward_copy_mono,		/* copy_mono */\
2305*593dc095SDavid du Colombier 	gx_forward_copy_color,		/* copy_color */\
2306*593dc095SDavid du Colombier 	NULL		,		/* draw_line - obsolete */\
2307*593dc095SDavid du Colombier 	gx_forward_get_bits,		/* get_bits */\
2308*593dc095SDavid du Colombier 	gx_forward_get_params,		/* get_params */\
2309*593dc095SDavid du Colombier 	pdf14_put_params,		/* put_params */\
2310*593dc095SDavid du Colombier 	encode_color,			/* map_cmyk_color */\
2311*593dc095SDavid du Colombier 	gx_forward_get_xfont_procs,	/* get_xfont_procs */\
2312*593dc095SDavid du Colombier 	gx_forward_get_xfont_device,	/* get_xfont_device */\
2313*593dc095SDavid du Colombier 	NULL,				/* map_rgb_alpha_color */\
2314*593dc095SDavid du Colombier 	gx_forward_get_page_device,	/* get_page_device */\
2315*593dc095SDavid du Colombier 	gx_forward_get_alpha_bits,	/* get_alpha_bits */\
2316*593dc095SDavid du Colombier 	NULL,				/* copy_alpha */\
2317*593dc095SDavid du Colombier 	gx_forward_get_band,		/* get_band */\
2318*593dc095SDavid du Colombier 	gx_forward_copy_rop,		/* copy_rop */\
2319*593dc095SDavid du Colombier 	pdf14_clist_fill_path,		/* fill_path */\
2320*593dc095SDavid du Colombier 	pdf14_clist_stroke_path,		/* stroke_path */\
2321*593dc095SDavid du Colombier 	gx_forward_fill_mask,		/* fill_mask */\
2322*593dc095SDavid du Colombier 	gx_forward_fill_trapezoid,	/* fill_trapezoid */\
2323*593dc095SDavid du Colombier 	gx_forward_fill_parallelogram,	/* fill_parallelogram */\
2324*593dc095SDavid du Colombier 	gx_forward_fill_triangle,	/* fill_triangle */\
2325*593dc095SDavid du Colombier 	gx_forward_draw_thin_line,	/* draw_thin_line */\
2326*593dc095SDavid du Colombier 	pdf14_clist_begin_image,	/* begin_image */\
2327*593dc095SDavid du Colombier 	gx_forward_image_data,		/* image_data */\
2328*593dc095SDavid du Colombier 	gx_forward_end_image,		/* end_image */\
2329*593dc095SDavid du Colombier 	gx_forward_strip_tile_rectangle, /* strip_tile_rectangle */\
2330*593dc095SDavid du Colombier 	gx_forward_strip_copy_rop,	/* strip_copy_rop, */\
2331*593dc095SDavid du Colombier 	gx_forward_get_clipping_box,	/* get_clipping_box */\
2332*593dc095SDavid du Colombier 	pdf14_clist_begin_typed_image,	/* begin_typed_image */\
2333*593dc095SDavid du Colombier 	gx_forward_get_bits_rectangle,	/* get_bits_rectangle */\
2334*593dc095SDavid du Colombier 	NULL,				/* map_color_rgb_alpha */\
2335*593dc095SDavid du Colombier 	pdf14_clist_create_compositor,	/* create_compositor */\
2336*593dc095SDavid du Colombier 	gx_forward_get_hardware_params,	/* get_hardware_params */\
2337*593dc095SDavid du Colombier 	pdf14_clist_text_begin,		/* text_begin */\
2338*593dc095SDavid du Colombier 	NULL,				/* finish_copydevice */\
2339*593dc095SDavid du Colombier 	pdf14_begin_transparency_group,\
2340*593dc095SDavid du Colombier 	pdf14_end_transparency_group,\
2341*593dc095SDavid du Colombier 	pdf14_begin_transparency_mask,\
2342*593dc095SDavid du Colombier 	pdf14_end_transparency_mask,\
2343*593dc095SDavid du Colombier 	NULL,				/* discard_transparency_layer */\
2344*593dc095SDavid du Colombier 	get_color_mapping_procs,	/* get_color_mapping_procs */\
2345*593dc095SDavid du Colombier 	get_color_comp_index,		/* get_color_comp_index */\
2346*593dc095SDavid du Colombier 	encode_color,			/* encode_color */\
2347*593dc095SDavid du Colombier 	decode_color			/* decode_color */\
2348*593dc095SDavid du Colombier }
2349*593dc095SDavid du Colombier 
2350*593dc095SDavid du Colombier private	dev_proc_create_compositor(pdf14_clist_create_compositor);
2351*593dc095SDavid du Colombier private	dev_proc_create_compositor(pdf14_clist_forward_create_compositor);
2352*593dc095SDavid du Colombier private	dev_proc_fill_path(pdf14_clist_fill_path);
2353*593dc095SDavid du Colombier private	dev_proc_stroke_path(pdf14_clist_stroke_path);
2354*593dc095SDavid du Colombier private	dev_proc_text_begin(pdf14_clist_text_begin);
2355*593dc095SDavid du Colombier private	dev_proc_begin_image(pdf14_clist_begin_image);
2356*593dc095SDavid du Colombier private	dev_proc_begin_typed_image(pdf14_clist_begin_typed_image);
2357*593dc095SDavid du Colombier 
2358*593dc095SDavid du Colombier private	const gx_device_procs pdf14_clist_Gray_procs =
2359*593dc095SDavid du Colombier 	pdf14_clist_procs(gx_default_DevGray_get_color_mapping_procs,
2360*593dc095SDavid du Colombier 			gx_default_DevGray_get_color_comp_index,
2361*593dc095SDavid du Colombier 			gx_default_8bit_map_gray_color,
2362*593dc095SDavid du Colombier 			gx_default_8bit_map_color_gray);
2363*593dc095SDavid du Colombier 
2364*593dc095SDavid du Colombier private	const gx_device_procs pdf14_clist_RGB_procs =
2365*593dc095SDavid du Colombier 	pdf14_clist_procs(gx_default_DevRGB_get_color_mapping_procs,
2366*593dc095SDavid du Colombier 			gx_default_DevRGB_get_color_comp_index,
2367*593dc095SDavid du Colombier 			gx_default_rgb_map_rgb_color,
2368*593dc095SDavid du Colombier 			gx_default_rgb_map_color_rgb);
2369*593dc095SDavid du Colombier 
2370*593dc095SDavid du Colombier private	const gx_device_procs pdf14_clist_CMYK_procs =
2371*593dc095SDavid du Colombier 	pdf14_clist_procs(gx_default_DevCMYK_get_color_mapping_procs,
2372*593dc095SDavid du Colombier 			gx_default_DevCMYK_get_color_comp_index,
2373*593dc095SDavid du Colombier 			cmyk_8bit_map_cmyk_color, cmyk_8bit_map_color_cmyk);
2374*593dc095SDavid du Colombier 
2375*593dc095SDavid du Colombier const pdf14_clist_device pdf14_clist_Gray_device = {
2376*593dc095SDavid du Colombier     std_device_color_stype_body(pdf14_clist_device, &pdf14_clist_Gray_procs,
2377*593dc095SDavid du Colombier 			"pdf14clistgray", &st_pdf14_clist_device,
2378*593dc095SDavid du Colombier 			XSIZE, YSIZE, X_DPI, Y_DPI, 8, 255, 256),
2379*593dc095SDavid du Colombier     { 0 }
2380*593dc095SDavid du Colombier };
2381*593dc095SDavid du Colombier 
2382*593dc095SDavid du Colombier const pdf14_clist_device pdf14_clist_RGB_device	= {
2383*593dc095SDavid du Colombier     std_device_color_stype_body(pdf14_clist_device, &pdf14_clist_RGB_procs,
2384*593dc095SDavid du Colombier 			"pdf14clistRGB", &st_pdf14_clist_device,
2385*593dc095SDavid du Colombier 			XSIZE, YSIZE, X_DPI, Y_DPI, 24, 255, 256),
2386*593dc095SDavid du Colombier     { 0 }
2387*593dc095SDavid du Colombier };
2388*593dc095SDavid du Colombier 
2389*593dc095SDavid du Colombier const pdf14_clist_device pdf14_clist_CMYK_device = {
2390*593dc095SDavid du Colombier     std_device_std_color_full_body_type(pdf14_clist_device,
2391*593dc095SDavid du Colombier 			&pdf14_clist_CMYK_procs, "PDF14clistcmyk",
2392*593dc095SDavid du Colombier 			&st_pdf14_clist_device, XSIZE, YSIZE, X_DPI, Y_DPI, 32,
2393*593dc095SDavid du Colombier 			0, 0, 0, 0, 0, 0),
2394*593dc095SDavid du Colombier     { 0 }
2395*593dc095SDavid du Colombier };
2396*593dc095SDavid du Colombier 
2397*593dc095SDavid du Colombier /*
2398*593dc095SDavid du Colombier  * the PDF 1.4 transparency spec says that color space for blending
2399*593dc095SDavid du Colombier  * operations can be based upon either a color space specified in the
2400*593dc095SDavid du Colombier  * group or a default value based upon the output device.  We are
2401*593dc095SDavid du Colombier  * currently only using a color space based upon the device.
2402*593dc095SDavid du Colombier  */
2403*593dc095SDavid du Colombier private	int
get_pdf14_clist_device_proto(gx_device * dev,const pdf14_clist_device ** pdevproto)2404*593dc095SDavid du Colombier get_pdf14_clist_device_proto(gx_device * dev,
2405*593dc095SDavid du Colombier 		const pdf14_clist_device ** pdevproto)
2406*593dc095SDavid du Colombier {
2407*593dc095SDavid du Colombier     pdf14_default_colorspace_t dev_cs =
2408*593dc095SDavid du Colombier 		pdf14_determine_default_blend_cs(dev);
2409*593dc095SDavid du Colombier 
2410*593dc095SDavid du Colombier     switch (dev_cs) {
2411*593dc095SDavid du Colombier 	case DeviceGray:
2412*593dc095SDavid du Colombier 	    *pdevproto = &pdf14_clist_Gray_device;
2413*593dc095SDavid du Colombier 	    break;
2414*593dc095SDavid du Colombier 	case DeviceRGB:
2415*593dc095SDavid du Colombier 	    *pdevproto = &pdf14_clist_RGB_device;
2416*593dc095SDavid du Colombier 	    break;
2417*593dc095SDavid du Colombier 	case DeviceCMYK:
2418*593dc095SDavid du Colombier 	    *pdevproto = &pdf14_clist_CMYK_device;
2419*593dc095SDavid du Colombier 	    break;
2420*593dc095SDavid du Colombier 	default:			/* Should not occur */
2421*593dc095SDavid du Colombier 	    return_error(gs_error_rangecheck);
2422*593dc095SDavid du Colombier     }
24233ff48bf5SDavid du Colombier     return 0;
24243ff48bf5SDavid du Colombier }
24253ff48bf5SDavid du Colombier 
24263ff48bf5SDavid du Colombier private	int
pdf14_create_clist_device(gs_memory_t * mem,gs_imager_state * pis,gx_device ** ppdev,gx_device * target)2427*593dc095SDavid du Colombier pdf14_create_clist_device(gs_memory_t *mem, gs_imager_state * pis,
2428*593dc095SDavid du Colombier 				gx_device ** ppdev, gx_device * target)
24293ff48bf5SDavid du Colombier {
2430*593dc095SDavid du Colombier     const pdf14_clist_device * dev_proto;
2431*593dc095SDavid du Colombier     pdf14_clist_device *pdev;
24323ff48bf5SDavid du Colombier     int code;
24333ff48bf5SDavid du Colombier 
2434*593dc095SDavid du Colombier     if_debug0('v', "[v]pdf14_create_clist_device\n");
2435*593dc095SDavid du Colombier 
2436*593dc095SDavid du Colombier     code = get_pdf14_clist_device_proto(target, &dev_proto);
24373ff48bf5SDavid du Colombier     if (code < 0)
24383ff48bf5SDavid du Colombier 	return code;
24393ff48bf5SDavid du Colombier 
2440*593dc095SDavid du Colombier     code = gs_copydevice((gx_device **) &pdev,
2441*593dc095SDavid du Colombier 			 (const gx_device *) dev_proto, mem);
24423ff48bf5SDavid du Colombier     if (code < 0)
24433ff48bf5SDavid du Colombier 	return code;
24443ff48bf5SDavid du Colombier 
2445*593dc095SDavid du Colombier     check_device_separable((gx_device *)pdev);
2446*593dc095SDavid du Colombier     gx_device_fill_in_procs((gx_device *)pdev);
24473ff48bf5SDavid du Colombier 
2448*593dc095SDavid du Colombier     gs_pdf14_device_copy_params((gx_device *)pdev, target);
2449*593dc095SDavid du Colombier 
2450*593dc095SDavid du Colombier     rc_assign(pdev->target, target, "pdf14_create_clist_device");
2451*593dc095SDavid du Colombier 
2452*593dc095SDavid du Colombier     code = dev_proc((gx_device *) pdev, open_device) ((gx_device *) pdev);
2453*593dc095SDavid du Colombier     *ppdev = (gx_device *) pdev;
2454*593dc095SDavid du Colombier     return code;
2455*593dc095SDavid du Colombier }
2456*593dc095SDavid du Colombier 
2457*593dc095SDavid du Colombier /*
2458*593dc095SDavid du Colombier  * Disable the PDF 1.4 clist compositor device.  Once created, the PDF 1.4
2459*593dc095SDavid du Colombier  * compositor device is never removed.  (We do not have a remove compositor
2460*593dc095SDavid du Colombier  * method.)  However it is no-op'ed when the PDF 1.4 device is popped.  This
2461*593dc095SDavid du Colombier  * routine implements that action.
2462*593dc095SDavid du Colombier  */
2463*593dc095SDavid du Colombier private	int
pdf14_disable_clist_device(gs_memory_t * mem,gs_imager_state * pis,gx_device * dev)2464*593dc095SDavid du Colombier pdf14_disable_clist_device(gs_memory_t *mem, gs_imager_state * pis,
2465*593dc095SDavid du Colombier 				gx_device * dev)
2466*593dc095SDavid du Colombier {
2467*593dc095SDavid du Colombier     gx_device_forward * pdev = (gx_device_forward *)dev;
2468*593dc095SDavid du Colombier     gx_device * target = pdev->target;
2469*593dc095SDavid du Colombier 
2470*593dc095SDavid du Colombier     if_debug0('v', "[v]pdf14_disable_clist_device\n");
2471*593dc095SDavid du Colombier 
2472*593dc095SDavid du Colombier     /*
2473*593dc095SDavid du Colombier      * To disable the action of this device, we forward all device
2474*593dc095SDavid du Colombier      * procedures to the target except the create_compositor and copy
2475*593dc095SDavid du Colombier      * the target's color_info.
2476*593dc095SDavid du Colombier      */
2477*593dc095SDavid du Colombier     dev->color_info = target->color_info;
2478*593dc095SDavid du Colombier     pdf14_forward_device_procs(dev);
2479*593dc095SDavid du Colombier     set_dev_proc(dev, create_compositor, pdf14_clist_forward_create_compositor);
24803ff48bf5SDavid du Colombier     return 0;
24813ff48bf5SDavid du Colombier }
24823ff48bf5SDavid du Colombier 
2483*593dc095SDavid du Colombier /*
2484*593dc095SDavid du Colombier  * Recreate the PDF 1.4 clist compositor device.  Once created, the PDF 1.4
2485*593dc095SDavid du Colombier  * compositor device is never removed.  (We do not have a remove compositor
2486*593dc095SDavid du Colombier  * method.)  However it is no-op'ed when the PDF 1.4 device is popped.  This
2487*593dc095SDavid du Colombier  * routine will re-enable the compositor if the PDF 1.4 device is pushed
2488*593dc095SDavid du Colombier  * again.
2489*593dc095SDavid du Colombier  */
2490*593dc095SDavid du Colombier private	int
pdf14_recreate_clist_device(gs_memory_t * mem,gs_imager_state * pis,gx_device * dev)2491*593dc095SDavid du Colombier pdf14_recreate_clist_device(gs_memory_t	*mem, gs_imager_state *	pis,
2492*593dc095SDavid du Colombier 				gx_device * dev)
24933ff48bf5SDavid du Colombier {
2494*593dc095SDavid du Colombier     pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2495*593dc095SDavid du Colombier     gx_device * target = pdev->target;
2496*593dc095SDavid du Colombier     const pdf14_clist_device * dev_proto;
2497*593dc095SDavid du Colombier     int code;
24983ff48bf5SDavid du Colombier 
2499*593dc095SDavid du Colombier     if_debug0('v', "[v]pdf14_recreate_clist_device\n");
2500*593dc095SDavid du Colombier 
2501*593dc095SDavid du Colombier     /*
2502*593dc095SDavid du Colombier      * We will not use the entire prototype device but we will set the
2503*593dc095SDavid du Colombier      * color related info to match the prototype.
2504*593dc095SDavid du Colombier      */
2505*593dc095SDavid du Colombier     code = get_pdf14_clist_device_proto(target, &dev_proto);
2506*593dc095SDavid du Colombier     if (code < 0)
2507*593dc095SDavid du Colombier 	return code;
2508*593dc095SDavid du Colombier     pdev->color_info = dev_proto->color_info;
2509*593dc095SDavid du Colombier     pdev->procs = dev_proto->procs;
2510*593dc095SDavid du Colombier     gx_device_fill_in_procs(dev);
2511*593dc095SDavid du Colombier     check_device_separable((gx_device *)pdev);
2512*593dc095SDavid du Colombier 
2513*593dc095SDavid du Colombier     return code;
2514*593dc095SDavid du Colombier }
2515*593dc095SDavid du Colombier 
2516*593dc095SDavid du Colombier /*
2517*593dc095SDavid du Colombier  * When we are banding, we have two PDF 1.4 compositor devices.  One for
2518*593dc095SDavid du Colombier  * when we are creating the clist.  The second is for imaging the data from
2519*593dc095SDavid du Colombier  * the clist.  This routine is part of the clist writing PDF 1.4 device.
2520*593dc095SDavid du Colombier  * This routine is only called once the PDF 1.4 clist write compositor already
2521*593dc095SDavid du Colombier  * exists.
2522*593dc095SDavid du Colombier  */
2523*593dc095SDavid du Colombier private	int
pdf14_clist_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pct,gs_imager_state * pis,gs_memory_t * mem)2524*593dc095SDavid du Colombier pdf14_clist_create_compositor(gx_device	* dev, gx_device ** pcdev,
2525*593dc095SDavid du Colombier     const gs_composite_t * pct, gs_imager_state * pis, gs_memory_t * mem)
2526*593dc095SDavid du Colombier {
2527*593dc095SDavid du Colombier     pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2528*593dc095SDavid du Colombier     int code;
2529*593dc095SDavid du Colombier 
2530*593dc095SDavid du Colombier     /* We only handle a few PDF 1.4 transparency operations 4 */
2531*593dc095SDavid du Colombier     if (gs_is_pdf14trans_compositor(pct)) {
2532*593dc095SDavid du Colombier 	const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pct;
2533*593dc095SDavid du Colombier 
2534*593dc095SDavid du Colombier 	switch (pdf14pct->params.pdf14_op) {
2535*593dc095SDavid du Colombier 	    case PDF14_PUSH_DEVICE:
2536*593dc095SDavid du Colombier 		/* Re-activate the PDF 1.4 compositor */
2537*593dc095SDavid du Colombier 		pdev->saved_target_color_info = pdev->target->color_info;
2538*593dc095SDavid du Colombier 		pdev->target->color_info = pdev->color_info;
2539*593dc095SDavid du Colombier 		pdev->save_get_cmap_procs = pis->get_cmap_procs;
2540*593dc095SDavid du Colombier 		pis->get_cmap_procs = pdf14_get_cmap_procs;
2541*593dc095SDavid du Colombier 		gx_set_cmap_procs(pis, dev);
2542*593dc095SDavid du Colombier 		code = pdf14_recreate_clist_device(mem, pis, dev);
2543*593dc095SDavid du Colombier 		pdev->blend_mode = pdev->text_knockout = 0;
2544*593dc095SDavid du Colombier 		pdev->opacity = pdev->shape = 0.0;
2545*593dc095SDavid du Colombier 		if (code < 0)
2546*593dc095SDavid du Colombier 		    return code;
2547*593dc095SDavid du Colombier 		/*
2548*593dc095SDavid du Colombier 		 * This routine is part of the PDF 1.4 clist write device.
2549*593dc095SDavid du Colombier 		 * Change the compositor procs to not create another since we
2550*593dc095SDavid du Colombier 		 * do not need to create a chain of identical devices.
2551*593dc095SDavid du Colombier 		 */
2552*593dc095SDavid du Colombier 		{
2553*593dc095SDavid du Colombier 		    gs_composite_t pctemp = *pct;
2554*593dc095SDavid du Colombier 
2555*593dc095SDavid du Colombier 		    pctemp.type = &gs_composite_pdf14trans_no_clist_writer_type;
2556*593dc095SDavid du Colombier 		    code = dev_proc(pdev->target, create_compositor)
2557*593dc095SDavid du Colombier 				(pdev->target, pcdev, &pctemp, pis, mem);
2558*593dc095SDavid du Colombier 		    *pcdev = dev;
2559*593dc095SDavid du Colombier 		    return code;
2560*593dc095SDavid du Colombier 		}
2561*593dc095SDavid du Colombier 	    case PDF14_POP_DEVICE:
2562*593dc095SDavid du Colombier 		/* Restore the color_info for the clist device */
2563*593dc095SDavid du Colombier 		pdev->target->color_info = pdev->saved_target_color_info;
2564*593dc095SDavid du Colombier 		pis->get_cmap_procs = pdev->save_get_cmap_procs;
2565*593dc095SDavid du Colombier 		gx_set_cmap_procs(pis, pdev->target);
2566*593dc095SDavid du Colombier 		/* Disable the PDF 1.4 compositor */
2567*593dc095SDavid du Colombier 		pdf14_disable_clist_device(mem, pis, dev);
2568*593dc095SDavid du Colombier 		/*
2569*593dc095SDavid du Colombier 		 * Make sure that the transfer funtions, etc. are current.
2570*593dc095SDavid du Colombier 		 */
2571*593dc095SDavid du Colombier 		code = cmd_put_color_mapping(
2572*593dc095SDavid du Colombier 			(gx_device_clist_writer *)(pdev->target), pis);
2573*593dc095SDavid du Colombier 		if (code < 0)
2574*593dc095SDavid du Colombier 		    return code;
2575*593dc095SDavid du Colombier 		break;
2576*593dc095SDavid du Colombier 	    case PDF14_BEGIN_TRANS_GROUP:
2577*593dc095SDavid du Colombier 		/*
2578*593dc095SDavid du Colombier 		 * Keep track of any changes made in the blending parameters.
2579*593dc095SDavid du Colombier 		 */
2580*593dc095SDavid du Colombier 		pdev->text_knockout = pdf14pct->params.Knockout;
2581*593dc095SDavid du Colombier 		pdev->blend_mode = pdf14pct->params.blend_mode;
2582*593dc095SDavid du Colombier 		pdev->opacity = pdf14pct->params.opacity.alpha;
2583*593dc095SDavid du Colombier 		pdev->shape = pdf14pct->params.shape.alpha;
2584*593dc095SDavid du Colombier 		{
2585*593dc095SDavid du Colombier 		    const gs_pdf14trans_params_t * pparams = &((const gs_pdf14trans_t *)pct)->params;
2586*593dc095SDavid du Colombier 
2587*593dc095SDavid du Colombier 		    if (pparams->Background_components != 0 &&
2588*593dc095SDavid du Colombier 			pparams->Background_components != pdev->color_info.num_components)
2589*593dc095SDavid du Colombier 			return_error(gs_error_rangecheck);
2590*593dc095SDavid du Colombier 		}
2591*593dc095SDavid du Colombier 		break;
2592*593dc095SDavid du Colombier 	    default:
2593*593dc095SDavid du Colombier 		break;		/* Pass remaining ops to target */
2594*593dc095SDavid du Colombier 	}
2595*593dc095SDavid du Colombier     }
2596*593dc095SDavid du Colombier     code = dev_proc(pdev->target, create_compositor)
2597*593dc095SDavid du Colombier 			(pdev->target, pcdev, pct, pis, mem);
2598*593dc095SDavid du Colombier     if (*pcdev != pdev->target)
2599*593dc095SDavid du Colombier 	rc_assign(pdev->target, *pcdev, "pdf14_clist_create_compositor");
2600*593dc095SDavid du Colombier     *pcdev = dev;
2601*593dc095SDavid du Colombier     return code;
2602*593dc095SDavid du Colombier }
2603*593dc095SDavid du Colombier 
2604*593dc095SDavid du Colombier /*
2605*593dc095SDavid du Colombier  * The PDF 1.4 clist compositor is never removed.  (We do not have a 'remove
2606*593dc095SDavid du Colombier  * compositor' method.  However the compositor is disabled when we are not
2607*593dc095SDavid du Colombier  * doing a page which uses PDF 1.4 transparency.  This routine is only active
2608*593dc095SDavid du Colombier  * when the PDF 1.4 compositor is 'disabled'.  It checks for reenabling the
2609*593dc095SDavid du Colombier  * PDF 1.4 compositor.  Otherwise it simply passes create compositor requests
2610*593dc095SDavid du Colombier  * to the targer.
2611*593dc095SDavid du Colombier  */
2612*593dc095SDavid du Colombier private	int
pdf14_clist_forward_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pct,gs_imager_state * pis,gs_memory_t * mem)2613*593dc095SDavid du Colombier pdf14_clist_forward_create_compositor(gx_device	* dev, gx_device * * pcdev,
2614*593dc095SDavid du Colombier 	const gs_composite_t * pct, gs_imager_state * pis,
2615*593dc095SDavid du Colombier 	gs_memory_t * mem)
2616*593dc095SDavid du Colombier {
2617*593dc095SDavid du Colombier     pdf14_device *pdev = (pdf14_device *)dev;
2618*593dc095SDavid du Colombier     gx_device * tdev = pdev->target;
2619*593dc095SDavid du Colombier     gx_device * ndev;
2620*593dc095SDavid du Colombier     int code = 0;
2621*593dc095SDavid du Colombier 
2622*593dc095SDavid du Colombier     *pcdev = dev;
2623*593dc095SDavid du Colombier     if (gs_is_pdf14trans_compositor(pct)) {
2624*593dc095SDavid du Colombier 	const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pct;
2625*593dc095SDavid du Colombier 
2626*593dc095SDavid du Colombier 	if (pdf14pct->params.pdf14_op == PDF14_PUSH_DEVICE)
2627*593dc095SDavid du Colombier 	    return pdf14_clist_create_compositor(dev, &ndev, pct, pis, mem);
2628*593dc095SDavid du Colombier 	return 0;
2629*593dc095SDavid du Colombier     }
2630*593dc095SDavid du Colombier     code = dev_proc(tdev, create_compositor)(tdev, &ndev, pct, pis, mem);
2631*593dc095SDavid du Colombier     if (code < 0)
2632*593dc095SDavid du Colombier 	return code;
2633*593dc095SDavid du Colombier     pdev->target = ndev;
2634*593dc095SDavid du Colombier     return 0;
2635*593dc095SDavid du Colombier }
2636*593dc095SDavid du Colombier 
2637*593dc095SDavid du Colombier /*
2638*593dc095SDavid du Colombier  * If any of the PDF 1.4 transparency blending parameters have changed, we
2639*593dc095SDavid du Colombier  * need to send them to the PDF 1.4 compositor on the output side of the clist.
2640*593dc095SDavid du Colombier  */
2641*593dc095SDavid du Colombier private	int
pdf14_clist_update_params(pdf14_clist_device * pdev,const gs_imager_state * pis)2642*593dc095SDavid du Colombier pdf14_clist_update_params(pdf14_clist_device * pdev, const gs_imager_state * pis)
2643*593dc095SDavid du Colombier {
2644*593dc095SDavid du Colombier     gs_pdf14trans_params_t params = { 0 };
2645*593dc095SDavid du Colombier     gx_device * pcdev;
2646*593dc095SDavid du Colombier     int changed = 0;
2647*593dc095SDavid du Colombier     int code = 0;
2648*593dc095SDavid du Colombier 
2649*593dc095SDavid du Colombier     params.pdf14_op = PDF14_SET_BLEND_PARAMS;
2650*593dc095SDavid du Colombier     if (pis->blend_mode != pdev->blend_mode) {
2651*593dc095SDavid du Colombier 	changed |= PDF14_SET_BLEND_MODE;
2652*593dc095SDavid du Colombier 	params.blend_mode = pdev->blend_mode = pis->blend_mode;
2653*593dc095SDavid du Colombier     }
2654*593dc095SDavid du Colombier     if (pis->text_knockout != pdev->text_knockout) {
2655*593dc095SDavid du Colombier 	changed |= PDF14_SET_TEXT_KNOCKOUT;
2656*593dc095SDavid du Colombier 	params.text_knockout = pdev->text_knockout = pis->text_knockout;
2657*593dc095SDavid du Colombier     }
2658*593dc095SDavid du Colombier     if (pis->shape.alpha != pdev->shape) {
2659*593dc095SDavid du Colombier 	changed |= PDF14_SET_SHAPE_ALPHA;
2660*593dc095SDavid du Colombier 	params.shape.alpha = pdev->shape = pis->shape.alpha;
2661*593dc095SDavid du Colombier     }
2662*593dc095SDavid du Colombier     if (pis->opacity.alpha != pdev->opacity) {
2663*593dc095SDavid du Colombier 	changed |= PDF14_SET_OPACITY_ALPHA;
2664*593dc095SDavid du Colombier 	params.opacity.alpha = pdev->opacity = pis->opacity.alpha;
2665*593dc095SDavid du Colombier     }
2666*593dc095SDavid du Colombier     /*
2667*593dc095SDavid du Colombier      * Put parameters into a compositor parameter and then call the
2668*593dc095SDavid du Colombier      * create_compositor.  This will pass the data through the clist
2669*593dc095SDavid du Colombier      * to the PDF 1.4 transparency output device.  Note:  This action
2670*593dc095SDavid du Colombier      * never creates a new PDF 1.4 compositor and it does not change
2671*593dc095SDavid du Colombier      * the imager state.
2672*593dc095SDavid du Colombier      */
2673*593dc095SDavid du Colombier     if (changed != 0) {
2674*593dc095SDavid du Colombier 	params.changed = changed;
2675*593dc095SDavid du Colombier 	code = send_pdf14trans((gs_imager_state *)pis, (gx_device *)pdev,
2676*593dc095SDavid du Colombier 					&pcdev, &params, pis->memory);
2677*593dc095SDavid du Colombier     }
2678*593dc095SDavid du Colombier     return code;
2679*593dc095SDavid du Colombier }
2680*593dc095SDavid du Colombier 
2681*593dc095SDavid du Colombier /*
2682*593dc095SDavid du Colombier  * fill_path routine for the PDF 1.4 transaprency compositor device for
2683*593dc095SDavid du Colombier  * writing the clist.
2684*593dc095SDavid du Colombier  */
2685*593dc095SDavid du Colombier private	int
pdf14_clist_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)2686*593dc095SDavid du Colombier pdf14_clist_fill_path(gx_device	*dev, const gs_imager_state *pis,
2687*593dc095SDavid du Colombier 			   gx_path *ppath, const gx_fill_params *params,
2688*593dc095SDavid du Colombier 			   const gx_drawing_color *pdcolor,
2689*593dc095SDavid du Colombier 			   const gx_clip_path *pcpath)
2690*593dc095SDavid du Colombier {
2691*593dc095SDavid du Colombier     pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2692*593dc095SDavid du Colombier     gs_imager_state new_is = *pis;
2693*593dc095SDavid du Colombier     int code;
2694*593dc095SDavid du Colombier 
2695*593dc095SDavid du Colombier     /*
2696*593dc095SDavid du Colombier      * Ensure that that the PDF 1.4 reading compositor will have the current
2697*593dc095SDavid du Colombier      * blending parameters.  This is needed since the fill_rectangle routines
2698*593dc095SDavid du Colombier      * do not have access to the imager state.  Thus we have to pass any
2699*593dc095SDavid du Colombier      * changes explictly.
2700*593dc095SDavid du Colombier      */
2701*593dc095SDavid du Colombier     code = pdf14_clist_update_params(pdev, pis);
2702*593dc095SDavid du Colombier     if (code < 0)
2703*593dc095SDavid du Colombier 	return code;
2704*593dc095SDavid du Colombier     /*
2705*593dc095SDavid du Colombier      * The blend operations are not idempotent.  Force non-idempotent
2706*593dc095SDavid du Colombier      * filling and stroking operations.
2707*593dc095SDavid du Colombier      */
2708*593dc095SDavid du Colombier     new_is.log_op |= lop_pdf14;
2709*593dc095SDavid du Colombier     return gx_default_fill_path(dev, &new_is, ppath, params, pdcolor, pcpath);
2710*593dc095SDavid du Colombier }
2711*593dc095SDavid du Colombier 
2712*593dc095SDavid du Colombier /*
2713*593dc095SDavid du Colombier  * stroke_path routine for the PDF 1.4 transaprency compositor device for
2714*593dc095SDavid du Colombier  * writing the clist.
2715*593dc095SDavid du Colombier  */
2716*593dc095SDavid du Colombier private	int
pdf14_clist_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)2717*593dc095SDavid du Colombier pdf14_clist_stroke_path(gx_device *dev,	const gs_imager_state *pis,
2718*593dc095SDavid du Colombier 			     gx_path *ppath, const gx_stroke_params *params,
2719*593dc095SDavid du Colombier 			     const gx_drawing_color *pdcolor,
2720*593dc095SDavid du Colombier 			     const gx_clip_path *pcpath)
2721*593dc095SDavid du Colombier {
2722*593dc095SDavid du Colombier     pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2723*593dc095SDavid du Colombier     gs_imager_state new_is = *pis;
2724*593dc095SDavid du Colombier     int code;
2725*593dc095SDavid du Colombier 
2726*593dc095SDavid du Colombier     /*
2727*593dc095SDavid du Colombier      * Ensure that that the PDF 1.4 reading compositor will have the current
2728*593dc095SDavid du Colombier      * blending parameters.  This is needed since the fill_rectangle routines
2729*593dc095SDavid du Colombier      * do not have access to the imager state.  Thus we have to pass any
2730*593dc095SDavid du Colombier      * changes explictly.
2731*593dc095SDavid du Colombier      */
2732*593dc095SDavid du Colombier     code = pdf14_clist_update_params(pdev, pis);
2733*593dc095SDavid du Colombier     if (code < 0)
2734*593dc095SDavid du Colombier 	return code;
2735*593dc095SDavid du Colombier     /*
2736*593dc095SDavid du Colombier      * The blend operations are not idempotent.  Force non-idempotent
2737*593dc095SDavid du Colombier      * filling and stroking operations.
2738*593dc095SDavid du Colombier      */
2739*593dc095SDavid du Colombier     new_is.log_op |= lop_pdf14;
2740*593dc095SDavid du Colombier     return gx_default_stroke_path(dev, &new_is, ppath, params, pdcolor, pcpath);
2741*593dc095SDavid du Colombier }
2742*593dc095SDavid du Colombier 
2743*593dc095SDavid du Colombier /*
2744*593dc095SDavid du Colombier  * text_begin routine for the PDF 1.4 transaprency compositor device for
2745*593dc095SDavid du Colombier  * writing the clist.
2746*593dc095SDavid du Colombier  */
2747*593dc095SDavid du Colombier private	int
pdf14_clist_text_begin(gx_device * dev,gs_imager_state * pis,const gs_text_params_t * text,gs_font * font,gx_path * path,const gx_device_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * memory,gs_text_enum_t ** ppenum)2748*593dc095SDavid du Colombier pdf14_clist_text_begin(gx_device * dev,	gs_imager_state	* pis,
2749*593dc095SDavid du Colombier 		 const gs_text_params_t * text, gs_font * font,
2750*593dc095SDavid du Colombier 		 gx_path * path, const gx_device_color * pdcolor,
2751*593dc095SDavid du Colombier 		 const gx_clip_path * pcpath, gs_memory_t * memory,
2752*593dc095SDavid du Colombier 		 gs_text_enum_t ** ppenum)
2753*593dc095SDavid du Colombier {
2754*593dc095SDavid du Colombier     pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2755*593dc095SDavid du Colombier     gs_text_enum_t *penum;
2756*593dc095SDavid du Colombier     int code;
2757*593dc095SDavid du Colombier 
2758*593dc095SDavid du Colombier     /*
2759*593dc095SDavid du Colombier      * Ensure that that the PDF 1.4 reading compositor will have the current
2760*593dc095SDavid du Colombier      * blending parameters.  This is needed since the fill_rectangle routines
2761*593dc095SDavid du Colombier      * do not have access to the imager state.  Thus we have to pass any
2762*593dc095SDavid du Colombier      * changes explictly.
2763*593dc095SDavid du Colombier      */
2764*593dc095SDavid du Colombier     code = pdf14_clist_update_params(pdev, pis);
2765*593dc095SDavid du Colombier     if (code < 0)
2766*593dc095SDavid du Colombier 	return code;
2767*593dc095SDavid du Colombier     /* Pass text_begin to the target */
2768*593dc095SDavid du Colombier     code = gx_default_text_begin(dev, pis, text, font, path,
2769*593dc095SDavid du Colombier 				pdcolor, pcpath, memory, &penum);
2770*593dc095SDavid du Colombier     if (code < 0)
2771*593dc095SDavid du Colombier 	return code;
2772*593dc095SDavid du Colombier     *ppenum = (gs_text_enum_t *)penum;
2773*593dc095SDavid du Colombier     return code;
2774*593dc095SDavid du Colombier }
2775*593dc095SDavid du Colombier 
2776*593dc095SDavid du Colombier private	int
pdf14_clist_begin_image(gx_device * dev,const gs_imager_state * pis,const gs_image_t * pim,gs_image_format_t format,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)2777*593dc095SDavid du Colombier pdf14_clist_begin_image(gx_device * dev,
2778*593dc095SDavid du Colombier 		       const gs_imager_state * pis, const gs_image_t * pim,
2779*593dc095SDavid du Colombier 		       gs_image_format_t format, const gs_int_rect * prect,
2780*593dc095SDavid du Colombier 		       const gx_drawing_color * pdcolor,
2781*593dc095SDavid du Colombier 		       const gx_clip_path * pcpath,
2782*593dc095SDavid du Colombier 		       gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
2783*593dc095SDavid du Colombier {
2784*593dc095SDavid du Colombier     pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2785*593dc095SDavid du Colombier     int code;
2786*593dc095SDavid du Colombier 
2787*593dc095SDavid du Colombier     /*
2788*593dc095SDavid du Colombier      * Ensure that that the PDF 1.4 reading compositor will have the current
2789*593dc095SDavid du Colombier      * blending parameters.  This is needed since the fill_rectangle routines
2790*593dc095SDavid du Colombier      * do not have access to the imager state.  Thus we have to pass any
2791*593dc095SDavid du Colombier      * changes explictly.
2792*593dc095SDavid du Colombier      */
2793*593dc095SDavid du Colombier     code = pdf14_clist_update_params(pdev, pis);
2794*593dc095SDavid du Colombier     if (code < 0)
2795*593dc095SDavid du Colombier 	return code;
2796*593dc095SDavid du Colombier     /* Pass image to the target */
2797*593dc095SDavid du Colombier     return gx_default_begin_image(dev, pis, pim, format, prect,
2798*593dc095SDavid du Colombier 					pdcolor, pcpath, memory, pinfo);
2799*593dc095SDavid du Colombier }
2800*593dc095SDavid du Colombier 
2801*593dc095SDavid du Colombier private	int
pdf14_clist_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 * mem,gx_image_enum_common_t ** pinfo)2802*593dc095SDavid du Colombier pdf14_clist_begin_typed_image(gx_device	* dev, const gs_imager_state * pis,
2803*593dc095SDavid du Colombier 			   const gs_matrix *pmat, const gs_image_common_t *pic,
2804*593dc095SDavid du Colombier 			   const gs_int_rect * prect,
2805*593dc095SDavid du Colombier 			   const gx_drawing_color * pdcolor,
2806*593dc095SDavid du Colombier 			   const gx_clip_path * pcpath, gs_memory_t * mem,
2807*593dc095SDavid du Colombier 			   gx_image_enum_common_t ** pinfo)
2808*593dc095SDavid du Colombier {
2809*593dc095SDavid du Colombier     pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
2810*593dc095SDavid du Colombier     int code;
2811*593dc095SDavid du Colombier 
2812*593dc095SDavid du Colombier     /*
2813*593dc095SDavid du Colombier      * Ensure that that the PDF 1.4 reading compositor will have the current
2814*593dc095SDavid du Colombier      * blending parameters.  This is needed since the fill_rectangle routines
2815*593dc095SDavid du Colombier      * do not have access to the imager state.  Thus we have to pass any
2816*593dc095SDavid du Colombier      * changes explictly.
2817*593dc095SDavid du Colombier      */
2818*593dc095SDavid du Colombier     code = pdf14_clist_update_params(pdev, pis);
2819*593dc095SDavid du Colombier     if (code < 0)
2820*593dc095SDavid du Colombier 	return code;
2821*593dc095SDavid du Colombier     /* Pass image to the target */
2822*593dc095SDavid du Colombier     return gx_default_begin_typed_image(dev, pis, pmat,
2823*593dc095SDavid du Colombier 			    pic, prect, pdcolor, pcpath, mem, pinfo);
2824*593dc095SDavid du Colombier }
2825*593dc095SDavid du Colombier 
2826*593dc095SDavid du Colombier /*
2827*593dc095SDavid du Colombier  * When we push a PDF 1.4 transparency compositor onto the clist, we also need
2828*593dc095SDavid du Colombier  * to create a compositing device for clist writing.  The primary purpose of
2829*593dc095SDavid du Colombier  * this device is to provide support for the process color model in which
2830*593dc095SDavid du Colombier  * the PDF 1.4 transparency is done.  (This may differ from the process color
2831*593dc095SDavid du Colombier  * model of the output device.)  The actual work of compositing the image is
2832*593dc095SDavid du Colombier  * done on the output (reader) side of the clist.
2833*593dc095SDavid du Colombier  */
2834*593dc095SDavid du Colombier private	int
c_pdf14trans_clist_write_update(const gs_composite_t * pcte,gx_device * dev,gx_device ** pcdev,gs_imager_state * pis,gs_memory_t * mem)2835*593dc095SDavid du Colombier c_pdf14trans_clist_write_update(const gs_composite_t * pcte, gx_device * dev,
2836*593dc095SDavid du Colombier 		gx_device ** pcdev, gs_imager_state * pis, gs_memory_t * mem)
2837*593dc095SDavid du Colombier {
2838*593dc095SDavid du Colombier     const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pcte;
2839*593dc095SDavid du Colombier     pdf14_clist_device * p14dev;
2840*593dc095SDavid du Colombier     int code = 0;
2841*593dc095SDavid du Colombier 
2842*593dc095SDavid du Colombier     /* We only handle the push/pop operations */
2843*593dc095SDavid du Colombier     switch (pdf14pct->params.pdf14_op) {
2844*593dc095SDavid du Colombier 	case PDF14_PUSH_DEVICE:
2845*593dc095SDavid du Colombier 	    code = pdf14_create_clist_device(mem, pis, pcdev, dev);
2846*593dc095SDavid du Colombier 	    /*
2847*593dc095SDavid du Colombier 	     * Set the color_info of the clist device to match the compositing
2848*593dc095SDavid du Colombier 	     * device.  We will restore it when the compositor is popped.
2849*593dc095SDavid du Colombier 	     * See pdf14_clist_create_compositor for the restore.  Do the same
2850*593dc095SDavid du Colombier 	     * with the imager state's get_cmap_procs.  We do not want the
2851*593dc095SDavid du Colombier 	     * imager state to use transfer functions on our color values.  The
2852*593dc095SDavid du Colombier 	     * transfer functions will be applied at the end after we have done
2853*593dc095SDavid du Colombier 	     * our PDF 1.4 blend operations.
2854*593dc095SDavid du Colombier 	     */
2855*593dc095SDavid du Colombier 	    p14dev = (pdf14_clist_device *)(*pcdev);
2856*593dc095SDavid du Colombier 	    p14dev->saved_target_color_info = dev->color_info;
2857*593dc095SDavid du Colombier 	    dev->color_info = (*pcdev)->color_info;
2858*593dc095SDavid du Colombier 	    p14dev->save_get_cmap_procs = pis->get_cmap_procs;
2859*593dc095SDavid du Colombier 	    pis->get_cmap_procs = pdf14_get_cmap_procs;
2860*593dc095SDavid du Colombier 	    gx_set_cmap_procs(pis, dev);
2861*593dc095SDavid du Colombier 	    return code;
2862*593dc095SDavid du Colombier 	case PDF14_POP_DEVICE:
2863*593dc095SDavid du Colombier 	    /*
2864*593dc095SDavid du Colombier 	     * Ensure that the tranfer functions, etc.  are current before we
2865*593dc095SDavid du Colombier 	     * dump our transparency image to the output device.
2866*593dc095SDavid du Colombier 	     */
2867*593dc095SDavid du Colombier 	    code = cmd_put_halftone((gx_device_clist_writer *)
2868*593dc095SDavid du Colombier 			(((pdf14_clist_device *)dev)->target), pis->dev_ht);
2869*593dc095SDavid du Colombier 	    break;
2870*593dc095SDavid du Colombier 	default:
2871*593dc095SDavid du Colombier 	    break;		/* do nothing for remaining ops */
2872*593dc095SDavid du Colombier     }
2873*593dc095SDavid du Colombier     *pcdev = dev;
2874*593dc095SDavid du Colombier     return code;
2875*593dc095SDavid du Colombier }
2876*593dc095SDavid du Colombier 
2877*593dc095SDavid du Colombier /*
2878*593dc095SDavid du Colombier  * When we push a PDF 1.4 transparency compositor, we need to make the clist
2879*593dc095SDavid du Colombier  * device color_info data match the compositing device.  We need to do this
2880*593dc095SDavid du Colombier  * since the PDF 1.4 transparency compositing device may use a different
2881*593dc095SDavid du Colombier  * process color model than the output device.  We do not need to modify the
2882*593dc095SDavid du Colombier  * color related device procs since the compositing device has its own.  We
2883*593dc095SDavid du Colombier  * restore the color_info data when the transparency device is popped.
2884*593dc095SDavid du Colombier  */
2885*593dc095SDavid du Colombier private	int
c_pdf14trans_clist_read_update(gs_composite_t * pcte,gx_device * cdev,gx_device * tdev,gs_imager_state * pis,gs_memory_t * mem)2886*593dc095SDavid du Colombier c_pdf14trans_clist_read_update(gs_composite_t *	pcte, gx_device	* cdev,
2887*593dc095SDavid du Colombier 		gx_device * tdev, gs_imager_state * pis, gs_memory_t * mem)
2888*593dc095SDavid du Colombier {
2889*593dc095SDavid du Colombier     pdf14_device * p14dev = (pdf14_device *)tdev;
2890*593dc095SDavid du Colombier     gs_pdf14trans_t * pdf14pct = (gs_pdf14trans_t *) pcte;
2891*593dc095SDavid du Colombier 
2892*593dc095SDavid du Colombier     /*
2893*593dc095SDavid du Colombier      * We only handle the push/pop operations. Save and restore the color_info
2894*593dc095SDavid du Colombier      * field for the clist device.  (This is needed since the process color
2895*593dc095SDavid du Colombier      * model of the clist device needs to match the PDF 1.4 compositing
2896*593dc095SDavid du Colombier      * device.
2897*593dc095SDavid du Colombier      */
2898*593dc095SDavid du Colombier     switch (pdf14pct->params.pdf14_op) {
2899*593dc095SDavid du Colombier 	case PDF14_PUSH_DEVICE:
2900*593dc095SDavid du Colombier 	    p14dev->saved_clist_color_info = cdev->color_info;
2901*593dc095SDavid du Colombier 	    cdev->color_info = p14dev->color_info;
2902*593dc095SDavid du Colombier 	    break;
2903*593dc095SDavid du Colombier 	case PDF14_POP_DEVICE:
2904*593dc095SDavid du Colombier 	    cdev->color_info = p14dev->saved_clist_color_info;
2905*593dc095SDavid du Colombier 	    break;
2906*593dc095SDavid du Colombier 	default:
2907*593dc095SDavid du Colombier 	    break;		/* do nothing for remaining ops */
2908*593dc095SDavid du Colombier     }
29093ff48bf5SDavid du Colombier     return 0;
29103ff48bf5SDavid du Colombier }
2911