mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 17:45:09 +00:00
gdiplus: Support line gradient brushes in GdipFillPath.
This commit is contained in:
parent
e66e489417
commit
68dba4eff3
|
@ -172,6 +172,164 @@ static void transform_and_round_points(GpGraphics *graphics, POINT *pti,
|
|||
}
|
||||
}
|
||||
|
||||
static ARGB blend_colors(ARGB start, ARGB end, int current, int total)
|
||||
{
|
||||
ARGB result=0;
|
||||
ARGB i;
|
||||
for (i=0xff; i<=0xff0000; i = i << 8)
|
||||
result |= (((start&i)*(total - current)+(end&i)*(current))/total)&i;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
|
||||
{
|
||||
switch (brush->bt)
|
||||
{
|
||||
case BrushTypeLinearGradient:
|
||||
{
|
||||
GpLineGradient *line = (GpLineGradient*)brush;
|
||||
RECT rc;
|
||||
int num_steps = 255;
|
||||
|
||||
SelectClipPath(graphics->hdc, RGN_AND);
|
||||
if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
|
||||
{
|
||||
GpPointF endpointsf[2];
|
||||
POINT endpointsi[2];
|
||||
POINT poly[4];
|
||||
|
||||
SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
|
||||
|
||||
/* fill with starting color */
|
||||
FillRect(graphics->hdc, &rc, brush->gdibrush);
|
||||
|
||||
endpointsf[0] = line->startpoint;
|
||||
endpointsf[1] = line->endpoint;
|
||||
transform_and_round_points(graphics, endpointsi, endpointsf, 2);
|
||||
|
||||
if (abs(endpointsi[0].x-endpointsi[1].x) > abs(endpointsi[0].y-endpointsi[1].y))
|
||||
{
|
||||
/* vertical-ish gradient */
|
||||
int endborderx; /* vertical rectangle boundary near endpoint */
|
||||
int startx, endx; /* x co-ordinates of endpoints shifted to intersect the top of the visible rectangle */
|
||||
int startbottomx, endbottomx; /* x co-ordinate of endpoints shifted to intersect the bottom of the visible rectangle */
|
||||
int width;
|
||||
COLORREF col;
|
||||
HBRUSH hbrush, hprevbrush;
|
||||
int i;
|
||||
|
||||
if (endpointsi[1].x > endpointsi[0].x)
|
||||
endborderx = rc.right;
|
||||
else
|
||||
endborderx = rc.left;
|
||||
|
||||
startx = roundr((rc.top - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
|
||||
endx = roundr((rc.top - endpointsf[1].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[1].X);
|
||||
width = endx - startx;
|
||||
startbottomx = roundr((rc.bottom - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
|
||||
endbottomx = startbottomx+width;
|
||||
|
||||
if (num_steps > abs(width)) num_steps = abs(width);
|
||||
|
||||
poly[0].x = endborderx;
|
||||
poly[0].y = rc.bottom;
|
||||
poly[1].x = endborderx;
|
||||
poly[1].y = rc.top;
|
||||
poly[2].y = rc.top;
|
||||
poly[3].y = rc.bottom;
|
||||
|
||||
for (i=1; i<num_steps; i++)
|
||||
{
|
||||
ARGB argb = blend_colors(line->startcolor, line->endcolor, i, num_steps);
|
||||
int ofs = width * i / num_steps;
|
||||
col = ARGB2COLORREF(argb);
|
||||
hbrush = CreateSolidBrush(col);
|
||||
hprevbrush = SelectObject(graphics->hdc, hbrush);
|
||||
poly[2].x = startx + ofs;
|
||||
poly[3].x = startbottomx + ofs;
|
||||
Polygon(graphics->hdc, poly, 4);
|
||||
SelectObject(graphics->hdc, hprevbrush);
|
||||
DeleteObject(hbrush);
|
||||
}
|
||||
|
||||
poly[2].x = endx;
|
||||
poly[3].x = endbottomx;
|
||||
|
||||
/* draw the ending color */
|
||||
col = ARGB2COLORREF(line->endcolor);
|
||||
hbrush = CreateSolidBrush(col);
|
||||
hprevbrush = SelectObject(graphics->hdc, hbrush);
|
||||
Polygon(graphics->hdc, poly, 4);
|
||||
SelectObject(graphics->hdc, hprevbrush);
|
||||
DeleteObject(hbrush);
|
||||
}
|
||||
else if (endpointsi[0].y != endpointsi[1].y)
|
||||
{
|
||||
/* horizontal-ish gradient */
|
||||
int endbordery; /* horizontal rectangle boundary near endpoint */
|
||||
int starty, endy; /* y co-ordinates of endpoints shifted to intersect the left of the visible rectangle */
|
||||
int startrighty, endrighty; /* y co-ordinate of endpoints shifted to intersect the right of the visible rectangle */
|
||||
int height;
|
||||
COLORREF col;
|
||||
HBRUSH hbrush, hprevbrush;
|
||||
int i;
|
||||
|
||||
if (endpointsi[1].y > endpointsi[0].y)
|
||||
endbordery = rc.bottom;
|
||||
else
|
||||
endbordery = rc.top;
|
||||
|
||||
starty = roundr((rc.left - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
|
||||
endy = roundr((rc.left - endpointsf[1].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[1].Y);
|
||||
height = endy - starty;
|
||||
startrighty = roundr((rc.right - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
|
||||
endrighty = startrighty+height;
|
||||
|
||||
if (num_steps > abs(height)) num_steps = abs(height);
|
||||
|
||||
poly[0].x = rc.right;
|
||||
poly[0].y = endbordery;
|
||||
poly[1].x = rc.left;
|
||||
poly[1].y = endbordery;
|
||||
poly[2].x = rc.left;
|
||||
poly[3].x = rc.right;
|
||||
|
||||
for (i=1; i<num_steps; i++)
|
||||
{
|
||||
ARGB argb = blend_colors(line->startcolor, line->endcolor, i, num_steps);
|
||||
int ofs = height * i / num_steps;
|
||||
col = ARGB2COLORREF(argb);
|
||||
hbrush = CreateSolidBrush(col);
|
||||
hprevbrush = SelectObject(graphics->hdc, hbrush);
|
||||
poly[2].y = starty + ofs;
|
||||
poly[3].y = startrighty + ofs;
|
||||
Polygon(graphics->hdc, poly, 4);
|
||||
SelectObject(graphics->hdc, hprevbrush);
|
||||
DeleteObject(hbrush);
|
||||
}
|
||||
|
||||
poly[2].y = endy;
|
||||
poly[3].y = endrighty;
|
||||
|
||||
/* draw the ending color */
|
||||
col = ARGB2COLORREF(line->endcolor);
|
||||
hbrush = CreateSolidBrush(col);
|
||||
hprevbrush = SelectObject(graphics->hdc, hbrush);
|
||||
Polygon(graphics->hdc, poly, 4);
|
||||
SelectObject(graphics->hdc, hprevbrush);
|
||||
DeleteObject(hbrush);
|
||||
}
|
||||
/* else startpoint == endpoint */
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SelectObject(graphics->hdc, brush->gdibrush);
|
||||
FillPath(graphics->hdc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* GdipDrawPie/GdipFillPie helper function */
|
||||
static void draw_pie(GpGraphics *graphics, REAL x, REAL y, REAL width,
|
||||
REAL height, REAL startAngle, REAL sweepAngle)
|
||||
|
@ -2086,7 +2244,6 @@ GpStatus WINGDIPAPI GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *p
|
|||
|
||||
save_state = SaveDC(graphics->hdc);
|
||||
EndPath(graphics->hdc);
|
||||
SelectObject(graphics->hdc, brush->gdibrush);
|
||||
SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
|
||||
: WINDING));
|
||||
|
||||
|
@ -2098,7 +2255,7 @@ GpStatus WINGDIPAPI GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *p
|
|||
goto end;
|
||||
|
||||
EndPath(graphics->hdc);
|
||||
FillPath(graphics->hdc);
|
||||
brush_fill_path(graphics, brush);
|
||||
|
||||
retval = Ok;
|
||||
|
||||
|
|
Loading…
Reference in a new issue