gdiplus: Fill path gradients with a solid color.
This commit is contained in:
parent
7b918934e6
commit
703b31b2e8
|
@ -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)
|
static INT brush_can_fill_path(GpBrush *brush)
|
||||||
{
|
{
|
||||||
switch (brush->bt)
|
switch (brush->bt)
|
||||||
|
@ -958,6 +963,7 @@ static INT brush_can_fill_pixels(GpBrush *brush)
|
||||||
case BrushTypeHatchFill:
|
case BrushTypeHatchFill:
|
||||||
case BrushTypeLinearGradient:
|
case BrushTypeLinearGradient:
|
||||||
case BrushTypeTextureFill:
|
case BrushTypeTextureFill:
|
||||||
|
case BrushTypePathGradient:
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1173,6 +1179,140 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush,
|
||||||
|
|
||||||
return stat;
|
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; i<flat_path->pathdata.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<max_y; y++)
|
||||||
|
{
|
||||||
|
REAL yf = (REAL)y;
|
||||||
|
|
||||||
|
if (!seen_start && yf >= 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; x<max_x; x++)
|
||||||
|
argb_pixels[(x-fill_area->X) + (y-fill_area->Y)*cdwStride] = fill->centercolor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GdipDeletePath(flat_path);
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return NotImplemented;
|
return NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue