Skip to content

Commit 20ba4a9

Browse files
hughbeakoeplinger
authored andcommitted
Fix some region transform bugs (mono#526)
* Fix some region transform bugs * Fix checking of infinite regions and their scans Fixes mono#507 Fixes mono#438 Fixes mono#529 Fixes mono#528 Fixes mono#527
1 parent fe8e0bf commit 20ba4a9

File tree

2 files changed

+227
-125
lines changed

2 files changed

+227
-125
lines changed

src/region.c

Lines changed: 45 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -320,10 +320,16 @@ gdip_is_region_empty (const GpRegion *region, BOOL allowNegative)
320320
static BOOL
321321
gdip_is_rect_infinite (const GpRectF *rect)
322322
{
323-
return (rect && (rect->X == REGION_INFINITE_POSITION) &&
324-
(rect->Y == REGION_INFINITE_POSITION) &&
325-
(rect->Width == REGION_INFINITE_LENGTH) &&
326-
(rect->Height == REGION_INFINITE_LENGTH));
323+
if (!rect)
324+
return FALSE;
325+
326+
if (gdip_is_rectF_empty (rect, /* allowNegative */ TRUE))
327+
return FALSE;
328+
329+
if (rect->Width >= REGION_INFINITE_LENGTH || rect->Height >= REGION_INFINITE_LENGTH)
330+
return TRUE;
331+
332+
return FALSE;
327333
}
328334

329335
BOOL
@@ -2039,18 +2045,17 @@ GdipGetRegionScans (GpRegion *region, GpRectF* rects, INT* count, GpMatrix* matr
20392045

20402046
if (gdip_is_region_empty (work, /* allowNegative */ TRUE)) {
20412047
*count = 0;
2048+
} else if (gdip_is_InfiniteRegion (work)) {
2049+
if (rects) {
2050+
rects->X = REGION_INFINITE_POSITION;
2051+
rects->Y = REGION_INFINITE_POSITION;
2052+
rects->Width = REGION_INFINITE_LENGTH;
2053+
rects->Height = REGION_INFINITE_LENGTH;
2054+
}
2055+
2056+
*count = 1;
20422057
} else {
20432058
switch (region->type) {
2044-
case RegionTypeInfinite:
2045-
if (rects) {
2046-
rects->X = REGION_INFINITE_POSITION;
2047-
rects->Y = REGION_INFINITE_POSITION;
2048-
rects->Width = REGION_INFINITE_LENGTH;
2049-
rects->Height = REGION_INFINITE_LENGTH;
2050-
}
2051-
2052-
*count = 1;
2053-
break;
20542059
case RegionTypeRect:
20552060
if (rects) {
20562061
for (int i = 0; i < work->cnt; i++) {
@@ -2208,10 +2213,8 @@ GdipTranslateRegion (GpRegion *region, float dx, float dy)
22082213
if (!region)
22092214
return InvalidParameter;
22102215

2211-
/* can't transforman infinite region to anything else than an infinite region
2212-
* (even if you scale it by half it's still infinite ;-) see unit tests
2213-
*/
2214-
if (gdip_is_InfiniteRegion (region))
2216+
// Infinite regions cannot be transformed.
2217+
if (region->type == RegionTypeInfinite)
22152218
return Ok;
22162219

22172220
switch (region->type) {
@@ -2251,18 +2254,14 @@ GdipTranslateRegionI (GpRegion *region, int dx, int dy)
22512254
static GpStatus
22522255
ScaleRegion (GpRegion *region, float sx, float sy)
22532256
{
2254-
if (!region)
2255-
return InvalidParameter;
2257+
g_assert (region);
2258+
g_assert (region->type == RegionTypeRect && region->rects);
22562259

2257-
if ((region->type == RegionTypeRect) && region->rects) {
2258-
int i;
2259-
GpRectF *rect;
2260-
for (i = 0, rect = region->rects ; i < region->cnt; i++, rect++) {
2261-
rect->X *= sx;
2262-
rect->Y *= sy;
2263-
rect->Width *= sx;
2264-
rect->Height *= sy;
2265-
}
2260+
for (int i = 0; i < region->cnt; i++) {
2261+
region->rects[i].X *= sx;
2262+
region->rects[i].Y *= sy;
2263+
region->rects[i].Width *= sx;
2264+
region->rects[i].Height *= sy;
22662265
}
22672266

22682267
return Ok;
@@ -2276,43 +2275,36 @@ GdipTransformRegion (GpRegion *region, GpMatrix *matrix)
22762275
if (!region || !matrix)
22772276
return InvalidParameter;
22782277

2279-
/* no transformation to do on an empty region */
2280-
if ((region->cnt == 0) && (region->type == RegionTypeRect))
2278+
// Infinite and empty regions cannot be transformed.
2279+
if (region->type == RegionTypeInfinite || ((region->cnt == 0) && (region->type == RegionTypeRect)))
22812280
return Ok;
22822281

2283-
/* don't (possibly) convert to a bitmap if the matrix is empty (a no-op) */
2282+
// Nothing to do.
22842283
if (gdip_is_matrix_empty (matrix))
22852284
return Ok;
22862285

2287-
/* can't transforman infinite region to anything else than an infinite region
2288-
* (even if you scale it by half it's still infinite ;-) see unit tests
2289-
*/
2290-
if (gdip_is_InfiniteRegion (region))
2291-
return Ok;
2286+
BOOL isSimpleMatrix = (matrix->xy == 0) && (matrix->yx == 0);
2287+
BOOL matrixHasTranslate = (matrix->x0 != 0) || (matrix->y0 != 0);
2288+
BOOL matrixHasScale = (matrix->xx != 1) || (matrix->yy != 1);
22922289

22932290
/* try to avoid heavy stuff (e.g. conversion to path, invalidating
22942291
* bitmap...) if the transform is:
22952292
* - a translation + scale operations (for rectangle ebased region)
22962293
* - only to do a scale operation (for a rectangle based region)
22972294
* - only to do a simple translation (for both rectangular and bitmap based regions)
22982295
*/
2299-
if ((matrix->xy == 0.0f) && (matrix->yx == 0.0f)) {
2300-
BOOL s = (((matrix->xx != 1.0f) || (matrix->yy != 1.0f)) && (region->type == RegionTypeRect));
2301-
BOOL t = ((matrix->x0 != 0.0f) || (matrix->yx != 0.0f));
2302-
if (s) {
2303-
status = ScaleRegion (region,
2304-
gdip_matrix_get_x_scale (matrix),
2305-
gdip_matrix_get_y_scale (matrix));
2306-
}
2307-
if (t && (status == Ok)) {
2308-
status = GdipTranslateRegion (region,
2309-
gdip_matrix_get_x_translation (matrix),
2310-
gdip_matrix_get_y_translation (matrix));
2311-
}
2296+
if (region->type == RegionTypeRect) {
2297+
if (isSimpleMatrix) {
2298+
if (matrixHasScale)
2299+
ScaleRegion (region, matrix->xx, matrix->yy);
2300+
if (matrixHasTranslate)
2301+
GdipTranslateRegion (region, matrix->x0, matrix->y0);
23122302

2313-
/* return now if we could optimize the transform (to avoid bitmaps) */
2314-
if (t || s)
2315-
return status;
2303+
return Ok;
2304+
}
2305+
} else if (isSimpleMatrix && !matrixHasScale) {
2306+
GdipTranslateRegion (region, matrix->x0, matrix->y0);
2307+
return Ok;
23162308
}
23172309

23182310
/* most matrix operations would change the rectangles into path so we always preempt this */

0 commit comments

Comments
 (0)