reactos/win32ss/gdi/eng/lineto.c

740 lines
20 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Line functions
* FILE: win32ss/gdi/eng/lineto.c
* PROGRAMER: ReactOS Team
*/
#include <win32k.h>
#define NDEBUG
#include <debug.h>
static void FASTCALL
TranslateRects(RECT_ENUM *RectEnum, POINTL* Translate)
{
RECTL* CurrentRect;
if (0 != Translate->x || 0 != Translate->y)
{
for (CurrentRect = RectEnum->arcl; CurrentRect < RectEnum->arcl + RectEnum->c; CurrentRect++)
{
CurrentRect->left += Translate->x;
CurrentRect->right += Translate->x;
CurrentRect->top += Translate->y;
CurrentRect->bottom += Translate->y;
}
}
}
LONG
HandleStyles(
BRUSHOBJ *pbo,
POINTL* Translate,
LONG x,
LONG y,
LONG deltax,
LONG deltay,
LONG dx,
LONG dy,
PULONG piStyle)
{
PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo;
PULONG pulStyles = pebo->pbrush->pStyle;
ULONG iStyle, cStyles = pebo->pbrush->dwStyleCount;
LONG diStyle, offStyle, lStyleMax;
if (cStyles > 0)
{
if (deltax > deltay)
{
offStyle = (- Translate->x) % pebo->pbrush->ulStyleSize;
diStyle = dx;
lStyleMax = x;
}
else
{
offStyle = (- Translate->y) % pebo->pbrush->ulStyleSize;
diStyle = dy;
lStyleMax = y;
}
/* Now loop until we have found the style index */
for (iStyle = 0; offStyle >= pulStyles[iStyle]; iStyle++)
{
offStyle -= pulStyles[iStyle];
}
if (diStyle > 0)
{
lStyleMax += pulStyles[iStyle] - offStyle;
}
else
{
lStyleMax -= offStyle + 1;
}
}
else
{
iStyle = 0;
lStyleMax = MAX_COORD;
}
*piStyle = iStyle;
return lStyleMax;
}
/*
* Draw a line from top-left to bottom-right
*/
void FASTCALL
NWtoSE(SURFOBJ* OutputObj, CLIPOBJ* Clip,
BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay,
POINTL* Translate)
{
int i;
int error;
BOOLEAN EnumMore;
RECTL* ClipRect;
RECT_ENUM RectEnum;
ULONG Pixel = pbo->iSolidColor;
LONG delta;
PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo;
PULONG pulStyles = pebo->pbrush->pStyle;
ULONG iStyle, cStyles = pebo->pbrush->dwStyleCount;
LONG lStyleMax;
lStyleMax = HandleStyles(pbo, Translate, x, y, deltax, deltay, 1, 1, &iStyle);
CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
TranslateRects(&RectEnum, Translate);
ClipRect = RectEnum.arcl;
delta = max(deltax, deltay);
i = 0;
error = delta >> 1;
while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
{
while ((ClipRect < RectEnum.arcl + RectEnum.c /* there's still a current clip rect */
&& (ClipRect->bottom <= y /* but it's above us */
|| (ClipRect->top <= y && ClipRect->right <= x))) /* or to the left of us */
|| EnumMore) /* no current clip rect, but rects left */
{
/* Skip to the next clip rect */
if (RectEnum.arcl + RectEnum.c <= ClipRect)
{
EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
TranslateRects(&RectEnum, Translate);
ClipRect = RectEnum.arcl;
}
else
{
ClipRect++;
}
}
if (ClipRect < RectEnum.arcl + RectEnum.c) /* If there's no current clip rect we're done */
{
if ((ClipRect->left <= x && ClipRect->top <= y) && ((iStyle & 1) == 0))
{
DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel(
OutputObj, x, y, Pixel);
}
if (deltax < deltay)
{
y++;
if (y == lStyleMax)
{
iStyle = (iStyle + 1) % cStyles;
lStyleMax = y + pulStyles[iStyle];
}
error = error + deltax;
if (deltay <= error)
{
x++;
error = error - deltay;
}
}
else
{
x++;
if (x == lStyleMax)
{
iStyle = (iStyle + 1) % cStyles;
lStyleMax = x + pulStyles[iStyle];
}
error = error + deltay;
if (deltax <= error)
{
y++;
error = error - deltax;
}
}
i++;
}
}
}
void FASTCALL
SWtoNE(SURFOBJ* OutputObj, CLIPOBJ* Clip,
BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay,
POINTL* Translate)
{
int i;
int error;
BOOLEAN EnumMore;
RECTL* ClipRect;
RECT_ENUM RectEnum;
ULONG Pixel = pbo->iSolidColor;
LONG delta;
PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo;
PULONG pulStyles = pebo->pbrush->pStyle;
ULONG iStyle, cStyles = pebo->pbrush->dwStyleCount;
LONG lStyleMax;
lStyleMax = HandleStyles(pbo, Translate, x, y, deltax, deltay, 1, -1, &iStyle);
CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTUP, 0);
EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
TranslateRects(&RectEnum, Translate);
ClipRect = RectEnum.arcl;
delta = max(deltax, deltay);
i = 0;
error = delta >> 1;
while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
{
while ((ClipRect < RectEnum.arcl + RectEnum.c
&& (y < ClipRect->top
|| (y < ClipRect->bottom && ClipRect->right <= x)))
|| EnumMore)
{
if (RectEnum.arcl + RectEnum.c <= ClipRect)
{
EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
TranslateRects(&RectEnum, Translate);
ClipRect = RectEnum.arcl;
}
else
{
ClipRect++;
}
}
if (ClipRect < RectEnum.arcl + RectEnum.c)
{
if ((ClipRect->left <= x && y < ClipRect->bottom) && ((iStyle & 1) == 0))
{
DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel(
OutputObj, x, y, Pixel);
}
if (deltax < deltay)
{
y--;
if (y == lStyleMax)
{
iStyle = (iStyle - 1) % cStyles;
lStyleMax = y - pulStyles[iStyle];
}
error = error + deltax;
if (deltay <= error)
{
x++;
error = error - deltay;
}
}
else
{
x++;
if (x == lStyleMax)
{
iStyle = (iStyle + 1) % cStyles;
lStyleMax = x + pulStyles[iStyle];
}
error = error + deltay;
if (deltax <= error)
{
y--;
error = error - deltax;
}
}
i++;
}
}
}
void FASTCALL
NEtoSW(SURFOBJ* OutputObj, CLIPOBJ* Clip,
BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay,
POINTL* Translate)
{
int i;
int error;
BOOLEAN EnumMore;
RECTL* ClipRect;
RECT_ENUM RectEnum;
ULONG Pixel = pbo->iSolidColor;
LONG delta;
PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo;
PULONG pulStyles = pebo->pbrush->pStyle;
ULONG iStyle, cStyles = pebo->pbrush->dwStyleCount;
LONG lStyleMax;
lStyleMax = HandleStyles(pbo, Translate, x, y, deltax, deltay, -1, 1, &iStyle);
CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_LEFTDOWN, 0);
EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
TranslateRects(&RectEnum, Translate);
ClipRect = RectEnum.arcl;
delta = max(deltax, deltay);
i = 0;
error = delta >> 1;
while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
{
while ((ClipRect < RectEnum.arcl + RectEnum.c
&& (ClipRect->bottom <= y
|| (ClipRect->top <= y && x < ClipRect->left)))
|| EnumMore)
{
if (RectEnum.arcl + RectEnum.c <= ClipRect)
{
EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
TranslateRects(&RectEnum, Translate);
ClipRect = RectEnum.arcl;
}
else
{
ClipRect++;
}
}
if (ClipRect < RectEnum.arcl + RectEnum.c)
{
if ((x < ClipRect->right && ClipRect->top <= y) && ((iStyle & 1) == 0))
{
DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel(
OutputObj, x, y, Pixel);
}
if (deltax < deltay)
{
y++;
if (y == lStyleMax)
{
iStyle = (iStyle + 1) % cStyles;
lStyleMax = y + pulStyles[iStyle];
}
error = error + deltax;
if (deltay <= error)
{
x--;
error = error - deltay;
}
}
else
{
x--;
if (x == lStyleMax)
{
iStyle = (iStyle - 1) % cStyles;
lStyleMax = x - pulStyles[iStyle];
}
error = error + deltay;
if (deltax <= error)
{
y++;
error = error - deltax;
}
}
i++;
}
}
}
void FASTCALL
SEtoNW(SURFOBJ* OutputObj, CLIPOBJ* Clip,
BRUSHOBJ* pbo, LONG x, LONG y, LONG deltax, LONG deltay,
POINTL* Translate)
{
int i;
int error;
BOOLEAN EnumMore;
RECTL* ClipRect;
RECT_ENUM RectEnum;
ULONG Pixel = pbo->iSolidColor;
LONG delta;
PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo;
PULONG pulStyles = pebo->pbrush->pStyle;
ULONG iStyle, cStyles = pebo->pbrush->dwStyleCount;
LONG lStyleMax;
lStyleMax = HandleStyles(pbo, Translate, x, y, deltax, deltay, -1, -1, &iStyle);
CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_LEFTUP, 0);
EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
TranslateRects(&RectEnum, Translate);
ClipRect = RectEnum.arcl;
delta = max(deltax, deltay);
i = 0;
error = delta >> 1;
while (i < delta && (ClipRect < RectEnum.arcl + RectEnum.c || EnumMore))
{
while ((ClipRect < RectEnum.arcl + RectEnum.c
&& (y < ClipRect->top
|| (y < ClipRect->bottom && x < ClipRect->left)))
|| EnumMore)
{
if (RectEnum.arcl + RectEnum.c <= ClipRect)
{
EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
TranslateRects(&RectEnum, Translate);
ClipRect = RectEnum.arcl;
}
else
{
ClipRect++;
}
}
if (ClipRect < RectEnum.arcl + RectEnum.c)
{
if ((x < ClipRect->right && y < ClipRect->bottom) && ((iStyle & 1) == 0))
{
DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel(
OutputObj, x, y, Pixel);
}
if (deltax < deltay)
{
y--;
if (y == lStyleMax)
{
iStyle = (iStyle - 1) % cStyles;
lStyleMax = y - pulStyles[iStyle];
}
error = error + deltax;
if (deltay <= error)
{
x--;
error = error - deltay;
}
}
else
{
x--;
if (x == lStyleMax)
{
iStyle = (iStyle - 1) % cStyles;
lStyleMax = x - pulStyles[iStyle];
}
error = error + deltay;
if (deltax <= error)
{
y--;
error = error - deltax;
}
}
i++;
}
}
}
/*
* @implemented
*/
BOOL APIENTRY
EngLineTo(
_Inout_ SURFOBJ *DestObj,
_In_ CLIPOBJ *Clip,
_In_ BRUSHOBJ *pbo,
_In_ LONG x1,
_In_ LONG y1,
_In_ LONG x2,
_In_ LONG y2,
_In_opt_ RECTL *RectBounds,
_In_ MIX mix)
{
LONG x, y, deltax, deltay, xchange, ychange, hx, vy;
ULONG i;
ULONG Pixel = pbo->iSolidColor;
SURFOBJ *OutputObj;
RECTL DestRect;
POINTL Translate;
INTENG_ENTER_LEAVE EnterLeave;
RECT_ENUM RectEnum;
BOOL EnumMore;
CLIPOBJ *pcoPriv = NULL;
PEBRUSHOBJ pebo = (PEBRUSHOBJ)pbo;
ULONG cStyles = pebo->pbrush->dwStyleCount;
if (x1 < x2)
{
DestRect.left = x1;
DestRect.right = x2;
}
else
{
DestRect.left = x2;
DestRect.right = x1 + 1;
}
if (y1 < y2)
{
DestRect.top = y1;
DestRect.bottom = y2;
}
else
{
DestRect.top = y2;
DestRect.bottom = y1 + 1;
}
if (! IntEngEnter(&EnterLeave, DestObj, &DestRect, FALSE, &Translate, &OutputObj))
{
return FALSE;
}
if (!Clip)
{
Clip = pcoPriv = EngCreateClip();
if (!Clip)
{
return FALSE;
}
IntEngUpdateClipRegion((XCLIPOBJ*)Clip, 0, 0, RectBounds);
}
x1 += Translate.x;
x2 += Translate.x;
y1 += Translate.y;
y2 += Translate.y;
x = x1;
y = y1;
deltax = x2 - x1;
deltay = y2 - y1;
if (0 == deltax && 0 == deltay)
{
return TRUE;
}
if (deltax < 0)
{
xchange = -1;
deltax = - deltax;
hx = x2 + 1;
}
else
{
xchange = 1;
hx = x1;
}
if (deltay < 0)
{
ychange = -1;
deltay = - deltay;
vy = y2 + 1;
}
else
{
ychange = 1;
vy = y1;
}
if ((y1 == y2) && (cStyles == 0))
{
CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
do
{
EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top + Translate.y <= y1; i++)
{
if (y1 < RectEnum.arcl[i].bottom + Translate.y &&
RectEnum.arcl[i].left + Translate.x <= hx + deltax &&
hx < RectEnum.arcl[i].right + Translate.x &&
max(hx, RectEnum.arcl[i].left + Translate.x) <
min(hx + deltax, RectEnum.arcl[i].right + Translate.x))
{
DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_HLine(
OutputObj,
max(hx, RectEnum.arcl[i].left + Translate.x),
min(hx + deltax, RectEnum.arcl[i].right + Translate.x),
y1, Pixel);
}
}
}
while (EnumMore);
}
else if ((x1 == x2) && (cStyles == 0))
{
CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
do
{
EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
for (i = 0; i < RectEnum.c; i++)
{
if (RectEnum.arcl[i].left + Translate.x <= x1 &&
x1 < RectEnum.arcl[i].right + Translate.x &&
RectEnum.arcl[i].top + Translate.y <= vy + deltay &&
vy < RectEnum.arcl[i].bottom + Translate.y)
{
DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_VLine(
OutputObj, x1,
max(vy, RectEnum.arcl[i].top + Translate.y),
min(vy + deltay, RectEnum.arcl[i].bottom + Translate.y),
Pixel);
}
}
}
while (EnumMore);
}
else
{
if (0 < xchange)
{
if (0 < ychange)
{
NWtoSE(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
}
else
{
SWtoNE(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
}
}
else
{
if (0 < ychange)
{
NEtoSW(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
}
else
{
SEtoNW(OutputObj, Clip, pbo, x, y, deltax, deltay, &Translate);
}
}
}
if (pcoPriv)
{
EngDeleteClip(pcoPriv);
}
return IntEngLeave(&EnterLeave);
}
BOOL APIENTRY
IntEngLineTo(SURFOBJ *psoDest,
CLIPOBJ *ClipObj,
BRUSHOBJ *pbo,
LONG x1,
LONG y1,
LONG x2,
LONG y2,
RECTL *RectBounds,
MIX Mix)
{
BOOLEAN ret;
SURFACE *psurfDest;
PEBRUSHOBJ GdiBrush;
RECTL b;
ASSERT(psoDest);
psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
ASSERT(psurfDest);
GdiBrush = CONTAINING_RECORD(
pbo,
EBRUSHOBJ,
BrushObject);
ASSERT(GdiBrush);
ASSERT(GdiBrush->pbrush);
if (GdiBrush->pbrush->flAttrs & BR_IS_NULL)
return TRUE;
/* No success yet */
ret = FALSE;
/* Clip lines totally outside the clip region. This is not done as an
* optimization (there are very few lines drawn outside the region) but
* as a workaround for what seems to be a problem in the CL54XX driver */
if (NULL == ClipObj || DC_TRIVIAL == ClipObj->iDComplexity)
{
b.left = 0;
b.right = psoDest->sizlBitmap.cx;
b.top = 0;
b.bottom = psoDest->sizlBitmap.cy;
}
else
{
b = ClipObj->rclBounds;
}
if ((x1 < b.left && x2 < b.left) || (b.right <= x1 && b.right <= x2) ||
(y1 < b.top && y2 < b.top) || (b.bottom <= y1 && b.bottom <= y2))
{
return TRUE;
}
b.left = min(x1, x2);
b.right = max(x1, x2);
b.top = min(y1, y2);
b.bottom = max(y1, y2);
if (b.left == b.right) b.right++;
if (b.top == b.bottom) b.bottom++;
if (psurfDest->flags & HOOK_LINETO)
{
/* Call the driver's DrvLineTo */
ret = GDIDEVFUNCS(psoDest).LineTo(
psoDest, ClipObj, pbo, x1, y1, x2, y2, &b, Mix);
}
#if 0
if (! ret && (psurfDest->flags & HOOK_STROKEPATH))
{
/* FIXME: Emulate LineTo using drivers DrvStrokePath and set ret on success */
}
#endif
if (! ret)
{
ret = EngLineTo(psoDest, ClipObj, pbo, x1, y1, x2, y2, RectBounds, Mix);
}
return ret;
}
BOOL APIENTRY
IntEngPolyline(SURFOBJ *psoDest,
CLIPOBJ *Clip,
BRUSHOBJ *pbo,
CONST LPPOINT pt,
LONG dCount,
MIX Mix)
{
LONG i;
RECTL rect;
BOOL ret = FALSE;
// Draw the Polyline with a call to IntEngLineTo for each segment.
for (i = 1; i < dCount; i++)
{
rect.left = min(pt[i-1].x, pt[i].x);
rect.top = min(pt[i-1].y, pt[i].y);
rect.right = max(pt[i-1].x, pt[i].x);
rect.bottom = max(pt[i-1].y, pt[i].y);
ret = IntEngLineTo(psoDest,
Clip,
pbo,
pt[i-1].x,
pt[i-1].y,
pt[i].x,
pt[i].y,
&rect,
Mix);
if (!ret)
{
break;
}
}
return ret;
}
/* EOF */