]> Pileus Git - ~andy/gtk/blob - gdk/linux-fb/midash.c
Fixes #136082 and #135265, patch by Morten Welinder.
[~andy/gtk] / gdk / linux-fb / midash.c
1 /***********************************************************
2
3 Copyright 1987, 1998  The Open Group
4
5 All Rights Reserved.
6
7 The above copyright notice and this permission notice shall be included in
8 all copies or substantial portions of the Software.
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
13 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
14 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16
17 Except as contained in this notice, the name of The Open Group shall not be
18 used in advertising or otherwise to promote the sale, use or other dealings
19 in this Software without prior written authorization from The Open Group.
20
21
22 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
23
24                         All Rights Reserved
25
26 Permission to use, copy, modify, and distribute this software and its 
27 documentation for any purpose and without fee is hereby granted, 
28 provided that the above copyright notice appear in all copies and that
29 both that copyright notice and this permission notice appear in 
30 supporting documentation, and that the name of Digital not be
31 used in advertising or publicity pertaining to distribution of the
32 software without specific, written prior permission.  
33
34 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
35 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
36 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
37 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
38 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
39 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
40 SOFTWARE.
41
42 ******************************************************************/
43 /* $TOG: midash.c /main/14 1998/02/09 14:46:34 kaleb $ */
44
45 #include <config.h>
46 #include "mi.h"
47
48 static miDashPtr CheckDashStorage();
49
50 /* return a list of DashRec.  there will be an extra
51 entry at the end holding the last point of the polyline.
52    this means that the code that actually draws dashes can
53 get a pair of points for every dash.  only the point in the last
54 dash record is useful; the other fields are not used.
55    nseg is the number of segments, not the number of points.
56
57 example:
58
59    dash1.start
60    dash2.start
61    dash3.start
62    last-point
63
64 defines a list of segments
65    (dash1.pt, dash2.pt)
66    (dash2.pt, dash3.pt)
67    (dash3.pt, last-point)
68 and nseg == 3.
69
70 NOTE:
71     EVEN_DASH == ~ODD_DASH
72
73 NOTE ALSO:
74     miDashLines may return 0 segments, going from pt[0] to pt[0] with one dash.
75 */
76
77 enum { EVEN_DASH=0, ODD_DASH=1 };
78
79 #define sign(x) ((x)>0)?1:( ((x)<0)?-1:0 )
80
81 miDashPtr
82 miDashLine(npt, ppt, nDash, pDash, offset, pnseg)
83 int npt;
84 GdkPoint* ppt;
85 unsigned int nDash;
86 unsigned char *pDash;
87 unsigned int offset;
88 int *pnseg;
89 {
90     GdkPoint pt1, pt2;
91     int lenCur;         /* npt used from this dash */
92     int lenMax;         /* npt in this dash */
93     int iDash = 0;      /* index of current dash */
94     int which;          /* EVEN_DASH or ODD_DASH */
95     miDashPtr pseg;     /* list of dash segments */
96     miDashPtr psegBase; /* start of list */
97     int nseg = 0;       /* number of dashes so far */
98     int nsegMax = 0;    /* num segs we can fit in this list */
99
100     int x, y, len;
101     int adx, ady, signdx, signdy;
102     int du, dv, e1, e2, e, base_e = 0;
103
104     lenCur = offset;
105     which = EVEN_DASH;
106     while(lenCur >= pDash[iDash])
107     {
108         lenCur -= pDash[iDash];
109         iDash++;
110         if (iDash >= nDash)
111             iDash = 0;
112         which = ~which;
113     }
114     lenMax = pDash[iDash];
115
116     psegBase = (miDashPtr)NULL;
117     pt2 = ppt[0];               /* just in case there is only one point */
118
119     while(--npt)
120     {
121         if (PtEqual(ppt[0], ppt[1]))
122         {
123             ppt++;
124             continue;           /* no duplicated points in polyline */
125         }
126         pt1 = *ppt++;
127         pt2 = *ppt;
128
129         adx = pt2.x - pt1.x;
130         ady = pt2.y - pt1.y;
131         signdx = sign(adx);
132         signdy = sign(ady);
133         adx = abs(adx);
134         ady = abs(ady);
135
136         if (adx > ady)
137         {
138             du = adx;
139             dv = ady;
140             len = adx;
141         }
142         else
143         {
144             du = ady;
145             dv = adx;
146             len = ady;
147         }
148
149         e1 = dv * 2;
150         e2 = e1 - 2*du;
151         e = e1 - du;
152         x = pt1.x;
153         y = pt1.y;
154
155         nseg++;
156         pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
157         if (!pseg)
158             return (miDashPtr)NULL;
159         pseg->pt = pt1;
160         pseg->e1 = e1;
161         pseg->e2 = e2;
162         base_e = pseg->e = e;
163         pseg->which = which;
164         pseg->newLine = 1;
165
166         while (len--)
167         {
168             if (adx > ady)
169             {
170                 /* X_AXIS */
171                 if (((signdx > 0) && (e < 0)) ||
172                     ((signdx <=0) && (e <=0))
173                    )
174                 {
175                     e += e1;
176                 }
177                 else
178                 {
179                     y += signdy;
180                     e += e2;
181                 }
182                 x += signdx;
183             }
184             else
185             {
186                 /* Y_AXIS */
187                 if (((signdx > 0) && (e < 0)) ||
188                     ((signdx <=0) && (e <=0))
189                    )
190                 {
191                     e +=e1;
192                 }
193                 else
194                 {
195                     x += signdx;
196                     e += e2;
197                 }
198                 y += signdy;
199             }
200
201             lenCur++;
202             if (lenCur >= lenMax && (len || npt <= 1))
203             {
204                 nseg++;
205                 pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
206                 if (!pseg)
207                     return (miDashPtr)NULL;
208                 pseg->pt.x = x;
209                 pseg->pt.y = y;
210                 pseg->e1 = e1;
211                 pseg->e2 = e2;
212                 pseg->e = e;
213                 which = ~which;
214                 pseg->which = which;
215                 pseg->newLine = 0;
216
217                 /* move on to next dash */
218                 iDash++;
219                 if (iDash >= nDash)
220                     iDash = 0;
221                 lenMax = pDash[iDash];
222                 lenCur = 0;
223             }
224         } /* while len-- */
225     } /* while --npt */
226
227     if (lenCur == 0 && nseg != 0)
228     {
229         nseg--;
230         which = ~which;
231     }
232     *pnseg = nseg;
233     pseg = CheckDashStorage(&psegBase, nseg+1, &nsegMax);
234     if (!pseg)
235         return (miDashPtr)NULL;
236     pseg->pt = pt2;
237     pseg->e = base_e;
238     pseg->which = which;
239     pseg->newLine = 0;
240     return psegBase;
241
242
243
244 #define NSEGDELTA 16
245
246 /* returns a pointer to the pseg[nseg-1], growing the storage as
247 necessary.  this interface seems unnecessarily cumbersome.
248
249 */
250
251 static
252 miDashPtr
253 CheckDashStorage(ppseg, nseg, pnsegMax)
254 miDashPtr *ppseg;               /* base pointer */
255 int nseg;                       /* number of segment we want to write to */
256 int *pnsegMax;                  /* size (in segments) of list so far */
257 {
258     if (nseg > *pnsegMax)
259     {
260         miDashPtr newppseg;
261
262         *pnsegMax += NSEGDELTA;
263         newppseg = (miDashPtr)g_realloc(*ppseg,
264                                        (*pnsegMax)*sizeof(miDashRec));
265         if (!newppseg)
266         {
267             g_free(*ppseg);
268             return (miDashPtr)NULL;
269         }
270         *ppseg = newppseg;
271     }
272     return(*ppseg+(nseg-1));
273 }
274
275 void
276 miStepDash (dist, pDashIndex, pDash, numInDashList, pDashOffset)
277     int dist;                   /* distance to step */
278     int *pDashIndex;            /* current dash */
279     unsigned char *pDash;       /* dash list */
280     int numInDashList;          /* total length of dash list */
281     int *pDashOffset;           /* offset into current dash */
282 {
283     int dashIndex, dashOffset;
284     int totallen;
285     int i;
286     
287     dashIndex = *pDashIndex;
288     dashOffset = *pDashOffset;
289     if (dist < pDash[dashIndex] - dashOffset)
290     {
291         *pDashOffset = dashOffset + dist;
292         return;
293     }
294     dist -= pDash[dashIndex] - dashOffset;
295     if (++dashIndex == numInDashList)
296         dashIndex = 0;
297     totallen = 0;
298     for (i = 0; i < numInDashList; i++)
299         totallen += pDash[i];
300     if (totallen <= dist)
301         dist = dist % totallen;
302     while (dist >= pDash[dashIndex])
303     {
304         dist -= pDash[dashIndex];
305         if (++dashIndex == numInDashList)
306             dashIndex = 0;
307     }
308     *pDashIndex = dashIndex;
309     *pDashOffset = dist;
310 }