From d170af286f2afe0b5b4752770117b99be61e882a Mon Sep 17 00:00:00 2001 From: James Tabor Date: Wed, 2 Jul 2008 07:47:23 +0000 Subject: [PATCH] Arc, RoundRect: - Converted over to use the new draw/fill square algorithm for draw arcs and draw/fill round rects. - Tested with (Area.exe) Yuan program. Getting better. svn path=/trunk/; revision=34248 --- reactos/subsystems/win32/win32k/objects/arc.c | 69 +- .../subsystems/win32/win32k/objects/drawing.c | 738 +++++++++++++----- .../win32/win32k/objects/fillshap.c | 308 ++------ 3 files changed, 636 insertions(+), 479 deletions(-) diff --git a/reactos/subsystems/win32/win32k/objects/arc.c b/reactos/subsystems/win32/win32k/objects/arc.c index 95f9a1f9e05..4aa462e3fee 100644 --- a/reactos/subsystems/win32/win32k/objects/arc.c +++ b/reactos/subsystems/win32/win32k/objects/arc.c @@ -26,6 +26,7 @@ #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0))) BOOL FASTCALL IntFillArc( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, double StartArc, double EndArc, ARCTYPE arctype); +BOOL FASTCALL IntDrawArc( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, double StartArc, double EndArc, ARCTYPE arctype, PGDIBRUSHOBJ PenBrushObj); static BOOL @@ -147,6 +148,16 @@ IntArc( DC *dc, arctype); } + ret = IntDrawArc( dc, + RectBounds.left, + RectBounds.top, + abs(RectBounds.right-RectBounds.left), // Width + abs(RectBounds.bottom-RectBounds.top), // Height + AngleStart, + AngleEnd, + arctype, + PenBrushObj); + BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap); if (NULL == BitmapObj) { @@ -161,63 +172,11 @@ IntArc( DC *dc, if (arctype == GdiTypePie) { PUTLINE(CenterX, CenterY, SfCx + CenterX, SfCy + CenterY, PenBrushInst); - } - { - double AngS = AngleStart, AngT = AngleEnd, - Factor = fabs(RadiusX) < 25 ? 1.0 : (25/fabs(RadiusX)); - int x,y, ox = 0, oy = 0; - BOOL Start = TRUE; - - if (dc->DcLevel.flPath & DCPATH_CLOCKWISE) - { - DPRINT1("Arc CW\n"); - for (; AngS < AngT; AngS += Factor) - { - x = (RadiusX * Rcos(AngS)); - y = (RadiusY * Rsin(AngS)); - - DPRINT("Arc CW -> %d, X: %d Y: %d\n",(INT)AngS,x,y); - if (Start) - { - PUTPIXEL(x + CenterX, y + CenterY, PenBrushInst); - ox = x; - oy = y; - Start = FALSE; - continue; - } - PUTLINE(ox + CenterX, oy + CenterY, x + CenterX, y + CenterY, PenBrushInst); - ox = x; - oy = y; - } - } - else - { - DPRINT1("Arc CCW\n"); - for (; AngT < AngS; AngS -= Factor) - { - x = (RadiusX * Rcos(AngS)); - y = (RadiusY * Rsin(AngS)); - - DPRINT("Arc CCW -> %d, X: %d Y: %d\n",(INT)AngS,x,y); - if (Start) - { - PUTPIXEL(x + CenterX, y + CenterY, PenBrushInst); - ox = x; - oy = y; - Start = FALSE; - continue; - } - PUTLINE(ox + CenterX, oy + CenterY, x + CenterX, y + CenterY, PenBrushInst); - ox = x; - oy = y; - } - } - } - if (arctype == GdiTypePie) PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, PenBrushInst); + } if (arctype == GdiTypeChord) - PUTLINE(EfCx + CenterX, EfCy + CenterY, SfCx + CenterX, SfCy + CenterY, PenBrushInst); - + PUTLINE(EfCx + CenterX, EfCy + CenterY, SfCx + CenterX, SfCy + CenterY, PenBrushInst); + PenBrushObj->ptPenWidth.x = PenOrigWidth; BITMAPOBJ_UnlockBitmap(BitmapObj); PENOBJ_UnlockPen(PenBrushObj); diff --git a/reactos/subsystems/win32/win32k/objects/drawing.c b/reactos/subsystems/win32/win32k/objects/drawing.c index 8390304d840..ba33e8850a9 100755 --- a/reactos/subsystems/win32/win32k/objects/drawing.c +++ b/reactos/subsystems/win32/win32k/objects/drawing.c @@ -63,6 +63,9 @@ typedef struct _Rect int width, height; /* width and height of rect */ } Rect, *PRect; +int FASTCALL IntFillRect(DC *dc, INT XLeft, INT YLeft, INT Width, INT Height, PGDIBRUSHOBJ BrushObj, BOOL Pen); +int FASTCALL app_fill_rect(DC *dc, Rect r, PGDIBRUSHOBJ BrushObj, BOOL Pen); + static POINT INTERNAL_CALL @@ -101,152 +104,8 @@ rect(int x, int y, int width, int height) * is no way for the program to know which portions of the * window are currently obscured. */ -static -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); - - 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->XlateBrush); - - 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; -} - -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; -} - +#define app_fill_rect( dc, r, BrushObj, Pen) \ + IntFillRect(dc, r.x, r.y, r.width, r.height, BrushObj, Pen) /* * Drawing an ellipse with a certain line thickness. @@ -306,7 +165,7 @@ app_draw_ellipse(DC *g, Rect r, PGDIBRUSHOBJ BrushObj) // START_DEBUG(); if ((r.width <= 2) || (r.height <= 2)) - return app_fill_rect_pen(g, r, BrushObj); + return app_fill_rect(g, r, BrushObj, TRUE); r1.x = r.x + a; r1.y = r.y; @@ -405,8 +264,8 @@ app_draw_ellipse(DC *g, Rect r, PGDIBRUSHOBJ BrushObj) 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); + result &= app_fill_rect(g, r1, BrushObj, TRUE); + result &= app_fill_rect(g, r2, BrushObj, TRUE); prevx = r1.x; prevy = r1.y; @@ -414,14 +273,14 @@ app_draw_ellipse(DC *g, Rect r, PGDIBRUSHOBJ BrushObj) 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); + result &= app_fill_rect(g, rect(r1.x,r1.y, + W,1), BrushObj, TRUE); + result &= app_fill_rect(g, rect( + r1.x+r1.width-W,r1.y,W,1), BrushObj, TRUE); + result &= app_fill_rect(g, rect(r2.x, + r2.y,W,1), BrushObj, TRUE); + result &= app_fill_rect(g, rect( + r2.x+r2.width-W,r2.y,W,1), BrushObj, TRUE); prevx = r1.x; prevy = r1.y; @@ -450,14 +309,14 @@ app_draw_ellipse(DC *g, Rect r, PGDIBRUSHOBJ BrushObj) W = w; if (W+W >= r.width) { - result &= app_fill_rect_pen(g, rect(r.x, r1.y, - r.width, r1.height), BrushObj); + result &= app_fill_rect(g, rect(r.x, r1.y, + r.width, r1.height), BrushObj, TRUE); 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); + result &= app_fill_rect(g, rect(r.x, r1.y, W, r1.height), BrushObj, TRUE); + result &= app_fill_rect(g, rect(r.x+r.width-W, r1.y, + W, r1.height), BrushObj, TRUE); } return result; } @@ -505,7 +364,8 @@ app_fill_arc_rect(DC *g, POINT p2, // End int start_angle, int end_angle, - PGDIBRUSHOBJ BrushObj) + PGDIBRUSHOBJ BrushObj, + BOOL Pen) { int x1, x2; int start_above, end_above; @@ -580,36 +440,36 @@ app_fill_arc_rect(DC *g, { /* fill outsides of wedge */ if (! app_fill_rect(g, rect(r.x, r.y, - x1-r.x, r.height), BrushObj)) + x1-r.x, r.height), BrushObj, Pen)) return 0; return app_fill_rect(g, rect(x2, r.y, - r.x+r.width-x2, r.height), BrushObj); + r.x+r.width-x2, r.height), BrushObj, Pen); } else { /* fill inside of wedge */ r.width = x1-x2; r.x = x2; - return app_fill_rect(g, r, BrushObj); + return app_fill_rect(g, r, BrushObj, Pen); } } else if (start_above) { /* fill to the left of the start_line */ r.width = x1-r.x; - return app_fill_rect(g, r, BrushObj); + return app_fill_rect(g, r, BrushObj, Pen); } else if (end_above) { /* fill right of end_line */ r.width = r.x+r.width-x2; r.x = x2; - return app_fill_rect(g, r, BrushObj); + return app_fill_rect(g, r, BrushObj, Pen); } else { if (start_angle > end_angle) - return app_fill_rect(g,r, BrushObj); + return app_fill_rect(g,r, BrushObj, Pen); else return 1; } @@ -675,7 +535,7 @@ app_fill_arc_rect(DC *g, if (start_above && end_above) { if (start_angle > end_angle) - return app_fill_rect(g,r, BrushObj); + return app_fill_rect(g,r, BrushObj, Pen); else return 1; } @@ -683,14 +543,14 @@ app_fill_arc_rect(DC *g, { /* fill to the left of end_line */ r.width = x2-r.x; - return app_fill_rect(g,r, BrushObj); + return app_fill_rect(g,r, BrushObj, Pen); } else if (end_above) { /* fill right of start_line */ r.width = r.x+r.width-x1; r.x = x1; - return app_fill_rect(g,r, BrushObj); + return app_fill_rect(g,r, BrushObj, Pen); } else { @@ -698,17 +558,17 @@ app_fill_arc_rect(DC *g, { /* fill outsides of wedge */ if (! app_fill_rect(g, rect(r.x, r.y, - x2-r.x, r.height), BrushObj)) + x2-r.x, r.height), BrushObj, Pen)) return 0; return app_fill_rect(g, rect(x1, r.y, - r.x+r.width-x1, r.height), BrushObj); + r.x+r.width-x1, r.height), BrushObj, Pen); } else { /* fill inside of wedge */ r.width = x2-x1; r.x = x1; - return app_fill_rect(g, r, BrushObj); + return app_fill_rect(g, r, BrushObj, Pen); } } } @@ -767,7 +627,7 @@ app_fill_ellipse(DC *g, Rect r, PGDIBRUSHOBJ BrushObj) // START_DEBUG(); if ((r.width <= 2) || (r.height <= 2)) - return app_fill_rect(g, r, BrushObj); + return app_fill_rect(g, r, BrushObj, FALSE); r1.x = r.x + a; r1.y = r.y; @@ -813,8 +673,8 @@ app_fill_ellipse(DC *g, Rect r, PGDIBRUSHOBJ BrushObj) if (r1.y+r1.height < r2.y) { /* distinct rectangles */ - result &= app_fill_rect(g, r1, BrushObj); - result &= app_fill_rect(g, r2, BrushObj); + result &= app_fill_rect(g, r1, BrushObj, FALSE); + result &= app_fill_rect(g, r2, BrushObj, FALSE); } /* move down */ @@ -839,7 +699,7 @@ app_fill_ellipse(DC *g, Rect r, PGDIBRUSHOBJ BrushObj) r1.x = r.x; r1.width = r.width; r1.height = r2.y+r2.height-r1.y; - result &= app_fill_rect(g, r1, BrushObj); + result &= app_fill_rect(g, r1, BrushObj, FALSE); } else if (x <= a) { /* crossover, draw final line */ @@ -847,7 +707,7 @@ app_fill_ellipse(DC *g, Rect r, PGDIBRUSHOBJ BrushObj) r1.width = r.width; r1.height = r1.y+r1.height-r2.y; r1.y = r2.y; - result &= app_fill_rect(g, r1, BrushObj); + result &= app_fill_rect(g, r1, BrushObj, FALSE); } return result; } @@ -1014,10 +874,10 @@ app_fill_arc(DC *g, Rect r, int start_angle, int end_angle, PGDIBRUSHOBJ BrushOb /* distinct rectangles */ result &= app_fill_arc_rect(g, r1, p0, p1, p2, - start_angle, end_angle, BrushObj); + start_angle, end_angle, BrushObj, FALSE); result &= app_fill_arc_rect(g, r2, p0, p1, p2, - start_angle, end_angle, BrushObj); + start_angle, end_angle, BrushObj, FALSE); } /* move down */ @@ -1039,7 +899,7 @@ app_fill_arc(DC *g, Rect r, int start_angle, int end_angle, PGDIBRUSHOBJ BrushOb while (r1.height > 0) { result &= app_fill_arc_rect(g, rect(r1.x, r1.y, r1.width, 1), - p0, p1, p2, start_angle, end_angle, BrushObj); + p0, p1, p2, start_angle, end_angle, BrushObj, FALSE); r1.y += 1; r1.height -= 1; } @@ -1053,7 +913,7 @@ app_fill_arc(DC *g, Rect r, int start_angle, int end_angle, PGDIBRUSHOBJ BrushOb while (r1.height > 0) { result &= app_fill_arc_rect(g, rect(r1.x, r1.y, r1.width, 1), - p0, p1, p2, start_angle, end_angle, BrushObj); + p0, p1, p2, start_angle, end_angle, BrushObj, FALSE); r1.y += 1; r1.height -= 1; } @@ -1061,8 +921,345 @@ app_fill_arc(DC *g, Rect r, int start_angle, int end_angle, PGDIBRUSHOBJ BrushOb return result; } +int app_draw_arc(DC *g, Rect r, int start_angle, int end_angle, PGDIBRUSHOBJ PenBrushObj, BOOL Chord) +{ + /* 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 = PenBrushObj->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; + + /* arc rectangle calculations */ + int movedown, moveout; + int innerX = 0, prevx, prevy, W; + Rect r1, r2; + int result = 1; + + /* line descriptions */ + POINT p0, p1, p2; + +// START_DEBUG(); + + /* if angles differ by 360 degrees or more, close the shape */ + if ((start_angle + 360 <= end_angle) || + (start_angle - 360 >= end_angle)) + { + return app_draw_ellipse(g, r, PenBrushObj); + } + + /* make start_angle >= 0 and <= 360 */ + while (start_angle < 0) + start_angle += 360; + start_angle %= 360; + + /* make end_angle >= 0 and <= 360 */ + while (end_angle < 0) + end_angle += 360; + end_angle %= 360; + + /* draw nothing if the angles are equal */ + if (start_angle == end_angle) + return 1; + + /* find arc wedge line end points */ + p1 = app_boundary_point(r, start_angle); + p2 = app_boundary_point(r, end_angle); + if (Chord) + 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); + + /* determine ellipse rectangles */ + 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_arc_rect(g, r1, + p0, p1, p2, + start_angle, end_angle, PenBrushObj, TRUE); + result &= app_fill_arc_rect(g, r2, + p0, p1, p2, + start_angle, end_angle, PenBrushObj, TRUE); + + prevx = r1.x; + prevy = r1.y; + } + else if (r1.y+r1.height < r2.y) + { + /* draw distinct rectangles */ + result &= app_fill_arc_rect(g, rect( + r1.x,r1.y,W,1), + p0, p1, p2, + start_angle, end_angle, PenBrushObj, TRUE); + result &= app_fill_arc_rect(g, rect( + r1.x+r1.width-W,r1.y,W,1), + p0, p1, p2, + start_angle, end_angle, PenBrushObj, TRUE); + result &= app_fill_arc_rect(g, rect( + r2.x,r2.y,W,1), + p0, p1, p2, + start_angle, end_angle, PenBrushObj, TRUE); + result &= app_fill_arc_rect(g, rect( + r2.x+r2.width-W,r2.y,W,1), + p0, p1, p2, + start_angle, end_angle, PenBrushObj, TRUE); + + 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 lines */ + 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) { + while (r1.height > 0) { + result &= app_fill_arc_rect(g, rect(r.x, + r1.y, r.width, 1), p0, p1, p2, + start_angle, end_angle, PenBrushObj, TRUE); + r1.y += 1; + r1.height -= 1; + } + return result; + } + + while (r1.height > 0) { + result &= app_fill_arc_rect(g, rect(r.x, r1.y, + W, 1), p0, p1, p2, + start_angle, end_angle, PenBrushObj, TRUE); + result &= app_fill_arc_rect(g, rect(r.x+r.width-W, + r1.y, W, 1), p0, p1, p2, + start_angle, end_angle, PenBrushObj, TRUE); + r1.y += 1; + r1.height -= 1; + } + } + + return result; +} + /* ReactOS Interface *********************************************************/ +int +FASTCALL +IntFillRect( DC *dc, + INT XLeft, + INT YLeft, + INT Width, + INT Height, + PGDIBRUSHOBJ BrushObj, + BOOL Pen) +{ + 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 (Width < 0) + { + XLeft += Width; + Width = 0 - Width; + } + if (Height < 0) + { + YLeft += Height; + Height = 0 - Height; + } + + DestRect.left = XLeft; + DestRect.right = XLeft + Width; + + DestRect.top = YLeft; + DestRect.bottom = YLeft + Height; + + BrushOrigin.x = BrushObj->ptOrigin.x; + BrushOrigin.y = BrushObj->ptOrigin.y; + + if (Dc_Attr->jROP2 == R2_XORPEN) + ROP = PATINVERT; + else + ROP = PATCOPY; + + if (Pen) + IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlatePen); + else + IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlateBrush); + + 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; +} + BOOL FASTCALL IntFillArc( PDC dc, @@ -1100,6 +1297,28 @@ IntFillArc( PDC dc, return ret; } +BOOL +FASTCALL +IntDrawArc( PDC dc, + INT XLeft, + INT YLeft, + INT Width, + INT Height, + double StartArc, + double EndArc, + ARCTYPE arctype, + PGDIBRUSHOBJ PenBrushObj) +{ + int Start = ceill(StartArc); + int End = ceill(EndArc); + BOOL Chord = (arctype == GdiTypeChord); + // Sort out alignment here. + return app_draw_arc(dc, rect( XLeft, YLeft, Width, Height), + (dc->DcLevel.flPath & DCPATH_CLOCKWISE) ? -End : -Start, + (dc->DcLevel.flPath & DCPATH_CLOCKWISE) ? -Start : -End, + PenBrushObj, Chord); +} + BOOL FASTCALL IntDrawEllipse( PDC dc, @@ -1139,3 +1358,154 @@ IntFillEllipse( PDC dc, BRUSHOBJ_UnlockBrush(FillBrushObj); return ret; } + +BOOL +FASTCALL +IntFillRoundRect( PDC dc, + INT Left, + INT Top, + INT Right, + INT Bottom, + INT Wellipse, + INT Hellipse) +{ + PDC_ATTR Dc_Attr; + PGDIBRUSHOBJ FillBrushObj; + Rect r; + int rx, ry; /* radius in x and y directions */ + + 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; + } + // x y Width Height + r = rect( Left, Top, abs(Right-Left), abs(Bottom-Top)); + rx = Wellipse/2; + ry = Hellipse/2; + + if (Wellipse > r.width) + { + if (Hellipse > r.height) // > W > H + ret = app_fill_ellipse(dc, r, FillBrushObj); + else // > W < H + { + + app_fill_arc(dc, rect( r.x, r.y, r.width - 1, Hellipse), + 0, 180, FillBrushObj,FALSE); + app_fill_arc(dc, rect(r.x, Bottom - Hellipse - 1, r.width - 1, Hellipse), + 180, 360, FillBrushObj, FALSE); + } + } + else if(Hellipse > r.height) // < W > H + { + app_fill_arc(dc, rect(r.x, r.y, Wellipse, r.height - 1), + 90, 270, FillBrushObj, FALSE); + app_fill_arc(dc, rect(Right - Wellipse - 1, r.y, Wellipse, r.height - 1), + 270, 90, FillBrushObj,FALSE); + } + else // < W < H + { + app_fill_arc(dc, rect(r.x, r.y, Wellipse, Hellipse), + 90, 180, FillBrushObj, FALSE); + + app_fill_arc(dc, rect(r.x, Bottom - Hellipse - 1, Wellipse, Hellipse), + 180, 270, FillBrushObj, FALSE); + + app_fill_arc(dc, rect(Right - Wellipse - 1, Bottom - Hellipse - 1, Wellipse, Hellipse), + 270, 360, FillBrushObj,FALSE); + + app_fill_arc(dc, rect(Right - Wellipse - 1, r.y, Wellipse, Hellipse ), + 0, 90, FillBrushObj,FALSE); + } + if (Wellipse < r.width) + { + app_fill_rect(dc, rect(r.x+rx, r.y, r.width-rx-rx, ry+1), FillBrushObj, FALSE); + app_fill_rect(dc, rect(r.x+rx, r.y+r.height-ry+1, r.width-rx-rx, ry-1), FillBrushObj, FALSE); + } + if (Hellipse < r.height) + { + app_fill_rect(dc, rect(r.x, r.y+ry+1, r.width, r.height-ry-ry), FillBrushObj, FALSE); + } + + BRUSHOBJ_UnlockBrush(FillBrushObj); + return TRUE; +} + + +BOOL +FASTCALL +IntDrawRoundRect( PDC dc, + INT Left, + INT Top, + INT Right, + INT Bottom, + INT Wellipse, + INT Hellipse, + PGDIBRUSHOBJ PenBrushObj) +{ + Rect r; + int rx, ry; /* radius in x and y directions */ + int w = PenBrushObj->ptPenWidth.x; + + r = rect( Left, Top, abs(Right-Left), abs(Bottom-Top)); + rx = Wellipse/2; + ry = Hellipse/2; + + if (Wellipse > r.width) + { + if (Hellipse > r.height) // > W > H + app_draw_ellipse(dc, r, PenBrushObj); + else // > W < H + { + + app_draw_arc(dc, rect( r.x, r.y, r.width - 1, Hellipse - 1), + 0, 180, PenBrushObj, FALSE); + app_draw_arc(dc, rect(r.x, Bottom - Hellipse, r.width - 1, Hellipse - 1), + 180, 360, PenBrushObj, FALSE); + } + } + else if(Hellipse > r.height) // < W > H + { + app_draw_arc(dc, rect(r.x, r.y, Wellipse - 1, r.height - 1), + 90, 270, PenBrushObj, FALSE); + app_draw_arc(dc, rect(Right - Wellipse, r.y, Wellipse - 1, r.height - 1), + 270, 90, PenBrushObj, FALSE); + } + else // < W < H + { + app_draw_arc(dc, rect(r.x, r.y, Wellipse-1, Hellipse - 1), + 90, 180, PenBrushObj, FALSE); + + app_draw_arc(dc, rect(r.x, Bottom - Hellipse, Wellipse - 1, Hellipse - 1), + 180, 270, PenBrushObj, FALSE); + + app_draw_arc(dc, rect(Right - Wellipse, Bottom - Hellipse, Wellipse - 1, Hellipse - 1), + 270, 360, PenBrushObj, FALSE); + + app_draw_arc(dc, rect(Right - Wellipse, r.y, Wellipse - 1, Hellipse - 1 ), + 0, 90, PenBrushObj, FALSE); + } + if ( Hellipse < r.height) + { + app_fill_rect(dc, rect(r.x, r.y+ry+1, w, r.height-ry-ry), PenBrushObj, TRUE); + + + app_fill_rect(dc, rect(r.x+r.width-w, r.y+ry+1, w, r.height-ry-ry), + PenBrushObj, TRUE); + } + if ( Wellipse < r.width) + { + app_fill_rect(dc, rect(r.x+rx, r.y+r.height-w, r.width-rx-rx, w), + PenBrushObj, TRUE); + + app_fill_rect(dc, rect(r.x+rx, r.y, r.width-rx-rx, w), PenBrushObj, TRUE); + } + return TRUE; +} + diff --git a/reactos/subsystems/win32/win32k/objects/fillshap.c b/reactos/subsystems/win32/win32k/objects/fillshap.c index 3de20205ffe..9785e6f46a5 100644 --- a/reactos/subsystems/win32/win32k/objects/fillshap.c +++ b/reactos/subsystems/win32/win32k/objects/fillshap.c @@ -46,6 +46,8 @@ 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 IntFillRoundRect( PDC dc, INT Left, INT Top, INT Right, INT Bottom, INT Wellipse, INT Hellipse); +BOOL FASTCALL IntDrawRoundRect( PDC dc, INT Left, INT Top, INT Right, INT Bottom, INT Wellipse, INT Hellipse, PGDIBRUSHOBJ PenBrushObj); BOOL FASTCALL IntGdiPolygon(PDC dc, @@ -550,7 +552,7 @@ IntRectangle(PDC dc, DestRect.left = LeftRect; DestRect.right = RightRect; - DestRect.top = TopRect; + DestRect.top = TopRect; DestRect.bottom = BottomRect; FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush); @@ -669,271 +671,97 @@ BOOL FASTCALL IntRoundRect( PDC dc, - int left, - int top, - int right, - int bottom, + int Left, + int Top, + int Right, + int Bottom, int xCurveDiameter, int yCurveDiameter) { PDC_ATTR Dc_Attr; - BITMAPOBJ *BitmapObj; - PGDIBRUSHOBJ PenBrushObj, FillBrushObj; - GDIBRUSHINST FillBrushInst, PenBrushInst; - RECTL RectBounds; - int potential_steps; - int i, col, row, width, height, x1, x1start, x2, x2start, y1, y2; - int xradius, yradius; - //float aspect_square; - long a_square, b_square, - two_a_square, two_b_square, - four_a_square, four_b_square, - d, dinc, ddec; - BOOL first, - ret = TRUE; // default to success + PGDIBRUSHOBJ PenBrushObj; + RECTL RectBounds; + LONG PenWidth, PenOrigWidth; + BOOL ret = TRUE; // default to success ASSERT ( dc ); // caller's responsibility to set this up if ( PATH_IsPathOpen(dc->DcLevel) ) - return PATH_RoundRect ( dc, left, top, right, bottom, + return PATH_RoundRect ( dc, Left, Top, Right, Bottom, xCurveDiameter, yCurveDiameter ); + + if ((Left == Right) || (Top == Bottom)) return TRUE; + + xCurveDiameter = max(abs( xCurveDiameter ), 1); + yCurveDiameter = max(abs( yCurveDiameter ), 1); + + if (Right < Left) + { + INT tmp = Right; Right = Left; Left = tmp; + } + if (Bottom < Top) + { + INT tmp = Bottom; Bottom = Top; Top = tmp; + } + Dc_Attr = dc->pDc_Attr; if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr; - xradius = xCurveDiameter >> 1; - yradius = yCurveDiameter >> 1; - - left += dc->ptlDCOrig.x; - right += dc->ptlDCOrig.x; - top += dc->ptlDCOrig.y; - bottom += dc->ptlDCOrig.y; - - RectBounds.left = left; - RectBounds.right = right; - RectBounds.top = top; - RectBounds.bottom = bottom; - - BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap); - if (!BitmapObj) + PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen); + if (!PenBrushObj) { /* Nothing to do, as we don't have a bitmap */ SetLastWin32Error(ERROR_INTERNAL_ERROR); return FALSE; } - FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush); - if (FillBrushObj) + PenOrigWidth = PenWidth = PenBrushObj->ptPenWidth.x; + if (PenBrushObj->ulPenStyle == PS_NULL) PenWidth = 0; + + if (PenBrushObj->ulPenStyle == PS_INSIDEFRAME) { - if (FillBrushObj->flAttrs & GDIBRUSH_IS_NULL) - { - /* make null brush check simpler... */ - BRUSHOBJ_UnlockBrush(FillBrushObj); - FillBrushObj = NULL; - } - else - { - IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush); - } + 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; } - PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen); - if (PenBrushObj) - { - if (PenBrushObj->flAttrs & GDIBRUSH_IS_NULL) - { - /* make null pen check simpler... */ - PENOBJ_UnlockPen(PenBrushObj); - PenBrushObj = NULL; - } - else - { - IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen); - } - } + if (!PenWidth) PenWidth = 1; + PenBrushObj->ptPenWidth.x = PenWidth; - right--; - bottom--; + RectBounds.left = Left; + RectBounds.top = Top; + RectBounds.right = Right; + RectBounds.bottom = Bottom; - width = right - left; - height = bottom - top; + IntLPtoDP(dc, (LPPOINT)&RectBounds, 2); - if ( (xradius<<1) > width ) - xradius = width >> 1; - if ( (yradius<<1) > height ) - yradius = height >> 1; + RectBounds.left += dc->ptlDCOrig.x; + RectBounds.top += dc->ptlDCOrig.y; + RectBounds.right += dc->ptlDCOrig.x; + RectBounds.bottom += dc->ptlDCOrig.y; - b_square = yradius * yradius; - a_square = xradius * xradius; - row = yradius; - col = 0; - two_a_square = a_square << 1; - four_a_square = a_square << 2; - four_b_square = b_square << 2; - two_b_square = b_square << 1; - d = two_a_square * ((row - 1) * (row)) - + a_square - + two_b_square * (1 - a_square); - - x1 = left+xradius; - x2 = right-xradius; - y1 = top; - y2 = bottom; - - x1start = x1; - x2start = x2; - - dinc = two_b_square*3; /* two_b_square * (3 + (col << 1)); */ - ddec = four_a_square * row; - - first = TRUE; - for ( ;; ) - { - if ( d >= 0 ) - { - if ( FillBrushObj ) - PUTLINE ( x1, y1, x2, y1, FillBrushInst ); - if ( first ) - { - if ( PenBrushObj ) - { - if ( x1start > x1 ) - { - PUTLINE ( x1, y1, x1start, y1, PenBrushInst ); - PUTLINE ( x2start+1, y2, x2+1, y2, PenBrushInst ); - } - else - { - PUTPIXEL ( x1, y1, PenBrushInst ); - PUTPIXEL ( x2, y2, PenBrushInst ); - } - } - first = FALSE; - } - else - { - if ( FillBrushObj ) - PUTLINE ( x1, y2, x2, y2, FillBrushInst ); - if ( PenBrushObj ) - { - if ( x1start >= x1 ) - { - PUTLINE ( x1, y1, x1start+1, y1, PenBrushInst ); - PUTLINE ( x2start, y2, x2+1, y2, PenBrushInst ); - } - else - { - PUTPIXEL ( x1, y1, PenBrushInst ); - PUTPIXEL ( x2, y2, PenBrushInst ); - } - } - } - if ( PenBrushObj ) - { - if ( x1start > x1 ) - { - PUTLINE ( x1, y2, x1start+1, y2, PenBrushInst ); - PUTLINE ( x2start, y1, x2+1, y1, PenBrushInst ); - } - else - { - PUTPIXEL ( x1, y2, PenBrushInst ); - PUTPIXEL ( x2, y1, PenBrushInst ); - } - } - x1start = x1-1; - x2start = x2+1; - row--, y1++, y2--, ddec -= four_a_square; - d -= ddec; - } - - potential_steps = ( a_square * row ) / b_square - col + 1; - while ( d < 0 && potential_steps-- ) - { - d += dinc; /* two_b_square * (3 + (col << 1)); */ - col++, x1--, x2++, dinc += four_b_square; - } - - if ( a_square * row <= b_square * col ) - break; - }; - - d = two_b_square * (col + 1) * col - + two_a_square * (row * (row - 2) + 1) - + (1 - two_a_square) * b_square; - dinc = ddec; /* four_b_square * col; */ - ddec = two_a_square * ((row << 1) - 3); - - while ( row ) - { - if ( FillBrushObj ) - { - PUTLINE ( x1, y1, x2, y1, FillBrushInst ); - PUTLINE ( x1, y2, x2, y2, FillBrushInst ); - } - if ( PenBrushObj ) - { - PUTPIXEL ( x2, y1, PenBrushInst ); - PUTPIXEL ( x1, y2, PenBrushInst ); - PUTPIXEL ( x2, y2, PenBrushInst ); - PUTPIXEL ( x1, y1, PenBrushInst ); - } - - if ( d <= 0 ) - { - col++, x1--, x2++, dinc += four_b_square; - d += dinc; //four_b_square * col; - } - - row--, y1++, y2--, ddec -= four_a_square; - d -= ddec; //two_a_square * ((row << 1) - 3); - } - - if ( FillBrushObj ) - { - PUTLINE ( left, y1, right, y1, FillBrushInst ); - PUTLINE ( left, y2, right, y2, FillBrushInst ); - } - if ( PenBrushObj ) - { - if ( x1 > (left+1) ) - { - PUTLINE ( left, y1, x1, y1, PenBrushInst ); - PUTLINE ( x2+1, y1, right, y1, PenBrushInst ); - PUTLINE ( left+1, y2, x1, y2, PenBrushInst ); - PUTLINE ( x2+1, y2, right+1, y2, PenBrushInst ); - } - else - { - PUTPIXEL ( left, y1, PenBrushInst ); - PUTPIXEL ( right, y2, PenBrushInst ); - } - } - - x1 = left+xradius; - x2 = right-xradius; - y1 = top+yradius; - y2 = bottom-yradius; - - if ( FillBrushObj ) - { - for ( i = y1+1; i < y2; i++ ) - PUTLINE ( left, i, right, i, FillBrushInst ); - } - - if ( PenBrushObj ) - { - PUTLINE ( x1, top, x2, top, PenBrushInst ); - PUTLINE ( right, y1, right, y2, PenBrushInst ); - PUTLINE ( x2, bottom, x1, bottom, PenBrushInst ); - PUTLINE ( left, y2, left, y1, PenBrushInst ); - } - - BITMAPOBJ_UnlockBitmap(BitmapObj); - if (PenBrushObj != NULL) - PENOBJ_UnlockPen(PenBrushObj); - if (FillBrushObj != NULL) - BRUSHOBJ_UnlockBrush(FillBrushObj); + ret = IntFillRoundRect( dc, + RectBounds.left, + RectBounds.top, + RectBounds.right, + RectBounds.bottom, + xCurveDiameter, + yCurveDiameter); + if (ret) + ret = IntDrawRoundRect( dc, + RectBounds.left, + RectBounds.top, + RectBounds.right, + RectBounds.bottom, + xCurveDiameter, + yCurveDiameter, + PenBrushObj); + PenBrushObj->ptPenWidth.x = PenOrigWidth; + PENOBJ_UnlockPen(PenBrushObj); return ret; }