#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <math.h>
#include <X11/X.h>
#include <X11/Xprotostr.h>
#include "regionstr.h"
#include "gcstruct.h"
#include "pixmapstr.h"
#include "mifpoly.h"
#include "mi.h"
#include "mifillarc.h"
#define QUADRANT (90 * 64)
#define HALFCIRCLE (180 * 64)
#define QUADRANT3 (270 * 64)
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define Dsin(d) sin((double)d*(M_PI/11520.0))
#define Dcos(d) cos((double)d*(M_PI/11520.0))
_X_EXPORT void
miFillArcSetup(arc, info)
xArc *arc;
miFillArcRec *info;
{
info->y = arc->height >> 1;
info->dy = arc->height & 1;
info->yorg = arc->y + info->y;
info->dx = arc->width & 1;
info->xorg = arc->x + (arc->width >> 1) + info->dx;
info->dx = 1 - info->dx;
if (arc->width == arc->height)
{
info->ym = 8;
info->xm = 8;
info->yk = info->y << 3;
if (!info->dx)
{
info->xk = 0;
info->e = -1;
}
else
{
info->y++;
info->yk += 4;
info->xk = -4;
info->e = - (info->y << 3);
}
}
else
{
info->ym = (arc->width * arc->width) << 3;
info->xm = (arc->height * arc->height) << 3;
info->yk = info->y * info->ym;
if (!info->dy)
info->yk -= info->ym >> 1;
if (!info->dx)
{
info->xk = 0;
info->e = - (info->xm >> 3);
}
else
{
info->y++;
info->yk += info->ym;
info->xk = -(info->xm >> 1);
info->e = info->xk - info->yk;
}
}
}
static void
miFillArcDSetup(xArc *arc, miFillArcDRec *info)
{
info->y = arc->height >> 1;
info->dy = arc->height & 1;
info->yorg = arc->y + info->y;
info->dx = arc->width & 1;
info->xorg = arc->x + (arc->width >> 1) + info->dx;
info->dx = 1 - info->dx;
info->ym = ((double)arc->width) * (arc->width * 8);
info->xm = ((double)arc->height) * (arc->height * 8);
info->yk = info->y * info->ym;
if (!info->dy)
info->yk -= info->ym / 2.0;
if (!info->dx)
{
info->xk = 0;
info->e = - (info->xm / 8.0);
}
else
{
info->y++;
info->yk += info->ym;
info->xk = -info->xm / 2.0;
info->e = info->xk - info->yk;
}
}
static void
miGetArcEdge(
xArc *arc,
miSliceEdgePtr edge,
int k,
Bool top,
Bool left )
{
int xady, y;
y = arc->height >> 1;
if (!(arc->width & 1))
y++;
if (!top)
{
y = -y;
if (arc->height & 1)
y--;
}
xady = k + y * edge->dx;
if (xady <= 0)
edge->x = - ((-xady) / edge->dy + 1);
else
edge->x = (xady - 1) / edge->dy;
edge->e = xady - edge->x * edge->dy;
if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0)))
edge->e = edge->dy - edge->e + 1;
if (left)
edge->x++;
edge->x += arc->x + (arc->width >> 1);
if (edge->dx > 0)
{
edge->deltax = 1;
edge->stepx = edge->dx / edge->dy;
edge->dx = edge->dx % edge->dy;
}
else
{
edge->deltax = -1;
edge->stepx = - ((-edge->dx) / edge->dy);
edge->dx = (-edge->dx) % edge->dy;
}
if (!top)
{
edge->deltax = -edge->deltax;
edge->stepx = -edge->stepx;
}
}
static void
miEllipseAngleToSlope (int angle, int width, int height, int *dxp, int *dyp,
double *d_dxp, double *d_dyp)
{
int dx, dy;
double d_dx, d_dy, scale;
Bool negative_dx, negative_dy;
switch (angle) {
case 0:
*dxp = -1;
*dyp = 0;
if (d_dxp) {
*d_dxp = width / 2.0;
*d_dyp = 0;
}
break;
case QUADRANT:
*dxp = 0;
*dyp = 1;
if (d_dxp) {
*d_dxp = 0;
*d_dyp = - height / 2.0;
}
break;
case HALFCIRCLE:
*dxp = 1;
*dyp = 0;
if (d_dxp) {
*d_dxp = - width / 2.0;
*d_dyp = 0;
}
break;
case QUADRANT3:
*dxp = 0;
*dyp = -1;
if (d_dxp) {
*d_dxp = 0;
*d_dyp = height / 2.0;
}
break;
default:
d_dx = Dcos(angle) * width;
d_dy = Dsin(angle) * height;
if (d_dxp) {
*d_dxp = d_dx / 2.0;
*d_dyp = - d_dy / 2.0;
}
negative_dx = FALSE;
if (d_dx < 0.0)
{
d_dx = -d_dx;
negative_dx = TRUE;
}
negative_dy = FALSE;
if (d_dy < 0.0)
{
d_dy = -d_dy;
negative_dy = TRUE;
}
scale = d_dx;
if (d_dy > d_dx)
scale = d_dy;
dx = floor ((d_dx * 32768) / scale + 0.5);
if (negative_dx)
dx = -dx;
*dxp = dx;
dy = floor ((d_dy * 32768) / scale + 0.5);
if (negative_dy)
dy = -dy;
*dyp = dy;
break;
}
}
static void
miGetPieEdge(
xArc *arc,
int angle,
miSliceEdgePtr edge,
Bool top,
Bool left )
{
int k;
int dx, dy;
miEllipseAngleToSlope (angle, arc->width, arc->height, &dx, &dy, 0, 0);
if (dy == 0)
{
edge->x = left ? -65536 : 65536;
edge->stepx = 0;
edge->e = 0;
edge->dx = -1;
return;
}
if (dx == 0)
{
edge->x = arc->x + (arc->width >> 1);
if (left && (arc->width & 1))
edge->x++;
else if (!left && !(arc->width & 1))
edge->x--;
edge->stepx = 0;
edge->e = 0;
edge->dx = -1;
return;
}
if (dy < 0) {
dx = -dx;
dy = -dy;
}
k = (arc->height & 1) ? dx : 0;
if (arc->width & 1)
k += dy;
edge->dx = dx << 1;
edge->dy = dy << 1;
miGetArcEdge(arc, edge, k, top, left);
}
_X_EXPORT void
miFillArcSliceSetup(arc, slice, pGC)
xArc *arc;
miArcSliceRec *slice;
GCPtr pGC;
{
int angle1, angle2;
angle1 = arc->angle1;
if (arc->angle2 < 0)
{
angle2 = angle1;
angle1 += arc->angle2;
}
else
angle2 = angle1 + arc->angle2;
while (angle1 < 0)
angle1 += FULLCIRCLE;
while (angle1 >= FULLCIRCLE)
angle1 -= FULLCIRCLE;
while (angle2 < 0)
angle2 += FULLCIRCLE;
while (angle2 >= FULLCIRCLE)
angle2 -= FULLCIRCLE;
slice->min_top_y = 0;
slice->max_top_y = arc->height >> 1;
slice->min_bot_y = 1 - (arc->height & 1);
slice->max_bot_y = slice->max_top_y - 1;
slice->flip_top = FALSE;
slice->flip_bot = FALSE;
if (pGC->arcMode == ArcPieSlice)
{
slice->edge1_top = (angle1 < HALFCIRCLE);
slice->edge2_top = (angle2 <= HALFCIRCLE);
if ((angle2 == 0) || (angle1 == HALFCIRCLE))
{
if (angle2 ? slice->edge2_top : slice->edge1_top)
slice->min_top_y = slice->min_bot_y;
else
slice->min_top_y = arc->height;
slice->min_bot_y = 0;
}
else if ((angle1 == 0) || (angle2 == HALFCIRCLE))
{
slice->min_top_y = slice->min_bot_y;
if (angle1 ? slice->edge1_top : slice->edge2_top)
slice->min_bot_y = arc->height;
else
slice->min_bot_y = 0;
}
else if (slice->edge1_top == slice->edge2_top)
{
if (angle2 < angle1)
{
slice->flip_top = slice->edge1_top;
slice->flip_bot = !slice->edge1_top;
}
else if (slice->edge1_top)
{
slice->min_top_y = 1;
slice->min_bot_y = arc->height;
}
else
{
slice->min_bot_y = 0;
slice->min_top_y = arc->height;
}
}
miGetPieEdge(arc, angle1, &slice->edge1,
slice->edge1_top, !slice->edge1_top);
miGetPieEdge(arc, angle2, &slice->edge2,
slice->edge2_top, slice->edge2_top);
}
else
{
double w2, h2, x1, y1, x2, y2, dx, dy, scale;
int signdx, signdy, y, k;
Bool isInt1 = TRUE, isInt2 = TRUE;
w2 = (double)arc->width / 2.0;
h2 = (double)arc->height / 2.0;
if ((angle1 == 0) || (angle1 == HALFCIRCLE))
{
x1 = angle1 ? -w2 : w2;
y1 = 0.0;
}
else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3))
{
x1 = 0.0;
y1 = (angle1 == QUADRANT) ? h2 : -h2;
}
else
{
isInt1 = FALSE;
x1 = Dcos(angle1) * w2;
y1 = Dsin(angle1) * h2;
}
if ((angle2 == 0) || (angle2 == HALFCIRCLE))
{
x2 = angle2 ? -w2 : w2;
y2 = 0.0;
}
else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3))
{
x2 = 0.0;
y2 = (angle2 == QUADRANT) ? h2 : -h2;
}
else
{
isInt2 = FALSE;
x2 = Dcos(angle2) * w2;
y2 = Dsin(angle2) * h2;
}
dx = x2 - x1;
dy = y2 - y1;
if (arc->height & 1)
{
y1 -= 0.5;
y2 -= 0.5;
}
if (arc->width & 1)
{
x1 += 0.5;
x2 += 0.5;
}
if (dy < 0.0)
{
dy = -dy;
signdy = -1;
}
else
signdy = 1;
if (dx < 0.0)
{
dx = -dx;
signdx = -1;
}
else
signdx = 1;
if (isInt1 && isInt2)
{
slice->edge1.dx = dx * 2;
slice->edge1.dy = dy * 2;
}
else
{
scale = (dx > dy) ? dx : dy;
slice->edge1.dx = floor((dx * 32768) / scale + .5);
slice->edge1.dy = floor((dy * 32768) / scale + .5);
}
if (!slice->edge1.dy)
{
if (signdx < 0)
{
y = floor(y1 + 1.0);
if (y >= 0)
{
slice->min_top_y = y;
slice->min_bot_y = arc->height;
}
else
{
slice->max_bot_y = -y - (arc->height & 1);
}
}
else
{
y = floor(y1);
if (y >= 0)
slice->max_top_y = y;
else
{
slice->min_top_y = arc->height;
slice->min_bot_y = -y - (arc->height & 1);
}
}
slice->edge1_top = TRUE;
slice->edge1.x = 65536;
slice->edge1.stepx = 0;
slice->edge1.e = 0;
slice->edge1.dx = -1;
slice->edge2 = slice->edge1;
slice->edge2_top = FALSE;
}
else if (!slice->edge1.dx)
{
if (signdy < 0)
x1 -= 1.0;
slice->edge1.x = ceil(x1);
slice->edge1_top = signdy < 0;
slice->edge1.x += arc->x + (arc->width >> 1);
slice->edge1.stepx = 0;
slice->edge1.e = 0;
slice->edge1.dx = -1;
slice->edge2_top = !slice->edge1_top;
slice->edge2 = slice->edge1;
}
else
{
if (signdx < 0)
slice->edge1.dx = -slice->edge1.dx;
if (signdy < 0)
slice->edge1.dx = -slice->edge1.dx;
k = ceil(((x1 + x2) * slice->edge1.dy - (y1 + y2) * slice->edge1.dx) / 2.0);
slice->edge2.dx = slice->edge1.dx;
slice->edge2.dy = slice->edge1.dy;
slice->edge1_top = signdy < 0;
slice->edge2_top = !slice->edge1_top;
miGetArcEdge(arc, &slice->edge1, k,
slice->edge1_top, !slice->edge1_top);
miGetArcEdge(arc, &slice->edge2, k,
slice->edge2_top, slice->edge2_top);
}
}
}
#define ADDSPANS() \
pts->x = xorg - x; \
pts->y = yorg - y; \
*wids = slw; \
pts++; \
wids++; \
if (miFillArcLower(slw)) \
{ \
pts->x = xorg - x; \
pts->y = yorg + y + dy; \
pts++; \
*wids++ = slw; \
}
static void
miFillEllipseI(
DrawablePtr pDraw,
GCPtr pGC,
xArc *arc )
{
int x, y, e;
int yk, xk, ym, xm, dx, dy, xorg, yorg;
int slw;
miFillArcRec info;
DDXPointPtr points;
DDXPointPtr pts;
int *widths;
int *wids;
points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * arc->height);
if (!points)
return;
widths = (int *)ALLOCATE_LOCAL(sizeof(int) * arc->height);
if (!widths)
{
DEALLOCATE_LOCAL(points);
return;
}
miFillArcSetup(arc, &info);
MIFILLARCSETUP();
if (pGC->miTranslate)
{
xorg += pDraw->x;
yorg += pDraw->y;
}
pts = points;
wids = widths;
while (y > 0)
{
MIFILLARCSTEP(slw);
ADDSPANS();
}
(*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
DEALLOCATE_LOCAL(widths);
DEALLOCATE_LOCAL(points);
}
static void
miFillEllipseD(
DrawablePtr pDraw,
GCPtr pGC,
xArc *arc )
{
int x, y;
int xorg, yorg, dx, dy, slw;
double e, yk, xk, ym, xm;
miFillArcDRec info;
DDXPointPtr points;
DDXPointPtr pts;
int *widths;
int *wids;
points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * arc->height);
if (!points)
return;
widths = (int *)ALLOCATE_LOCAL(sizeof(int) * arc->height);
if (!widths)
{
DEALLOCATE_LOCAL(points);
return;
}
miFillArcDSetup(arc, &info);
MIFILLARCSETUP();
if (pGC->miTranslate)
{
xorg += pDraw->x;
yorg += pDraw->y;
}
pts = points;
wids = widths;
while (y > 0)
{
MIFILLARCSTEP(slw);
ADDSPANS();
}
(*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
DEALLOCATE_LOCAL(widths);
DEALLOCATE_LOCAL(points);
}
#define ADDSPAN(l,r) \
if (r >= l) \
{ \
pts->x = l; \
pts->y = ya; \
pts++; \
*wids++ = r - l + 1; \
}
#define ADDSLICESPANS(flip) \
if (!flip) \
{ \
ADDSPAN(xl, xr); \
} \
else \
{ \
xc = xorg - x; \
ADDSPAN(xc, xr); \
xc += slw - 1; \
ADDSPAN(xl, xc); \
}
static void
miFillArcSliceI(
DrawablePtr pDraw,
GCPtr pGC,
xArc *arc )
{
int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
int x, y, e;
miFillArcRec info;
miArcSliceRec slice;
int ya, xl, xr, xc;
DDXPointPtr points;
DDXPointPtr pts;
int *widths;
int *wids;
miFillArcSetup(arc, &info);
miFillArcSliceSetup(arc, &slice, pGC);
MIFILLARCSETUP();
slw = arc->height;
if (slice.flip_top || slice.flip_bot)
slw += (arc->height >> 1) + 1;
points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * slw);
if (!points)
return;
widths = (int *)ALLOCATE_LOCAL(sizeof(int) * slw);
if (!widths)
{
DEALLOCATE_LOCAL(points);
return;
}
if (pGC->miTranslate)
{
xorg += pDraw->x;
yorg += pDraw->y;
slice.edge1.x += pDraw->x;
slice.edge2.x += pDraw->x;
}
pts = points;
wids = widths;
while (y > 0)
{
MIFILLARCSTEP(slw);
MIARCSLICESTEP(slice.edge1);
MIARCSLICESTEP(slice.edge2);
if (miFillSliceUpper(slice))
{
ya = yorg - y;
MIARCSLICEUPPER(xl, xr, slice, slw);
ADDSLICESPANS(slice.flip_top);
}
if (miFillSliceLower(slice))
{
ya = yorg + y + dy;
MIARCSLICELOWER(xl, xr, slice, slw);
ADDSLICESPANS(slice.flip_bot);
}
}
(*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
DEALLOCATE_LOCAL(widths);
DEALLOCATE_LOCAL(points);
}
static void
miFillArcSliceD(
DrawablePtr pDraw,
GCPtr pGC,
xArc *arc )
{
int x, y;
int dx, dy, xorg, yorg, slw;
double e, yk, xk, ym, xm;
miFillArcDRec info;
miArcSliceRec slice;
int ya, xl, xr, xc;
DDXPointPtr points;
DDXPointPtr pts;
int *widths;
int *wids;
miFillArcDSetup(arc, &info);
miFillArcSliceSetup(arc, &slice, pGC);
MIFILLARCSETUP();
slw = arc->height;
if (slice.flip_top || slice.flip_bot)
slw += (arc->height >> 1) + 1;
points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * slw);
if (!points)
return;
widths = (int *)ALLOCATE_LOCAL(sizeof(int) * slw);
if (!widths)
{
DEALLOCATE_LOCAL(points);
return;
}
if (pGC->miTranslate)
{
xorg += pDraw->x;
yorg += pDraw->y;
slice.edge1.x += pDraw->x;
slice.edge2.x += pDraw->x;
}
pts = points;
wids = widths;
while (y > 0)
{
MIFILLARCSTEP(slw);
MIARCSLICESTEP(slice.edge1);
MIARCSLICESTEP(slice.edge2);
if (miFillSliceUpper(slice))
{
ya = yorg - y;
MIARCSLICEUPPER(xl, xr, slice, slw);
ADDSLICESPANS(slice.flip_top);
}
if (miFillSliceLower(slice))
{
ya = yorg + y + dy;
MIARCSLICELOWER(xl, xr, slice, slw);
ADDSLICESPANS(slice.flip_bot);
}
}
(*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
DEALLOCATE_LOCAL(widths);
DEALLOCATE_LOCAL(points);
}
_X_EXPORT void
miPolyFillArc(pDraw, pGC, narcs, parcs)
DrawablePtr pDraw;
GCPtr pGC;
int narcs;
xArc *parcs;
{
int i;
xArc *arc;
for(i = narcs, arc = parcs; --i >= 0; arc++)
{
if (miFillArcEmpty(arc))
continue;;
if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE))
{
if (miCanFillArc(arc))
miFillEllipseI(pDraw, pGC, arc);
else
miFillEllipseD(pDraw, pGC, arc);
}
else
{
if (miCanFillArc(arc))
miFillArcSliceI(pDraw, pGC, arc);
else
miFillArcSliceD(pDraw, pGC, arc);
}
}
}