gdi32: Use a better algorithm for CreateRoundRectRgn.
This commit is contained in:
parent
a86b765a50
commit
3e51dd7515
|
@ -1512,7 +1512,7 @@ static BOOL wide_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close
|
|||
|
||||
if (pdev->pen_join == PS_JOIN_ROUND || pdev->pen_endcap == PS_ENDCAP_ROUND)
|
||||
round_cap = CreateEllipticRgn( -(pdev->pen_width / 2), -(pdev->pen_width / 2),
|
||||
(pdev->pen_width + 1) / 2, (pdev->pen_width + 1) / 2 );
|
||||
(pdev->pen_width + 1) / 2 + 1, (pdev->pen_width + 1) / 2 + 1 );
|
||||
|
||||
if (close)
|
||||
wide_line_segments( pdev, num, pts, TRUE, 0, num, &pts[0], &pts[0], round_cap, total );
|
||||
|
@ -1538,7 +1538,7 @@ static BOOL dashed_wide_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOO
|
|||
|
||||
if (pdev->pen_join == PS_JOIN_ROUND || pdev->pen_endcap == PS_ENDCAP_ROUND)
|
||||
round_cap = CreateEllipticRgn( -(pdev->pen_width / 2), -(pdev->pen_width / 2),
|
||||
(pdev->pen_width + 1) / 2, (pdev->pen_width + 1) / 2 );
|
||||
(pdev->pen_width + 1) / 2 + 1, (pdev->pen_width + 1) / 2 + 1);
|
||||
|
||||
start = 0;
|
||||
cur_len = 0;
|
||||
|
|
|
@ -754,101 +754,80 @@ HRGN WINAPI CreateRoundRectRgn( INT left, INT top,
|
|||
{
|
||||
RGNOBJ * obj;
|
||||
HRGN hrgn = 0;
|
||||
int asq, bsq, d, xd, yd;
|
||||
RECT rect;
|
||||
int a, b, i, x, y, asq, bsq, dx, dy, err;
|
||||
RECT *rects;
|
||||
|
||||
/* Make the dimensions sensible */
|
||||
|
||||
if (left > right) { INT tmp = left; left = right; right = tmp; }
|
||||
if (top > bottom) { INT tmp = top; top = bottom; bottom = tmp; }
|
||||
/* the region is for the rectangle interior, but only at right and bottom for some reason */
|
||||
right--;
|
||||
bottom--;
|
||||
|
||||
ellipse_width = abs(ellipse_width);
|
||||
ellipse_height = abs(ellipse_height);
|
||||
|
||||
/* Check parameters */
|
||||
|
||||
if (ellipse_width > right-left) ellipse_width = right-left;
|
||||
if (ellipse_height > bottom-top) ellipse_height = bottom-top;
|
||||
ellipse_width = min( right - left, abs( ellipse_width ));
|
||||
ellipse_height = min( bottom - top, abs( ellipse_height ));
|
||||
|
||||
/* Check if we can do a normal rectangle instead */
|
||||
|
||||
if ((ellipse_width < 2) || (ellipse_height < 2))
|
||||
return CreateRectRgn( left, top, right, bottom );
|
||||
|
||||
/* Create region */
|
||||
|
||||
d = (ellipse_height < 128) ? ((3 * ellipse_height) >> 2) : 64;
|
||||
if (!(obj = HeapAlloc( GetProcessHeap(), 0, sizeof(*obj) ))) return 0;
|
||||
if (!init_region( &obj->rgn, d ))
|
||||
obj->rgn.size = ellipse_height;
|
||||
obj->rgn.numRects = ellipse_height;
|
||||
obj->rgn.extents.left = left;
|
||||
obj->rgn.extents.top = top;
|
||||
obj->rgn.extents.right = right;
|
||||
obj->rgn.extents.bottom = bottom;
|
||||
|
||||
obj->rgn.rects = rects = HeapAlloc( GetProcessHeap(), 0, obj->rgn.size * sizeof(RECT) );
|
||||
if (!rects) goto done;
|
||||
|
||||
/* based on an algorithm by Alois Zingl */
|
||||
|
||||
a = ellipse_width - 1;
|
||||
b = ellipse_height - 1;
|
||||
asq = 8 * a * a;
|
||||
bsq = 8 * b * b;
|
||||
dx = 4 * b * b * (1 - a);
|
||||
dy = 4 * a * a * (1 + (b % 2));
|
||||
err = dx + dy + a * a * (b % 2);
|
||||
|
||||
x = 0;
|
||||
y = ellipse_height / 2;
|
||||
|
||||
rects[y].left = left;
|
||||
rects[y].right = right;
|
||||
|
||||
while (x <= ellipse_width / 2)
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, obj );
|
||||
return 0;
|
||||
int e2 = 2 * err;
|
||||
if (e2 >= dx)
|
||||
{
|
||||
x++;
|
||||
err += dx += bsq;
|
||||
}
|
||||
if (e2 <= dy)
|
||||
{
|
||||
y++;
|
||||
err += dy += asq;
|
||||
rects[y].left = left + x;
|
||||
rects[y].right = right - x;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ellipse algorithm, based on an article by K. Porter */
|
||||
/* in DDJ Graphics Programming Column, 8/89 */
|
||||
|
||||
asq = ellipse_width * ellipse_width / 4; /* a^2 */
|
||||
bsq = ellipse_height * ellipse_height / 4; /* b^2 */
|
||||
d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
|
||||
xd = 0;
|
||||
yd = asq * ellipse_height; /* 2a^2b */
|
||||
|
||||
rect.left = left + ellipse_width / 2;
|
||||
rect.right = right - ellipse_width / 2;
|
||||
|
||||
/* Loop to draw first half of quadrant */
|
||||
|
||||
while (xd < yd)
|
||||
for (i = 0; i < ellipse_height / 2; i++)
|
||||
{
|
||||
if (d > 0) /* if nearest pixel is toward the center */
|
||||
{
|
||||
/* move toward center */
|
||||
rect.top = top++;
|
||||
rect.bottom = rect.top + 1;
|
||||
if (!REGION_UnionRectWithRegion( &rect, &obj->rgn )) goto done;
|
||||
rect.top = --bottom;
|
||||
rect.bottom = rect.top + 1;
|
||||
if (!REGION_UnionRectWithRegion( &rect, &obj->rgn )) goto done;
|
||||
yd -= 2*asq;
|
||||
d -= yd;
|
||||
}
|
||||
rect.left--; /* next horiz point */
|
||||
rect.right++;
|
||||
xd += 2*bsq;
|
||||
d += bsq + xd;
|
||||
rects[i].left = rects[b - i].left;
|
||||
rects[i].right = rects[b - i].right;
|
||||
rects[i].top = top + i;
|
||||
rects[i].bottom = rects[i].top + 1;
|
||||
}
|
||||
|
||||
/* Loop to draw second half of quadrant */
|
||||
|
||||
d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
|
||||
while (yd >= 0)
|
||||
rects[i - 1].bottom = bottom - ellipse_height + i; /* extend to bottom of rectangle */
|
||||
for (; i < ellipse_height; i++)
|
||||
{
|
||||
/* next vertical point */
|
||||
rect.top = top++;
|
||||
rect.bottom = rect.top + 1;
|
||||
if (!REGION_UnionRectWithRegion( &rect, &obj->rgn )) goto done;
|
||||
rect.top = --bottom;
|
||||
rect.bottom = rect.top + 1;
|
||||
if (!REGION_UnionRectWithRegion( &rect, &obj->rgn )) goto done;
|
||||
if (d < 0) /* if nearest pixel is outside ellipse */
|
||||
{
|
||||
rect.left--; /* move away from center */
|
||||
rect.right++;
|
||||
xd += 2*bsq;
|
||||
d += xd;
|
||||
}
|
||||
yd -= 2*asq;
|
||||
d += asq - yd;
|
||||
}
|
||||
|
||||
/* Add the inside rectangle */
|
||||
|
||||
if (top <= bottom)
|
||||
{
|
||||
rect.top = top;
|
||||
rect.bottom = bottom;
|
||||
if (!REGION_UnionRectWithRegion( &rect, &obj->rgn )) goto done;
|
||||
rects[i].top = bottom - ellipse_height + i;
|
||||
rects[i].bottom = rects[i].top + 1;
|
||||
}
|
||||
|
||||
hrgn = alloc_gdi_handle( &obj->header, OBJ_REGION, ®ion_funcs );
|
||||
|
|
Loading…
Reference in New Issue