-- v3: win32u: Forward to Rectangle() if the ellipse width or height is zero.
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/win32u/dibdrv/graphics.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index cc62d6a681b..56c6ebc44f8 100644 --- a/dlls/win32u/dibdrv/graphics.c +++ b/dlls/win32u/dibdrv/graphics.c @@ -1531,16 +1531,16 @@ BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, { dibdrv_physdev *pdev = get_dibdrv_pdev( dev ); DC *dc = get_physdev_dc( dev ); - RECT rect; + RECT rect, arc_rect; POINT start, end, rect_center, *points, *top_points; int count, max_points; BOOL ret = TRUE; HRGN outline = 0, interior = 0;
- SetRect( &rect, 0, 0, ellipse_width, ellipse_height ); + SetRect( &arc_rect, 0, 0, ellipse_width, ellipse_height ); /* We are drawing four arcs, but the number of points we will actually use * is exactly as many as in one ellipse arc. */ - max_points = get_arc_max_points( dc, &rect ); + max_points = get_arc_max_points( dc, &arc_rect ); points = malloc( max_points * sizeof(*points) ); top_points = malloc( max_points * sizeof(*points) ); if (!points || !top_points) @@ -1556,27 +1556,30 @@ BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, return FALSE; }
- SetRect( &rect, left, top, left + ellipse_width, top + ellipse_height ); + SetRect( &rect, left, top, right, bottom ); + order_rect( &rect ); + + SetRect( &arc_rect, rect.left, rect.top, rect.left + ellipse_width, rect.top + ellipse_height ); /* Points are relative to the arc center. * We just need to specify any point on the vector. */ start.x = -1; start.y = 0; end.x = 0; end.y = -1; - count = get_arc_points( dc, AD_CLOCKWISE, &rect, start, end, top_points ); + count = get_arc_points( dc, AD_CLOCKWISE, &arc_rect, start, end, top_points );
- SetRect( &rect, right - ellipse_width, top, right, top + ellipse_height ); + SetRect( &arc_rect, rect.right - ellipse_width, rect.top, rect.right, rect.top + ellipse_height ); start.x = 0; start.y = -1; end.x = 1; end.y = 0; - count += get_arc_points( dc, AD_CLOCKWISE, &rect, start, end, top_points + count ); + count += get_arc_points( dc, AD_CLOCKWISE, &arc_rect, start, end, top_points + count );
if (count * 2 > max_points) ERR( "point count %u * 2 exceeds max points %u\n", count, max_points );
- rect_center.x = (left + right) / 2; - rect_center.y = (top + bottom) / 2; + rect_center.x = (rect.left + rect.right) / 2; + rect_center.y = (rect.top + rect.bottom) / 2; lp_to_dp( dc, &rect_center, 1 );
if (dc->attr->arc_direction == AD_CLOCKWISE)
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/win32u/dibdrv/graphics.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index 56c6ebc44f8..17751e44644 100644 --- a/dlls/win32u/dibdrv/graphics.c +++ b/dlls/win32u/dibdrv/graphics.c @@ -316,6 +316,12 @@ static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, POINT start, P
count = generate_ellipse_top_half( dc, width, height, points );
+ /* The ellipse is always generated counterclockwise from the origin. + * This means our points will essentially be backwards if the world + * transform includes a flip. Swap the arc direction to correct for this. */ + if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < dc->xformWorld2Vport.eM12 * dc->xformWorld2Vport.eM21) + arc_dir = (arc_dir == AD_CLOCKWISE ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE); + /* Transform the start and end, but do not translate them, so that they * remain relative to the ellipse center. */ lp_to_dp_no_translate( dc, &start );
From: Elizabeth Figura zfigura@codeweavers.com
This unnecessarily loses precision, and if the point is very close to the origin (as for the internal arcs generated by RoundRect(), but also for those specified manually) this may generate an incorrect arc.
This addresses the last artifacts from bug 35331. --- dlls/win32u/dibdrv/graphics.c | 41 +++++++++++++++-------------------- 1 file changed, 17 insertions(+), 24 deletions(-)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index 17751e44644..44d73dc7515 100644 --- a/dlls/win32u/dibdrv/graphics.c +++ b/dlls/win32u/dibdrv/graphics.c @@ -267,7 +267,7 @@ static unsigned int generate_ellipse_top_half( const DC *dc, double width, doubl return pos; }
-static int find_intersection( const POINT *points, int x, int y, int count ) +static int find_intersection( const POINT *points, double x, double y, int count ) { int i;
@@ -299,15 +299,16 @@ static int find_intersection( const POINT *points, int x, int y, int count ) } }
-static void lp_to_dp_no_translate( DC *dc, POINT *point ) +static void lp_to_dp_no_translate( DC *dc, double *x, double *y ) { - double x = point->x; - double y = point->y; - point->x = GDI_ROUND( x * dc->xformWorld2Vport.eM11 + y * dc->xformWorld2Vport.eM21 ); - point->y = GDI_ROUND( x * dc->xformWorld2Vport.eM12 + y * dc->xformWorld2Vport.eM22 ); + double in_x = *x, in_y = *y; + + *x = in_x * dc->xformWorld2Vport.eM11 + in_y * dc->xformWorld2Vport.eM21; + *y = in_x * dc->xformWorld2Vport.eM12 + in_y * dc->xformWorld2Vport.eM22; }
-static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, POINT start, POINT end, POINT *points ) +static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, double start_x, double start_y, + double end_x, double end_y, POINT *points ) { int i, pos, count, start_pos, end_pos; int width = rect->right - rect->left; @@ -324,11 +325,11 @@ static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, POINT start, P
/* Transform the start and end, but do not translate them, so that they * remain relative to the ellipse center. */ - lp_to_dp_no_translate( dc, &start ); - lp_to_dp_no_translate( dc, &end ); + lp_to_dp_no_translate( dc, &start_x, &start_y ); + lp_to_dp_no_translate( dc, &end_x, &end_y );
- start_pos = find_intersection( points, start.x, start.y, count ); - end_pos = find_intersection( points, end.x, end.y, count ); + start_pos = find_intersection( points, start_x, start_y, count ); + end_pos = find_intersection( points, end_x, end_y, count ); if (arc_dir == AD_CLOCKWISE) { int tmp = start_pos; @@ -429,9 +430,9 @@ static BOOL draw_arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom, { points[0] = dc->attr->cur_pos; lp_to_dp( dc, points, 1 ); - count = 1 + get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0], pt[1], points + 1 ); + count = 1 + get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0].x, pt[0].y, pt[1].x, pt[1].y, points + 1 ); } - else count = get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0], pt[1], points ); + else count = get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0].x, pt[0].y, pt[1].x, pt[1].y, points );
if (count > max_points) ERR( "point count %u exceeds max points %u\n", count, max_points ); @@ -1538,7 +1539,7 @@ BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, dibdrv_physdev *pdev = get_dibdrv_pdev( dev ); DC *dc = get_physdev_dc( dev ); RECT rect, arc_rect; - POINT start, end, rect_center, *points, *top_points; + POINT rect_center, *points, *top_points; int count, max_points; BOOL ret = TRUE; HRGN outline = 0, interior = 0; @@ -1568,18 +1569,10 @@ BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, SetRect( &arc_rect, rect.left, rect.top, rect.left + ellipse_width, rect.top + ellipse_height ); /* Points are relative to the arc center. * We just need to specify any point on the vector. */ - start.x = -1; - start.y = 0; - end.x = 0; - end.y = -1; - count = get_arc_points( dc, AD_CLOCKWISE, &arc_rect, start, end, top_points ); + count = get_arc_points( dc, AD_CLOCKWISE, &arc_rect, -1.0, 0.0, 0.0, -1.0, top_points );
SetRect( &arc_rect, rect.right - ellipse_width, rect.top, rect.right, rect.top + ellipse_height ); - start.x = 0; - start.y = -1; - end.x = 1; - end.y = 0; - count += get_arc_points( dc, AD_CLOCKWISE, &arc_rect, start, end, top_points + count ); + count += get_arc_points( dc, AD_CLOCKWISE, &arc_rect, 0.0, -1.0, 1.0, 0.0, top_points + count );
if (count * 2 > max_points) ERR( "point count %u * 2 exceeds max points %u\n", count, max_points );
From: Elizabeth Figura zfigura@codeweavers.com
Before 5924ab4c5155d97f4b23a33e97258c1ec382ea02 we would forward to Rectangle() if the width or height was <= 2. This is incorrect for scaling transformations, but forwarding when the dimensions are zero is still correct, and avoids errors. --- dlls/win32u/dibdrv/graphics.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index 44d73dc7515..9d956e51950 100644 --- a/dlls/win32u/dibdrv/graphics.c +++ b/dlls/win32u/dibdrv/graphics.c @@ -1544,6 +1544,9 @@ BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, BOOL ret = TRUE; HRGN outline = 0, interior = 0;
+ if (!ellipse_width || !ellipse_height) + return dibdrv_Rectangle( dev, left, top, right, bottom ); + SetRect( &arc_rect, 0, 0, ellipse_width, ellipse_height ); /* We are drawing four arcs, but the number of points we will actually use * is exactly as many as in one ellipse arc. */
This merge request was approved by Huw Davies.