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
-- v6: 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 point 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 6cdc2a58059..4287845fa9b 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 = heap_alloc_zero(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 = heap_alloc_zero(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; } @@ -169,7 +184,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))) return FALSE;
/* do the same with halves */ @@ -1333,7 +1348,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; @@ -1357,7 +1372,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;
@@ -1829,7 +1844,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; } @@ -1845,7 +1860,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); }
@@ -1870,7 +1885,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; } @@ -1933,11 +1948,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; } @@ -1959,27 +1974,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) @@ -2000,7 +2015,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) @@ -2041,13 +2056,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; } @@ -2066,39 +2081,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; @@ -2117,13 +2132,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; } @@ -2137,11 +2152,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; } @@ -2200,7 +2215,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 c292318b06e..ad1b08f1517 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -67,6 +67,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);
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 6dc34707bbf..54c07a4db8c 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -2153,7 +2153,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 ad1b08f1517..479723fc263 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 4287845fa9b..9fb3f97c978 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -2798,3 +2798,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 d0d9f4ba54e..ea5e3b08ed0 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 479723fc263..263c4ae1976 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 ea5e3b08ed0..88f90c0be77 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 54c07a4db8c..3845ce376ca 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -2050,13 +2050,52 @@ end:
GpStatus trace_path(GpGraphics *graphics, GpPath *path) { - GpStatus result; + POINT *pti = heap_alloc_zero(path->pathdata.Count * sizeof(POINT)); + BYTE *tp = heap_alloc_zero(path->pathdata.Count); + GpPointF *ptcopy = heap_alloc_zero(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: + heap_free(pti); + heap_free(ptcopy); + heap_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 3845ce376ca..5e027e29631 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) { @@ -1921,28 +1922,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 = heap_alloc_zero(count * sizeof(POINT)); - BYTE *tp = heap_alloc_zero(count); - GpPointF *ptcopy = heap_alloc_zero(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; } @@ -1950,38 +1951,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: @@ -1990,36 +1989,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: @@ -2028,23 +2027,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: - heap_free(pti); - heap_free(ptcopy); - heap_free(tp); - + GdipDeletePath(clonedpath); return status; }
@@ -3659,8 +3648,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);
@@ -4340,8 +4328,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) { @@ -4634,7 +4621,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 full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=141310
Your paranoid android.
=== debian11 (build log) ===
error: patch failed: dlls/gdiplus/graphicspath.c:75 error: patch failed: dlls/gdiplus/gdiplus_private.h:67 error: patch failed: dlls/gdiplus/graphics.c:1921 Task: Patch failed to apply
=== debian11b (build log) ===
error: patch failed: dlls/gdiplus/graphicspath.c:75 error: patch failed: dlls/gdiplus/gdiplus_private.h:67 error: patch failed: dlls/gdiplus/graphics.c:1921 Task: Patch failed to apply