/* Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gdevxalt.c,v 1.2.6.2.2.1 2003/01/17 00:49:02 giles Exp $ */ /* Alternative X Windows drivers for help in driver debugging */ #include "gx.h" /* for gx_bitmap; includes std.h */ #include "math_.h" #include "memory_.h" #include "x_.h" #include "gserrors.h" #include "gsparam.h" #include "gsstruct.h" #include "gxdevice.h" #include "gsdevice.h" /* for gs_copydevice */ #include "gdevx.h" extern const gx_device_X gs_x11_device; /* * Define a forwarding device with a cache for the first 16 colors, * which avoids all of the time-consuming color mapping calls for * the black-and-white, 2-bit gray, and 1-bit CMYK devices defined here. */ typedef struct { gx_device_forward_common; gx_color_index color_cache[16]; /* * alt_map_color returns a value >= 0 if it maps directly to the final * gx_color_index, or < 0 if it only sets RGB values. */ dev_proc_map_color_rgb((*alt_map_color)); } gx_device_X_wrapper; #define X_WRAPPER_DATA(amc_proc)\ /* gx_device_forward_common */\ {0}, /* std_procs */\ 0, /* target */\ /* gx_device_X_wrapper */\ {0}, /* cache */\ amc_proc gs_private_st_suffix_add0_final(st_device_X_wrapper, gx_device_X_wrapper, "gx_device_X_wrapper", gdevx_wrapper_enum_ptrs, gdevx_wrapper_reloc_ptrs, gx_device_finalize, st_device_forward); /* ---------------- Generic procedures ---------------- */ /* Forward declarations */ private int get_dev_target(P2(gx_device **, gx_device *)); #define set_dev_target(tdev, dev)\ return_if_error(get_dev_target(&tdev, dev)) private int get_target_info(P1(gx_device *)); private gx_color_index x_alt_map_color(P2(gx_device *, gx_color_index)); /* Clear the color mapping cache. */ private void x_clear_color_cache(gx_device /*gx_device_X_wrapper */ * dev) { gx_device_X_wrapper *xdev = (gx_device_X_wrapper *) dev; int i; for (i = 0; i < countof(xdev->color_cache); ++i) xdev->color_cache[i] = gx_no_color_index; gx_device_decache_colors(dev); } /* "Wrappers" for driver procedures */ private int x_wrap_open(gx_device * dev) { gx_device *tdev; int rcode, code; set_dev_target(tdev, dev); rcode = (*dev_proc(tdev, open_device)) (tdev); if (rcode < 0) return rcode; tdev->is_open = true; code = get_target_info(dev); return (code < 0 ? code : rcode); } private int x_forward_sync_output(gx_device * dev) { gx_device *tdev; set_dev_target(tdev, dev); return (*dev_proc(tdev, sync_output)) (tdev); } private int x_forward_output_page(gx_device * dev, int num_copies, int flush) { gx_device *tdev; set_dev_target(tdev, dev); return (*dev_proc(tdev, output_page)) (tdev, num_copies, flush); } private int x_wrap_close(gx_device * dev) { /* * The underlying x11 device will be closed and freed as soon as there * are no more pointers to it, which normally occurs in the next * statement. */ gx_device_set_target((gx_device_forward *)dev, NULL); x_clear_color_cache(dev); return 0; } private int x_wrap_map_color_rgb(gx_device * dev, gx_color_index color, gx_color_value prgb[3]) { gx_device *tdev; set_dev_target(tdev, dev); return (*dev_proc(tdev, map_color_rgb)) (tdev, x_alt_map_color(dev, color), prgb); } private int x_wrap_fill_rectangle(gx_device * dev, int x, int y, int w, int h, gx_color_index color) { gx_device *tdev; set_dev_target(tdev, dev); return (*dev_proc(tdev, fill_rectangle)) (tdev, x, y, w, h, x_alt_map_color(dev, color)); } private int x_wrap_copy_mono(gx_device * dev, const byte * base, int sourcex, int raster, gx_bitmap_id id, int x, int y, int w, int h, gx_color_index zero, gx_color_index one) { gx_device *tdev; set_dev_target(tdev, dev); return (*dev_proc(tdev, copy_mono)) (tdev, base, sourcex, raster, id, x, y, w, h, x_alt_map_color(dev, zero), x_alt_map_color(dev, one)); } private int x_wrap_copy_color(gx_device * dev, const byte * base, int sourcex, int raster, gx_bitmap_id id, int x, int y, int w, int h) { gx_device *tdev; #define mapped_bytes 480 /* must be a multiple of 3 & 4 */ int depth_bytes, source_bits; int block_w, block_h; int xblock, yblock; byte mapped[mapped_bytes]; fit_copy(dev, base, sourcex, raster, id, x, y, w, h); set_dev_target(tdev, dev); /* Device pixels must be an integral number of bytes. */ if (tdev->color_info.depth & 7) return gx_default_copy_color(dev, base, sourcex, raster, id, x, y, w, h); depth_bytes = tdev->color_info.depth >> 3; source_bits = dev->color_info.depth; { int mapped_pixels = mapped_bytes / depth_bytes; if (w > mapped_pixels >> 1) block_w = min(w, mapped_pixels), block_h = 1; else block_w = w, block_h = mapped_pixels / w; } for (yblock = y; yblock < y + h; yblock += block_h) for (xblock = x; xblock < x + w; xblock += block_w) { byte *p = mapped; int xend = min(xblock + block_w, x + w); int yend = min(yblock + block_h, y + h); int xcur, ycur; int code; for (ycur = yblock; ycur < yend; ++ycur) for (xcur = xblock; xcur < xend; ++xcur) { int sbit = (xcur - x + sourcex) * source_bits; uint sbyte = base[(ycur - y) * raster + (sbit >> 3)]; uint spixel = ((sbyte << (sbit & 7)) & 0xff) >> (8 - source_bits); gx_color_index cindex = ((gx_device_X_wrapper *) dev)->color_cache[spixel]; if (cindex == gx_no_color_index) cindex = x_alt_map_color(dev, spixel); switch (depth_bytes) { case 4: *p++ = (byte) (cindex >> 24); case 3: *p++ = (byte) (cindex >> 16); case 2: *p++ = (byte) (cindex >> 8); default /*case 1 */ : *p++ = (byte) cindex; } } code = (*dev_proc(tdev, copy_color)) (tdev, mapped, 0, (xend - xblock) * depth_bytes, gx_no_bitmap_id, xblock, yblock, xend - xblock, yend - yblock); if (code < 0) return code; } return 0; } private int x_forward_copy_color(gx_device * dev, const byte * base, int sourcex, int raster, gx_bitmap_id id, int x, int y, int w, int h) { gx_device *tdev; set_dev_target(tdev, dev); return (*dev_proc(tdev, copy_color)) (tdev, base, sourcex, raster, id, x, y, w, h); } private int x_forward_get_bits(gx_device * dev, int y, byte * str, byte ** actual_data) { gx_device *tdev; set_dev_target(tdev, dev); return (*dev_proc(tdev, get_bits)) (tdev, y, str, actual_data); } private int x_wrap_get_bits(gx_device * dev, int y, byte * str, byte ** actual_data) { int depth = dev->color_info.depth; gx_device *tdev; int width; int sdepth; byte smask; uint dsize; gs_memory_t *mem = dev->memory; byte *row; byte *base; int code; gx_color_index pixel_in = gx_no_color_index; /* * The following initialization is unnecessary: since no pixel has a * value of gx_no_color_index, the test pixel != pixel_in will always * succeed the first time through the loop below, so pixel_out will * always be set before it is used. We initialize pixel_out solely to * suppress bogus warning messages from certain compilers. */ gx_color_index pixel_out = 0; int xi; int sbit; DECLARE_LINE_ACCUM(str, depth, 0); set_dev_target(tdev, dev); width = tdev->width; sdepth = tdev->color_info.depth; smask = (sdepth <= 8 ? (1 << sdepth) - 1 : 0xff); dsize = (width * sdepth + 7) / 8; row = gs_alloc_bytes(mem, dsize, "x_wrap_get_bits"); if (row == 0) return_error(gs_error_VMerror); code = (*dev_proc(tdev, get_bits)) (tdev, y, row, &base); if (code < 0) goto gx; for (sbit = 0, xi = 0; xi < width; sbit += sdepth, ++xi) { const byte *sptr = base + (sbit >> 3); gx_color_index pixel; gx_color_value rgb[3]; int i; if (sdepth <= 8) pixel = (*sptr >> (8 - sdepth - (sbit & 7))) & smask; else { pixel = 0; for (i = 0; i < sdepth; i += 8, ++sptr) pixel = (pixel << 8) + *sptr; } if (pixel != pixel_in) { (*dev_proc(tdev, map_color_rgb))(tdev, pixel, rgb); pixel_in = pixel; if (dev->color_info.num_components <= 3) pixel_out = (*dev_proc(dev, map_rgb_color)) (dev, rgb[0], rgb[1], rgb[2]); else { /* Convert RGB to CMYK. */ gx_color_value c = gx_max_color_value - rgb[0]; gx_color_value m = gx_max_color_value - rgb[1]; gx_color_value y = gx_max_color_value - rgb[2]; gx_color_value k = (c < m ? min(c, y) : min(m, y)); pixel_out = (*dev_proc(dev, map_cmyk_color)) (dev, c - k, m - k, y - k, k); } } LINE_ACCUM(pixel_out, depth); } LINE_ACCUM_STORE(depth); gx:gs_free_object(mem, row, "x_wrap_get_bits"); *actual_data = str; return code; } private int x_wrap_get_params(gx_device * dev, gs_param_list * plist) { gx_device *tdev; /* We assume that a get_params call has no side effects.... */ gx_device_X save_dev; int ecode; set_dev_target(tdev, dev); save_dev = *(gx_device_X *) tdev; if (tdev->is_open) tdev->color_info = dev->color_info; tdev->dname = dev->dname; ecode = (*dev_proc(tdev, get_params)) (tdev, plist); *(gx_device_X *) tdev = save_dev; return ecode; } private int x_wrap_put_params(gx_device * dev, gs_param_list * plist) { gx_device *tdev; gx_device_color_info cinfo; const char *dname; int rcode, code; set_dev_target(tdev, dev); /* * put_params will choke if we simply feed it the output of * get_params; we have to substitute color_info the same way. */ cinfo = tdev->color_info; dname = tdev->dname; tdev->color_info = dev->color_info; tdev->dname = dev->dname; rcode = (*dev_proc(tdev, put_params)) (tdev, plist); tdev->color_info = cinfo; tdev->dname = dname; if (rcode < 0) return rcode; code = get_target_info(dev); return (code < 0 ? code : rcode); } /* Internal procedures */ /* Get the target, creating it if necessary. */ private int get_dev_target(gx_device ** ptdev, gx_device * dev) { gx_device *tdev = ((gx_device_forward *) dev)->target; if (tdev == 0) { /* Create an X device instance. */ int code = gs_copydevice(&tdev, (const gx_device *)&gs_x11_device, dev->memory); if (code < 0) return 0; gx_device_fill_in_procs(tdev); gx_device_set_target((gx_device_forward *)dev, tdev); x_clear_color_cache(dev); } *ptdev = tdev; return 0; } /* Copy parameters back from the target. */ private int get_target_info(gx_device * dev) { gx_device *tdev; set_dev_target(tdev, dev); #define copy(m) dev->m = tdev->m; #define copy2(m) copy(m[0]); copy(m[1]) #define copy4(m) copy2(m); copy(m[2]); copy(m[3]) copy(width); copy(height); copy2(MediaSize); copy4(ImagingBBox); copy(ImagingBBox_set); copy2(HWResolution); copy2(MarginsHWResolution); copy2(Margins); copy4(HWMargins); if (dev->color_info.num_components == 3) { /* Leave the anti-aliasing information alone. */ gx_device_anti_alias_info aa; aa = dev->color_info.anti_alias; copy(color_info); dev->color_info.anti_alias = aa; } #undef copy4 #undef copy2 #undef copy x_clear_color_cache(dev); return 0; } /* Map a fake CMYK or black/white color to a real X color if necessary. */ private gx_color_index x_alt_map_color(gx_device * dev, gx_color_index color) { gx_device_X_wrapper *xdev = (gx_device_X_wrapper *) dev; gx_device *tdev; gx_color_value rgb[3]; gx_color_index cindex; int result; if (color == gx_no_color_index) return color; if (color < 16) { cindex = ((gx_device_X_wrapper *) dev)->color_cache[color]; if (cindex != gx_no_color_index) return cindex; } set_dev_target(tdev, dev); result = xdev->alt_map_color(dev, color, rgb); if (result >= 0) cindex = result; else cindex = dev_proc(tdev, map_rgb_color)(tdev, rgb[0], rgb[1], rgb[2]); if (color < 16) ((gx_device_X_wrapper *) dev)->color_cache[color] = cindex; return cindex; } /* ---------------- CMYK procedures ---------------- */ /* Device procedures */ private dev_proc_open_device(x_cmyk_open); private dev_proc_put_params(x_cmyk_put_params); private dev_proc_map_cmyk_color(x_cmyk_map_cmyk_color); /* Extended device procedures */ private dev_proc_map_color_rgb(x_cmyk_alt_map_color); /* The device descriptor */ private const gx_device_procs x_cmyk_procs = { x_cmyk_open, gx_forward_get_initial_matrix, x_forward_sync_output, x_forward_output_page, x_wrap_close, NULL, /* map_rgb_color */ x_wrap_map_color_rgb, x_wrap_fill_rectangle, gx_default_tile_rectangle, x_wrap_copy_mono, x_wrap_copy_color, gx_default_draw_line, x_wrap_get_bits, x_wrap_get_params, x_cmyk_put_params, x_cmyk_map_cmyk_color, gx_forward_get_xfont_procs, gx_forward_get_xfont_device, NULL, /* map_rgb_alpha_color */ gx_forward_get_page_device, gx_forward_get_alpha_bits, NULL /* copy_alpha */ }; /* The instances are public. */ const gx_device_X_wrapper gs_x11cmyk_device = { std_device_dci_type_body(gx_device_X_wrapper, &x_cmyk_procs, "x11cmyk", &st_device_X_wrapper, FAKE_RES * 85 / 10, FAKE_RES * 11, /* x and y extent (nominal) */ FAKE_RES, FAKE_RES, /* x and y density (nominal) */ 4, 4, 1, 1, 2, 2), X_WRAPPER_DATA(x_cmyk_alt_map_color) }; const gx_device_X_wrapper gs_x11cmyk2_device = { std_device_dci_type_body(gx_device_X_wrapper, &x_cmyk_procs, "x11cmyk2", &st_device_X_wrapper, FAKE_RES * 85 / 10, FAKE_RES * 11, /* x and y extent (nominal) */ FAKE_RES, FAKE_RES, /* x and y density (nominal) */ 4, 8, 3, 3, 4, 4), X_WRAPPER_DATA(x_cmyk_alt_map_color) }; const gx_device_X_wrapper gs_x11cmyk4_device = { std_device_dci_type_body(gx_device_X_wrapper, &x_cmyk_procs, "x11cmyk4", &st_device_X_wrapper, FAKE_RES * 85 / 10, FAKE_RES * 11, /* x and y extent (nominal) */ FAKE_RES, FAKE_RES, /* x and y density (nominal) */ 4, 16, 15, 15, 16, 16), X_WRAPPER_DATA(x_cmyk_alt_map_color) }; const gx_device_X_wrapper gs_x11cmyk8_device = { std_device_dci_type_body(gx_device_X_wrapper, &x_cmyk_procs, "x11cmyk8", &st_device_X_wrapper, FAKE_RES * 85 / 10, FAKE_RES * 11, /* x and y extent (nominal) */ FAKE_RES, FAKE_RES, /* x and y density (nominal) */ 4, 32, 255, 255, 256, 256), X_WRAPPER_DATA(x_cmyk_alt_map_color) }; /* Map a fake color to RGB. */ private int x_cmyk_alt_map_color(gx_device * dev, gx_color_index color, gx_color_value rgb[3]) { int shift = dev->color_info.depth >> 2; int mask = (1 << shift) - 1; /* The following division is guaranteed exact. */ gx_color_value scale = gx_max_color_value / mask; int cw = ~color & mask; int cb = cw - ((color >> shift) & mask); int cg = cw - ((color >> (shift * 2)) & mask); int cr = cw - ((color >> (shift * 3)) & mask); rgb[0] = max(cr, 0) * scale; rgb[1] = max(cg, 0) * scale; rgb[2] = max(cb, 0) * scale; return -1; } /* Set color mapping procedures */ private void x_cmyk_set_procs(gx_device *dev) { if (dev->color_info.depth == 4) { set_dev_proc(dev, map_cmyk_color, cmyk_1bit_map_cmyk_color); } else { set_dev_proc(dev, map_cmyk_color, x_cmyk_map_cmyk_color); } } /* Device procedures */ private int x_cmyk_open(gx_device *dev) { int code = x_wrap_open(dev); if (code >= 0) x_cmyk_set_procs(dev); return code; } private int x_cmyk_put_params(gx_device * dev, gs_param_list * plist) { int code = x_wrap_put_params(dev, plist); if (code >= 0) x_cmyk_set_procs(dev); return code; } private gx_color_index x_cmyk_map_cmyk_color(gx_device * dev, gx_color_value c, gx_color_value m, gx_color_value y, gx_color_value k) { int shift = dev->color_info.depth >> 2; gx_color_index pixel = c >> (gx_color_value_bits - shift); pixel = (pixel << shift) | (m >> (gx_color_value_bits - shift)); pixel = (pixel << shift) | (y >> (gx_color_value_bits - shift)); return (pixel << shift) | (k >> (gx_color_value_bits - shift)); } /* ---------------- Black-and-white procedures ---------------- */ /* Extended device procedures */ private dev_proc_map_color_rgb(x_mono_alt_map_color); /* The device descriptor */ private const gx_device_procs x_mono_procs = { x_wrap_open, gx_forward_get_initial_matrix, x_forward_sync_output, x_forward_output_page, x_wrap_close, gx_default_b_w_map_rgb_color, x_wrap_map_color_rgb, x_wrap_fill_rectangle, gx_default_tile_rectangle, x_wrap_copy_mono, gx_default_copy_color, /* this is fast for the 1-bit case */ gx_default_draw_line, x_wrap_get_bits, x_wrap_get_params, x_wrap_put_params, gx_default_map_cmyk_color, gx_forward_get_xfont_procs, gx_forward_get_xfont_device, NULL, /* map_rgb_alpha_color */ gx_forward_get_page_device, gx_forward_get_alpha_bits, NULL /* copy_alpha */ }; /* The instance is public. */ const gx_device_X_wrapper gs_x11mono_device = { std_device_dci_type_body(gx_device_X_wrapper, &x_mono_procs, "x11mono", &st_device_X_wrapper, FAKE_RES * 85 / 10, FAKE_RES * 11, /* x and y extent (nominal) */ FAKE_RES, FAKE_RES, /* x and y density (nominal) */ 1, 1, 1, 0, 2, 0), X_WRAPPER_DATA(x_mono_alt_map_color) }; /* Map a fake color to RGB. */ private int x_mono_alt_map_color(gx_device * dev, gx_color_index color, gx_color_value rgb[3]) { rgb[0] = rgb[1] = rgb[2] = (color ? 0 : gx_max_color_value); return -1; } /* ---------------- 2- and 4-bit gray-scale procedures ---------------- */ /* Extended device procedures */ private dev_proc_map_color_rgb(x_gray_alt_map_color); /* The device descriptor */ private const gx_device_procs x_gray_procs = { x_wrap_open, gx_forward_get_initial_matrix, x_forward_sync_output, x_forward_output_page, x_wrap_close, gx_default_gray_map_rgb_color, x_wrap_map_color_rgb, x_wrap_fill_rectangle, gx_default_tile_rectangle, x_wrap_copy_mono, x_wrap_copy_color, gx_default_draw_line, x_wrap_get_bits, x_wrap_get_params, x_wrap_put_params, gx_default_map_cmyk_color, gx_forward_get_xfont_procs, gx_forward_get_xfont_device, NULL, /* map_rgb_alpha_color */ gx_forward_get_page_device, gx_forward_get_alpha_bits, NULL /* copy_alpha */ }; /* The instances are public. */ const gx_device_X_wrapper gs_x11gray2_device = { std_device_dci_type_body(gx_device_X_wrapper, &x_gray_procs, "x11gray2", &st_device_X_wrapper, FAKE_RES * 85 / 10, FAKE_RES * 11, /* x and y extent (nominal) */ FAKE_RES, FAKE_RES, /* x and y density (nominal) */ 1, 2, 3, 0, 4, 0), X_WRAPPER_DATA(x_gray_alt_map_color) }; const gx_device_X_wrapper gs_x11gray4_device = { std_device_dci_type_body(gx_device_X_wrapper, &x_gray_procs, "x11gray4", &st_device_X_wrapper, FAKE_RES * 85 / 10, FAKE_RES * 11, /* x and y extent (nominal) */ FAKE_RES, FAKE_RES, /* x and y density (nominal) */ 1, 4, 15, 0, 16, 0), X_WRAPPER_DATA(x_gray_alt_map_color) }; /* Map a fake color to RGB. */ private int x_gray_alt_map_color(gx_device * dev, gx_color_index color, gx_color_value rgb[3]) { rgb[0] = rgb[1] = rgb[2] = color * gx_max_color_value / dev->color_info.max_gray; return -1; } #ifdef USE_BROKEN_X11ALPHA /* ---------------- Alpha procedures ---------------- */ /* Device procedures */ private dev_proc_map_color_rgb(x_alpha_map_color_rgb); private dev_proc_map_rgb_alpha_color(x_alpha_map_rgb_alpha_color); private dev_proc_copy_alpha(x_alpha_copy_alpha); /* Extended device procedures */ private dev_proc_map_color_rgb(x_alpha_alt_map_color); /* The device descriptor */ private const gx_device_procs x_alpha_procs = { x_wrap_open, gx_forward_get_initial_matrix, x_forward_sync_output, x_forward_output_page, x_wrap_close, gx_forward_map_rgb_color, x_alpha_map_color_rgb, x_wrap_fill_rectangle, gx_default_tile_rectangle, x_wrap_copy_mono, x_forward_copy_color, gx_default_draw_line, x_forward_get_bits, x_wrap_get_params, x_wrap_put_params, gx_forward_map_cmyk_color, gx_forward_get_xfont_procs, gx_forward_get_xfont_device, x_alpha_map_rgb_alpha_color, gx_forward_get_page_device, gx_default_get_alpha_bits, /*gx_default_copy_alpha */ x_alpha_copy_alpha }; /* The instance is public. */ const gx_device_X_wrapper gs_x11alpha_device = { std_device_dci_alpha_type_body(gx_device_X_wrapper, &x_alpha_procs, "x11alpha", &st_device_X_wrapper, FAKE_RES * 85 / 10, FAKE_RES * 11, /* x and y extent (nominal) */ FAKE_RES, FAKE_RES, /* x and y density (nominal) */ 3, 32, 255, 255, 256, 256, 4, 4), X_WRAPPER_DATA(x_alpha_alt_map_color) }; /* Map a fake color to RGB. */ private int x_alpha_alt_map_color(gx_device * dev, gx_color_index color, gx_color_value rgb[3]) { return color & 0xffffff; /* just remove alpha */ } #endif /* Device procedures */ /* We encode a complemented alpha value in the top 8 bits of the */ /* device color. */ private int x_alpha_map_color_rgb(gx_device * dev, gx_color_index color, gx_color_value prgb[3]) { return gx_forward_map_color_rgb(dev, color & 0xffffff, prgb); } private gx_color_index x_alpha_map_rgb_alpha_color(gx_device * dev, gx_color_value r, gx_color_value g, gx_color_value b, gx_color_value alpha) { gx_color_index color = gx_forward_map_rgb_color(dev, r, g, b); byte abyte = alpha >> (gx_color_value_bits - 8); return (abyte == 0 ? (gx_color_index)0xff << 24 : ((gx_color_index) (abyte ^ 0xff) << 24) + color); } #ifdef USE_BROKEN_X11ALPHA private int x_alpha_copy_alpha(gx_device * dev, const unsigned char *base, int sourcex, int raster, gx_bitmap_id id, int x, int y, int w, int h, gx_color_index color, int depth) { gx_device *tdev; int xi, yi; const byte *row = base; gx_color_index base_color = color & 0xffffff; /* We fake alpha by interpreting it as saturation, i.e., */ /* alpha = 0 is white, alpha = 15/15 is the full color. */ gx_color_value rgb[3]; gx_color_index shades[16]; int i; set_dev_target(tdev, dev); for (i = 0; i < 15; ++i) shades[i] = gx_no_color_index; shades[15] = base_color; (*dev_proc(tdev, map_color_rgb)) (tdev, base_color, rgb); /* Do the copy operation pixel-by-pixel. */ /* For the moment, if the base color has alpha in it, we ignore it. */ for (yi = y; yi < y + h; row += raster, ++yi) { int prev_x = x; gx_color_index prev_color = gx_no_color_index; uint prev_alpha = 0x10; /* not a possible value */ for (xi = x; xi < x + w; ++xi) { int sx = sourcex + xi - x; uint alpha2 = row[sx >> 1]; uint alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4); gx_color_index a_color; if (alpha == prev_alpha) continue; prev_alpha = alpha; if (alpha == 0) a_color = gx_no_color_index; else while ((a_color = shades[alpha]) == gx_no_color_index) { /* Map the color now. */ #define make_shade(v, alpha)\ (gx_max_color_value -\ ((gx_max_color_value - (v)) * (alpha) / 15)) gx_color_value r = make_shade(rgb[0], alpha); gx_color_value g = make_shade(rgb[1], alpha); gx_color_value b = make_shade(rgb[2], alpha); #undef make_shade a_color = (*dev_proc(tdev, map_rgb_color)) (tdev, r, g, b); if (a_color != gx_no_color_index) { shades[alpha] = a_color; break; } /* Try a higher saturation. (We know */ /* the fully saturated color exists.) */ alpha += (16 - alpha) >> 1; } if (a_color != prev_color) { if (prev_color != gx_no_color_index) (*dev_proc(tdev, fill_rectangle)) (tdev, prev_x, yi, xi - prev_x, 1, prev_color); prev_x = xi; prev_color = a_color; } } if (prev_color != gx_no_color_index) (*dev_proc(tdev, fill_rectangle)) (tdev, prev_x, yi, x + w - prev_x, 1, prev_color); } return 0; } #endif /* ---------------- Permuted RGB16/32 procedures ---------------- */ /* Device procedures */ private dev_proc_map_rgb_color(x_rg16x_map_rgb_color); private dev_proc_map_rgb_color(x_rg32x_map_rgb_color); /* Extended device procedures */ private dev_proc_map_color_rgb(x_rg16x_alt_map_color); private dev_proc_map_color_rgb(x_rg32x_alt_map_color); /* The device descriptor */ #define RGBX_PROCS(map_rgb_proc)\ x_wrap_open,\ gx_forward_get_initial_matrix,\ x_forward_sync_output,\ x_forward_output_page,\ x_wrap_close,\ map_rgb_proc, /* differs */\ x_wrap_map_color_rgb,\ x_wrap_fill_rectangle,\ gx_default_tile_rectangle,\ x_wrap_copy_mono,\ x_forward_copy_color,\ gx_default_draw_line,\ x_forward_get_bits,\ x_wrap_get_params,\ x_wrap_put_params,\ gx_forward_map_cmyk_color,\ gx_forward_get_xfont_procs,\ gx_forward_get_xfont_device,\ x_alpha_map_rgb_alpha_color,\ gx_forward_get_page_device,\ gx_default_get_alpha_bits,\ gx_default_copy_alpha private const gx_device_procs x_rg16x_procs = { RGBX_PROCS(x_rg16x_map_rgb_color) }; const gx_device_X_wrapper gs_x11rg16x_device = { std_device_dci_type_body(gx_device_X_wrapper, &x_rg16x_procs, "x11rg16x", &st_device_X_wrapper, FAKE_RES * 85 / 10, FAKE_RES * 11, /* x and y extent (nominal) */ FAKE_RES, FAKE_RES, /* x and y density (nominal) */ 3, 16, 31, 31, 32, 32), X_WRAPPER_DATA(x_rg16x_alt_map_color) }; private const gx_device_procs x_rg32x_procs = { RGBX_PROCS(x_rg32x_map_rgb_color) }; const gx_device_X_wrapper gs_x11rg32x_device = { std_device_dci_type_body(gx_device_X_wrapper, &x_rg32x_procs, "x11rg32x", &st_device_X_wrapper, FAKE_RES * 85 / 10, FAKE_RES * 11, /* x and y extent (nominal) */ FAKE_RES, FAKE_RES, /* x and y density (nominal) */ 3, 32, 1023, 1023, 1024, 1024), X_WRAPPER_DATA(x_rg32x_alt_map_color) }; /* Map RGB to a fake color. */ private gx_color_index x_rg16x_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g, gx_color_value b) { /* Permute the colors to G5/B5/R6. */ return (r >> (gx_color_value_bits - 6)) + ((g >> (gx_color_value_bits - 5)) << 11) + ((b >> (gx_color_value_bits - 5)) << 6); } private gx_color_index x_rg32x_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g, gx_color_value b) { /* Permute the colors to G11/B10/R11. */ return (r >> (gx_color_value_bits - 11)) + ((gx_color_index)(g >> (gx_color_value_bits - 11)) << 21) + ((gx_color_index)(b >> (gx_color_value_bits - 10)) << 11); } /* Map a fake color to RGB. */ private int x_rg16x_alt_map_color(gx_device * dev, gx_color_index color, gx_color_value rgb[3]) { rgb[0] = (color & 0x3f) * gx_max_color_value / 0x3f; rgb[1] = ((color >> 11) & 0x1f) * gx_max_color_value / 0x1f; rgb[2] = ((color >> 6) & 0x1f) * gx_max_color_value / 0x1f; return -1; } private int x_rg32x_alt_map_color(gx_device * dev, gx_color_index color, gx_color_value rgb[3]) { rgb[0] = (color & 0x7ff) * gx_max_color_value / 0x7ff; rgb[1] = ((color >> 21) & 0x7ff) * gx_max_color_value / 0x7ff; rgb[2] = ((color >> 11) & 0x3ff) * gx_max_color_value / 0x3ff; return -1; }