/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: Line functions * FILE: win32ss/gdi/eng/lineto.c * PROGRAMER: ReactOS Team */ #include #define NDEBUG #include 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 */