xref: /plan9-contrib/sys/src/cmd/gs/src/gxoprect.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: gxoprect.c,v 1.6 2005/06/20 08:59:23 igor Exp $ */
18*593dc095SDavid du Colombier /* generic (very slow) overprint fill rectangle 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 "gxdevice.h"
25*593dc095SDavid du Colombier #include "gsdevice.h"
26*593dc095SDavid du Colombier #include "gxgetbit.h"
27*593dc095SDavid du Colombier #include "gxoprect.h"
28*593dc095SDavid du Colombier #include "gsbitops.h"
29*593dc095SDavid du Colombier 
30*593dc095SDavid du Colombier 
31*593dc095SDavid du Colombier /*
32*593dc095SDavid du Colombier  * Unpack a scanline for a depth < 8. In this case we know the depth is
33*593dc095SDavid du Colombier  * divisor of 8 and thus a power of 2, which implies that 8 / depth is
34*593dc095SDavid du Colombier  * also a power of 2.
35*593dc095SDavid du Colombier  */
36*593dc095SDavid du Colombier private void
unpack_scanline_lt8(gx_color_index * destp,const byte * srcp,int src_offset,int width,int depth)37*593dc095SDavid du Colombier unpack_scanline_lt8(
38*593dc095SDavid du Colombier     gx_color_index *    destp,
39*593dc095SDavid du Colombier     const byte *        srcp,
40*593dc095SDavid du Colombier     int                 src_offset,
41*593dc095SDavid du Colombier     int                 width,
42*593dc095SDavid du Colombier     int                 depth )
43*593dc095SDavid du Colombier {
44*593dc095SDavid du Colombier     byte                buff = 0;
45*593dc095SDavid du Colombier     int                 i = 0, shift = 8 - depth, p_per_byte = 8 / depth;
46*593dc095SDavid du Colombier 
47*593dc095SDavid du Colombier     /* exit early if nothing to do */
48*593dc095SDavid du Colombier     if (width == 0)
49*593dc095SDavid du Colombier         return;
50*593dc095SDavid du Colombier 
51*593dc095SDavid du Colombier     /* skip over src_offset */
52*593dc095SDavid du Colombier     if (src_offset >= p_per_byte) {
53*593dc095SDavid du Colombier         srcp += src_offset / p_per_byte;
54*593dc095SDavid du Colombier         src_offset &= (p_per_byte - 1);
55*593dc095SDavid du Colombier     }
56*593dc095SDavid du Colombier     if (src_offset > 0) {
57*593dc095SDavid du Colombier         buff = *srcp++ << (src_offset * depth);
58*593dc095SDavid du Colombier         i = src_offset;
59*593dc095SDavid du Colombier         width += src_offset;
60*593dc095SDavid du Colombier     }
61*593dc095SDavid du Colombier 
62*593dc095SDavid du Colombier     /* process the interesting part of the scanline */
63*593dc095SDavid du Colombier     for (; i < width; i++, buff <<= depth) {
64*593dc095SDavid du Colombier         if ((i & (p_per_byte - 1)) == 0)
65*593dc095SDavid du Colombier             buff = *srcp++;
66*593dc095SDavid du Colombier         *destp++ = buff >> shift;
67*593dc095SDavid du Colombier     }
68*593dc095SDavid du Colombier }
69*593dc095SDavid du Colombier 
70*593dc095SDavid du Colombier /*
71*593dc095SDavid du Colombier  * Pack a scanline for a depth of < 8. Note that data prior to dest_offset
72*593dc095SDavid du Colombier  * and any data beyond the width must be left undisturbed.
73*593dc095SDavid du Colombier  */
74*593dc095SDavid du Colombier private void
pack_scanline_lt8(const gx_color_index * srcp,byte * destp,int dest_offset,int width,int depth)75*593dc095SDavid du Colombier pack_scanline_lt8(
76*593dc095SDavid du Colombier     const gx_color_index *  srcp,
77*593dc095SDavid du Colombier     byte *                  destp,
78*593dc095SDavid du Colombier     int                     dest_offset,
79*593dc095SDavid du Colombier     int                     width,
80*593dc095SDavid du Colombier     int                     depth )
81*593dc095SDavid du Colombier {
82*593dc095SDavid du Colombier     byte                    buff = 0;
83*593dc095SDavid du Colombier     int                     i = 0, p_per_byte = 8 / depth;
84*593dc095SDavid du Colombier 
85*593dc095SDavid du Colombier     /* exit early if nothing to do */
86*593dc095SDavid du Colombier     if (width == 0)
87*593dc095SDavid du Colombier         return;
88*593dc095SDavid du Colombier 
89*593dc095SDavid du Colombier     /* skip over dest_offset */
90*593dc095SDavid du Colombier     if (dest_offset >= p_per_byte) {
91*593dc095SDavid du Colombier         destp += dest_offset / p_per_byte;
92*593dc095SDavid du Colombier         dest_offset &= (p_per_byte - 1);
93*593dc095SDavid du Colombier     }
94*593dc095SDavid du Colombier     if (dest_offset > 0) {
95*593dc095SDavid du Colombier         buff = *destp++ >> (8 - dest_offset * depth);
96*593dc095SDavid du Colombier         i = dest_offset;
97*593dc095SDavid du Colombier         width += dest_offset;
98*593dc095SDavid du Colombier     }
99*593dc095SDavid du Colombier 
100*593dc095SDavid du Colombier     /* process the interesting part of the scanline */
101*593dc095SDavid du Colombier     for (; i < width; i++) {
102*593dc095SDavid du Colombier         buff = (buff << depth) | *srcp++;
103*593dc095SDavid du Colombier         if ((i & (p_per_byte - 1)) == p_per_byte - 1)
104*593dc095SDavid du Colombier             *destp++ = buff;
105*593dc095SDavid du Colombier     }
106*593dc095SDavid du Colombier     if ((i &= (p_per_byte - 1)) != 0) {
107*593dc095SDavid du Colombier         int     shift = depth * (p_per_byte - i);
108*593dc095SDavid du Colombier         int     mask = (1 << shift) - 1;
109*593dc095SDavid du Colombier 
110*593dc095SDavid du Colombier         *destp = (*destp & mask) | (buff << shift);
111*593dc095SDavid du Colombier     }
112*593dc095SDavid du Colombier }
113*593dc095SDavid du Colombier 
114*593dc095SDavid du Colombier /*
115*593dc095SDavid du Colombier  * Unpack a scanline for a depth >= 8. In this case, the depth must be
116*593dc095SDavid du Colombier  * a multiple of 8.
117*593dc095SDavid du Colombier  */
118*593dc095SDavid du Colombier private void
unpack_scanline_ge8(gx_color_index * destp,const byte * srcp,int src_offset,int width,int depth)119*593dc095SDavid du Colombier unpack_scanline_ge8(
120*593dc095SDavid du Colombier     gx_color_index *    destp,
121*593dc095SDavid du Colombier     const byte *        srcp,
122*593dc095SDavid du Colombier     int                 src_offset,
123*593dc095SDavid du Colombier     int                 width,
124*593dc095SDavid du Colombier     int                 depth )
125*593dc095SDavid du Colombier {
126*593dc095SDavid du Colombier     gx_color_index      buff = 0;
127*593dc095SDavid du Colombier     int                 i, j, bytes_per_p = depth >> 3;
128*593dc095SDavid du Colombier 
129*593dc095SDavid du Colombier     /* skip over src_offset */
130*593dc095SDavid du Colombier     srcp += src_offset * bytes_per_p;
131*593dc095SDavid du Colombier 
132*593dc095SDavid du Colombier     /* process the interesting part of the scanline */
133*593dc095SDavid du Colombier     width *= bytes_per_p;
134*593dc095SDavid du Colombier     for (i = 0, j = 0; i < width; i++) {
135*593dc095SDavid du Colombier         buff = (buff << 8) | *srcp++;
136*593dc095SDavid du Colombier         if (++j == bytes_per_p) {
137*593dc095SDavid du Colombier             *destp++ = buff;
138*593dc095SDavid du Colombier             buff = 0;
139*593dc095SDavid du Colombier             j = 0;
140*593dc095SDavid du Colombier         }
141*593dc095SDavid du Colombier     }
142*593dc095SDavid du Colombier }
143*593dc095SDavid du Colombier 
144*593dc095SDavid du Colombier /*
145*593dc095SDavid du Colombier  * Pack a scanline for depth >= 8.
146*593dc095SDavid du Colombier  */
147*593dc095SDavid du Colombier private void
pack_scanline_ge8(const gx_color_index * srcp,byte * destp,int dest_offset,int width,int depth)148*593dc095SDavid du Colombier pack_scanline_ge8(
149*593dc095SDavid du Colombier     const gx_color_index *  srcp,
150*593dc095SDavid du Colombier     byte *                  destp,
151*593dc095SDavid du Colombier     int                     dest_offset,
152*593dc095SDavid du Colombier     int                     width,
153*593dc095SDavid du Colombier     int                     depth )
154*593dc095SDavid du Colombier {
155*593dc095SDavid du Colombier     gx_color_index          buff = 0;
156*593dc095SDavid du Colombier     int                     i, j, bytes_per_p = depth >> 3;
157*593dc095SDavid du Colombier     int                     shift = depth - 8;
158*593dc095SDavid du Colombier 
159*593dc095SDavid du Colombier     /* skip over dest_offset */
160*593dc095SDavid du Colombier     destp += dest_offset;
161*593dc095SDavid du Colombier 
162*593dc095SDavid du Colombier     /* process the interesting part of the scanline */
163*593dc095SDavid du Colombier     width *= bytes_per_p;
164*593dc095SDavid du Colombier     for (i = 0, j = bytes_per_p - 1; i < width; i++, buff <<= 8) {
165*593dc095SDavid du Colombier         if (++j == bytes_per_p) {
166*593dc095SDavid du Colombier             buff = *srcp++;
167*593dc095SDavid du Colombier             j = 0;
168*593dc095SDavid du Colombier         }
169*593dc095SDavid du Colombier         *destp++ = buff >> shift;
170*593dc095SDavid du Colombier     }
171*593dc095SDavid du Colombier }
172*593dc095SDavid du Colombier 
173*593dc095SDavid du Colombier 
174*593dc095SDavid du Colombier /*
175*593dc095SDavid du Colombier  * Perform the fill rectangle operation for a non-separable color encoding
176*593dc095SDavid du Colombier  * that requires overprint support. This situation requires that colors be
177*593dc095SDavid du Colombier  * decoded, modified, and re-encoded. These steps must be performed per
178*593dc095SDavid du Colombier  * output pixel, so there is no hope of achieving good performance.
179*593dc095SDavid du Colombier  * Consequently, only minimal performance optimizations are applied below.
180*593dc095SDavid du Colombier  *
181*593dc095SDavid du Colombier  * The overprint device structure is known only in gsovr.c, and thus is not
182*593dc095SDavid du Colombier  * available here. The required information from the overprint device is,
183*593dc095SDavid du Colombier  * therefore, provided via explicit operands.  The device operand points to
184*593dc095SDavid du Colombier  * the target of the overprint compositor device, not the compositor device
185*593dc095SDavid du Colombier  * itself. The drawn_comps bit array and the memory descriptor pointer are
186*593dc095SDavid du Colombier  * also provided explicitly as operands.
187*593dc095SDavid du Colombier  *
188*593dc095SDavid du Colombier  * Returns 0 on success, < 0 in the event of an error.
189*593dc095SDavid du Colombier  */
190*593dc095SDavid du Colombier int
gx_overprint_generic_fill_rectangle(gx_device * tdev,gx_color_index drawn_comps,int x,int y,int w,int h,gx_color_index color,gs_memory_t * mem)191*593dc095SDavid du Colombier gx_overprint_generic_fill_rectangle(
192*593dc095SDavid du Colombier     gx_device *             tdev,
193*593dc095SDavid du Colombier     gx_color_index          drawn_comps,
194*593dc095SDavid du Colombier     int                     x,
195*593dc095SDavid du Colombier     int                     y,
196*593dc095SDavid du Colombier     int                     w,
197*593dc095SDavid du Colombier     int                     h,
198*593dc095SDavid du Colombier     gx_color_index          color,
199*593dc095SDavid du Colombier     gs_memory_t *           mem )
200*593dc095SDavid du Colombier {
201*593dc095SDavid du Colombier     gx_color_value          src_cvals[GX_DEVICE_COLOR_MAX_COMPONENTS];
202*593dc095SDavid du Colombier     gx_color_index *        pcolor_buff = 0;
203*593dc095SDavid du Colombier     byte *                  gb_buff = 0;
204*593dc095SDavid du Colombier     gs_get_bits_params_t    gb_params;
205*593dc095SDavid du Colombier     gs_int_rect             gb_rect;
206*593dc095SDavid du Colombier     int                     depth = tdev->color_info.depth;
207*593dc095SDavid du Colombier     int                     bit_x, start_x, end_x, raster, code;
208*593dc095SDavid du Colombier     void                    (*unpack_proc)( gx_color_index *,
209*593dc095SDavid du Colombier                                             const byte *,
210*593dc095SDavid du Colombier                                             int, int, int );
211*593dc095SDavid du Colombier     void                    (*pack_proc)( const gx_color_index *,
212*593dc095SDavid du Colombier                                           byte *,
213*593dc095SDavid du Colombier                                           int, int, int );
214*593dc095SDavid du Colombier 
215*593dc095SDavid du Colombier     fit_fill(tdev, x, y, w, h);
216*593dc095SDavid du Colombier     bit_x = x * depth;
217*593dc095SDavid du Colombier     start_x = bit_x & ~(8 * align_bitmap_mod - 1);
218*593dc095SDavid du Colombier     end_x = bit_x + w * depth;
219*593dc095SDavid du Colombier 
220*593dc095SDavid du Colombier     /* select the appropriate pack/unpack routines */
221*593dc095SDavid du Colombier     if (depth >= 8) {
222*593dc095SDavid du Colombier         unpack_proc = unpack_scanline_ge8;
223*593dc095SDavid du Colombier         pack_proc = pack_scanline_ge8;
224*593dc095SDavid du Colombier     } else {
225*593dc095SDavid du Colombier         unpack_proc = unpack_scanline_lt8;
226*593dc095SDavid du Colombier         pack_proc = pack_scanline_lt8;
227*593dc095SDavid du Colombier     }
228*593dc095SDavid du Colombier 
229*593dc095SDavid du Colombier     /* decode the source color */
230*593dc095SDavid du Colombier     if ((code = dev_proc(tdev, decode_color)(tdev, color, src_cvals)) < 0)
231*593dc095SDavid du Colombier         return code;
232*593dc095SDavid du Colombier 
233*593dc095SDavid du Colombier     /* allocate space for a scanline of color indices */
234*593dc095SDavid du Colombier     pcolor_buff = (gx_color_index *)
235*593dc095SDavid du Colombier                       gs_alloc_bytes( mem,
236*593dc095SDavid du Colombier                                       w *  arch_sizeof_color_index,
237*593dc095SDavid du Colombier                                       "overprint generic fill rectangle" );
238*593dc095SDavid du Colombier     if (pcolor_buff == 0)
239*593dc095SDavid du Colombier         return gs_note_error(gs_error_VMerror);
240*593dc095SDavid du Colombier 
241*593dc095SDavid du Colombier     /* allocate a buffer for the returned data */
242*593dc095SDavid du Colombier     raster = bitmap_raster(end_x - start_x);
243*593dc095SDavid du Colombier     gb_buff = gs_alloc_bytes(mem, raster, "overprint generic fill rectangle");
244*593dc095SDavid du Colombier     if (gb_buff == 0) {
245*593dc095SDavid du Colombier         gs_free_object( mem,
246*593dc095SDavid du Colombier                         pcolor_buff,
247*593dc095SDavid du Colombier                         "overprint generic fill rectangle" );
248*593dc095SDavid du Colombier         return gs_note_error(gs_error_VMerror);
249*593dc095SDavid du Colombier     }
250*593dc095SDavid du Colombier 
251*593dc095SDavid du Colombier     /*
252*593dc095SDavid du Colombier      * Initialize the get_bits parameters. The selection of options is
253*593dc095SDavid du Colombier      * based on the following logic:
254*593dc095SDavid du Colombier      *
255*593dc095SDavid du Colombier      *  - Overprint is only defined with respect to components of the
256*593dc095SDavid du Colombier      *    process color model, so the retrieved information must be kept
257*593dc095SDavid du Colombier      *    in that color model. The gx_bitmap_format_t bitfield regards
258*593dc095SDavid du Colombier      *    this as the native color space.
259*593dc095SDavid du Colombier      *
260*593dc095SDavid du Colombier      *  - Overprinting and alpha compositing don't mix, so there is no
261*593dc095SDavid du Colombier      *    reason to retrieve the alpha information.
262*593dc095SDavid du Colombier      *
263*593dc095SDavid du Colombier      *  - Data should be returned in the depth of the process color
264*593dc095SDavid du Colombier      *    model. Though this depth could be specified explicitly, there
265*593dc095SDavid du Colombier      *    is little reason to do so.
266*593dc095SDavid du Colombier      *
267*593dc095SDavid du Colombier      *  - Though overprint is much more easily implemented with planar
268*593dc095SDavid du Colombier      *    data, there is no planar version of the copy_color method to
269*593dc095SDavid du Colombier      *    send the modified data back to device. Hence, we must retrieve
270*593dc095SDavid du Colombier      *    data in chunky form.
271*593dc095SDavid du Colombier      *
272*593dc095SDavid du Colombier      *  - It is not possible to modify the raster data "in place", as
273*593dc095SDavid du Colombier      *    doing so would bypass any other forwarding devices currently
274*593dc095SDavid du Colombier      *    in the device "stack" (e.g.: a bounding box device). Hence,
275*593dc095SDavid du Colombier      *    we must work with a copy of the data, which is passed to the
276*593dc095SDavid du Colombier      *    copy_color method at the end of fill_rectangle operation.
277*593dc095SDavid du Colombier      *
278*593dc095SDavid du Colombier      *  - Though we only require data for those planes that will not be
279*593dc095SDavid du Colombier      *    modified, there is no benefit to returning less than the full
280*593dc095SDavid du Colombier      *    data for each pixel if the color encoding is not separable.
281*593dc095SDavid du Colombier      *    Since this routine will be used only for encodings that are
282*593dc095SDavid du Colombier      *    not separable, we might as well ask for full information.
283*593dc095SDavid du Colombier      *
284*593dc095SDavid du Colombier      *  - Though no particular alignment and offset are required, it is
285*593dc095SDavid du Colombier      *    useful to make the copy operation as fast as possible. Ideally
286*593dc095SDavid du Colombier      *    we would calculate an offset so that the data achieves optimal
287*593dc095SDavid du Colombier      *    alignment. Alas, some of the devices work much more slowly if
288*593dc095SDavid du Colombier      *    anything but GB_OFFSET_0 is specified, so that is what we use.
289*593dc095SDavid du Colombier      */
290*593dc095SDavid du Colombier     gb_params.options =  GB_COLORS_NATIVE
291*593dc095SDavid du Colombier                        | GB_ALPHA_NONE
292*593dc095SDavid du Colombier                        | GB_DEPTH_ALL
293*593dc095SDavid du Colombier                        | GB_PACKING_CHUNKY
294*593dc095SDavid du Colombier                        | GB_RETURN_COPY
295*593dc095SDavid du Colombier                        | GB_ALIGN_STANDARD
296*593dc095SDavid du Colombier                        | GB_OFFSET_0
297*593dc095SDavid du Colombier                        | GB_RASTER_STANDARD;
298*593dc095SDavid du Colombier     gb_params.x_offset = 0;     /* for consistency */
299*593dc095SDavid du Colombier     gb_params.data[0] = gb_buff;
300*593dc095SDavid du Colombier     gb_params.raster = raster;
301*593dc095SDavid du Colombier 
302*593dc095SDavid du Colombier     gb_rect.p.x = x;
303*593dc095SDavid du Colombier     gb_rect.q.x = x + w;
304*593dc095SDavid du Colombier 
305*593dc095SDavid du Colombier     /* process each scanline separately */
306*593dc095SDavid du Colombier     while (h-- > 0 && code >= 0) {
307*593dc095SDavid du Colombier         gx_color_index *    cp = pcolor_buff;
308*593dc095SDavid du Colombier         int                 i;
309*593dc095SDavid du Colombier 
310*593dc095SDavid du Colombier         gb_rect.p.y = y++;
311*593dc095SDavid du Colombier         gb_rect.q.y = y;
312*593dc095SDavid du Colombier         code = dev_proc(tdev, get_bits_rectangle)( tdev,
313*593dc095SDavid du Colombier                                                    &gb_rect,
314*593dc095SDavid du Colombier                                                    &gb_params,
315*593dc095SDavid du Colombier                                                    0 );
316*593dc095SDavid du Colombier         if (code < 0)
317*593dc095SDavid du Colombier             break;
318*593dc095SDavid du Colombier         unpack_proc(pcolor_buff, gb_buff, 0, w, depth);
319*593dc095SDavid du Colombier         for (i = 0; i < w; i++, cp++) {
320*593dc095SDavid du Colombier             gx_color_index  comps;
321*593dc095SDavid du Colombier             int             j;
322*593dc095SDavid du Colombier             gx_color_value  dest_cvals[GX_DEVICE_COLOR_MAX_COMPONENTS];
323*593dc095SDavid du Colombier 
324*593dc095SDavid du Colombier             if ((code = dev_proc(tdev, decode_color)(tdev, *cp, dest_cvals)) < 0)
325*593dc095SDavid du Colombier                 break;
326*593dc095SDavid du Colombier             for (j = 0, comps = drawn_comps; comps != 0; ++j, comps >>= 1) {
327*593dc095SDavid du Colombier                 if ((comps & 0x1) != 0)
328*593dc095SDavid du Colombier                     dest_cvals[j] = src_cvals[j];
329*593dc095SDavid du Colombier             }
330*593dc095SDavid du Colombier             *cp = dev_proc(tdev, encode_color)(tdev, dest_cvals);
331*593dc095SDavid du Colombier         }
332*593dc095SDavid du Colombier         pack_proc(pcolor_buff, gb_buff, 0, w, depth);
333*593dc095SDavid du Colombier         code = dev_proc(tdev, copy_color)( tdev,
334*593dc095SDavid du Colombier                                            gb_buff,
335*593dc095SDavid du Colombier                                            0,
336*593dc095SDavid du Colombier                                            raster,
337*593dc095SDavid du Colombier                                            gs_no_bitmap_id,
338*593dc095SDavid du Colombier                                            x, y - 1, w, 1 );
339*593dc095SDavid du Colombier     }
340*593dc095SDavid du Colombier 
341*593dc095SDavid du Colombier     gs_free_object( mem,
342*593dc095SDavid du Colombier                     gb_buff,
343*593dc095SDavid du Colombier                     "overprint generic fill rectangle" );
344*593dc095SDavid du Colombier     gs_free_object( mem,
345*593dc095SDavid du Colombier                     pcolor_buff,
346*593dc095SDavid du Colombier                     "overprint generic fill rectangle" );
347*593dc095SDavid du Colombier 
348*593dc095SDavid du Colombier     return code;
349*593dc095SDavid du Colombier }
350*593dc095SDavid du Colombier 
351*593dc095SDavid du Colombier 
352*593dc095SDavid du Colombier 
353*593dc095SDavid du Colombier /*
354*593dc095SDavid du Colombier  * Replication of 2 and 4 bit patterns to fill a mem_mono_chunk.
355*593dc095SDavid du Colombier  */
356*593dc095SDavid du Colombier private mono_fill_chunk fill_pat_2[4] = {
357*593dc095SDavid du Colombier     mono_fill_make_pattern(0x00), mono_fill_make_pattern(0x55),
358*593dc095SDavid du Colombier     mono_fill_make_pattern(0xaa), mono_fill_make_pattern(0xff)
359*593dc095SDavid du Colombier };
360*593dc095SDavid du Colombier 
361*593dc095SDavid du Colombier private mono_fill_chunk fill_pat_4[16] = {
362*593dc095SDavid du Colombier     mono_fill_make_pattern(0x00), mono_fill_make_pattern(0x11),
363*593dc095SDavid du Colombier     mono_fill_make_pattern(0x22), mono_fill_make_pattern(0x33),
364*593dc095SDavid du Colombier     mono_fill_make_pattern(0x44), mono_fill_make_pattern(0x55),
365*593dc095SDavid du Colombier     mono_fill_make_pattern(0x66), mono_fill_make_pattern(0x77),
366*593dc095SDavid du Colombier     mono_fill_make_pattern(0x88), mono_fill_make_pattern(0x99),
367*593dc095SDavid du Colombier     mono_fill_make_pattern(0xaa), mono_fill_make_pattern(0xbb),
368*593dc095SDavid du Colombier     mono_fill_make_pattern(0xcc), mono_fill_make_pattern(0xdd),
369*593dc095SDavid du Colombier     mono_fill_make_pattern(0xee), mono_fill_make_pattern(0xff)
370*593dc095SDavid du Colombier };
371*593dc095SDavid du Colombier 
372*593dc095SDavid du Colombier /*
373*593dc095SDavid du Colombier  * Replicate a color or mask as required to fill a mem_mono_fill_chunk.
374*593dc095SDavid du Colombier  * This is possible if (8 * sizeof(mono_fill_chunk)) % depth == 0.
375*593dc095SDavid du Colombier  * Since sizeof(mono_fill_chunk) is a power of 2, this will be the case
376*593dc095SDavid du Colombier  * if depth is a power of 2 and depth <= 8 * sizeof(mono_fill_chunk).
377*593dc095SDavid du Colombier  */
378*593dc095SDavid du Colombier private mono_fill_chunk
replicate_color(int depth,mono_fill_chunk color)379*593dc095SDavid du Colombier replicate_color(int depth, mono_fill_chunk color)
380*593dc095SDavid du Colombier {
381*593dc095SDavid du Colombier     switch (depth) {
382*593dc095SDavid du Colombier 
383*593dc095SDavid du Colombier       case 1:
384*593dc095SDavid du Colombier         color = (mono_fill_chunk)(-(int)color); break;
385*593dc095SDavid du Colombier 
386*593dc095SDavid du Colombier       case 2:
387*593dc095SDavid du Colombier         color = fill_pat_2[color]; break;
388*593dc095SDavid du Colombier 
389*593dc095SDavid du Colombier       case 4:
390*593dc095SDavid du Colombier         color = fill_pat_4[color]; break;
391*593dc095SDavid du Colombier 
392*593dc095SDavid du Colombier       case 8:
393*593dc095SDavid du Colombier         color= mono_fill_make_pattern(color); break;
394*593dc095SDavid du Colombier 
395*593dc095SDavid du Colombier #if mono_fill_chunk_bytes > 2
396*593dc095SDavid du Colombier       case 16:
397*593dc095SDavid du Colombier         color = (color << 16) | color;
398*593dc095SDavid du Colombier         /* fall through */
399*593dc095SDavid du Colombier #endif
400*593dc095SDavid du Colombier #if mono_fill_chunk_bytes > 4
401*593dc095SDavid du Colombier       case 32:
402*593dc095SDavid du Colombier         color = (color << 32) | color;
403*593dc095SDavid du Colombier         break;
404*593dc095SDavid du Colombier #endif
405*593dc095SDavid du Colombier     }
406*593dc095SDavid du Colombier 
407*593dc095SDavid du Colombier     return color;
408*593dc095SDavid du Colombier }
409*593dc095SDavid du Colombier 
410*593dc095SDavid du Colombier 
411*593dc095SDavid du Colombier /*
412*593dc095SDavid du Colombier  * Perform the fill rectangle operation for a separable color encoding
413*593dc095SDavid du Colombier  * that requires overprint support.
414*593dc095SDavid du Colombier  *
415*593dc095SDavid du Colombier  * This is handled via two separate cases. If
416*593dc095SDavid du Colombier  *
417*593dc095SDavid du Colombier  *    (8 * sizeof(mono_fill_chunk)) % tdev->color_info.depth = 0,
418*593dc095SDavid du Colombier  *
419*593dc095SDavid du Colombier  * then is possible to work via the masked analog of the bits_fill_rectangle
420*593dc095SDavid du Colombier  * procedure, bits_fill_rectangle_masked. This requires that both the
421*593dc095SDavid du Colombier  * color and component mask be replicated sufficiently to fill the
422*593dc095SDavid du Colombier  * mono_fill_chunk. The somewhat elaborate set-up aside, the resulting
423*593dc095SDavid du Colombier  * algorithm is about as efficient as can be achieved when using
424*593dc095SDavid du Colombier  * get_bits_rectangle. More efficient algorithms require overprint to be
425*593dc095SDavid du Colombier  * implemented in the target device itself.
426*593dc095SDavid du Colombier  *
427*593dc095SDavid du Colombier  * If the condition is not satisfied, a simple byte-wise algorithm is
428*593dc095SDavid du Colombier  * used. This requires minimal setup but is not efficient, as it works in
429*593dc095SDavid du Colombier  * units that are too small. More efficient methods are possible in this
430*593dc095SDavid du Colombier  * case, but the required setup for a general depth is excessive (even
431*593dc095SDavid du Colombier  * with the restriction that depth % 8 = 0). Hence, efficiency for these
432*593dc095SDavid du Colombier  * cases is better addressed by direct implementation of overprint for
433*593dc095SDavid du Colombier  * memory devices.
434*593dc095SDavid du Colombier  *
435*593dc095SDavid du Colombier  * For both cases, the color and retain_mask values passed to this
436*593dc095SDavid du Colombier  * procedure are expected to be already swapped as required for a byte-
437*593dc095SDavid du Colombier  * oriented bitmap. This consideration affects only little-endian
438*593dc095SDavid du Colombier  * machines. For those machines, if depth > 9 the color passed to these
439*593dc095SDavid du Colombier  * two procedures will not be the same as that passed to
440*593dc095SDavid du Colombier  * gx_overprint_generic_fill_rectangle.
441*593dc095SDavid du Colombier  *
442*593dc095SDavid du Colombier  * Returns 0 on success, < 0 in the event of an error.
443*593dc095SDavid du Colombier  */
444*593dc095SDavid du Colombier int
gx_overprint_sep_fill_rectangle_1(gx_device * tdev,gx_color_index retain_mask,int x,int y,int w,int h,gx_color_index color,gs_memory_t * mem)445*593dc095SDavid du Colombier gx_overprint_sep_fill_rectangle_1(
446*593dc095SDavid du Colombier     gx_device *             tdev,
447*593dc095SDavid du Colombier     gx_color_index          retain_mask,    /* already swapped */
448*593dc095SDavid du Colombier     int                     x,
449*593dc095SDavid du Colombier     int                     y,
450*593dc095SDavid du Colombier     int                     w,
451*593dc095SDavid du Colombier     int                     h,
452*593dc095SDavid du Colombier     gx_color_index          color,          /* already swapped */
453*593dc095SDavid du Colombier     gs_memory_t *           mem )
454*593dc095SDavid du Colombier {
455*593dc095SDavid du Colombier     byte *                  gb_buff = 0;
456*593dc095SDavid du Colombier     gs_get_bits_params_t    gb_params;
457*593dc095SDavid du Colombier     gs_int_rect             gb_rect;
458*593dc095SDavid du Colombier     int                     code = 0, bit_w, depth = tdev->color_info.depth;
459*593dc095SDavid du Colombier     int                     raster;
460*593dc095SDavid du Colombier     mono_fill_chunk         rep_color, rep_mask;
461*593dc095SDavid du Colombier 
462*593dc095SDavid du Colombier     fit_fill(tdev, x, y, w, h);
463*593dc095SDavid du Colombier     bit_w = w * depth;
464*593dc095SDavid du Colombier 
465*593dc095SDavid du Colombier     /* set up replicated color and retain mask */
466*593dc095SDavid du Colombier     if (depth < 8 * sizeof(mono_fill_chunk)) {
467*593dc095SDavid du Colombier         rep_color = replicate_color(depth, (mono_fill_chunk)color);
468*593dc095SDavid du Colombier         rep_mask = replicate_color(depth, (mono_fill_chunk)retain_mask);
469*593dc095SDavid du Colombier     } else {
470*593dc095SDavid du Colombier         rep_color = (mono_fill_chunk)color;
471*593dc095SDavid du Colombier         rep_mask = (mono_fill_chunk)retain_mask;
472*593dc095SDavid du Colombier     }
473*593dc095SDavid du Colombier 
474*593dc095SDavid du Colombier     /* allocate a buffer for the returned data */
475*593dc095SDavid du Colombier     raster = bitmap_raster(w * depth);
476*593dc095SDavid du Colombier     gb_buff = gs_alloc_bytes(mem, raster, "overprint sep fill rectangle 1");
477*593dc095SDavid du Colombier     if (gb_buff == 0)
478*593dc095SDavid du Colombier         return gs_note_error(gs_error_VMerror);
479*593dc095SDavid du Colombier 
480*593dc095SDavid du Colombier     /*
481*593dc095SDavid du Colombier      * Initialize the get_bits parameters. The selection of options is
482*593dc095SDavid du Colombier      * the same as that for gx_overprint_generic_fill_rectangle (above).
483*593dc095SDavid du Colombier      */
484*593dc095SDavid du Colombier     gb_params.options =  GB_COLORS_NATIVE
485*593dc095SDavid du Colombier                        | GB_ALPHA_NONE
486*593dc095SDavid du Colombier                        | GB_DEPTH_ALL
487*593dc095SDavid du Colombier                        | GB_PACKING_CHUNKY
488*593dc095SDavid du Colombier                        | GB_RETURN_COPY
489*593dc095SDavid du Colombier                        | GB_ALIGN_STANDARD
490*593dc095SDavid du Colombier                        | GB_OFFSET_0
491*593dc095SDavid du Colombier                        | GB_RASTER_STANDARD;
492*593dc095SDavid du Colombier     gb_params.x_offset = 0;     /* for consistency */
493*593dc095SDavid du Colombier     gb_params.data[0] = gb_buff;
494*593dc095SDavid du Colombier     gb_params.raster = raster;
495*593dc095SDavid du Colombier 
496*593dc095SDavid du Colombier     gb_rect.p.x = x;
497*593dc095SDavid du Colombier     gb_rect.q.x = x + w;
498*593dc095SDavid du Colombier 
499*593dc095SDavid du Colombier     /* process each scanline separately */
500*593dc095SDavid du Colombier     while (h-- > 0 && code >= 0) {
501*593dc095SDavid du Colombier         gb_rect.p.y = y++;
502*593dc095SDavid du Colombier         gb_rect.q.y = y;
503*593dc095SDavid du Colombier         code = dev_proc(tdev, get_bits_rectangle)( tdev,
504*593dc095SDavid du Colombier                                                    &gb_rect,
505*593dc095SDavid du Colombier                                                    &gb_params,
506*593dc095SDavid du Colombier                                                    0 );
507*593dc095SDavid du Colombier         if (code < 0)
508*593dc095SDavid du Colombier             break;
509*593dc095SDavid du Colombier         bits_fill_rectangle_masked( gb_buff,
510*593dc095SDavid du Colombier                                     0,
511*593dc095SDavid du Colombier                                     raster,
512*593dc095SDavid du Colombier                                     rep_color,
513*593dc095SDavid du Colombier                                     rep_mask,
514*593dc095SDavid du Colombier                                     bit_w,
515*593dc095SDavid du Colombier                                     1 );
516*593dc095SDavid du Colombier         code = dev_proc(tdev, copy_color)( tdev,
517*593dc095SDavid du Colombier                                            gb_buff,
518*593dc095SDavid du Colombier                                            0,
519*593dc095SDavid du Colombier                                            raster,
520*593dc095SDavid du Colombier                                            gs_no_bitmap_id,
521*593dc095SDavid du Colombier                                            x, y - 1, w, 1 );
522*593dc095SDavid du Colombier     }
523*593dc095SDavid du Colombier 
524*593dc095SDavid du Colombier     gs_free_object( mem,
525*593dc095SDavid du Colombier                     gb_buff,
526*593dc095SDavid du Colombier                     "overprint generic fill rectangle" );
527*593dc095SDavid du Colombier 
528*593dc095SDavid du Colombier     return code;
529*593dc095SDavid du Colombier }
530*593dc095SDavid du Colombier 
531*593dc095SDavid du Colombier 
532*593dc095SDavid du Colombier int
gx_overprint_sep_fill_rectangle_2(gx_device * tdev,gx_color_index retain_mask,int x,int y,int w,int h,gx_color_index color,gs_memory_t * mem)533*593dc095SDavid du Colombier gx_overprint_sep_fill_rectangle_2(
534*593dc095SDavid du Colombier     gx_device *             tdev,
535*593dc095SDavid du Colombier     gx_color_index          retain_mask,    /* already swapped */
536*593dc095SDavid du Colombier     int                     x,
537*593dc095SDavid du Colombier     int                     y,
538*593dc095SDavid du Colombier     int                     w,
539*593dc095SDavid du Colombier     int                     h,
540*593dc095SDavid du Colombier     gx_color_index          color,          /* already swapped */
541*593dc095SDavid du Colombier     gs_memory_t *           mem )
542*593dc095SDavid du Colombier {
543*593dc095SDavid du Colombier     byte *                  gb_buff = 0;
544*593dc095SDavid du Colombier     gs_get_bits_params_t    gb_params;
545*593dc095SDavid du Colombier     gs_int_rect             gb_rect;
546*593dc095SDavid du Colombier     int                     code = 0, byte_w, raster;
547*593dc095SDavid du Colombier     int                     byte_depth = tdev->color_info.depth >> 3;
548*593dc095SDavid du Colombier     byte *                  pcolor;
549*593dc095SDavid du Colombier     byte *                  pmask;
550*593dc095SDavid du Colombier 
551*593dc095SDavid du Colombier     fit_fill(tdev, x, y, w, h);
552*593dc095SDavid du Colombier     byte_w = w * byte_depth;
553*593dc095SDavid du Colombier 
554*593dc095SDavid du Colombier     /* set up color and retain mask pointers */
555*593dc095SDavid du Colombier     pcolor = (byte *)&color;
556*593dc095SDavid du Colombier     pmask = (byte *)&retain_mask;
557*593dc095SDavid du Colombier #if arch_is_big_endian
558*593dc095SDavid du Colombier     pcolor += arch_sizeof_color_index - byte_depth;
559*593dc095SDavid du Colombier     pmask += arch_sizeof_color_index - byte_depth;
560*593dc095SDavid du Colombier #endif
561*593dc095SDavid du Colombier 
562*593dc095SDavid du Colombier     /* allocate a buffer for the returned data */
563*593dc095SDavid du Colombier     raster = bitmap_raster(w * (byte_depth << 3));
564*593dc095SDavid du Colombier     gb_buff = gs_alloc_bytes(mem, raster, "overprint sep fill rectangle 2");
565*593dc095SDavid du Colombier     if (gb_buff == 0)
566*593dc095SDavid du Colombier         return gs_note_error(gs_error_VMerror);
567*593dc095SDavid du Colombier 
568*593dc095SDavid du Colombier     /*
569*593dc095SDavid du Colombier      * Initialize the get_bits parameters. The selection of options is
570*593dc095SDavid du Colombier      * the same as that for gx_overprint_generic_fill_rectangle (above).
571*593dc095SDavid du Colombier      */
572*593dc095SDavid du Colombier     gb_params.options =  GB_COLORS_NATIVE
573*593dc095SDavid du Colombier                        | GB_ALPHA_NONE
574*593dc095SDavid du Colombier                        | GB_DEPTH_ALL
575*593dc095SDavid du Colombier                        | GB_PACKING_CHUNKY
576*593dc095SDavid du Colombier                        | GB_RETURN_COPY
577*593dc095SDavid du Colombier                        | GB_ALIGN_STANDARD
578*593dc095SDavid du Colombier                        | GB_OFFSET_0
579*593dc095SDavid du Colombier                        | GB_RASTER_STANDARD;
580*593dc095SDavid du Colombier     gb_params.x_offset = 0;     /* for consistency */
581*593dc095SDavid du Colombier     gb_params.data[0] = gb_buff;
582*593dc095SDavid du Colombier     gb_params.raster = raster;
583*593dc095SDavid du Colombier 
584*593dc095SDavid du Colombier     gb_rect.p.x = x;
585*593dc095SDavid du Colombier     gb_rect.q.x = x + w;
586*593dc095SDavid du Colombier 
587*593dc095SDavid du Colombier     /* process each scanline separately */
588*593dc095SDavid du Colombier     while (h-- > 0 && code >= 0) {
589*593dc095SDavid du Colombier         int     i, j;
590*593dc095SDavid du Colombier         byte *  cp = gb_buff;
591*593dc095SDavid du Colombier 
592*593dc095SDavid du Colombier         gb_rect.p.y = y++;
593*593dc095SDavid du Colombier         gb_rect.q.y = y;
594*593dc095SDavid du Colombier         code = dev_proc(tdev, get_bits_rectangle)( tdev,
595*593dc095SDavid du Colombier                                                    &gb_rect,
596*593dc095SDavid du Colombier                                                    &gb_params,
597*593dc095SDavid du Colombier                                                    0 );
598*593dc095SDavid du Colombier         if (code < 0)
599*593dc095SDavid du Colombier             break;
600*593dc095SDavid du Colombier         for (i = 0, j = 0; i < byte_w; i++, cp++) {
601*593dc095SDavid du Colombier             *cp = (*cp & pmask[j]) | pcolor[j];
602*593dc095SDavid du Colombier             if (++j == byte_depth)
603*593dc095SDavid du Colombier                 j = 0;
604*593dc095SDavid du Colombier         }
605*593dc095SDavid du Colombier         code = dev_proc(tdev, copy_color)( tdev,
606*593dc095SDavid du Colombier                                            gb_buff,
607*593dc095SDavid du Colombier                                            0,
608*593dc095SDavid du Colombier                                            raster,
609*593dc095SDavid du Colombier                                            gs_no_bitmap_id,
610*593dc095SDavid du Colombier                                            x, y - 1, w, 1 );
611*593dc095SDavid du Colombier     }
612*593dc095SDavid du Colombier 
613*593dc095SDavid du Colombier     gs_free_object( mem,
614*593dc095SDavid du Colombier                     gb_buff,
615*593dc095SDavid du Colombier                     "overprint generic fill rectangle" );
616*593dc095SDavid du Colombier 
617*593dc095SDavid du Colombier     return code;
618*593dc095SDavid du Colombier }
619*593dc095SDavid du Colombier 
620