From 6948650efd3fb9e2a70b8cf16aca57e9d0b7eb0a Mon Sep 17 00:00:00 2001 From: Chris Liddell Date: Tue, 23 Jul 2013 16:24:19 +0100 Subject: Commit of build_consolidation branch Squashed into one commit (see branch for details of the evolution of the branch). This brings gpcl6 and gxps into the Ghostscript build system, and a shared set of graphics library object files for all the interpreters. Also, brings the same configuration options to the pcl and xps products as we have for Ghostscript. --- base/gxoprect.c | 626 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 626 insertions(+) create mode 100644 base/gxoprect.c (limited to 'base/gxoprect.c') diff --git a/base/gxoprect.c b/base/gxoprect.c new file mode 100644 index 000000000..5a188128a --- /dev/null +++ b/base/gxoprect.c @@ -0,0 +1,626 @@ +/* Copyright (C) 2001-2012 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, + CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ + + +/* generic (very slow) overprint fill rectangle implementation */ + +#include "memory_.h" +#include "gx.h" +#include "gserrors.h" +#include "gsutil.h" /* for gs_next_ids */ +#include "gxdevice.h" +#include "gsdevice.h" +#include "gxgetbit.h" +#include "gxoprect.h" +#include "gsbitops.h" + +/* + * Unpack a scanline for a depth < 8. In this case we know the depth is + * divisor of 8 and thus a power of 2, which implies that 8 / depth is + * also a power of 2. + */ +static void +unpack_scanline_lt8( + gx_color_index * destp, + const byte * srcp, + int src_offset, + int width, + int depth ) +{ + byte buff = 0; + int i = 0, shift = 8 - depth, p_per_byte = 8 / depth; + + /* exit early if nothing to do */ + if (width == 0) + return; + + /* skip over src_offset */ + if (src_offset >= p_per_byte) { + srcp += src_offset / p_per_byte; + src_offset &= (p_per_byte - 1); + } + if (src_offset > 0) { + buff = *srcp++ << (src_offset * depth); + i = src_offset; + width += src_offset; + } + + /* process the interesting part of the scanline */ + for (; i < width; i++, buff <<= depth) { + if ((i & (p_per_byte - 1)) == 0) + buff = *srcp++; + *destp++ = buff >> shift; + } +} + +/* + * Pack a scanline for a depth of < 8. Note that data prior to dest_offset + * and any data beyond the width must be left undisturbed. + */ +static void +pack_scanline_lt8( + const gx_color_index * srcp, + byte * destp, + int dest_offset, + int width, + int depth ) +{ + byte buff = 0; + int i = 0, p_per_byte = 8 / depth; + + /* exit early if nothing to do */ + if (width == 0) + return; + + /* skip over dest_offset */ + if (dest_offset >= p_per_byte) { + destp += dest_offset / p_per_byte; + dest_offset &= (p_per_byte - 1); + } + if (dest_offset > 0) { + buff = *destp++ >> (8 - dest_offset * depth); + i = dest_offset; + width += dest_offset; + } + + /* process the interesting part of the scanline */ + for (; i < width; i++) { + buff = (buff << depth) | *srcp++; + if ((i & (p_per_byte - 1)) == p_per_byte - 1) + *destp++ = buff; + } + if ((i &= (p_per_byte - 1)) != 0) { + int shift = depth * (p_per_byte - i); + int mask = (1 << shift) - 1; + + *destp = (*destp & mask) | (buff << shift); + } +} + +/* + * Unpack a scanline for a depth >= 8. In this case, the depth must be + * a multiple of 8. + */ +static void +unpack_scanline_ge8( + gx_color_index * destp, + const byte * srcp, + int src_offset, + int width, + int depth ) +{ + gx_color_index buff = 0; + int i, j, bytes_per_p = depth >> 3; + + /* skip over src_offset */ + srcp += src_offset * bytes_per_p; + + /* process the interesting part of the scanline */ + width *= bytes_per_p; + for (i = 0, j = 0; i < width; i++) { + buff = (buff << 8) | *srcp++; + if (++j == bytes_per_p) { + *destp++ = buff; + buff = 0; + j = 0; + } + } +} + +/* + * Pack a scanline for depth >= 8. + */ +static void +pack_scanline_ge8( + const gx_color_index * srcp, + byte * destp, + int dest_offset, + int width, + int depth ) +{ + gx_color_index buff = 0; + int i, j, bytes_per_p = depth >> 3; + int shift = depth - 8; + + /* skip over dest_offset */ + destp += dest_offset; + + /* process the interesting part of the scanline */ + width *= bytes_per_p; + for (i = 0, j = bytes_per_p - 1; i < width; i++, buff <<= 8) { + if (++j == bytes_per_p) { + buff = *srcp++; + j = 0; + } + *destp++ = buff >> shift; + } +} + +/* + * Perform the fill rectangle operation for a non-separable color encoding + * that requires overprint support. This situation requires that colors be + * decoded, modified, and re-encoded. These steps must be performed per + * output pixel, so there is no hope of achieving good performance. + * Consequently, only minimal performance optimizations are applied below. + * + * The overprint device structure is known only in gsovr.c, and thus is not + * available here. The required information from the overprint device is, + * therefore, provided via explicit operands. The device operand points to + * the target of the overprint compositor device, not the compositor device + * itself. The drawn_comps bit array and the memory descriptor pointer are + * also provided explicitly as operands. + * + * Returns 0 on success, < 0 in the event of an error. + */ +int +gx_overprint_generic_fill_rectangle( + gx_device * tdev, + bool blendspot, + gx_color_index drawn_comps, + ushort k_value, + int x, + int y, + int w, + int h, + gx_color_index color, + gs_memory_t * mem ) +{ + gx_color_value src_cvals[GX_DEVICE_COLOR_MAX_COMPONENTS]; + gx_color_index * pcolor_buff = 0; + byte * gb_buff = 0; + gs_get_bits_params_t gb_params; + gs_int_rect gb_rect; + int depth = tdev->color_info.depth; + int bit_x, start_x, end_x, raster, code; + void (*unpack_proc)( gx_color_index *, + const byte *, + int, int, int ); + void (*pack_proc)( const gx_color_index *, + byte *, + int, int, int ); + + fit_fill(tdev, x, y, w, h); + bit_x = x * depth; + start_x = bit_x & ~(8 * align_bitmap_mod - 1); + end_x = bit_x + w * depth; + + /* select the appropriate pack/unpack routines */ + if (depth >= 8) { + unpack_proc = unpack_scanline_ge8; + pack_proc = pack_scanline_ge8; + } else { + unpack_proc = unpack_scanline_lt8; + pack_proc = pack_scanline_lt8; + } + + /* decode the source color */ + if ((code = dev_proc(tdev, decode_color)(tdev, color, src_cvals)) < 0) + return code; + + /* allocate space for a scanline of color indices */ + pcolor_buff = (gx_color_index *) + gs_alloc_bytes( mem, + w * arch_sizeof_color_index, + "overprint generic fill rectangle" ); + if (pcolor_buff == 0) + return gs_note_error(gs_error_VMerror); + + /* allocate a buffer for the returned data */ + raster = bitmap_raster(end_x - start_x); + gb_buff = gs_alloc_bytes(mem, raster, "overprint generic fill rectangle"); + if (gb_buff == 0) { + gs_free_object( mem, + pcolor_buff, + "overprint generic fill rectangle" ); + return gs_note_error(gs_error_VMerror); + } + + /* + * Initialize the get_bits parameters. The selection of options is + * based on the following logic: + * + * - Overprint is only defined with respect to components of the + * process color model, so the retrieved information must be kept + * in that color model. The gx_bitmap_format_t bitfield regards + * this as the native color space. + * + * - Overprinting and alpha compositing don't mix, so there is no + * reason to retrieve the alpha information. + * + * - Data should be returned in the depth of the process color + * model. Though this depth could be specified explicitly, there + * is little reason to do so. + * + * - Though overprint is much more easily implemented with planar + * data, there is no planar version of the copy_color method to + * send the modified data back to device. Hence, we must retrieve + * data in chunky form. + * + * - It is not possible to modify the raster data "in place", as + * doing so would bypass any other forwarding devices currently + * in the device "stack" (e.g.: a bounding box device). Hence, + * we must work with a copy of the data, which is passed to the + * copy_color method at the end of fill_rectangle operation. + * + * - Though we only require data for those planes that will not be + * modified, there is no benefit to returning less than the full + * data for each pixel if the color encoding is not separable. + * Since this routine will be used only for encodings that are + * not separable, we might as well ask for full information. + * + * - Though no particular alignment and offset are required, it is + * useful to make the copy operation as fast as possible. Ideally + * we would calculate an offset so that the data achieves optimal + * alignment. Alas, some of the devices work much more slowly if + * anything but GB_OFFSET_0 is specified, so that is what we use. + */ + gb_params.options = GB_COLORS_NATIVE + | GB_ALPHA_NONE + | GB_DEPTH_ALL + | GB_PACKING_CHUNKY + | GB_RETURN_COPY + | GB_ALIGN_STANDARD + | GB_OFFSET_0 + | GB_RASTER_STANDARD; + gb_params.x_offset = 0; /* for consistency */ + gb_params.data[0] = gb_buff; + gb_params.raster = raster; + + gb_rect.p.x = x; + gb_rect.q.x = x + w; + + /* process each scanline separately */ + while (h-- > 0 && code >= 0) { + gx_color_index * cp = pcolor_buff; + int i; + + gb_rect.p.y = y++; + gb_rect.q.y = y; + code = dev_proc(tdev, get_bits_rectangle)( tdev, + &gb_rect, + &gb_params, + 0 ); + if (code < 0) + break; + unpack_proc(pcolor_buff, gb_buff, 0, w, depth); + for (i = 0; i < w; i++, cp++) { + gx_color_index comps; + int j; + gx_color_value dest_cvals[GX_DEVICE_COLOR_MAX_COMPONENTS]; + + if ((code = dev_proc(tdev, decode_color)(tdev, *cp, dest_cvals)) < 0) + break; + if (k_value > 0) { + /* Have to run through all 3 components */ + for (j = 0, comps = drawn_comps; j < 3; j++, comps >>= 1) { + if ((comps & 0x1) != 0) + dest_cvals[j] = src_cvals[j]; + else { + int temp = (dest_cvals[j] * (256 - k_value)); + dest_cvals[j] = temp >> 8; + } + } + } else { + for (j = 0, comps = drawn_comps; comps != 0; ++j, comps >>= 1) { + if ((comps & 0x1) != 0) + dest_cvals[j] = src_cvals[j]; + } + } + *cp = dev_proc(tdev, encode_color)(tdev, dest_cvals); + } + pack_proc(pcolor_buff, gb_buff, 0, w, depth); + code = dev_proc(tdev, copy_color)( tdev, + gb_buff, + 0, + raster, + gs_no_bitmap_id, + x, y - 1, w, 1 ); + } + + gs_free_object( mem, + gb_buff, + "overprint generic fill rectangle" ); + gs_free_object( mem, + pcolor_buff, + "overprint generic fill rectangle" ); + + return code; +} + +/* + * Replication of 2 and 4 bit patterns to fill a mem_mono_chunk. + */ +static mono_fill_chunk fill_pat_2[4] = { + mono_fill_make_pattern(0x00), mono_fill_make_pattern(0x55), + mono_fill_make_pattern(0xaa), mono_fill_make_pattern(0xff) +}; + +static mono_fill_chunk fill_pat_4[16] = { + mono_fill_make_pattern(0x00), mono_fill_make_pattern(0x11), + mono_fill_make_pattern(0x22), mono_fill_make_pattern(0x33), + mono_fill_make_pattern(0x44), mono_fill_make_pattern(0x55), + mono_fill_make_pattern(0x66), mono_fill_make_pattern(0x77), + mono_fill_make_pattern(0x88), mono_fill_make_pattern(0x99), + mono_fill_make_pattern(0xaa), mono_fill_make_pattern(0xbb), + mono_fill_make_pattern(0xcc), mono_fill_make_pattern(0xdd), + mono_fill_make_pattern(0xee), mono_fill_make_pattern(0xff) +}; + +/* + * Replicate a color or mask as required to fill a mem_mono_fill_chunk. + * This is possible if (8 * sizeof(mono_fill_chunk)) % depth == 0. + * Since sizeof(mono_fill_chunk) is a power of 2, this will be the case + * if depth is a power of 2 and depth <= 8 * sizeof(mono_fill_chunk). + */ +static mono_fill_chunk +replicate_color(int depth, mono_fill_chunk color) +{ + switch (depth) { + + case 1: + color = (mono_fill_chunk)(-(int)color); break; + + case 2: + color = fill_pat_2[color]; break; + + case 4: + color = fill_pat_4[color]; break; + + case 8: + color= mono_fill_make_pattern(color); break; + +#if mono_fill_chunk_bytes > 2 + case 16: + color = (color << 16) | color; + /* fall through */ +#endif +#if mono_fill_chunk_bytes > 4 + case 32: + color = (color << 32) | color; + break; +#endif + } + + return color; +} + +/* + * Perform the fill rectangle operation for a separable color encoding + * that requires overprint support. + * + * This is handled via two separate cases. If + * + * (8 * sizeof(mono_fill_chunk)) % tdev->color_info.depth = 0, + * + * then is possible to work via the masked analog of the bits_fill_rectangle + * procedure, bits_fill_rectangle_masked. This requires that both the + * color and component mask be replicated sufficiently to fill the + * mono_fill_chunk. The somewhat elaborate set-up aside, the resulting + * algorithm is about as efficient as can be achieved when using + * get_bits_rectangle. More efficient algorithms require overprint to be + * implemented in the target device itself. + * + * If the condition is not satisfied, a simple byte-wise algorithm is + * used. This requires minimal setup but is not efficient, as it works in + * units that are too small. More efficient methods are possible in this + * case, but the required setup for a general depth is excessive (even + * with the restriction that depth % 8 = 0). Hence, efficiency for these + * cases is better addressed by direct implementation of overprint for + * memory devices. + * + * For both cases, the color and retain_mask values passed to this + * procedure are expected to be already swapped as required for a byte- + * oriented bitmap. This consideration affects only little-endian + * machines. For those machines, if depth > 9 the color passed to these + * two procedures will not be the same as that passed to + * gx_overprint_generic_fill_rectangle. + * + * Returns 0 on success, < 0 in the event of an error. + */ +int +gx_overprint_sep_fill_rectangle_1( + gx_device * tdev, + gx_color_index retain_mask, /* already swapped */ + int x, + int y, + int w, + int h, + gx_color_index color, /* already swapped */ + gs_memory_t * mem ) +{ + byte * gb_buff = 0; + gs_get_bits_params_t gb_params; + gs_int_rect gb_rect; + int code = 0, bit_w, depth = tdev->color_info.depth; + int raster; + mono_fill_chunk rep_color, rep_mask; + + fit_fill(tdev, x, y, w, h); + bit_w = w * depth; + + /* set up replicated color and retain mask */ + if (depth < 8 * sizeof(mono_fill_chunk)) { + rep_color = replicate_color(depth, (mono_fill_chunk)color); + rep_mask = replicate_color(depth, (mono_fill_chunk)retain_mask); + } else { + rep_color = (mono_fill_chunk)color; + rep_mask = (mono_fill_chunk)retain_mask; + } + + /* allocate a buffer for the returned data */ + raster = bitmap_raster(w * depth); + gb_buff = gs_alloc_bytes(mem, raster, "overprint sep fill rectangle 1"); + if (gb_buff == 0) + return gs_note_error(gs_error_VMerror); + + /* + * Initialize the get_bits parameters. The selection of options is + * the same as that for gx_overprint_generic_fill_rectangle (above). + */ + gb_params.options = GB_COLORS_NATIVE + | GB_ALPHA_NONE + | GB_DEPTH_ALL + | GB_PACKING_CHUNKY + | GB_RETURN_COPY + | GB_ALIGN_STANDARD + | GB_OFFSET_0 + | GB_RASTER_STANDARD; + gb_params.x_offset = 0; /* for consistency */ + gb_params.data[0] = gb_buff; + gb_params.raster = raster; + + gb_rect.p.x = x; + gb_rect.q.x = x + w; + + /* process each scanline separately */ + while (h-- > 0 && code >= 0) { + gb_rect.p.y = y++; + gb_rect.q.y = y; + code = dev_proc(tdev, get_bits_rectangle)( tdev, + &gb_rect, + &gb_params, + 0 ); + if (code < 0) + break; + bits_fill_rectangle_masked( gb_buff, + 0, + raster, + rep_color, + rep_mask, + bit_w, + 1 ); + code = dev_proc(tdev, copy_color)( tdev, + gb_buff, + 0, + raster, + gs_no_bitmap_id, + x, y - 1, w, 1 ); + } + + gs_free_object( mem, + gb_buff, + "overprint generic fill rectangle" ); + + return code; +} + +int +gx_overprint_sep_fill_rectangle_2( + gx_device * tdev, + bool blendspot, + gx_color_index retain_mask, /* already swapped */ + int x, + int y, + int w, + int h, + gx_color_index color, /* already swapped */ + gs_memory_t * mem ) +{ + byte * gb_buff = 0; + gs_get_bits_params_t gb_params; + gs_int_rect gb_rect; + int code = 0, byte_w, raster; + int byte_depth = tdev->color_info.depth >> 3; + byte * pcolor; + byte * pmask; + + fit_fill(tdev, x, y, w, h); + byte_w = w * byte_depth; + + /* set up color and retain mask pointers */ + pcolor = (byte *)&color; + pmask = (byte *)&retain_mask; +#if arch_is_big_endian + pcolor += arch_sizeof_color_index - byte_depth; + pmask += arch_sizeof_color_index - byte_depth; +#endif + + /* allocate a buffer for the returned data */ + raster = bitmap_raster(w * (byte_depth << 3)); + gb_buff = gs_alloc_bytes(mem, raster, "overprint sep fill rectangle 2"); + if (gb_buff == 0) + return gs_note_error(gs_error_VMerror); + + /* + * Initialize the get_bits parameters. The selection of options is + * the same as that for gx_overprint_generic_fill_rectangle (above). + */ + gb_params.options = GB_COLORS_NATIVE + | GB_ALPHA_NONE + | GB_DEPTH_ALL + | GB_PACKING_CHUNKY + | GB_RETURN_COPY + | GB_ALIGN_STANDARD + | GB_OFFSET_0 + | GB_RASTER_STANDARD; + gb_params.x_offset = 0; /* for consistency */ + gb_params.data[0] = gb_buff; + gb_params.raster = raster; + + gb_rect.p.x = x; + gb_rect.q.x = x + w; + + /* process each scanline separately */ + while (h-- > 0 && code >= 0) { + int i, j; + byte * cp = gb_buff; + + gb_rect.p.y = y++; + gb_rect.q.y = y; + code = dev_proc(tdev, get_bits_rectangle)( tdev, + &gb_rect, + &gb_params, + 0 ); + if (code < 0) + break; + for (i = 0, j = 0; i < byte_w; i++, cp++) { + *cp = (*cp & pmask[j]) | pcolor[j]; + if (++j == byte_depth) + j = 0; + } + code = dev_proc(tdev, copy_color)( tdev, + gb_buff, + 0, + raster, + gs_no_bitmap_id, + x, y - 1, w, 1 ); + } + + gs_free_object( mem, + gb_buff, + "overprint generic fill rectangle" ); + + return code; +} -- cgit v1.2.1