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