From 9f5ede7adb3efb91586abf15a2e9f8cf8071e949 Mon Sep 17 00:00:00 2001 From: James Tabor Date: Tue, 1 Jul 2008 13:30:44 +0000 Subject: [PATCH] Arc, Ellipse: - Converted over to use the new fill square algorithm for fill arcs and draw/fill ellipse. - Tested with (Area.exe) Yuan program. Chord work and the CW/CCW works as it should. - The pie angle still floats with aspect ratio of ellipse and not point fixed. Work in progress. svn path=/trunk/; revision=34233 --- reactos/subsystems/win32/win32k/objects/arc.c | 53 ++- .../subsystems/win32/win32k/objects/drawing.c | 376 ++++++++++++++++-- .../win32/win32k/objects/fillshap.c | 270 ++++--------- 3 files changed, 452 insertions(+), 247 deletions(-) diff --git a/reactos/subsystems/win32/win32k/objects/arc.c b/reactos/subsystems/win32/win32k/objects/arc.c index 7cefebec2f4..95f9a1f9e05 100644 --- a/reactos/subsystems/win32/win32k/objects/arc.c +++ b/reactos/subsystems/win32/win32k/objects/arc.c @@ -42,7 +42,7 @@ IntArc( DC *dc, ARCTYPE arctype) { PDC_ATTR Dc_Attr; - RECTL RectBounds; + RECTL RectBounds, RectSEpts; PGDIBRUSHOBJ PenBrushObj; GDIBRUSHINST PenBrushInst; BITMAPOBJ *BitmapObj; @@ -67,17 +67,6 @@ IntArc( DC *dc, (Bottom - Top == 1)))) return TRUE; - if (dc->DcLevel.flPath & DCPATH_CLOCKWISE) - { - INT X, Y; - X = XRadialStart; - Y = YRadialStart; - XRadialStart = XRadialEnd; - YRadialStart = YRadialEnd; - XRadialEnd = X; - YRadialEnd = Y; - } - Dc_Attr = dc->pDc_Attr; if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr; @@ -105,25 +94,31 @@ IntArc( DC *dc, if (!PenWidth) PenWidth = 1; PenBrushObj->ptPenWidth.x = PenWidth; - Left += dc->ptlDCOrig.x; - Right += dc->ptlDCOrig.x; - Top += dc->ptlDCOrig.y; - Bottom += dc->ptlDCOrig.y; - - XRadialStart += dc->ptlDCOrig.x; - YRadialStart += dc->ptlDCOrig.y; - XRadialEnd += dc->ptlDCOrig.x; - YRadialEnd += dc->ptlDCOrig.y; - - DPRINT("1: StartX: %d, StartY: %d, EndX: %d, EndY: %d\n", - XRadialStart,YRadialStart,XRadialEnd,YRadialEnd); - RectBounds.left = Left; RectBounds.right = Right; RectBounds.top = Top; RectBounds.bottom = Bottom; + RectSEpts.left = XRadialStart; + RectSEpts.top = YRadialStart; + RectSEpts.right = XRadialEnd; + RectSEpts.bottom = YRadialEnd; + IntLPtoDP(dc, (LPPOINT)&RectBounds, 2); + IntLPtoDP(dc, (LPPOINT)&RectSEpts, 2); + + RectBounds.left += dc->ptlDCOrig.x; + RectBounds.right += dc->ptlDCOrig.x; + RectBounds.top += dc->ptlDCOrig.y; + RectBounds.bottom += dc->ptlDCOrig.y; + + RectSEpts.left += dc->ptlDCOrig.x; + RectSEpts.top += dc->ptlDCOrig.y; + RectSEpts.right += dc->ptlDCOrig.x; + RectSEpts.bottom += dc->ptlDCOrig.y; + + DPRINT("1: StartX: %d, StartY: %d, EndX: %d, EndY: %d\n", + RectSEpts.left,RectSEpts.top,RectSEpts.right,RectSEpts.bottom); DPRINT("1: Left: %d, Top: %d, Right: %d, Bottom: %d\n", RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom); @@ -132,8 +127,8 @@ IntArc( DC *dc, RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 1); CenterX = (RectBounds.right + RectBounds.left) / 2; CenterY = (RectBounds.bottom + RectBounds.top) / 2; - AngleEnd = atan2((YRadialEnd - CenterY), XRadialEnd - CenterX)*(360.0/(M_PI*2)); - AngleStart = atan2((YRadialStart - CenterY), XRadialStart - CenterX)*(360.0/(M_PI*2)); + AngleEnd = atan2((RectSEpts.bottom - CenterY), RectSEpts.right - CenterX)*(360.0/(M_PI*2)); + AngleStart = atan2((RectSEpts.top - CenterY), RectSEpts.left - CenterX)*(360.0/(M_PI*2)); SfCx = (Rcos(AngleStart) * RadiusX); SfCy = (Rsin(AngleStart) * RadiusY); @@ -175,7 +170,7 @@ IntArc( DC *dc, if (dc->DcLevel.flPath & DCPATH_CLOCKWISE) { - DPRINT("Arc CW\n"); + DPRINT1("Arc CW\n"); for (; AngS < AngT; AngS += Factor) { x = (RadiusX * Rcos(AngS)); @@ -197,7 +192,7 @@ IntArc( DC *dc, } else { - DPRINT("Arc CCW\n"); + DPRINT1("Arc CCW\n"); for (; AngT < AngS; AngS -= Factor) { x = (RadiusX * Rcos(AngS)); diff --git a/reactos/subsystems/win32/win32k/objects/drawing.c b/reactos/subsystems/win32/win32k/objects/drawing.c index 35f881ce3cb..8390304d840 100755 --- a/reactos/subsystems/win32/win32k/objects/drawing.c +++ b/reactos/subsystems/win32/win32k/objects/drawing.c @@ -81,12 +81,11 @@ INTERNAL_CALL rect(int x, int y, int width, int height) { Rect r; - r.x = x; - r.y = y; - r.width = width; - r.height = height; - return r; + r.y = y; + r.width = width; + r.height = height; + return r; } @@ -107,11 +106,13 @@ int INTERNAL_CALL app_fill_rect(DC *dc, Rect r, PGDIBRUSHOBJ BrushObj) { + DWORD ROP = PATCOPY; RECTL DestRect; BITMAPOBJ *BitmapObj; GDIBRUSHINST BrushInst; POINTL BrushOrigin; BOOL Ret = TRUE; + PDC_ATTR Dc_Attr = NULL; ASSERT(BrushObj); @@ -124,6 +125,8 @@ app_fill_rect(DC *dc, Rect r, PGDIBRUSHOBJ BrushObj) if (!(BrushObj->flAttrs & GDIBRUSH_IS_NULL)) { + Dc_Attr = dc->pDc_Attr; + if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr; /* fix negative spaces */ if (r.width < 0) @@ -146,6 +149,11 @@ app_fill_rect(DC *dc, Rect r, PGDIBRUSHOBJ BrushObj) BrushOrigin.x = BrushObj->ptOrigin.x; BrushOrigin.y = BrushObj->ptOrigin.y; + if (Dc_Attr->jROP2 == R2_XORPEN) + ROP = PATINVERT; + else + ROP = PATCOPY; + IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlateBrush); Ret = IntEngBitBlt( @@ -159,13 +167,301 @@ app_fill_rect(DC *dc, Rect r, PGDIBRUSHOBJ BrushObj) NULL, &BrushInst.BrushObject, // use pDC->eboFill &BrushOrigin, - ROP3_TO_ROP4(PATCOPY)); + ROP3_TO_ROP4(ROP)); } BITMAPOBJ_UnlockBitmap(BitmapObj); return (int)Ret; } +static +int +INTERNAL_CALL +app_fill_rect_pen(DC *dc, Rect r, PGDIBRUSHOBJ BrushObj) +{ + DWORD ROP = PATCOPY; + RECTL DestRect; + BITMAPOBJ *BitmapObj; + GDIBRUSHINST BrushInst; + POINTL BrushOrigin; + BOOL Ret = TRUE; + PDC_ATTR Dc_Attr = NULL; + + ASSERT(BrushObj); + + BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap); + if (BitmapObj == NULL) + { + SetLastWin32Error(ERROR_INVALID_HANDLE); + return 0; + } + + if (!(BrushObj->flAttrs & GDIBRUSH_IS_NULL)) + { + Dc_Attr = dc->pDc_Attr; + if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr; + + /* fix negative spaces */ + if (r.width < 0) + { + r.x += r.width; + r.width = 0 - r.width; + } + if (r.height < 0) + { + r.y += r.height; + r.height = 0 - r.height; + } + + DestRect.left = r.x; + DestRect.right = r.x + r.width; + + DestRect.top = r.y; + DestRect.bottom = r.y + r.height; + + BrushOrigin.x = BrushObj->ptOrigin.x; + BrushOrigin.y = BrushObj->ptOrigin.y; + + if (Dc_Attr->jROP2 == R2_XORPEN) + ROP = PATINVERT; + else + ROP = PATCOPY; + + IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlatePen); + + Ret = IntEngBitBlt( + &BitmapObj->SurfObj, + NULL, + NULL, + dc->CombinedClip, + NULL, + &DestRect, + NULL, + NULL, + &BrushInst.BrushObject, // use pDC->eboFill + &BrushOrigin, + ROP3_TO_ROP4(ROP)); + } + + BITMAPOBJ_UnlockBitmap(BitmapObj); + return (int)Ret; +} + + +/* + * Drawing an ellipse with a certain line thickness. + * Use an inner and and outer ellipse and fill the spaces between. + * The inner ellipse uses all UPPERCASE letters, the outer lowercase. + * + * This algorithm is based on the fill_ellipse algorithm presented + * above, but uses two ellipse calculations, and some fix-up code + * to avoid pathological cases where the inner ellipse is almost + * the same size as the outer (in which case the border of the + * elliptical curve might otherwise have appeared broken). + */ +static +int +INTERNAL_CALL +app_draw_ellipse(DC *g, Rect r, PGDIBRUSHOBJ BrushObj) +{ + /* Outer ellipse: e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */ + + int a = r.width / 2; + int b = r.height / 2; + int x = 0; + int y = b; + long a2 = a*a; + long b2 = b*b; + long xcrit = (3 * a2 / 4) + 1; + long ycrit = (3 * b2 / 4) + 1; + long t = b2 + a2 - 2*a2*b; /* t = e(x+1,y-1) */ + long dxt = b2*(3+x+x); + long dyt = a2*(3-y-y); + int d2xt = b2+b2; + int d2yt = a2+a2; + + int w = BrushObj->ptPenWidth.x; + + /* Inner ellipse: E(X,Y) = B*B*X*X + A*A*Y*Y - A*A*B*B */ + + int A = a-w > 0 ? a-w : 0; + int B = b-w > 0 ? b-w : 0; + int X = 0; + int Y = B; + long A2 = A*A; + long B2 = B*B; + long XCRIT = (3 * A2 / 4) + 1; + long YCRIT = (3 * B2 / 4) + 1; + long T = B2 + A2 - 2*A2*B; /* T = E(X+1,Y-1) */ + long DXT = B2*(3+X+X); + long DYT = A2*(3-Y-Y); + int D2XT = B2+B2; + int D2YT = A2+A2; + + int movedown, moveout; + int innerX = 0, prevx, prevy, W; + Rect r1, r2; + int result = 1; + +// START_DEBUG(); + + if ((r.width <= 2) || (r.height <= 2)) + return app_fill_rect_pen(g, r, BrushObj); + + r1.x = r.x + a; + r1.y = r.y; + r1.width = r.width & 1; /* i.e. if width is odd */ + r1.height = 1; + + r2 = r1; + r2.y = r.y + r.height - 1; + + prevx = r1.x; + prevy = r1.y; + + while (y > 0) + { + while (Y == y) + { + innerX = X; + + if (T + A2*Y < XCRIT) /* E(X+1,Y-1/2) <= 0 */ + { + /* move outwards to encounter edge */ + X += 1; + T += DXT; + DXT += D2XT; + } + else if (T - B2*X >= YCRIT) /* e(x+1/2,y-1) > 0 */ + { + /* drop down one line */ + Y -= 1; + T += DYT; + DYT += D2YT; + } + else { + /* drop diagonally down and out */ + X += 1; + Y -= 1; + T += DXT + DYT; + DXT += D2XT; + DYT += D2YT; + } + } + + movedown = moveout = 0; + + W = x - innerX; + if (r1.x + W < prevx) + W = prevx - r1.x; + if (W < w) + W = w; + + if (t + a2*y < xcrit) /* e(x+1,y-1/2) <= 0 */ + { + /* move outwards to encounter edge */ + x += 1; + t += dxt; + dxt += d2xt; + + moveout = 1; + } + else if (t - b2*x >= ycrit) /* e(x+1/2,y-1) > 0 */ + { + /* drop down one line */ + y -= 1; + t += dyt; + dyt += d2yt; + + movedown = 1; + } + else { + /* drop diagonally down and out */ + x += 1; + y -= 1; + t += dxt + dyt; + dxt += d2xt; + dyt += d2yt; + + movedown = 1; + moveout = 1; + } + + if (movedown) { + if (r1.width == 0) { + r1.x -= 1; r1.width += 2; + r2.x -= 1; r2.width += 2; + moveout = 0; + } + + if (r1.x < r.x) + r1.x = r2.x = r.x; + if (r1.width > r.width) + r1.width = r2.width = r.width; + if (r1.y == r2.y-1) { + r1.x = r2.x = r.x; + r1.width = r2.width = r.width; + } + + if ((r1.y < r.y+w) || (r1.x+W >= r1.x+r1.width-W)) + { + result &= app_fill_rect_pen(g, r1, BrushObj); + result &= app_fill_rect_pen(g, r2, BrushObj); + + prevx = r1.x; + prevy = r1.y; + } + else if (r1.y+r1.height < r2.y) + { + /* draw distinct rectangles */ + result &= app_fill_rect_pen(g, rect(r1.x,r1.y, + W,1), BrushObj); + result &= app_fill_rect_pen(g, rect( + r1.x+r1.width-W,r1.y,W,1), BrushObj); + result &= app_fill_rect_pen(g, rect(r2.x, + r2.y,W,1), BrushObj); + result &= app_fill_rect_pen(g, rect( + r2.x+r2.width-W,r2.y,W,1), BrushObj); + + prevx = r1.x; + prevy = r1.y; + } + + /* move down */ + r1.y += 1; + r2.y -= 1; + } + + if (moveout) { + /* move outwards */ + r1.x -= 1; r1.width += 2; + r2.x -= 1; r2.width += 2; + } + } + if ((x <= a) && (prevy < r2.y)) { + /* draw final line */ + r1.height = r1.y+r1.height-r2.y; + r1.y = r2.y; + + W = w; + if (r.x + W != prevx) + W = prevx - r.x; + if (W < w) + W = w; + + if (W+W >= r.width) { + result &= app_fill_rect_pen(g, rect(r.x, r1.y, + r.width, r1.height), BrushObj); + return result; + } + + result &= app_fill_rect_pen(g, rect(r.x, r1.y, W, r1.height), BrushObj); + result &= app_fill_rect_pen(g, rect(r.x+r.width-W, r1.y, + W, r1.height), BrushObj); + } + return result; +} + /* * Draw an arc of an ellipse from start_angle anti-clockwise to * end_angle. If the angles coincide, draw nothing; if they @@ -652,14 +948,11 @@ app_fill_arc(DC *g, Rect r, int start_angle, int end_angle, PGDIBRUSHOBJ BrushOb /* find arc wedge line end points */ p1 = app_boundary_point(r, start_angle); p2 = app_boundary_point(r, end_angle); - p0 = pt(r.x + r.width/2, r.y + r.height/2); if (Chord) - { - int zx, zy; - zx = (p0.x-p1.x)/2; - zy = (p2.y-p1.y)/2; - p0 = pt(p1.x+zx,p0.y+zy); - } + p0 = pt((p1.x+p2.x)/2,(p1.y+p2.y)/2); + else + p0 = pt(r.x + r.width/2, r.y + r.height/2); + /* initialise rectangles to be drawn */ r1.x = r.x + a; r1.y = r.y; @@ -785,8 +1078,7 @@ IntFillArc( PDC dc, PGDIBRUSHOBJ FillBrushObj; int Start = ceill(StartArc); int End = ceill(EndArc); - Rect r; - BOOL Chord = (arctype == GdiTypeChord); + BOOL Chord = (arctype == GdiTypeChord), ret; Dc_Attr = dc->pDc_Attr; if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr; @@ -798,18 +1090,52 @@ IntFillArc( PDC dc, SetLastWin32Error(ERROR_INTERNAL_ERROR); return FALSE; } - r.x = XLeft; - r.y = YLeft; - r.width = Width; - r.height = Height; // Sort out alignment here. - app_fill_arc(dc, r, - (dc->DcLevel.flPath & DCPATH_CLOCKWISE) ? -End : -Start, - (dc->DcLevel.flPath & DCPATH_CLOCKWISE) ? -Start : -End, - FillBrushObj, Chord); - + ret = app_fill_arc(dc, rect( XLeft, YLeft, Width, Height), + (dc->DcLevel.flPath & DCPATH_CLOCKWISE) ? -End : -Start, + (dc->DcLevel.flPath & DCPATH_CLOCKWISE) ? -Start : -End, + FillBrushObj, Chord); BRUSHOBJ_UnlockBrush(FillBrushObj); - return TRUE; + return ret; } +BOOL +FASTCALL +IntDrawEllipse( PDC dc, + INT XLeft, + INT YLeft, + INT Width, + INT Height, + PGDIBRUSHOBJ PenBrushObj) +{ + return (BOOL)app_draw_ellipse(dc, rect( XLeft, YLeft, Width, Height), PenBrushObj); +} + +BOOL +FASTCALL +IntFillEllipse( PDC dc, + INT XLeft, + INT YLeft, + INT Width, + INT Height) +{ + BOOL ret; + PDC_ATTR Dc_Attr; + PGDIBRUSHOBJ FillBrushObj; + + Dc_Attr = dc->pDc_Attr; + if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr; + + FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush); + if (NULL == FillBrushObj) + { + DPRINT1("FillEllipse Fail\n"); + SetLastWin32Error(ERROR_INTERNAL_ERROR); + return FALSE; + } + ret = (BOOL)app_fill_ellipse(dc, rect( XLeft, YLeft, Width, Height), FillBrushObj); + + BRUSHOBJ_UnlockBrush(FillBrushObj); + return ret; +} diff --git a/reactos/subsystems/win32/win32k/objects/fillshap.c b/reactos/subsystems/win32/win32k/objects/fillshap.c index 791df4fb25c..3de20205ffe 100644 --- a/reactos/subsystems/win32/win32k/objects/fillshap.c +++ b/reactos/subsystems/win32/win32k/objects/fillshap.c @@ -41,6 +41,12 @@ &RectBounds, \ ROP2_TO_MIX(Dc_Attr->jROP2)); +#define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0))) +#define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0))) + +BOOL FASTCALL IntFillEllipse( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height); +BOOL FASTCALL IntDrawEllipse( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, PGDIBRUSHOBJ PenBrushObj); + BOOL FASTCALL IntGdiPolygon(PDC dc, PPOINT UnsafePoints, @@ -133,9 +139,9 @@ IntGdiPolygon(PDC dc, ret = IntEngLineTo(&BitmapObj->SurfObj, dc->CombinedClip, &PenBrushInst.BrushObject, - UnsafePoints[Count-1].x, /* From */ + UnsafePoints[Count-1].x, /* From */ UnsafePoints[Count-1].y, - UnsafePoints[0].x, /* To */ + UnsafePoints[0].x, /* To */ UnsafePoints[0].y, &DestRect, ROP2_TO_MIX(Dc_Attr->jROP2)); /* MIX */ @@ -156,6 +162,7 @@ IntGdiPolyPolygon(DC *dc, { if (PATH_IsPathOpen(dc->DcLevel)) return PATH_PolyPolygon ( dc, Points, PolyCounts, Count); + while (--Count >=0) { if (!IntGdiPolygon ( dc, Points, *PolyCounts )) @@ -179,247 +186,124 @@ IntGdiPolyPolygon(DC *dc, * This function uses optimized Bresenham's ellipse algorithm. It draws * four lines of the ellipse in one pass. * - * Todo - * Make it look like a Windows ellipse. */ BOOL STDCALL NtGdiEllipse( HDC hDC, - int nLeftRect, - int nTopRect, - int nRightRect, - int nBottomRect) + int Left, + int Top, + int Right, + int Bottom) { - int ix, iy; - int A, B, C, D; - int da, db; - int NewA, NewB, NewC, NewD; - int nx, ny; - int CenterX, CenterY; - int RadiusX, RadiusY; - int Temp; - PGDIBRUSHOBJ FillBrush, PenBrush; - GDIBRUSHINST FillBrushInst, PenBrushInst; - BITMAPOBJ *BitmapObj; - RECTL RectBounds; PDC dc; PDC_ATTR Dc_Attr; - BOOL ret = TRUE, Cond1, Cond2; -/* top - ___________________ - +| | - | | - | | - left | | right - | | - | | - 0|___________________| - 0 bottom + - */ - /* - * Check the parameters. - */ - DPRINT("nLeftRect: %d, nTopRect: %d, nRightRect: %d, nBottomRect: %d\n",nLeftRect,nTopRect,nRightRect,nBottomRect); + RECTL RectBounds; + PGDIBRUSHOBJ PenBrushObj; + BOOL ret = TRUE; + LONG PenWidth, PenOrigWidth; + LONG RadiusX, RadiusY, CenterX, CenterY; - if ((nLeftRect == nRightRect) || (nTopRect == nBottomRect)) return TRUE; - - /* - * Get pointers to all necessary GDI objects. - */ + if ((Left == Right) || (Top == Bottom)) return TRUE; dc = DC_LockDc(hDC); if (dc == NULL) { - SetLastWin32Error(ERROR_INVALID_HANDLE); - return FALSE; + SetLastWin32Error(ERROR_INVALID_HANDLE); + return FALSE; } - if (dc->DC_Type == DC_TYPE_INFO) { - DC_UnlockDc(dc); - /* Yes, Windows really returns TRUE in this case */ - return TRUE; + DC_UnlockDc(dc); + /* Yes, Windows really returns TRUE in this case */ + return TRUE; } if (PATH_IsPathOpen(dc->DcLevel)) { - ret = PATH_Ellipse(dc, nLeftRect, nTopRect, nRightRect, nBottomRect); - DC_UnlockDc(dc); - return ret; + ret = PATH_Ellipse(dc, Left, Top, Right, Bottom); + DC_UnlockDc(dc); + return ret; } - if (nRightRect < nLeftRect) + if (Right < Left) { - INT tmp = nRightRect; nRightRect = nLeftRect; nLeftRect = tmp; + INT tmp = Right; Right = Left; Left = tmp; } - if (nBottomRect < nTopRect) + if (Bottom < Top) { - INT tmp = nBottomRect; nBottomRect = nTopRect; nTopRect = tmp; + INT tmp = Bottom; Bottom = Top; Top = tmp; } Dc_Attr = dc->pDc_Attr; if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr; - FillBrush = BRUSHOBJ_LockBrush(Dc_Attr->hbrush); - if (NULL == FillBrush) + PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen); + if (NULL == PenBrushObj) { + DPRINT1("Ellipse Fail 1\n"); DC_UnlockDc(dc); SetLastWin32Error(ERROR_INTERNAL_ERROR); return FALSE; } - PenBrush = PENOBJ_LockPen(Dc_Attr->hpen); - if (NULL == PenBrush) + PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x; + if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0; + + if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME) { - BRUSHOBJ_UnlockBrush(FillBrush); - DC_UnlockDc(dc); - SetLastWin32Error(ERROR_INTERNAL_ERROR); - return FALSE; + if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2; + if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2; + Left += PenWidth / 2; + Right -= (PenWidth - 1) / 2; + Top += PenWidth / 2; + Bottom -= (PenWidth - 1) / 2; } - BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap); - if (NULL == BitmapObj) - { - BRUSHOBJ_UnlockBrush(FillBrush); - PENOBJ_UnlockPen(PenBrush); - DC_UnlockDc(dc); - SetLastWin32Error(ERROR_INTERNAL_ERROR); - return FALSE; - } - - IntGdiInitBrushInstance(&FillBrushInst, FillBrush, dc->XlateBrush); - IntGdiInitBrushInstance(&PenBrushInst, PenBrush, dc->XlatePen); - - RectBounds.left = nLeftRect; - RectBounds.right = nRightRect; - RectBounds.top = nTopRect; - RectBounds.bottom = nBottomRect; + if (!PenWidth) PenWidth = 1; + PenBrushObj->ptPenWidth.x = PenWidth; + RectBounds.left = Left; + RectBounds.right = Right; + RectBounds.top = Top; + RectBounds.bottom = Bottom; + IntLPtoDP(dc, (LPPOINT)&RectBounds, 2); - DPRINT("1: Left: %d, Top: %d, Right: %d, Bottom: %d\n", - RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom); - + RectBounds.left += dc->ptlDCOrig.x; RectBounds.right += dc->ptlDCOrig.x; RectBounds.top += dc->ptlDCOrig.y; RectBounds.bottom += dc->ptlDCOrig.y; - DPRINT("2: Left: %d, Top: %d, Right: %d, Bottom: %d\n", + + // Setup for dynamic width and height. + RadiusX = max((RectBounds.right - RectBounds.left) / 2, 2); // Needs room + RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 2); + CenterX = (RectBounds.right + RectBounds.left) / 2; + CenterY = (RectBounds.bottom + RectBounds.top) / 2; + + DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n", RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom); - RadiusX = max((RectBounds.right - RectBounds.left) >> 1, 1); - RadiusY = max((RectBounds.bottom - RectBounds.top) >> 1, 1); - CenterX = RectBounds.left + RadiusX; - CenterY = RectBounds.top + RadiusY; - DPRINT("3: RadiusX: %d, RadiusY: %d, CenterX: %d, CenterY: %d\n", - RadiusX,RadiusY,CenterX,CenterY); + DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n", + CenterX - RadiusX, CenterY + RadiusY, RadiusX*2, RadiusY*2); - if (RadiusX > RadiusY) - { - nx = RadiusX; - ny = RadiusY; - } - else - { - nx = RadiusY; - ny = RadiusX; - } - da = -1; - db = 0xFFFF; - ix = 0; - iy = nx * 64; - NewA = 0; - NewB = (iy + 32) >> 6; - NewC = 0; - NewD = (NewB * ny) / nx; + ret = IntFillEllipse( dc, + CenterX - RadiusX, + CenterY - RadiusY, + RadiusX*2, // Width + RadiusY*2); // Height + if (ret) + ret = IntDrawEllipse( dc, + CenterX - RadiusX, + CenterY - RadiusY, + RadiusX*2, // Width + RadiusY*2, // Height + PenBrushObj); - do { - A = NewA; - B = NewB; - C = NewC; - D = NewD; - - ix += iy / nx; - iy -= ix / nx; - NewA = (ix + 32) >> 6; - NewB = (iy + 32) >> 6; - NewC = (NewA * ny) / nx; - NewD = (NewB * ny) / nx; - - if (RadiusX > RadiusY) - { - Temp = A; A = C; C = Temp; - Temp = B; B = D; D = Temp; - Cond1 = ((C != NewA) || (B != NewD)) && (NewC <= NewD); - Cond2 = ((D != NewB) || (A != NewC)) && (NewC <= B); - } - else - { - Cond1 = ((C != NewC) || (B != NewB)) && (NewA <= NewB); - Cond2 = ((D != NewD) || (A != NewA)) && (NewA <= B); - } - - /* - * Draw the lines going from inner to outer (+ mirrored). - */ - - if ((A > da) && (A < db)) - { - PUTLINE(CenterX - D, CenterY + A, CenterX + D, CenterY + A, FillBrushInst); - if (A) - { - PUTLINE(CenterX - D, CenterY - A, CenterX + D, CenterY - A, FillBrushInst); - } - da = A; - } - - /* - * Draw the lines going from outer to inner (+ mirrored). - */ - - if ((B < db) && (B > da)) - { - PUTLINE(CenterX - C, CenterY + B, CenterX + C, CenterY + B, FillBrushInst); - PUTLINE(CenterX - C, CenterY - B, CenterX + C, CenterY - B, FillBrushInst); - db = B; - } - - /* - * Draw the pixels on the margin. - */ - - if (Cond1) - { - PUTPIXEL(CenterX + C, CenterY + B, PenBrushInst); - if (C) - PUTPIXEL(CenterX - C, CenterY + B, PenBrushInst); - if (B) - { - PUTPIXEL(CenterX + C, CenterY - B, PenBrushInst); - if (C) - PUTPIXEL(CenterX - C, CenterY - B, PenBrushInst); - } - } - - if (Cond2) - { - PUTPIXEL(CenterX + D, CenterY + A, PenBrushInst); - if (D) - PUTPIXEL(CenterX - D, CenterY + A, PenBrushInst); - if (A) - { - PUTPIXEL(CenterX + D, CenterY - A, PenBrushInst); - if (D) - PUTPIXEL(CenterX - D, CenterY - A, PenBrushInst); - } - } - } while (B > A); - - BITMAPOBJ_UnlockBitmap(BitmapObj); - BRUSHOBJ_UnlockBrush(FillBrush); - PENOBJ_UnlockPen(PenBrush); + PenBrushObj->ptPenWidth.x = PenOrigWidth; + PENOBJ_UnlockPen(PenBrushObj); DC_UnlockDc(dc); - DPRINT("NtGdiEllipse exit \n"); + DPRINT("Ellipse Exit.\n"); return ret; }