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/graphics.c | 93 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 835c2889bd1..7475557280c 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -1920,6 +1920,98 @@ static void shorten_bezier_amt(GpPointF * pt, REAL amt, BOOL rev) } }
+static void poly_clip(GpGraphics *graphics, POINT *pti, BYTE *tp, int count) +{ + RectF rect; + BITMAP structBitmapHeader = {0}; + HGDIOBJ hBitmap = GetCurrentObject(graphics->hdc, OBJ_BITMAP); + BYTE *tpcopy = malloc(count); + + memcpy(tpcopy, tp, count); + GetObjectW(hBitmap, sizeof(BITMAP), &structBitmapHeader); + set_rect(&rect, 0, 0, structBitmapHeader.bmWidth, structBitmapHeader.bmHeight); + + /* Ignore data that is not meant for drawing */ + if (rect.Width == 1 && rect.Height == 1) + return; + + /* DC attributes were not set, assume client area */ + if (rect.Width == 0 && rect.Height == 0) + { + RECT lpRect; + GetClientRect(graphics->hwnd, &lpRect); + rect.Width = lpRect.right; + rect.Height = lpRect.bottom; + } + + for (int i = 0; i < count; i++) + { + switch(tp[i] &~ PT_CLOSEFIGURE) + { + case PT_BEZIERTO: + { + int j; + + for (j = 0; j < 3; j++) + { + REAL x = pti[i + j].x; + REAL y = pti[i + j].y; + + /* At least part of the rectangle encompassing the bezier lies within the DC's region */ + if (rect.X <= x && rect.Y <= y && x <= rect.X + rect.Width && y <= rect.Y + rect.Height) + break; + } + + if (j == 3) + { + for(j = 0; j < 3; j++) + tp[i + j] = PT_MOVETO; + } + + i += 2; + break; + } + case PT_LINETO: + { + int x1, y1, x2 = pti[i].x, y2 = pti[i].y; + + if (i == 0) + { + x1 = y1 = 0; + } + else + { + x1 = pti[i - 1].x; + y1 = pti[i - 1].y; + } + + /* If any of the connecting points lies within DC's region */ + if ((rect.X <= x1 && rect.Y <= y1 && x1 <= rect.X + rect.Width && y1 <= rect.Y + rect.Height) || + (rect.X <= x2 && rect.Y <= y2 && x2 <= rect.X + rect.Width && y2 <= rect.Y + rect.Height)) + { + if (i != 0) + { + tp[i - 1] = tpcopy[i - 1]; + tp[i] = tpcopy[i]; + } + break; + } + + tp[i] = PT_MOVETO; + + break; + } + case PT_MOVETO: + break; + + default: + ERR("Bad point type \n"); + } + } + + free(tpcopy); +} + /* 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) @@ -2036,6 +2128,7 @@ static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF * tp[i] = convert_path_point_type(types[i]); }
+ poly_clip(graphics, pti, tp, count); PolyDraw(graphics->hdc, pti, tp, count);
status = Ok;