diff --git a/dlls/gdi32/dibdrv/graphics.c b/dlls/gdi32/dibdrv/graphics.c index 07ff72d1e71..49cf38df221 100644 --- a/dlls/gdi32/dibdrv/graphics.c +++ b/dlls/gdi32/dibdrv/graphics.c @@ -319,7 +319,7 @@ static BOOL draw_arc( 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, rc; POINT pt[2], *points; int width, height, count; BOOL ret = TRUE; @@ -370,8 +370,10 @@ static BOOL draw_arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom, return FALSE; } - if (pdev->brush.style != BS_NULL && extra_lines > 0 && - !(interior = CreatePolygonRgn( points, count, WINDING ))) + if (pdev->brush.style != BS_NULL && + extra_lines > 0 && + get_dib_rect( &pdev->dib, &rc ) && + !(interior = create_polypolygon_region( points, &count, 1, WINDING, &rc ))) { HeapFree( GetProcessHeap(), 0, points ); if (outline) DeleteObject( outline ); @@ -1246,6 +1248,7 @@ BOOL dibdrv_PolyPolygon( PHYSDEV dev, const POINT *pt, const INT *counts, DWORD dibdrv_physdev *pdev = get_dibdrv_pdev(dev); DC *dc = get_physdev_dc( dev ); DWORD total, i, pos; + RECT rc; BOOL ret = TRUE; POINT pt_buf[32]; POINT *points = pt_buf; @@ -1266,7 +1269,8 @@ BOOL dibdrv_PolyPolygon( PHYSDEV dev, const POINT *pt, const INT *counts, DWORD lp_to_dp( dc, points, total ); if (pdev->brush.style != BS_NULL && - !(interior = CreatePolyPolygonRgn( points, counts, polygons, dc->polyFillMode ))) + get_dib_rect( &pdev->dib, &rc ) && + !(interior = create_polypolygon_region( points, counts, polygons, dc->polyFillMode, &rc ))) { ret = FALSE; goto done; diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index 4236aa3690a..cf904d633d6 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -354,6 +354,8 @@ extern HPALETTE PALETTE_Init(void) DECLSPEC_HIDDEN; extern BOOL add_rect_to_region( HRGN rgn, const RECT *rect ) DECLSPEC_HIDDEN; extern INT mirror_region( HRGN dst, HRGN src, INT width ) DECLSPEC_HIDDEN; extern BOOL REGION_FrameRgn( HRGN dest, HRGN src, INT x, INT y ) DECLSPEC_HIDDEN; +extern HRGN create_polypolygon_region( const POINT *pts, const INT *count, INT nbpolygons, + INT mode, const RECT *clip_rect ) DECLSPEC_HIDDEN; #define RGN_DEFAULT_RECTS 4 typedef struct diff --git a/dlls/gdi32/region.c b/dlls/gdi32/region.c index d36975069e8..4899d439b73 100644 --- a/dlls/gdi32/region.c +++ b/dlls/gdi32/region.c @@ -2388,7 +2388,8 @@ static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, */ static unsigned int REGION_CreateEdgeTable(const INT *Count, INT nbpolygons, const POINT *pts, EdgeTable *ET, - EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock) + EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock, + const RECT *clip_rect) { const POINT *top, *bottom; const POINT *PrevPt, *CurrPt, *EndPt; @@ -2419,7 +2420,7 @@ static unsigned int REGION_CreateEdgeTable(const INT *Count, INT nbpolygons, * In this loop we are dealing with two vertices at * a time -- these make up one edge of the polygon. */ - while (count--) + for ( ; count; PrevPt = CurrPt, count--) { CurrPt = pts++; @@ -2440,30 +2441,25 @@ static unsigned int REGION_CreateEdgeTable(const INT *Count, INT nbpolygons, /* * don't add horizontal edges to the Edge table. */ - if (bottom->y != top->y) - { - pETEs->ymax = bottom->y-1; - /* -1 so we don't get last scanline */ + if (bottom->y == top->y) continue; + if (clip_rect && (top->y >= clip_rect->bottom || bottom->y <= clip_rect->top)) continue; + pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */ /* * initialize integer edge algorithm */ - dy = bottom->y - top->y; - bres_init_polygon(dy, top->x, bottom->x, &pETEs->bres); - if (total + dy < total) return 0; /* overflow */ - total += dy; + dy = bottom->y - top->y; + bres_init_polygon(dy, top->x, bottom->x, &pETEs->bres); - REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, - &iSLLBlock); + if (clip_rect) dy = min( bottom->y, clip_rect->bottom ) - max( top->y, clip_rect->top ); + if (total + dy < total) return 0; /* overflow */ + total += dy; - if (PrevPt->y > ET->ymax) - ET->ymax = PrevPt->y; - if (PrevPt->y < ET->ymin) - ET->ymin = PrevPt->y; - pETEs++; - } + REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock); - PrevPt = CurrPt; + if (PrevPt->y > ET->ymax) ET->ymax = PrevPt->y; + if (PrevPt->y < ET->ymin) ET->ymin = PrevPt->y; + pETEs++; } } return total; @@ -2587,12 +2583,13 @@ static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock) } } - /*********************************************************************** - * CreatePolyPolygonRgn (GDI32.@) + * create_polypolygon_region + * + * Helper for CreatePolyPolygonRgn. */ -HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count, - INT nbpolygons, INT mode) +HRGN create_polypolygon_region( const POINT *Pts, const INT *Count, INT nbpolygons, INT mode, + const RECT *clip_rect ) { HRGN hrgn = 0; WINEREGION *obj = NULL; @@ -2630,10 +2627,12 @@ HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count, if (! (pETEs = HeapAlloc( GetProcessHeap(), 0, sizeof(EdgeTableEntry) * total ))) return 0; - if (!(nb_points = REGION_CreateEdgeTable(Count, nbpolygons, Pts, &ET, pETEs, &SLLBlock))) goto done; + if (!(nb_points = REGION_CreateEdgeTable( Count, nbpolygons, Pts, &ET, pETEs, &SLLBlock, clip_rect ))) + goto done; if (!(obj = alloc_region( nb_points / 2 ))) goto done; + if (clip_rect) ET.ymax = min( ET.ymax, clip_rect->bottom ); list_init( &AET ); pSLL = ET.scanlines.next; if (mode != WINDING) { @@ -2650,21 +2649,25 @@ HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count, pSLL = pSLL->next; } - LIST_FOR_EACH_ENTRY( active, &AET, struct edge_table_entry, entry ) + if (!clip_rect || y >= clip_rect->top) { - if (first) + LIST_FOR_EACH_ENTRY( active, &AET, struct edge_table_entry, entry ) { - obj->rects[obj->numRects].left = active->bres.minor_axis; - obj->rects[obj->numRects].top = y; + if (first) + { + obj->rects[obj->numRects].left = active->bres.minor_axis; + obj->rects[obj->numRects].top = y; + } + else if (obj->rects[obj->numRects].left != active->bres.minor_axis) + { + obj->rects[obj->numRects].right = active->bres.minor_axis; + obj->rects[obj->numRects].bottom = y + 1; + obj->numRects++; + } + first = !first; } - else if (obj->rects[obj->numRects].left != active->bres.minor_axis) - { - obj->rects[obj->numRects].right = active->bres.minor_axis; - obj->rects[obj->numRects].bottom = y + 1; - obj->numRects++; - } - first = !first; } + next_scanline( &AET, y ); if (obj->numRects) @@ -2693,26 +2696,30 @@ HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count, /* * for each active edge */ - LIST_FOR_EACH_ENTRY( active, &AET, struct edge_table_entry, entry ) + if (!clip_rect || y >= clip_rect->top) { - /* - * add to the buffer only those edges that - * are in the Winding active edge table. - */ - if (pWETE == &active->winding_entry) { - if (first) + LIST_FOR_EACH_ENTRY( active, &AET, struct edge_table_entry, entry ) + { + /* + * add to the buffer only those edges that + * are in the Winding active edge table. + */ + if (pWETE == &active->winding_entry) { - obj->rects[obj->numRects].left = active->bres.minor_axis; - obj->rects[obj->numRects].top = y; + if (first) + { + obj->rects[obj->numRects].left = active->bres.minor_axis; + obj->rects[obj->numRects].top = y; + } + else if (obj->rects[obj->numRects].left != active->bres.minor_axis) + { + obj->rects[obj->numRects].right = active->bres.minor_axis; + obj->rects[obj->numRects].bottom = y + 1; + obj->numRects++; + } + first = !first; + pWETE = list_next( &WETE, pWETE ); } - else if (obj->rects[obj->numRects].left != active->bres.minor_axis) - { - obj->rects[obj->numRects].right = active->bres.minor_axis; - obj->rects[obj->numRects].bottom = y + 1; - obj->numRects++; - } - first = !first; - pWETE = list_next( &WETE, pWETE ); } } @@ -2756,11 +2763,19 @@ done: } +/*********************************************************************** + * CreatePolyPolygonRgn (GDI32.@) + */ +HRGN WINAPI CreatePolyPolygonRgn( const POINT *pts, const INT *count, INT nbpolygons, INT mode ) +{ + return create_polypolygon_region( pts, count, nbpolygons, mode, NULL ); +} + + /*********************************************************************** * CreatePolygonRgn (GDI32.@) */ -HRGN WINAPI CreatePolygonRgn( const POINT *points, INT count, - INT mode ) +HRGN WINAPI CreatePolygonRgn( const POINT *points, INT count, INT mode ) { - return CreatePolyPolygonRgn( points, &count, 1, mode ); + return create_polypolygon_region( points, &count, 1, mode, NULL ); }