Validate user data before passing it to PolyDraw.
The program in the bug requests to draw figures outrageously outside the DC's region after presumably, some uninitialized values happen as a result of a missing font. Native gdiplus seems to handle this gracefully so we probably also should.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=41617
Signed-off-by: David Kahurani k.kahurani@gmail.com
-- v7: gdiplus: Hook on optimized path drawing code gdiplus: Re-implement trace_path to avoid circular dependency gdiplus: Make get_region_hrgn public to gdiplus gdiplus: Clip polygons before drawing them gdiplus: Make get_graphis_device_bounds public to gdiplus gdiplus: Allow for writing nodes to an empty path points list
From: David Kahurani k.kahurani@gmail.com
This should allow us to construct a path based on points that are all unknown at the time of list creation
Signed-off-by: David Kahurani k.kahurani@gmail.com --- dlls/gdiplus/graphicspath.c | 103 +++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 44 deletions(-)
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index 24c2888cfe8..024e75ebcc8 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -75,10 +75,25 @@ static void free_path_list(path_list_node_t *node) * pointer on success * NULL on allocation problems */ -static path_list_node_t* add_path_list_node(path_list_node_t *node, REAL x, REAL y, BOOL type) +static path_list_node_t* add_path_list_node(path_list_node_t **node, REAL x, REAL y, BOOL type) { path_list_node_t *new;
+ if (!*node) + { + *node = calloc(1, sizeof(path_list_node_t)); + + if (!*node) + return NULL; + + (*node)->pt.X = x; + (*node)->pt.Y = y; + (*node)->type = type; + (*node)->next = NULL; + + return *node; + } + new = calloc(1, sizeof(path_list_node_t)); if(!new) return NULL; @@ -86,8 +101,8 @@ static path_list_node_t* add_path_list_node(path_list_node_t *node, REAL x, REAL new->pt.X = x; new->pt.Y = y; new->type = type; - new->next = node->next; - node->next = new; + new->next = (*node)->next; + (*node)->next = new;
return new; } @@ -207,7 +222,7 @@ static BOOL flatten_bezier(path_list_node_t *start, REAL x2, REAL y2, REAL x3, R } else /* add a middle point */ - if(!(node = add_path_list_node(start, mp[2].X, mp[2].Y, PathPointTypeLine))) + if(!(node = add_path_list_node(&start, mp[2].X, mp[2].Y, PathPointTypeLine))) { ret = FALSE; break; @@ -1383,7 +1398,7 @@ GpStatus WINGDIPAPI GdipFlattenPath(GpPath *path, GpMatrix* matrix, REAL flatnes
/* always add line points and start points */ if((type == PathPointTypeStart) || (type == PathPointTypeLine)){ - if(!add_path_list_node(node, pt.X, pt.Y, path->pathdata.Types[i])) + if(!add_path_list_node(&node, pt.X, pt.Y, path->pathdata.Types[i])) goto memout;
node = node->next; @@ -1407,7 +1422,7 @@ GpStatus WINGDIPAPI GdipFlattenPath(GpPath *path, GpMatrix* matrix, REAL flatnes start = node; /* add Bezier end point */ type = (path->pathdata.Types[i] & ~PathPointTypePathTypeMask) | PathPointTypeLine; - if(!add_path_list_node(node, pt.X, pt.Y, type)) + if(!add_path_list_node(&node, pt.X, pt.Y, type)) goto memout; node = node->next;
@@ -1873,7 +1888,7 @@ static void add_bevel_point(const GpPointF *endpoint, const GpPointF *nextpoint,
if (segment_length == 0.0) { - *last_point = add_path_list_node(*last_point, endpoint->X, + *last_point = add_path_list_node(last_point, endpoint->X, endpoint->Y, PathPointTypeLine); return; } @@ -1889,7 +1904,7 @@ static void add_bevel_point(const GpPointF *endpoint, const GpPointF *nextpoint, bevel_dy = -distance * segment_dx / segment_length; }
- *last_point = add_path_list_node(*last_point, endpoint->X + bevel_dx, + *last_point = add_path_list_node(last_point, endpoint->X + bevel_dx, endpoint->Y + bevel_dy, PathPointTypeLine); }
@@ -1914,7 +1929,7 @@ static void widen_joint(const GpPointF *p1, const GpPointF *p2, const GpPointF * float dy = (dy0*dy1*(dy0-dy1) + dx0*dx0*dy1 - dx1*dx1*dy0)/det; if (dx*dx + dy*dy < pen->miterlimit*pen->miterlimit * distance*distance) { - *last_point = add_path_list_node(*last_point, p2->X + dx, + *last_point = add_path_list_node(last_point, p2->X + dx, p2->Y + dy, PathPointTypeLine); break; } @@ -1977,11 +1992,11 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint, }
if (add_first_points) - *last_point = add_path_list_node(*last_point, endpoint->X - extend_dx + bevel_dx, + *last_point = add_path_list_node(last_point, endpoint->X - extend_dx + bevel_dx, endpoint->Y - extend_dy + bevel_dy, PathPointTypeLine);
if (add_last_point) - *last_point = add_path_list_node(*last_point, endpoint->X - extend_dx - bevel_dx, + *last_point = add_path_list_node(last_point, endpoint->X - extend_dx - bevel_dx, endpoint->Y - extend_dy - bevel_dy, PathPointTypeLine); break; } @@ -2003,27 +2018,27 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint, dy2 = dy * control_point_distance;
/* first 90-degree arc */ - *last_point = add_path_list_node(*last_point, endpoint->X + dy, + *last_point = add_path_list_node(last_point, endpoint->X + dy, endpoint->Y - dx, PathPointTypeLine);
- *last_point = add_path_list_node(*last_point, endpoint->X + dy + dx2, + *last_point = add_path_list_node(last_point, endpoint->X + dy + dx2, endpoint->Y - dx + dy2, PathPointTypeBezier);
- *last_point = add_path_list_node(*last_point, endpoint->X + dx + dy2, + *last_point = add_path_list_node(last_point, endpoint->X + dx + dy2, endpoint->Y + dy - dx2, PathPointTypeBezier);
/* midpoint */ - *last_point = add_path_list_node(*last_point, endpoint->X + dx, + *last_point = add_path_list_node(last_point, endpoint->X + dx, endpoint->Y + dy, PathPointTypeBezier);
/* second 90-degree arc */ - *last_point = add_path_list_node(*last_point, endpoint->X + dx - dy2, + *last_point = add_path_list_node(last_point, endpoint->X + dx - dy2, endpoint->Y + dy + dx2, PathPointTypeBezier);
- *last_point = add_path_list_node(*last_point, endpoint->X - dy + dx2, + *last_point = add_path_list_node(last_point, endpoint->X - dy + dx2, endpoint->Y + dx + dy2, PathPointTypeBezier);
- *last_point = add_path_list_node(*last_point, endpoint->X - dy, + *last_point = add_path_list_node(last_point, endpoint->X - dy, endpoint->Y + dx, PathPointTypeBezier); } else if (add_last_point) @@ -2044,7 +2059,7 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint, if (add_first_points) { add_bevel_point(endpoint, nextpoint, pen_width, 1, last_point);
- *last_point = add_path_list_node(*last_point, endpoint->X - dx, + *last_point = add_path_list_node(last_point, endpoint->X - dx, endpoint->Y - dy, PathPointTypeLine); } if (add_first_points || add_last_point) @@ -2085,13 +2100,13 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, perp_dx = -distance * segment_dy / segment_length; perp_dy = distance * segment_dx / segment_length;
- *last_point = add_path_list_node(*last_point, endpoint->X - par_dx - perp_dx, + *last_point = add_path_list_node(last_point, endpoint->X - par_dx - perp_dx, endpoint->Y - par_dy - perp_dy, PathPointTypeStart); - *last_point = add_path_list_node(*last_point, endpoint->X - par_dx + perp_dx, + *last_point = add_path_list_node(last_point, endpoint->X - par_dx + perp_dx, endpoint->Y - par_dy + perp_dy, PathPointTypeLine); - *last_point = add_path_list_node(*last_point, endpoint->X + par_dx + perp_dx, + *last_point = add_path_list_node(last_point, endpoint->X + par_dx + perp_dx, endpoint->Y + par_dy + perp_dy, PathPointTypeLine); - *last_point = add_path_list_node(*last_point, endpoint->X + par_dx - perp_dx, + *last_point = add_path_list_node(last_point, endpoint->X + par_dx - perp_dx, endpoint->Y + par_dy - perp_dy, PathPointTypeLine); break; } @@ -2110,39 +2125,39 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, dy2 = dy * control_point_distance;
/* starting point */ - *last_point = add_path_list_node(*last_point, endpoint->X + dy, + *last_point = add_path_list_node(last_point, endpoint->X + dy, endpoint->Y - dx, PathPointTypeStart);
/* first 90-degree arc */ - *last_point = add_path_list_node(*last_point, endpoint->X + dy + dx2, + *last_point = add_path_list_node(last_point, endpoint->X + dy + dx2, endpoint->Y - dx + dy2, PathPointTypeBezier); - *last_point = add_path_list_node(*last_point, endpoint->X + dx + dy2, + *last_point = add_path_list_node(last_point, endpoint->X + dx + dy2, endpoint->Y + dy - dx2, PathPointTypeBezier); - *last_point = add_path_list_node(*last_point, endpoint->X + dx, + *last_point = add_path_list_node(last_point, endpoint->X + dx, endpoint->Y + dy, PathPointTypeBezier);
/* second 90-degree arc */ - *last_point = add_path_list_node(*last_point, endpoint->X + dx - dy2, + *last_point = add_path_list_node(last_point, endpoint->X + dx - dy2, endpoint->Y + dy + dx2, PathPointTypeBezier); - *last_point = add_path_list_node(*last_point, endpoint->X - dy + dx2, + *last_point = add_path_list_node(last_point, endpoint->X - dy + dx2, endpoint->Y + dx + dy2, PathPointTypeBezier); - *last_point = add_path_list_node(*last_point, endpoint->X - dy, + *last_point = add_path_list_node(last_point, endpoint->X - dy, endpoint->Y + dx, PathPointTypeBezier);
/* third 90-degree arc */ - *last_point = add_path_list_node(*last_point, endpoint->X - dy - dx2, + *last_point = add_path_list_node(last_point, endpoint->X - dy - dx2, endpoint->Y + dx - dy2, PathPointTypeBezier); - *last_point = add_path_list_node(*last_point, endpoint->X - dx - dy2, + *last_point = add_path_list_node(last_point, endpoint->X - dx - dy2, endpoint->Y - dy + dx2, PathPointTypeBezier); - *last_point = add_path_list_node(*last_point, endpoint->X - dx, + *last_point = add_path_list_node(last_point, endpoint->X - dx, endpoint->Y - dy, PathPointTypeBezier);
/* fourth 90-degree arc */ - *last_point = add_path_list_node(*last_point, endpoint->X - dx + dy2, + *last_point = add_path_list_node(last_point, endpoint->X - dx + dy2, endpoint->Y - dy - dx2, PathPointTypeBezier); - *last_point = add_path_list_node(*last_point, endpoint->X + dy - dx2, + *last_point = add_path_list_node(last_point, endpoint->X + dy - dx2, endpoint->Y - dx - dy2, PathPointTypeBezier); - *last_point = add_path_list_node(*last_point, endpoint->X + dy, + *last_point = add_path_list_node(last_point, endpoint->X + dy, endpoint->Y - dx, PathPointTypeBezier);
break; @@ -2161,13 +2176,13 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, perp_dx = -pen_width * segment_dy / segment_length; perp_dy = pen_width * segment_dx / segment_length;
- *last_point = add_path_list_node(*last_point, endpoint->X + par_dx, + *last_point = add_path_list_node(last_point, endpoint->X + par_dx, endpoint->Y + par_dy, PathPointTypeStart); - *last_point = add_path_list_node(*last_point, endpoint->X - perp_dx, + *last_point = add_path_list_node(last_point, endpoint->X - perp_dx, endpoint->Y - perp_dy, PathPointTypeLine); - *last_point = add_path_list_node(*last_point, endpoint->X - par_dx, + *last_point = add_path_list_node(last_point, endpoint->X - par_dx, endpoint->Y - par_dy, PathPointTypeLine); - *last_point = add_path_list_node(*last_point, endpoint->X + perp_dx, + *last_point = add_path_list_node(last_point, endpoint->X + perp_dx, endpoint->Y + perp_dy, PathPointTypeLine); break; } @@ -2181,11 +2196,11 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, REAL perp_dx = -par_dy; REAL perp_dy = par_dx;
- *last_point = add_path_list_node(*last_point, endpoint->X, + *last_point = add_path_list_node(last_point, endpoint->X, endpoint->Y, PathPointTypeStart); - *last_point = add_path_list_node(*last_point, endpoint->X + SQRT3 * par_dx - perp_dx, + *last_point = add_path_list_node(last_point, endpoint->X + SQRT3 * par_dx - perp_dx, endpoint->Y + SQRT3 * par_dy - perp_dy, PathPointTypeLine); - *last_point = add_path_list_node(*last_point, endpoint->X + SQRT3 * par_dx + perp_dx, + *last_point = add_path_list_node(last_point, endpoint->X + SQRT3 * par_dx + perp_dx, endpoint->Y + SQRT3 * par_dy + perp_dy, PathPointTypeLine); break; } @@ -2245,7 +2260,7 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, /* rotation of CustomCap according to line */ perp_dx = custom->pathdata.Points[i].X * cosa + (custom->pathdata.Points[i].Y - 1.0) * sina; perp_dy = custom->pathdata.Points[i].X * sina - (custom->pathdata.Points[i].Y - 1.0) * cosa; - *last_point = add_path_list_node(*last_point, posx + perp_dx, + *last_point = add_path_list_node(last_point, posx + perp_dx, posy + perp_dy, custom->pathdata.Types[i]); } }
From: David Kahurani k.kahurani@gmail.com
This is required so as to be able to use it in the graphicspath module
Signed-off-by: David Kahurani k.kahurani@gmail.com --- dlls/gdiplus/gdiplus_private.h | 1 + dlls/gdiplus/graphics.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 6f7e72124c2..617008dd7c7 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -66,6 +66,7 @@ extern GpStatus gdi_transform_acquire(GpGraphics *graphics); extern GpStatus gdi_transform_release(GpGraphics *graphics); extern GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space, GpCoordinateSpace src_space, GpMatrix *matrix); +extern GpStatus get_graphics_device_bounds(GpGraphics *, GpRectF *); extern GpStatus gdip_transform_points(GpGraphics *graphics, GpCoordinateSpace dst_space, GpCoordinateSpace src_space, GpPointF *points, INT count); void transform_properties(GpGraphics *, GDIPCONST GpMatrix *, BOOL, REAL *, REAL *, REAL *); diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 5101378d0e1..33ce2f3d036 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -2150,7 +2150,7 @@ static GpStatus restore_container(GpGraphics* graphics, return Ok; }
-static GpStatus get_graphics_device_bounds(GpGraphics* graphics, GpRectF* rect) +GpStatus get_graphics_device_bounds(GpGraphics* graphics, GpRectF* rect) { RECT wnd_rect; GpStatus stat=Ok;
From: David Kahurani k.kahurani@gmail.com
This should reduce the load on GDI when an application is trying to draw to regions outside of selected DC's region
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=41617 Signed-off-by: David Kahurani k.kahurani@gmail.com --- dlls/gdiplus/gdiplus_private.h | 1 + dlls/gdiplus/graphicspath.c | 158 +++++++++++++++++++++++++++++++++ dlls/gdiplus/region.c | 40 +++++++-- 3 files changed, 190 insertions(+), 9 deletions(-)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 617008dd7c7..7f7307d7482 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -136,6 +136,7 @@ extern DWORD write_region_data(const GpRegion *region, void *data); extern DWORD write_path_data(GpPath *path, void *data);
extern GpStatus trace_path(GpGraphics *graphics, GpPath *path); +extern GpStatus clip_path(GpGraphics *graphics, GpPath *in, GpPath *out);
typedef struct region_element region_element; extern void delete_element(region_element *element); diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index 024e75ebcc8..13e19c225f1 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -2843,3 +2843,161 @@ DWORD write_path_data(GpPath *path, void *data) memset(types + i, 0, ((path->pathdata.Count + 3) & ~3) - path->pathdata.Count); return size; } + +GpStatus clip_path(GpGraphics *graphics, GpPath *in, GpPath *out) +{ + RectF rect; + int i; + path_list_node_t *list, *pos = NULL; + + get_graphics_device_bounds(graphics, &rect); + + for (i = 1; i < in->pathdata.Count - 1; i++) + { + RectF bounds; + + switch(in->pathdata.Types[i] & PathPointTypePathTypeMask) + { + case PathPointTypeBezier: + { + int j, leftmost = in->pathdata.Points[i - 1].X, rightmost = in->pathdata.Points[i - 1].X, + top = in->pathdata.Points[i - 1].Y, bottom = in->pathdata.Points[i - 1].Y; + + for (j = 0; j < 3; j++) + { + if (in->pathdata.Points[i + j].X < leftmost) + leftmost = in->pathdata.Points[i + j].X; + + if (in->pathdata.Points[i + j].X > rightmost) + rightmost = in->pathdata.Points[i + j].X; + + if (in->pathdata.Points[i + j].Y < top) + top = in->pathdata.Points[i + j].Y; + + if (in->pathdata.Points[i + j].Y > bottom) + bottom = in->pathdata.Points[i + j].Y; + } + + set_rect(&bounds, leftmost, top, rightmost - leftmost, bottom - top); + + /* properties of intersect rectangle */ + leftmost = (rect.X < bounds.X) ? bounds.X : rect.X; + top = (rect.Y < bounds.Y) ? bounds.Y : rect.Y; + + rightmost = (rect.X + rect.Width < bounds.X + bounds.Width) + ? rect.X + rect.Width : bounds.X + bounds.Width; + bottom = (rect.Y + rect.Height < bounds.Y + bounds.Height) + ? rect.Y + rect.Height : bounds.Y + bounds.Height; + + if (leftmost < rightmost && top < bottom) + { + /* restore the immediate previous point, if skipped, as it is needed to connect to the rest of the points */ + if (pos && pos->pt.X != in->pathdata.Points[i - 1].X && pos->pt.Y != in->pathdata.Points[i - 1].Y) + add_path_list_node(&list, in->pathdata.Points[i - 1].X, in->pathdata.Points[i - 1].Y, + PathPointTypeLine); + for(j = 0; j < 3; j++) + pos = add_path_list_node(&list, in->pathdata.Points[i + j].X, in->pathdata.Points[i + j].Y, + PathPointTypeBezier); + } + + i += 2; + break; + } + case PathPointTypeLine: + { + GpPointF tmp[4]; + + int j, leftmost = in->pathdata.Points[i - 1].X, rightmost = in->pathdata.Points[i - 1].X, + top = in->pathdata.Points[i - 1].Y, bottom = in->pathdata.Points[i - 1].Y; + + /* widen the path by a width of 10 */ + if (in->pathdata.Points[i - 1].Y != in->pathdata.Points[i].Y) + { + tmp[0].X = in->pathdata.Points[i - 1].X + 5; + tmp[0].Y = in->pathdata.Points[i - 1].Y; + tmp[1].X = in->pathdata.Points[i - 1].X - 5; + tmp[1].Y = in->pathdata.Points[i - 1].Y; + + tmp[2].X = in->pathdata.Points[i].X + 5; + tmp[2].Y = in->pathdata.Points[i].Y; + tmp[3].X = in->pathdata.Points[i].X - 5; + tmp[3].Y = in->pathdata.Points[i].Y; + } + else + { + tmp[0].X = in->pathdata.Points[i - 1].X; + tmp[0].Y = in->pathdata.Points[i - 1].Y + 5; + tmp[1].X = in->pathdata.Points[i - 1].X; + tmp[1].Y = in->pathdata.Points[i - 1].Y - 5; + + tmp[2].X = in->pathdata.Points[i].X; + tmp[2].Y = in->pathdata.Points[i].Y + 5; + tmp[3].X = in->pathdata.Points[i].X; + tmp[3].Y = in->pathdata.Points[i].Y - 5; + } + + for (j = 0; j < 4; j++) + { + if (tmp[j].X < leftmost) + leftmost = tmp[j].X; + + if (tmp[j].X > rightmost) + rightmost = tmp[j].X; + + if (tmp[j].Y < top) + top = tmp[j].Y; + + if (tmp[j].Y > bottom) + bottom = tmp[j].Y; + } + + set_rect(&bounds, leftmost, top, rightmost - leftmost, bottom - top); + + leftmost = (rect.X < bounds.X) ? bounds.X : rect.X; + top = (rect.Y < bounds.Y) ? bounds.Y : rect.Y; + + rightmost = (rect.X + rect.Width < bounds.X + bounds.Width) + ? rect.X + rect.Width : bounds.X + bounds.Width; + bottom = (rect.Y + rect.Height < bounds.Y + bounds.Height) + ? rect.Y + rect.Height : bounds.Y + bounds.Height; + + if (leftmost < rightmost && top < bottom) + { + if (pos && pos->pt.X != in->pathdata.Points[i - 1].X && pos->pt.Y != in->pathdata.Points[i - 1].Y) + add_path_list_node(&list, in->pathdata.Points[i - 1].X, in->pathdata.Points[i - 1].Y, + PathPointTypeLine); + + pos = add_path_list_node(&list, in->pathdata.Points[i].X, in->pathdata.Points[i].Y, + PathPointTypeLine); + } + } + case PathPointTypeStart: + add_path_list_node(&list, in->pathdata.Points[i].X, in->pathdata.Points[i].Y, + PathPointTypeBezier); + break; + + default: + ERR("Bad point type \n"); + } + } + + i = path_list_count(list); + + if (!lengthen_path(out, i)) + { + free_path_list(list); + return OutOfMemory; + } + + out->pathdata.Count = i; + + pos = list; + for (i = 0; i < out->pathdata.Count; i++){ + out->pathdata.Points[i] = pos->pt; + out->pathdata.Types[i] = pos->type; + pos = pos->next; + } + + free_path_list(list); + return Ok; +} diff --git a/dlls/gdiplus/region.c b/dlls/gdiplus/region.c index 058f659561b..3d066efa44c 100644 --- a/dlls/gdiplus/region.c +++ b/dlls/gdiplus/region.c @@ -987,12 +987,13 @@ GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed) return Ok; }
-static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn) +static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, BOOL clip, HRGN *hrgn) { HDC new_hdc=NULL; GpGraphics *new_graphics=NULL; GpStatus stat; INT save_state; + GpPath *clippedpath;
if (!path->pathdata.Count) /* PathToRegion doesn't support empty paths */ { @@ -1029,7 +1030,28 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn)
gdi_transform_acquire(graphics);
- stat = trace_path(graphics, path); + if (clip) + { + GpFillMode fillmode; + + GdipGetPathFillMode(path, &fillmode); + stat = GdipCreatePath(fillmode, &clippedpath); + if (stat != Ok) + return stat; + + stat = clip_path(graphics, path, clippedpath); + + if (stat != Ok) + { + GdipDeletePath(clippedpath); + return stat; + } + + stat = trace_path(graphics, clippedpath); + } + else + stat = trace_path(graphics, path); + if (stat == Ok) { *hrgn = PathToRegion(graphics->hdc); @@ -1051,7 +1073,7 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn) return stat; }
-static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *graphics, HRGN *hrgn) +static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *graphics, BOOL clip, HRGN *hrgn) { switch (element->type) { @@ -1062,7 +1084,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap *hrgn = CreateRectRgn(0, 0, 0, 0); return *hrgn ? Ok : OutOfMemory; case RegionDataPath: - return get_path_hrgn(element->elementdata.path, graphics, hrgn); + return get_path_hrgn(element->elementdata.path, graphics, clip, hrgn); case RegionDataRect: { GpPath* path; @@ -1075,7 +1097,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap stat = GdipAddPathRectangle(path, rc->X, rc->Y, rc->Width, rc->Height);
if (stat == Ok) - stat = get_path_hrgn(path, graphics, hrgn); + stat = get_path_hrgn(path, graphics, clip, hrgn);
GdipDeletePath(path);
@@ -1091,7 +1113,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap GpStatus stat; int ret;
- stat = get_region_hrgn(element->elementdata.combine.left, graphics, &left); + stat = get_region_hrgn(element->elementdata.combine.left, graphics, clip, &left); if (stat != Ok) { *hrgn = NULL; @@ -1104,7 +1126,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap switch (element->type) { case CombineModeIntersect: - return get_region_hrgn(element->elementdata.combine.right, graphics, hrgn); + return get_region_hrgn(element->elementdata.combine.right, graphics, clip, hrgn); case CombineModeXor: case CombineModeExclude: left = CreateRectRgn(-(1 << 22), -(1 << 22), 1 << 22, 1 << 22); break; @@ -1114,7 +1136,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap } }
- stat = get_region_hrgn(element->elementdata.combine.right, graphics, &right); + stat = get_region_hrgn(element->elementdata.combine.right, graphics, clip, &right); if (stat != Ok) { DeleteObject(left); @@ -1190,7 +1212,7 @@ GpStatus WINGDIPAPI GdipGetRegionHRgn(GpRegion *region, GpGraphics *graphics, HR if (!region || !hrgn) return InvalidParameter;
- return get_region_hrgn(®ion->node, graphics, hrgn); + return get_region_hrgn(®ion->node, graphics, FALSE, hrgn); }
GpStatus WINGDIPAPI GdipIsEmptyRegion(GpRegion *region, GpGraphics *graphics, BOOL *res)
From: David Kahurani k.kahurani@gmail.com
Now that we added a flag to get_region_hrgn, we need to use get_region_hrgn directly instead of through GdipGetRegionHRgn inorder to access this flag
Signed-off-by: David Kahurani k.kahurani@gmail.com --- dlls/gdiplus/gdiplus_private.h | 1 + dlls/gdiplus/region.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 7f7307d7482..140c6c68dfb 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -140,6 +140,7 @@ extern GpStatus clip_path(GpGraphics *graphics, GpPath *in, GpPath *out);
typedef struct region_element region_element; extern void delete_element(region_element *element); +extern GpStatus get_region_hrgn(region_element *element, GpGraphics *graphics, BOOL clip, HRGN *hrgn);
extern GpStatus get_hatch_data(GpHatchStyle hatchstyle, const unsigned char **result);
diff --git a/dlls/gdiplus/region.c b/dlls/gdiplus/region.c index 3d066efa44c..76ef84e4aca 100644 --- a/dlls/gdiplus/region.c +++ b/dlls/gdiplus/region.c @@ -1073,7 +1073,7 @@ static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, BOOL clip, HRG return stat; }
-static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *graphics, BOOL clip, HRGN *hrgn) +GpStatus get_region_hrgn(struct region_element *element, GpGraphics *graphics, BOOL clip, HRGN *hrgn) { switch (element->type) {
From: David Kahurani k.kahurani@gmail.com
trace_path calls poly_draw which will in turn call SOFTWARE_GdipFillPath which will again call trace_path leading to a circular dependency
Signed-off-by: David Kahurani k.kahurani@gmail.com --- dlls/gdiplus/graphics.c | 47 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 33ce2f3d036..9e4897ecdb4 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -2047,13 +2047,52 @@ end:
GpStatus trace_path(GpGraphics *graphics, GpPath *path) { - GpStatus result; + POINT *pti = malloc(path->pathdata.Count * sizeof(POINT)); + BYTE *tp = malloc(path->pathdata.Count); + GpPointF *ptcopy = malloc(path->pathdata.Count * sizeof(GpPointF)); + INT i; + GpStatus status = GenericError; + + if(!path->pathdata.Count){ + status = Ok; + goto end; + } + if(!pti || !tp || !ptcopy){ + status = OutOfMemory; + goto end; + } + + for(i = 1; i < path->pathdata.Count; i++){ + if((path->pathdata.Types[i] & PathPointTypePathTypeMask) == PathPointTypeBezier){ + if((i + 2 >= path->pathdata.Count) || !(path->pathdata.Types[i + 1] & PathPointTypeBezier) + || !(path->pathdata.Types[i + 2] & PathPointTypeBezier)){ + ERR("Bad bezier points\n"); + goto end; + } + i += 2; + } + } + + memcpy(ptcopy, path->pathdata.Points, path->pathdata.Count * sizeof(GpPointF)); + gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptcopy, path->pathdata.Count); + round_points(pti, ptcopy, path->pathdata.Count); + + for(i = 0; i < path->pathdata.Count; i++){ + tp[i] = convert_path_point_type(path->pathdata.Types[i]); + }
BeginPath(graphics->hdc); - result = draw_poly(graphics, NULL, path->pathdata.Points, - path->pathdata.Types, path->pathdata.Count, FALSE); + PolyDraw(graphics->hdc, pti, tp, path->pathdata.Count); EndPath(graphics->hdc); - return result; + + status = Ok; + +end: + free(pti); + free(ptcopy); + free(tp); + + return status; }
typedef enum GraphicsContainerType {
From: David Kahurani k.kahurani@gmail.com
Signed-off-by: David Kahurani k.kahurani@gmail.com --- dlls/gdiplus/graphics.c | 103 ++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 58 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 9e4897ecdb4..70a4bf190a7 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -50,6 +50,7 @@ static GpStatus draw_driver_string(GpGraphics *graphics, GDIPCONST UINT16 *text, GDIPCONST GpBrush *brush, GDIPCONST PointF *positions, INT flags, GDIPCONST GpMatrix *matrix);
+static GpStatus SOFTWARE_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *path); /* Converts from gdiplus path point type to gdi path point type. */ static BYTE convert_path_point_type(BYTE type) { @@ -1918,28 +1919,28 @@ static void shorten_bezier_amt(GpPointF * pt, REAL amt, BOOL rev) }
/* Draws a combination of bezier curves and lines between points. */ -static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF * pt, - GDIPCONST BYTE * types, INT count, BOOL caps) +static GpStatus draw_path(GpGraphics *graphics, GpPen *pen, GpPath *path, BOOL caps) { - POINT *pti = malloc(count * sizeof(POINT)); - BYTE *tp = malloc(count); - GpPointF *ptcopy = malloc(count * sizeof(GpPointF)); - INT i, j; + GpPath *clonedpath; + INT i, count = path->pathdata.Count; GpStatus status = GenericError;
- if(!count){ + if(!path->pathdata.Count){ status = Ok; goto end; } - if(!pti || !tp || !ptcopy){ + + GdipClonePath(path, &clonedpath); + + if(!clonedpath){ status = OutOfMemory; goto end; }
- for(i = 1; i < count; i++){ - if((types[i] & PathPointTypePathTypeMask) == PathPointTypeBezier){ - if((i + 2 >= count) || !(types[i + 1] & PathPointTypeBezier) - || !(types[i + 2] & PathPointTypeBezier)){ + for(i = 1; i < clonedpath->pathdata.Count; i++){ + if((clonedpath->pathdata.Types[i] & PathPointTypePathTypeMask) == PathPointTypeBezier){ + if((i + 2 >= count) || !(clonedpath->pathdata.Types[i + 1] & PathPointTypeBezier) + || !(clonedpath->pathdata.Types[i + 2] & PathPointTypeBezier)){ ERR("Bad bezier points\n"); goto end; } @@ -1947,38 +1948,36 @@ static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF * } }
- memcpy(ptcopy, pt, count * sizeof(GpPointF)); - /* If we are drawing caps, go through the points and adjust them accordingly, * and draw the caps. */ if(caps){ - switch(types[count - 1] & PathPointTypePathTypeMask){ + switch(clonedpath->pathdata.Types[count - 1] & PathPointTypePathTypeMask){ case PathPointTypeBezier: if(pen->endcap == LineCapArrowAnchor) - shorten_bezier_amt(&ptcopy[count - 4], pen->width, FALSE); + shorten_bezier_amt(&clonedpath->pathdata.Points[count - 4], pen->width, FALSE); else if((pen->endcap == LineCapCustom) && pen->customend) - shorten_bezier_amt(&ptcopy[count - 4], + shorten_bezier_amt(&clonedpath->pathdata.Points[count - 4], pen->width * pen->customend->inset, FALSE);
draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->endcap, pen->width, pen->customend, - pt[count - 1].X - (ptcopy[count - 1].X - ptcopy[count - 2].X), - pt[count - 1].Y - (ptcopy[count - 1].Y - ptcopy[count - 2].Y), - pt[count - 1].X, pt[count - 1].Y); + path->pathdata.Points[count - 1].X - (clonedpath->pathdata.Points[count - 1].X - clonedpath->pathdata.Points[count - 2].X), + path->pathdata.Points[count - 1].Y - (clonedpath->pathdata.Points[count - 1].Y - clonedpath->pathdata.Points[count - 2].Y), + path->pathdata.Points[count - 1].X, path->pathdata.Points[count - 1].Y);
break; case PathPointTypeLine: if(pen->endcap == LineCapArrowAnchor) - shorten_line_amt(ptcopy[count - 2].X, ptcopy[count - 2].Y, - &ptcopy[count - 1].X, &ptcopy[count - 1].Y, + shorten_line_amt(clonedpath->pathdata.Points[count - 2].X, clonedpath->pathdata.Points[count - 2].Y, + &clonedpath->pathdata.Points[count - 1].X, &clonedpath->pathdata.Points[count - 1].Y, pen->width); else if((pen->endcap == LineCapCustom) && pen->customend) - shorten_line_amt(ptcopy[count - 2].X, ptcopy[count - 2].Y, - &ptcopy[count - 1].X, &ptcopy[count - 1].Y, + shorten_line_amt(clonedpath->pathdata.Points[count - 2].X, clonedpath->pathdata.Points[count - 2].Y, + &clonedpath->pathdata.Points[count - 1].X, &clonedpath->pathdata.Points[count - 1].Y, pen->customend->inset * pen->width);
draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->endcap, pen->width, pen->customend, - pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X, - pt[count - 1].Y); + path->pathdata.Points[count - 2].X, path->pathdata.Points[count - 2].Y, path->pathdata.Points[count - 1].X, + path->pathdata.Points[count - 1].Y);
break; default: @@ -1987,36 +1986,36 @@ static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF * }
/* Find start of points */ - for(j = 1; j < count && ((types[j] & PathPointTypePathTypeMask) - == PathPointTypeStart); j++); + for(i = 1; i < count && ((clonedpath->pathdata.Types[i] & PathPointTypePathTypeMask) + == PathPointTypeStart); i++);
- switch(types[j] & PathPointTypePathTypeMask){ + switch(clonedpath->pathdata.Types[i] & PathPointTypePathTypeMask){ case PathPointTypeBezier: if(pen->startcap == LineCapArrowAnchor) - shorten_bezier_amt(&ptcopy[j - 1], pen->width, TRUE); + shorten_bezier_amt(&clonedpath->pathdata.Points[i - 1], pen->width, TRUE); else if((pen->startcap == LineCapCustom) && pen->customstart) - shorten_bezier_amt(&ptcopy[j - 1], + shorten_bezier_amt(&clonedpath->pathdata.Points[i - 1], pen->width * pen->customstart->inset, TRUE);
draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->startcap, pen->width, pen->customstart, - pt[j - 1].X - (ptcopy[j - 1].X - ptcopy[j].X), - pt[j - 1].Y - (ptcopy[j - 1].Y - ptcopy[j].Y), - pt[j - 1].X, pt[j - 1].Y); + path->pathdata.Points[i - 1].X - (clonedpath->pathdata.Points[i - 1].X - clonedpath->pathdata.Points[i].X), + path->pathdata.Points[i - 1].Y - (clonedpath->pathdata.Points[i - 1].Y - clonedpath->pathdata.Points[i].Y), + path->pathdata.Points[i - 1].X, path->pathdata.Points[i - 1].Y);
break; case PathPointTypeLine: if(pen->startcap == LineCapArrowAnchor) - shorten_line_amt(ptcopy[j].X, ptcopy[j].Y, - &ptcopy[j - 1].X, &ptcopy[j - 1].Y, + shorten_line_amt(clonedpath->pathdata.Points[i].X, clonedpath->pathdata.Points[i].Y, + &clonedpath->pathdata.Points[i - 1].X, &clonedpath->pathdata.Points[i - 1].Y, pen->width); else if((pen->startcap == LineCapCustom) && pen->customstart) - shorten_line_amt(ptcopy[j].X, ptcopy[j].Y, - &ptcopy[j - 1].X, &ptcopy[j - 1].Y, + shorten_line_amt(clonedpath->pathdata.Points[i].X, clonedpath->pathdata.Points[i].Y, + &clonedpath->pathdata.Points[i - 1].X, &clonedpath->pathdata.Points[i - 1].Y, pen->customstart->inset * pen->width);
draw_cap(graphics, get_gdi_brush_color(pen->brush), pen->startcap, pen->width, pen->customstart, - pt[j].X, pt[j].Y, pt[j - 1].X, - pt[j - 1].Y); + path->pathdata.Points[i].X, path->pathdata.Points[i].Y, path->pathdata.Points[i - 1].X, + path->pathdata.Points[i - 1].Y);
break; default: @@ -2025,23 +2024,13 @@ static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF * } }
- gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptcopy, count); - - round_points(pti, ptcopy, count); - - for(i = 0; i < count; i++){ - tp[i] = convert_path_point_type(types[i]); - } - - PolyDraw(graphics->hdc, pti, tp, count); + GdipCreatePath(FillModeAlternate, &path); + SOFTWARE_GdipFillPath(graphics, pen->brush, clonedpath);
status = Ok;
end: - free(pti); - free(ptcopy); - free(tp); - + GdipDeletePath(clonedpath); return status; }
@@ -3650,8 +3639,7 @@ static GpStatus GDI32_GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *pat
gdi_transform_acquire(graphics);
- retval = draw_poly(graphics, pen, path->pathdata.Points, - path->pathdata.Types, path->pathdata.Count, TRUE); + retval = draw_path(graphics, pen, path, TRUE);
gdi_transform_release(graphics);
@@ -4331,8 +4319,7 @@ static GpStatus GDI32_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath gdi_transform_acquire(graphics);
BeginPath(graphics->hdc); - retval = draw_poly(graphics, NULL, path->pathdata.Points, - path->pathdata.Types, path->pathdata.Count, FALSE); + retval = draw_path(graphics, NULL, path, FALSE);
if(retval == Ok) { @@ -4625,7 +4612,7 @@ static GpStatus GDI32_GdipFillRegion(GpGraphics* graphics, GpBrush* brush, ExtSelectClipRgn(graphics->hdc, hrgn, RGN_COPY); DeleteObject(hrgn);
- status = GdipGetRegionHRgn(region, graphics, &hrgn); + status = get_region_hrgn(®ion->node, graphics, FALSE, &hrgn); if (status != Ok) { RestoreDC(graphics->hdc, save_state);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=141314
Your paranoid android.
=== debian11 (32 bit report) ===
gdiplus: Unhandled exception: page fault on read access to 0x00000038 in 32-bit code (0x78e6d876). graphics.c:4240: Test failed: 0: expected 1, got 0 graphics.c:4265: Test failed: 0: expected 1, got 0 graphics.c:4316: Test failed: 0: expected 1, got 0 graphics.c:4341: Test failed: 0: expected 1, got 0 graphics.c:4316: Test failed: 1: expected 1, got 0 graphics.c:4341: Test failed: 1: expected 1, got 0 graphics.c:4240: Test failed: 2: expected 1, got 0 graphics.c:4265: Test failed: 2: expected 1, got 0 graphics.c:4316: Test failed: 2: expected 1, got 0 graphics.c:4341: Test failed: 2: expected 1, got 0 graphics.c:4240: Test failed: 3: expected 2, got 0 graphics.c:4265: Test failed: 3: expected 2, got 0 graphics.c:4316: Test failed: 3: expected 2, got 0 graphics.c:4341: Test failed: 3: expected 2, got 0 graphics.c:4240: Test failed: 4: expected 1, got 0 graphics.c:4265: Test failed: 4: expected 1, got 0 graphics.c:4316: Test failed: 4: expected 1, got 0 graphics.c:4341: Test failed: 4: expected 1, got 0 graphics.c:4240: Test failed: 5: expected 1, got 0 graphics.c:4265: Test failed: 5: expected 1, got 0 graphics.c:4316: Test failed: 5: expected 1, got 0 graphics.c:4341: Test failed: 5: expected 1, got 0 graphics.c:4240: Test failed: 6: expected 1, got 0 graphics.c:4265: Test failed: 6: expected 1, got 0 graphics.c:4316: Test failed: 6: expected 1, got 0 graphics.c:4341: Test failed: 6: expected 1, got 0 graphics.c:4240: Test failed: 7: expected 6, got 0 graphics.c:4265: Test failed: 7: expected 6, got 0 graphics.c:4316: Test failed: 7: expected 6, got 0 graphics.c:4341: Test failed: 7: expected 6, got 0 graphics.c:4240: Test failed: 8: expected 20, got 0 graphics.c:4265: Test failed: 8: expected 20, got 0 graphics.c:4316: Test failed: 8: expected 20, got 0 graphics.c:4341: Test failed: 8: expected 20, got 0 Unhandled exception: page fault on read access to 0x00000038 in 32-bit code (0x78e6d876).
=== debian11b (64 bit WoW report) ===
gdiplus: Unhandled exception: page fault on read access to 0x0000000000000048 in 64-bit code (0x0000007906f712). graphics.c:4240: Test failed: 0: expected 1, got 0 graphics.c:4265: Test failed: 0: expected 1, got 0 graphics.c:4316: Test failed: 0: expected 1, got 0 graphics.c:4341: Test failed: 0: expected 1, got 0 graphics.c:4316: Test failed: 1: expected 1, got 0 graphics.c:4341: Test failed: 1: expected 1, got 0 graphics.c:4240: Test failed: 2: expected 1, got 0 graphics.c:4265: Test failed: 2: expected 1, got 0 graphics.c:4316: Test failed: 2: expected 1, got 0 graphics.c:4341: Test failed: 2: expected 1, got 0 graphics.c:4240: Test failed: 3: expected 2, got 0 graphics.c:4265: Test failed: 3: expected 2, got 0 graphics.c:4316: Test failed: 3: expected 2, got 0 graphics.c:4341: Test failed: 3: expected 2, got 0 graphics.c:4240: Test failed: 4: expected 1, got 0 graphics.c:4265: Test failed: 4: expected 1, got 0 graphics.c:4316: Test failed: 4: expected 1, got 0 graphics.c:4341: Test failed: 4: expected 1, got 0 graphics.c:4240: Test failed: 5: expected 1, got 0 graphics.c:4265: Test failed: 5: expected 1, got 0 graphics.c:4316: Test failed: 5: expected 1, got 0 graphics.c:4341: Test failed: 5: expected 1, got 0 graphics.c:4240: Test failed: 6: expected 1, got 0 graphics.c:4265: Test failed: 6: expected 1, got 0 graphics.c:4316: Test failed: 6: expected 1, got 0 graphics.c:4341: Test failed: 6: expected 1, got 0 graphics.c:4240: Test failed: 7: expected 6, got 0 graphics.c:4265: Test failed: 7: expected 6, got 0 graphics.c:4316: Test failed: 7: expected 6, got 0 graphics.c:4341: Test failed: 7: expected 6, got 0 graphics.c:4240: Test failed: 8: expected 20, got 0 graphics.c:4265: Test failed: 8: expected 20, got 0 graphics.c:4316: Test failed: 8: expected 20, got 0 graphics.c:4341: Test failed: 8: expected 20, got 0 Unhandled exception: page fault on read access to 0x0000000000000048 in 64-bit code (0x0000007906f712).
I don't believe `draw_poly` is the right place for this. Either optimizations should be in gdi32, or in `SOFTWARE_GdipFillPath` (which we don't use now for drawing outlines because the gdi32 path is currently more efficient, but we could if that changed).
This merge request was closed by Esme Povirk.
Oh, sorry, didn't realize you weren't doing that anymore.