1706f2543Smrg/***********************************************************
2706f2543Smrg
3706f2543SmrgCopyright 1987, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included in
12706f2543Smrgall copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20706f2543Smrg
21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be
22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings
23706f2543Smrgin this Software without prior written authorization from The Open Group.
24706f2543Smrg
25706f2543Smrg
26706f2543SmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27706f2543Smrg
28706f2543Smrg                        All Rights Reserved
29706f2543Smrg
30706f2543SmrgPermission to use, copy, modify, and distribute this software and its
31706f2543Smrgdocumentation for any purpose and without fee is hereby granted,
32706f2543Smrgprovided that the above copyright notice appear in all copies and that
33706f2543Smrgboth that copyright notice and this permission notice appear in
34706f2543Smrgsupporting documentation, and that the name of Digital not be
35706f2543Smrgused in advertising or publicity pertaining to distribution of the
36706f2543Smrgsoftware without specific, written prior permission.
37706f2543Smrg
38706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44706f2543SmrgSOFTWARE.
45706f2543Smrg
46706f2543Smrg******************************************************************/
47706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
48706f2543Smrg#include <dix-config.h>
49706f2543Smrg#endif
50706f2543Smrg
51706f2543Smrg#include <X11/X.h>
52706f2543Smrg
53706f2543Smrg#include "misc.h"
54706f2543Smrg#include "scrnintstr.h"
55706f2543Smrg#include "gcstruct.h"
56706f2543Smrg#include "windowstr.h"
57706f2543Smrg#include "pixmap.h"
58706f2543Smrg#include "mi.h"
59706f2543Smrg#include "miline.h"
60706f2543Smrg
61706f2543Smrg/* Draw lineSolid, fillStyle-independent zero width lines.
62706f2543Smrg *
63706f2543Smrg * Must keep X and Y coordinates in "ints" at least until after they're
64706f2543Smrg * translated and clipped to accomodate CoordModePrevious lines with very
65706f2543Smrg * large coordinates.
66706f2543Smrg *
67706f2543Smrg * Draws the same pixels regardless of sign(dx) or sign(dy).
68706f2543Smrg *
69706f2543Smrg * Ken Whaley
70706f2543Smrg *
71706f2543Smrg */
72706f2543Smrg
73706f2543Smrg/* largest positive value that can fit into a component of a point.
74706f2543Smrg * Assumes that the point structure is {type x, y;} where type is
75706f2543Smrg * a signed type.
76706f2543Smrg */
77706f2543Smrg#define MAX_COORDINATE ((1 << (((sizeof(DDXPointRec) >> 1) << 3) - 1)) - 1)
78706f2543Smrg
79706f2543Smrg#define MI_OUTPUT_POINT(xx, yy)\
80706f2543Smrg{\
81706f2543Smrg    if ( !new_span && yy == current_y)\
82706f2543Smrg    {\
83706f2543Smrg        if (xx < spans->x)\
84706f2543Smrg	    spans->x = xx;\
85706f2543Smrg	++*widths;\
86706f2543Smrg    }\
87706f2543Smrg    else\
88706f2543Smrg    {\
89706f2543Smrg        ++Nspans;\
90706f2543Smrg	++spans;\
91706f2543Smrg	++widths;\
92706f2543Smrg	spans->x = xx;\
93706f2543Smrg	spans->y = yy;\
94706f2543Smrg	*widths = 1;\
95706f2543Smrg	current_y = yy;\
96706f2543Smrg        new_span = FALSE;\
97706f2543Smrg    }\
98706f2543Smrg}
99706f2543Smrg
100706f2543Smrgvoid
101706f2543SmrgmiZeroLine(
102706f2543Smrg    DrawablePtr pDraw,
103706f2543Smrg    GCPtr	pGC,
104706f2543Smrg    int		mode,		/* Origin or Previous */
105706f2543Smrg    int		npt,		/* number of points */
106706f2543Smrg    DDXPointPtr pptInit)
107706f2543Smrg{
108706f2543Smrg    int Nspans, current_y = 0;
109706f2543Smrg    DDXPointPtr ppt;
110706f2543Smrg    DDXPointPtr pspanInit, spans;
111706f2543Smrg    int *pwidthInit, *widths, list_len;
112706f2543Smrg    int xleft, ytop, xright, ybottom;
113706f2543Smrg    int new_x1, new_y1, new_x2, new_y2;
114706f2543Smrg    int x = 0, y = 0, x1, y1, x2, y2, xstart, ystart;
115706f2543Smrg    int oc1, oc2;
116706f2543Smrg    int result;
117706f2543Smrg    int pt1_clipped, pt2_clipped = 0;
118706f2543Smrg    Bool new_span;
119706f2543Smrg    int signdx, signdy;
120706f2543Smrg    int clipdx, clipdy;
121706f2543Smrg    int width, height;
122706f2543Smrg    int adx, ady;
123706f2543Smrg    int octant;
124706f2543Smrg    unsigned int bias = miGetZeroLineBias(pDraw->pScreen);
125706f2543Smrg    int e, e1, e2, e3;	/* Bresenham error terms */
126706f2543Smrg    int length;		/* length of lines == # of pixels on major axis */
127706f2543Smrg
128706f2543Smrg    xleft   = pDraw->x;
129706f2543Smrg    ytop    = pDraw->y;
130706f2543Smrg    xright  = pDraw->x + pDraw->width - 1;
131706f2543Smrg    ybottom = pDraw->y + pDraw->height - 1;
132706f2543Smrg
133706f2543Smrg    if (!pGC->miTranslate)
134706f2543Smrg    {
135706f2543Smrg	/* do everything in drawable-relative coordinates */
136706f2543Smrg	xleft    = 0;
137706f2543Smrg	ytop     = 0;
138706f2543Smrg	xright  -= pDraw->x;
139706f2543Smrg	ybottom -= pDraw->y;
140706f2543Smrg    }
141706f2543Smrg
142706f2543Smrg    /* it doesn't matter whether we're in drawable or screen coordinates,
143706f2543Smrg     * FillSpans simply cannot take starting coordinates outside of the
144706f2543Smrg     * range of a DDXPointRec component.
145706f2543Smrg     */
146706f2543Smrg    if (xright > MAX_COORDINATE)
147706f2543Smrg	xright = MAX_COORDINATE;
148706f2543Smrg    if (ybottom > MAX_COORDINATE)
149706f2543Smrg	ybottom = MAX_COORDINATE;
150706f2543Smrg
151706f2543Smrg    /* since we're clipping to the drawable's boundaries & coordinate
152706f2543Smrg     * space boundaries, we're guaranteed that the larger of width/height
153706f2543Smrg     * is the longest span we'll need to output
154706f2543Smrg     */
155706f2543Smrg    width = xright - xleft + 1;
156706f2543Smrg    height = ybottom - ytop + 1;
157706f2543Smrg    list_len = (height >= width) ? height : width;
158706f2543Smrg    pspanInit = malloc(list_len * sizeof(DDXPointRec));
159706f2543Smrg    pwidthInit = malloc(list_len * sizeof(int));
160706f2543Smrg    if (!pspanInit || !pwidthInit) {
161706f2543Smrg	free(pspanInit);
162706f2543Smrg	free(pwidthInit);
163706f2543Smrg	return;
164706f2543Smrg    }
165706f2543Smrg    Nspans = 0;
166706f2543Smrg    new_span = TRUE;
167706f2543Smrg    spans  = pspanInit - 1;
168706f2543Smrg    widths = pwidthInit - 1;
169706f2543Smrg    ppt = pptInit;
170706f2543Smrg
171706f2543Smrg    xstart = ppt->x;
172706f2543Smrg    ystart = ppt->y;
173706f2543Smrg    if (pGC->miTranslate)
174706f2543Smrg    {
175706f2543Smrg	xstart += pDraw->x;
176706f2543Smrg	ystart += pDraw->y;
177706f2543Smrg    }
178706f2543Smrg
179706f2543Smrg    /* x2, y2, oc2 copied to x1, y1, oc1 at top of loop to simplify
180706f2543Smrg     * iteration logic
181706f2543Smrg     */
182706f2543Smrg    x2 = xstart;
183706f2543Smrg    y2 = ystart;
184706f2543Smrg    oc2 = 0;
185706f2543Smrg    MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom);
186706f2543Smrg
187706f2543Smrg    while (--npt > 0)
188706f2543Smrg    {
189706f2543Smrg	if (Nspans > 0)
190706f2543Smrg	    (*pGC->ops->FillSpans)(pDraw, pGC, Nspans, pspanInit,
191706f2543Smrg				   pwidthInit, FALSE);
192706f2543Smrg	Nspans = 0;
193706f2543Smrg	new_span = TRUE;
194706f2543Smrg	spans  = pspanInit - 1;
195706f2543Smrg	widths = pwidthInit - 1;
196706f2543Smrg
197706f2543Smrg	x1  = x2;
198706f2543Smrg	y1  = y2;
199706f2543Smrg	oc1 = oc2;
200706f2543Smrg	++ppt;
201706f2543Smrg
202706f2543Smrg	x2 = ppt->x;
203706f2543Smrg	y2 = ppt->y;
204706f2543Smrg	if (pGC->miTranslate && (mode != CoordModePrevious))
205706f2543Smrg	{
206706f2543Smrg	    x2 += pDraw->x;
207706f2543Smrg	    y2 += pDraw->y;
208706f2543Smrg	}
209706f2543Smrg	else if (mode == CoordModePrevious)
210706f2543Smrg	{
211706f2543Smrg	    x2 += x1;
212706f2543Smrg	    y2 += y1;
213706f2543Smrg	}
214706f2543Smrg
215706f2543Smrg	oc2 = 0;
216706f2543Smrg	MIOUTCODES(oc2, x2, y2, xleft, ytop, xright, ybottom);
217706f2543Smrg
218706f2543Smrg	CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant);
219706f2543Smrg
220706f2543Smrg	if (adx > ady)
221706f2543Smrg	{
222706f2543Smrg	    e1 = ady << 1;
223706f2543Smrg	    e2 = e1 - (adx << 1);
224706f2543Smrg	    e  = e1 - adx;
225706f2543Smrg	    length  = adx;	/* don't draw endpoint in main loop */
226706f2543Smrg
227706f2543Smrg	    FIXUP_ERROR(e, octant, bias);
228706f2543Smrg
229706f2543Smrg	    new_x1 = x1;
230706f2543Smrg	    new_y1 = y1;
231706f2543Smrg	    new_x2 = x2;
232706f2543Smrg	    new_y2 = y2;
233706f2543Smrg	    pt1_clipped = 0;
234706f2543Smrg	    pt2_clipped = 0;
235706f2543Smrg
236706f2543Smrg	    if ((oc1 | oc2) != 0)
237706f2543Smrg	    {
238706f2543Smrg		result = miZeroClipLine(xleft, ytop, xright, ybottom,
239706f2543Smrg					&new_x1, &new_y1, &new_x2, &new_y2,
240706f2543Smrg					adx, ady,
241706f2543Smrg					&pt1_clipped, &pt2_clipped,
242706f2543Smrg					octant, bias, oc1, oc2);
243706f2543Smrg		if (result == -1)
244706f2543Smrg		    continue;
245706f2543Smrg
246706f2543Smrg		length = abs(new_x2 - new_x1);
247706f2543Smrg
248706f2543Smrg		/* if we've clipped the endpoint, always draw the full length
249706f2543Smrg		 * of the segment, because then the capstyle doesn't matter
250706f2543Smrg		 */
251706f2543Smrg		if (pt2_clipped)
252706f2543Smrg		    length++;
253706f2543Smrg
254706f2543Smrg		if (pt1_clipped)
255706f2543Smrg		{
256706f2543Smrg		    /* must calculate new error terms */
257706f2543Smrg		    clipdx = abs(new_x1 - x1);
258706f2543Smrg		    clipdy = abs(new_y1 - y1);
259706f2543Smrg		    e += (clipdy * e2) + ((clipdx - clipdy) * e1);
260706f2543Smrg		}
261706f2543Smrg	    }
262706f2543Smrg
263706f2543Smrg	    /* draw the segment */
264706f2543Smrg
265706f2543Smrg	    x = new_x1;
266706f2543Smrg	    y = new_y1;
267706f2543Smrg
268706f2543Smrg	    e3 = e2 - e1;
269706f2543Smrg	    e  = e - e1;
270706f2543Smrg
271706f2543Smrg	    while (length--)
272706f2543Smrg	    {
273706f2543Smrg		MI_OUTPUT_POINT(x, y);
274706f2543Smrg		e += e1;
275706f2543Smrg		if (e >= 0)
276706f2543Smrg		{
277706f2543Smrg		    y += signdy;
278706f2543Smrg		    e += e3;
279706f2543Smrg		}
280706f2543Smrg		x += signdx;
281706f2543Smrg	    }
282706f2543Smrg	}
283706f2543Smrg	else    /* Y major line */
284706f2543Smrg	{
285706f2543Smrg	    e1 = adx << 1;
286706f2543Smrg	    e2 = e1 - (ady << 1);
287706f2543Smrg	    e  = e1 - ady;
288706f2543Smrg	    length  = ady;	/* don't draw endpoint in main loop */
289706f2543Smrg
290706f2543Smrg	    SetYMajorOctant(octant);
291706f2543Smrg	    FIXUP_ERROR(e, octant, bias);
292706f2543Smrg
293706f2543Smrg	    new_x1 = x1;
294706f2543Smrg	    new_y1 = y1;
295706f2543Smrg	    new_x2 = x2;
296706f2543Smrg	    new_y2 = y2;
297706f2543Smrg	    pt1_clipped = 0;
298706f2543Smrg	    pt2_clipped = 0;
299706f2543Smrg
300706f2543Smrg	    if ((oc1 | oc2) != 0)
301706f2543Smrg	    {
302706f2543Smrg		result = miZeroClipLine(xleft, ytop, xright, ybottom,
303706f2543Smrg					&new_x1, &new_y1, &new_x2, &new_y2,
304706f2543Smrg					adx, ady,
305706f2543Smrg					&pt1_clipped, &pt2_clipped,
306706f2543Smrg					octant, bias, oc1, oc2);
307706f2543Smrg		if (result == -1)
308706f2543Smrg		    continue;
309706f2543Smrg
310706f2543Smrg		length = abs(new_y2 - new_y1);
311706f2543Smrg
312706f2543Smrg		/* if we've clipped the endpoint, always draw the full length
313706f2543Smrg		 * of the segment, because then the capstyle doesn't matter
314706f2543Smrg		 */
315706f2543Smrg		if (pt2_clipped)
316706f2543Smrg		    length++;
317706f2543Smrg
318706f2543Smrg		if (pt1_clipped)
319706f2543Smrg		{
320706f2543Smrg		    /* must calculate new error terms */
321706f2543Smrg		    clipdx = abs(new_x1 - x1);
322706f2543Smrg		    clipdy = abs(new_y1 - y1);
323706f2543Smrg		    e += (clipdx * e2) + ((clipdy - clipdx) * e1);
324706f2543Smrg		}
325706f2543Smrg	    }
326706f2543Smrg
327706f2543Smrg	    /* draw the segment */
328706f2543Smrg
329706f2543Smrg	    x = new_x1;
330706f2543Smrg	    y = new_y1;
331706f2543Smrg
332706f2543Smrg	    e3 = e2 - e1;
333706f2543Smrg	    e  = e - e1;
334706f2543Smrg
335706f2543Smrg	    while (length--)
336706f2543Smrg	    {
337706f2543Smrg		MI_OUTPUT_POINT(x, y);
338706f2543Smrg		e += e1;
339706f2543Smrg		if (e >= 0)
340706f2543Smrg		{
341706f2543Smrg		    x += signdx;
342706f2543Smrg		    e += e3;
343706f2543Smrg		}
344706f2543Smrg		y += signdy;
345706f2543Smrg	    }
346706f2543Smrg	}
347706f2543Smrg    }
348706f2543Smrg
349706f2543Smrg    /* only do the capnotlast check on the last segment
350706f2543Smrg     * and only if the endpoint wasn't clipped.  And then, if the last
351706f2543Smrg     * point is the same as the first point, do not draw it, unless the
352706f2543Smrg     * line is degenerate
353706f2543Smrg     */
354706f2543Smrg    if ( (! pt2_clipped) && (pGC->capStyle != CapNotLast) &&
355706f2543Smrg		(((xstart != x2) || (ystart != y2)) || (ppt == pptInit + 1)))
356706f2543Smrg    {
357706f2543Smrg	MI_OUTPUT_POINT(x, y);
358706f2543Smrg    }
359706f2543Smrg
360706f2543Smrg    if (Nspans > 0)
361706f2543Smrg	(*pGC->ops->FillSpans)(pDraw, pGC, Nspans, pspanInit,
362706f2543Smrg			       pwidthInit, FALSE);
363706f2543Smrg
364706f2543Smrg    free(pwidthInit);
365706f2543Smrg    free(pspanInit);
366706f2543Smrg}
367706f2543Smrg
368706f2543Smrgvoid
369706f2543SmrgmiZeroDashLine(
370706f2543Smrg            DrawablePtr dst,
371706f2543Smrg            GCPtr pgc,
372706f2543Smrg            int mode,
373706f2543Smrg            int nptInit,		/* number of points in polyline */
374706f2543Smrg            DDXPointRec *pptInit	/* points in the polyline */
375706f2543Smrg        )
376706f2543Smrg{
377706f2543Smrg    /* XXX kludge until real zero-width dash code is written */
378706f2543Smrg    pgc->lineWidth = 1;
379706f2543Smrg    miWideDash (dst, pgc, mode, nptInit, pptInit);
380706f2543Smrg    pgc->lineWidth = 0;
381706f2543Smrg}
382