gdi32: Clip the computed region to the DIB rectangle in PolyPolygon().

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Alexandre Julliard 2018-04-04 15:21:14 +02:00
parent 737a113c10
commit 0188dc7da8
3 changed files with 80 additions and 59 deletions

View File

@ -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 ); dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
DC *dc = get_physdev_dc( dev ); DC *dc = get_physdev_dc( dev );
RECT rect; RECT rect, rc;
POINT pt[2], *points; POINT pt[2], *points;
int width, height, count; int width, height, count;
BOOL ret = TRUE; BOOL ret = TRUE;
@ -370,8 +370,10 @@ static BOOL draw_arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
return FALSE; return FALSE;
} }
if (pdev->brush.style != BS_NULL && extra_lines > 0 && if (pdev->brush.style != BS_NULL &&
!(interior = CreatePolygonRgn( points, count, WINDING ))) extra_lines > 0 &&
get_dib_rect( &pdev->dib, &rc ) &&
!(interior = create_polypolygon_region( points, &count, 1, WINDING, &rc )))
{ {
HeapFree( GetProcessHeap(), 0, points ); HeapFree( GetProcessHeap(), 0, points );
if (outline) DeleteObject( outline ); 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); dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
DC *dc = get_physdev_dc( dev ); DC *dc = get_physdev_dc( dev );
DWORD total, i, pos; DWORD total, i, pos;
RECT rc;
BOOL ret = TRUE; BOOL ret = TRUE;
POINT pt_buf[32]; POINT pt_buf[32];
POINT *points = pt_buf; 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 ); lp_to_dp( dc, points, total );
if (pdev->brush.style != BS_NULL && 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; ret = FALSE;
goto done; goto done;

View File

@ -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 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 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 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 #define RGN_DEFAULT_RECTS 4
typedef struct typedef struct

View File

@ -2388,7 +2388,8 @@ static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
*/ */
static unsigned int REGION_CreateEdgeTable(const INT *Count, INT nbpolygons, static unsigned int REGION_CreateEdgeTable(const INT *Count, INT nbpolygons,
const POINT *pts, EdgeTable *ET, const POINT *pts, EdgeTable *ET,
EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock) EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock,
const RECT *clip_rect)
{ {
const POINT *top, *bottom; const POINT *top, *bottom;
const POINT *PrevPt, *CurrPt, *EndPt; 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 * In this loop we are dealing with two vertices at
* a time -- these make up one edge of the polygon. * a time -- these make up one edge of the polygon.
*/ */
while (count--) for ( ; count; PrevPt = CurrPt, count--)
{ {
CurrPt = pts++; 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. * don't add horizontal edges to the Edge table.
*/ */
if (bottom->y != top->y) 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; pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */
/* -1 so we don't get last scanline */
/* /*
* initialize integer edge algorithm * initialize integer edge algorithm
*/ */
dy = bottom->y - top->y; dy = bottom->y - top->y;
bres_init_polygon(dy, top->x, bottom->x, &pETEs->bres); bres_init_polygon(dy, top->x, bottom->x, &pETEs->bres);
if (total + dy < total) return 0; /* overflow */
total += dy;
REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, if (clip_rect) dy = min( bottom->y, clip_rect->bottom ) - max( top->y, clip_rect->top );
&iSLLBlock); if (total + dy < total) return 0; /* overflow */
total += dy;
if (PrevPt->y > ET->ymax) REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock);
ET->ymax = PrevPt->y;
if (PrevPt->y < ET->ymin)
ET->ymin = PrevPt->y;
pETEs++;
}
PrevPt = CurrPt; if (PrevPt->y > ET->ymax) ET->ymax = PrevPt->y;
if (PrevPt->y < ET->ymin) ET->ymin = PrevPt->y;
pETEs++;
} }
} }
return total; 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, HRGN create_polypolygon_region( const POINT *Pts, const INT *Count, INT nbpolygons, INT mode,
INT nbpolygons, INT mode) const RECT *clip_rect )
{ {
HRGN hrgn = 0; HRGN hrgn = 0;
WINEREGION *obj = NULL; WINEREGION *obj = NULL;
@ -2630,10 +2627,12 @@ HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count,
if (! (pETEs = HeapAlloc( GetProcessHeap(), 0, sizeof(EdgeTableEntry) * total ))) if (! (pETEs = HeapAlloc( GetProcessHeap(), 0, sizeof(EdgeTableEntry) * total )))
return 0; 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 ))) if (!(obj = alloc_region( nb_points / 2 )))
goto done; goto done;
if (clip_rect) ET.ymax = min( ET.ymax, clip_rect->bottom );
list_init( &AET ); list_init( &AET );
pSLL = ET.scanlines.next; pSLL = ET.scanlines.next;
if (mode != WINDING) { if (mode != WINDING) {
@ -2650,21 +2649,25 @@ HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count,
pSLL = pSLL->next; 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; if (first)
obj->rects[obj->numRects].top = y; {
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 ); next_scanline( &AET, y );
if (obj->numRects) if (obj->numRects)
@ -2693,26 +2696,30 @@ HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count,
/* /*
* for each active edge * for each active edge
*/ */
LIST_FOR_EACH_ENTRY( active, &AET, struct edge_table_entry, entry ) if (!clip_rect || y >= clip_rect->top)
{ {
/* 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. /*
*/ * add to the buffer only those edges that
if (pWETE == &active->winding_entry) { * are in the Winding active edge table.
if (first) */
if (pWETE == &active->winding_entry)
{ {
obj->rects[obj->numRects].left = active->bres.minor_axis; if (first)
obj->rects[obj->numRects].top = y; {
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.@) * CreatePolygonRgn (GDI32.@)
*/ */
HRGN WINAPI CreatePolygonRgn( const POINT *points, INT count, HRGN WINAPI CreatePolygonRgn( const POINT *points, INT count, INT mode )
INT mode )
{ {
return CreatePolyPolygonRgn( points, &count, 1, mode ); return create_polypolygon_region( points, &count, 1, mode, NULL );
} }