home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / xditview / draw.c < prev    next >
C/C++ Source or Header  |  1993-03-30  |  15KB  |  722 lines

  1. /*
  2.  * draw.c
  3.  *
  4.  * accept dvi function calls and translate to X
  5.  */
  6.  
  7. #include <X11/Xos.h>
  8. #include <X11/IntrinsicP.h>
  9. #include <X11/StringDefs.h>
  10. #include <stdio.h>
  11. #include <ctype.h>
  12. #include <math.h>
  13.  
  14. /* math.h on a Sequent doesn't define M_PI, apparently */
  15. #ifndef M_PI
  16. #define M_PI    3.14159265358979323846
  17. #endif
  18.  
  19. #include "DviP.h"
  20.  
  21. #define DeviceToX(dw, n) ((int)((n) * (dw)->dvi.scale_factor + .5))
  22. #define XPos(dw) (DeviceToX((dw), (dw)->dvi.state->x - \
  23.                   (dw)->dvi.text_device_width) + (dw)->dvi.text_x_width)
  24. #define YPos(dw) (DeviceToX((dw), (dw)->dvi.state->y))
  25.  
  26. static int FakeCharacter();
  27.  
  28. HorizontalMove(dw, delta)
  29.     DviWidget    dw;
  30.     int        delta;
  31. {
  32.     dw->dvi.state->x += delta;
  33. }
  34.  
  35. HorizontalGoto(dw, NewPosition)
  36.     DviWidget    dw;
  37.     int        NewPosition;
  38. {
  39.     dw->dvi.state->x = NewPosition;
  40. }
  41.  
  42. VerticalMove(dw, delta)
  43.     DviWidget    dw;
  44.     int        delta;
  45. {
  46.     dw->dvi.state->y += delta;
  47. }
  48.  
  49. VerticalGoto(dw, NewPosition)
  50.     DviWidget    dw;
  51.     int        NewPosition;
  52. {
  53.     dw->dvi.state->y = NewPosition;
  54. }
  55.  
  56. AdjustCacheDeltas (dw)
  57.     DviWidget    dw;
  58. {
  59.     int extra;
  60.     int nadj;
  61.     int i;
  62.  
  63.     nadj = 0;
  64.     extra = DeviceToX(dw, dw->dvi.text_device_width)
  65.         - dw->dvi.text_x_width;
  66.     if (extra == 0)
  67.         return;
  68.     for (i = 0; i <= dw->dvi.cache.index; i++)
  69.         if (dw->dvi.cache.adjustable[i])
  70.             ++nadj;
  71.     if (nadj == 0)
  72.         return;
  73.     dw->dvi.text_x_width += extra;
  74.     for (i = 0; i <= dw->dvi.cache.index; i++)
  75.         if (dw->dvi.cache.adjustable[i]) {
  76.             int x;
  77.             int *deltap;
  78.  
  79.             x = extra/nadj;
  80.             deltap = &dw->dvi.cache.cache[i].delta;
  81. #define MIN_DELTA 2
  82.             if (*deltap > 0 && x + *deltap < MIN_DELTA) {
  83.                 x = MIN_DELTA - *deltap;
  84.                 if (x <= 0)
  85.                     *deltap = MIN_DELTA;
  86.                 else
  87.                     x = 0;
  88.             }
  89.             else
  90.                 *deltap += x;
  91.             extra -= x;
  92.             --nadj;
  93.             dw->dvi.cache.adjustable[i] = 0;
  94.         }
  95. }
  96.  
  97. FlushCharCache (dw)
  98.     DviWidget    dw;
  99. {
  100.     if (dw->dvi.cache.char_index != 0) {
  101.         AdjustCacheDeltas (dw);
  102.         XDrawText (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  103.                dw->dvi.cache.start_x, dw->dvi.cache.start_y,
  104.                dw->dvi.cache.cache, dw->dvi.cache.index + 1);
  105.     }    
  106.     dw->dvi.cache.index = 0;
  107.     dw->dvi.cache.max = DVI_TEXT_CACHE_SIZE;
  108. #if 0
  109.     if (dw->dvi.noPolyText)
  110.         dw->dvi.cache.max = 1;
  111. #endif
  112.     dw->dvi.cache.char_index = 0;
  113.     dw->dvi.cache.cache[0].nchars = 0;
  114.     dw->dvi.cache.start_x = dw->dvi.cache.x    = XPos (dw);
  115.     dw->dvi.cache.start_y = dw->dvi.cache.y = YPos (dw);
  116. }
  117.  
  118. Newline (dw)
  119.     DviWidget    dw;
  120. {
  121.     FlushCharCache (dw);
  122.     dw->dvi.text_x_width = dw->dvi.text_device_width = 0;
  123.     dw->dvi.word_flag = 0;
  124. }
  125.  
  126. Word (dw)
  127.     DviWidget    dw;
  128. {
  129.     dw->dvi.word_flag = 1;
  130. }
  131.  
  132. #define charWidth(fi,c) (\
  133.     (fi)->per_char ?\
  134.     (fi)->per_char[(c) - (fi)->min_char_or_byte2].width\
  135.     :\
  136.     (fi)->max_bounds.width\
  137. )
  138.  
  139.  
  140. static
  141. int charExists (fi, c)
  142.     XFontStruct    *fi;
  143.     int        c;
  144. {
  145.     XCharStruct *p;
  146.  
  147.     if (fi->per_char == NULL ||
  148.         c < fi->min_char_or_byte2 || c > fi->max_char_or_byte2)
  149.         return 0;
  150.     p = fi->per_char + (c - fi->min_char_or_byte2);
  151.     return (p->lbearing != 0 || p->rbearing != 0 || p->width != 0
  152.         || p->ascent != 0 || p->descent != 0 || p->attributes != 0);
  153. }
  154.  
  155. static
  156. DoCharacter (dw, c, wid)
  157.     DviWidget dw;
  158.     int c;
  159.     int wid;    /* width in device units */
  160. {
  161.     register XFontStruct    *font;
  162.     register XTextItem    *text;
  163.     int    x, y;
  164.     
  165.     x = XPos(dw);
  166.     y = YPos(dw);
  167.  
  168.     /*
  169.      * quick and dirty extents calculation:
  170.      */
  171.     if (!(y + 24 >= dw->dvi.extents.y1
  172.           && y - 24 <= dw->dvi.extents.y2
  173. #if 0
  174.           && x + 24 >= dw->dvi.extents.x1
  175.           && x - 24 <= dw->dvi.extents.x2
  176. #endif
  177.         ))
  178.         return;
  179.     
  180.     if (y != dw->dvi.cache.y
  181.         || dw->dvi.cache.char_index >= DVI_CHAR_CACHE_SIZE) {
  182.         FlushCharCache (dw);
  183.         x = dw->dvi.cache.x;
  184.     }
  185.     /*
  186.      * load a new font, if the current block is not empty,
  187.      * step to the next.
  188.      */
  189.     if (dw->dvi.cache.font_size != dw->dvi.state->font_size ||
  190.         dw->dvi.cache.font_number != dw->dvi.state->font_number)
  191.     {
  192.         dw->dvi.cache.font_size = dw->dvi.state->font_size;
  193.         dw->dvi.cache.font_number = dw->dvi.state->font_number;
  194.         dw->dvi.cache.font = QueryFont (dw,
  195.                         dw->dvi.cache.font_number,
  196.                         dw->dvi.cache.font_size);
  197.         if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
  198.             ++dw->dvi.cache.index;
  199.             if (dw->dvi.cache.index >= dw->dvi.cache.max)
  200.                 FlushCharCache (dw);
  201.             dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
  202.             dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
  203.         }
  204.     }
  205.     if (x != dw->dvi.cache.x || dw->dvi.word_flag) {
  206.         if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
  207.             ++dw->dvi.cache.index;
  208.             if (dw->dvi.cache.index >= dw->dvi.cache.max)
  209.                 FlushCharCache (dw);
  210.             dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
  211.         }
  212.         dw->dvi.cache.adjustable[dw->dvi.cache.index]
  213.             = dw->dvi.word_flag;
  214.         dw->dvi.word_flag = 0;
  215.     }
  216.     font = dw->dvi.cache.font;
  217.     text = &dw->dvi.cache.cache[dw->dvi.cache.index];
  218.     if (text->nchars == 0) {
  219.         text->chars = &dw->dvi.cache.char_cache[dw->dvi.cache.char_index];
  220.         text->delta = x - dw->dvi.cache.x;
  221.         if (font != dw->dvi.font) {
  222.             text->font = font->fid;
  223.             dw->dvi.font = font;
  224.         } else
  225.             text->font = None;
  226.         dw->dvi.cache.x += text->delta;
  227.     }
  228.     if (charExists(font, c)) {
  229.         int w;
  230.         dw->dvi.cache.char_cache[dw->dvi.cache.char_index++] = (char) c;
  231.         ++text->nchars;
  232.         w = charWidth(font, c);
  233.         dw->dvi.cache.x += w;
  234.         if (wid != 0) {
  235.             dw->dvi.text_x_width += w;
  236.             dw->dvi.text_device_width += wid;
  237.         }
  238.     }
  239. }
  240.  
  241. static
  242. int FindCharWidth (dw, buf, widp)
  243.     DviWidget dw;
  244.     char *buf;
  245.     int *widp;
  246. {
  247.     int maxpos;
  248.     int i;
  249.  
  250.     if (dw->dvi.device_font == 0
  251.         || dw->dvi.state->font_number != dw->dvi.device_font_number) {
  252.         dw->dvi.device_font_number = dw->dvi.state->font_number;
  253.         dw->dvi.device_font
  254.             = QueryDeviceFont (dw, dw->dvi.device_font_number);
  255.     }
  256.     if (dw->dvi.device_font
  257.         && device_char_width (dw->dvi.device_font,
  258.                   dw->dvi.state->font_size, buf, widp))
  259.         return 1;
  260.  
  261.     maxpos = MaxFontPosition (dw);
  262.     for (i = 1; i <= maxpos; i++) {
  263.         DeviceFont *f = QueryDeviceFont (dw, i);
  264.         if (f && device_font_special (f)
  265.             && device_char_width (f, dw->dvi.state->font_size,
  266.                       buf, widp)) {
  267.             dw->dvi.state->font_number = i;
  268.             return 1;
  269.         }
  270.     }
  271.     return 0;
  272. }
  273.  
  274. /* Return the width of the character in device units. */
  275.  
  276. int PutCharacter (dw, buf)
  277.     DviWidget dw;
  278.     char *buf;
  279. {
  280.     int        prevFont;
  281.     int        c = -1;
  282.     int        wid = 0;
  283.     DviCharNameMap    *map;
  284.  
  285.     if (!dw->dvi.display_enable)
  286.         return 0;    /* The width doesn't matter in this case. */
  287.     prevFont = dw->dvi.state->font_number;
  288.     if (!FindCharWidth (dw, buf, &wid))
  289.         return 0;
  290.     map = QueryFontMap (dw, dw->dvi.state->font_number);
  291.     if (map)
  292.         c = DviCharIndex (map, buf);
  293.     if (c >= 0)
  294.         DoCharacter (dw, c, wid);
  295.     else
  296.         (void) FakeCharacter (dw, buf, wid);
  297.     dw->dvi.state->font_number = prevFont;
  298.     return wid;
  299. }
  300.  
  301. /* Return 1 if we can fake it; 0 otherwise. */
  302.  
  303. static
  304. int FakeCharacter (dw, buf, wid)
  305.     DviWidget dw;
  306.     char *buf;
  307.     int wid;
  308. {
  309.     int oldx, oldw;
  310.     char ch[2];
  311.     char *chars = 0;
  312.  
  313.     if (buf[0] == '\0' || buf[1] == '\0' || buf[2] != '\0')
  314.         return 0;
  315. #define pack2(c1, c2) (((c1) << 8) | (c2))
  316.  
  317.     switch (pack2(buf[0], buf[1])) {
  318.     case pack2('f', 'i'):
  319.         chars = "fi";
  320.         break;
  321.     case pack2('f', 'l'):
  322.         chars = "fl";
  323.         break;
  324.     case pack2('f', 'f'):
  325.         chars = "ff";
  326.         break;
  327.     case pack2('F', 'i'):
  328.         chars = "ffi";
  329.         break;
  330.     case pack2('F', 'l'):
  331.         chars = "ffl";
  332.         break;
  333.     }
  334.     if (!chars)
  335.         return 0;
  336.     oldx = dw->dvi.state->x;
  337.     oldw = dw->dvi.text_device_width;
  338.     ch[1] = '\0';
  339.     for (; *chars; chars++) {
  340.         ch[0] = *chars;
  341.         dw->dvi.state->x += PutCharacter (dw, ch);
  342.     }
  343.     dw->dvi.state->x = oldx;
  344.     dw->dvi.text_device_width = oldw + wid;
  345.     return 1;
  346. }
  347.  
  348. PutNumberedCharacter (dw, c)
  349.     DviWidget dw;
  350.     int c;
  351. {
  352.     char *name;
  353.     int wid;
  354.     DviCharNameMap    *map;
  355.  
  356.     if (!dw->dvi.display_enable)
  357.         return;
  358.  
  359.     if (dw->dvi.device_font == 0
  360.         || dw->dvi.state->font_number != dw->dvi.device_font_number) {
  361.         dw->dvi.device_font_number = dw->dvi.state->font_number;
  362.         dw->dvi.device_font
  363.             = QueryDeviceFont (dw, dw->dvi.device_font_number);
  364.     }
  365.     
  366.     if (dw->dvi.device_font == 0
  367.         || !device_code_width (dw->dvi.device_font,
  368.                    dw->dvi.state->font_size, c, &wid))
  369.         return;
  370.     if (dw->dvi.native) {
  371.         DoCharacter (dw, c, wid);
  372.         return;
  373.     }
  374.     map = QueryFontMap (dw, dw->dvi.state->font_number);
  375.     if (!map)
  376.         return;
  377.     for (name = device_name_for_code (dw->dvi.device_font, c);
  378.          name;
  379.          name = device_name_for_code ((DeviceFont *)0, c)) {
  380.         int code = DviCharIndex (map, name);
  381.         if (code >= 0) {
  382.             DoCharacter (dw, code, wid);
  383.             break;
  384.         }
  385.         if (FakeCharacter (dw, name, wid))
  386.             break;
  387.     }
  388. }
  389.  
  390. ClearPage (dw)
  391.     DviWidget    dw;
  392. {
  393.     XClearWindow (XtDisplay (dw), XtWindow (dw));
  394. }
  395.  
  396. static
  397. setGC (dw)
  398.     DviWidget    dw;
  399. {
  400.     int desired_line_width;
  401.     
  402.     if (dw->dvi.line_thickness < 0)
  403.         desired_line_width = (int)(((double)dw->dvi.device_resolution
  404.                         * dw->dvi.state->font_size)
  405.                        / (10.0*72.0*dw->dvi.sizescale));
  406.     else
  407.         desired_line_width = dw->dvi.line_thickness;
  408.     
  409.     if (desired_line_width != dw->dvi.line_width) {
  410.         XGCValues values;
  411.         values.line_width = DeviceToX(dw, desired_line_width);
  412.         if (values.line_width == 0)
  413.             values.line_width = 1;
  414.         XChangeGC(XtDisplay (dw), dw->dvi.normal_GC,
  415.               GCLineWidth, &values);
  416.         dw->dvi.line_width = desired_line_width;
  417.     }
  418. }
  419.  
  420. static
  421. setFillGC (dw)
  422.     DviWidget    dw;
  423. {
  424.     int fill_type;
  425.     
  426.     if (dw->dvi.fill == DVI_FILL_MAX)
  427.         fill_type = DVI_FILL_BLACK;
  428.     else if (dw->dvi.fill == 0)
  429.         fill_type = DVI_FILL_WHITE;
  430.     else
  431.         fill_type = DVI_FILL_GRAY;
  432.     if (dw->dvi.fill_type != fill_type) {
  433.         XGCValues values;
  434.         switch (fill_type) {
  435.         case DVI_FILL_WHITE:
  436.             values.foreground = dw->dvi.background;
  437.             values.fill_style = FillSolid;
  438.             break;
  439.         case DVI_FILL_BLACK:
  440.             values.foreground = dw->dvi.foreground;
  441.             values.fill_style = FillSolid;
  442.             break;
  443.         case DVI_FILL_GRAY:
  444.             values.foreground = dw->dvi.foreground;
  445.             values.fill_style = FillOpaqueStippled;
  446.             break;
  447.         }
  448.         XChangeGC(XtDisplay (dw), dw->dvi.fill_GC,
  449.               GCFillStyle|GCForeground,
  450.               &values);
  451.         dw->dvi.fill_type = fill_type;
  452.     }
  453. }
  454.  
  455. DrawLine (dw, x, y)
  456.     DviWidget    dw;
  457.     int        x, y;
  458. {
  459.     int xp, yp;
  460.  
  461.     AdjustCacheDeltas (dw);
  462.     setGC (dw);
  463.     xp = XPos (dw);
  464.     yp = YPos (dw);
  465.     XDrawLine (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  466.            xp, yp,
  467.            xp + DeviceToX (dw, x), yp + DeviceToX (dw, y));
  468. }
  469.  
  470. DrawCircle (dw, diam)
  471.     DviWidget    dw;
  472.     int        diam;
  473. {
  474.     int d;
  475.  
  476.     AdjustCacheDeltas (dw);
  477.     setGC (dw);
  478.     d = DeviceToX (dw, diam);
  479.     XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  480.           XPos (dw), YPos (dw) - d/2,
  481.           d, d, 0, 64*360);
  482. }
  483.  
  484. DrawFilledCircle (dw, diam)
  485.     DviWidget    dw;
  486.     int        diam;
  487. {
  488.     int d;
  489.  
  490.     AdjustCacheDeltas (dw);
  491.     setFillGC (dw);
  492.     d = DeviceToX (dw, diam);
  493.     XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
  494.           XPos (dw), YPos (dw) - d/2,
  495.           d, d, 0, 64*360);
  496. }
  497.  
  498. DrawEllipse (dw, a, b)
  499.     DviWidget    dw;
  500.     int        a, b;
  501. {
  502.     AdjustCacheDeltas (dw);
  503.     setGC (dw);
  504.     XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  505.           XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
  506.           DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
  507. }
  508.  
  509. DrawFilledEllipse (dw, a, b)
  510.     DviWidget    dw;
  511.     int        a, b;
  512. {
  513.     AdjustCacheDeltas (dw);
  514.     setFillGC (dw);
  515.     XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
  516.           XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
  517.           DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
  518. }
  519.  
  520. DrawArc (dw, x0, y0, x1, y1)
  521.     DviWidget    dw;
  522.     int        x0, y0, x1, y1;
  523. {
  524.     int angle1, angle2;
  525.     int rad = (int)((sqrt ((double)x0*x0 + (double)y0*y0)
  526.             + sqrt ((double)x1*x1 + (double)y1*y1) + 1.0)/2.0);
  527.     if ((x0 == 0 && y0 == 0) || (x1 == 0 && y1 == 0))
  528.         return;
  529.     angle1 = (int)(atan2 ((double)y0, (double)-x0)*180.0*64.0/M_PI);
  530.     angle2 = (int)(atan2 ((double)-y1, (double)x1)*180.0*64.0/M_PI);
  531.     
  532.     angle2 -= angle1;
  533.     if (angle2 < 0)
  534.         angle2 += 64*360;
  535.     
  536.     AdjustCacheDeltas (dw);
  537.     setGC (dw);
  538.  
  539.     rad = DeviceToX (dw, rad);
  540.     XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  541.           XPos (dw) + DeviceToX (dw, x0) - rad,
  542.           YPos (dw) + DeviceToX (dw, y0) - rad,
  543.           rad*2, rad*2, angle1, angle2);
  544. }
  545.  
  546. DrawPolygon (dw, v, n)
  547.     DviWidget    dw;
  548.     int        *v;
  549.     int        n;
  550. {
  551.     XPoint *p;
  552.     int i;
  553.     int dx, dy;
  554.     
  555.     n /= 2;
  556.     
  557.     AdjustCacheDeltas (dw);
  558.     setGC (dw);
  559.     p = (XPoint *)XtMalloc((n + 2)*sizeof(XPoint));
  560.     p[0].x = XPos (dw);
  561.     p[0].y = YPos (dw);
  562.     dx = 0;
  563.     dy = 0;
  564.     for (i = 0; i < n; i++) {
  565.         dx += v[2*i];
  566.         p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
  567.         dy += v[2*i + 1];
  568.         p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
  569.     }
  570.     p[n+1].x = p[0].x;
  571.     p[n+1].y = p[0].y;
  572.     XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  573.            p, n + 2, CoordModeOrigin);
  574.     XtFree((char *)p);
  575. }
  576.  
  577.  
  578. DrawFilledPolygon (dw, v, n)
  579.     DviWidget    dw;
  580.     int        *v;
  581.     int        n;
  582. {
  583.     XPoint *p;
  584.     int i;
  585.     int dx, dy;
  586.     
  587.     n /= 2;
  588.     if (n < 2)
  589.         return;
  590.     
  591.     AdjustCacheDeltas (dw);
  592.     setFillGC (dw);
  593.     p = (XPoint *)XtMalloc((n + 1)*sizeof(XPoint));
  594.     p[0].x = XPos (dw);
  595.     p[0].y = YPos (dw);
  596.     dx = 0;
  597.     dy = 0;
  598.     for (i = 0; i < n; i++) {
  599.         dx += v[2*i];
  600.         p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
  601.         dy += v[2*i + 1];
  602.         p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
  603.     }
  604.     XFillPolygon (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
  605.               p, n + 1, Complex, CoordModeOrigin);
  606.     XtFree((char *)p);
  607. }
  608.  
  609. #define POINTS_MAX 10000
  610.  
  611. static
  612. appendPoint(points, pointi, x, y)
  613.     XPoint    *points;
  614.     int    *pointi;
  615.     int    x, y;
  616. {
  617.     if (*pointi < POINTS_MAX) {
  618.         points[*pointi].x = x;
  619.         points[*pointi].y = y;
  620.         *pointi += 1;
  621.     }
  622. }
  623.  
  624. #define FLATNESS 1
  625.  
  626. static
  627. flattenCurve(points, pointi, x2, y2, x3, y3, x4, y4)
  628.     XPoint    *points;
  629.     int    *pointi;
  630.     int    x2, y2, x3, y3, x4, y4;
  631. {
  632.     int x1, y1, dx, dy, n1, n2, n;
  633.  
  634.     x1 = points[*pointi - 1].x;
  635.     y1 = points[*pointi - 1].y;
  636.     
  637.     dx = x4 - x1;
  638.     dy = y4 - y1;
  639.     
  640.     n1 = dy*(x2 - x1) - dx*(y2 - y1);
  641.     n2 = dy*(x3 - x1) - dx*(y3 - y1);
  642.     if (n1 < 0)
  643.         n1 = -n1;
  644.     if (n2 < 0)
  645.         n2 = -n2;
  646.     n = n1 > n2 ? n1 : n2;
  647.  
  648.     if (n*n / (dy*dy + dx*dx) <= FLATNESS*FLATNESS)
  649.         appendPoint (points, pointi, x4, y4);
  650.     else {
  651.         flattenCurve (points, pointi,
  652.                   (x1 + x2)/2, (y1 + y2)/2,
  653.                   (x1 + x2*2 + x3)/4, (y1 + y2*2 + y3)/4,
  654.                   (x1 +3*x2 + 3*x3 + x4)/8, (y1 +3*y2 + 3*y3 + y4)/8);
  655.         flattenCurve (points, pointi,
  656.                   (x2 + x3*2 + x4)/4, (y2 + y3*2 + y4)/4,
  657.                   (x3 + x4)/2, (y3 + y4)/2,
  658.                   x4, y4);
  659.     }
  660. }
  661.  
  662.  
  663. DrawSpline (dw, v, n)
  664.     DviWidget    dw;
  665.     int        *v;
  666.     int        n;
  667. {
  668.     int sx, sy, tx, ty;
  669.     int ox, oy, dx, dy;
  670.     int i;
  671.     int pointi;
  672.     XPoint points[POINTS_MAX];
  673.     
  674.     if (n == 0 || (n & 1) != 0)
  675.         return;
  676.     AdjustCacheDeltas (dw);
  677.     setGC (dw);
  678.     ox = XPos (dw);
  679.     oy = YPos (dw);
  680.     dx = v[0];
  681.     dy = v[1];
  682.     sx = ox;
  683.     sy = oy;
  684.     tx = sx + DeviceToX (dw, dx);
  685.     ty = sy + DeviceToX (dw, dy);
  686.     
  687.     pointi = 0;
  688.     
  689.     appendPoint (points, &pointi, sx, sy);
  690.     appendPoint (points, &pointi, (sx + tx)/2, (sy + ty)/2);
  691.     
  692.     for (i = 2; i < n; i += 2) {
  693.         int ux = ox + DeviceToX (dw, dx += v[i]);
  694.         int uy = oy + DeviceToX (dw, dy += v[i+1]);
  695.         flattenCurve (points, &pointi,
  696.                    (sx + tx*5)/6, (sy + ty*5)/6,
  697.                    (tx*5 + ux)/6, (ty*5 + uy)/6,
  698.                    (tx + ux)/2, (ty + uy)/2);
  699.         sx = tx;
  700.         sy = ty;
  701.         tx = ux;
  702.         ty = uy;
  703.     }
  704.     
  705.     appendPoint (points, &pointi, tx, ty);
  706.     
  707.     XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  708.            points, pointi, CoordModeOrigin);
  709. }
  710.  
  711.  
  712. /*
  713. Local Variables:
  714. c-indent-level: 8
  715. c-continued-statement-offset: 8
  716. c-brace-offset: -8
  717. c-argdecl-indent: 8
  718. c-label-offset: -8
  719. c-tab-always-indent: nil
  720. End:
  721. */
  722.