home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / s / stex2-18.zip / SeeTeX / Xtex / DviPage2.c < prev    next >
C/C++ Source or Header  |  1992-06-25  |  35KB  |  1,308 lines

  1. /*
  2.  * Copyright 1989 Dirk Grunwald
  3.  * 
  4.  * Permission to use, copy, modify, distribute, and sell this software
  5.  * and its documentation for any purpose is hereby granted without fee,
  6.  * provided that the above copyright notice appear in all copies and that
  7.  * both that copyright notice and this permission notice appear in
  8.  * supporting documentation, and that the name of Dirk Grunwald or M.I.T.
  9.  * not be used in advertising or publicity pertaining to distribution of
  10.  * the software without specific, written prior permission.  Dirk
  11.  * Grunwald and M.I.T. makes no representations about the suitability of
  12.  * this software for any purpose.  It is provided "as is" without express
  13.  * or implied warranty.
  14.  * 
  15.  * DIRK GRUNWALD AND M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  16.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17.  * FITNESS, IN NO EVENT SHALL M.I.T.  BE LIABLE FOR ANY SPECIAL, INDIRECT
  18.  * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  19.  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  20.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  21.  * OR PERFORMANCE OF THIS SOFTWARE.
  22.  * 
  23.  * Author:
  24.  *     Dr. Dirk Grunwald
  25.  *     Dept. of Computer Science
  26.  *     Campus Box 430
  27.  *     Univ. of Colorado, Boulder
  28.  *     Boulder, CO 80309
  29.  * 
  30.  *     grunwald@colorado.edu
  31.  *     
  32.  */ 
  33.  
  34. /***********************************************************************
  35.  *
  36.  *    Tpic/tpic2 specials
  37.  *
  38.  ***********************************************************************/
  39.  
  40. /*
  41.  * Improvements by Martin Jourdan, INRIA (jourdan@minos.inria.fr),
  42.  * April 1990.
  43.  *
  44.  * 1. Accomodation of Tpic 2 output language; most of the stuff was
  45.  *    written by Tim Morgan, but I modified it a little.
  46.  * 2. Shading is now completely effective.  There are five levels of
  47.  *    shading:
  48.  *    fillval < 0.1:        white
  49.  *    0.1 <= fillval < 0.35:    lightgray 25% density
  50.  *    0.35 <= fillval <= 0.65: midgray 50% density
  51.  *    0.65 < fillval <= 0.9:    darkgray 75% density
  52.  *    fillval > 0.9:        black
  53.  *    (see functions "getTile", "fill_path" and "fill_arc")
  54.  *    As requested by the "specification" of Tpic 2, default fillval
  55.  *    is 0.5, except if textures are used (see below).
  56.  *    Shading applies to *complete* ellipses/circles ("fill_arc") and
  57.  *    to arbitrary closed but *convex* polygons ("fill_path").  So
  58.  *    triangular solid arrowheads come out nicely.  However the
  59.  *    specification of Tpic2 does not *guarantee* that polygons are
  60.  *    actually convex, it's just an assumption I make for sake of
  61.  *    speed (?); cross your fingers!
  62.  *    In addition to being shaded, objects can be invisible or dotted
  63.  *    or dashed (in the source text); however I assume, as is
  64.  *    presently the case, that, *in the output*, only solid or
  65.  *    invisible objects can be shaded; more precisely a shaded
  66.  *    dotted/dashed object is output twice, first as an invisible
  67.  *    shaded object then as a non-shaded dotted/dashed object.  Beware
  68.  *    of changes by Tim Morgan!
  69.  * 3. Textures are supported (for poor ole guys who only have tpic1):
  70.  *    the patterns are analyzed to compute their density (ratio of
  71.  *    "black" bits to total number of bits), which is then used as a
  72.  *    valid fillval that overrides the default of 0.5.
  73.  * 4. Other changes:
  74.  *  - I stole from "xdvi" a fast routine to draw complete ellipses and
  75.  *    circles, because XDrawArc is awfully slow on my machine.
  76.  *  - I took care of the very small arcs generated by tpic2 for dotted
  77.  *    ellipses, which put too heavy a strain on my X server.
  78.  *  - I made changes to pen size work (see "set_pen_size").
  79.  *  - I added dotted/dashed decoding for splines but did not do more
  80.  *    because I can't figure out what "flush_spline" does...
  81.  * Remains to be done:
  82.  *  - make better use of updateRegion
  83.  *  - move some initializations (wDepth, GCArcMode) to DviPage.c, at
  84.  *    window/GC creation time
  85.  *  - clean up code; for instance, some routines work on
  86.  *    Tpic-coordinates while some others work on X-coordinates...
  87.  *  - implement dotted/dashed splines?
  88.  */
  89.  
  90. /*
  91.  * Support drawing routines for TeXsun and TeX
  92.  *
  93.  *      Copyright, (C) 1987, 1988 Tim Morgan, UC Irvine
  94.  *
  95.  * At the time these routines are called, the values of hh and vv should
  96.  * have been updated to the upper left corner of the graph (the position
  97.  * the \special appears at in the dvi file).  Then the coordinates in the
  98.  * graphics commands are in terms of a virtual page with axes oriented the
  99.  * same as the Imagen and the SUN normally have:
  100.  *
  101.  *                      0,0
  102.  *                       +-----------> +x
  103.  *                       |
  104.  *                       |
  105.  *                       |
  106.  *                      \ /
  107.  *                       +y
  108.  *
  109.  * Angles are measured in the conventional way, from +x towards +y.
  110.  * Unfortunately, that reverses the meaning of "counterclockwise"
  111.  * from what it's normally thought of.
  112.  *
  113.  * A lot of floating point arithmetic has been converted to integer
  114.  * arithmetic for speed.  In some places, this is kind-of kludgy, but
  115.  * it's worth it.
  116.  */
  117.  
  118.  
  119. #include <X11/IntrinsicP.h>
  120. #include <X11/StringDefs.h>
  121. #include <stdio.h>
  122. #include "dvi-simple.h"
  123. #include <assert.h>
  124. #include "xtex.h"
  125.  
  126. #include "DviPageP.h"
  127.  
  128. #if defined (HAVE_GHOSTSCRIPT)
  129. #include "DviPageGS-2.h"
  130. #endif
  131.  
  132. #if defined (HAVE_DPS)
  133. #include "DviPageDPS.h"
  134. #endif
  135.  
  136. #if defined (HAVE_NEWS)
  137. #include "DviPageNEWS.h"
  138. #endif
  139.  
  140.  
  141. extern char *ProgName;
  142.  
  143. #include    <math.h>
  144. #include    <ctype.h>
  145.  
  146. #define texPicConvHoriz(w,x)\
  147.   ( ((int) x * (int) w -> dviPage.pixelsPerInchHoriz) / (int) 1000 )
  148.  
  149. #define texPicConvVert(w,x)\
  150.   ( ((int) x * (int) w -> dviPage.pixelsPerInchVert) / (int) 1000 )
  151.  
  152. static double shading = -1.0;
  153.  
  154. /*
  155.  * Draw a line from (fx,fy) to (tx,ty) -- Tpic-coordinates
  156.  * Right now, we ignore pen_size.
  157.  */
  158. static void line_btw(w, fx, fy, tx, ty)
  159.      DviPageWidget w;
  160.      int fx, fy, tx, ty;
  161. {
  162.     int rx = fastFromSpHoriz(w, w -> dviPage.dviStackPointer -> h);
  163.     int ry = fastFromSpVert(w, w -> dviPage.dviStackPointer -> v);
  164.   
  165.     fx = texPicConvHoriz(w, fx);
  166.     fy = texPicConvVert(w, fy);
  167.     tx = texPicConvHoriz(w, tx);
  168.     ty = texPicConvVert(w, ty);
  169.   
  170.     if ( fx == tx && fy == ty ) {
  171.     fx += rx;
  172.     fy += ry;
  173.  
  174.     if ( XPointInRegion(w -> dviPage.updateRegion, fx, fy) ) {
  175.         XDrawPoint(XtDisplay(w), XtWindow(w),
  176.                w -> dviPage.paintGC, fx, fy);
  177.     }
  178.     }
  179.     else {
  180.     XDrawLine(XtDisplay(w), XtWindow(w),
  181.           w -> dviPage.paintGC,
  182.           fx + rx, fy + ry, tx + rx, ty + ry);
  183.     }
  184. }
  185.  
  186. /*
  187.  * Draw a dot at (x,y) -- Tpic-coordinates
  188.  */
  189. static void dot_at(w, x, y)
  190.      DviPageWidget w;
  191.      int x;
  192.      int y;
  193. {
  194.     line_btw(w, x, y, x+1, y);
  195. }
  196.  
  197. /*
  198.  * Return a tile for shading
  199.  * Three levels of shading (in addition to black and white) are
  200.  * available, because I use standard bitmaps found in the X distribution.
  201.  */
  202. static Pixmap
  203. getTile(w, shading)
  204.     DviPageWidget w;
  205.     double shading;
  206. {
  207.     static Pixmap    shadeTiles[3];  
  208.     static int        wDepth = 0;
  209.     Pixmap        the_tile;
  210.  
  211.     if (shading < 0.35) {    /* lightgray 25% density */
  212.     the_tile = shadeTiles[0];
  213.     if (!the_tile) {    /* initialize tile */
  214. #include <X11/bitmaps/light_gray>
  215.  
  216.         if (wDepth == 0) {    /* this code belongs to DviPage.c */
  217.         /* the depth won't change during a session */
  218.         XWindowAttributes wAttrs;
  219.         XGetWindowAttributes(XtDisplay(w), XtWindow(w), &wAttrs);
  220.         wDepth = wAttrs.depth;
  221.         }
  222.         shadeTiles[0] = the_tile =
  223.         XCreatePixmapFromBitmapData
  224.             (XtDisplay(w), XtWindow(w),
  225.              light_gray_bits,
  226.              light_gray_width,
  227.              light_gray_height,
  228.              w -> dviPage.paintGC -> values.foreground,
  229.              w -> dviPage.paintGC -> values.background,
  230.              wDepth);
  231.     }
  232.     } else if (shading > 0.65) { /* darkgray 75% density */
  233.     the_tile = shadeTiles[2];
  234.     if (!the_tile) {
  235. #include <X11/bitmaps/flipped_gray>
  236.  
  237.         if (wDepth == 0) {
  238.         XWindowAttributes wAttrs;
  239.         XGetWindowAttributes(XtDisplay(w), XtWindow(w), &wAttrs);
  240.         wDepth = wAttrs.depth;
  241.         }
  242.         shadeTiles[2] = the_tile =
  243.         XCreatePixmapFromBitmapData
  244.             (XtDisplay(w), XtWindow(w),
  245.              flipped_gray_bits,
  246.              flipped_gray_width,
  247.              flipped_gray_height,
  248.              w -> dviPage.paintGC -> values.foreground,
  249.              w -> dviPage.paintGC -> values.background,
  250.              wDepth);
  251.     }
  252.     } else {
  253.     the_tile = shadeTiles[1];
  254.     if (!the_tile) {    /* midgray 50% density */
  255. #include <X11/bitmaps/gray>
  256.  
  257.         if (wDepth == 0) {
  258.         XWindowAttributes wAttrs;
  259.         XGetWindowAttributes(XtDisplay(w), XtWindow(w), &wAttrs);
  260.         wDepth = wAttrs.depth;
  261.         }
  262.         shadeTiles[1] = the_tile =
  263.         XCreatePixmapFromBitmapData
  264.             (XtDisplay(w), XtWindow(w),
  265.              gray_bits,
  266.              gray_width,
  267.              gray_height,
  268.              w -> dviPage.paintGC -> values.foreground,
  269.              w -> dviPage.paintGC -> values.background,
  270.              wDepth);
  271.     }
  272.     }
  273.     return the_tile;
  274. }
  275.  
  276. /*
  277.  * Shade the given polygon -- X-coordinates.  Reset shading.
  278.  * The polygon is assumed to be convex!
  279.  */
  280. static void
  281. fill_path(w, xxyy, path_len)
  282.     DviPageWidget w;
  283.     XPoint *xxyy;
  284.     int path_len;
  285. {
  286.     if (shading >= 0.0) {
  287.     if (shading < 0.1) {    /* white */
  288.         XFillPolygon(XtDisplay(w), XtWindow(w), w -> dviPage.clearGC,
  289.              xxyy, path_len, Convex, CoordModeOrigin);
  290.     } else if (shading > 0.9) { /* black */
  291.         XFillPolygon(XtDisplay(w), XtWindow(w), w -> dviPage.paintGC,
  292.              xxyy, path_len, Convex, CoordModeOrigin);
  293.     } else {        /* gray -- one of three levels */
  294.         XGCValues    values;
  295.         /* temporarily set fill_style to Tiled */
  296.         values.fill_style = FillTiled;
  297.         values.tile = getTile(w, shading);
  298.         XChangeGC(XtDisplay(w), w -> dviPage.paintGC,
  299.               (unsigned) (GCFillStyle | GCTile),
  300.               &values);
  301.         /* fill */
  302.         XFillPolygon(XtDisplay(w), XtWindow(w), w -> dviPage.paintGC,
  303.              xxyy, path_len, Convex, CoordModeOrigin);
  304.         /* reset fill_style to Solid */
  305.         values.fill_style = FillSolid;
  306.         XChangeGC(XtDisplay(w), w -> dviPage.paintGC,
  307.               (unsigned) GCFillStyle,
  308.               &values);
  309.     }
  310.     }
  311.     shading = -1.0;        /* reset shading */
  312. }
  313.  
  314. /*
  315.  * Shade the given ellipse or circle -- X-coordinates.  Reset shading.
  316.  * The ellipse or circle is assumed to be complete!
  317.  */
  318. static void
  319. fill_arc(w, x, y, wd, ht)
  320.     DviPageWidget w;
  321.     int x, y;
  322.     unsigned int wd, ht;
  323. {
  324.     static arcModeInit = 0;
  325.  
  326.     if (!arcModeInit) {
  327.     /* This code belongs to DviPage.c */
  328.     XGCValues    values;
  329.  
  330.     values.arc_mode = ArcPieSlice;
  331.     XChangeGC(XtDisplay(w), w -> dviPage.paintGC,
  332.           (unsigned) GCArcMode,
  333.           &values);
  334.     XChangeGC(XtDisplay(w), w -> dviPage.clearGC,
  335.           (unsigned) GCArcMode,
  336.           &values);
  337.     arcModeInit = 1;
  338.     }
  339.   
  340.     if (shading >= 0.0) {
  341.     if (shading < 0.1) {
  342.         XFillArc(XtDisplay(w), XtWindow(w), w -> dviPage.clearGC,
  343.              x, y, wd, ht, 0, 360*64);
  344.     } else if (shading > 0.9) {
  345.         XFillArc(XtDisplay(w), XtWindow(w), w -> dviPage.paintGC,
  346.              x, y, wd, ht, 0, 360*64);
  347.     } else {
  348.         XGCValues    values;
  349.  
  350.         values.fill_style = FillTiled;
  351.         values.tile = getTile(w, shading);
  352.         XChangeGC(XtDisplay(w), w -> dviPage.paintGC,
  353.               (unsigned) (GCFillStyle | GCTile),
  354.               &values);
  355.  
  356.         /* XFillArc is awfully slow but it's worth it */
  357.         XFillArc(XtDisplay(w), XtWindow(w), w -> dviPage.paintGC,
  358.              x, y, wd, ht, 0, 360*64);
  359.  
  360.         values.fill_style = FillSolid;
  361.         XChangeGC(XtDisplay(w), w -> dviPage.paintGC,
  362.               (unsigned) GCFillStyle,
  363.               &values);
  364.     }
  365.     }
  366.     shading = -1.0;
  367. }
  368.  
  369. /*****************************************************************************/
  370.  
  371. #define    TWOPI        (3.14159265359*2.0)
  372. #define    MAX_PEN_SIZE    7    /* Max pixels of pen width */
  373.  
  374. /* Unfortunately, these values also appear in dvisun.c */
  375. #define    xRESOLUTION(w)    ( w -> dviPage.pixelsPerInchHoriz )
  376. #define    yRESOLUTION(w)    ( w -> dviPage.pixelsPerInchVert )
  377.  
  378. /*
  379.  * Set the size of the virtual pen used to draw in milli-inches
  380.  */
  381.  
  382. /* ARGSUSED */
  383. static void set_pen_size(w, cp)
  384.      DviPageWidget w;
  385.      char *cp;
  386. {
  387.     int ps;
  388.     XGCValues    values;
  389.   
  390.     if (sscanf(cp, " %d ", &ps) != 1) {
  391.     error(0,0, "illegal .ps command format: %s", cp);
  392.     return;
  393.     }
  394.     w -> dviPage.penSize
  395.     = (ps*(xRESOLUTION(w)+yRESOLUTION(w)) + 1000) / 2000;
  396.     if (w -> dviPage.penSize < 1)
  397.     w -> dviPage.penSize = 1;
  398.     else if (w -> dviPage.penSize > MAX_PEN_SIZE)
  399.     w -> dviPage.penSize = MAX_PEN_SIZE;
  400.  
  401.     /* update paintGC -> line_width */
  402.     values.line_width = w -> dviPage.penSize;
  403.     XChangeGC(XtDisplay(w), w -> dviPage.paintGC,
  404.           (unsigned) GCLineWidth,
  405.           &values);
  406. }
  407.  
  408.  
  409. /*
  410.  * Print (if requested) the line defined by previous path commands.
  411.  * Shade if necessary.
  412.  */
  413. static void flush_path(w, invis)
  414.     DviPageWidget w;
  415.     int invis;
  416. {
  417.     register int i;
  418.     int *xx = w -> dviPage.xx;
  419.     int *yy = w -> dviPage.yy;
  420.     int path_len = w -> dviPage.pathLen;
  421.     XPoint xxyy[MAXPOINTS];
  422.     int rx = fastFromSpHoriz(w, w -> dviPage.dviStackPointer -> h);
  423.     int ry = fastFromSpVert(w, w -> dviPage.dviStackPointer -> v);
  424.   
  425.     for (i=1; i <= path_len; i++) {
  426.     /* Convert Tpic-coordinates to X-coordinates */
  427.     xxyy[i-1].x = texPicConvHoriz(w, xx[i]) + rx;
  428.     xxyy[i-1].y = texPicConvVert(w, yy[i]) + ry;
  429.     }
  430.   
  431.     fill_path(w, xxyy, path_len);
  432.  
  433.     if (!invis) {
  434.       if ( path_len > 2 ) {
  435.     /* A single call to XDrawLines is better than */
  436.     /* multiple calls to line_btw */
  437.     XDrawLines(XtDisplay(w), XtWindow(w),
  438.            w -> dviPage.paintGC,
  439.            xxyy, path_len, CoordModeOrigin);
  440.       }
  441.       /* unless, of course, you're drawing a dotted line this way */
  442.       else {
  443.     for (i=1; i < path_len; i++) {
  444.       line_btw(w, xx[i], yy[i], xx[i+1], yy[i+1]);
  445.     }
  446.       }
  447.     }
  448.   
  449.     w -> dviPage.pathLen = 0;
  450. }
  451.  
  452. /*
  453.  * Print a dashed line along the previously defined path, with
  454.  * the dashes/inch defined.
  455.  * Assume no shading takes place.
  456.  */
  457. static void flush_dashed(w, cp, dotted)
  458.     DviPageWidget w;
  459.     char *cp;
  460.     int dotted;
  461. {
  462.     int i, numdots, x0, y0, x1, y1;
  463.     int cx0, cy0, cx1, cy1;
  464.     float inchesperdash;
  465.     double d, spacesize, a, b, dx, dy, milliperdash;
  466.   
  467.     int *xx = w -> dviPage.xx;
  468.     int *yy = w -> dviPage.yy;
  469.     int path_len = w -> dviPage.pathLen;
  470.   
  471.     if (sscanf(cp, " %f ", &inchesperdash) != 1) {
  472.     error(0,0,"illegal format for dotted/dashed line: %s", cp);
  473.     return;
  474.     }
  475.     if (path_len <= 1 || inchesperdash <= 0.0) {
  476.     error(0,0,"illegal conditions for dotted/dashed line");
  477.     return;
  478.     }
  479.     milliperdash = inchesperdash * 1000.0;
  480.     x0 = xx[1];    y0 = yy[1];
  481.     x1 = xx[2];    y1 = yy[2];
  482.     dx = x1 - x0;
  483.     dy = y1 - y0;
  484.     if (dotted) {
  485.     numdots = sqrt(dx*dx + dy*dy) / milliperdash + 0.5;
  486.     for (i=0; i <= numdots; i++) {
  487.         a = (float) i / (float) numdots;
  488.         cx0 = x0 + a*dx + 0.5;
  489.         cy0 = y0 + a*dy + 0.5;
  490.         dot_at(w,cx0, cy0);
  491.     }
  492.     }
  493.     else {
  494.     d = sqrt(dx*dx + dy*dy);
  495.     if (d <= 2.0*milliperdash)
  496.         line_btw(w, x0, y0, x1, y1);
  497.     else {
  498.         numdots = d / (2.0*milliperdash) + 1.0;
  499.         spacesize = (d - numdots * milliperdash) / (numdots - 1);
  500.         for (i=0; i<numdots-1; i++) {
  501.         a = i * (milliperdash + spacesize) / d;
  502.         b = a + milliperdash / d;
  503.         cx0 = x0 + a*dx + 0.5;
  504.         cy0 = y0 + a*dy + 0.5;
  505.         cx1 = x0 + b*dx + 0.5;
  506.         cy1 = y0 + b*dy + 0.5;
  507.         line_btw(w, cx0, cy0, cx1, cy1);
  508.         b += spacesize / d;
  509.         }
  510.         cx0 = x0 + b*dx + 0.5;
  511.         cy0 = y0 + b*dy + 0.5;
  512.         line_btw(w, cx0, cy0, x1, y1);
  513.     }
  514.     }
  515.   
  516.     w -> dviPage.pathLen = 0;
  517. }
  518.  
  519.  
  520. /*
  521.  * Add a point to the current path
  522.  */
  523. static void add_path(w, cp)
  524.     DviPageWidget w;
  525.     char *cp;
  526. {
  527.     int pathx, pathy;
  528.   
  529.     if (++( w -> dviPage.pathLen) >= MAXPOINTS) {
  530.     error(0,0, "Too many points");
  531.     return;
  532.     }
  533.     if (sscanf(cp, " %d %d ", &pathx, &pathy) != 2) {
  534.     error(0,0,"Malformed path command");
  535.     return;
  536.     }
  537.     w-> dviPage.xx[w -> dviPage.pathLen] = pathx;
  538.     w-> dviPage.yy[w -> dviPage.pathLen] = pathy;
  539. }
  540.  
  541. /*
  542.  * Draw a *complete* ellipse or circle with the indicated center and radices.
  543.  * Tpic-coordinates.
  544.  * Stolen from xdvi.
  545.  */
  546. static    void
  547. draw_ellipse(w, xc, yc, xr, yr)
  548.     DviPageWidget w;
  549.     int xc, yc, xr, yr;
  550. {
  551.     double angle, theta;
  552.     int n, px0, py0, px1, py1;
  553.  
  554.     angle = (xr + yr) / 2.0;
  555.     theta = sqrt(1.0 / angle);
  556.     n = TWOPI / theta + 0.5;
  557.     if (n < 12) n = 12;
  558.     else if (n > 80) n = 80;
  559.     n /= 2;
  560.     theta = TWOPI / n;
  561.  
  562.     angle = 0.0;
  563.     px0 = xc + xr;        /* cos(0) = 1 */
  564.     py0 = yc;            /* Sin(0) = 0 */
  565.     while ((angle += theta) <= TWOPI) {
  566.     px1 = xc + xr*cos(angle) + 0.5;
  567.     py1 = yc + yr*sin(angle) + 0.5;
  568.     line_btw(w, px0, py0, px1, py1);
  569.     px0 = px1;
  570.     py0 = py1;
  571.     }
  572.     line_btw(w, px0, py0, xc + xr, yc);
  573. }
  574.  
  575. /*
  576.  * Draw an arc
  577.  */
  578. static void arc(w, cp, invis)
  579.     DviPageWidget w;
  580.     char *cp;
  581.     int invis;
  582. {
  583.     int xc, yc, xrad, yrad;
  584.     float start_angle, end_angle;
  585.     int angS, angE;
  586.     Bool doit = True;
  587.     
  588.     int rx = fastFromSpHoriz(w, w -> dviPage.dviStackPointer -> h);
  589.     int ry = fastFromSpVert(w, w -> dviPage.dviStackPointer -> v);
  590.   
  591.     if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad,
  592.            &start_angle, &end_angle) != 6) {
  593.     error(0,0,"illegal arc specification: %s", cp);
  594.     return;
  595.     }
  596.  
  597.     if (shading >= 0.0)
  598.     if (start_angle > 0.0 || end_angle < 6.282)
  599.         error(0,0,"Attempt to fill an incomplete arc");
  600.     else            /* this call could be made more elegant */
  601.         fill_arc(w,
  602.              texPicConvHoriz(w, xc) + rx - texPicConvHoriz(w, xrad),
  603.              texPicConvVert(w, yc) + ry - texPicConvVert(w, yrad),
  604.              (unsigned) (2 * texPicConvHoriz(w, xrad)),
  605.              (unsigned) (2 * texPicConvVert(w, yrad)));
  606.  
  607.     if (invis)
  608.     return;
  609.  
  610.     /* We have a specialized fast way to draw closed circles/ellipses */
  611.     if (start_angle <= 0.0 && end_angle >= 6.282) {
  612.     draw_ellipse(w, xc, yc, xrad, yrad);
  613.     return;
  614.     }
  615.   
  616.     xc = texPicConvHoriz(w, xc);
  617.     yc = texPicConvVert(w, yc);
  618.     xrad = texPicConvHoriz(w, xrad);
  619.     yrad = texPicConvVert(w, yrad);
  620.   
  621.     angS = (int) ( (start_angle * 360 * 64) / TWOPI);
  622.     angE = (int) ( ((end_angle - start_angle) * 360 * 64) / TWOPI);
  623.   
  624.     if ( w -> dviPage.haveBackingStore ) {
  625.     doit = XRectInRegion( w -> dviPage.updateRegion,
  626.                  xc + rx - xrad, yc + ry - yrad,
  627.                  2 * xrad, 2 * yrad) != RectangleOut;
  628.     }
  629.     
  630.     if (doit) {
  631.     /* beware of very small arcs (actually dots) generated by tpic2 */
  632.     /* for dotted ellipses; threshold is half a degree but can be tuned */
  633.     if (angE < 32)
  634.         XDrawPoint(XtDisplay(w), XtWindow(w), w -> dviPage.paintGC,
  635.                xc + rx + (int) (xrad * cos(start_angle)),
  636.                yc + ry + (int) (yrad * sin(start_angle)));
  637.     else
  638.         XDrawArc(XtDisplay(w), XtWindow(w), w -> dviPage.paintGC,
  639.              xc + rx - xrad, yc + ry - yrad,
  640.              2 * xrad, 2 * yrad, -angS, -angE);
  641.     }
  642. }
  643.  
  644.  
  645. /*
  646.  * APPROXIMATE integer distance between two points
  647.  */
  648. #define    dist(x0, y0, x1, y1)    (abs(x0-x1)+abs(y0-y1))
  649.  
  650. /*
  651.  * Draw a spline along the previously defined path
  652.  */
  653. static void flush_spline(widget, cp)
  654.     DviPageWidget widget;
  655.     char *cp;
  656. {
  657.     int xp, yp, N, lastx=(-1), lasty;
  658.     int t1, t2, t3, steps, j;
  659.     register int i, w;
  660.   
  661.     int *xx = widget -> dviPage.xx;
  662.     int *yy = widget -> dviPage.yy;
  663.     int path_len = widget -> dviPage.pathLen;
  664.   
  665.     /* Dotted/dashed variables and decoding */
  666.     float inchesperdash;
  667.     enum {spSolid, spDotted, spDashed} spStyle;
  668.  
  669.     if (cp && *cp) {
  670.     if (sscanf(cp, " %f ", &inchesperdash) != 1) {
  671.         error(0,0,"illegal format for dotted/dashed line: %s", cp);
  672.         spStyle = spSolid;
  673.     } else if (inchesperdash < 0.0) {
  674.         spStyle = spDotted;
  675.         inchesperdash = -inchesperdash;
  676.     } else if (inchesperdash > 0.0)
  677.         spStyle = spDashed;
  678.     else spStyle = spSolid;
  679.     } else spStyle = spSolid;
  680.  
  681. #ifdef    lint
  682.     lasty = -1;
  683. #endif
  684.     N = path_len + 1;
  685.     xx[0] = xx[1];    yy[0] = yy[1];
  686.     xx[N] = xx[N-1];    yy[N] = yy[N-1];
  687.     for (i=0; i<N-1; i++) {    /* interval */
  688.     steps = (dist(xx[i], yy[i], xx[i+1], yy[i+1]) +
  689.          dist(xx[i+1], yy[i+1], xx[i+2], yy[i+2])) / 80;
  690.     for (j=0; j<steps; j++) { /* points within */
  691.         w = (j*1000 + 500) / steps;
  692.         t1 = w * w / 20;
  693.         w -= 500;
  694.         t2 = (750000 - w * w) / 10;
  695.         w -= 500;
  696.         t3 = w * w / 20;
  697.         xp = (t1*xx[i+2] + t2*xx[i+1] + t3*xx[i] + 50000) / 100000;
  698.         yp = (t1*yy[i+2] + t2*yy[i+1] + t3*yy[i] + 50000) / 100000;
  699.         if (lastx > -1) line_btw(widget, lastx, lasty, xp, yp);
  700.         lastx = xp;
  701.         lasty = yp;
  702.     }
  703.     }
  704.   
  705.     widget -> dviPage.pathLen = 0;
  706. }
  707.  
  708. static double txshading = -1.0;
  709.  
  710. /*
  711.  * Process textures (.tx command): analyse density and set txshading
  712.  */
  713. static void
  714. Texture(cp)
  715. register char *cp;
  716. {
  717.     int blackbits = 0, totalbits = 0;
  718.  
  719.     while (*cp) {
  720.     switch (*cp) {
  721.     case '0':
  722.         totalbits += 4;
  723.         break;
  724.     case '1':
  725.     case '2':
  726.     case '4':
  727.     case '8':
  728.         blackbits += 1;
  729.         totalbits += 4;
  730.         break;
  731.     case '3':
  732.     case '5':
  733.     case '6':
  734.     case '9':
  735.     case 'a':
  736.     case 'A':
  737.     case 'c':
  738.     case 'C':
  739.         blackbits += 2;
  740.         totalbits += 4;
  741.         break;
  742.     case '7':
  743.     case 'b':
  744.     case 'B':
  745.     case 'd':
  746.     case 'D':
  747.     case 'e':
  748.     case 'E':
  749.         blackbits += 3;
  750.         totalbits += 4;
  751.         break;
  752.     case 'f':
  753.     case 'F':
  754.         blackbits += 4;
  755.         totalbits += 4;
  756.         break;
  757.     case ' ':
  758.         break;
  759.     default:
  760.         error(0,0,"Invalid character in .tx pattern: \"%c\"", *cp);
  761.         break;
  762.     }
  763.     cp++;
  764.     }
  765.     txshading = (double) blackbits / (double) totalbits;
  766. }                               /* end of Texture */
  767.  
  768. /*
  769.  * Set shading for the *next* polygon, circle, or ellipse
  770.  */
  771. /* ARGSUSED */
  772. static void shade_last(w, cp)
  773.     DviPageWidget w;
  774.     char *cp;
  775. {
  776.     if (cp && *cp) {
  777.     if (sscanf(cp, "%lf", &shading) != 1)
  778.         error(0,0,"illegal format for shading value: %s", cp);
  779.     else if (shading < 0.0 || shading > 1.0) {
  780.         error(0,0,"bad shading value: %f", shading);
  781.         shading = 0.5;
  782.     }
  783.     }
  784.     else if (txshading >= 0.0)    /* account for textures */
  785.     shading = txshading;
  786.     else shading = 0.5;        /* default value as requested by tpic2 */
  787.  
  788.     /* The following code is totally useless
  789.        (as are w->dviPage.{whiten,blacken,shade}, BTW) */
  790. /*
  791.     w -> dviPage.whiten = w -> dviPage.blacken = w -> dviPage.shade = False;
  792.     if (shading > 0.9) w -> dviPage.blacken = True;
  793.     else if (shading >= 0.0 && shading < 0.1) w -> dviPage.whiten = True;
  794.     else if (shading >= 0.1 && shading <= 0.9) w -> dviPage.shade = True;
  795. */
  796. }
  797.  
  798. /***********************************************************************
  799.  *
  800.  *    Button specials
  801.  *
  802.  ***********************************************************************/
  803.  
  804. #define SKIPWHITE(cp) while (cp && *cp && isspace(*cp)) cp++
  805.  
  806. static void
  807. CallAction(widget,action) 
  808. DviPageWidget widget;
  809. char *action;
  810. {
  811.   int actionLen = strlen( action );
  812.   
  813.   Bool doFree;
  814.   char stringCopy[1024];
  815.   char *allocatedStr;
  816.   char *str;
  817.   
  818.   char *actionProcName;
  819.   int num_params;
  820.   char *params[100];    /* lets hope they don't have more than that.. */
  821.   
  822.   if ( actionLen > 1023 ) {
  823.     allocatedStr = str = XtMalloc( actionLen + 2 );
  824.     doFree = True;
  825.   }
  826.   else {
  827.     str = stringCopy;
  828.     doFree = False;
  829.   }
  830.   
  831.   SKIPWHITE(str);
  832.   strcpy(str, action);
  833.   
  834.   for (;;) {
  835.     SKIPWHITE(str);
  836.     if ( str == 0 || *str == 0 ) break;
  837.     
  838.     /* skip to action procedure name */
  839.     SKIPWHITE(str);
  840.     actionProcName = str;
  841.     
  842.     /* find end of action procedure name- terminate by space or paren */
  843.     while (*str && !( isspace(*str) || *str == '(' )) str++;
  844.     /* terminate action procedure name string */
  845.     *(str++) = 0;
  846.  
  847.     if ( *actionProcName == 0 ) {
  848.       return;
  849.     }
  850.     
  851.     /* skip past any openning paren, e.g. in case of 'foo (bar)' */
  852.     
  853.     SKIPWHITE(str);
  854.     if ( *str == '(') str++;
  855.     
  856.     /* now, scan to build a list of params */
  857.     num_params = 0;
  858.     while ( *str && *str != ')' && num_params < 100) {
  859.       SKIPWHITE(str);
  860.       params[num_params] = str;
  861.       while (*str && !( isspace(*str) || *str == ',' || *str==')' )) {
  862.     if (*str == '\\') {
  863.       str++;
  864.       if ( *str == 0 ) str--;
  865.     }
  866.     /* is it a quoted parameter ? */
  867.     if( *str == '"' ){
  868.       /* find the closing quote, no error check here, hope for the best*/
  869.       while( *str && *str != '"' ) str++; 
  870.     }
  871.     str++;
  872.     }
  873.  
  874. /*    SKIPWHITE(str);  this SKIPWHITE chops letters off later words */
  875.       
  876.       /* terminate this parameter */
  877.       
  878.       num_params++;
  879.       if ( *str == 0 ) {
  880.     break;
  881.       } 
  882.       else if (*str == ')') {
  883.     *(str++) = 0;
  884.     break;
  885.       }
  886.       else {
  887.     *(str++) = 0;
  888.       }
  889.       
  890.       SKIPWHITE(str);
  891.     }
  892.     
  893.     SKIPWHITE(str);
  894.     if ( *str == ')') str++;
  895.     
  896.     XtCallActionProc((Widget) widget, actionProcName, NULL, params, num_params);
  897.   }
  898.   
  899.   if ( doFree ) {
  900.     XtFree( allocatedStr );
  901.   }
  902. }
  903.  
  904. static void registerActionProc(w, cp)
  905. DviPageWidget w;
  906. char *cp;
  907. {
  908.  
  909.   long dx;    /* origin displacement for width */
  910.   long wd;    /* width */
  911.   long dy;    /* origin displacement for height */
  912.   long ht;    /* height */
  913.  
  914.   XGCValues    values;
  915.  
  916.   int rx = fastFromSpHoriz(w, w -> dviPage.dviStackPointer -> h);
  917.   int ry = fastFromSpVert(w, w -> dviPage.dviStackPointer -> v);
  918.  
  919.   XPoint xxyy[5];
  920.  
  921.   /* get button area in scaled pixels */
  922.   
  923.   dx = strtol(cp, &cp, 0);
  924.   dx = fastFromSpHoriz(w, dx);
  925.  
  926.   wd = strtol(cp, &cp, 0);
  927.   wd = fastFromSpHoriz(w, wd);
  928.  
  929.   dy = strtol(cp, &cp, 0);
  930.   dy = fastFromSpVert(w, dy);
  931.  
  932.   ht = strtol(cp, &cp, 0);
  933.   ht = fastFromSpVert(w, ht);
  934.  
  935.   xxyy[0].x = rx + dx;    /* lower left */
  936.   xxyy[0].y = ry - dy;
  937.  
  938.   xxyy[1].x = rx + wd;    /* lower right */
  939.   xxyy[1].y = ry - dy;
  940.  
  941.   xxyy[2].x = rx + wd;    /* upper right */
  942.   xxyy[2].y = ry - ht;
  943.  
  944.   xxyy[3].x = rx + dx;    /* upper left */
  945.   xxyy[3].y = ry - ht;
  946.  
  947.   xxyy[4].x = rx + dx;    /* lower left */
  948.   xxyy[4].y = ry - dy;
  949.  
  950.   values.foreground    = w -> dviPage.boxColor;
  951.   XChangeGC( XtDisplay(w), w -> dviPage.paintGC, GCForeground, &values);
  952.   
  953.   XDrawLines(XtDisplay(w), XtWindow(w),
  954.          w -> dviPage.paintGC,
  955.          xxyy, 5, CoordModeOrigin);
  956.  
  957.   if ( w -> dviPage.reverseVideo ) {
  958.     values.foreground    = w -> dviPage.background;
  959.   } else {
  960.     values.foreground    = w -> dviPage.foreground;
  961.   }
  962.     
  963.   XChangeGC( XtDisplay(w), w -> dviPage.paintGC, GCForeground, &values);
  964.  
  965.   SKIPWHITE(cp);
  966.   if ( *cp ) {
  967.     DviButton *thisButton = (DviButton *) XtMalloc( sizeof(DviButton) );
  968.     int len = strlen(cp);
  969.  
  970.     thisButton -> upperLeft  = xxyy[3];
  971.     thisButton -> lowerRight = xxyy[1];
  972.     if ( len < DVI_REGION_STRLEN ) {
  973.       thisButton -> longerAction = 0;
  974.       strcpy( thisButton -> action, cp);
  975.     } else {
  976.       thisButton -> longerAction = XtMalloc(len+1);
  977.       strcpy( thisButton -> longerAction, cp);
  978.     }
  979.  
  980.     thisButton -> next = w -> dviPage.buttons;
  981.     w -> dviPage.buttons = thisButton;
  982.   }
  983. }
  984.  
  985. void actionPushButton(w, event, params, num_params)
  986.      DviPageWidget w;
  987.      XEvent *event;
  988.      String *params;
  989.      Cardinal *num_params;
  990. {
  991.   Window root, child;
  992.   int root_x, root_y, win_x, win_y;
  993.   unsigned int buttons;
  994.   DviButton *b;
  995.  
  996.   /* find the mouse */
  997.   XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child,
  998.         &root_x, &root_y, &win_x, &win_y, &buttons);
  999.  
  1000.   b = w -> dviPage.buttons;
  1001.   while ( b ) {
  1002.  
  1003.     if (   win_x >= b -> upperLeft.x
  1004.     && win_x <= b -> lowerRight.x
  1005.     && win_y >= b -> upperLeft.y
  1006.     && win_y <= b -> lowerRight.y )
  1007.     {
  1008.       /* found a button, push it.. */
  1009.       char *action = b -> action;
  1010.       if ( b -> longerAction ) {
  1011.     action = b -> longerAction;
  1012.       }
  1013.       CallAction(w, action);
  1014.     }
  1015.  
  1016.     b = b -> next;
  1017.     
  1018.   }
  1019. }
  1020.  
  1021.  
  1022. /*
  1023.  * Draw the bounding box for a \psfig special.
  1024.  *
  1025.  * expected format of the command string is
  1026.  *
  1027.  * width height bbllx bblly bburx bbury
  1028.  *
  1029.  * *ll* means lower-left, *ur* means upper-right.
  1030.  *
  1031.  * We just draw the bounding box.
  1032.  */
  1033. static void
  1034. psfigBeginOutline(w,cp,fudge_height)
  1035. DviPageWidget w;
  1036. char *cp;
  1037. int fudge_height;
  1038. {
  1039.   int bbllx, bblly;
  1040.   int bburx, bbury;
  1041.   int width, height;
  1042.  
  1043.   int rx = fastFromSpHoriz(w, w -> dviPage.dviStackPointer -> h);
  1044.   int ry = fastFromSpVert(w, w -> dviPage.dviStackPointer -> v);
  1045.  
  1046.   sscanf(cp, " %d %d %d %d %d %d ",
  1047.      &width, &height,
  1048.      &bbllx, &bblly, &bburx, &bbury);
  1049.  
  1050.   width = fastFromSpHoriz(w, width);
  1051.   height = fastFromSpVert(w, height);
  1052.  
  1053.   /* 
  1054.    * fudge_height == TRUE for situations when ry is the bottom of the 
  1055.    * box rather than the top, so we just adjust the height accordingly
  1056.    */
  1057.   if (fudge_height) ry -= height; /* for use with \epsfbox{} specials */
  1058.  
  1059.   XDrawLine(XtDisplay(w), XtWindow(w),
  1060.         w -> dviPage.paintGC,
  1061.         rx, ry, rx + width, ry );
  1062.   XDrawLine(XtDisplay(w), XtWindow(w),
  1063.         w -> dviPage.paintGC,
  1064.         rx + width, ry, rx + width, ry + height);
  1065.   XDrawLine(XtDisplay(w), XtWindow(w),
  1066.         w -> dviPage.paintGC,
  1067.         rx + width, ry + height, rx, ry + height);
  1068.   XDrawLine(XtDisplay(w), XtWindow(w),
  1069.         w -> dviPage.paintGC,
  1070.         rx, ry + height, rx, ry);
  1071. }
  1072.  
  1073. /*****************************************************************************/
  1074.  
  1075.  
  1076.  
  1077. /*****************************************************************************/
  1078.  
  1079. /***********************************************************************
  1080.  *
  1081.  *    Psfig/Postscript specials
  1082.  *
  1083.  ***********************************************************************/
  1084.  
  1085. /*
  1086.  * Draw the bounding box for a \psfig special.
  1087.  *
  1088.  * expected format of the command string is
  1089.  *
  1090.  * width height bbllx bblly bburx bbury
  1091.  *
  1092.  * *ll* means lower-left, *ur* means upper-right.
  1093.  *
  1094.  * We just draw the bounding box.
  1095.  */
  1096.   /* 
  1097.    * fudge_height == TRUE for situations when ry is the bottom of the 
  1098.    * box rather than the top.
  1099.    */
  1100.  
  1101. static void
  1102.   psfigBegin(w,cp,fudge_height)
  1103. DviPageWidget w;
  1104. char *cp;
  1105. int fudge_height;
  1106. {
  1107.  
  1108. #if defined(HAVE_GHOSTSCRIPT)
  1109.    if ( xtexResources.useGhostScript ) psfigBeginGHOST(w, cp, fudge_height); 
  1110.    else
  1111. #endif
  1112. #if defined(HAVE_DPS)
  1113.    if ( xtexResources.useDPS ) psfigBeginDPS(w, cp, fudge_height); 
  1114.    else
  1115. #endif
  1116. #if defined(HAVE_NEWS)
  1117.    if ( xtexResources.useNEWS ) psfigBeginNEWS(w, cp, fudge_height); 
  1118.    else
  1119. #endif
  1120.    xtexResources.showPostScript = False;
  1121. }
  1122.  
  1123. static void
  1124.   psfigPlotfile(w,cp)
  1125. DviPageWidget w;
  1126. char *cp;
  1127. {
  1128.  
  1129. #if defined(HAVE_GHOSTSCRIPT)
  1130.    if ( xtexResources.useGhostScript ) psfigPlotfileGHOST(w, cp); 
  1131.    else
  1132. #endif
  1133. #if defined(HAVE_DPS)
  1134.    if ( xtexResources.useDPS ) psfigPlotfileDPS(w, cp); 
  1135.    else
  1136. #endif
  1137. #if defined(HAVE_NEWS)
  1138.    if ( xtexResources.useNEWS ) psfigPlotfileNEWS(w, cp); 
  1139.    else
  1140. #endif
  1141.    xtexResources.showPostScript = False;
  1142.  
  1143. }
  1144.  
  1145. static void
  1146.   psfigEnd(w,cp)
  1147. DviPageWidget w;
  1148. char *cp;
  1149. {
  1150.  
  1151. #if defined(HAVE_GHOSTSCRIPT)
  1152.    if ( xtexResources.useGhostScript ) psfigEndGHOST(w, cp); 
  1153.    else
  1154. #endif
  1155. #if defined(HAVE_DPS)
  1156.    if ( xtexResources.useDPS ) psfigEndDPS(w, cp); 
  1157.    else
  1158. #endif
  1159. #if defined(HAVE_NEWS)
  1160.    if ( xtexResources.useNEWS ) psfigEndNEWS(w, cp); 
  1161.    else
  1162. #endif
  1163.    xtexResources.showPostScript = False;
  1164.  
  1165. }
  1166.  
  1167. #ifndef DECWINDOWS
  1168. int
  1169.   _DoAsyncs()
  1170. {
  1171.   /* a ruse for DEC windows specific extension to libX. */
  1172. }
  1173. #endif
  1174.  
  1175. void doSpecial(w, cp)
  1176.      DviPageWidget w;
  1177.      char *cp;
  1178. {
  1179. #define    COMLEN    64
  1180.   char command[COMLEN], *orig_cp;
  1181.   register int len;
  1182.   
  1183.   orig_cp = cp;
  1184.   while (isspace(*cp)) ++cp;
  1185.   len = 0;
  1186.   while (!isspace(*cp) && *cp && len < COMLEN-1) command[len++] = *cp++;
  1187.   command[len] = '\0';
  1188.   if (strcmp(command, "pn") == 0) set_pen_size(w,cp);
  1189.   else if (strcmp(command, "fp") == 0) flush_path(w, 0);
  1190.   else if (strcmp(command, "da") == 0) flush_dashed(w, cp, 0);
  1191.   else if (strcmp(command, "dt") == 0) flush_dashed(w, cp, 1);
  1192.   else if (strcmp(command, "pa") == 0) add_path(w, cp);
  1193.   else if (strcmp(command, "ar") == 0) arc(w, cp, 0);
  1194.   else if (strcmp(command, "ia") == 0) arc(w, cp, 1);
  1195.   else if (strcmp(command, "sp") == 0) flush_spline(w, cp);
  1196.   else if (strcmp(command, "sh") == 0) shade_last(w, cp);
  1197.   else if (strcmp(command, "wh") == 0) shade_last(w, "0");
  1198.   else if (strcmp(command, "bk") == 0) shade_last(w, "1");
  1199.   else if (strcmp(command, "ip") == 0) flush_path(w, 1);
  1200.   else if (strcmp(command, "tx") == 0) Texture(cp);
  1201. #if !defined(HAVE_DPS) && !defined(HAVE_NEWS) && !defined(HAVE_GHOSTSCRIPT)
  1202.   else if (strcmp(command,"ps::[begin]") == 0) psfigBeginOutline(w, cp, FALSE);
  1203.   else if (strncmp(command, "ps:",3) == 0)        /* do nothing */;
  1204. #else
  1205.   else if (strcmp(command, "ps::[begin]") == 0) {
  1206.  
  1207.     if ( xtexResources.showPostScript ) {
  1208.       psfigBegin(w, cp, FALSE);
  1209.     } else {
  1210.       psfigBeginOutline(w, cp, FALSE);
  1211.     }
  1212.   }
  1213.   else if (strcmp(command, "ps::[end]") == 0 ) {
  1214.     if ( xtexResources.showPostScript ) {
  1215.       psfigEnd(w, cp);
  1216.     }
  1217.   }
  1218.   else if (strncmp(command, "ps:",3) == 0 ) {
  1219.     if ( xtexResources.showPostScript ){
  1220.       psfigPlotfile(w, cp);
  1221.     }
  1222.   }
  1223. /* LPC: support for dvitps \special's */
  1224.   else if (strcmp(command, "dvitps:") == 0) {
  1225.       char *cp2;
  1226.       char *keyword = "plotfile";
  1227.  
  1228.       while (isspace(*cp)) ++cp;
  1229.       len = 0;
  1230.       while (!isspace(*cp) && *cp && len < COMLEN-1) command[len++] = *cp++;
  1231.       command[len] = '\0';
  1232.       while (isspace(*cp)) ++cp;
  1233.       if (*cp == '"') cp++;
  1234.       cp2 = &cp[strlen(cp)-1];
  1235.       while ((cp2 > cp) && (isspace(*cp2))) cp2--;
  1236.       if (*cp2 == '"') *cp2 = '\0';
  1237.       if (strcmp(command, "Include0")==0) ;    /* Ignore prolog */
  1238.       else if (strcmp(command, "Include1")==0) {    /* This *is* *it* ! */
  1239.         cp2 = XtMalloc(strlen(cp) + strlen(keyword) + 1);
  1240.         if (cp2 == NULL) return;
  1241.         sprintf(cp2, "%s %s", keyword, cp);
  1242.         psfigPlotfile(w, cp2);
  1243.         free(cp2);
  1244.       }
  1245.       else if (strcmp(command, "Literal")==0) {    /* Arguments or End */
  1246.         if (strncmp(cp, "endTexFig", 9)==0) {
  1247.            psfigEnd(w, cp);
  1248.         } else {    /* Assume startTexFig */
  1249.            psfigBegin(w, cp, FALSE);
  1250.         }
  1251.       }
  1252.   }
  1253. /* LPC: end of support for dvitps \special's */
  1254.  
  1255. /* VK: dvips \special's (generated by \epsfbox{} macro)
  1256.  * special to include a file looks like this:
  1257.  *   PSfile=foo.ps llx=0 lly=0 urx=257 ury=144 rwi=2570
  1258.  * so we need to fudge the command to look like the one dvitps uses
  1259.  * out in order to use the psfig*GHOST() functions.  these functions
  1260.  * expect the values to be in scaled points, so we must convert them.
  1261.  */
  1262. #define PSFILE "psfile="
  1263. #define SPperPT (65536)  /* number of scaled points per point */
  1264.   else if (strncasecmp(command, PSFILE, sizeof(PSFILE)-1) == 0) {
  1265.       char *fn = command + sizeof(PSFILE) - 1;
  1266.       char fake_cp[80];
  1267.       int llx, lly, urx, ury, rwi, rhe;
  1268.  
  1269.       if (sscanf(cp," llx=%d lly=%d urx=%d ury=%d rwi=%d",
  1270.          &llx, &lly, &urx, &ury, &rwi) != 5) {
  1271.       error(0,0,"cannot parse special \"%s\".",orig_cp);
  1272.       return;
  1273.       }
  1274.       /* 
  1275.        * calculate raw height based on scaling of raw width, since 
  1276.        * dvips special doesn't give it.  this assumes the image was 
  1277.        * scaled the same in both horizontal and vertical directions.
  1278.        */
  1279.       rhe = (rwi/(urx - llx)) * (ury - lly);
  1280.       /* scale the values to match output from \psfig{} */
  1281.       llx *= SPperPT;
  1282.       lly *= SPperPT;
  1283.       urx *= SPperPT;
  1284.       ury *= SPperPT;
  1285.       rwi *= SPperPT / 10;
  1286.       rhe *= SPperPT / 10;
  1287.       sprintf(fake_cp," %d %d %d %d %d %d", rwi, rhe, llx, lly, urx, ury);
  1288.       if (xtexResources.showPostScript) {
  1289.     psfigBegin(w, fake_cp, TRUE);
  1290.     sprintf(fake_cp,"plotfile %s", fn);
  1291.     psfigPlotfile(w, fake_cp);
  1292.     psfigEnd(w, "");
  1293.       } else {            /* don't show postscript */
  1294.       psfigBeginOutline(w, fake_cp, TRUE);
  1295.       }
  1296.   }
  1297. #undef PSFILE
  1298. #undef SPperPT
  1299. /* VK: end dvips handling */
  1300. #endif
  1301.   else if (strncmp(command, "ln03", 4) == 0)         /* do nothing */;
  1302.   else if (strncmp(command, "xtex:", 7) == 0) registerActionProc(w, cp) ;
  1303.   else {
  1304.     error(0,0, "special \"%s\" not implemented", orig_cp);
  1305.   }
  1306. }
  1307.  
  1308.