From ff31a448b3b1c623ab21ea29229d0c94bbc0046f Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 6 Jan 2012 17:20:37 +0100 Subject: [PATCH] gdi32: Implement Arc, ArcTo, Chord, and Pie, using line segments for now. --- dlls/gdi32/dibdrv/dc.c | 8 +- dlls/gdi32/dibdrv/dibdrv.h | 8 ++ dlls/gdi32/dibdrv/graphics.c | 229 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 241 insertions(+), 4 deletions(-) diff --git a/dlls/gdi32/dibdrv/dc.c b/dlls/gdi32/dibdrv/dc.c index 5b63aa540f3..ac506b2a10c 100644 --- a/dlls/gdi32/dibdrv/dc.c +++ b/dlls/gdi32/dibdrv/dc.c @@ -558,12 +558,12 @@ const struct gdi_dc_funcs dib_driver = NULL, /* pAbortPath */ dibdrv_AlphaBlend, /* pAlphaBlend */ NULL, /* pAngleArc */ - NULL, /* pArc */ - NULL, /* pArcTo */ + dibdrv_Arc, /* pArc */ + dibdrv_ArcTo, /* pArcTo */ NULL, /* pBeginPath */ dibdrv_BlendImage, /* pBlendImage */ dibdrv_ChoosePixelFormat, /* pChoosePixelFormat */ - NULL, /* pChord */ + dibdrv_Chord, /* pChord */ NULL, /* pCloseFigure */ dibdrv_CopyBitmap, /* pCopyBitmap */ NULL, /* pCreateBitmap */ @@ -627,7 +627,7 @@ const struct gdi_dc_funcs dib_driver = NULL, /* pOffsetWindowOrg */ dibdrv_PaintRgn, /* pPaintRgn */ dibdrv_PatBlt, /* pPatBlt */ - NULL, /* pPie */ + dibdrv_Pie, /* pPie */ NULL, /* pPolyBezier */ NULL, /* pPolyBezierTo */ NULL, /* pPolyDraw */ diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h index 2ce1884e611..8327e342c56 100644 --- a/dlls/gdi32/dibdrv/dibdrv.h +++ b/dlls/gdi32/dibdrv/dibdrv.h @@ -110,8 +110,14 @@ typedef struct dibdrv_physdev extern BOOL dibdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst, PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blend ) DECLSPEC_HIDDEN; +extern BOOL dibdrv_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + INT start_x, INT start_y, INT end_x, INT end_y ) DECLSPEC_HIDDEN; +extern BOOL dibdrv_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + INT start_x, INT start_y, INT end_x, INT end_y ) DECLSPEC_HIDDEN; extern DWORD dibdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits, struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION func ) DECLSPEC_HIDDEN; +extern BOOL dibdrv_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + INT start_x, INT start_y, INT end_x, INT end_y ) DECLSPEC_HIDDEN; extern BOOL dibdrv_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom ) DECLSPEC_HIDDEN; extern BOOL dibdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *rect, LPCWSTR str, UINT count, const INT *dx ) DECLSPEC_HIDDEN; @@ -124,6 +130,8 @@ extern BOOL dibdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG n extern BOOL dibdrv_LineTo( PHYSDEV dev, INT x, INT y ) DECLSPEC_HIDDEN; extern BOOL dibdrv_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop ) DECLSPEC_HIDDEN; extern BOOL dibdrv_PaintRgn( PHYSDEV dev, HRGN hrgn ) DECLSPEC_HIDDEN; +extern BOOL dibdrv_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + INT start_x, INT start_y, INT end_x, INT end_y ) DECLSPEC_HIDDEN; extern BOOL dibdrv_PolyPolygon( PHYSDEV dev, const POINT *pt, const INT *counts, DWORD polygons ) DECLSPEC_HIDDEN; extern BOOL dibdrv_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines ) DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/dibdrv/graphics.c b/dlls/gdi32/dibdrv/graphics.c index 0cde4de4300..99be734f7e7 100644 --- a/dlls/gdi32/dibdrv/graphics.c +++ b/dlls/gdi32/dibdrv/graphics.c @@ -109,6 +109,199 @@ static int ellipse_first_quadrant( int width, int height, POINT *data ) return pos; } +static int find_intersection( const POINT *points, int x, int y, int count ) +{ + int i; + + if (y >= 0) + { + if (x >= 0) /* first quadrant */ + { + for (i = 0; i < count; i++) if (points[i].x * y <= points[i].y * x) break; + return i; + } + /* second quadrant */ + for (i = 0; i < count; i++) if (points[i].x * y < points[i].y * -x) break; + return 2 * count - i; + } + if (x >= 0) /* fourth quadrant */ + { + 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 int get_arc_points( PHYSDEV dev, 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; + + count = ellipse_first_quadrant( width, height, points ); + for (i = 0; i < count; i++) + { + points[i].x -= width / 2; + points[i].y -= height / 2; + } + if (GetArcDirection( dev->hdc ) != 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 (GetArcDirection( dev->hdc ) == AD_CLOCKWISE) + { + for (i = start_pos; i < end_pos; i++, pos++) + { + switch ((i / count) % 4) + { + 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->left + 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->left + 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; + } + } + } + else + { + for (i = start_pos; i < end_pos; i++, pos++) + { + switch ((i / count) % 4) + { + 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->left + 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->left + 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; + } + } + } + + memmove( points, points + count, (pos - count) * sizeof(POINT) ); + return pos - count; +} + +/* 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 ) +{ + dibdrv_physdev *pdev = get_dibdrv_pdev( dev ); + RECT rect; + POINT pt[2], *points; + int width, height, count; + BOOL ret = TRUE; + HRGN outline = 0, interior = 0; + + if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom )) return TRUE; + + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + pt[0].x = start_x; + pt[0].y = start_y; + pt[1].x = end_x; + pt[1].y = end_y; + LPtoDP( dev->hdc, pt, 2 ); + /* make them relative to the ellipse center */ + pt[0].x -= left + width / 2; + pt[0].y -= top + height / 2; + pt[1].x -= left + width / 2; + pt[1].y -= top + height / 2; + + points = HeapAlloc( GetProcessHeap(), 0, (width + height) * 3 * sizeof(*points) ); + if (!points) return FALSE; + + if (extra_lines == -1) + { + GetCurrentPositionEx( dev->hdc, points ); + LPtoDP( dev->hdc, points, 1 ); + count = 1 + get_arc_points( dev, &rect, pt[0], pt[1], points + 1 ); + } + else count = get_arc_points( dev, &rect, pt[0], pt[1], points ); + + if (extra_lines == 2) + { + points[count].x = rect.left + width / 2; + points[count].y = rect.top + height / 2; + count++; + } + if (count < 2) + { + HeapFree( GetProcessHeap(), 0, points ); + return TRUE; + } + + if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 ))) + { + HeapFree( GetProcessHeap(), 0, points ); + return FALSE; + } + + if (pdev->brush.style != BS_NULL && extra_lines > 0 && + !(interior = CreatePolygonRgn( points, count, WINDING ))) + { + HeapFree( GetProcessHeap(), 0, points ); + return FALSE; + } + + if (pdev->pen_uses_region) outline = CreateRectRgn( 0, 0, 0, 0 ); + + /* if not using a region, paint the interior first so the outline can overlap it */ + if (interior && !outline) + { + ret = brush_region( pdev, interior ); + DeleteObject( interior ); + interior = 0; + } + + reset_dash_origin( pdev ); + pdev->pen_lines( pdev, count, points, extra_lines > 0, outline ); + + if (interior) + { + CombineRgn( interior, interior, outline, RGN_DIFF ); + ret = brush_region( pdev, interior ); + DeleteObject( interior ); + } + if (outline) + { + if (ret) ret = pen_region( pdev, outline ); + DeleteObject( outline ); + } + HeapFree( GetProcessHeap(), 0, points ); + return ret; +} + /* Intensities of the 17 glyph levels when drawn with text component of 0xff on a black bkgnd. [A log-log plot of these data gives: y = 77.05 * x^0.4315]. */ static const BYTE ramp[17] = @@ -452,6 +645,33 @@ done: } /*********************************************************************** + * dibdrv_Arc + */ +BOOL dibdrv_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + INT start_x, INT start_y, INT end_x, INT end_y ) +{ + return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 0 ); +} + +/*********************************************************************** + * dibdrv_ArcTo + */ +BOOL dibdrv_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + INT start_x, INT start_y, INT end_x, INT end_y ) +{ + return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, -1 ); +} + +/*********************************************************************** + * dibdrv_Chord + */ +BOOL dibdrv_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + INT start_x, INT start_y, INT end_x, INT end_y ) +{ + return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 1 ); +} + +/*********************************************************************** * dibdrv_Ellipse */ BOOL dibdrv_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom ) @@ -882,6 +1102,15 @@ BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, } /*********************************************************************** + * dibdrv_Pie + */ +BOOL dibdrv_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + INT start_x, INT start_y, INT end_x, INT end_y ) +{ + return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 2 ); +} + +/*********************************************************************** * dibdrv_SetPixel */ COLORREF dibdrv_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color ) -- 2.11.4.GIT