2 * Copyright (C) 2007 Google (Evan Stade)
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "gdiplus_private.h"
28 #include "wine/debug.h"
30 /* looks-right constant */
31 #define TENSION_CONST (0.3)
33 static inline INT roundr(REAL x)
35 return (INT) floor(x+0.5);
38 static inline REAL deg2rad(REAL degrees)
40 return (M_PI*2.0) * degrees / 360.0;
43 /* Converts angle (in degrees) to x/y coordinates */
44 static void deg2xy(REAL angle, REAL x_0, REAL y_0, REAL *x, REAL *y)
46 REAL radAngle, hypotenuse;
48 radAngle = deg2rad(angle);
49 hypotenuse = 50.0; /* arbitrary */
51 *x = x_0 + cos(radAngle) * hypotenuse;
52 *y = y_0 + sin(radAngle) * hypotenuse;
55 /* GdipDrawPie/GdipFillPie helper function */
56 static GpStatus draw_pie(GpGraphics *graphics, HBRUSH gdibrush, HPEN gdipen,
57 REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
59 HGDIOBJ old_pen, old_brush;
60 REAL x_0, y_0, x_1, y_1, x_2, y_2;
63 return InvalidParameter;
65 old_pen = SelectObject(graphics->hdc, gdipen);
66 old_brush = SelectObject(graphics->hdc, gdibrush);
68 x_0 = x + (width/2.0);
69 y_0 = y + (height/2.0);
71 deg2xy(startAngle+sweepAngle, x_0, y_0, &x_1, &y_1);
72 deg2xy(startAngle, x_0, y_0, &x_2, &y_2);
74 Pie(graphics->hdc, roundr(x), roundr(y), roundr(x+width), roundr(y+height),
75 roundr(x_1), roundr(y_1), roundr(x_2), roundr(y_2));
77 SelectObject(graphics->hdc, old_pen);
78 SelectObject(graphics->hdc, old_brush);
83 /* GdipDrawCurve helper function.
84 * Calculates Bezier points from cardinal spline points. */
85 static void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
86 REAL *y1, REAL *x2, REAL *y2)
90 /* calculate tangent */
91 xdiff = pts[2].X - pts[0].X;
92 ydiff = pts[2].Y - pts[0].Y;
94 /* apply tangent to get control points */
95 *x1 = pts[1].X - tension * xdiff;
96 *y1 = pts[1].Y - tension * ydiff;
97 *x2 = pts[1].X + tension * xdiff;
98 *y2 = pts[1].Y + tension * ydiff;
101 /* GdipDrawCurve helper function.
102 * Calculates Bezier points from cardinal spline endpoints. */
103 static void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj,
104 REAL tension, REAL *x, REAL *y)
106 /* tangent at endpoints is the line from the endpoint to the adjacent point */
107 *x = roundr(tension * (xadj - xend) + xend);
108 *y = roundr(tension * (yadj - yend) + yend);
111 GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics)
117 return InvalidParameter;
119 *graphics = GdipAlloc(sizeof(GpGraphics));
120 if(!*graphics) return OutOfMemory;
122 (*graphics)->hdc = hdc;
123 (*graphics)->hwnd = NULL;
128 GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics)
132 if((ret = GdipCreateFromHDC(GetDC(hwnd), graphics)) != Ok)
135 (*graphics)->hwnd = hwnd;
140 GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
142 if(!graphics) return InvalidParameter;
144 ReleaseDC(graphics->hwnd, graphics->hdc);
146 HeapFree(GetProcessHeap(), 0, graphics);
151 GpStatus WINGDIPAPI GdipDrawArc(GpGraphics *graphics, GpPen *pen, REAL x,
152 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
155 REAL x_0, y_0, x_1, y_1, x_2, y_2;
157 if(!graphics || !pen)
158 return InvalidParameter;
160 old_pen = SelectObject(graphics->hdc, pen->gdipen);
162 x_0 = x + (width/2.0);
163 y_0 = y + (height/2.0);
165 deg2xy(startAngle+sweepAngle, x_0, y_0, &x_1, &y_1);
166 deg2xy(startAngle, x_0, y_0, &x_2, &y_2);
168 Arc(graphics->hdc, roundr(x), roundr(y), roundr(x+width), roundr(y+height),
169 roundr(x_1), roundr(y_1), roundr(x_2), roundr(y_2));
171 SelectObject(graphics->hdc, old_pen);
176 GpStatus WINGDIPAPI GdipDrawBezier(GpGraphics *graphics, GpPen *pen, REAL x1,
177 REAL y1, REAL x2, REAL y2, REAL x3, REAL y3, REAL x4, REAL y4)
180 POINT pt[4] = {{roundr(x1), roundr(y1)}, {roundr(x2), roundr(y2)},
181 {roundr(x3), roundr(y3)}, {roundr(x4), roundr(y4)}};
183 if(!graphics || !pen)
184 return InvalidParameter;
186 old_pen = SelectObject(graphics->hdc, pen->gdipen);
188 PolyBezier(graphics->hdc, pt, 4);
190 SelectObject(graphics->hdc, old_pen);
195 /* Approximates cardinal spline with Bezier curves. */
196 GpStatus WINGDIPAPI GdipDrawCurve2(GpGraphics *graphics, GpPen *pen,
197 GDIPCONST GpPointF *points, INT count, REAL tension)
201 /* PolyBezier expects count*3-2 points. */
202 int i, len_pt = count*3-2;
206 if(!graphics || !pen)
207 return InvalidParameter;
209 tension = tension * TENSION_CONST;
211 calc_curve_bezier_endp(points[0].X, points[0].Y, points[1].X, points[1].Y,
214 pt[0].x = roundr(points[0].X);
215 pt[0].y = roundr(points[0].Y);
216 pt[1].x = roundr(x1);
217 pt[1].y = roundr(y1);
219 for(i = 0; i < count-2; i++){
220 calc_curve_bezier(&(points[i]), tension, &x1, &y1, &x2, &y2);
222 pt[3*i+2].x = roundr(x1);
223 pt[3*i+2].y = roundr(y1);
224 pt[3*i+3].x = roundr(points[i+1].X);
225 pt[3*i+3].y = roundr(points[i+1].Y);
226 pt[3*i+4].x = roundr(x2);
227 pt[3*i+4].y = roundr(y2);
230 calc_curve_bezier_endp(points[count-1].X, points[count-1].Y,
231 points[count-2].X, points[count-2].Y, tension, &x1, &y1);
235 pt[len_pt-1].x = roundr(points[count-1].X);
236 pt[len_pt-1].y = roundr(points[count-1].Y);
238 old_pen = SelectObject(graphics->hdc, pen->gdipen);
240 PolyBezier(graphics->hdc, pt, len_pt);
242 SelectObject(graphics->hdc, old_pen);
247 GpStatus WINGDIPAPI GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1,
248 INT y1, INT x2, INT y2)
252 if(!pen || !graphics)
253 return InvalidParameter;
255 old_obj = SelectObject(graphics->hdc, pen->gdipen);
256 MoveToEx(graphics->hdc, x1, y1, NULL);
257 LineTo(graphics->hdc, x2, y2);
258 SelectObject(graphics->hdc, old_obj);
263 GpStatus WINGDIPAPI GdipDrawLines(GpGraphics *graphics, GpPen *pen, GDIPCONST
264 GpPointF *points, INT count)
269 if(!pen || !graphics || (count < 2))
270 return InvalidParameter;
272 old_obj = SelectObject(graphics->hdc, pen->gdipen);
273 MoveToEx(graphics->hdc, roundr(points[0].X), roundr(points[0].Y), NULL);
275 for(i = 1; i < count; i++){
276 LineTo(graphics->hdc, roundr(points[i].X), roundr(points[i].Y));
279 SelectObject(graphics->hdc, old_obj);
284 GpStatus WINGDIPAPI GdipDrawPie(GpGraphics *graphics, GpPen *pen, REAL x,
285 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
288 return InvalidParameter;
290 return draw_pie(graphics, GetStockObject(NULL_BRUSH), pen->gdipen, x, y,
291 width, height, startAngle, sweepAngle);
294 GpStatus WINGDIPAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x,
295 INT y, INT width, INT height)
301 if(!pen || !graphics)
302 return InvalidParameter;
304 lb.lbStyle = BS_SOLID;
305 lb.lbColor = pen->color;
308 hpen = ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_SQUARE, (INT) pen->width,
311 old_obj = SelectObject(graphics->hdc, hpen);
313 /* assume pen aligment centered */
314 MoveToEx(graphics->hdc, x, y, NULL);
315 LineTo(graphics->hdc, x+width, y);
316 LineTo(graphics->hdc, x+width, y+height);
317 LineTo(graphics->hdc, x, y+height);
318 LineTo(graphics->hdc, x, y);
320 SelectObject(graphics->hdc, old_obj);
326 GpStatus WINGDIPAPI GdipFillPie(GpGraphics *graphics, GpBrush *brush, REAL x,
327 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
330 return InvalidParameter;
332 return draw_pie(graphics, brush->gdibrush, GetStockObject(NULL_PEN), x, y,
333 width, height, startAngle, sweepAngle);