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 );
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;

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 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

View File

@ -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 );
}