Alexandre Julliard : gdi32: Build the region object directly instead of making a copy in CreatePolyPolygonRgn.
Alexandre Julliard
julliard at winehq.org
Wed Apr 4 15:08:01 CDT 2018
Module: wine
Branch: master
Commit: 99b64f74320ba11b282a33aad2edc28551501875
URL: https://source.winehq.org/git/wine.git/?a=commit;h=99b64f74320ba11b282a33aad2edc28551501875
Author: Alexandre Julliard <julliard at winehq.org>
Date: Wed Apr 4 15:12:55 2018 +0200
gdi32: Build the region object directly instead of making a copy in CreatePolyPolygonRgn.
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/gdi32/region.c | 169 +++++++++++++++++++++++-----------------------------
1 file changed, 74 insertions(+), 95 deletions(-)
diff --git a/dlls/gdi32/region.c b/dlls/gdi32/region.c
index 8e0f32d..d369750 100644
--- a/dlls/gdi32/region.c
+++ b/dlls/gdi32/region.c
@@ -2537,18 +2537,26 @@ static void REGION_computeWAET( struct list *AET, struct list *WETE )
}
/***********************************************************************
- * REGION_InsertionSort
- *
- * Just a simple insertion sort to sort the Active Edge Table.
+ * next_scanline
*
+ * Update the Active Edge Table for the next scan line and sort it again.
*/
-static BOOL REGION_InsertionSort( struct list *AET )
+static inline BOOL next_scanline( struct list *AET, int y )
{
struct edge_table_entry *active, *next, *insert;
BOOL changed = FALSE;
LIST_FOR_EACH_ENTRY_SAFE( active, next, AET, struct edge_table_entry, entry )
{
+ if (active->ymax == y) /* leaving this edge */
+ {
+ list_remove( &active->entry );
+ changed = TRUE;
+ }
+ else bres_incr_polygon( &active->bres );
+ }
+ LIST_FOR_EACH_ENTRY_SAFE( active, next, AET, struct edge_table_entry, entry )
+ {
LIST_FOR_EACH_ENTRY( insert, AET, struct edge_table_entry, entry )
{
if (insert == active) break;
@@ -2581,66 +2589,13 @@ static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
/***********************************************************************
- * REGION_PtsToRegion
- *
- * Create an array of rectangles from a list of points.
- */
-static WINEREGION *REGION_PtsToRegion( const POINT *pts, unsigned int size )
-{
- int cur_band = 0, prev_band = 0;
- RECT *extents;
- WINEREGION *reg;
-
- if (!(reg = alloc_region( size / 2 ))) return NULL;
-
- extents = ®->extents;
- extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
-
- /* the loop uses 2 points per iteration */
- for (; size > 0; pts += 2, size -= 2)
- {
- if (pts[0].x == pts[1].x)
- continue;
-
- if (reg->numRects && pts[0].y != reg->rects[cur_band].top)
- {
- prev_band = REGION_Coalesce( reg, prev_band, cur_band );
- cur_band = reg->numRects;
- }
-
- add_rect( reg, pts[0].x, pts[0].y, pts[1].x, pts[1].y + 1 );
- if (pts[0].x < extents->left)
- extents->left = pts[0].x;
- if (pts[1].x > extents->right)
- extents->right = pts[1].x;
- }
-
- if (reg->numRects) {
- REGION_Coalesce( reg, prev_band, cur_band );
- extents->top = reg->rects[0].top;
- extents->bottom = reg->rects[reg->numRects-1].bottom;
- } else {
- extents->left = 0;
- extents->top = 0;
- extents->right = 0;
- extents->bottom = 0;
- }
- REGION_compact( reg );
-
- return reg;
-}
-
-/* Number of points in the first point buffer. Must be an even number. */
-#define NUMPTSTOBUFFER 200
-
-/***********************************************************************
* CreatePolyPolygonRgn (GDI32.@)
*/
HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count,
INT nbpolygons, INT mode)
{
HRGN hrgn = 0;
- WINEREGION *obj;
+ WINEREGION *obj = NULL;
INT y; /* current scanline */
struct list WETE, *pWETE; /* Winding Edge Table */
ScanLineList *pSLL; /* current scanLineList */
@@ -2648,11 +2603,10 @@ HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count,
struct list AET; /* header for AET */
EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
ScanLineListBlock SLLBlock; /* header for scanlinelist */
- BOOL fixWAET = FALSE;
- POINT buffer[NUMPTSTOBUFFER], *points = buffer;
- struct edge_table_entry *active, *next;
- unsigned int nb_points, pos = 0;
- INT poly, total;
+ struct edge_table_entry *active;
+ unsigned int nb_points;
+ int cur_band = 0, prev_band = 0;
+ INT i, poly, total, first = 1;
TRACE("%p, count %d, polygons %d, mode %d\n", Pts, *Count, nbpolygons, mode);
@@ -2677,11 +2631,9 @@ HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count,
return 0;
if (!(nb_points = REGION_CreateEdgeTable(Count, nbpolygons, Pts, &ET, pETEs, &SLLBlock))) goto done;
- if (nb_points > NUMPTSTOBUFFER)
- {
- if (nb_points > INT_MAX / sizeof(*points)) goto done;
- if (!(points = HeapAlloc( GetProcessHeap(), 0, nb_points * sizeof(*points) ))) goto done;
- }
+ if (!(obj = alloc_region( nb_points / 2 )))
+ goto done;
+
list_init( &AET );
pSLL = ET.scanlines.next;
if (mode != WINDING) {
@@ -2698,18 +2650,28 @@ HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count,
pSLL = pSLL->next;
}
- LIST_FOR_EACH_ENTRY_SAFE( active, next, &AET, struct edge_table_entry, entry )
+ LIST_FOR_EACH_ENTRY( active, &AET, struct edge_table_entry, entry )
{
- points[pos].x = active->bres.minor_axis;
- points[pos].y = y;
- pos++;
-
- if (active->ymax == y) /* leaving this edge */
- list_remove( &active->entry );
- else
- bres_incr_polygon( &active->bres );
+ 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;
+ }
+ next_scanline( &AET, y );
+
+ if (obj->numRects)
+ {
+ prev_band = REGION_Coalesce( obj, prev_band, cur_band );
+ cur_band = obj->numRects;
}
- REGION_InsertionSort(&AET);
}
}
else {
@@ -2731,47 +2693,64 @@ HRGN WINAPI CreatePolyPolygonRgn(const POINT *Pts, const INT *Count,
/*
* for each active edge
*/
- LIST_FOR_EACH_ENTRY_SAFE( active, next, &AET, struct edge_table_entry, entry )
+ 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) {
- points[pos].x = active->bres.minor_axis;
- points[pos].y = y;
- pos++;
+ 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 );
}
- if (active->ymax == y) /* leaving this edge */
- {
- list_remove( &active->entry );
- fixWAET = TRUE;
- }
- else
- bres_incr_polygon( &active->bres );
}
/*
* recompute the winding active edge table if
* we just resorted or have exited an edge.
*/
- if (REGION_InsertionSort(&AET) || fixWAET) {
- REGION_computeWAET( &AET, &WETE );
- fixWAET = FALSE;
+ if (next_scanline( &AET, y )) REGION_computeWAET( &AET, &WETE );
+
+ if (obj->numRects)
+ {
+ prev_band = REGION_Coalesce( obj, prev_band, cur_band );
+ cur_band = obj->numRects;
}
}
}
- assert( pos == nb_points );
+ assert( obj->numRects <= nb_points / 2 );
+
+ if (obj->numRects)
+ {
+ obj->extents.left = INT_MAX;
+ obj->extents.right = INT_MIN;
+ obj->extents.top = obj->rects[0].top;
+ obj->extents.bottom = obj->rects[obj->numRects-1].bottom;
+ for (i = 0; i < obj->numRects; i++)
+ {
+ obj->extents.left = min( obj->extents.left, obj->rects[i].left );
+ obj->extents.right = max( obj->extents.right, obj->rects[i].right );
+ }
+ }
+ REGION_compact( obj );
- if (!(obj = REGION_PtsToRegion( points, pos ))) goto done;
if (!(hrgn = alloc_gdi_handle( obj, OBJ_REGION, ®ion_funcs )))
free_region( obj );
done:
REGION_FreeStorage(SLLBlock.next);
- if (points != buffer) HeapFree( GetProcessHeap(), 0, points );
HeapFree( GetProcessHeap(), 0, pETEs );
return hrgn;
}
More information about the wine-cvs
mailing list