home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 February / PCWK0296.iso / sharewar / dos / program / gs300sr1 / gs300sr1.exe / GDEVX.C < prev    next >
C/C++ Source or Header  |  1994-08-01  |  33KB  |  1,022 lines

  1. /* Copyright (C) 1989, 1992, 1993, 1994 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevx.c */
  20. /* X Windows driver for Ghostscript library */
  21. /* The X include files include <sys/types.h>, which, on some machines */
  22. /* at least, define uint, ushort, and ulong, which std.h also defines. */
  23. /* std.h has taken care of this. */
  24. #include "gx.h"            /* for gx_bitmap; includes std.h */
  25. #include "math_.h"
  26. #include "memory_.h"
  27. #include "x_.h"
  28. #include "gserrors.h"
  29. #include "gsparam.h"
  30. #include "gxdevice.h"
  31. #include "gdevx.h"
  32.  
  33. /* Define the maximum size of the temporary pixmap for copy_mono */
  34. /* that we are willing to leave lying around in the server */
  35. /* between uses.  (Assume 32-bit ints here!) */
  36. private int max_temp_pixmap = 20000;
  37.  
  38. /* Forward references */
  39. private int set_tile(P2(gx_device *, const gx_tile_bitmap *));
  40. private void free_cp(P1(gx_device *));
  41. /* Screen updating machinery */
  42. #define update_init(dev)\
  43.   ((gx_device_X *)(dev))->up_area = 0,\
  44.   ((gx_device_X *)(dev))->up_count = 0
  45. #define update_flush(dev)\
  46.   if ( ((gx_device_X *)(dev))->up_area != 0 ) update_do_flush(dev)
  47. private void update_do_flush(P1(gx_device *));
  48. private void x_send_event(P2(gx_device *, Atom));
  49.  
  50. /* Procedures */
  51.  
  52. extern int gdev_x_open(P1(gx_device_X *));
  53. private dev_proc_open_device(x_open);
  54. private dev_proc_get_initial_matrix(x_get_initial_matrix);
  55. private dev_proc_sync_output(x_sync);
  56. private dev_proc_output_page(x_output_page);
  57. private dev_proc_close_device(x_close);
  58. private dev_proc_map_rgb_color(x_map_rgb_color);
  59. private dev_proc_map_color_rgb(x_map_color_rgb);
  60. private dev_proc_fill_rectangle(x_fill_rectangle);
  61. private dev_proc_tile_rectangle(x_tile_rectangle);
  62. private dev_proc_copy_mono(x_copy_mono);
  63. private dev_proc_copy_color(x_copy_color);
  64. private dev_proc_draw_line(x_draw_line);
  65. private dev_proc_put_params(x_put_params);
  66. dev_proc_get_xfont_procs(x_get_xfont_procs);
  67.  
  68. /* The device descriptor */
  69. private gx_device_procs x_procs = {
  70.     x_open,
  71.     x_get_initial_matrix,
  72.     x_sync,
  73.     x_output_page,
  74.     x_close,
  75.     x_map_rgb_color,
  76.     x_map_color_rgb,
  77.     x_fill_rectangle,
  78.     x_tile_rectangle,
  79.     x_copy_mono,
  80.     x_copy_color,
  81.     x_draw_line,
  82.     gx_default_get_bits,
  83.     NULL,            /* get_params */
  84.     x_put_params,
  85.     NULL,
  86.     x_get_xfont_procs
  87. };
  88.  
  89. /* The instance is public. */
  90. gx_device_X gs_x11_device = {
  91.     sizeof(gx_device_X),
  92.     &x_procs,
  93.     "x11",
  94.     (int)(8.5*FAKE_RES),
  95.     (int)(11*FAKE_RES),    /* x and y extent (nominal) */
  96.     FAKE_RES, FAKE_RES,    /* x and y density (nominal) */
  97.     no_margins,
  98.     dci_color(24, 255, 255),
  99.     dev_init_misc,
  100.     { 0 },            /* std_procs */
  101.     { /* image */
  102.       0, 0,            /* width, height */
  103.       0, XYBitmap, NULL,    /* xoffset, format, data */
  104.       LSBFirst, 8,        /* byte-order, bitmap-unit */
  105.       MSBFirst, 8, 1,    /* bitmap-bit-order, bitmap-pad, depth */
  106.       0, 1,            /* bytes_per_line, bits_per_pixel */
  107.       0, 0, 0,        /* red_mask, green_mask, blue_mask */
  108.       NULL,            /* *obdata */
  109.        { NULL,            /* *(*create_image)() */
  110.          NULL,            /* (*destroy_image)() */
  111.          NULL,            /* (*get_pixel)() */
  112.          NULL,            /* (*put_pixel)() */
  113.          NULL,            /* *(*sub_image)() */
  114.          NULL            /* (*add_pixel)() */
  115.        },
  116.     },
  117.     NULL, NULL,        /* dpy, scr */
  118.                 /* (connection not initialized) */
  119.     NULL,            /* vinfo */
  120.     (Colormap)None,        /* cmap */
  121.     (Window)None,        /* win */
  122.     NULL,            /* gc */
  123.     (Pixmap)0,        /* bpixmap */
  124.     0,            /* ghostview */
  125.     (Window)None,        /* mwin */
  126. #if HaveStdCMap
  127.     NULL,            /* std_cmap */
  128. #endif
  129.     identity_matrix_body,    /* initial matrix (filled in) */
  130.     (Atom)0, (Atom)0, (Atom)0,    /* Atoms: NEXT, PAGE, DONE */
  131.      { 0, 0, 0, 0 }, 0, 0,    /* update, up_area, up_count */
  132.     (Pixmap)0,        /* dest */
  133.     0L, ~0L,        /* colors_or, colors_and */
  134.      { /* cp */
  135.        (Pixmap)0,        /* pixmap */
  136.        NULL,        /* gc */
  137.        -1, -1        /* raster, height */
  138.      },
  139.      { /* ht */
  140.        (Pixmap)None,        /* pixmap */
  141.        (Pixmap)None,        /* no_pixmap */
  142.        gx_no_bitmap_id,        /* id */
  143.        0, 0, 0,            /* width, height, raster */
  144.        0, 0                /* fore_c, back_c */
  145.      },
  146.     GXcopy,            /* function */
  147.     FillSolid,        /* fill_style */
  148.     0,            /* font */
  149.     0, 0,            /* back_color, fore_color */
  150.     0, 0,            /* background, foreground */
  151.     NULL,            /* dither_colors */
  152.     0, 0,            /* color_mask, half_dev_color */
  153.     NULL,            /* dynamic_colors */
  154.     0, 0,            /* dynamic_size, dynamic_number */
  155.     0, 0,            /* borderColor, borderWidth */
  156.     NULL,            /* geometry */
  157.     128, 5,            /* maxGrayRamp, maxRGBRamp */
  158.     NULL,            /* palette */
  159.     NULL, NULL, NULL,    /* regularFonts, symbolFonts, dingbatFonts */
  160.     NULL, NULL, NULL,    /* regular_fonts, symbol_fonts, dingbat_fonts */
  161.     1, 1,            /* useXFonts, useFontExtensions */
  162.     1, 0,            /* useScalableFonts, logXFonts */
  163.     0.0, 0.0,        /* xResolution, yResolution */
  164.     1,            /* useBackingPixmap */
  165.     1, 1,            /* useXPutImage, useXSetTile */
  166. };
  167.  
  168. /* If XPutImage doesn't work, do it ourselves. */
  169. private void alt_put_image(P11(gx_device *dev, Display *dpy, Drawable win,
  170.   GC gc, XImage *pi, int sx, int sy, int dx, int dy, unsigned w, unsigned h));
  171. #define put_image(dpy,win,gc,im,sx,sy,x,y,w,h)\
  172.   if ( xdev->useXPutImage) XPutImage(dpy,win,gc,im,sx,sy,x,y,w,h);\
  173.   else alt_put_image(dev,dpy,win,gc,im,sx,sy,x,y,w,h)
  174.  
  175.  
  176. /* Open the device.  Most of the code is in gdevxini.c. */
  177. private int
  178. x_open(gx_device *dev)
  179. {
  180.     gx_device_X *xdev = (gx_device_X *)dev;
  181.     int code = gdev_x_open(xdev);
  182.  
  183.     if (code < 0) return code;
  184.     update_init(dev);
  185.     return 0;
  186. }
  187.  
  188. /* Close the device. */
  189. private int
  190. x_close(gx_device *dev)
  191. {
  192.     gx_device_X *xdev = (gx_device_X *)dev;
  193.  
  194.     if (xdev->ghostview) x_send_event(dev, xdev->DONE);
  195.     if (xdev->vinfo) {
  196.     XFree((char *)xdev->vinfo);
  197.     xdev->vinfo = NULL;
  198.     }
  199.     if (xdev->dither_colors) {
  200.     if (gx_device_has_color(xdev))
  201. #define cube(r) (r*r*r)
  202.         gs_free((char *)xdev->dither_colors, sizeof(x_pixel),
  203.             cube(xdev->color_info.dither_rgb), "gdev_x_rgb_cube");
  204. #undef cube
  205.     else
  206.         gs_free((char *)xdev->dither_colors, sizeof(x_pixel),
  207.             xdev->color_info.dither_gray, "gdev_x_gray_ramp");
  208.     xdev->dither_colors = NULL;
  209.     }
  210.     if (xdev->dynamic_colors) {
  211.     gs_free((char *)xdev->dynamic_colors, sizeof(XColor),
  212.         xdev->dynamic_size, "gdev_x_dynamic_colors");
  213.     xdev->dynamic_colors = NULL;
  214.     }
  215.     while (xdev->regular_fonts) {
  216.     x11fontmap *font = xdev->regular_fonts;
  217.     xdev->regular_fonts = font->next;
  218.     if (font->std_names) XFreeFontNames(font->std_names);
  219.     if (font->iso_names) XFreeFontNames(font->iso_names);
  220.     gs_free(font->x11_name, sizeof(char), strlen(font->x11_name)+1,
  221.         "gdev_x_font_x11name");
  222.     gs_free(font->ps_name, sizeof(char), strlen(font->ps_name)+1,
  223.         "gdev_x_font_psname");
  224.     gs_free((char *)font, sizeof(x11fontmap), 1, "gdev_x_fontmap");
  225.     }
  226.     while (xdev->symbol_fonts) {
  227.     x11fontmap *font = xdev->symbol_fonts;
  228.     xdev->symbol_fonts = font->next;
  229.     if (font->std_names) XFreeFontNames(font->std_names);
  230.     if (font->iso_names) XFreeFontNames(font->iso_names);
  231.     gs_free(font->x11_name, sizeof(char), strlen(font->x11_name)+1,
  232.         "gdev_x_font_x11name");
  233.     gs_free(font->ps_name, sizeof(char), strlen(font->ps_name)+1,
  234.         "gdev_x_font_psname");
  235.     gs_free((char *)font, sizeof(x11fontmap), 1, "gdev_x_fontmap");
  236.     }
  237.     while (xdev->dingbat_fonts) {
  238.     x11fontmap *font = xdev->dingbat_fonts;
  239.     xdev->dingbat_fonts = font->next;
  240.     if (font->std_names) XFreeFontNames(font->std_names);
  241.     if (font->iso_names) XFreeFontNames(font->iso_names);
  242.     gs_free(font->x11_name, sizeof(char), strlen(font->x11_name)+1,
  243.         "gdev_x_font_x11name");
  244.     gs_free(font->ps_name, sizeof(char), strlen(font->ps_name)+1,
  245.         "gdev_x_font_psname");
  246.     gs_free((char *)font, sizeof(x11fontmap), 1, "gdev_x_fontmap");
  247.     }
  248.     XCloseDisplay(xdev->dpy);
  249.     return 0;
  250. }
  251.  
  252. /* Map a color.  The "device colors" are just r,g,b packed together. */
  253. private gx_color_index
  254. x_map_rgb_color(register gx_device *dev,
  255.         gx_color_value r, gx_color_value g, gx_color_value b)
  256. {
  257.     gx_device_X *xdev = (gx_device_X *)dev;
  258.     unsigned short dr = r & xdev->color_mask;    /* Nearest color that */
  259.     unsigned short dg = g & xdev->color_mask;    /* the X device can   */
  260.     unsigned short db = b & xdev->color_mask;    /* represent          */
  261.  
  262.     /* foreground and background get special treatment */
  263.     /* They maybe mapped to other colors. */
  264. #define cv_max (gx_max_color_value & xdev->color_mask)
  265.     if (dr == 0 && dg == 0 && db == 0) {
  266.     return xdev->foreground;
  267.     }
  268.     if (dr == cv_max && dg == cv_max && db == cv_max) {
  269.     return xdev->background;
  270.     }
  271. #define cv_denom (gx_max_color_value + 1)
  272. #if HaveStdCMap
  273.     /* check the standard colormap first */
  274.     if (xdev->std_cmap) {
  275.     XStandardColormap *cmap = xdev->std_cmap;
  276.  
  277.     if (gx_device_has_color(xdev)) {
  278.         unsigned short cr, cg, cb;        /* rgb cube indices */
  279.         unsigned short cvr, cvg, cvb;    /* color value on cube */
  280.  
  281.         cr = r * (cmap->red_max + 1) / cv_denom;
  282.         cg = g * (cmap->green_max + 1) / cv_denom;
  283.         cb = b * (cmap->blue_max + 1) / cv_denom;
  284.         cvr = (0xffff * cr / cmap->red_max);
  285.         cvg = (0xffff * cg / cmap->green_max);
  286.         cvb = (0xffff * cb / cmap->blue_max);
  287.         if (abs((int)r - (int)cvr) < xdev->half_dev_color &&
  288.         abs((int)g - (int)cvg) < xdev->half_dev_color &&
  289.         abs((int)b - (int)cvb) < xdev->half_dev_color)
  290.         return cr * cmap->red_mult + cg * cmap->green_mult +
  291.                cb * cmap->blue_mult + cmap->base_pixel;
  292.     } else {
  293.         unsigned short cr;
  294.         unsigned short cvr;
  295.  
  296.         cr = r * (xdev->color_info.max_gray + 1) / cv_denom;
  297.         cvr = (0xffff * cr / cmap->red_max);
  298.         if (abs((int)r - (int)cvr) < xdev->half_dev_color)
  299.         return cr * cmap->red_mult + cmap->base_pixel;
  300.     }
  301.     } else
  302. #endif
  303.     /* If there is no standard colormap, check the dither cube/ramp */
  304.     if (xdev->dither_colors) {
  305.     if (gx_device_has_color(xdev)) {
  306.         unsigned short cr, cg, cb;        /* rgb cube indices */
  307.         unsigned short cvr, cvg, cvb;    /* color value on cube */
  308.         int dither_rgb = xdev->color_info.dither_rgb;
  309.         int max_rgb = dither_rgb - 1;
  310.  
  311.         cr = (r * max_rgb + gx_max_color_value / 2) / gx_max_color_value;
  312.         cg = (g * max_rgb + gx_max_color_value / 2) / gx_max_color_value;
  313.         cb = (b * max_rgb + gx_max_color_value / 2) / gx_max_color_value;
  314.         cvr = gx_max_color_value * cr / max_rgb;
  315.         cvg = gx_max_color_value * cg / max_rgb;
  316.         cvb = gx_max_color_value * cb / max_rgb;
  317.         if (abs((int)r - (int)cvr) < xdev->half_dev_color &&
  318.         abs((int)g - (int)cvg) < xdev->half_dev_color &&
  319.         abs((int)b - (int)cvb) < xdev->half_dev_color) {
  320.         return xdev->dither_colors[cube_index(cr, cg, cb)];
  321.         }
  322.     } else {
  323.         unsigned short cr;
  324.         unsigned short cvr;
  325.  
  326. #define max_gray (xdev->color_info.dither_gray - 1)
  327.         cr = r * (xdev->color_info.dither_gray) / gx_max_color_value;
  328.         cvr = (gx_max_color_value * cr / max_gray) & xdev->color_mask;
  329.         if (abs((int)r - (int)cvr) < xdev->half_dev_color)
  330.         return xdev->dither_colors[cr];
  331. #undef max_gray
  332.     }
  333.     }
  334. #undef cv_denom
  335.     /* Finally look through the list of dynamic colors */
  336.  
  337.     if (xdev->dynamic_colors) {
  338.     int i;
  339.     XColor *xcp = xdev->dynamic_colors + (xdev->dynamic_number - 1);
  340.     XColor xc;
  341.  
  342.     for (i = xdev->dynamic_number; --i >= 0; xcp--) {
  343.         if (xcp->red == dr && xcp->green == dg && xcp->blue == db) {
  344.         return xcp->pixel;
  345.         }
  346.     }
  347.  
  348.     /* If we've filled up the dynamic color list, */
  349.     /* don't bother asking the server. */
  350.     if ( xdev->dynamic_number >= xdev->dynamic_size )
  351.       return gx_no_color_index;
  352.  
  353.     /* If not in our list of dynamic colors, ask the X server and */
  354.     /* add an entry if there is room. */
  355.     xc.red = dr;
  356.     xc.green = dg;
  357.     xc.blue = db;
  358.  
  359.     if (XAllocColor(xdev->dpy, xdev->cmap, &xc)) {
  360.         xdev->dynamic_colors[xdev->dynamic_number] = xc;
  361.         xdev->dynamic_number++;
  362.         return xc.pixel;
  363.     }
  364.     }
  365.     return gx_no_color_index;
  366. }
  367.  
  368.  
  369. /* Map a "device color" back to r-g-b. */
  370. /* This doesn't happed often, so we just ask the display */
  371. /* Foreground and background be mapped to other colors, so */
  372. /* they are handled specially. */
  373. private int
  374. x_map_color_rgb(register gx_device *dev, gx_color_index color,
  375.         gx_color_value prgb[3])
  376. {
  377.     gx_device_X *xdev = (gx_device_X *)dev;
  378.  
  379.     if (color == xdev->foreground)
  380.     prgb[0] = prgb[1] = prgb[2] = 0;
  381.     else if (color == xdev->background)
  382.     prgb[0] = prgb[1] = prgb[2] = gx_max_color_value;
  383.     else {
  384.     XColor xc;
  385.  
  386.     xc.pixel = color;
  387.     XQueryColor(xdev->dpy, xdev->cmap, &xc);
  388.     prgb[0] = xc.red;
  389.     prgb[1] = xc.green;
  390.     prgb[2] = xc.blue;
  391.     }
  392.     return 0;
  393. }
  394.  
  395. /* Get initial matrix for X device */
  396. private void
  397. x_get_initial_matrix(register gx_device *dev, register gs_matrix *pmat)
  398. {
  399.     gx_device_X *xdev = (gx_device_X *)dev;
  400.  
  401.     pmat->xx = xdev->initial_matrix.xx;
  402.     pmat->xy = xdev->initial_matrix.xy;
  403.     pmat->yx = xdev->initial_matrix.yx;
  404.     pmat->yy = xdev->initial_matrix.yy;
  405.     pmat->tx = xdev->initial_matrix.tx;
  406.     pmat->ty = xdev->initial_matrix.ty;
  407. }
  408.  
  409. /* Synchronize the display with the commands already given */
  410. private int
  411. x_sync(register gx_device *dev)
  412. {
  413.     gx_device_X *xdev = (gx_device_X *)dev;
  414.  
  415.     update_flush(dev);
  416.     XSync(xdev->dpy, 0);
  417.     return 0;
  418. }
  419.  
  420. /* Send event to ghostview process */
  421. private void
  422. x_send_event(gx_device *dev, Atom msg)
  423. {
  424.     gx_device_X *xdev = (gx_device_X *)dev;
  425.     XEvent event;
  426.  
  427.     event.xclient.type = ClientMessage;
  428.     event.xclient.display = xdev->dpy;
  429.     event.xclient.window = xdev->win;
  430.     event.xclient.message_type = msg;
  431.     event.xclient.format = 32;
  432.     event.xclient.data.l[0] = xdev->mwin;
  433.     event.xclient.data.l[1] = xdev->dest;
  434.     XSendEvent(xdev->dpy, xdev->win, False, 0, &event);
  435. }
  436.  
  437. /* Output "page" */
  438. private int
  439. x_output_page(gx_device *dev, int num_copies, int flush)
  440. {
  441.     gx_device_X *xdev = (gx_device_X *)dev;
  442.  
  443.     x_sync(dev);
  444.  
  445.     /* Send ghostview a "page" client event */
  446.     /* Wait for a "next" client event */
  447.     if (xdev->ghostview) {
  448.     XEvent event;
  449.  
  450.     x_send_event(dev, xdev->PAGE);
  451.     XNextEvent(xdev->dpy, &event);
  452.     while (event.type != ClientMessage ||
  453.            event.xclient.message_type != xdev->NEXT) {
  454.         XNextEvent(xdev->dpy, &event);
  455.     }
  456.     }
  457.     return 0;
  458. }
  459.  
  460. /* Fill a rectangle with a color. */
  461. private int
  462. x_fill_rectangle(register gx_device *dev,
  463.          int x, int y, int w, int h, gx_color_index color)
  464. {
  465.     gx_device_X *xdev = (gx_device_X *)dev;
  466.  
  467.     fit_fill(dev, x, y, w, h);
  468.     set_fill_style(FillSolid);
  469.     set_fore_color(color);
  470.     set_function(GXcopy);
  471.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  472.     /* If we are filling the entire screen, reset */
  473.     /* colors_or and colors_and.  It's wasteful to do this */
  474.     /* on every operation, but there's no separate driver routine */
  475.     /* for erasepage (yet). */
  476.     if (x == 0 && y == 0 && w == xdev->width && h == xdev->height) {
  477.     if (color == xdev->foreground || color == xdev->background) {
  478.         int i;
  479.         XErrorHandler oldhandler = XSetErrorHandler(x_catch_free_colors);
  480.         for (i = 0; i < xdev->dynamic_number; i++) {
  481.         XFreeColors(xdev->dpy, xdev->cmap,
  482.                 &xdev->dynamic_colors[i].pixel, 1, 0);
  483.         }
  484.         XSync(xdev->dpy, False);    /* Force any errors */
  485.         oldhandler = XSetErrorHandler(oldhandler);
  486.         xdev->dynamic_number = 0;
  487.     }
  488.     xdev->colors_or = xdev->colors_and = color;
  489.     }
  490.     if (xdev->bpixmap != (Pixmap) 0) {
  491.     x_update_add(dev, x, y, w, h);
  492.     }
  493. #ifdef DEBUG
  494.     if (gs_debug['F'])
  495.     dprintf5("[F] fill (%d,%d):(%d,%d) %ld\n",
  496.          x, y, w, h, (long)color);
  497. #endif
  498.     return 0;
  499. }
  500.  
  501. /* Tile a rectangle. */
  502. private int
  503. x_tile_rectangle(register gx_device *dev, const gx_tile_bitmap *tile,
  504.            int x, int y, int w, int h,
  505.          gx_color_index zero, gx_color_index one,
  506.          int px, int py)
  507. {
  508.     gx_device_X *xdev = (gx_device_X *)dev;
  509.  
  510.     fit_fill(dev, x, y, w, h);
  511.  
  512.     /* Give up if one color is transparent, or if the tile is colored. */
  513.     /* We should implement the latter someday, since X can handle it. */
  514.  
  515.     if (one == gx_no_color_index || zero == gx_no_color_index)
  516.       return gx_default_tile_rectangle(dev, tile, x, y, w, h,
  517.                        zero, one, px, py);
  518.  
  519.     /* For the moment, give up if the phase is non-zero. */
  520.     if (px | py)
  521.       return gx_default_tile_rectangle(dev, tile, x, y, w, h,
  522.                        zero, one, px, py);
  523.  
  524.     /*
  525.      * Remember, an X tile is already filled with particular
  526.      * pixel values (i.e., colors).  Therefore if we are changing
  527.      * fore/background color, we must invalidate the tile (using
  528.      * the same technique as in set_tile).  This problem only
  529.      * bites when using grayscale -- you may want to change
  530.      * fg/bg but use the same halftone screen.
  531.      */
  532.     if ((zero != xdev->ht.back_c) || (one != xdev->ht.fore_c))
  533.     xdev->ht.id = ~tile->id;    /* force reload */
  534.  
  535.     set_back_color(zero);
  536.     set_fore_color(one);
  537.     if (!set_tile(dev, tile))
  538.       {    /* Bad news.  Fall back to the default algorithm. */
  539.     return gx_default_tile_rectangle(dev, tile, x, y, w, h,
  540.                      zero, one, px, py);
  541.       }
  542.     /* Use the tile to fill the rectangle */
  543.     set_fill_style(FillTiled);
  544.     set_function(GXcopy);
  545.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  546.     if (xdev->bpixmap != (Pixmap) 0) {
  547.       x_update_add(dev, x, y, w, h);
  548.     }
  549. #ifdef DEBUG
  550.     if (gs_debug['F'])
  551.     dprintf6("[F] tile (%d,%d):(%d,%d) %ld,%ld\n",
  552.          x, y, w, h, (long)zero, (long)one);
  553. #endif
  554.     return 0;
  555. }
  556.  
  557. /* Set up with a specified tile. */
  558. /* Return false if we can't do it for some reason. */
  559. private int
  560. set_tile(register gx_device *dev, register const gx_tile_bitmap *tile)
  561. {
  562.     gx_device_X *xdev = (gx_device_X *)dev;
  563.  
  564. #ifdef DEBUG
  565.     if (gs_debug['T'])
  566.     return 0;
  567. #endif
  568.     if (tile->id == xdev->ht.id && tile->id != gx_no_bitmap_id)
  569.     return xdev->useXSetTile;
  570.     /* Set up the tile Pixmap */
  571.     if (tile->size.x != xdev->ht.width ||
  572.     tile->size.y != xdev->ht.height ||
  573.     xdev->ht.pixmap == (Pixmap) 0) {
  574.     if (xdev->ht.pixmap != (Pixmap) 0)
  575.         XFreePixmap(xdev->dpy, xdev->ht.pixmap);
  576.     xdev->ht.pixmap = XCreatePixmap(xdev->dpy, xdev->win,
  577.                     tile->size.x, tile->size.y,
  578.                     xdev->vinfo->depth);
  579.     if (xdev->ht.pixmap == (Pixmap) 0)
  580.         return 0;
  581.     xdev->ht.width = tile->size.x, xdev->ht.height = tile->size.y;
  582.     xdev->ht.raster = tile->raster;
  583.     }
  584.     xdev->ht.fore_c = xdev->fore_color;
  585.     xdev->ht.back_c = xdev->back_color;
  586.     /* Copy the tile into the Pixmap */
  587.     xdev->image.data = (char *)tile->data;
  588.     xdev->image.width = tile->size.x;
  589.     xdev->image.height = tile->size.y;
  590.     xdev->image.bytes_per_line = tile->raster;
  591.     xdev->image.format = XYBitmap;
  592.     set_fill_style(FillSolid);
  593. #ifdef DEBUG
  594.     if (gs_debug['H']) {
  595.     int i;
  596.  
  597.     dprintf4("[H] 0x%lx: width=%d height=%d raster=%d\n",
  598.          (ulong)tile->data, tile->size.x, tile->size.y, tile->raster);
  599.     for (i = 0; i < tile->raster * tile->size.y; i++)
  600.         dprintf1(" %02x", tile->data[i]);
  601.     dputc('\n');
  602.     }
  603. #endif
  604.     XSetTile(xdev->dpy, xdev->gc, xdev->ht.no_pixmap);    /* *** X bug *** */
  605.     set_function(GXcopy);
  606.     put_image(xdev->dpy, xdev->ht.pixmap, xdev->gc, &xdev->image,
  607.           0, 0, 0, 0, tile->size.x, tile->size.y);
  608.     XSetTile(xdev->dpy, xdev->gc, xdev->ht.pixmap);
  609.     xdev->ht.id = tile->id;
  610.     return xdev->useXSetTile;
  611. }
  612.  
  613. /* Copy a monochrome bitmap. */
  614. private int
  615. x_copy_mono(register gx_device *dev,
  616.         const byte *base, int sourcex, int raster, gx_bitmap_id id,
  617.         int x, int y, int w, int h,
  618.         gx_color_index zero, gx_color_index one)
  619. /*
  620.  * X doesn't directly support the simple operation of writing a color
  621.  * through a mask specified by an image.  The plot is the following:
  622.  *  If neither color is gx_no_color_index ("transparent"),
  623.  *    use XPutImage with the "copy" function as usual.
  624.  *  If the color either bitwise-includes or is bitwise-included-in
  625.  *    every color written to date
  626.  *    (a special optimization for writing black/white on color displays),
  627.  *    use XPutImage with an appropriate Boolean function.
  628.  *  Otherwise, do the following complicated stuff:
  629.  *    Create pixmap of depth 1 if necessary.
  630.  *    If foreground color is "transparent" then
  631.  *      invert the raster data.
  632.  *    Use XPutImage to copy the raster image to the newly
  633.  *      created Pixmap.
  634.  *    Install the Pixmap as the clip_mask in the X GC and
  635.  *      tweak the clip origin.
  636.  *    Do an XFillRectangle, fill style=solid, specifying a
  637.  *      rectangle the same size as the original raster data.
  638.  *    De-install the clip_mask.
  639.  */
  640. {
  641.     gx_device_X *xdev = (gx_device_X *)dev;
  642.     int function = GXcopy;
  643.  
  644.     x_pixel
  645.     bc = zero,
  646.     fc = one;
  647.  
  648.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  649.  
  650.     xdev->image.width = raster << 3;
  651.     xdev->image.height = h;
  652.     xdev->image.data = (char *)base;
  653.     xdev->image.bytes_per_line = raster;
  654.     set_fill_style(FillSolid);
  655.  
  656.     /* Check for null, easy 1-color, hard 1-color, and 2-color cases. */
  657.     if (zero != gx_no_color_index) {
  658.     if (one != gx_no_color_index) {
  659.         /* 2-color case. */
  660.         /* Simply replace existing bits with what's in the image. */
  661.     } else if (!(~xdev->colors_and & bc)) {
  662.         function = GXand;
  663.         fc = ~(x_pixel) 0;
  664.     } else if (!(~bc & xdev->colors_or)) {
  665.         function = GXor;
  666.         fc = 0;
  667.     } else {
  668.         goto hard;
  669.     }
  670.     } else {
  671.     if (one == gx_no_color_index) {    /* no-op */
  672.         return 0;
  673.     } else if (!(~xdev->colors_and & fc)) {
  674.         function = GXand;
  675.         bc = ~(x_pixel) 0;
  676.     } else if (!(~fc & xdev->colors_or)) {
  677.         function = GXor;
  678.         bc = 0;
  679.     } else {
  680.         goto hard;
  681.     }
  682.     }
  683.     xdev->image.format = XYBitmap;
  684.     set_function(function);
  685.     if (bc != xdev->back_color) {
  686.     XSetBackground(xdev->dpy, xdev->gc, (xdev->back_color = bc));
  687.     }
  688.     if (fc != xdev->fore_color) {
  689.     XSetForeground(xdev->dpy, xdev->gc, (xdev->fore_color = fc));
  690.     }
  691.     if (zero != gx_no_color_index)
  692.     note_color(zero);
  693.     if (one != gx_no_color_index)
  694.     note_color(one);
  695.     put_image(xdev->dpy, xdev->dest, xdev->gc, &xdev->image,
  696.           sourcex, 0, x, y, w, h);
  697.  
  698.     goto out;
  699.  
  700. hard:    /* Handle the hard 1-color case. */
  701.     if (raster > xdev->cp.raster || h > xdev->cp.height) {
  702.     /* Must allocate a new pixmap and GC. */
  703.     /* Release the old ones first. */
  704.     free_cp(dev);
  705.  
  706.     /* Create the clipping pixmap, depth must be 1. */
  707.     xdev->cp.pixmap =
  708.         XCreatePixmap(xdev->dpy, xdev->win, raster << 3, h, 1);
  709.     if (xdev->cp.pixmap == (Pixmap) 0) {
  710.         lprintf("x_copy_mono: can't allocate pixmap\n");
  711.         exit(1);
  712.     }
  713.     xdev->cp.gc = XCreateGC(xdev->dpy, xdev->cp.pixmap, 0, 0);
  714.     if (xdev->cp.gc == (GC) 0) {
  715.         lprintf("x_copy_mono: can't allocate GC\n");
  716.         exit(1);
  717.     }
  718.     xdev->cp.raster = raster;
  719.     xdev->cp.height = h;
  720.     }
  721.     /* Initialize static mask image params */
  722.     xdev->image.format = XYBitmap;
  723.     set_function(GXcopy);
  724.  
  725.     /* Select polarity based on fg/bg transparency. */
  726.     if (one == gx_no_color_index) {    /* invert */
  727.     XSetBackground(xdev->dpy, xdev->cp.gc, (x_pixel) 1);
  728.     XSetForeground(xdev->dpy, xdev->cp.gc, (x_pixel) 0);
  729.     set_fore_color(zero);
  730.     } else {
  731.     XSetBackground(xdev->dpy, xdev->cp.gc, (x_pixel) 0);
  732.     XSetForeground(xdev->dpy, xdev->cp.gc, (x_pixel) 1);
  733.     set_fore_color(one);
  734.     }
  735.     put_image(xdev->dpy, xdev->cp.pixmap, xdev->cp.gc,
  736.           &xdev->image, sourcex, 0, 0, 0, w, h);
  737.  
  738.     /* Install as clipmask. */
  739.     XSetClipMask(xdev->dpy, xdev->gc, xdev->cp.pixmap);
  740.     XSetClipOrigin(xdev->dpy, xdev->gc, x, y);
  741.  
  742.     /*
  743.      * Draw a solid rectangle through the raster clip mask.
  744.      * Note fill style is guaranteed to be solid from above.
  745.      */
  746.     XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h);
  747.  
  748.     /* Tidy up.  Free the pixmap if it's big. */
  749.     XSetClipMask(xdev->dpy, xdev->gc, None);
  750.     if (raster * h > max_temp_pixmap)
  751.     free_cp(dev);
  752.  
  753. out:if (xdev->bpixmap != (Pixmap) 0) {
  754.     /* We wrote to the pixmap, so update the display now. */
  755.     x_update_add(dev, x, y, w, h);
  756.     }
  757.     return 0;
  758. }
  759.  
  760. /* Internal routine to free the GC and pixmap used for copying. */
  761. private void
  762. free_cp(register gx_device *dev)
  763. {
  764.     gx_device_X *xdev = (gx_device_X *)dev;
  765.  
  766.     if (xdev->cp.gc != NULL) {
  767.     XFreeGC(xdev->dpy, xdev->cp.gc);
  768.     xdev->cp.gc = NULL;
  769.     }
  770.     if (xdev->cp.pixmap != (Pixmap) 0) {
  771.     XFreePixmap(xdev->dpy, xdev->cp.pixmap);
  772.     xdev->cp.pixmap = (Pixmap) 0;
  773.     }
  774.     xdev->cp.raster = -1;    /* mark as unallocated */
  775. }
  776.  
  777. /* Copy a color bitmap. */
  778. private int
  779. x_copy_color(register gx_device *dev,
  780.          const byte *base, int sourcex, int raster, gx_bitmap_id id,
  781.          int x, int y, int w, int h)
  782. {    gx_device_X *xdev = (gx_device_X *)dev;
  783.     int depth = dev->color_info.depth;
  784.  
  785.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  786.     set_fill_style(FillSolid);
  787.     set_function(GXcopy);
  788.  
  789.     /* Filling with a colored halftone often gives rise to */
  790.     /* copy_color calls for a single pixel.  Check for this now. */
  791.  
  792.     if ( h == 1 && w == 1 )
  793.       {    uint sbit = sourcex * depth;
  794.         const byte *ptr = base + (sbit >> 3);
  795.         x_pixel pixel;
  796.         if ( depth < 8 )
  797.           pixel = (byte)(*ptr << (sbit & 7)) >> (8 - depth);
  798.         else
  799.           { pixel = *ptr++;
  800.             while ( (depth -= 8) > 0 )
  801.               pixel = (pixel << 8) + *ptr++;
  802.           }
  803.         set_fore_color(pixel);
  804.         XDrawPoint(xdev->dpy, xdev->dest, xdev->gc, x, y);
  805.       }
  806.     else
  807.       {    xdev->image.width = raster << 3;
  808.            xdev->image.height = h;
  809.            xdev->image.format = ZPixmap;
  810.            xdev->image.data = (char *)base;
  811.            xdev->image.depth = depth;
  812.            xdev->image.bytes_per_line = raster;
  813.            xdev->image.bits_per_pixel = depth;
  814.            XPutImage(xdev->dpy, xdev->dest, xdev->gc, &xdev->image,
  815.              sourcex, 0, x, y, w, h);
  816.            xdev->image.depth = xdev->image.bits_per_pixel = 1;
  817.       }
  818.     if (xdev->bpixmap != (Pixmap) 0)
  819.       x_update_add(dev, x, y, w, h);
  820. #ifdef DEBUG
  821.     if (gs_debug['F'])
  822.       dprintf4("[F] copy_color (%d,%d):(%d,%d)\n",
  823.            x, y, w, h);
  824. #endif
  825.     return 0;
  826. }
  827.  
  828. /* Draw a line */
  829. private int
  830. x_draw_line(register gx_device *dev,
  831.         int x0, int y0, int x1, int y1, gx_color_index color)
  832. {
  833.     gx_device_X *xdev = (gx_device_X *)dev;
  834.  
  835.     set_fore_color(color);
  836.     set_fill_style(FillSolid);
  837.     set_function(GXcopy);
  838.     XDrawLine(xdev->dpy, xdev->dest, xdev->gc, x0, y0, x1, y1);
  839.     if (xdev->bpixmap != (Pixmap) 0) {
  840.     int x = x0, y = y0, w = x1 - x0, h = y1 - y0;
  841.  
  842.     if (w < 0) x = x1, w = -w;
  843.     if (h < 0) y = y1, h = -h;
  844.     w++;
  845.     h++;
  846.     fit_fill(dev, x, y, w, h);
  847.     x_update_add(dev, x, y, w, h);
  848.     }
  849.     return 0;
  850. }
  851.  
  852. /* Set the device parameters.  We reimplement this so we can resize */
  853. /* the window and avoid closing and reopening the device. */
  854. private int
  855. x_put_params(gx_device *dev, gs_param_list *plist)
  856. {    gx_device_X *xdev = (gx_device_X *)dev;
  857.     gx_device temp_dev;
  858.     int code;
  859.     temp_dev = *dev;
  860.     code = gx_default_put_params_only(&temp_dev, plist);
  861.     if ( code < 0 )
  862.         return code;
  863.  
  864.     /* Hand off the change to the implementation. */
  865.     dev->x_pixels_per_inch = temp_dev.x_pixels_per_inch;
  866.     dev->y_pixels_per_inch = temp_dev.y_pixels_per_inch;
  867.     dev->width = temp_dev.width;
  868.     dev->height = temp_dev.height;
  869.     /* If the device is open, resize the window. */
  870.     /* Don't do this if Ghostview is active. */
  871.     if (dev->is_open && code != 0 && !xdev->ghostview) {
  872.     XResizeWindow(xdev->dpy, xdev->win, dev->width, dev->height);
  873.     if (xdev->bpixmap != (Pixmap) 0) {
  874.         XFreePixmap(xdev->dpy, xdev->bpixmap);
  875.         xdev->bpixmap = (Pixmap) 0;
  876.     }
  877.     xdev->dest = 0;
  878.     gdev_x_clear_window(xdev);
  879.     }
  880.     return code;
  881. }
  882.  
  883.  
  884. /* ------ Screen update procedures ------ */
  885.  
  886. /* Flush updates to the screen if needed. */
  887. private void
  888. update_do_flush(register gx_device *dev)
  889. {
  890.     gx_device_X *xdev = (gx_device_X *)dev;
  891.     int xo = xdev->update.xo, yo = xdev->update.yo;
  892.  
  893.     set_function(GXcopy);
  894.     XCopyArea(xdev->dpy, xdev->bpixmap, xdev->win, xdev->gc,
  895.           xo, yo, xdev->update.xe - xo, xdev->update.ye - yo,
  896.           xo, yo);
  897.     update_init(dev);
  898. }
  899.  
  900. /* Add a region to be updated. */
  901. /* This is only called if xdev->bpixmap != 0. */
  902. void
  903. x_update_add(gx_device *dev, int xo, int yo, int w, int h)
  904. {
  905.     register gx_device_X *xdev = (gx_device_X *)dev;
  906.     int xe = xo + w, ye = yo + h;
  907.     long new_area;
  908.  
  909.     if ( ++xdev->up_count >= 200 || xdev->up_area == 0 )
  910.       {    if ( xdev->up_area != 0 )
  911.           update_do_flush(dev);
  912.         new_area = (long)w * h;
  913.       }
  914.     else
  915.       {    /* See whether adding this rectangle */
  916.         /* would result in too much being copied unnecessarily. */
  917.         long old_area = xdev->up_area;
  918.         long new_up_area;
  919.         rect u;
  920.  
  921.         u.xo = min(xo, xdev->update.xo);
  922.         u.yo = min(yo, xdev->update.yo);
  923.         u.xe = max(xe, xdev->update.xe);
  924.         u.ye = max(ye, xdev->update.ye);
  925.         new_up_area = (long)(u.xe - u.xo) * (u.ye - u.yo);
  926.         /* The fraction of new_up_area used in the following test */
  927.         /* is not particularly critical; using a denominator */
  928.         /* that is a power of 2 eliminates a divide. */
  929.         if ( new_up_area > 100 &&
  930.              old_area + (new_area = (long)w * h) <
  931.               new_up_area - (new_up_area >> 2)
  932.            )
  933.           update_do_flush(dev);
  934.         else
  935.           {    xdev->update = u;
  936.             xdev->up_area = new_up_area;
  937.             return;
  938.           }
  939.       }
  940.     xdev->update.xo = xo;
  941.     xdev->update.yo = yo;
  942.     xdev->update.xe = xe;
  943.     xdev->update.ye = ye;
  944.     xdev->up_area = new_area;
  945. }
  946.  
  947. /* ------ Internal procedures ------ */
  948.  
  949. /* Substitute for XPutImage using XFillRectangle. */
  950. /* This is a total hack to get around an apparent bug */
  951. /* in some X servers.  It only works with the specific */
  952. /* parameters (bit/byte order, padding) used above. */
  953. private void
  954. alt_put_image(gx_device *dev, Display *dpy, Drawable win, GC gc,
  955.       XImage *pi, int sx, int sy, int dx, int dy, unsigned w, unsigned h)
  956. {
  957.     int raster = pi->bytes_per_line;
  958.     byte *data = (byte *) pi->data + sy * raster + (sx >> 3);
  959.     int init_mask = 0x80 >> (sx & 7);
  960.     int invert = 0;
  961.     int yi;
  962.  
  963. #define nrects 40
  964.     XRectangle rects[nrects];
  965.     XRectangle *rp = rects;
  966.  
  967.     XGCValues gcv;
  968.  
  969.     XGetGCValues(dpy, gc, (GCFunction | GCForeground | GCBackground), &gcv);
  970.  
  971.     if (gcv.function == GXcopy) {
  972.     XSetForeground(dpy, gc, gcv.background);
  973.     XFillRectangle(dpy, win, gc, dx, dy, w, h);
  974.     XSetForeground(dpy, gc, gcv.foreground);
  975.     } else if (gcv.function == GXand) {
  976.     if (gcv.background != ~(x_pixel) 0) {
  977.         XSetForeground(dpy, gc, gcv.background);
  978.         invert = 0xff;
  979.     }
  980.     } else if (gcv.function == GXor) {
  981.     if (gcv.background != 0) {
  982.         XSetForeground(dpy, gc, gcv.background);
  983.         invert = 0xff;
  984.     }
  985.     } else {
  986.     lprintf("alt_put_image: unimplemented function.\n");
  987.     exit(1);
  988.     }
  989.  
  990.     for (yi = 0; yi < h; yi++, data += raster) {
  991.     register int mask = init_mask;
  992.     register byte *dp = data;
  993.     register int xi = 0;
  994.  
  995.     while (xi < w) {
  996.         if ((*dp ^ invert) & mask) {
  997.         int xleft = xi;
  998.  
  999.         if (rp == &rects[nrects]) {
  1000.             XFillRectangles(dpy, win, gc, rects, nrects);
  1001.             rp = rects;
  1002.         }
  1003.         /* Scan over a run of 1-bits */
  1004.         rp->x = dx + xi, rp->y = dy + yi;
  1005.         do {
  1006.             if (!(mask >>= 1))
  1007.             mask = 0x80, dp++;
  1008.             xi++;
  1009.         } while (xi < w && (*dp & mask));
  1010.         rp->width = xi - xleft, rp->height = 1;
  1011.         rp++;
  1012.         } else {
  1013.         if (!(mask >>= 1))
  1014.             mask = 0x80, dp++;
  1015.         xi++;
  1016.         }
  1017.     }
  1018.     }
  1019.     XFillRectangles(dpy, win, gc, rects, rp - rects);
  1020.     if (invert) XSetForeground(dpy, gc, gcv.foreground);
  1021. }
  1022.