We are late in the regression season, and it's clear that quite a lot of patches are still needed to fix all of the rendering and memory errors (all of 7063, plus at least one more to fix yet another bug in Multisim reported in bug 53706). In the event that those patches are not considered safe enough, simply reverting the entirety of transformed arc support is an alternative.
This does sacrifice one feature for another, but it's not clear that bug 34579 and 35331 ever affected a real application. Certainly they did not name any.
From: Elizabeth Figura zfigura@codeweavers.com
This reverts commit 417112795aff5c85f81f78b04538df31fc22f1ff. --- dlls/win32u/dibdrv/graphics.c | 3 --- 1 file changed, 3 deletions(-)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index 9d956e51950..44d73dc7515 100644 --- a/dlls/win32u/dibdrv/graphics.c +++ b/dlls/win32u/dibdrv/graphics.c @@ -1544,9 +1544,6 @@ 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. */
From: Elizabeth Figura zfigura@codeweavers.com
This reverts commit 6be6f67dbb5ef8462a3a4b4e3eb587358213d6df. --- dlls/win32u/dibdrv/graphics.c | 41 ++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index 44d73dc7515..17751e44644 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, double x, double y, int count ) +static int find_intersection( const POINT *points, int x, int y, int count ) { int i;
@@ -299,16 +299,15 @@ static int find_intersection( const POINT *points, double x, double y, int count } }
-static void lp_to_dp_no_translate( DC *dc, double *x, double *y ) +static void lp_to_dp_no_translate( DC *dc, POINT *point ) { - 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; + 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 ); }
-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 ) +static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, POINT start, POINT end, POINT *points ) { int i, pos, count, start_pos, end_pos; int width = rect->right - rect->left; @@ -325,11 +324,11 @@ static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, double start_x
/* 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_x, &start_y ); - lp_to_dp_no_translate( dc, &end_x, &end_y ); + lp_to_dp_no_translate( dc, &start ); + lp_to_dp_no_translate( dc, &end );
- 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; @@ -430,9 +429,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].x, pt[0].y, pt[1].x, pt[1].y, points + 1 ); + count = 1 + get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0], pt[1], points + 1 ); } - else count = get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0].x, pt[0].y, pt[1].x, pt[1].y, points ); + else count = get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0], pt[1], points );
if (count > max_points) ERR( "point count %u exceeds max points %u\n", count, max_points ); @@ -1539,7 +1538,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 rect_center, *points, *top_points; + POINT start, end, rect_center, *points, *top_points; int count, max_points; BOOL ret = TRUE; HRGN outline = 0, interior = 0; @@ -1569,10 +1568,18 @@ 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. */ - count = get_arc_points( dc, AD_CLOCKWISE, &arc_rect, -1.0, 0.0, 0.0, -1.0, top_points ); + 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 );
SetRect( &arc_rect, rect.right - ellipse_width, rect.top, rect.right, rect.top + ellipse_height ); - count += get_arc_points( dc, AD_CLOCKWISE, &arc_rect, 0.0, -1.0, 1.0, 0.0, top_points + count ); + 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 );
if (count * 2 > max_points) ERR( "point count %u * 2 exceeds max points %u\n", count, max_points );
From: Elizabeth Figura zfigura@codeweavers.com
This reverts commit cf3660069fcaa79306686106f4c6e63c3ce9eaa3. --- dlls/win32u/dibdrv/graphics.c | 6 ------ 1 file changed, 6 deletions(-)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index 17751e44644..56c6ebc44f8 100644 --- a/dlls/win32u/dibdrv/graphics.c +++ b/dlls/win32u/dibdrv/graphics.c @@ -316,12 +316,6 @@ 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 reverts commit 46a99090e11184d0ceccbb81f14544f387b33759. --- dlls/win32u/dibdrv/graphics.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index 56c6ebc44f8..cc62d6a681b 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, arc_rect; + RECT rect; POINT start, end, rect_center, *points, *top_points; int count, max_points; BOOL ret = TRUE; HRGN outline = 0, interior = 0;
- SetRect( &arc_rect, 0, 0, ellipse_width, ellipse_height ); + SetRect( &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, &arc_rect ); + max_points = get_arc_max_points( dc, &rect ); points = malloc( max_points * sizeof(*points) ); top_points = malloc( max_points * sizeof(*points) ); if (!points || !top_points) @@ -1556,30 +1556,27 @@ BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, return FALSE; }
- SetRect( &rect, left, top, right, bottom ); - order_rect( &rect ); - - SetRect( &arc_rect, rect.left, rect.top, rect.left + ellipse_width, rect.top + ellipse_height ); + SetRect( &rect, left, top, left + ellipse_width, 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, &rect, start, end, top_points );
- SetRect( &arc_rect, rect.right - ellipse_width, rect.top, rect.right, rect.top + ellipse_height ); + SetRect( &rect, right - ellipse_width, top, right, 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, &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 = (rect.left + rect.right) / 2; - rect_center.y = (rect.top + rect.bottom) / 2; + rect_center.x = (left + right) / 2; + rect_center.y = (top + bottom) / 2; lp_to_dp( dc, &rect_center, 1 );
if (dc->attr->arc_direction == AD_CLOCKWISE)
From: Elizabeth Figura zfigura@codeweavers.com
This reverts commit 7e80632d46c9558bb8057a79d59ee0daff74d9a1. --- dlls/win32u/dibdrv/graphics.c | 45 +++++++++++++---------------------- 1 file changed, 16 insertions(+), 29 deletions(-)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index cc62d6a681b..197e91a7f5d 100644 --- a/dlls/win32u/dibdrv/graphics.c +++ b/dlls/win32u/dibdrv/graphics.c @@ -217,7 +217,7 @@ static unsigned int generate_ellipse_top_half( const DC *dc, double width, doubl double dy = -(a * pt.x + b * pt.y); int x_inc = (dx > 0 ? 1 : -1); int y_inc = (dy > 0 ? 1 : -1); - double sigma1, sigma2; + double sigma;
points[pos++] = pt;
@@ -226,42 +226,29 @@ static unsigned int generate_ellipse_top_half( const DC *dc, double width, doubl /* Increment y, maybe increment x. */ pt.y += y_inc;
- /* If this point has 45° slope, and it's directly adjacent to one - * we just wrote, using the algorithm as-is will select this point - * and then the one horizontally adjacent to it (our reflection - * across the 45° line.) This creates an L-shaped corner, which we - * don't want. Force incrementing X to skip that corner. */ - if (fabs(b * pt.x + c * pt.y) == fabs(a * pt.x + b * pt.y)) - { + sigma = (a * pt.x * pt.x) + (2 * b * pt.x * pt.y) + (c * pt.y * pt.y) - d; + /* σ < 0 if the next point would be inside the ellipse. + * If we are moving towards a vertical or horizontal tangent point, + * and (x, y+1) is outside the ellipse, then it's certainly + * closer to the ellipse than (x-1, y+1). [Same for the 180° + * rotation.] Hence we want to increment x if σ < 0. + * If we are moving away from a tangent point, the opposite applies, + * and we want to increment x if σ > 0. + * We are moving towards a tangent point if (dx > 0 XOR dy > 0), + * so want to increment x if (dx > 0 XOR dy > 0 XOR σ > 0). */ + if (sigma != 0.0 && (dx > 0) ^ (dy > 0) ^ (sigma > 0)) pt.x += x_inc; - continue; - } - - sigma1 = (a * pt.x * pt.x) + (2 * b * pt.x * pt.y) + (c * pt.y * pt.y) - d; - pt.x += x_inc; - sigma2 = (a * pt.x * pt.x) + (2 * b * pt.x * pt.y) + (c * pt.y * pt.y) - d; - - /* Pick whichever point is closer to the ellipse. */ - if (fabs(sigma2) > fabs(sigma1)) - pt.x -= x_inc; } else { /* Increment x, maybe increment y. */ pt.x += x_inc;
- if (fabs(b * pt.x + c * pt.y) == fabs(a * pt.x + b * pt.y)) - { + sigma = (a * pt.x * pt.x) + (2 * b * pt.x * pt.y) + (c * pt.y * pt.y) - d; + /* As above, but we are moving towards a tangent point if the + * opposite condition is true, i.e. (dx < 0 XOR dy > 0). */ + if (sigma != 0.0 && (dx < 0) ^ (dy > 0) ^ (sigma > 0)) pt.y += y_inc; - continue; - } - - sigma1 = (a * pt.x * pt.x) + (2 * b * pt.x * pt.y) + (c * pt.y * pt.y) - d; - pt.y += y_inc; - sigma2 = (a * pt.x * pt.x) + (2 * b * pt.x * pt.y) + (c * pt.y * pt.y) - d; - - if (fabs(sigma2) > fabs(sigma1)) - pt.y -= y_inc; } } return pos;
From: Elizabeth Figura zfigura@codeweavers.com
This reverts commit f4b46cef3fa7db1dbca332049d4b14b124dc5492. --- dlls/win32u/dibdrv/graphics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index 197e91a7f5d..414737fa8ca 100644 --- a/dlls/win32u/dibdrv/graphics.c +++ b/dlls/win32u/dibdrv/graphics.c @@ -1529,7 +1529,7 @@ BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, * is exactly as many as in one ellipse arc. */ max_points = get_arc_max_points( dc, &rect ); points = malloc( max_points * sizeof(*points) ); - top_points = malloc( max_points * sizeof(*points) ); + top_points = malloc( max_points / 2 * sizeof(*points) ); if (!points || !top_points) { free( points );
From: Elizabeth Figura zfigura@codeweavers.com
This reverts commit 5924ab4c5155d97f4b23a33e97258c1ec382ea02. --- dlls/win32u/dibdrv/graphics.c | 145 +++++++++++++++++++++------------- 1 file changed, 89 insertions(+), 56 deletions(-)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index 414737fa8ca..bce3173fe97 100644 --- a/dlls/win32u/dibdrv/graphics.c +++ b/dlls/win32u/dibdrv/graphics.c @@ -171,6 +171,43 @@ static void add_pen_lines_bounds( dibdrv_physdev *dev, int count, const POINT *p add_clipped_bounds( dev, &bounds, dev->clip ); }
+/* compute the points for the first quadrant of an ellipse, counterclockwise from the x axis */ +/* 'data' must contain enough space, (width+height)/2 is a reasonable upper bound */ +static int ellipse_first_quadrant( int width, int height, POINT *data ) +{ + const int a = width - 1; + const int b = height - 1; + const INT64 asq = (INT64)8 * a * a; + const INT64 bsq = (INT64)8 * b * b; + INT64 dx = (INT64)4 * b * b * (1 - a); + INT64 dy = (INT64)4 * a * a * (1 + (b % 2)); + INT64 err = dx + dy + a * a * (b % 2); + int pos = 0; + POINT pt; + + pt.x = a; + pt.y = height / 2; + + /* based on an algorithm by Alois Zingl */ + + while (pt.x >= width / 2) + { + INT64 e2 = 2 * err; + data[pos++] = pt; + if (e2 >= dx) + { + pt.x--; + err += dx += bsq; + } + if (e2 <= dy) + { + pt.y++; + err += dy += asq; + } + } + return pos; +} + /* Draw the "top half" of the ellipse, viz. the half that doesn't have any * points in the lower-right quadrant. * @@ -1519,94 +1556,90 @@ 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; - POINT start, end, rect_center, *points, *top_points; - int count, max_points; + POINT pt[2], *points; + int i, end, count; BOOL ret = TRUE; HRGN outline = 0, interior = 0;
- SetRect( &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 ); - points = malloc( max_points * sizeof(*points) ); - top_points = malloc( max_points / 2 * sizeof(*points) ); - if (!points || !top_points) + if (!get_pen_device_rect( dc, pdev, &rect, left, top, right, bottom )) return TRUE; + + pt[0].x = pt[0].y = 0; + pt[1].x = ellipse_width; + pt[1].y = ellipse_height; + lp_to_dp( dc, pt, 2 ); + ellipse_width = min( rect.right - rect.left, abs( pt[1].x - pt[0].x )); + ellipse_height = min( rect.bottom - rect.top, abs( pt[1].y - pt[0].y )); + if (ellipse_width <= 2|| ellipse_height <= 2) + return dibdrv_Rectangle( dev, left, top, right, bottom ); + + points = malloc( (ellipse_width + ellipse_height) * 2 * sizeof(*points) ); + if (!points) return FALSE; + + if (pdev->pen_uses_region && !(outline = NtGdiCreateRectRgn( 0, 0, 0, 0 ))) { free( points ); - free( top_points ); return FALSE; }
- if (pdev->pen_uses_region && !(outline = NtGdiCreateRectRgn( 0, 0, 0, 0 ))) + if (pdev->brush.style != BS_NULL && + !(interior = NtGdiCreateRoundRectRgn( rect.left, rect.top, rect.right + 1, rect.bottom + 1, + ellipse_width, ellipse_height ))) { free( points ); + if (outline) NtGdiDeleteObjectApp( outline ); return FALSE; }
- SetRect( &rect, left, top, left + ellipse_width, 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 ); - - SetRect( &rect, right - ellipse_width, top, right, 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 ); - - if (count * 2 > max_points) - ERR( "point count %u * 2 exceeds max points %u\n", count, max_points ); + /* if not using a region, paint the interior first so the outline can overlap it */ + if (interior && !outline) + { + ret = brush_region( pdev, interior ); + NtGdiDeleteObjectApp( interior ); + interior = 0; + }
- rect_center.x = (left + right) / 2; - rect_center.y = (top + bottom) / 2; - lp_to_dp( dc, &rect_center, 1 ); + count = ellipse_first_quadrant( ellipse_width, ellipse_height, points );
if (dc->attr->arc_direction == AD_CLOCKWISE) { - for (unsigned int i = 0; i < count; ++i) + for (i = 0; i < count; i++) { - points[i].x = top_points[i].x; - points[i].y = top_points[i].y; - points[count + i].x = rect_center.x * 2 - points[i].x; - points[count + i].y = rect_center.y * 2 - points[i].y; + points[i].x = rect.right - ellipse_width + points[i].x; + points[i].y = rect.bottom - ellipse_height + points[i].y; } } else { - for (unsigned int i = 0; i < count; ++i) + for (i = 0; i < count; i++) { - points[i].x = top_points[count - 1 - i].x; - points[i].y = top_points[count - 1 - i].y; - points[count + i].x = rect_center.x * 2 - points[i].x; - points[count + i].y = rect_center.y * 2 - points[i].y; + points[i].x = rect.right - ellipse_width + points[i].x; + points[i].y = rect.top + ellipse_height - 1 - points[i].y; } }
- free( top_points ); - - count *= 2; + /* horizontal symmetry */
- if (pdev->brush.style != BS_NULL && - get_dib_rect( &pdev->dib, &rect ) && - !(interior = create_polypolygon_region( points, &count, 1, WINDING, &rect ))) + end = 2 * count - 1; + /* avoid duplicating the midpoint */ + if (ellipse_width % 2 && ellipse_width == rect.right - rect.left) end--; + for (i = 0; i < count; i++) { - free( points ); - if (outline) NtGdiDeleteObjectApp( outline ); - return FALSE; + points[end - i].x = rect.left + rect.right - 1 - points[i].x; + points[end - i].y = points[i].y; } + count = end + 1;
- /* if not using a region, paint the interior first so the outline can overlap it */ - if (interior && !outline) + /* vertical symmetry */ + + end = 2 * count - 1; + /* avoid duplicating the midpoint */ + if (ellipse_height % 2 && ellipse_height == rect.bottom - rect.top) end--; + for (i = 0; i < count; i++) { - ret = brush_region( pdev, interior ); - NtGdiDeleteObjectApp( interior ); - interior = 0; + points[end - i].x = points[i].x; + points[end - i].y = rect.top + rect.bottom - 1 - points[i].y; } + count = end + 1;
reset_dash_origin( pdev ); pdev->pen_lines( pdev, count, points, TRUE, outline );
From: Elizabeth Figura zfigura@codeweavers.com
This reverts commit 16e1978a29c8caece6f258b09496e4e71cb6e698. --- dlls/win32u/dibdrv/graphics.c | 242 ++++++++++------------------------ 1 file changed, 68 insertions(+), 174 deletions(-)
diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c index bce3173fe97..009143bc2d2 100644 --- a/dlls/win32u/dibdrv/graphics.c +++ b/dlls/win32u/dibdrv/graphics.c @@ -208,185 +208,100 @@ static int ellipse_first_quadrant( int width, int height, POINT *data ) return pos; }
-/* Draw the "top half" of the ellipse, viz. the half that doesn't have any - * points in the lower-right quadrant. - * - * We draw as many as eight arcs; in each we always increment one of X or Y - * (depending on whether the absolute value of the slope is less than - * or greater than 1) and possibly increment the other. - * - * Loosely based on an algorithm by David Eberly. - */ -static unsigned int generate_ellipse_top_half( const DC *dc, double width, double height, POINT *points ) -{ - /* A general ellipse centered at (0, 0) can be defined by - * ax² + 2bxy + cy² - d = 0. - * The transformation of an ellipse can be obtained by inverting the - * transformation matrix and substituting the transformed x and y, which - * yields an ellipse in the same form. - * Precompute the transformed coefficients. */ - const XFORM *xform = &dc->xformVport2World; - double wsq = (width / 2) * (width / 2); - double hsq = (height / 2) * (height / 2); - const double a = (hsq * xform->eM11 * xform->eM11) + (wsq * xform->eM12 * xform->eM12); - const double b = (hsq * xform->eM11 * xform->eM21) + (wsq * xform->eM12 * xform->eM22); - const double c = (hsq * xform->eM21 * xform->eM21) + (wsq * xform->eM22 * xform->eM22); - const double d = (hsq * wsq); - unsigned int pos = 0; - int start_x; - POINT pt; - - /* We start from the point that satisfies y = 0, i.e. ax² = d. - * Note that a must be nonzero if the transformation matrix was singular. - * - * d/a must be positive, since both a and d are comprised of squares. - * - * This point is not on the ellipse axis, but that doesn't matter for our - * algorithm. We will take this set of points and rotate it 180 degrees - * to get the opposite side. */ - pt.x = -sqrt(d / a); - pt.y = 0; - start_x = pt.x; - - while (pt.y > 0 || (pt.y == 0 && pt.x != -start_x)) - { - double dx = (b * pt.x + c * pt.y); - double dy = -(a * pt.x + b * pt.y); - int x_inc = (dx > 0 ? 1 : -1); - int y_inc = (dy > 0 ? 1 : -1); - double sigma; - - points[pos++] = pt; - - if (fabs(dy) > fabs(dx)) - { - /* Increment y, maybe increment x. */ - pt.y += y_inc; - - sigma = (a * pt.x * pt.x) + (2 * b * pt.x * pt.y) + (c * pt.y * pt.y) - d; - /* σ < 0 if the next point would be inside the ellipse. - * If we are moving towards a vertical or horizontal tangent point, - * and (x, y+1) is outside the ellipse, then it's certainly - * closer to the ellipse than (x-1, y+1). [Same for the 180° - * rotation.] Hence we want to increment x if σ < 0. - * If we are moving away from a tangent point, the opposite applies, - * and we want to increment x if σ > 0. - * We are moving towards a tangent point if (dx > 0 XOR dy > 0), - * so want to increment x if (dx > 0 XOR dy > 0 XOR σ > 0). */ - if (sigma != 0.0 && (dx > 0) ^ (dy > 0) ^ (sigma > 0)) - pt.x += x_inc; - } - else - { - /* Increment x, maybe increment y. */ - pt.x += x_inc; - - sigma = (a * pt.x * pt.x) + (2 * b * pt.x * pt.y) + (c * pt.y * pt.y) - d; - /* As above, but we are moving towards a tangent point if the - * opposite condition is true, i.e. (dx < 0 XOR dy > 0). */ - if (sigma != 0.0 && (dx < 0) ^ (dy > 0) ^ (sigma > 0)) - pt.y += y_inc; - } - } - return pos; -} - static int find_intersection( const POINT *points, int x, int y, int count ) { int i;
- /* First point is always x <= 0, y == 0, so if y >= 0 we are in the - * top half. */ - - if (!y) - return (x < 0) ? 0 : count; - - if (y > 0) + if (y >= 0) { - /* top half */ - for (i = 0; i < count; i++) + if (x >= 0) /* first quadrant */ { - if (points[i].x * y >= points[i].y * x) - break; + for (i = 0; i < count; i++) if (points[i].x * y <= points[i].y * x) break; + return i; } - return i; + /* second quadrant */ + for (i = 0; i < count; i++) if (points[i].x * y < points[i].y * -x) break; + return 2 * count - i; } - else + if (x >= 0) /* fourth quadrant */ { - /* bottom half */ - for (i = 0; i < count; i++) - { - if (points[i].x * -y >= points[i].y * -x) - break; - } - return count + i; + for (i = 0; i < count; i++) if (points[i].x * -y <= points[i].y * x) break; + return 4 * count - i; } + /* third quadrant */ + for (i = 0; i < count; i++) if (points[i].x * -y < points[i].y * -x) break; + return 2 * count + i; }
-static void lp_to_dp_no_translate( DC *dc, POINT *point ) -{ - 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 ); -} - -static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, POINT start, POINT end, POINT *points ) +static int get_arc_points( int arc_dir, const RECT *rect, POINT start, POINT end, POINT *points ) { int i, pos, count, start_pos, end_pos; int width = rect->right - rect->left; int height = rect->bottom - rect->top; - POINT center = {rect->left + width / 2, rect->top + height / 2};
- count = generate_ellipse_top_half( dc, width, height, points ); - - /* 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 ); - - 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) + count = ellipse_first_quadrant( width, height, points ); + for (i = 0; i < count; i++) { - int tmp = start_pos; - start_pos = end_pos; - end_pos = tmp; + points[i].x -= width / 2; + points[i].y -= height / 2; } - if (end_pos <= start_pos) end_pos += 2 * count; - - lp_to_dp( dc, ¢er, 1 ); + if (arc_dir != AD_CLOCKWISE) + { + start.y = -start.y; + end.y = -end.y; + } + start_pos = find_intersection( points, start.x, start.y, count ); + end_pos = find_intersection( points, end.x, end.y, count ); + if (end_pos <= start_pos) end_pos += 4 * count;
pos = count; - if (arc_dir == AD_COUNTERCLOCKWISE) + if (arc_dir == AD_CLOCKWISE) { for (i = start_pos; i < end_pos; i++, pos++) { - if ((i / count) % 2 == 0) - { - points[pos].x = center.x + points[i % count].x; - points[pos].y = center.y + points[i % count].y; - } - else + switch ((i / count) % 4) { - points[pos].x = center.x - points[i % count].x; - points[pos].y = center.y - points[i % count].y; + case 0: + points[pos].x = rect->left + width/2 + points[i % count].x; + points[pos].y = rect->top + height/2 + points[i % count].y; + break; + case 1: + points[pos].x = rect->right-1 - width/2 - points[count - 1 - i % count].x; + points[pos].y = rect->top + height/2 + points[count - 1 - i % count].y; + break; + case 2: + points[pos].x = rect->right-1 - width/2 - points[i % count].x; + points[pos].y = rect->bottom-1 - height/2 - points[i % count].y; + break; + case 3: + points[pos].x = rect->left + width/2 + points[count - 1 - i % count].x; + points[pos].y = rect->bottom-1 - height/2 - points[count - 1 - i % count].y; + break; } } } else { - for (i = end_pos - 1; i >= start_pos; i--, pos++) + for (i = start_pos; i < end_pos; i++, pos++) { - if ((i / count) % 2 == 0) - { - points[pos].x = center.x + points[i % count].x; - points[pos].y = center.y + points[i % count].y; - } - else + switch ((i / count) % 4) { - points[pos].x = center.x - points[i % count].x; - points[pos].y = center.y - points[i % count].y; + case 0: + points[pos].x = rect->left + width/2 + points[i % count].x; + points[pos].y = rect->bottom-1 - height/2 - points[i % count].y; + break; + case 1: + points[pos].x = rect->right-1 - width/2 - points[count - 1 - i % count].x; + points[pos].y = rect->bottom-1 - height/2 - points[count - 1 - i % count].y; + break; + case 2: + points[pos].x = rect->right-1 - width/2 - points[i % count].x; + points[pos].y = rect->top + height/2 + points[i % count].y; + break; + case 3: + points[pos].x = rect->left + width/2 + points[count - 1 - i % count].x; + points[pos].y = rect->top + height/2 + points[count - 1 - i % count].y; + break; } } } @@ -395,23 +310,6 @@ static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, POINT start, P return pos - count; }
-static unsigned int get_arc_max_points( DC *dc, const RECT *rect ) -{ - POINT pts[4] = - { - {rect->left, rect->top}, - {rect->left, rect->bottom}, - {rect->right, rect->bottom}, - {rect->right, rect->top} - }; - unsigned int width, height; - - lp_to_dp( dc, pts, 4 ); - width = max( abs( pts[2].x - pts[0].x ), abs( pts[3].x - pts[1].x )); - height = max( abs( pts[2].y - pts[0].y ), abs( pts[3].y - pts[1].y )); - return (width + height) * 3; -} - /* backend for arc functions; extra_lines is -1 for ArcTo, 0 for Arc, 1 for Chord, 2 for Pie */ static BOOL draw_arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom, INT start_x, INT start_y, INT end_x, INT end_y, INT extra_lines ) @@ -420,11 +318,11 @@ static BOOL draw_arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom, DC *dc = get_physdev_dc( dev ); RECT rect, rc; POINT pt[2], *points; - int width, height, count, max_points; + int width, height, count; BOOL ret = TRUE; HRGN outline = 0, interior = 0;
- SetRect( &rect, left, top, right, bottom ); + if (!get_pen_device_rect( dc, pdev, &rect, left, top, right, bottom )) return TRUE;
width = rect.right - rect.left; height = rect.bottom - rect.top; @@ -433,32 +331,28 @@ static BOOL draw_arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom, pt[0].y = start_y; pt[1].x = end_x; pt[1].y = end_y; + lp_to_dp( dc, pt, 2 ); /* make them relative to the ellipse center */ pt[0].x -= rect.left + width / 2; pt[0].y -= rect.top + height / 2; pt[1].x -= rect.left + width / 2; pt[1].y -= rect.top + height / 2;
- max_points = get_arc_max_points( dc, &rect ); - points = malloc( max_points * sizeof(*points) ); + points = malloc( (width + height) * 3 * sizeof(*points) ); if (!points) return FALSE;
if (extra_lines == -1) { 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->attr->arc_direction, &rect, pt[0], pt[1], points + 1 ); } - else count = get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0], pt[1], points ); - - if (count > max_points) - ERR( "point count %u exceeds max points %u\n", count, max_points ); + else count = get_arc_points( dc->attr->arc_direction, &rect, pt[0], pt[1], points );
if (extra_lines == 2) { points[count].x = rect.left + width / 2; points[count].y = rect.top + height / 2; - lp_to_dp( dc, &points[count], 1 ); count++; } if (count < 2)
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/gdi32/dc.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 0a57d74485e..3a1fc4ff56e 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -937,6 +937,9 @@ INT WINAPI GetGraphicsMode( HDC hdc ) INT WINAPI SetGraphicsMode( HDC hdc, INT mode ) { DWORD ret; + + TRACE( "dc %p mode %#x\n", hdc, mode ); + return NtGdiGetAndSetDCDword( hdc, NtGdiSetGraphicsMode, mode, &ret ) ? ret : 0; }
@@ -957,6 +960,8 @@ INT WINAPI SetArcDirection( HDC hdc, INT dir ) DC_ATTR *dc_attr; INT ret;
+ TRACE( "dc %p dir %#x\n", hdc, dir ); + if (dir != AD_COUNTERCLOCKWISE && dir != AD_CLOCKWISE) { SetLastError(ERROR_INVALID_PARAMETER); @@ -1309,6 +1314,9 @@ BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform, DWORD mode ) { DC_ATTR *dc_attr;
+ TRACE( "dc %p matrix {%.8e %.8e} {%.8e %.8e} offset {%.8e %.8e} mode %#lx\n", + hdc, xform->eM11, xform->eM12, xform->eM21, xform->eM22, xform->eDx, xform->eDy, mode ); + if (!(dc_attr = get_dc_attr( hdc ))) return FALSE; if (dc_attr->emf && !EMFDC_ModifyWorldTransform( dc_attr, xform, mode )) return FALSE; return NtGdiModifyWorldTransform( hdc, xform, mode ); @@ -1321,6 +1329,9 @@ BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform ) { DC_ATTR *dc_attr;
+ TRACE( "dc %p matrix {%.8e %.8e} {%.8e %.8e} offset {%.8e %.8e}\n", + hdc, xform->eM11, xform->eM12, xform->eM21, xform->eM22, xform->eDx, xform->eDy ); + if (!(dc_attr = get_dc_attr( hdc ))) return FALSE; if (dc_attr->emf && !EMFDC_SetWorldTransform( dc_attr, xform )) return FALSE; return NtGdiModifyWorldTransform( hdc, xform, MWT_SET );
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/gdi32/tests/bitmap.c | 316 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+)
diff --git a/dlls/gdi32/tests/bitmap.c b/dlls/gdi32/tests/bitmap.c index eb5ef0994d6..2284f1f5e23 100644 --- a/dlls/gdi32/tests/bitmap.c +++ b/dlls/gdi32/tests/bitmap.c @@ -5981,6 +5981,321 @@ static void test_D3DKMTCreateDCFromMemory( void ) ok(ret, "Failed to free memory, error %lu.\n", GetLastError()); }
+static void test_arcs(void) +{ + static const unsigned int dib_width = 100, dib_height = 100; + unsigned int *bits; + HBITMAP bitmap; + XFORM xform; + BOOL ret; + HPEN pen; + HDC dc; + + static const BITMAPINFO bitmap_info = + { + .bmiHeader.biSize = sizeof(BITMAPINFOHEADER), + .bmiHeader.biWidth = dib_width, + .bmiHeader.biHeight = dib_height, + .bmiHeader.biBitCount = 32, + .bmiHeader.biPlanes = 1, + }; + + dc = CreateCompatibleDC( 0 ); + bitmap = CreateDIBSection( dc, &bitmap_info, DIB_RGB_COLORS, (void **)&bits, NULL, 0 ); + SelectObject( dc, bitmap ); + pen = CreatePen( PS_SOLID, 1, 0x111111 ); + SelectObject( dc, pen ); + + SelectObject( dc, CreateSolidBrush(0)); + + /* Don't test exact pixels, since approximating the native arc drawing + * algorithm is difficult. Do test that we're drawing to the right bounds, + * though. */ + + memset( bits, 0, dib_width * dib_height * 4 ); + Arc( dc, 10, 10, 40, 25, 0, 15, 20, 0 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x >= 40 || y >= 25 || (x < 22 && y < 16)) + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if (((x == 24 || x == 25) && (y == 10 || y == 24)) /* top/bottom center */ + || ((x == 10 || x == 39) && y == 17)) /* left/right center */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + memset( bits, 0, dib_width * dib_height * 4 ); + RoundRect( dc, 10, 10, 40, 25, 6, 9 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x >= 40 || y >= 25 + || ((x == 10 || x == 39) && (y == 10 || y == 24))) /* corners */ + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if (((x >= 13 && x < 37) && (y == 10 || y == 24)) /* top/bottom edge */ + || ((y >= 14 && y < 21) && (x == 10 || x == 39))) /* left/right edge */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + /* Same round rect, but with the ellipse width and height inverted. */ + memset( bits, 0, dib_width * dib_height * 4 ); + RoundRect( dc, 10, 10, 40, 25, -6, -9 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x >= 40 || y >= 25 + || ((x == 10 || x == 39) && (y == 10 || y == 24))) /* corners */ + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if (((x >= 13 && x < 37) && (y == 10 || y == 24)) /* top/bottom edge */ + || ((y >= 14 && y < 21) && (x == 10 || x == 39))) /* left/right edge */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + /* Round rect with ellipse sizes larger than the rectangle dimensions. + * This draws the whole ellipse, effectively clamping to the relevant dimensions. */ + + memset( bits, 0, dib_width * dib_height * 4 ); + RoundRect( dc, 10, 10, 40, 25, 6, 20 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x >= 40 || y >= 25) + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if (((x >= 13 && x < 37) && (y == 10 || y == 24)) /* top/bottom edge */ + || ((x == 10 || x == 39) && y == 17)) /* left/right center */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + /* Round rect with a 1-pixel ellipse. */ + + memset( bits, 0, dib_width * dib_height * 4 ); + RoundRect( dc, 10, 10, 40, 25, 1, 1 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x >= 40 || y >= 25) + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if (((x >= 11 && x < 39) && (y == 10 || y == 24)) /* top/bottom edge */ + || ((x == 10 || x == 39) && (y >= 11 && y < 24))) /* left/right edge */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + /* Round rect with a 0-pixel ellipse, which is identical to a simple rect. */ + + memset( bits, 0, dib_width * dib_height * 4 ); + RoundRect( dc, 10, 10, 40, 25, 0, 0 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (((x >= 10 && x < 40) && (y == 10 || y == 24)) /* top/bottom edge */ + || ((x == 10 || x == 39) && (y >= 10 && y < 25))) /* left/right edge */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + else + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + /* 0-pixel arc. */ + + memset( bits, 0, dib_width * dib_height * 4 ); + ret = Arc( dc, 10, 10, 40, 10, 0, 1, 1, 0 ); + ok(ret == TRUE, "Got %d.\n", ret); + + for (unsigned int y = 9; y <= 11; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + /* Arc with identical start/end points draws the whole ellipse. */ + + memset( bits, 0, dib_width * dib_height * 4 ); + Arc( dc, 10, 10, 40, 25, 0, 1, 0, 1 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x >= 40 || y >= 25) + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if (((x == 24 || x == 25) && (y == 10 || y == 24)) /* top/bottom center */ + || ((x == 10 || x == 39) && y == 17)) /* left/right center */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + /* Flipped arc direction. */ + + SetArcDirection( dc, AD_CLOCKWISE ); + + memset( bits, 0, dib_width * dib_height * 4 ); + Arc( dc, 10, 10, 40, 25, 20, 0, 0, 15 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x >= 40 || y >= 25 || (x < 22 && y < 16)) + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if (((x == 24 || x == 25) && (y == 10 || y == 24)) /* top/bottom center */ + || ((x == 10 || x == 39) && y == 17)) /* left/right center */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + /* Flip the arc rect. */ + + memset( bits, 0, dib_width * dib_height * 4 ); + Arc( dc, 40, 10, 10, 25, 20, 0, 0, 15 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x >= 40 || y >= 25 || (x < 22 && y < 16)) + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if (((x == 24 || x == 25) && (y == 10 || y == 24)) /* top/bottom center */ + || ((x == 10 || x == 39) && y == 17)) /* left/right center */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + /* Test with GM_ADVANCED. */ + + SetGraphicsMode( dc, GM_ADVANCED ); + + memset( bits, 0, dib_width * dib_height * 4 ); + Arc( dc, 10, 10, 40, 25, 20, 0, 0, 14 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x > 40 || y > 25 || (x < 22 && y < 16)) + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if ((x == 25 && (y == 10 || y == 25)) /* top/bottom center */ + || ((x == 10 || x == 40) && (y == 17 || y == 18))) /* left/right center */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + memset( bits, 0, dib_width * dib_height * 4 ); + RoundRect( dc, 10, 10, 40, 25, 6, 9 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x > 40 || y > 25) + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if (((x >= 13 && x <= 37) && (y == 10 || y == 25)) /* top/bottom edge */ + || ((y >= 14 && y <= 21) && (x == 10 || x == 40))) /* left/right edge */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + /* Flip the world transform. */ + + memset( &xform, 0, sizeof(xform) ); + xform.eM11 = 1.0f; + xform.eM22 = -1.0f; + xform.eDy = 35.0f; + SetWorldTransform( dc, &xform ); + + memset( bits, 0, dib_width * dib_height * 4 ); + Arc( dc, 10, 10, 40, 25, 20, 0, 0, 14 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x > 40 || y > 25 || (x < 22 && y > 19)) + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if ((x == 25 && (y == 10 || y == 25)) /* top/bottom center */ + || ((x == 10 || x == 40) && (y == 17 || y == 18))) /* left/right center */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + memset( bits, 0, dib_width * dib_height * 4 ); + RoundRect( dc, 10, 10, 40, 25, 6, 9 ); + + for (unsigned int y = 9; y <= 26; ++y) + { + for (unsigned int x = 9; x <= 41; ++x) + { + int colour = bits[(dib_height - 1 - y) * dib_width + x]; + + if (x < 10 || y < 10 || x > 40 || y > 25) + ok(!colour, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + + if (((x >= 13 && x <= 37) && (y == 10 || y == 25)) /* top/bottom edge */ + || ((y >= 14 && y <= 21) && (x == 10 || x == 40))) /* left/right edge */ + ok(colour == 0x111111, "Got unexpected colour %08x at (%u, %u).\n", colour, x, y); + } + } + + DeleteObject( bitmap ); + DeleteObject( pen ); + DeleteDC( dc ); +} + START_TEST(bitmap) { HMODULE hdll; @@ -6027,4 +6342,5 @@ START_TEST(bitmap) test_SetDIBitsToDevice(); test_SetDIBitsToDevice_RLE8(); test_D3DKMTCreateDCFromMemory(); + test_arcs(); }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=150752
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/win32u/dibdrv/graphics.c:217 error: patch failed: dlls/win32u/dibdrv/graphics.c:208 Task: Patch failed to apply
=== debian11 (build log) ===
error: patch failed: dlls/win32u/dibdrv/graphics.c:217 error: patch failed: dlls/win32u/dibdrv/graphics.c:208 Task: Patch failed to apply
=== debian11b (build log) ===
error: patch failed: dlls/win32u/dibdrv/graphics.c:217 error: patch failed: dlls/win32u/dibdrv/graphics.c:208 Task: Patch failed to apply
Unfortunately, I do think this is the way to go at this point. It looks like we'll need some `todo_wine`s in the tests though.