From: David Kahurani k.kahurani@gmail.com
This is a half-witted attempt at avoiding GdipGetRegionHrgn. in GdipFillPath. The use of GdipGetRegionHrgn happens as consequence of the use of regions in internal code. From the look of it, as per the development plans, it should be possible to remove it by avoiding internal use of regions.
This could be done, for instance, by reducing a region to a path before computing on it or rendering it. However, this is going to be fairly if not very complicated and, just like with the other MR, will not guarantee optimization.
This patch, for instance, might not have observable optimization impact. This is because 'trace_path' and 'PathToRegion' are still being used and are probably the most computation heavy sections of GdipGetRegionHrgn. Still, it should be possible to compute the exactly what data to render without these two methods. This could however get a bit complicated.
Signed-off-by: David Kahurani k.kahurani@gmail.com --- dlls/gdiplus/graphics.c | 60 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 70b88830ca2..51ebcd7959f 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -4351,19 +4351,71 @@ static GpStatus SOFTWARE_GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPa { GpStatus stat; GpRegion *rgn; + GpRectF bounds; + RECT bound_rect; + DWORD *pixel_data; + HRGN display, src, dst; + GpMatrix device_to_world;
if (!brush_can_fill_pixels(brush)) return NotImplemented;
- /* FIXME: This could probably be done more efficiently without regions. */ + stat = get_graphics_device_bounds(graphics, &bounds); + display = CreateRectRgn(bounds.X, bounds.Y, bounds.X + bounds.Width, bounds.Y + bounds.Height); + + if (stat == Ok) + stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice, + CoordinateSpaceWorld, &device_to_world); + + stat = GdipTransformPath(path, &device_to_world);
- stat = GdipCreateRegionPath(path, &rgn); + gdi_transform_acquire(graphics); + stat = trace_path(graphics, path);
if (stat == Ok) { - stat = GdipFillRegion(graphics, brush, rgn); + src = PathToRegion(graphics->hdc); + stat = src ? Ok : OutOfMemory; + }
- GdipDeleteRegion(rgn); + CombineRgn(dst, src, display, RGN_AND); + + if (stat == Ok && GetRgnBox(dst, &bound_rect) == NULLREGION) + { + DeleteObject(dst); + gdi_transform_release(graphics); + return Ok; + } + + if (stat == Ok) + { + GpRect gp_bound_rect; + + gp_bound_rect.X = bound_rect.left; + gp_bound_rect.Y = bound_rect.top; + gp_bound_rect.Width = bound_rect.right - bound_rect.left; + gp_bound_rect.Height = bound_rect.bottom - bound_rect.top; + + pixel_data = calloc(gp_bound_rect.Width * gp_bound_rect.Height, sizeof(*pixel_data)); + + if (!pixel_data) + stat = OutOfMemory; + + if (!pixel_data) + stat = OutOfMemory; + + if (stat == Ok) + { + stat = brush_fill_pixels(graphics, brush, pixel_data, &gp_bound_rect, gp_bound_rect.Width); + if (stat == Ok) + stat = alpha_blend_pixels_hrgn(graphics, gp_bound_rect.X, gp_bound_rect.Y, (BYTE*)pixel_data, gp_bound_rect.Width, gp_bound_rect.Height, gp_bound_rect.Width * 4, dst, PixelFormat32bppARGB); + free(pixel_data); + } + + DeleteObject(dst); + DeleteObject(src); + DeleteObject(display); + gdi_transform_release(graphics); }
return stat;