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