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