mi_zerolin.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. /* This file is part of the GNU libxmi package.
  2. Copyright (C) 1985, 1986, 1987, 1988, 1989, X Consortium. For an
  3. associated permission notice, see the accompanying file README-X.
  4. GNU enhancements Copyright (C) 1998, 1999, 2000, 2005, Free Software
  5. Foundation, Inc.
  6. The GNU libxmi package is free software. You may redistribute it
  7. and/or modify it under the terms of the GNU General Public License as
  8. published by the Free Software foundation; either version 2, or (at your
  9. option) any later version.
  10. The GNU libxmi package is distributed in the hope that it will be
  11. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. General Public License for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with the GNU plotutils package; see the file COPYING. If not, write to
  16. the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
  17. Boston, MA 02110-1301, USA. */
  18. /* This module contains the miZeroLine() and miZeroDash() functions. They
  19. a rasterize single-pixel (i.e., `zero-width') Bresenham polyline, either
  20. solid or dashed.
  21. The cap mode and join mode in the graphics context are ignored, except
  22. that if the cap mode is MI_CAP_NOT_LAST, the final pixel of the polyline
  23. is omitted.
  24. All painting goes through the low-level MI_PAINT_SPANS() and
  25. MI_COPY_AND_PAINT_SPANS() macros. */
  26. /* Historical note: this is a merger of MI code from X11, written by Ken
  27. Whaley, with low-level X11 CFB (color frame-buffer) code, of unknown
  28. authorship. (I wrote Ken, and he remembers writing the monochrome frame
  29. buffer code, but not the color code.) That's because the X11 MI code
  30. included miZeroLine(), but not miZeroDash(). I based the latter on the
  31. CFB routines. I needed to hack them extensively so that they would
  32. generate a list of spans to paint. I also removed clipping code. --rsm */
  33. #include "sys-defines.h"
  34. #include "extern.h"
  35. #include "xmi.h"
  36. #include "mi_spans.h"
  37. #include "mi_gc.h"
  38. #include "mi_api.h"
  39. #include "mi_line.h"
  40. /* Comment on drawing solid lines (from Ken Whaley):
  41. NON-SLOPED LINES
  42. Horizontal lines are always drawn left to right; we have to move the
  43. endpoints right by one after they're swapped. Vertical lines are always
  44. drawn top to bottom (y-increasing). This requires adding one to the
  45. y-coordinate of each endpoint after swapping. */
  46. /* forward references */
  47. static void cfbBresD (miPaintedSet *paintedSet, const miGC *pGC, int *pdashNum, int *pdashIndex, const unsigned int *pDash, int numInDashList, int *pdashOffset, bool isDoubleDash, int signdx, int signdy, int axis, int x1, int y1, int e, int e1, int e2, int len);
  48. static void cfbBresS (miPaintedSet *paintedSet, const miGC *pGC, int signdx, int signdy, int axis, int x1, int y1, int e, int e1, int e2, int len);
  49. static void cfbHorzS (miPaintedSet *paintedSet, const miGC *pGC, int x1, int y1, int len);
  50. static void cfbVertS (miPaintedSet *paintedSet, const miGC *pGC, int x1, int y1, int len);
  51. /* Macro for painting a single point. Used for ending line segments. */
  52. #define MI_PAINT_POINT(paintedSet, pixel, xx, yy) \
  53. {\
  54. miPoint *point;\
  55. unsigned int *width;\
  56. point = (miPoint *)mi_xmalloc(sizeof(miPoint));\
  57. width = (unsigned int *)mi_xmalloc(sizeof(unsigned int));\
  58. *width = 1;\
  59. point->x = xx;\
  60. point->y = yy;\
  61. MI_PAINT_SPANS(paintedSet, pixel, 1, point, width)\
  62. }
  63. /* Macro for generating a list of spans, used when the successive points on
  64. a Bresenham line are generated. Assumes the availability of working
  65. storage, accessed via pointers `ppt' and `pwidths', and also variables
  66. numSpans (initted to 0), firstspan (initted to true), and ycurr. The
  67. arrays should be at least as large as the longest generated Bresenham
  68. line segment. */
  69. #define MI_ADD_POINT(xx, yy, ppt, pwidth, numSpans, ycurr, firstspan, signdy) \
  70. {\
  71. if (!firstspan && yy == ycurr)\
  72. {\
  73. int xdelta = xx - ppt->x;\
  74. if (xdelta < 0)\
  75. {\
  76. (*pwidth) -= xdelta;\
  77. ppt->x = xx;\
  78. }\
  79. else if (xdelta > 0)\
  80. { \
  81. unsigned int widthcurr = *pwidth; \
  82. (*pwidth) = UMAX(widthcurr, (unsigned int)(1 + xdelta));\
  83. } \
  84. }\
  85. else\
  86. {\
  87. if (!firstspan)\
  88. {\
  89. ppt += signdy;\
  90. pwidth += signdy;\
  91. }\
  92. else\
  93. firstspan = false;\
  94. ppt->x = xx;\
  95. ppt->y = yy;\
  96. *pwidth = 1;\
  97. ycurr = yy;\
  98. ++numSpans;\
  99. }\
  100. }
  101. /*
  102. * Draw a solid Bresenham polyline, i.e. a `zero-width' solid polyline,
  103. * in paint type #1.
  104. */
  105. /* ARGS: mode = Origin or Previous
  106. npt = number of points
  107. pPts = point array */
  108. void
  109. miZeroLine (miPaintedSet *paintedSet, const miGC *pGC, miCoordMode mode, int npt, const miPoint *pPts)
  110. {
  111. const miPoint *ppt; /* pointer to point within array */
  112. /* temporaries */
  113. int xstart, ystart;
  114. int x1, x2;
  115. int y1, y2;
  116. /* ensure we have >=1 points */
  117. if (npt <= 0)
  118. return;
  119. /* loop through points, drawing a solid Bresenham segment for each line
  120. segment */
  121. ppt = pPts;
  122. xstart = ppt->x;
  123. ystart = ppt->y;
  124. x2 = xstart;
  125. y2 = ystart;
  126. while (--npt)
  127. {
  128. x1 = x2;
  129. y1 = y2;
  130. ++ppt;
  131. x2 = ppt->x;
  132. y2 = ppt->y;
  133. if (mode == MI_COORD_MODE_PREVIOUS)
  134. /* convert from relative coordinates */
  135. {
  136. x2 += x1;
  137. y2 += y1;
  138. }
  139. if (x1 == x2) /* vertical line */
  140. {
  141. if (y1 > y2)
  142. /* make line go top to bottom, keeping endpoint semantics */
  143. {
  144. int tmp;
  145. tmp = y2;
  146. y2 = y1 + 1;
  147. y1 = tmp + 1;
  148. }
  149. /* draw line */
  150. if (y1 != y2)
  151. cfbVertS (paintedSet, pGC, x1, y1, y2 - y1);
  152. /* restore final point */
  153. y2 = ppt->y;
  154. }
  155. else if (y1 == y2) /* horizontal line */
  156. {
  157. if (x1 > x2)
  158. /* force line from left to right, keeping endpoint semantics */
  159. {
  160. int tmp;
  161. tmp = x2;
  162. x2 = x1 + 1;
  163. x1 = tmp + 1;
  164. }
  165. /* draw line */
  166. if (x1 != x2)
  167. cfbHorzS (paintedSet, pGC, x1, y1, x2 - x1);
  168. /* restore final point */
  169. x2 = ppt->x;
  170. }
  171. else /* sloped line */
  172. {
  173. int adx; /* abs values of dx and dy */
  174. int ady;
  175. int signdx; /* sign of dx and dy */
  176. int signdy;
  177. int e, e1, e2; /* Bresenham error and increments */
  178. int axis; /* major axis */
  179. int len; /* length of segment */
  180. AbsDeltaAndSign(x2, x1, adx, signdx);
  181. AbsDeltaAndSign(y2, y1, ady, signdy);
  182. if (adx > ady)
  183. {
  184. axis = X_AXIS;
  185. e1 = ady << 1;
  186. e2 = e1 - (adx << 1);
  187. e = e1 - adx;
  188. FIXUP_X_MAJOR_ERROR(e, signdx, signdy);
  189. }
  190. else
  191. {
  192. axis = Y_AXIS;
  193. e1 = adx << 1;
  194. e2 = e1 - (ady << 1);
  195. e = e1 - ady;
  196. FIXUP_Y_MAJOR_ERROR(e, signdx, signdy);
  197. }
  198. /* we have Bresenham parameters and two points, so all we need to
  199. do now is draw */
  200. if (axis == X_AXIS)
  201. len = adx;
  202. else
  203. len = ady;
  204. cfbBresS (paintedSet, pGC,
  205. signdx, signdy, axis, x1, y1,
  206. e, e1, e2, len);
  207. } /* sloped line */
  208. } /* while (--npt) */
  209. /* Paint the last point if the end style isn't CapNotLast. (I.e. assume
  210. that a round/butt/projecting/triangular cap that is one pixel wide is
  211. the same as the single pixel of the endpoint.) */
  212. if (pGC->capStyle != (int)MI_CAP_NOT_LAST
  213. &&
  214. (xstart != x2 || ystart != y2 || ppt == pPts + 1))
  215. MI_PAINT_POINT(paintedSet, pGC->pixels[1], x2, y2)
  216. }
  217. /*
  218. * Draw a dashed Bresenham polyline, i.e. a `zero-width' dashed polyline.
  219. */
  220. /* ARGS: mode = Origin or Previous
  221. npt = number of points
  222. pPts = point array */
  223. void
  224. miZeroDash (miPaintedSet *paintedSet, const miGC *pGC, miCoordMode mode, int npt, const miPoint *pPts)
  225. {
  226. const miPoint *ppt; /* pointer to current point */
  227. /* temporaries */
  228. int xstart, ystart;
  229. int x1, x2, y1, y2;
  230. const unsigned int *pDash;
  231. int dashNum, dashIndex;
  232. int dashOffset;
  233. int numInDashList;
  234. bool isDoubleDash;
  235. /* ensure we have >=1 points */
  236. if (npt <= 0)
  237. return;
  238. /* perform initial offsetting into the dash array; compute dash values */
  239. pDash = pGC->dash;
  240. numInDashList = pGC->numInDashList;
  241. isDoubleDash = (pGC->lineStyle == (int)MI_LINE_DOUBLE_DASH ? true : false);
  242. dashNum = 0;
  243. dashIndex = 0;
  244. dashOffset = 0;
  245. miStepDash (pGC->dashOffset, &dashNum, &dashIndex,
  246. pDash, numInDashList, &dashOffset);
  247. /* loop through points, drawing a dashed Bresenham segment for each line
  248. segment of nonzero length */
  249. ppt = pPts;
  250. xstart = ppt->x;
  251. ystart = ppt->y;
  252. x2 = xstart;
  253. y2 = ystart;
  254. while (--npt)
  255. {
  256. x1 = x2;
  257. y1 = y2;
  258. ++ppt;
  259. x2 = ppt->x;
  260. y2 = ppt->y;
  261. if (mode == MI_COORD_MODE_PREVIOUS)
  262. /* convert from relative coordinates */
  263. {
  264. x2 += x1;
  265. y2 += y1;
  266. }
  267. /* use Bresenham algorithm for sloped lines (no special treatment for
  268. horizontal or vertical lines, unlike the undashed case) */
  269. {
  270. int adx; /* abs values of dx and dy */
  271. int ady;
  272. int signdx; /* sign of dx and dy */
  273. int signdy;
  274. int e, e1, e2; /* Bresenham error and increments */
  275. int axis; /* major axis */
  276. int len;
  277. AbsDeltaAndSign(x2, x1, adx, signdx);
  278. AbsDeltaAndSign(y2, y1, ady, signdy);
  279. if (adx > ady)
  280. {
  281. axis = X_AXIS;
  282. e1 = ady << 1;
  283. e2 = e1 - (adx << 1);
  284. e = e1 - adx;
  285. len = adx;
  286. FIXUP_X_MAJOR_ERROR(e, signdx, signdy);
  287. }
  288. else
  289. {
  290. axis = Y_AXIS;
  291. e1 = adx << 1;
  292. e2 = e1 - (ady << 1);
  293. e = e1 - ady;
  294. len = ady;
  295. FIXUP_Y_MAJOR_ERROR(e, signdx, signdy);
  296. }
  297. /* we have Bresenham parameters and two points, so all we need to
  298. do now is draw (updating dashNum, dashIndex and dashOffset) */
  299. cfbBresD (paintedSet, pGC,
  300. &dashNum, &dashIndex, pDash, numInDashList,
  301. &dashOffset, isDoubleDash,
  302. signdx, signdy, axis, x1, y1,
  303. e, e1, e2, len);
  304. }
  305. } /* while (nline--) */
  306. /* paint the last point if the end style isn't CapNotLast.
  307. (Assume that a projecting, butt, or round cap that is one
  308. pixel wide is the same as the single pixel of the endpoint.) */
  309. if (pGC->capStyle != (int)MI_CAP_NOT_LAST
  310. &&
  311. (xstart != x2 || ystart != y2 || ppt == pPts + 1))
  312. {
  313. if (dashNum & 1)
  314. {
  315. /* background dash */
  316. if (isDoubleDash)
  317. /* paint, in paint type #0 */
  318. MI_PAINT_POINT(paintedSet, pGC->pixels[0], x2, y2);
  319. }
  320. else
  321. /* foreground dash */
  322. {
  323. /* use a paint type that cycles through 1..(numPixels-1) */
  324. int numPixels = pGC->numPixels;
  325. int paintType = 1 + ((dashNum / 2) % (numPixels - 1));
  326. MI_PAINT_POINT(paintedSet, pGC->pixels[paintType], x2, y2);
  327. }
  328. }
  329. }
  330. /* Internal: draw solid Bresenham line segment, in paint type #1. Called
  331. by miZeroLine(). Endpoint semantics are used, i.e. we paint only len
  332. pixels (i.e. |dx| or |dy| pixels), not including the endpoint. */
  333. /* ARGS: signdx,signdy = signs of directions
  334. axis = major axis (Y_AXIS or X_AXIS)
  335. x1,y1 = initial point
  336. e = error accumulator
  337. e1,e2 = Bresenham increments
  338. len = length of line in pixels */
  339. static void
  340. cfbBresS (miPaintedSet *paintedSet, const miGC *pGC, int signdx, int signdy, int axis, int x1, int y1, int e, int e1, int e2, int len)
  341. {
  342. miPoint *pptInit, *pptLast;
  343. unsigned int *pwidthInit, *pwidthLast;
  344. int x, y;
  345. int e3;
  346. /* variables in span generation code, i.e. in MI_ADD_POINT() */
  347. int numSpans;
  348. int ycurr;
  349. miPoint *ppt;
  350. unsigned int *pwidth;
  351. bool firstspan;
  352. if (len == 0)
  353. return;
  354. /* set up work arrays */
  355. pptInit = (miPoint *)mi_xmalloc(len * sizeof(miPoint));
  356. pwidthInit = (unsigned int *)mi_xmalloc(len * sizeof(unsigned int));
  357. pptLast = pptInit + (len - 1);
  358. pwidthLast = pwidthInit + (len - 1);
  359. /* reset variables used in MI_ADD_POINT() */
  360. numSpans = 0;
  361. ycurr = 0;
  362. firstspan = true;
  363. if (signdy >= 0)
  364. {
  365. ppt = pptInit;
  366. pwidth = pwidthInit;
  367. }
  368. else
  369. {
  370. ppt = pptLast;
  371. pwidth = pwidthLast;
  372. }
  373. e3 = e2 - e1;
  374. e = e - e1; /* make looping easier */
  375. #define BresStep(minor,major) \
  376. {if ((e += e1) >= 0) { e += e3; minor; } major;}
  377. #define Loop_x(counter,store) while (counter--) \
  378. {store; BresStep(y+=signdy,x+=signdx) }
  379. #define Loop_y(counter,store) while (counter--) \
  380. {store; BresStep(x+=signdx, y+=signdy) }
  381. /* point to first point, and generate len pixels */
  382. x = x1;
  383. y = y1;
  384. switch (axis)
  385. {
  386. case X_AXIS:
  387. default:
  388. Loop_x(len, MI_ADD_POINT(x, y, ppt, pwidth, numSpans, ycurr, firstspan, signdy))
  389. break;
  390. case Y_AXIS:
  391. Loop_y(len, MI_ADD_POINT(x, y, ppt, pwidth, numSpans, ycurr, firstspan, signdy))
  392. break;
  393. }
  394. if (numSpans > 0)
  395. {
  396. if (signdy < 0)
  397. /* spans are offset, so shift downward */
  398. {
  399. miPoint *ppt_src = pptLast - (numSpans - 1);
  400. miPoint *ppt_dst = pptInit;
  401. unsigned int *pwidth_src = pwidthLast - (numSpans - 1);
  402. unsigned int *pwidth_dst = pwidthInit;
  403. int count = numSpans;
  404. while (count--)
  405. {
  406. *ppt_dst++ = *ppt_src++;
  407. *pwidth_dst++ = *pwidth_src++;
  408. }
  409. }
  410. MI_PAINT_SPANS(paintedSet, pGC->pixels[1], numSpans, pptInit, pwidthInit)
  411. }
  412. }
  413. /* Internal: draw dashed Bresenham line segment. Called by miZeroDash().
  414. Endpoint semantics are used. */
  415. /* ARGS: pdashNum = absolute dash number
  416. pdashIndx = index into dash array
  417. pDash = dash array
  418. numInDashList = length of dash array
  419. pdashOffset = offset into current dash
  420. signdx,signdy = signs of directions
  421. axis = major axis (Y_AXIS or X_AXIS)
  422. x1,y1 = initial point
  423. e = error accumulator
  424. e1,e2 = Bresenham increments
  425. len = length of line in pixels */
  426. static void
  427. cfbBresD (miPaintedSet *paintedSet, const miGC *pGC, int *pdashNum, int *pdashIndex, const unsigned int *pDash, int numInDashList, int *pdashOffset, bool isDoubleDash, int signdx, int signdy, int axis, int x1, int y1, int e, int e1, int e2, int len)
  428. {
  429. miPoint *pptInit_fg, *pptInit_bg = (miPoint *)NULL;
  430. miPoint *pptLast_fg, *pptLast_bg = (miPoint *)NULL;
  431. unsigned int *pwidthInit_fg, *pwidthInit_bg = (unsigned int *)NULL;
  432. unsigned int *pwidthLast_fg, *pwidthLast_bg = (unsigned int *)NULL;
  433. int x, y;
  434. int e3;
  435. int dashNum, dashIndex;
  436. int dashOffset;
  437. int dashRemaining;
  438. int thisDash;
  439. /* variables in span generation code, i.e. in MI_ADD_POINT() */
  440. int numSpans_fg, numSpans_bg = 0;
  441. int ycurr_fg, ycurr_bg = 0;
  442. miPoint *ppt_fg, *ppt_bg = (miPoint *)NULL;
  443. unsigned int *pwidth_fg, *pwidth_bg = (unsigned int *)NULL;
  444. bool firstspan_fg, firstspan_bg = false;
  445. /* set up work arrays */
  446. pptInit_fg = (miPoint *)mi_xmalloc(len * sizeof(miPoint));
  447. pwidthInit_fg = (unsigned int *)mi_xmalloc(len * sizeof(unsigned int));
  448. pptLast_fg = pptInit_fg + (len - 1);
  449. pwidthLast_fg = pwidthInit_fg + (len - 1);
  450. if (isDoubleDash)
  451. {
  452. pptInit_bg = (miPoint *)mi_xmalloc(len * sizeof(miPoint));
  453. pwidthInit_bg = (unsigned int *)mi_xmalloc(len * sizeof(unsigned int));
  454. pptLast_bg = pptInit_bg + (len - 1);
  455. pwidthLast_bg = pwidthInit_bg + (len - 1);
  456. }
  457. dashNum = *pdashNum; /* absolute number of current dash */
  458. dashIndex = *pdashIndex; /* index of current dash */
  459. dashOffset = *pdashOffset; /* offset into current dash */
  460. dashRemaining = (int)(pDash[dashIndex]) - dashOffset; /* how much is left */
  461. if (len <= (thisDash = dashRemaining))
  462. /* line segment will be solid, not dashed */
  463. {
  464. thisDash = len;
  465. dashRemaining -= len;
  466. }
  467. #define NextDash {\
  468. dashNum++; \
  469. dashIndex++; \
  470. if (dashIndex == numInDashList) \
  471. dashIndex = 0; \
  472. dashRemaining = (int)(pDash[dashIndex]); \
  473. if ((thisDash = dashRemaining) >= len) \
  474. { \
  475. dashRemaining -= len; \
  476. thisDash = len; \
  477. } \
  478. }
  479. e3 = e2-e1;
  480. e = e - e1; /* make looping easier */
  481. /* point to first point */
  482. x = x1;
  483. y = y1;
  484. /* loop, generating dashes (in the absence of dashing, would
  485. generate len pixels in all) */
  486. for ( ; ; )
  487. {
  488. len -= thisDash;
  489. /* reset variables used in MI_ADD_POINT() */
  490. numSpans_fg = 0;
  491. ycurr_fg = 0;
  492. firstspan_fg = true;
  493. if (signdy >= 0)
  494. {
  495. ppt_fg = pptInit_fg;
  496. pwidth_fg = pwidthInit_fg;
  497. }
  498. else
  499. {
  500. ppt_fg = pptLast_fg;
  501. pwidth_fg = pwidthLast_fg;
  502. }
  503. if (isDoubleDash)
  504. {
  505. numSpans_bg = 0;
  506. ycurr_bg = 0;
  507. firstspan_bg = true;
  508. ppt_bg = pptInit_bg;
  509. pwidth_bg = pwidthInit_bg;
  510. if (signdy >= 0)
  511. {
  512. ppt_bg = pptInit_bg;
  513. pwidth_bg = pwidthInit_bg;
  514. }
  515. else
  516. {
  517. ppt_bg = pptLast_bg;
  518. pwidth_bg = pwidthLast_bg;
  519. }
  520. }
  521. switch (axis)
  522. {
  523. case X_AXIS:
  524. default:
  525. if (dashIndex & 1)
  526. {
  527. if (isDoubleDash)
  528. {
  529. /* create background dash */
  530. Loop_x(thisDash, MI_ADD_POINT(x, y, ppt_bg, pwidth_bg, numSpans_bg, ycurr_bg, firstspan_bg, signdy))
  531. }
  532. else
  533. /* not double dashing; no background dash */
  534. Loop_x(thisDash, ;);
  535. }
  536. else
  537. /* create foreground dash */
  538. Loop_x(thisDash, MI_ADD_POINT(x, y, ppt_fg, pwidth_fg, numSpans_fg, ycurr_fg, firstspan_fg, signdy))
  539. break;
  540. case Y_AXIS:
  541. if (dashIndex & 1)
  542. {
  543. if (isDoubleDash)
  544. {
  545. /* create background dash */
  546. Loop_y(thisDash, MI_ADD_POINT(x, y, ppt_bg, pwidth_bg, numSpans_bg, ycurr_bg, firstspan_bg, signdy))
  547. }
  548. else
  549. /* not double dashing; no background dash */
  550. Loop_y(thisDash, ;);
  551. }
  552. else
  553. /* create foreground dash */
  554. Loop_y(thisDash, MI_ADD_POINT(x, y, ppt_fg, pwidth_fg, numSpans_fg, ycurr_fg, firstspan_fg, signdy))
  555. break;
  556. } /* end switch */
  557. if (numSpans_fg > 0)
  558. /* have a foreground dash to paint */
  559. {
  560. miPoint *pptStart_fg;
  561. unsigned int *pwidthStart_fg;
  562. if (signdy >= 0)
  563. {
  564. pptStart_fg = pptInit_fg;
  565. pwidthStart_fg = pwidthInit_fg;
  566. }
  567. else
  568. {
  569. pptStart_fg = pptLast_fg - (numSpans_fg - 1);
  570. pwidthStart_fg = pwidthLast_fg - (numSpans_fg - 1);
  571. }
  572. /* for foreground dash, use a paint type that cycles through
  573. 1..(numPixels-1) */
  574. {
  575. int numPixels = pGC->numPixels;
  576. int paintType = 1 + ((dashNum / 2) % (numPixels - 1));
  577. MI_COPY_AND_PAINT_SPANS(paintedSet, pGC->pixels[paintType], numSpans_fg, pptStart_fg, pwidthStart_fg)
  578. }
  579. }
  580. if (isDoubleDash && numSpans_bg > 0)
  581. /* have a background dash to paint */
  582. {
  583. miPoint *pptStart_bg;
  584. unsigned int *pwidthStart_bg;
  585. if (signdy >= 0)
  586. {
  587. pptStart_bg = pptInit_bg;
  588. pwidthStart_bg = pwidthInit_bg;
  589. }
  590. else
  591. {
  592. pptStart_bg = pptLast_bg - (numSpans_bg - 1);
  593. pwidthStart_bg = pwidthLast_bg - (numSpans_bg - 1);
  594. }
  595. /* for background dash, use paint type #0 */
  596. MI_COPY_AND_PAINT_SPANS(paintedSet, pGC->pixels[0], numSpans_bg, pptStart_bg, pwidthStart_bg)
  597. }
  598. if (len == 0)
  599. break; /* break out of dash-generating loop */
  600. NextDash /* update dashNum, dashIndex, thisDash, dashRemaining */
  601. } /* end infinite dash-generating loop */
  602. *pdashNum = dashNum;
  603. *pdashIndex = dashIndex;
  604. *pdashOffset = (int)(pDash[dashIndex]) - dashRemaining;
  605. free (pwidthInit_fg);
  606. free (pptInit_fg);
  607. if (isDoubleDash)
  608. {
  609. free (pwidthInit_bg);
  610. free (pptInit_bg);
  611. }
  612. }
  613. /* Internal: draw horizontal zero-width solid line segment, in paint type #1.
  614. Called by miZeroLine().
  615. Called with len >= 1, and len=x2-x1. Endpoint semantics
  616. are used, so we paint only len pixels, i.e. x1..x2-1. */
  617. /* ARGS: x1,y1 = initial point, len = length of line */
  618. static void
  619. cfbHorzS (miPaintedSet *paintedSet, const miGC *pGC, int x1, int y1, int len)
  620. {
  621. miPoint *ppt;
  622. unsigned int *pwidth;
  623. ppt = (miPoint *)mi_xmalloc(sizeof(miPoint));
  624. pwidth = (unsigned int *)mi_xmalloc(sizeof(unsigned int));
  625. ppt->x = x1;
  626. ppt->y = y1;
  627. *pwidth = (unsigned int)len;
  628. MI_PAINT_SPANS(paintedSet, pGC->pixels[1], 1, ppt, pwidth)
  629. }
  630. /* Internal: draw vertical zero-width solid line segment, in paint type #1.
  631. Called by miZeroLine().
  632. Called with len >= 1, and len=y2-y1. Endpoint semantics
  633. are used, so we paint only len pixels, i.e. y1..y2-1. */
  634. /* ARGS: x1,y1 = initial point, len = length of line */
  635. static void
  636. cfbVertS (miPaintedSet *paintedSet, const miGC *pGC, int x1, int y1, int len)
  637. {
  638. miPoint *ppt, *pptInit;
  639. unsigned int *pwidth, *pwidthInit;
  640. int i;
  641. ppt = pptInit = (miPoint *)mi_xmalloc(len * sizeof(miPoint));
  642. pwidth = pwidthInit = (unsigned int *)mi_xmalloc(len * sizeof(unsigned int));
  643. for (i = 0; i < len; i++)
  644. {
  645. ppt->x = x1;
  646. ppt->y = y1 + i;
  647. ppt++;
  648. *pwidth++ = (unsigned int)1;
  649. }
  650. MI_PAINT_SPANS(paintedSet, pGC->pixels[1], len, pptInit, pwidthInit)
  651. }