1*593dc095SDavid du Colombier /* Copyright (C) 2002 Aladdin Enterprises. All rights reserved.
2*593dc095SDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
5*593dc095SDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
9*593dc095SDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15*593dc095SDavid du Colombier */
16*593dc095SDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gsovrc.c,v 1.10 2005/06/29 23:46:24 dan Exp $ */
18*593dc095SDavid du Colombier /* overprint/overprint mode compositor implementation */
19*593dc095SDavid du Colombier
20*593dc095SDavid du Colombier #include "memory_.h"
21*593dc095SDavid du Colombier #include "gx.h"
22*593dc095SDavid du Colombier #include "gserrors.h"
23*593dc095SDavid du Colombier #include "gsutil.h" /* for gs_next_ids */
24*593dc095SDavid du Colombier #include "gxcomp.h"
25*593dc095SDavid du Colombier #include "gxdevice.h"
26*593dc095SDavid du Colombier #include "gsdevice.h"
27*593dc095SDavid du Colombier #include "gxgetbit.h"
28*593dc095SDavid du Colombier #include "gsovrc.h"
29*593dc095SDavid du Colombier #include "gxdcolor.h"
30*593dc095SDavid du Colombier #include "gxoprect.h"
31*593dc095SDavid du Colombier #include "gsbitops.h"
32*593dc095SDavid du Colombier #include "gxistate.h"
33*593dc095SDavid du Colombier
34*593dc095SDavid du Colombier
35*593dc095SDavid du Colombier /* GC descriptor for gs_overprint_t */
36*593dc095SDavid du Colombier private_st_gs_overprint_t();
37*593dc095SDavid du Colombier
38*593dc095SDavid du Colombier /*
39*593dc095SDavid du Colombier * Utility routine for encoding or decoding a color index. We cannot use
40*593dc095SDavid du Colombier * the general integer encoding routins for these, as they may be 64 bits
41*593dc095SDavid du Colombier * in length (the general routines are only designed for 32 bits). We also
42*593dc095SDavid du Colombier * cannot use the color-specific routines, as we do not have the required
43*593dc095SDavid du Colombier * device color information available.
44*593dc095SDavid du Colombier *
45*593dc095SDavid du Colombier * The scheme employed is the potentially 64-bit analog of the 32-bit
46*593dc095SDavid du Colombier * routines: the low order seven bits of each bytes represents a base-128
47*593dc095SDavid du Colombier * digit, and the high order bit is set if there is another digit. The
48*593dc095SDavid du Colombier * encoding order is little-endian.
49*593dc095SDavid du Colombier *
50*593dc095SDavid du Colombier * The write routine returns 0 on success, with *psize set to the number
51*593dc095SDavid du Colombier * of bytes used. Alternatively, the return value will be gs_error_rangecheck,
52*593dc095SDavid du Colombier * with *psize set to the number of bytes required, if there was insufficient
53*593dc095SDavid du Colombier * space.
54*593dc095SDavid du Colombier *
55*593dc095SDavid du Colombier * The read routine returns the number of bytes read on success, or < 0 in
56*593dc095SDavid du Colombier * the event of an error.
57*593dc095SDavid du Colombier */
58*593dc095SDavid du Colombier private int
write_color_index(gx_color_index cindex,byte * data,uint * psize)59*593dc095SDavid du Colombier write_color_index(gx_color_index cindex, byte * data, uint * psize)
60*593dc095SDavid du Colombier {
61*593dc095SDavid du Colombier int num_bytes = 0;
62*593dc095SDavid du Colombier gx_color_index ctmp = cindex;
63*593dc095SDavid du Colombier
64*593dc095SDavid du Colombier for (num_bytes = 1; (ctmp >>= 7) != 0; ++num_bytes)
65*593dc095SDavid du Colombier ;
66*593dc095SDavid du Colombier if (num_bytes > *psize) {
67*593dc095SDavid du Colombier *psize = num_bytes;
68*593dc095SDavid du Colombier return gs_error_rangecheck;
69*593dc095SDavid du Colombier }
70*593dc095SDavid du Colombier ctmp = cindex;
71*593dc095SDavid du Colombier *psize = num_bytes;
72*593dc095SDavid du Colombier for (; num_bytes > 1; ctmp >>= 7, --num_bytes)
73*593dc095SDavid du Colombier *data++ = 0x80 | (ctmp & 0x7f);
74*593dc095SDavid du Colombier *data = ctmp & 0x7f;
75*593dc095SDavid du Colombier return 0;
76*593dc095SDavid du Colombier }
77*593dc095SDavid du Colombier
78*593dc095SDavid du Colombier private int
read_color_index(gx_color_index * pcindex,const byte * data,uint size)79*593dc095SDavid du Colombier read_color_index(gx_color_index * pcindex, const byte * data, uint size)
80*593dc095SDavid du Colombier {
81*593dc095SDavid du Colombier gx_color_index cindex = 0;
82*593dc095SDavid du Colombier int nbytes = 0, shift = 0;
83*593dc095SDavid du Colombier
84*593dc095SDavid du Colombier for (;; shift += 7, data++) {
85*593dc095SDavid du Colombier if (++nbytes > size)
86*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
87*593dc095SDavid du Colombier else {
88*593dc095SDavid du Colombier int c = *data;
89*593dc095SDavid du Colombier
90*593dc095SDavid du Colombier cindex += (c & 0x7f) << shift;
91*593dc095SDavid du Colombier if ((c & 0x80) == 0)
92*593dc095SDavid du Colombier break;
93*593dc095SDavid du Colombier }
94*593dc095SDavid du Colombier }
95*593dc095SDavid du Colombier *pcindex = cindex;
96*593dc095SDavid du Colombier return nbytes;
97*593dc095SDavid du Colombier }
98*593dc095SDavid du Colombier
99*593dc095SDavid du Colombier /*
100*593dc095SDavid du Colombier * Check for equality of two overprint compositor objects.
101*593dc095SDavid du Colombier *
102*593dc095SDavid du Colombier * This is fairly simple.
103*593dc095SDavid du Colombier */
104*593dc095SDavid du Colombier private bool
c_overprint_equal(const gs_composite_t * pct0,const gs_composite_t * pct1)105*593dc095SDavid du Colombier c_overprint_equal(const gs_composite_t * pct0, const gs_composite_t * pct1)
106*593dc095SDavid du Colombier {
107*593dc095SDavid du Colombier if (pct0->type == pct1->type) {
108*593dc095SDavid du Colombier const gs_overprint_params_t * pparams0;
109*593dc095SDavid du Colombier const gs_overprint_params_t * pparams1;
110*593dc095SDavid du Colombier
111*593dc095SDavid du Colombier pparams0 = &((const gs_overprint_t *)(pct0))->params;
112*593dc095SDavid du Colombier pparams1 = &((const gs_overprint_t *)(pct1))->params;
113*593dc095SDavid du Colombier if (!pparams0->retain_any_comps)
114*593dc095SDavid du Colombier return !pparams1->retain_any_comps;
115*593dc095SDavid du Colombier else if (pparams0->retain_spot_comps)
116*593dc095SDavid du Colombier return pparams1->retain_spot_comps;
117*593dc095SDavid du Colombier else
118*593dc095SDavid du Colombier return pparams0->drawn_comps == pparams1->drawn_comps;
119*593dc095SDavid du Colombier } else
120*593dc095SDavid du Colombier return false;
121*593dc095SDavid du Colombier }
122*593dc095SDavid du Colombier
123*593dc095SDavid du Colombier /*
124*593dc095SDavid du Colombier * Bits corresponding to boolean values in the first byte of the string
125*593dc095SDavid du Colombier * representation of an overprint compositor.
126*593dc095SDavid du Colombier */
127*593dc095SDavid du Colombier #define OVERPRINT_ANY_COMPS 1
128*593dc095SDavid du Colombier #define OVERPRINT_SPOT_COMPS 2
129*593dc095SDavid du Colombier
130*593dc095SDavid du Colombier /*
131*593dc095SDavid du Colombier * Convert an overprint compositor to string form for use by the command
132*593dc095SDavid du Colombier * list device.
133*593dc095SDavid du Colombier */
134*593dc095SDavid du Colombier private int
c_overprint_write(const gs_composite_t * pct,byte * data,uint * psize)135*593dc095SDavid du Colombier c_overprint_write(const gs_composite_t * pct, byte * data, uint * psize)
136*593dc095SDavid du Colombier {
137*593dc095SDavid du Colombier const gs_overprint_params_t * pparams = &((const gs_overprint_t *)pct)->params;
138*593dc095SDavid du Colombier byte flags = 0;
139*593dc095SDavid du Colombier int used = 1, avail = *psize;
140*593dc095SDavid du Colombier
141*593dc095SDavid du Colombier /* encoded the booleans in a single byte */
142*593dc095SDavid du Colombier if (pparams->retain_any_comps) {
143*593dc095SDavid du Colombier flags |= OVERPRINT_ANY_COMPS;
144*593dc095SDavid du Colombier
145*593dc095SDavid du Colombier /* write out the component bits only if necessary (and possible) */
146*593dc095SDavid du Colombier if (pparams->retain_spot_comps)
147*593dc095SDavid du Colombier flags |= OVERPRINT_SPOT_COMPS;
148*593dc095SDavid du Colombier else {
149*593dc095SDavid du Colombier uint tmp_size = (avail > 0 ? avail - 1 : 0);
150*593dc095SDavid du Colombier int code = write_color_index( pparams->drawn_comps,
151*593dc095SDavid du Colombier data + 1,
152*593dc095SDavid du Colombier &tmp_size );
153*593dc095SDavid du Colombier
154*593dc095SDavid du Colombier if (code < 0 && code != gs_error_rangecheck)
155*593dc095SDavid du Colombier return code;
156*593dc095SDavid du Colombier used += tmp_size;
157*593dc095SDavid du Colombier }
158*593dc095SDavid du Colombier }
159*593dc095SDavid du Colombier
160*593dc095SDavid du Colombier /* check for overflow */
161*593dc095SDavid du Colombier *psize = used;
162*593dc095SDavid du Colombier if (used > avail)
163*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
164*593dc095SDavid du Colombier data[0] = flags;
165*593dc095SDavid du Colombier return 0;
166*593dc095SDavid du Colombier }
167*593dc095SDavid du Colombier
168*593dc095SDavid du Colombier /*
169*593dc095SDavid du Colombier * Convert the string representation of the overprint parameter into the
170*593dc095SDavid du Colombier * full compositor.
171*593dc095SDavid du Colombier */
172*593dc095SDavid du Colombier private int
c_overprint_read(gs_composite_t ** ppct,const byte * data,uint size,gs_memory_t * mem)173*593dc095SDavid du Colombier c_overprint_read(
174*593dc095SDavid du Colombier gs_composite_t ** ppct,
175*593dc095SDavid du Colombier const byte * data,
176*593dc095SDavid du Colombier uint size,
177*593dc095SDavid du Colombier gs_memory_t * mem )
178*593dc095SDavid du Colombier {
179*593dc095SDavid du Colombier gs_overprint_params_t params;
180*593dc095SDavid du Colombier byte flags = 0;
181*593dc095SDavid du Colombier int code = 0, nbytes = 1;
182*593dc095SDavid du Colombier
183*593dc095SDavid du Colombier if (size < 1)
184*593dc095SDavid du Colombier return_error(gs_error_rangecheck);
185*593dc095SDavid du Colombier flags = *data;
186*593dc095SDavid du Colombier params.retain_any_comps = (flags & OVERPRINT_ANY_COMPS) != 0;
187*593dc095SDavid du Colombier params.retain_spot_comps = (flags & OVERPRINT_SPOT_COMPS) != 0;
188*593dc095SDavid du Colombier
189*593dc095SDavid du Colombier /* check if the drawn_comps array is present */
190*593dc095SDavid du Colombier if (params.retain_any_comps && !params.retain_spot_comps) {
191*593dc095SDavid du Colombier code = read_color_index(¶ms.drawn_comps, data + 1, size - 1);
192*593dc095SDavid du Colombier if (code < 0)
193*593dc095SDavid du Colombier return code;
194*593dc095SDavid du Colombier nbytes += code;
195*593dc095SDavid du Colombier }
196*593dc095SDavid du Colombier
197*593dc095SDavid du Colombier code = gs_create_overprint(ppct, ¶ms, mem);
198*593dc095SDavid du Colombier
199*593dc095SDavid du Colombier return code < 0 ? code : nbytes;
200*593dc095SDavid du Colombier }
201*593dc095SDavid du Colombier
202*593dc095SDavid du Colombier
203*593dc095SDavid du Colombier private composite_create_default_compositor_proc(c_overprint_create_default_compositor);
204*593dc095SDavid du Colombier
205*593dc095SDavid du Colombier /* methods for the overprint compositor */
206*593dc095SDavid du Colombier const gs_composite_type_t gs_composite_overprint_type = {
207*593dc095SDavid du Colombier GX_COMPOSITOR_OVERPRINT,
208*593dc095SDavid du Colombier {
209*593dc095SDavid du Colombier c_overprint_create_default_compositor, /* procs.create_default_compositor */
210*593dc095SDavid du Colombier c_overprint_equal, /* procs.equal */
211*593dc095SDavid du Colombier c_overprint_write, /* procs.write */
212*593dc095SDavid du Colombier c_overprint_read, /* procs.read */
213*593dc095SDavid du Colombier gx_default_composite_clist_write_update,/* procs.composite_clist_write_update */
214*593dc095SDavid du Colombier gx_default_composite_clist_read_update /* procs.composite_clist_reade_update */
215*593dc095SDavid du Colombier } /* procs */
216*593dc095SDavid du Colombier };
217*593dc095SDavid du Colombier
218*593dc095SDavid du Colombier
219*593dc095SDavid du Colombier /*
220*593dc095SDavid du Colombier * Create an overprint compositor data structure.
221*593dc095SDavid du Colombier *
222*593dc095SDavid du Colombier * Currently this just a stub.
223*593dc095SDavid du Colombier */
224*593dc095SDavid du Colombier int
gs_create_overprint(gs_composite_t ** ppct,const gs_overprint_params_t * pparams,gs_memory_t * mem)225*593dc095SDavid du Colombier gs_create_overprint(
226*593dc095SDavid du Colombier gs_composite_t ** ppct,
227*593dc095SDavid du Colombier const gs_overprint_params_t * pparams,
228*593dc095SDavid du Colombier gs_memory_t * mem )
229*593dc095SDavid du Colombier {
230*593dc095SDavid du Colombier gs_overprint_t * pct;
231*593dc095SDavid du Colombier
232*593dc095SDavid du Colombier rc_alloc_struct_0( pct,
233*593dc095SDavid du Colombier gs_overprint_t,
234*593dc095SDavid du Colombier &st_overprint,
235*593dc095SDavid du Colombier mem,
236*593dc095SDavid du Colombier return_error(gs_error_VMerror),
237*593dc095SDavid du Colombier "gs_create_overprint" );
238*593dc095SDavid du Colombier pct->type = &gs_composite_overprint_type;
239*593dc095SDavid du Colombier pct->id = gs_next_ids(mem, 1);
240*593dc095SDavid du Colombier pct->params = *pparams;
241*593dc095SDavid du Colombier *ppct = (gs_composite_t *)pct;
242*593dc095SDavid du Colombier return 0;
243*593dc095SDavid du Colombier }
244*593dc095SDavid du Colombier
245*593dc095SDavid du Colombier
246*593dc095SDavid du Colombier /*
247*593dc095SDavid du Colombier * Verify that a compositor data structure is for the overprint compositor.
248*593dc095SDavid du Colombier * This is used by the gs_pdf1.4_device (and eventually the PDFWrite
249*593dc095SDavid du Colombier * device), which implements overprint and overprint mode directly.
250*593dc095SDavid du Colombier */
251*593dc095SDavid du Colombier int
gs_is_overprint_compositor(const gs_composite_t * pct)252*593dc095SDavid du Colombier gs_is_overprint_compositor(const gs_composite_t * pct)
253*593dc095SDavid du Colombier {
254*593dc095SDavid du Colombier return pct->type == &gs_composite_overprint_type;
255*593dc095SDavid du Colombier }
256*593dc095SDavid du Colombier
257*593dc095SDavid du Colombier
258*593dc095SDavid du Colombier /*
259*593dc095SDavid du Colombier * The overprint device.
260*593dc095SDavid du Colombier *
261*593dc095SDavid du Colombier * In principle there are two versions of this device: one if the traget
262*593dc095SDavid du Colombier * device is separable and linear, the other if it is not. The two have
263*593dc095SDavid du Colombier * slightly different data structures, but differ primarily in terms of
264*593dc095SDavid du Colombier * the standard set of methods. Because methods are non-static in
265*593dc095SDavid du Colombier * GhostScript, we make use of the same data structure and handle the
266*593dc095SDavid du Colombier * distinction during initialization.
267*593dc095SDavid du Colombier *
268*593dc095SDavid du Colombier * The data fields reflect entries in the gs_overprint_params_t
269*593dc095SDavid du Colombier * structure. There is no explicit retain_any_comps field, as the current
270*593dc095SDavid du Colombier * setting of this field can be determined by checking the fill_rectangle
271*593dc095SDavid du Colombier * method. There is also no retain_spot_comps field, as the code will
272*593dc095SDavid du Colombier * will determine explicitly which components are to be drawn.
273*593dc095SDavid du Colombier */
274*593dc095SDavid du Colombier typedef struct overprint_device_s {
275*593dc095SDavid du Colombier gx_device_forward_common;
276*593dc095SDavid du Colombier
277*593dc095SDavid du Colombier /*
278*593dc095SDavid du Colombier * The set of components to be drawn. This field is used only if the
279*593dc095SDavid du Colombier * target color space is not separable and linear.
280*593dc095SDavid du Colombier */
281*593dc095SDavid du Colombier gx_color_index drawn_comps;
282*593dc095SDavid du Colombier
283*593dc095SDavid du Colombier /*
284*593dc095SDavid du Colombier * The mask of gx_color_index bits to be retained during a drawing
285*593dc095SDavid du Colombier * operation. A bit in this mask is 1 if the corresponding bit or
286*593dc095SDavid du Colombier * the color index is to be retained; otherwise it is 0.
287*593dc095SDavid du Colombier *
288*593dc095SDavid du Colombier * The "non-drawn" region of the drawing gx_color_index is assumed
289*593dc095SDavid du Colombier * to have the value zero, so for a separable and linear color
290*593dc095SDavid du Colombier * encoding, the per-pixel drawing operation is:
291*593dc095SDavid du Colombier *
292*593dc095SDavid du Colombier * output = (output & retain_mask) | src
293*593dc095SDavid du Colombier *
294*593dc095SDavid du Colombier * (For the fully general case, replace src by (src & ~retain_mask).)
295*593dc095SDavid du Colombier * Because of byte-alignment, byte-order and performance consideration,
296*593dc095SDavid du Colombier * the actually implement operation may be more complex, but this does
297*593dc095SDavid du Colombier * not change the overall effect.
298*593dc095SDavid du Colombier *
299*593dc095SDavid du Colombier * The actual value of retain_mask will be byte swap if this is
300*593dc095SDavid du Colombier * required. It will be required if depth > 8 and the host processor
301*593dc095SDavid du Colombier * is little-endian.
302*593dc095SDavid du Colombier */
303*593dc095SDavid du Colombier gx_color_index retain_mask;
304*593dc095SDavid du Colombier
305*593dc095SDavid du Colombier } overprint_device_t;
306*593dc095SDavid du Colombier
307*593dc095SDavid du Colombier gs_private_st_suffix_add0_final( st_overprint_device_t,
308*593dc095SDavid du Colombier overprint_device_t,
309*593dc095SDavid du Colombier "overprint_device_t",
310*593dc095SDavid du Colombier overprint_device_t_enum_ptrs,
311*593dc095SDavid du Colombier overprint_device_t_reloc_ptrs,
312*593dc095SDavid du Colombier gx_device_finalize,
313*593dc095SDavid du Colombier st_device_forward );
314*593dc095SDavid du Colombier
315*593dc095SDavid du Colombier
316*593dc095SDavid du Colombier /*
317*593dc095SDavid du Colombier * In the default (overprint false) case, the overprint device is almost
318*593dc095SDavid du Colombier * a pure forwarding device: only the open_device and create_compositor
319*593dc095SDavid du Colombier * methods are not pure-forwarding methods. The
320*593dc095SDavid du Colombier * gx_device_foward_fill_in_procs procedure does not fill in all of the
321*593dc095SDavid du Colombier * necessary procedures, so some of them are provided explicitly below.
322*593dc095SDavid du Colombier * The put_params procedure also requires a small modification, so that
323*593dc095SDavid du Colombier * the open/close state of this device always reflects that of its
324*593dc095SDavid du Colombier * target.
325*593dc095SDavid du Colombier *
326*593dc095SDavid du Colombier * This and other method arrays are not declared const so that they may
327*593dc095SDavid du Colombier * be initialized once via gx_device_forward_fill_in_procs. They are
328*593dc095SDavid du Colombier * constant once this initialization is complete.
329*593dc095SDavid du Colombier */
330*593dc095SDavid du Colombier private dev_proc_open_device(overprint_open_device);
331*593dc095SDavid du Colombier private dev_proc_put_params(overprint_put_params);
332*593dc095SDavid du Colombier private dev_proc_get_page_device(overprint_get_page_device);
333*593dc095SDavid du Colombier private dev_proc_create_compositor(overprint_create_compositor);
334*593dc095SDavid du Colombier
335*593dc095SDavid du Colombier private gx_device_procs no_overprint_procs = {
336*593dc095SDavid du Colombier overprint_open_device, /* open_device */
337*593dc095SDavid du Colombier 0, /* get_initial_matrix */
338*593dc095SDavid du Colombier 0, /* sync_output */
339*593dc095SDavid du Colombier 0, /* output_page */
340*593dc095SDavid du Colombier 0, /* close_device */
341*593dc095SDavid du Colombier 0, /* map_rgb_color */
342*593dc095SDavid du Colombier 0, /* map_color_rgb */
343*593dc095SDavid du Colombier gx_forward_fill_rectangle, /* fill_rectangle */
344*593dc095SDavid du Colombier gx_forward_tile_rectangle, /* tile_rectangle */
345*593dc095SDavid du Colombier gx_forward_copy_mono, /* copy_mono */
346*593dc095SDavid du Colombier gx_forward_copy_color, /* copy_color */
347*593dc095SDavid du Colombier 0, /* draw_line (obsolete) */
348*593dc095SDavid du Colombier 0, /* get_bits */
349*593dc095SDavid du Colombier 0, /* get_params */
350*593dc095SDavid du Colombier overprint_put_params, /* put_params */
351*593dc095SDavid du Colombier 0, /* map_cmyk_color */
352*593dc095SDavid du Colombier 0, /* get_xfont_procs */
353*593dc095SDavid du Colombier 0, /* get_xfont_device */
354*593dc095SDavid du Colombier 0, /* map_rgb_alpha_color */
355*593dc095SDavid du Colombier overprint_get_page_device, /* get_page_device */
356*593dc095SDavid du Colombier 0, /* get_alpha_bits (obsolete) */
357*593dc095SDavid du Colombier 0, /* copy alpha */
358*593dc095SDavid du Colombier 0, /* get_band */
359*593dc095SDavid du Colombier 0, /* copy_rop */
360*593dc095SDavid du Colombier 0, /* fill_path */
361*593dc095SDavid du Colombier 0, /* stroke_path */
362*593dc095SDavid du Colombier 0, /* fill_mask */
363*593dc095SDavid du Colombier 0, /* fill_trapezoid */
364*593dc095SDavid du Colombier 0, /* fill_parallelogram */
365*593dc095SDavid du Colombier 0, /* fill_triangle */
366*593dc095SDavid du Colombier 0, /* draw_thin_line */
367*593dc095SDavid du Colombier 0, /* begin_image */
368*593dc095SDavid du Colombier 0, /* image_data (obsolete) */
369*593dc095SDavid du Colombier 0, /* end_image (obsolete) */
370*593dc095SDavid du Colombier gx_forward_strip_tile_rectangle, /* strip_tile_rectangle */
371*593dc095SDavid du Colombier 0, /* strip_copy_rop */
372*593dc095SDavid du Colombier 0, /* get_clipping_box */
373*593dc095SDavid du Colombier 0, /* begin_typed_image */
374*593dc095SDavid du Colombier 0, /* get_bits_rectangle */
375*593dc095SDavid du Colombier 0, /* map_color_rgb_alpha */
376*593dc095SDavid du Colombier overprint_create_compositor, /* create_compositor */
377*593dc095SDavid du Colombier 0, /* get_hardware_params */
378*593dc095SDavid du Colombier 0, /* text_begin */
379*593dc095SDavid du Colombier 0, /* gx_finish_copydevice */
380*593dc095SDavid du Colombier 0, /* begin_transparency_group */
381*593dc095SDavid du Colombier 0, /* end_transparency_group */
382*593dc095SDavid du Colombier 0, /* being_transparency_mask */
383*593dc095SDavid du Colombier 0, /* end_transparency_mask */
384*593dc095SDavid du Colombier 0, /* discard_transparency_layer */
385*593dc095SDavid du Colombier 0, /* get_color_mapping_procs */
386*593dc095SDavid du Colombier 0, /* get_color_comp_index */
387*593dc095SDavid du Colombier 0, /* encode_color */
388*593dc095SDavid du Colombier 0 /* decode_color */
389*593dc095SDavid du Colombier };
390*593dc095SDavid du Colombier
391*593dc095SDavid du Colombier /*
392*593dc095SDavid du Colombier * If overprint is set, the high and mid-level rendering methods are
393*593dc095SDavid du Colombier * replaced by the default routines. The low-level color rendering methods
394*593dc095SDavid du Colombier * are replaced with one of two sets of functions, depending on whether or
395*593dc095SDavid du Colombier * not the target device has a separable and linear color encoding.
396*593dc095SDavid du Colombier *
397*593dc095SDavid du Colombier * 1. If the target device does not have a separable and linear
398*593dc095SDavid du Colombier * encoding, an overprint-specific fill_rectangle method is used,
399*593dc095SDavid du Colombier * and the default methods are used for all other low-level rendering
400*593dc095SDavid du Colombier * methods. There is no way to achieve good rendering performance
401*593dc095SDavid du Colombier * when overprint is true and the color encoding is not separable
402*593dc095SDavid du Colombier * and linear, so there is little reason to use more elaborate
403*593dc095SDavid du Colombier * methods int this case.
404*593dc095SDavid du Colombier *
405*593dc095SDavid du Colombier * 2. If the target device does have a separable and linear color
406*593dc095SDavid du Colombier * model, at least the fill_rectangle method and potentially other
407*593dc095SDavid du Colombier * methods will be replaced by overprint-specific methods. Those
408*593dc095SDavid du Colombier * methods not replaced will have their default values. The number
409*593dc095SDavid du Colombier * of methods replaced is dependent on the desired level of
410*593dc095SDavid du Colombier * performance: the more methods, the better the performance.
411*593dc095SDavid du Colombier *
412*593dc095SDavid du Colombier * Note that certain procedures, such as copy_alpha and copy_rop,
413*593dc095SDavid du Colombier * are likely to always be given their default values, as the concepts
414*593dc095SDavid du Colombier * of alpha-compositing and raster operations are not compatible in
415*593dc095SDavid du Colombier * a strict sense.
416*593dc095SDavid du Colombier */
417*593dc095SDavid du Colombier private dev_proc_fill_rectangle(overprint_generic_fill_rectangle);
418*593dc095SDavid du Colombier private dev_proc_fill_rectangle(overprint_sep_fill_rectangle);
419*593dc095SDavid du Colombier /* other low-level overprint_sep_* rendering methods prototypes go here */
420*593dc095SDavid du Colombier
421*593dc095SDavid du Colombier private gx_device_procs generic_overprint_procs = {
422*593dc095SDavid du Colombier overprint_open_device, /* open_device */
423*593dc095SDavid du Colombier 0, /* get_initial_matrix */
424*593dc095SDavid du Colombier 0, /* sync_output */
425*593dc095SDavid du Colombier 0, /* output_page */
426*593dc095SDavid du Colombier 0, /* close_device */
427*593dc095SDavid du Colombier 0, /* map_rgb_color */
428*593dc095SDavid du Colombier 0, /* map_color_rgb */
429*593dc095SDavid du Colombier overprint_generic_fill_rectangle, /* fill_rectangle */
430*593dc095SDavid du Colombier gx_default_tile_rectangle, /* tile_rectangle */
431*593dc095SDavid du Colombier gx_default_copy_mono, /* copy_mono */
432*593dc095SDavid du Colombier gx_default_copy_color, /* copy_color */
433*593dc095SDavid du Colombier gx_default_draw_line, /* draw_line (obsolete) */
434*593dc095SDavid du Colombier 0, /* get_bits */
435*593dc095SDavid du Colombier 0, /* get_params */
436*593dc095SDavid du Colombier overprint_put_params, /* put_params */
437*593dc095SDavid du Colombier 0, /* map_cmyk_color */
438*593dc095SDavid du Colombier 0, /* get_xfont_procs */
439*593dc095SDavid du Colombier gx_default_get_xfont_device, /* get_xfont_device */
440*593dc095SDavid du Colombier 0, /* map_rgb_alpha_color */
441*593dc095SDavid du Colombier overprint_get_page_device, /* get_page_device */
442*593dc095SDavid du Colombier 0, /* get_alpha_bits (obsolete) */
443*593dc095SDavid du Colombier gx_default_copy_alpha, /* copy alpha */
444*593dc095SDavid du Colombier 0, /* get_band */
445*593dc095SDavid du Colombier gx_default_copy_rop, /* copy_rop */
446*593dc095SDavid du Colombier gx_default_fill_path, /* fill_path */
447*593dc095SDavid du Colombier gx_default_stroke_path, /* stroke_path */
448*593dc095SDavid du Colombier gx_default_fill_mask, /* fill_mask */
449*593dc095SDavid du Colombier gx_default_fill_trapezoid, /* fill_trapezoid */
450*593dc095SDavid du Colombier gx_default_fill_parallelogram, /* fill_parallelogram */
451*593dc095SDavid du Colombier gx_default_fill_triangle, /* fill_triangle */
452*593dc095SDavid du Colombier gx_default_draw_thin_line, /* draw_thin_line */
453*593dc095SDavid du Colombier gx_default_begin_image, /* begin_image */
454*593dc095SDavid du Colombier 0, /* image_data (obsolete) */
455*593dc095SDavid du Colombier 0, /* end_image (obsolete) */
456*593dc095SDavid du Colombier gx_default_strip_tile_rectangle, /* strip_tile_rectangle */
457*593dc095SDavid du Colombier gx_default_strip_copy_rop, /* strip_copy_rop */
458*593dc095SDavid du Colombier 0, /* get_clipping_box */
459*593dc095SDavid du Colombier gx_default_begin_typed_image, /* begin_typed_image */
460*593dc095SDavid du Colombier 0, /* get_bits_rectangle */
461*593dc095SDavid du Colombier 0, /* map_color_rgb_alpha */
462*593dc095SDavid du Colombier overprint_create_compositor, /* create_compositor */
463*593dc095SDavid du Colombier 0, /* get_hardware_params */
464*593dc095SDavid du Colombier gx_default_text_begin, /* text_begin */
465*593dc095SDavid du Colombier 0, /* gx_finish_copydevice */
466*593dc095SDavid du Colombier 0, /* begin_transparency_group */
467*593dc095SDavid du Colombier 0, /* end_transparency_group */
468*593dc095SDavid du Colombier 0, /* begin_transparency_mask */
469*593dc095SDavid du Colombier 0, /* end_transparency_mask */
470*593dc095SDavid du Colombier 0, /* discard_transparency_layer */
471*593dc095SDavid du Colombier 0, /* get_color_mapping_procs */
472*593dc095SDavid du Colombier 0, /* get_color_comp_index */
473*593dc095SDavid du Colombier 0, /* encode_color */
474*593dc095SDavid du Colombier 0 /* decode_color */
475*593dc095SDavid du Colombier };
476*593dc095SDavid du Colombier
477*593dc095SDavid du Colombier private gx_device_procs sep_overprint_procs = {
478*593dc095SDavid du Colombier overprint_open_device, /* open_device */
479*593dc095SDavid du Colombier 0, /* get_initial_matrix */
480*593dc095SDavid du Colombier 0, /* sync_output */
481*593dc095SDavid du Colombier 0, /* output_page */
482*593dc095SDavid du Colombier 0, /* close_device */
483*593dc095SDavid du Colombier 0, /* map_rgb_color */
484*593dc095SDavid du Colombier 0, /* map_color_rgb */
485*593dc095SDavid du Colombier overprint_sep_fill_rectangle, /* fill_rectangle */
486*593dc095SDavid du Colombier gx_default_tile_rectangle, /* tile_rectangle */
487*593dc095SDavid du Colombier gx_default_copy_mono, /* copy_mono */
488*593dc095SDavid du Colombier gx_default_copy_color, /* copy_color */
489*593dc095SDavid du Colombier gx_default_draw_line, /* draw_line (obsolete) */
490*593dc095SDavid du Colombier 0, /* get_bits */
491*593dc095SDavid du Colombier 0, /* get_params */
492*593dc095SDavid du Colombier overprint_put_params, /* put_params */
493*593dc095SDavid du Colombier 0, /* map_cmyk_color */
494*593dc095SDavid du Colombier 0, /* get_xfont_procs */
495*593dc095SDavid du Colombier gx_default_get_xfont_device, /* get_xfont_device */
496*593dc095SDavid du Colombier 0, /* map_rgb_alpha_color */
497*593dc095SDavid du Colombier overprint_get_page_device, /* get_page_device */
498*593dc095SDavid du Colombier 0, /* get_alpha_bits (obsolete) */
499*593dc095SDavid du Colombier gx_default_copy_alpha, /* copy alpha */
500*593dc095SDavid du Colombier 0, /* get_band */
501*593dc095SDavid du Colombier gx_default_copy_rop, /* copy_rop */
502*593dc095SDavid du Colombier gx_default_fill_path, /* fill_path */
503*593dc095SDavid du Colombier gx_default_stroke_path, /* stroke_path */
504*593dc095SDavid du Colombier gx_default_fill_mask, /* fill_mask */
505*593dc095SDavid du Colombier gx_default_fill_trapezoid, /* fill_trapezoid */
506*593dc095SDavid du Colombier gx_default_fill_parallelogram, /* fill_parallelogram */
507*593dc095SDavid du Colombier gx_default_fill_triangle, /* fill_triangle */
508*593dc095SDavid du Colombier gx_default_draw_thin_line, /* draw_thin_line */
509*593dc095SDavid du Colombier gx_default_begin_image, /* begin_image */
510*593dc095SDavid du Colombier 0, /* image_data (obsolete) */
511*593dc095SDavid du Colombier 0, /* end_image (obsolete) */
512*593dc095SDavid du Colombier gx_default_strip_tile_rectangle, /* strip_tile_rectangle */
513*593dc095SDavid du Colombier gx_default_strip_copy_rop, /* strip_copy_rop */
514*593dc095SDavid du Colombier 0, /* get_clipping_box */
515*593dc095SDavid du Colombier gx_default_begin_typed_image, /* begin_typed_image */
516*593dc095SDavid du Colombier 0, /* get_bits_rectangle */
517*593dc095SDavid du Colombier 0, /* map_color_rgb_alpha */
518*593dc095SDavid du Colombier overprint_create_compositor, /* create_compositor */
519*593dc095SDavid du Colombier 0, /* get_hardware_params */
520*593dc095SDavid du Colombier gx_default_text_begin, /* text_begin */
521*593dc095SDavid du Colombier 0, /* gx_finish_copydevice */
522*593dc095SDavid du Colombier 0, /* begin_transparency_group */
523*593dc095SDavid du Colombier 0, /* end_transparency_group */
524*593dc095SDavid du Colombier 0, /* begin_transparency_mask */
525*593dc095SDavid du Colombier 0, /* end_transparency_mask */
526*593dc095SDavid du Colombier 0, /* discard_transparency_layer */
527*593dc095SDavid du Colombier 0, /* get_color_mapping_procs */
528*593dc095SDavid du Colombier 0, /* get_color_comp_index */
529*593dc095SDavid du Colombier 0, /* encode_color */
530*593dc095SDavid du Colombier 0 /* decode_color */
531*593dc095SDavid du Colombier };
532*593dc095SDavid du Colombier
533*593dc095SDavid du Colombier /*
534*593dc095SDavid du Colombier * The prototype for the overprint device does not provide much
535*593dc095SDavid du Colombier * information; it exists primarily to facilitate use gx_init_device
536*593dc095SDavid du Colombier * and sundry other device utility routines.
537*593dc095SDavid du Colombier */
538*593dc095SDavid du Colombier const overprint_device_t gs_overprint_device = {
539*593dc095SDavid du Colombier std_device_std_body_open( overprint_device_t, /* device type */
540*593dc095SDavid du Colombier 0, /* static_procs */
541*593dc095SDavid du Colombier "overprint_device", /* dname */
542*593dc095SDavid du Colombier 0, 0, /* width, height */
543*593dc095SDavid du Colombier 1, 1 ), /* HWResolution */
544*593dc095SDavid du Colombier { 0 } /* procs */
545*593dc095SDavid du Colombier };
546*593dc095SDavid du Colombier
547*593dc095SDavid du Colombier
548*593dc095SDavid du Colombier
549*593dc095SDavid du Colombier /*
550*593dc095SDavid du Colombier * Utility to reorder bytes in a color or mask based on the endianness of
551*593dc095SDavid du Colombier * the current device. This is required on little-endian machines if the
552*593dc095SDavid du Colombier * depth is larger 8. The resulting value is also replicated to fill the
553*593dc095SDavid du Colombier * entire gx_color_index if the depth is a divisor of the color index
554*593dc095SDavid du Colombier * size. If this is not the case, the result will be in the low-order
555*593dc095SDavid du Colombier * bytes of the color index.
556*593dc095SDavid du Colombier *
557*593dc095SDavid du Colombier * Though this process can be handled in full generality, the code below
558*593dc095SDavid du Colombier * takes advantage of the fact that depths that are > 8 must be a multiple
559*593dc095SDavid du Colombier * of 8 and <= 64
560*593dc095SDavid du Colombier */
561*593dc095SDavid du Colombier #if !arch_is_big_endian
562*593dc095SDavid du Colombier
563*593dc095SDavid du Colombier private gx_color_index
swap_color_index(int depth,gx_color_index color)564*593dc095SDavid du Colombier swap_color_index(int depth, gx_color_index color)
565*593dc095SDavid du Colombier {
566*593dc095SDavid du Colombier int shift = depth - 8;
567*593dc095SDavid du Colombier gx_color_index mask = 0xff;
568*593dc095SDavid du Colombier
569*593dc095SDavid du Colombier color = ((color >> shift) & mask)
570*593dc095SDavid du Colombier | ((color & mask) << shift)
571*593dc095SDavid du Colombier | (color & ~((mask << shift) | mask));
572*593dc095SDavid du Colombier if (depth > 24) {
573*593dc095SDavid du Colombier shift -= 16;
574*593dc095SDavid du Colombier mask <<= 8;
575*593dc095SDavid du Colombier color = ((color >> shift) & mask)
576*593dc095SDavid du Colombier | ((color & mask) << shift)
577*593dc095SDavid du Colombier | (color & ~((mask << shift) | mask));
578*593dc095SDavid du Colombier
579*593dc095SDavid du Colombier if (depth > 40) {
580*593dc095SDavid du Colombier shift -= 16;
581*593dc095SDavid du Colombier mask <<= 8;
582*593dc095SDavid du Colombier color = ((color >> shift) & mask)
583*593dc095SDavid du Colombier | ((color & mask) << shift)
584*593dc095SDavid du Colombier | (color & ~((mask << shift) | mask));
585*593dc095SDavid du Colombier
586*593dc095SDavid du Colombier if (depth > 56) {
587*593dc095SDavid du Colombier shift -= 16;
588*593dc095SDavid du Colombier mask <<= 8;
589*593dc095SDavid du Colombier color = ((color >> shift) & mask)
590*593dc095SDavid du Colombier | ((color & mask) << shift)
591*593dc095SDavid du Colombier | (color & ~((mask << shift) | mask));
592*593dc095SDavid du Colombier }
593*593dc095SDavid du Colombier }
594*593dc095SDavid du Colombier }
595*593dc095SDavid du Colombier
596*593dc095SDavid du Colombier return color;
597*593dc095SDavid du Colombier }
598*593dc095SDavid du Colombier
599*593dc095SDavid du Colombier #endif /* !arch_is_big_endian */
600*593dc095SDavid du Colombier
601*593dc095SDavid du Colombier /*
602*593dc095SDavid du Colombier * Update the retain_mask field to reflect the information in the
603*593dc095SDavid du Colombier * drawn_comps field. This is useful only if the device color model
604*593dc095SDavid du Colombier * is separable.
605*593dc095SDavid du Colombier */
606*593dc095SDavid du Colombier private void
set_retain_mask(overprint_device_t * opdev)607*593dc095SDavid du Colombier set_retain_mask(overprint_device_t * opdev)
608*593dc095SDavid du Colombier {
609*593dc095SDavid du Colombier int i, ncomps = opdev->color_info.num_components;
610*593dc095SDavid du Colombier gx_color_index drawn_comps = opdev->drawn_comps, retain_mask = 0;
611*593dc095SDavid du Colombier #if !arch_is_big_endian
612*593dc095SDavid du Colombier int depth = opdev->color_info.depth;
613*593dc095SDavid du Colombier #endif
614*593dc095SDavid du Colombier
615*593dc095SDavid du Colombier for (i = 0; i < ncomps; i++, drawn_comps >>= 1) {
616*593dc095SDavid du Colombier if ((drawn_comps & 0x1) == 0)
617*593dc095SDavid du Colombier retain_mask |= opdev->color_info.comp_mask[i];
618*593dc095SDavid du Colombier }
619*593dc095SDavid du Colombier #if !arch_is_big_endian
620*593dc095SDavid du Colombier if (depth > 8)
621*593dc095SDavid du Colombier retain_mask = swap_color_index(depth, retain_mask);
622*593dc095SDavid du Colombier #endif
623*593dc095SDavid du Colombier opdev->retain_mask = retain_mask;
624*593dc095SDavid du Colombier }
625*593dc095SDavid du Colombier
626*593dc095SDavid du Colombier /* enlarge mask of non-zero components */
627*593dc095SDavid du Colombier private gx_color_index
check_drawn_comps(int ncomps,frac cvals[GX_DEVICE_COLOR_MAX_COMPONENTS])628*593dc095SDavid du Colombier check_drawn_comps(int ncomps, frac cvals[GX_DEVICE_COLOR_MAX_COMPONENTS])
629*593dc095SDavid du Colombier {
630*593dc095SDavid du Colombier int i;
631*593dc095SDavid du Colombier gx_color_index mask = 0x1, drawn_comps = 0;
632*593dc095SDavid du Colombier
633*593dc095SDavid du Colombier for (i = 0; i < ncomps; i++, mask <<= 1) {
634*593dc095SDavid du Colombier if (cvals[i] != frac_0)
635*593dc095SDavid du Colombier drawn_comps |= mask;
636*593dc095SDavid du Colombier }
637*593dc095SDavid du Colombier return drawn_comps;
638*593dc095SDavid du Colombier }
639*593dc095SDavid du Colombier
640*593dc095SDavid du Colombier /*
641*593dc095SDavid du Colombier * Update the overprint-specific device parameters.
642*593dc095SDavid du Colombier *
643*593dc095SDavid du Colombier * If spot colors are to be retain, the set of process (non-spot) colors is
644*593dc095SDavid du Colombier * determined by mapping through the standard color spaces and check which
645*593dc095SDavid du Colombier * components assume non-zero values.
646*593dc095SDavid du Colombier */
647*593dc095SDavid du Colombier private int
update_overprint_params(overprint_device_t * opdev,const gs_overprint_params_t * pparams)648*593dc095SDavid du Colombier update_overprint_params(
649*593dc095SDavid du Colombier overprint_device_t * opdev,
650*593dc095SDavid du Colombier const gs_overprint_params_t * pparams )
651*593dc095SDavid du Colombier {
652*593dc095SDavid du Colombier int ncomps = opdev->color_info.num_components;
653*593dc095SDavid du Colombier
654*593dc095SDavid du Colombier /* check if overprint is to be turned off */
655*593dc095SDavid du Colombier if (!pparams->retain_any_comps) {
656*593dc095SDavid du Colombier /* if fill_rectangle forwards, overprint is already off */
657*593dc095SDavid du Colombier if (dev_proc(opdev, fill_rectangle) != gx_forward_fill_rectangle)
658*593dc095SDavid du Colombier memcpy( &opdev->procs,
659*593dc095SDavid du Colombier &no_overprint_procs,
660*593dc095SDavid du Colombier sizeof(no_overprint_procs) );
661*593dc095SDavid du Colombier return 0;
662*593dc095SDavid du Colombier }
663*593dc095SDavid du Colombier
664*593dc095SDavid du Colombier /* set the procedures according to the color model */
665*593dc095SDavid du Colombier if (opdev->color_info.separable_and_linear == GX_CINFO_SEP_LIN)
666*593dc095SDavid du Colombier memcpy( &opdev->procs,
667*593dc095SDavid du Colombier &sep_overprint_procs,
668*593dc095SDavid du Colombier sizeof(sep_overprint_procs) );
669*593dc095SDavid du Colombier else
670*593dc095SDavid du Colombier memcpy( &opdev->procs,
671*593dc095SDavid du Colombier &generic_overprint_procs,
672*593dc095SDavid du Colombier sizeof(generic_overprint_procs) );
673*593dc095SDavid du Colombier
674*593dc095SDavid du Colombier /* see if we need to determine the spot color components */
675*593dc095SDavid du Colombier if (!pparams->retain_spot_comps)
676*593dc095SDavid du Colombier opdev->drawn_comps = pparams->drawn_comps;
677*593dc095SDavid du Colombier else {
678*593dc095SDavid du Colombier gx_device * dev = (gx_device *)opdev;
679*593dc095SDavid du Colombier const gx_cm_color_map_procs * pprocs;
680*593dc095SDavid du Colombier frac cvals[GX_DEVICE_COLOR_MAX_COMPONENTS];
681*593dc095SDavid du Colombier gx_color_index drawn_comps = 0;
682*593dc095SDavid du Colombier static const frac frac_13 = float2frac(1.0 / 3.0);
683*593dc095SDavid du Colombier
684*593dc095SDavid du Colombier if ((pprocs = dev_proc(opdev, get_color_mapping_procs)(dev)) == 0 ||
685*593dc095SDavid du Colombier pprocs->map_gray == 0 ||
686*593dc095SDavid du Colombier pprocs->map_rgb == 0 ||
687*593dc095SDavid du Colombier pprocs->map_cmyk == 0 )
688*593dc095SDavid du Colombier return_error(gs_error_unknownerror);
689*593dc095SDavid du Colombier
690*593dc095SDavid du Colombier pprocs->map_gray(dev, frac_13, cvals);
691*593dc095SDavid du Colombier drawn_comps |= check_drawn_comps(ncomps, cvals);
692*593dc095SDavid du Colombier
693*593dc095SDavid du Colombier pprocs->map_rgb(dev, 0, frac_13, frac_0, frac_0, cvals);
694*593dc095SDavid du Colombier drawn_comps |= check_drawn_comps(ncomps, cvals);
695*593dc095SDavid du Colombier pprocs->map_rgb(dev, 0, frac_0, frac_13, frac_0, cvals);
696*593dc095SDavid du Colombier drawn_comps |= check_drawn_comps(ncomps, cvals);
697*593dc095SDavid du Colombier pprocs->map_rgb(dev, 0, frac_0, frac_0, frac_13, cvals);
698*593dc095SDavid du Colombier drawn_comps |= check_drawn_comps(ncomps, cvals);
699*593dc095SDavid du Colombier
700*593dc095SDavid du Colombier pprocs->map_cmyk(dev, frac_13, frac_0, frac_0, frac_0, cvals);
701*593dc095SDavid du Colombier drawn_comps |= check_drawn_comps(ncomps, cvals);
702*593dc095SDavid du Colombier pprocs->map_cmyk(dev, frac_0, frac_13, frac_0, frac_0, cvals);
703*593dc095SDavid du Colombier drawn_comps |= check_drawn_comps(ncomps, cvals);
704*593dc095SDavid du Colombier pprocs->map_cmyk(dev, frac_0, frac_0, frac_13, frac_0, cvals);
705*593dc095SDavid du Colombier drawn_comps |= check_drawn_comps(ncomps, cvals);
706*593dc095SDavid du Colombier pprocs->map_cmyk(dev, frac_0, frac_0, frac_0, frac_13, cvals);
707*593dc095SDavid du Colombier drawn_comps |= check_drawn_comps(ncomps, cvals);
708*593dc095SDavid du Colombier
709*593dc095SDavid du Colombier opdev->drawn_comps = drawn_comps;
710*593dc095SDavid du Colombier }
711*593dc095SDavid du Colombier
712*593dc095SDavid du Colombier /* check for degenerate case */
713*593dc095SDavid du Colombier if (opdev->drawn_comps == ((gx_color_index)1 << ncomps) - 1) {
714*593dc095SDavid du Colombier memcpy( &opdev->procs,
715*593dc095SDavid du Colombier &no_overprint_procs,
716*593dc095SDavid du Colombier sizeof(no_overprint_procs) );
717*593dc095SDavid du Colombier return 0;
718*593dc095SDavid du Colombier }
719*593dc095SDavid du Colombier
720*593dc095SDavid du Colombier /* if appropriate, update the retain_mask field */
721*593dc095SDavid du Colombier if (opdev->color_info.separable_and_linear == GX_CINFO_SEP_LIN)
722*593dc095SDavid du Colombier set_retain_mask(opdev);
723*593dc095SDavid du Colombier
724*593dc095SDavid du Colombier return 0;
725*593dc095SDavid du Colombier }
726*593dc095SDavid du Colombier
727*593dc095SDavid du Colombier
728*593dc095SDavid du Colombier /*
729*593dc095SDavid du Colombier * The open_device method for the overprint device is about as close to
730*593dc095SDavid du Colombier * a pure "forwarding" open_device operation as is possible. Its only
731*593dc095SDavid du Colombier * significant function is to ensure that the is_open field of the
732*593dc095SDavid du Colombier * overprint device matches that of the target device.
733*593dc095SDavid du Colombier *
734*593dc095SDavid du Colombier * We assume this procedure is called only if the device is not already
735*593dc095SDavid du Colombier * open, and that gs_opendevice will take care of the is_open flag.
736*593dc095SDavid du Colombier */
737*593dc095SDavid du Colombier private int
overprint_open_device(gx_device * dev)738*593dc095SDavid du Colombier overprint_open_device(gx_device * dev)
739*593dc095SDavid du Colombier {
740*593dc095SDavid du Colombier overprint_device_t * opdev = (overprint_device_t *)dev;
741*593dc095SDavid du Colombier gx_device * tdev = opdev->target;
742*593dc095SDavid du Colombier int code = 0;
743*593dc095SDavid du Colombier
744*593dc095SDavid du Colombier /* the overprint device must have a target */
745*593dc095SDavid du Colombier if (tdev == 0)
746*593dc095SDavid du Colombier return_error(gs_error_unknownerror);
747*593dc095SDavid du Colombier if ((code = gs_opendevice(tdev)) >= 0)
748*593dc095SDavid du Colombier gx_device_copy_params(dev, tdev);
749*593dc095SDavid du Colombier return code;
750*593dc095SDavid du Colombier }
751*593dc095SDavid du Colombier
752*593dc095SDavid du Colombier /*
753*593dc095SDavid du Colombier * The put_params method for the overprint device will check if the
754*593dc095SDavid du Colombier * target device has closed and, if so, close itself.
755*593dc095SDavid du Colombier */
756*593dc095SDavid du Colombier private int
overprint_put_params(gx_device * dev,gs_param_list * plist)757*593dc095SDavid du Colombier overprint_put_params(gx_device * dev, gs_param_list * plist)
758*593dc095SDavid du Colombier {
759*593dc095SDavid du Colombier overprint_device_t * opdev = (overprint_device_t *)dev;
760*593dc095SDavid du Colombier gx_device * tdev = opdev->target;
761*593dc095SDavid du Colombier int code = 0;
762*593dc095SDavid du Colombier
763*593dc095SDavid du Colombier
764*593dc095SDavid du Colombier if (tdev != 0 && (code = dev_proc(tdev, put_params)(tdev, plist)) >= 0) {
765*593dc095SDavid du Colombier gx_device_decache_colors(dev);
766*593dc095SDavid du Colombier if (!tdev->is_open)
767*593dc095SDavid du Colombier code = gs_closedevice(dev);
768*593dc095SDavid du Colombier }
769*593dc095SDavid du Colombier return code;
770*593dc095SDavid du Colombier }
771*593dc095SDavid du Colombier
772*593dc095SDavid du Colombier /*
773*593dc095SDavid du Colombier * The overprint device must never be confused with a page device.
774*593dc095SDavid du Colombier * Thus, we always forward the request for the page device to the
775*593dc095SDavid du Colombier * target, as should all forwarding devices.
776*593dc095SDavid du Colombier */
777*593dc095SDavid du Colombier private gx_device *
overprint_get_page_device(gx_device * dev)778*593dc095SDavid du Colombier overprint_get_page_device(gx_device * dev)
779*593dc095SDavid du Colombier {
780*593dc095SDavid du Colombier overprint_device_t * opdev = (overprint_device_t *)dev;
781*593dc095SDavid du Colombier gx_device * tdev = opdev->target;
782*593dc095SDavid du Colombier
783*593dc095SDavid du Colombier return tdev == 0 ? 0 : dev_proc(tdev, get_page_device)(tdev);
784*593dc095SDavid du Colombier }
785*593dc095SDavid du Colombier
786*593dc095SDavid du Colombier /*
787*593dc095SDavid du Colombier * Calling create_compositor on the overprint device just updates the
788*593dc095SDavid du Colombier * overprint parameters; no new device is created.
789*593dc095SDavid du Colombier */
790*593dc095SDavid du Colombier private int
overprint_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pct,gs_imager_state * pis,gs_memory_t * memory)791*593dc095SDavid du Colombier overprint_create_compositor(
792*593dc095SDavid du Colombier gx_device * dev,
793*593dc095SDavid du Colombier gx_device ** pcdev,
794*593dc095SDavid du Colombier const gs_composite_t * pct,
795*593dc095SDavid du Colombier gs_imager_state * pis,
796*593dc095SDavid du Colombier gs_memory_t * memory )
797*593dc095SDavid du Colombier {
798*593dc095SDavid du Colombier if (pct->type != &gs_composite_overprint_type)
799*593dc095SDavid du Colombier return gx_default_create_compositor(dev, pcdev, pct, pis, memory);
800*593dc095SDavid du Colombier else {
801*593dc095SDavid du Colombier int code;
802*593dc095SDavid du Colombier
803*593dc095SDavid du Colombier /* device must already exist, so just update the parameters */
804*593dc095SDavid du Colombier code = update_overprint_params(
805*593dc095SDavid du Colombier (overprint_device_t *)dev,
806*593dc095SDavid du Colombier &((const gs_overprint_t *)pct)->params );
807*593dc095SDavid du Colombier if (code >= 0)
808*593dc095SDavid du Colombier *pcdev = dev;
809*593dc095SDavid du Colombier return code;
810*593dc095SDavid du Colombier }
811*593dc095SDavid du Colombier }
812*593dc095SDavid du Colombier
813*593dc095SDavid du Colombier
814*593dc095SDavid du Colombier /*
815*593dc095SDavid du Colombier * The two rectangle-filling routines (which do the actual work) are just
816*593dc095SDavid du Colombier * stubbs for the time being. The actual routines would allocate a buffer,
817*593dc095SDavid du Colombier * use get_bits_rectangle to build a buffer of the existing data, modify
818*593dc095SDavid du Colombier * the appropriate components, then invoke the copy_color procedure on the
819*593dc095SDavid du Colombier * target device.
820*593dc095SDavid du Colombier */
821*593dc095SDavid du Colombier private int
overprint_generic_fill_rectangle(gx_device * dev,int x,int y,int width,int height,gx_color_index color)822*593dc095SDavid du Colombier overprint_generic_fill_rectangle(
823*593dc095SDavid du Colombier gx_device * dev,
824*593dc095SDavid du Colombier int x,
825*593dc095SDavid du Colombier int y,
826*593dc095SDavid du Colombier int width,
827*593dc095SDavid du Colombier int height,
828*593dc095SDavid du Colombier gx_color_index color )
829*593dc095SDavid du Colombier {
830*593dc095SDavid du Colombier overprint_device_t * opdev = (overprint_device_t *)dev;
831*593dc095SDavid du Colombier gx_device * tdev = opdev->target;
832*593dc095SDavid du Colombier
833*593dc095SDavid du Colombier if (tdev == 0)
834*593dc095SDavid du Colombier return 0;
835*593dc095SDavid du Colombier else
836*593dc095SDavid du Colombier return gx_overprint_generic_fill_rectangle( tdev,
837*593dc095SDavid du Colombier opdev->drawn_comps,
838*593dc095SDavid du Colombier x, y, width, height,
839*593dc095SDavid du Colombier color,
840*593dc095SDavid du Colombier dev->memory );
841*593dc095SDavid du Colombier }
842*593dc095SDavid du Colombier
843*593dc095SDavid du Colombier private int
overprint_sep_fill_rectangle(gx_device * dev,int x,int y,int width,int height,gx_color_index color)844*593dc095SDavid du Colombier overprint_sep_fill_rectangle(
845*593dc095SDavid du Colombier gx_device * dev,
846*593dc095SDavid du Colombier int x,
847*593dc095SDavid du Colombier int y,
848*593dc095SDavid du Colombier int width,
849*593dc095SDavid du Colombier int height,
850*593dc095SDavid du Colombier gx_color_index color )
851*593dc095SDavid du Colombier {
852*593dc095SDavid du Colombier overprint_device_t * opdev = (overprint_device_t *)dev;
853*593dc095SDavid du Colombier gx_device * tdev = opdev->target;
854*593dc095SDavid du Colombier
855*593dc095SDavid du Colombier if (tdev == 0)
856*593dc095SDavid du Colombier return 0;
857*593dc095SDavid du Colombier else {
858*593dc095SDavid du Colombier int depth = tdev->color_info.depth;
859*593dc095SDavid du Colombier
860*593dc095SDavid du Colombier /*
861*593dc095SDavid du Colombier * Swap the color index into the order required by a byte-oriented
862*593dc095SDavid du Colombier * bitmap. This is required only for littl-endian processors, and
863*593dc095SDavid du Colombier * then only if the depth > 8.
864*593dc095SDavid du Colombier */
865*593dc095SDavid du Colombier #if !arch_is_big_endian
866*593dc095SDavid du Colombier if (depth > 8)
867*593dc095SDavid du Colombier color = swap_color_index(depth, color);
868*593dc095SDavid du Colombier #endif
869*593dc095SDavid du Colombier
870*593dc095SDavid du Colombier /*
871*593dc095SDavid du Colombier * We can handle rectangle filling via bits_fill_rectangle_masked
872*593dc095SDavid du Colombier * if the depth is a divisor of 8 * sizeof(mono_fill_chunk). The
873*593dc095SDavid du Colombier * non-masked fill_rectangle code uses a byte-oriented routine
874*593dc095SDavid du Colombier * if depth > 8, but there is not much advantage to doing so if
875*593dc095SDavid du Colombier * masking is required.
876*593dc095SDavid du Colombier *
877*593dc095SDavid du Colombier * Directly testing (8 * sizeof(mono_fill_chunk)) % depth is
878*593dc095SDavid du Colombier * potentially expensive, since many rectangles are small. We
879*593dc095SDavid du Colombier * can avoid the modulus operation by noting that
880*593dc095SDavid du Colombier * 8 * sizeof(mono_fill_chunk) will be a power of 2, and so
881*593dc095SDavid du Colombier * we need only check that depth is a power of 2 and
882*593dc095SDavid du Colombier * depth < 8 * sizeof(mono_fill_chunk).
883*593dc095SDavid du Colombier */
884*593dc095SDavid du Colombier if ( depth <= 8 * sizeof(mono_fill_chunk) &&
885*593dc095SDavid du Colombier (depth & (depth - 1)) == 0 )
886*593dc095SDavid du Colombier return gx_overprint_sep_fill_rectangle_1( tdev,
887*593dc095SDavid du Colombier opdev->retain_mask,
888*593dc095SDavid du Colombier x, y, width, height,
889*593dc095SDavid du Colombier color,
890*593dc095SDavid du Colombier dev->memory );
891*593dc095SDavid du Colombier else
892*593dc095SDavid du Colombier return gx_overprint_sep_fill_rectangle_2( tdev,
893*593dc095SDavid du Colombier opdev->retain_mask,
894*593dc095SDavid du Colombier x, y, width, height,
895*593dc095SDavid du Colombier color,
896*593dc095SDavid du Colombier dev->memory );
897*593dc095SDavid du Colombier }
898*593dc095SDavid du Colombier }
899*593dc095SDavid du Colombier
900*593dc095SDavid du Colombier
901*593dc095SDavid du Colombier /* complete a porcedure set */
902*593dc095SDavid du Colombier private void
fill_in_procs(gx_device_procs * pprocs)903*593dc095SDavid du Colombier fill_in_procs(gx_device_procs * pprocs)
904*593dc095SDavid du Colombier {
905*593dc095SDavid du Colombier gx_device_forward tmpdev;
906*593dc095SDavid du Colombier
907*593dc095SDavid du Colombier /*
908*593dc095SDavid du Colombier * gx_device_forward_fill_in_procs calls gx_device_fill_in_procs, which
909*593dc095SDavid du Colombier * requires the color_info field of the device be set to "reasonable"
910*593dc095SDavid du Colombier * values. Which values is irrelevant in this case, but they must not
911*593dc095SDavid du Colombier * contain dangling pointers, excessive numbers of components, etc.
912*593dc095SDavid du Colombier */
913*593dc095SDavid du Colombier memcpy( &tmpdev.color_info,
914*593dc095SDavid du Colombier &gs_overprint_device.color_info,
915*593dc095SDavid du Colombier sizeof(tmpdev.color_info) );
916*593dc095SDavid du Colombier /*
917*593dc095SDavid du Colombier * Prevent the check_device_separable routine from executing while we
918*593dc095SDavid du Colombier * fill in the procs. Our tmpdev is not complete enough for it.
919*593dc095SDavid du Colombier */
920*593dc095SDavid du Colombier tmpdev.color_info.separable_and_linear = GX_CINFO_SEP_LIN_NONE;
921*593dc095SDavid du Colombier tmpdev.static_procs = 0;
922*593dc095SDavid du Colombier memcpy(&tmpdev.procs, pprocs, sizeof(tmpdev.procs));
923*593dc095SDavid du Colombier gx_device_forward_fill_in_procs(&tmpdev);
924*593dc095SDavid du Colombier memcpy(pprocs, &tmpdev.procs, sizeof(tmpdev.procs));
925*593dc095SDavid du Colombier }
926*593dc095SDavid du Colombier
927*593dc095SDavid du Colombier /*
928*593dc095SDavid du Colombier * Create an overprint compositor.
929*593dc095SDavid du Colombier *
930*593dc095SDavid du Colombier * Note that this routine will be called only if the device is not already
931*593dc095SDavid du Colombier * an overprint compositor. Hence, if pct->params.retain_any_comps is
932*593dc095SDavid du Colombier * false, we can just return.
933*593dc095SDavid du Colombier *
934*593dc095SDavid du Colombier * We also suppress use of overprint if the current device color model has only
935*593dc095SDavid du Colombier * a single component. In this case overprint mode is inapplicable (it applies
936*593dc095SDavid du Colombier * only to CMYK devices), and nothing can possibly be gained by using overprint.
937*593dc095SDavid du Colombier * More significantly, this cause avoids erroneous use of overprint when a
938*593dc095SDavid du Colombier * mask caching device is the current device, which would otherwise require
939*593dc095SDavid du Colombier * elaborate special handling in the caching device create_compositor
940*593dc095SDavid du Colombier * procedure.
941*593dc095SDavid du Colombier */
942*593dc095SDavid du Colombier private int
c_overprint_create_default_compositor(const gs_composite_t * pct,gx_device ** popdev,gx_device * tdev,gs_imager_state * pis,gs_memory_t * mem)943*593dc095SDavid du Colombier c_overprint_create_default_compositor(
944*593dc095SDavid du Colombier const gs_composite_t * pct,
945*593dc095SDavid du Colombier gx_device ** popdev,
946*593dc095SDavid du Colombier gx_device * tdev,
947*593dc095SDavid du Colombier gs_imager_state * pis,
948*593dc095SDavid du Colombier gs_memory_t * mem )
949*593dc095SDavid du Colombier {
950*593dc095SDavid du Colombier const gs_overprint_t * ovrpct = (const gs_overprint_t *)pct;
951*593dc095SDavid du Colombier overprint_device_t * opdev = 0;
952*593dc095SDavid du Colombier
953*593dc095SDavid du Colombier /* see if there is anything to do */
954*593dc095SDavid du Colombier if ( !ovrpct->params.retain_any_comps) {
955*593dc095SDavid du Colombier *popdev = tdev;
956*593dc095SDavid du Colombier return 0;
957*593dc095SDavid du Colombier }
958*593dc095SDavid du Colombier
959*593dc095SDavid du Colombier /* check if the procedure arrays have been initialized */
960*593dc095SDavid du Colombier if (no_overprint_procs.get_xfont_procs == 0) {
961*593dc095SDavid du Colombier fill_in_procs(&no_overprint_procs);
962*593dc095SDavid du Colombier fill_in_procs(&generic_overprint_procs);
963*593dc095SDavid du Colombier fill_in_procs(&sep_overprint_procs);
964*593dc095SDavid du Colombier }
965*593dc095SDavid du Colombier
966*593dc095SDavid du Colombier /* build the overprint device */
967*593dc095SDavid du Colombier opdev = gs_alloc_struct_immovable( mem,
968*593dc095SDavid du Colombier overprint_device_t,
969*593dc095SDavid du Colombier &st_overprint_device_t,
970*593dc095SDavid du Colombier "create overprint compositor" );
971*593dc095SDavid du Colombier if ((*popdev = (gx_device *)opdev) == 0)
972*593dc095SDavid du Colombier return_error(gs_error_VMerror);
973*593dc095SDavid du Colombier gx_device_init( (gx_device *)opdev,
974*593dc095SDavid du Colombier (const gx_device *)&gs_overprint_device,
975*593dc095SDavid du Colombier mem,
976*593dc095SDavid du Colombier true );
977*593dc095SDavid du Colombier gx_device_copy_params((gx_device *)opdev, tdev);
978*593dc095SDavid du Colombier gx_device_set_target((gx_device_forward *)opdev, tdev);
979*593dc095SDavid du Colombier
980*593dc095SDavid du Colombier /* set up the overprint parameters */
981*593dc095SDavid du Colombier return update_overprint_params( opdev,
982*593dc095SDavid du Colombier &((const gs_overprint_t *)pct)->params );
983*593dc095SDavid du Colombier }
984