From 703b31b2e8c5e212f6445c8d7c0a666e73b3820c Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Mon, 20 Feb 2012 17:08:05 -0600 Subject: [PATCH] gdiplus: Fill path gradients with a solid color. --- dlls/gdiplus/graphics.c | 140 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index ddae06ee3b5..72c6f014cc6 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -875,6 +875,11 @@ static ARGB resample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT } } +static REAL intersect_line_scanline(const GpPointF *p1, const GpPointF *p2, REAL y) +{ + return (p1->X - p2->X) * (p2->Y - y) / (p2->Y - p1->Y) + p2->X; +} + static INT brush_can_fill_path(GpBrush *brush) { switch (brush->bt) @@ -958,6 +963,7 @@ static INT brush_can_fill_pixels(GpBrush *brush) case BrushTypeHatchFill: case BrushTypeLinearGradient: case BrushTypeTextureFill: + case BrushTypePathGradient: return 1; default: return 0; @@ -1173,6 +1179,140 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush, return stat; } + case BrushTypePathGradient: + { + GpPathGradient *fill = (GpPathGradient*)brush; + GpPath *flat_path; + GpMatrix *world_to_device; + GpStatus stat; + int i, figure_start=0; + GpPointF start_point, end_point, center_point; + BYTE type; + REAL min_yf, max_yf, line1_xf, line2_xf; + INT min_y, max_y, min_x, max_x; + INT x, y; + + stat = GdipClonePath(fill->path, &flat_path); + + if (stat != Ok) + return stat; + + stat = get_graphics_transform(graphics, CoordinateSpaceDevice, + CoordinateSpaceWorld, &world_to_device); + if (stat == Ok) + { + stat = GdipTransformPath(flat_path, world_to_device); + + if (stat == Ok) + { + center_point = fill->center; + stat = GdipTransformMatrixPoints(world_to_device, ¢er_point, 1); + } + + if (stat == Ok) + stat = GdipFlattenPath(flat_path, NULL, 0.5); + + GdipDeleteMatrix(world_to_device); + } + + if (stat != Ok) + { + GdipDeletePath(flat_path); + return stat; + } + + for (i=0; ipathdata.Count; i++) + { + int start_center_line=0, end_center_line=0; + int seen_start=0, seen_end=0, seen_center=0; + + type = flat_path->pathdata.Types[i]; + + if ((type&PathPointTypePathTypeMask) == PathPointTypeStart) + figure_start = i; + + start_point = flat_path->pathdata.Points[i]; + + if ((type&PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath || i+1 >= flat_path->pathdata.Count) + end_point = flat_path->pathdata.Points[figure_start]; + else if ((flat_path->pathdata.Types[i+1] & PathPointTypePathTypeMask) == PathPointTypeLine) + end_point = flat_path->pathdata.Points[i+1]; + else + continue; + + min_yf = center_point.Y; + if (min_yf > start_point.Y) min_yf = start_point.Y; + if (min_yf > end_point.Y) min_yf = end_point.Y; + + if (min_yf < fill_area->Y) + min_y = fill_area->Y; + else + min_y = (INT)ceil(min_yf); + + max_yf = center_point.Y; + if (max_yf < start_point.Y) max_yf = start_point.Y; + if (max_yf < end_point.Y) max_yf = end_point.Y; + + if (max_yf > fill_area->Y + fill_area->Height) + max_y = fill_area->Y + fill_area->Height; + else + max_y = (INT)ceil(max_yf); + + for (y=min_y; y= start_point.Y) + { + seen_start = 1; + start_center_line ^= 1; + } + if (!seen_end && yf >= end_point.Y) + { + seen_end = 1; + end_center_line ^= 1; + } + if (!seen_center && yf >= center_point.Y) + { + seen_center = 1; + start_center_line ^= 1; + end_center_line ^= 1; + } + + if (start_center_line) + line1_xf = intersect_line_scanline(&start_point, ¢er_point, yf); + else + line1_xf = intersect_line_scanline(&start_point, &end_point, yf); + + if (end_center_line) + line2_xf = intersect_line_scanline(&end_point, ¢er_point, yf); + else + line2_xf = intersect_line_scanline(&start_point, &end_point, yf); + + if (line1_xf < line2_xf) + { + min_x = (INT)ceil(line1_xf); + max_x = (INT)ceil(line2_xf); + } + else + { + min_x = (INT)ceil(line2_xf); + max_x = (INT)ceil(line1_xf); + } + + if (min_x < fill_area->X) + min_x = fill_area->X; + if (max_x > fill_area->X + fill_area->Width) + max_x = fill_area->X + fill_area->Width; + + for (x=min_x; xX) + (y-fill_area->Y)*cdwStride] = fill->centercolor; + } + } + + GdipDeletePath(flat_path); + return stat; + } default: return NotImplemented; }