From b5cf73edd952ef91a525871d9b330fd51831197e Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 16 Jun 2016 14:06:48 +0900 Subject: [PATCH] gdi32: Implement FillPath, StrokeAndFillPath and StrokePath in the DIB driver. Signed-off-by: Alexandre Julliard --- dlls/gdi32/dibdrv/dc.c | 6 +-- dlls/gdi32/dibdrv/dibdrv.h | 3 ++ dlls/gdi32/dibdrv/graphics.c | 97 ++++++++++++++++++++++++++++++++++++ dlls/gdi32/gdi_private.h | 1 + dlls/gdi32/path.c | 57 +++++++++++++++++++++ 5 files changed, 161 insertions(+), 3 deletions(-) diff --git a/dlls/gdi32/dibdrv/dc.c b/dlls/gdi32/dibdrv/dc.c index 4aa1d1d1626..314c6513ec3 100644 --- a/dlls/gdi32/dibdrv/dc.c +++ b/dlls/gdi32/dibdrv/dc.c @@ -424,7 +424,7 @@ const struct gdi_dc_funcs dib_driver = dibdrv_ExtFloodFill, /* pExtFloodFill */ NULL, /* pExtSelectClipRgn */ dibdrv_ExtTextOut, /* pExtTextOut */ - NULL, /* pFillPath */ + dibdrv_FillPath, /* pFillPath */ NULL, /* pFillRgn */ NULL, /* pFlattenPath */ NULL, /* pFontIsLinked */ @@ -519,8 +519,8 @@ const struct gdi_dc_funcs dib_driver = NULL, /* pStartPage */ dibdrv_StretchBlt, /* pStretchBlt */ NULL, /* pStretchDIBits */ - NULL, /* pStrokeAndFillPath */ - NULL, /* pStrokePath */ + dibdrv_StrokeAndFillPath, /* pStrokeAndFillPath */ + dibdrv_StrokePath, /* pStrokePath */ NULL, /* pUnrealizePalette */ NULL, /* pWidenPath */ dibdrv_wine_get_wgl_driver, /* wine_get_wgl_driver */ diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h index c64058b8e24..fc28acc2b15 100644 --- a/dlls/gdi32/dibdrv/dibdrv.h +++ b/dlls/gdi32/dibdrv/dibdrv.h @@ -120,6 +120,7 @@ extern BOOL dibdrv_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT b extern BOOL dibdrv_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT type ) 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; +extern BOOL dibdrv_FillPath( PHYSDEV dev ) DECLSPEC_HIDDEN; extern DWORD dibdrv_GetImage( PHYSDEV dev, BITMAPINFO *info, struct gdi_image_bits *bits, struct bitblt_coords *src ) DECLSPEC_HIDDEN; extern COLORREF dibdrv_GetNearestColor( PHYSDEV dev, COLORREF color ) DECLSPEC_HIDDEN; @@ -150,6 +151,8 @@ extern COLORREF dibdrv_SetDCPenColor( PHYSDEV dev, COLORREF color ) DECLSPEC_HID extern COLORREF dibdrv_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color ) DECLSPEC_HIDDEN; extern BOOL dibdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst, PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop ) DECLSPEC_HIDDEN; +extern BOOL dibdrv_StrokeAndFillPath( PHYSDEV dev ) DECLSPEC_HIDDEN; +extern BOOL dibdrv_StrokePath( PHYSDEV dev ) DECLSPEC_HIDDEN; extern struct opengl_funcs *dibdrv_wine_get_wgl_driver( PHYSDEV dev, UINT version ) DECLSPEC_HIDDEN; static inline dibdrv_physdev *get_dibdrv_pdev( PHYSDEV dev ) diff --git a/dlls/gdi32/dibdrv/graphics.c b/dlls/gdi32/dibdrv/graphics.c index 2c865c02250..bfb345143a0 100644 --- a/dlls/gdi32/dibdrv/graphics.c +++ b/dlls/gdi32/dibdrv/graphics.c @@ -402,6 +402,73 @@ static BOOL draw_arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom, return ret; } +/* helper for path stroking and filling functions */ +static BOOL stroke_and_fill_path( dibdrv_physdev *dev, BOOL stroke, BOOL fill ) +{ + POINT *points; + BYTE *types; + BOOL ret = TRUE; + HRGN outline = 0, interior = 0; + int i, pos, total; + + if (dev->brush.style == BS_NULL) fill = FALSE; + + total = get_gdi_flat_path( dev->dev.hdc, &points, &types, fill ? &interior : NULL ); + if (total == -1) return FALSE; + if (!total) goto done; + + if (stroke && dev->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( dev, interior ); + DeleteObject( interior ); + interior = 0; + } + + if (stroke) + { + pos = 0; + for (i = 1; i < total; i++) + { + if (types[i] != PT_MOVETO) continue; + if (i > pos + 1) + { + reset_dash_origin( dev ); + dev->pen_lines( dev, i - pos, points + pos, + fill || types[i - 1] & PT_CLOSEFIGURE, outline ); + } + pos = i; + } + if (i > pos + 1) + { + reset_dash_origin( dev ); + dev->pen_lines( dev, i - pos, points + pos, + fill || types[i - 1] & PT_CLOSEFIGURE, outline ); + } + } + + add_pen_lines_bounds( dev, total, points, outline ); + + if (interior) + { + CombineRgn( interior, interior, outline, RGN_DIFF ); + ret = brush_region( dev, interior ); + DeleteObject( interior ); + } + if (outline) + { + if (ret) ret = pen_region( dev, outline ); + DeleteObject( outline ); + } + +done: + HeapFree( GetProcessHeap(), 0, points ); + HeapFree( GetProcessHeap(), 0, types ); + 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] = @@ -999,6 +1066,16 @@ BOOL dibdrv_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT type ) return TRUE; } +/*********************************************************************** + * dibdrv_FillPath + */ +BOOL dibdrv_FillPath( PHYSDEV dev ) +{ + dibdrv_physdev *pdev = get_dibdrv_pdev( dev ); + + return stroke_and_fill_path( pdev, FALSE, TRUE ); +} + /*********************************************************************** * dibdrv_GetNearestColor */ @@ -1499,3 +1576,23 @@ COLORREF dibdrv_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color ) free_clipped_rects( &clipped_rects ); return color; } + +/*********************************************************************** + * dibdrv_StrokeAndFillPath + */ +BOOL dibdrv_StrokeAndFillPath( PHYSDEV dev ) +{ + dibdrv_physdev *pdev = get_dibdrv_pdev( dev ); + + return stroke_and_fill_path( pdev, TRUE, TRUE ); +} + +/*********************************************************************** + * dibdrv_StrokePath + */ +BOOL dibdrv_StrokePath( PHYSDEV dev ) +{ + dibdrv_physdev *pdev = get_dibdrv_pdev( dev ); + + return stroke_and_fill_path( pdev, TRUE, FALSE ); +} diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index 08a5d3b6fb0..15e50e1c19b 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -335,6 +335,7 @@ typedef struct /* path.c */ extern void free_gdi_path( struct gdi_path *path ) DECLSPEC_HIDDEN; +extern int get_gdi_flat_path( HDC hdc, POINT **points, BYTE **flags, HRGN *rgn ) DECLSPEC_HIDDEN; extern BOOL PATH_SavePath( DC *dst, DC *src ) DECLSPEC_HIDDEN; extern BOOL PATH_RestorePath( DC *dst, DC *src ) DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/path.c b/dlls/gdi32/path.c index 0d89cfbb413..06fac7703cd 100644 --- a/dlls/gdi32/path.c +++ b/dlls/gdi32/path.c @@ -273,6 +273,32 @@ static BOOL start_new_stroke( struct path_physdev *physdev ) return add_log_points( physdev, &pos, 1, PT_MOVETO ) != NULL; } +/* convert a (flattened) path to a region */ +static HRGN path_to_region( const struct gdi_path *path, int mode ) +{ + int i, pos, polygons, *counts; + HRGN hrgn; + + if (!path->count) return 0; + + if (!(counts = HeapAlloc( GetProcessHeap(), 0, (path->count / 2) * sizeof(*counts) ))) return 0; + + pos = polygons = 0; + assert( path->flags[0] == PT_MOVETO ); + for (i = 1; i < path->count; i++) + { + if (path->flags[i] != PT_MOVETO) continue; + counts[polygons++] = i - pos; + pos = i; + } + if (i > pos + 1) counts[polygons++] = i - pos; + + assert( polygons <= path->count / 2 ); + hrgn = CreatePolyPolygonRgn( path->points, counts, polygons, mode ); + HeapFree( GetProcessHeap(), 0, counts ); + return hrgn; +} + /* PATH_CheckCorners * * Helper function for RoundRect() and Rectangle() @@ -505,6 +531,37 @@ static BOOL PATH_DoArcPart(struct gdi_path *pPath, FLOAT_POINT corners[], return TRUE; } +/* retrieve a flattened path in device coordinates, and optionally its region */ +/* the DC path is deleted; the returned data must be freed by caller */ +/* helper for stroke_and_fill_path in the DIB driver */ +int get_gdi_flat_path( HDC hdc, POINT **points, BYTE **flags, HRGN *rgn ) +{ + DC *dc = get_dc_ptr( hdc ); + int ret = -1; + + if (!dc) return -1; + + if (dc->path) + { + struct gdi_path *path = PATH_FlattenPath( dc->path ); + + free_gdi_path( dc->path ); + dc->path = NULL; + if (path) + { + ret = path->count; + *points = path->points; + *flags = path->flags; + if (rgn) *rgn = path_to_region( path, GetPolyFillMode( hdc )); + HeapFree( GetProcessHeap(), 0, path ); + } + } + else SetLastError( ERROR_CAN_NOT_COMPLETE ); + + release_dc_ptr( dc ); + return ret; +} + /*********************************************************************** * BeginPath (GDI32.@)