Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /*********************************************************** |
2 | ||
3 | Copyright 1987, 1998 The Open Group | |
4 | ||
5 | Permission to use, copy, modify, distribute, and sell this software and its | |
6 | documentation for any purpose is hereby granted without fee, provided that | |
7 | the above copyright notice appear in all copies and that both that | |
8 | copyright notice and this permission notice appear in supporting | |
9 | documentation. | |
10 | ||
11 | The above copyright notice and this permission notice shall be included in | |
12 | all copies or substantial portions of the Software. | |
13 | ||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 | OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | |
18 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
20 | ||
21 | Except as contained in this notice, the name of The Open Group shall not be | |
22 | used in advertising or otherwise to promote the sale, use or other dealings | |
23 | in this Software without prior written authorization from The Open Group. | |
24 | ||
25 | Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. | |
26 | ||
27 | All Rights Reserved | |
28 | ||
29 | Permission to use, copy, modify, and distribute this software and its | |
30 | documentation for any purpose and without fee is hereby granted, | |
31 | provided that the above copyright notice appear in all copies and that | |
32 | both that copyright notice and this permission notice appear in | |
33 | supporting documentation, and that the name of Digital not be | |
34 | used in advertising or publicity pertaining to distribution of the | |
35 | software without specific, written prior permission. | |
36 | ||
37 | DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
38 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
39 | DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
40 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
41 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
42 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
43 | SOFTWARE. | |
44 | ||
45 | ******************************************************************/ | |
46 | #ifdef HAVE_DIX_CONFIG_H | |
47 | #include <dix-config.h> | |
48 | #endif | |
49 | ||
50 | #include <X11/X.h> | |
51 | ||
52 | #include "misc.h" | |
53 | #include "scrnintstr.h" | |
54 | #include "gcstruct.h" | |
55 | #include "windowstr.h" | |
56 | #include "pixmap.h" | |
57 | #include "mi.h" | |
58 | #include "miline.h" | |
59 | ||
60 | /* Draw lineSolid, fillStyle-independent zero width lines. | |
61 | * | |
62 | * Must keep X and Y coordinates in "ints" at least until after they're | |
63 | * translated and clipped to accomodate CoordModePrevious lines with very | |
64 | * large coordinates. | |
65 | * | |
66 | * Draws the same pixels regardless of sign(dx) or sign(dy). | |
67 | * | |
68 | * Ken Whaley | |
69 | * | |
70 | */ | |
71 | ||
72 | /* largest positive value that can fit into a component of a point. | |
73 | * Assumes that the point structure is {type x, y;} where type is | |
74 | * a signed type. | |
75 | */ | |
76 | #define MAX_COORDINATE ((1 << (((sizeof(DDXPointRec) >> 1) << 3) - 1)) - 1) | |
77 | ||
78 | #define MI_OUTPUT_POINT(xx, yy)\ | |
79 | {\ | |
80 | if ( !new_span && yy == current_y)\ | |
81 | {\ | |
82 | if (xx < spans->x)\ | |
83 | spans->x = xx;\ | |
84 | ++*widths;\ | |
85 | }\ | |
86 | else\ | |
87 | {\ | |
88 | ++Nspans;\ | |
89 | ++spans;\ | |
90 | ++widths;\ | |
91 | spans->x = xx;\ | |
92 | spans->y = yy;\ | |
93 | *widths = 1;\ | |
94 | current_y = yy;\ | |
95 | new_span = FALSE;\ | |
96 | }\ | |
97 | } | |
98 | ||
99 | void | |
100 | miZeroLine(DrawablePtr pDraw, GCPtr pGC, int mode, /* Origin or Previous */ | |
101 | int npt, /* number of points */ | |
102 | DDXPointPtr pptInit) | |
103 | { | |
104 | int Nspans, current_y = 0; | |
105 | DDXPointPtr ppt; | |
106 | DDXPointPtr pspanInit, spans; | |
107 | int *pwidthInit, *widths, list_len; | |
108 | int xleft, ytop, xright, ybottom; | |
109 | int new_x1, new_y1, new_x2, new_y2; | |
110 | int x = 0, y = 0, x1, y1, x2, y2, xstart, ystart; | |
111 | int oc1, oc2; | |
112 | int result; | |
113 | int pt1_clipped, pt2_clipped = 0; | |
114 | Bool new_span; | |
115 | int signdx, signdy; | |
116 | int clipdx, clipdy; | |
117 | int width, height; | |
118 | int adx, ady; | |
119 | int octant; | |
120 | unsigned int bias = miGetZeroLineBias(pDraw->pScreen); | |
121 | int e, e1, e2, e3; /* Bresenham error terms */ | |
122 | int length; /* length of lines == # of pixels on major axis */ | |
123 | ||
124 | xleft = pDraw->x; | |
125 | ytop = pDraw->y; | |
126 | xright = pDraw->x + pDraw->width - 1; | |
127 | ybottom = pDraw->y + pDraw->height - 1; | |
128 | ||
129 | if (!pGC->miTranslate) { | |
130 | /* do everything in drawable-relative coordinates */ | |
131 | xleft = 0; | |
132 | ytop = 0; | |
133 | xright -= pDraw->x; | |
134 | ybottom -= pDraw->y; | |
135 | } | |
136 | ||
137 | /* it doesn't matter whether we're in drawable or screen coordinates, | |
138 | * FillSpans simply cannot take starting coordinates outside of the | |
139 | * range of a DDXPointRec component. | |
140 | */ | |
141 | if (xright > MAX_COORDINATE) | |
142 | xright = MAX_COORDINATE; | |
143 | if (ybottom > MAX_COORDINATE) | |
144 | ybottom = MAX_COORDINATE; | |
145 | ||
146 | /* since we're clipping to the drawable's boundaries & coordinate | |
147 | * space boundaries, we're guaranteed that the larger of width/height | |
148 | * is the longest span we'll need to output | |
149 | */ | |
150 | width = xright - xleft + 1; | |
151 | height = ybottom - ytop + 1; | |
152 | list_len = (height >= width) ? height : width; | |
153 | pspanInit = malloc(list_len * sizeof(DDXPointRec)); | |
154 | pwidthInit = malloc(list_len * sizeof(int)); | |
155 | if (!pspanInit || !pwidthInit) { | |
156 | free(pspanInit); | |
157 | free(pwidthInit); | |
158 | return; | |
159 | } | |
160 | Nspans = 0; | |
161 | new_span = TRUE; | |
162 | spans = pspanInit - 1; | |
163 | widths = pwidthInit - 1; | |
164 | ppt = pptInit; | |
165 | ||
166 | xstart = ppt->x; | |
167 | ystart = ppt->y; | |
168 | if (pGC->miTranslate) { | |
169 | xstart += pDraw->x; | |
170 | ystart += pDraw->y; | |
171 | } | |
172 | ||
173 | /* x2, y2, oc2 copied to x1, y1, oc1 at top of loop to simplify | |
174 | * iteration logic | |
175 | */ | |
176 | x2 = xstart; | |
177 | y2 = ystart; | |
178 | oc2 = 0; | |
179 | MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom); | |
180 | ||
181 | while (--npt > 0) { | |
182 | if (Nspans > 0) | |
183 | (*pGC->ops->FillSpans) (pDraw, pGC, Nspans, pspanInit, | |
184 | pwidthInit, FALSE); | |
185 | Nspans = 0; | |
186 | new_span = TRUE; | |
187 | spans = pspanInit - 1; | |
188 | widths = pwidthInit - 1; | |
189 | ||
190 | x1 = x2; | |
191 | y1 = y2; | |
192 | oc1 = oc2; | |
193 | ++ppt; | |
194 | ||
195 | x2 = ppt->x; | |
196 | y2 = ppt->y; | |
197 | if (pGC->miTranslate && (mode != CoordModePrevious)) { | |
198 | x2 += pDraw->x; | |
199 | y2 += pDraw->y; | |
200 | } | |
201 | else if (mode == CoordModePrevious) { | |
202 | x2 += x1; | |
203 | y2 += y1; | |
204 | } | |
205 | ||
206 | oc2 = 0; | |
207 | MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom); | |
208 | ||
209 | CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant); | |
210 | ||
211 | if (adx > ady) { | |
212 | e1 = ady << 1; | |
213 | e2 = e1 - (adx << 1); | |
214 | e = e1 - adx; | |
215 | length = adx; /* don't draw endpoint in main loop */ | |
216 | ||
217 | FIXUP_ERROR(e, octant, bias); | |
218 | ||
219 | new_x1 = x1; | |
220 | new_y1 = y1; | |
221 | new_x2 = x2; | |
222 | new_y2 = y2; | |
223 | pt1_clipped = 0; | |
224 | pt2_clipped = 0; | |
225 | ||
226 | if ((oc1 | oc2) != 0) { | |
227 | result = miZeroClipLine(xleft, ytop, xright, ybottom, | |
228 | &new_x1, &new_y1, &new_x2, &new_y2, | |
229 | adx, ady, | |
230 | &pt1_clipped, &pt2_clipped, | |
231 | octant, bias, oc1, oc2); | |
232 | if (result == -1) | |
233 | continue; | |
234 | ||
235 | length = abs(new_x2 - new_x1); | |
236 | ||
237 | /* if we've clipped the endpoint, always draw the full length | |
238 | * of the segment, because then the capstyle doesn't matter | |
239 | */ | |
240 | if (pt2_clipped) | |
241 | length++; | |
242 | ||
243 | if (pt1_clipped) { | |
244 | /* must calculate new error terms */ | |
245 | clipdx = abs(new_x1 - x1); | |
246 | clipdy = abs(new_y1 - y1); | |
247 | e += (clipdy * e2) + ((clipdx - clipdy) * e1); | |
248 | } | |
249 | } | |
250 | ||
251 | /* draw the segment */ | |
252 | ||
253 | x = new_x1; | |
254 | y = new_y1; | |
255 | ||
256 | e3 = e2 - e1; | |
257 | e = e - e1; | |
258 | ||
259 | while (length--) { | |
260 | MI_OUTPUT_POINT(x, y); | |
261 | e += e1; | |
262 | if (e >= 0) { | |
263 | y += signdy; | |
264 | e += e3; | |
265 | } | |
266 | x += signdx; | |
267 | } | |
268 | } | |
269 | else { /* Y major line */ | |
270 | ||
271 | e1 = adx << 1; | |
272 | e2 = e1 - (ady << 1); | |
273 | e = e1 - ady; | |
274 | length = ady; /* don't draw endpoint in main loop */ | |
275 | ||
276 | SetYMajorOctant(octant); | |
277 | FIXUP_ERROR(e, octant, bias); | |
278 | ||
279 | new_x1 = x1; | |
280 | new_y1 = y1; | |
281 | new_x2 = x2; | |
282 | new_y2 = y2; | |
283 | pt1_clipped = 0; | |
284 | pt2_clipped = 0; | |
285 | ||
286 | if ((oc1 | oc2) != 0) { | |
287 | result = miZeroClipLine(xleft, ytop, xright, ybottom, | |
288 | &new_x1, &new_y1, &new_x2, &new_y2, | |
289 | adx, ady, | |
290 | &pt1_clipped, &pt2_clipped, | |
291 | octant, bias, oc1, oc2); | |
292 | if (result == -1) | |
293 | continue; | |
294 | ||
295 | length = abs(new_y2 - new_y1); | |
296 | ||
297 | /* if we've clipped the endpoint, always draw the full length | |
298 | * of the segment, because then the capstyle doesn't matter | |
299 | */ | |
300 | if (pt2_clipped) | |
301 | length++; | |
302 | ||
303 | if (pt1_clipped) { | |
304 | /* must calculate new error terms */ | |
305 | clipdx = abs(new_x1 - x1); | |
306 | clipdy = abs(new_y1 - y1); | |
307 | e += (clipdx * e2) + ((clipdy - clipdx) * e1); | |
308 | } | |
309 | } | |
310 | ||
311 | /* draw the segment */ | |
312 | ||
313 | x = new_x1; | |
314 | y = new_y1; | |
315 | ||
316 | e3 = e2 - e1; | |
317 | e = e - e1; | |
318 | ||
319 | while (length--) { | |
320 | MI_OUTPUT_POINT(x, y); | |
321 | e += e1; | |
322 | if (e >= 0) { | |
323 | x += signdx; | |
324 | e += e3; | |
325 | } | |
326 | y += signdy; | |
327 | } | |
328 | } | |
329 | } | |
330 | ||
331 | /* only do the capnotlast check on the last segment | |
332 | * and only if the endpoint wasn't clipped. And then, if the last | |
333 | * point is the same as the first point, do not draw it, unless the | |
334 | * line is degenerate | |
335 | */ | |
336 | if ((!pt2_clipped) && (pGC->capStyle != CapNotLast) && | |
337 | (((xstart != x2) || (ystart != y2)) || (ppt == pptInit + 1))) { | |
338 | MI_OUTPUT_POINT(x, y); | |
339 | } | |
340 | ||
341 | if (Nspans > 0) | |
342 | (*pGC->ops->FillSpans) (pDraw, pGC, Nspans, pspanInit, | |
343 | pwidthInit, FALSE); | |
344 | ||
345 | free(pwidthInit); | |
346 | free(pspanInit); | |
347 | } | |
348 | ||
349 | void | |
350 | miZeroDashLine(DrawablePtr dst, GCPtr pgc, int mode, int nptInit, /* number of points in polyline */ | |
351 | DDXPointRec * pptInit /* points in the polyline */ | |
352 | ) | |
353 | { | |
354 | /* XXX kludge until real zero-width dash code is written */ | |
355 | pgc->lineWidth = 1; | |
356 | miWideDash(dst, pgc, mode, nptInit, pptInit); | |
357 | pgc->lineWidth = 0; | |
358 | } |