/contrib/groff/src/devices/xditview/draw.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 699 lines · 592 code · 79 blank · 28 comment · 123 complexity · 380d1b35d4444cea835b7b1456388d50 MD5 · raw file

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