xserver-multidpi/hw/xfree86/xaa/xaaLine.c

423 lines
14 KiB
C
Raw Normal View History

2003-11-14 17:48:57 +01:00
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif
#include <stdlib.h>
#include <X11/X.h>
#include "misc.h"
2003-11-14 17:48:57 +01:00
#include "xf86.h"
#include "xf86_OSproc.h"
#include "scrnintstr.h"
#include "pixmapstr.h"
#include "miline.h"
#include "xf86str.h"
#include "xaa.h"
#include "xaalocal.h"
void
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
XAAPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment * pSeg
2003-11-14 17:48:57 +01:00
#else
XAAPolyLines(DrawablePtr pDrawable, GCPtr pGC, int mode, /* Origin or Previous */
int npt, /* number of points */
DDXPointPtr pptInit
2003-11-14 17:48:57 +01:00
#endif
)
{
2003-11-14 17:48:57 +01:00
XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC);
BoxPtr pboxInit = RegionRects(pGC->pCompositeClip);
int nboxInit = RegionNumRects(pGC->pCompositeClip);
2003-11-14 17:48:57 +01:00
unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
int xorg = pDrawable->x;
int yorg = pDrawable->y;
int nbox;
BoxPtr pbox;
2003-11-14 17:48:57 +01:00
#ifndef POLYSEGMENT
DDXPointPtr ppt;
#endif
int x1, x2, y1, y2, tmp, len;
if (!nboxInit)
return;
2003-11-14 17:48:57 +01:00
if (infoRec->SolidLineFlags & LINE_LIMIT_COORDS) {
int minValX = infoRec->SolidLineLimits.x1;
int maxValX = infoRec->SolidLineLimits.x2;
int minValY = infoRec->SolidLineLimits.y1;
int maxValY = infoRec->SolidLineLimits.y2;
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
int n = nseg;
xSegment *s = pSeg;
2003-11-14 17:48:57 +01:00
while (n--)
2003-11-14 17:48:57 +01:00
#else
int n = npt;
int xorgtmp = xorg;
int yorgtmp = yorg;
ppt = pptInit;
x2 = ppt->x + xorgtmp;
y2 = ppt->y + yorgtmp;
while (--n)
2003-11-14 17:48:57 +01:00
#endif
{
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
x1 = s->x1 + xorg;
y1 = s->y1 + yorg;
x2 = s->x2 + xorg;
y2 = s->y2 + yorg;
s++;
2003-11-14 17:48:57 +01:00
#else
x1 = x2;
y1 = y2;
++ppt;
if (mode == CoordModePrevious) {
xorgtmp = x1;
yorgtmp = y1;
}
x2 = ppt->x + xorgtmp;
y2 = ppt->y + yorgtmp;
2003-11-14 17:48:57 +01:00
#endif
if (x1 > maxValX || x1 < minValX ||
x2 > maxValX || x2 < minValX ||
y1 > maxValY || y1 < minValY || y2 > maxValY || y2 < minValY) {
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
XAAFallbackOps.PolySegment(pDrawable, pGC, nseg, pSeg);
2003-11-14 17:48:57 +01:00
#else
XAAFallbackOps.Polylines(pDrawable, pGC, mode, npt, pptInit);
2003-11-14 17:48:57 +01:00
#endif
return;
}
}
2003-11-14 17:48:57 +01:00
}
(*infoRec->SetupForSolidLine) (infoRec->pScrn, pGC->fgPixel,
pGC->alu, pGC->planemask);
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
while (nseg--)
#else
ppt = pptInit;
x2 = ppt->x + xorg;
y2 = ppt->y + yorg;
while (--npt)
2003-11-14 17:48:57 +01:00
#endif
{
nbox = nboxInit;
pbox = pboxInit;
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
x1 = pSeg->x1 + xorg;
y1 = pSeg->y1 + yorg;
x2 = pSeg->x2 + xorg;
y2 = pSeg->y2 + yorg;
pSeg++;
2003-11-14 17:48:57 +01:00
#else
x1 = x2;
y1 = y2;
++ppt;
if (mode == CoordModePrevious) {
xorg = x1;
yorg = y1;
}
x2 = ppt->x + xorg;
y2 = ppt->y + yorg;
2003-11-14 17:48:57 +01:00
#endif
if (x1 == x2) { /* vertical line */
/* make the line go top to bottom of screen, keeping
endpoint semantics
*/
if (y1 > y2) {
tmp = y2;
y2 = y1 + 1;
y1 = tmp + 1;
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
if (pGC->capStyle != CapNotLast)
y1--;
2003-11-14 17:48:57 +01:00
#endif
}
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
else if (pGC->capStyle != CapNotLast)
y2++;
2003-11-14 17:48:57 +01:00
#endif
/* get to first band that might contain part of line */
while (nbox && (pbox->y2 <= y1)) {
pbox++;
nbox--;
}
/* stop when lower edge of box is beyond end of line */
while (nbox && (y2 >= pbox->y1)) {
if ((x1 >= pbox->x1) && (x1 < pbox->x2)) {
tmp = max(y1, pbox->y1);
len = min(y2, pbox->y2) - tmp;
if (len)
(*infoRec->SubsequentSolidHorVertLine) (infoRec->pScrn,
x1, tmp, len,
DEGREES_270);
}
nbox--;
pbox++;
}
2003-11-14 17:48:57 +01:00
#ifndef POLYSEGMENT
y2 = ppt->y + yorg;
2003-11-14 17:48:57 +01:00
#endif
}
else if (y1 == y2) { /* horizontal line */
/* force line from left to right, keeping endpoint semantics */
if (x1 > x2) {
tmp = x2;
x2 = x1 + 1;
x1 = tmp + 1;
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
if (pGC->capStyle != CapNotLast)
x1--;
2003-11-14 17:48:57 +01:00
#endif
}
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
else if (pGC->capStyle != CapNotLast)
x2++;
2003-11-14 17:48:57 +01:00
#endif
/* find the correct band */
while (nbox && (pbox->y2 <= y1)) {
pbox++;
nbox--;
}
/* try to draw the line, if we haven't gone beyond it */
if (nbox && (pbox->y1 <= y1)) {
int orig_y = pbox->y1;
/* when we leave this band, we're done */
while (nbox && (orig_y == pbox->y1)) {
if (pbox->x2 <= x1) {
/* skip boxes until one might contain start point */
nbox--;
pbox++;
continue;
}
/* stop if left of box is beyond right of line */
if (pbox->x1 >= x2) {
nbox = 0;
break;
}
tmp = max(x1, pbox->x1);
len = min(x2, pbox->x2) - tmp;
if (len)
(*infoRec->SubsequentSolidHorVertLine) (infoRec->pScrn,
tmp, y1, len,
DEGREES_0);
nbox--;
pbox++;
}
}
2003-11-14 17:48:57 +01:00
#ifndef POLYSEGMENT
x2 = ppt->x + xorg;
2003-11-14 17:48:57 +01:00
#endif
}
else { /* sloped line */
unsigned int oc1, oc2;
int dmin, dmaj, e, octant;
if (infoRec->SubsequentSolidBresenhamLine) {
if ((dmaj = x2 - x1) < 0) {
dmaj = -dmaj;
octant = XDECREASING;
}
else
octant = 0;
if ((dmin = y2 - y1) < 0) {
dmin = -dmin;
octant |= YDECREASING;
}
if (dmin >= dmaj) {
tmp = dmin;
dmin = dmaj;
dmaj = tmp;
octant |= YMAJOR;
}
e = -dmaj - ((bias >> octant) & 1);
len = dmaj;
dmin <<= 1;
dmaj <<= 1;
}
else { /* Muffle compiler */
dmin = dmaj = e = octant = len = 0;
}
while (nbox--) {
oc1 = oc2 = 0;
OUTCODES(oc1, x1, y1, pbox);
OUTCODES(oc2, x2, y2, pbox);
if (!(oc1 | oc2)) { /* unclipped */
if (infoRec->SubsequentSolidTwoPointLine) {
(*infoRec->SubsequentSolidTwoPointLine) (infoRec->pScrn,
x1, y1, x2, y2,
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
(pGC->
capStyle !=
CapNotLast) ?
0 :
2003-11-14 17:48:57 +01:00
#endif
OMIT_LAST);
}
else {
(*infoRec->SubsequentSolidBresenhamLine) (infoRec->
pScrn, x1, y1,
dmaj, dmin, e,
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
(pGC->
capStyle !=
CapNotLast)
? (len + 1) :
2003-11-14 17:48:57 +01:00
#endif
len, octant);
}
break;
}
else if (oc1 & oc2) { /* completely clipped */
pbox++;
}
else if (infoRec->ClippingFlags & HARDWARE_CLIP_SOLID_LINE) {
(*infoRec->SetClippingRectangle) (infoRec->pScrn,
pbox->x1, pbox->y1,
pbox->x2 - 1,
pbox->y2 - 1);
if (infoRec->SubsequentSolidBresenhamLine) {
(*infoRec->SubsequentSolidBresenhamLine) (infoRec->
pScrn, x1, y1,
dmaj, dmin, e,
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
(pGC->
capStyle !=
CapNotLast)
? (len + 1) :
2003-11-14 17:48:57 +01:00
#endif
len, octant);
}
else {
(*infoRec->SubsequentSolidTwoPointLine) (infoRec->pScrn,
x1, y1, x2, y2,
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
(pGC->
capStyle !=
CapNotLast) ?
0 :
2003-11-14 17:48:57 +01:00
#endif
OMIT_LAST);
}
(*infoRec->DisableClipping) (infoRec->pScrn);
pbox++;
}
else {
int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
int clip1 = 0, clip2 = 0;
int err, adx, ady;
if (octant & YMAJOR) {
ady = dmaj >> 1;
adx = dmin >> 1;
}
else {
ady = dmin >> 1;
adx = dmaj >> 1;
}
if (miZeroClipLine(pbox->x1, pbox->y1,
pbox->x2 - 1, pbox->y2 - 1,
&new_x1, &new_y1, &new_x2, &new_y2,
adx, ady, &clip1, &clip2,
octant, bias, oc1, oc2) == -1) {
pbox++;
continue;
}
if (octant & YMAJOR)
len = abs(new_y2 - new_y1);
else
len = abs(new_x2 - new_x1);
2003-11-14 17:48:57 +01:00
#ifdef POLYSEGMENT
if (clip2 != 0 || pGC->capStyle != CapNotLast)
len++;
2003-11-14 17:48:57 +01:00
#else
len += (clip2 != 0);
2003-11-14 17:48:57 +01:00
#endif
if (len) {
int abserr, clipdx, clipdy;
/* unwind bresenham error term to first point */
if (clip1) {
clipdx = abs(new_x1 - x1);
clipdy = abs(new_y1 - y1);
if (octant & YMAJOR)
err = e + clipdy * dmin - clipdx * dmaj;
else
err = e + clipdx * dmin - clipdy * dmaj;
}
else
err = e;
2003-11-14 17:48:57 +01:00
#define range infoRec->SolidBresenhamLineErrorTermBits
abserr = abs(err);
while ((abserr & range) ||
(dmaj & range) || (dmin & range)) {
dmin >>= 1;
dmaj >>= 1;
abserr >>= 1;
err /= 2;
}
(*infoRec->SubsequentSolidBresenhamLine) (infoRec->
pScrn, new_x1,
new_y1, dmaj,
dmin, err,
len, octant);
}
pbox++;
}
} /* while (nbox--) */
} /* sloped line */
} /* while (nline--) */
2003-11-14 17:48:57 +01:00
#ifndef POLYSEGMENT
/* paint the last point if the end style isn't CapNotLast.
(Assume that a projecting, butt, or round cap that is one
pixel wide is the same as the single pixel of the endpoint.)
*/
2003-11-14 17:48:57 +01:00
if ((pGC->capStyle != CapNotLast) &&
((ppt->x + xorg != pptInit->x + pDrawable->x) ||
(ppt->y + yorg != pptInit->y + pDrawable->y) ||
(ppt == pptInit + 1))) {
nbox = nboxInit;
pbox = pboxInit;
while (nbox--) {
if ((x2 >= pbox->x1) && (y2 >= pbox->y1) &&
(x2 < pbox->x2) && (y2 < pbox->y2)) {
(*infoRec->SubsequentSolidHorVertLine) (infoRec->pScrn, x2, y2,
1, DEGREES_0);
break;
}
else
pbox++;
}
2003-11-14 17:48:57 +01:00
}
#endif
SET_SYNC_FLAG(infoRec);
}