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