xref: /plan9/sys/src/cmd/gs/src/gsovrc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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(&params.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, &params, 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