blob: 642a22fd1a5e83a6d43f4e10217bf2412024d8aa [file] [log] [blame]
Evan Staded50be492007-06-11 11:54:03 -07001/*
2 * Copyright (C) 2007 Google (Evan Stade)
3 *
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.
8 *
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.
13 *
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
17 */
18
19#include <stdarg.h>
20#include <math.h>
Evan Stade44e98392007-08-15 16:22:09 -070021#include <limits.h>
Evan Staded50be492007-06-11 11:54:03 -070022
23#include "windef.h"
24#include "winbase.h"
25#include "winuser.h"
26#include "wingdi.h"
Evan Stadef7d27e02007-08-14 18:58:39 -070027#include "wine/unicode.h"
Evan Stade50799cf2007-07-30 19:10:03 -070028
29#define COBJMACROS
30#include "objbase.h"
31#include "ocidl.h"
32#include "olectl.h"
33#include "ole2.h"
34
Evan Stade3ea77f52007-08-07 18:42:00 -070035#include "winreg.h"
36#include "shlwapi.h"
37
Evan Staded50be492007-06-11 11:54:03 -070038#include "gdiplus.h"
39#include "gdiplus_private.h"
40#include "wine/debug.h"
Andrew Eikum632aef32009-07-05 17:04:20 -050041#include "wine/list.h"
Evan Staded50be492007-06-11 11:54:03 -070042
Evan Stade5128e5d2007-07-07 13:20:41 -070043WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
44
45/* looks-right constants */
Evan Stade5128e5d2007-07-07 13:20:41 -070046#define ANCHOR_WIDTH (2.0)
Evan Stade69a807c2007-07-06 16:13:49 -070047#define MAX_ITERS (50)
Evan Stade5c8b83c2007-06-19 19:31:28 -070048
Evan Stade72ab72c502007-06-18 16:55:51 -070049/* Converts angle (in degrees) to x/y coordinates */
50static void deg2xy(REAL angle, REAL x_0, REAL y_0, REAL *x, REAL *y)
51{
52 REAL radAngle, hypotenuse;
53
54 radAngle = deg2rad(angle);
55 hypotenuse = 50.0; /* arbitrary */
56
57 *x = x_0 + cos(radAngle) * hypotenuse;
58 *y = y_0 + sin(radAngle) * hypotenuse;
59}
60
Evan Stade85b5df42007-07-19 18:22:51 -070061/* Converts from gdiplus path point type to gdi path point type. */
62static BYTE convert_path_point_type(BYTE type)
63{
64 BYTE ret;
65
66 switch(type & PathPointTypePathTypeMask){
67 case PathPointTypeBezier:
68 ret = PT_BEZIERTO;
69 break;
70 case PathPointTypeLine:
71 ret = PT_LINETO;
72 break;
73 case PathPointTypeStart:
74 ret = PT_MOVETO;
75 break;
76 default:
77 ERR("Bad point type\n");
78 return 0;
79 }
80
81 if(type & PathPointTypeCloseSubpath)
82 ret |= PT_CLOSEFIGURE;
83
84 return ret;
85}
86
Evan Stade4c424b32007-07-24 17:18:54 -070087static INT prepare_dc(GpGraphics *graphics, GpPen *pen)
88{
89 HPEN gdipen;
90 REAL width;
Evan Stade1f61f482007-07-27 16:07:39 -070091 INT save_state = SaveDC(graphics->hdc), i, numdashes;
Evan Stadeb7053b72007-07-24 17:18:58 -070092 GpPointF pt[2];
Evan Stade1f61f482007-07-27 16:07:39 -070093 DWORD dash_array[MAX_DASHLEN];
Evan Stade4c424b32007-07-24 17:18:54 -070094
95 EndPath(graphics->hdc);
96
Evan Stadeafa4d322007-08-13 18:34:31 -070097 if(pen->unit == UnitPixel){
98 width = pen->width;
99 }
100 else{
101 /* Get an estimate for the amount the pen width is affected by the world
102 * transform. (This is similar to what some of the wine drivers do.) */
103 pt[0].X = 0.0;
104 pt[0].Y = 0.0;
105 pt[1].X = 1.0;
106 pt[1].Y = 1.0;
107 GdipTransformMatrixPoints(graphics->worldtrans, pt, 2);
108 width = sqrt((pt[1].X - pt[0].X) * (pt[1].X - pt[0].X) +
109 (pt[1].Y - pt[0].Y) * (pt[1].Y - pt[0].Y)) / sqrt(2.0);
Evan Stadeb7053b72007-07-24 17:18:58 -0700110
Evan Stadeafa4d322007-08-13 18:34:31 -0700111 width *= pen->width * convert_unit(graphics->hdc,
112 pen->unit == UnitWorld ? graphics->unit : pen->unit);
113 }
Evan Stade4c424b32007-07-24 17:18:54 -0700114
Evan Stade1f61f482007-07-27 16:07:39 -0700115 if(pen->dash == DashStyleCustom){
116 numdashes = min(pen->numdashes, MAX_DASHLEN);
117
118 TRACE("dashes are: ");
119 for(i = 0; i < numdashes; i++){
120 dash_array[i] = roundr(width * pen->dashes[i]);
121 TRACE("%d, ", dash_array[i]);
122 }
123 TRACE("\n and the pen style is %x\n", pen->style);
124
125 gdipen = ExtCreatePen(pen->style, roundr(width), &pen->brush->lb,
126 numdashes, dash_array);
127 }
128 else
129 gdipen = ExtCreatePen(pen->style, roundr(width), &pen->brush->lb, 0, NULL);
130
Evan Stade4c424b32007-07-24 17:18:54 -0700131 SelectObject(graphics->hdc, gdipen);
132
133 return save_state;
134}
135
136static void restore_dc(GpGraphics *graphics, INT state)
137{
138 DeleteObject(SelectObject(graphics->hdc, GetStockObject(NULL_PEN)));
139 RestoreDC(graphics->hdc, state);
140}
141
Evan Staded01c6972007-07-23 20:24:53 -0700142/* This helper applies all the changes that the points listed in ptf need in
143 * order to be drawn on the device context. In the end, this should include at
144 * least:
145 * -scaling by page unit
146 * -applying world transformation
147 * -converting from float to int
148 * Native gdiplus uses gdi32 to do all this (via SetMapMode, SetViewportExtEx,
149 * SetWindowExtEx, SetWorldTransform, etc.) but we cannot because we are using
150 * gdi to draw, and these functions would irreparably mess with line widths.
151 */
152static void transform_and_round_points(GpGraphics *graphics, POINT *pti,
Evan Stadec3e8af42007-07-24 17:18:50 -0700153 GpPointF *ptf, INT count)
Evan Staded01c6972007-07-23 20:24:53 -0700154{
155 REAL unitscale;
Evan Stadec3e8af42007-07-24 17:18:50 -0700156 GpMatrix *matrix;
Evan Staded01c6972007-07-23 20:24:53 -0700157 int i;
158
Evan Stade4c424b32007-07-24 17:18:54 -0700159 unitscale = convert_unit(graphics->hdc, graphics->unit);
Evan Staded01c6972007-07-23 20:24:53 -0700160
Evan Stade81621392007-07-24 17:18:39 -0700161 /* apply page scale */
162 if(graphics->unit != UnitDisplay)
163 unitscale *= graphics->scale;
164
Evan Stadec3e8af42007-07-24 17:18:50 -0700165 GdipCloneMatrix(graphics->worldtrans, &matrix);
166 GdipScaleMatrix(matrix, unitscale, unitscale, MatrixOrderAppend);
167 GdipTransformMatrixPoints(matrix, ptf, count);
Evan Stadef52adfd2007-07-25 19:15:20 -0700168 GdipDeleteMatrix(matrix);
Evan Stadec3e8af42007-07-24 17:18:50 -0700169
Evan Staded01c6972007-07-23 20:24:53 -0700170 for(i = 0; i < count; i++){
Evan Stadec3e8af42007-07-24 17:18:50 -0700171 pti[i].x = roundr(ptf[i].X);
172 pti[i].y = roundr(ptf[i].Y);
Evan Staded01c6972007-07-23 20:24:53 -0700173 }
174}
175
Vincent Povirka6161302009-05-01 14:26:50 -0500176static ARGB blend_colors(ARGB start, ARGB end, REAL position)
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500177{
178 ARGB result=0;
179 ARGB i;
180 for (i=0xff; i<=0xff0000; i = i << 8)
Vincent Povirka6161302009-05-01 14:26:50 -0500181 result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500182 return result;
183}
184
Vincent Povirka6161302009-05-01 14:26:50 -0500185static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
186{
187 REAL blendfac;
188
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500189 /* clamp to between 0.0 and 1.0, using the wrap mode */
190 if (brush->wrap == WrapModeTile)
191 {
192 position = fmodf(position, 1.0f);
193 if (position < 0.0f) position += 1.0f;
194 }
195 else /* WrapModeFlip* */
196 {
197 position = fmodf(position, 2.0f);
198 if (position < 0.0f) position += 2.0f;
199 if (position > 1.0f) position = 2.0f - position;
200 }
201
Vincent Povirka6161302009-05-01 14:26:50 -0500202 if (brush->blendcount == 1)
203 blendfac = position;
204 else
205 {
206 int i=1;
207 REAL left_blendpos, left_blendfac, right_blendpos, right_blendfac;
208 REAL range;
209
210 /* locate the blend positions surrounding this position */
211 while (position > brush->blendpos[i])
212 i++;
213
214 /* interpolate between the blend positions */
215 left_blendpos = brush->blendpos[i-1];
216 left_blendfac = brush->blendfac[i-1];
217 right_blendpos = brush->blendpos[i];
218 right_blendfac = brush->blendfac[i];
219 range = right_blendpos - left_blendpos;
220 blendfac = (left_blendfac * (right_blendpos - position) +
221 right_blendfac * (position - left_blendpos)) / range;
222 }
223 return blend_colors(brush->startcolor, brush->endcolor, blendfac);
224}
225
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500226static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
227{
228 switch (brush->bt)
229 {
230 case BrushTypeLinearGradient:
231 {
232 GpLineGradient *line = (GpLineGradient*)brush;
233 RECT rc;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500234
235 SelectClipPath(graphics->hdc, RGN_AND);
236 if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
237 {
238 GpPointF endpointsf[2];
239 POINT endpointsi[2];
240 POINT poly[4];
241
242 SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
243
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500244 endpointsf[0] = line->startpoint;
245 endpointsf[1] = line->endpoint;
246 transform_and_round_points(graphics, endpointsi, endpointsf, 2);
247
248 if (abs(endpointsi[0].x-endpointsi[1].x) > abs(endpointsi[0].y-endpointsi[1].y))
249 {
250 /* vertical-ish gradient */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500251 int startx, endx; /* x co-ordinates of endpoints shifted to intersect the top of the visible rectangle */
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500252 int startbottomx; /* x co-ordinate of start point shifted to intersect the bottom of the visible rectangle */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500253 int width;
254 COLORREF col;
255 HBRUSH hbrush, hprevbrush;
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500256 int leftx, rightx; /* x co-ordinates where the leftmost and rightmost gradient lines hit the top of the visible rectangle */
257 int x;
258 int tilt; /* horizontal distance covered by a gradient line */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500259
260 startx = roundr((rc.top - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
261 endx = roundr((rc.top - endpointsf[1].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[1].X);
262 width = endx - startx;
263 startbottomx = roundr((rc.bottom - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500264 tilt = startx - startbottomx;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500265
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500266 if (startx >= startbottomx)
267 {
268 leftx = rc.left;
269 rightx = rc.right + tilt;
270 }
271 else
272 {
273 leftx = rc.left + tilt;
274 rightx = rc.right;
275 }
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500276
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500277 poly[0].y = rc.bottom;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500278 poly[1].y = rc.top;
279 poly[2].y = rc.top;
280 poly[3].y = rc.bottom;
281
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500282 for (x=leftx; x<=rightx; x++)
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500283 {
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500284 ARGB argb = blend_line_gradient(line, (x-startx)/(REAL)width);
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500285 col = ARGB2COLORREF(argb);
286 hbrush = CreateSolidBrush(col);
287 hprevbrush = SelectObject(graphics->hdc, hbrush);
Vincent Povirkcb478a32009-05-01 15:37:35 -0500288 poly[0].x = x - tilt - 1;
289 poly[1].x = x - 1;
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500290 poly[2].x = x;
291 poly[3].x = x - tilt;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500292 Polygon(graphics->hdc, poly, 4);
293 SelectObject(graphics->hdc, hprevbrush);
294 DeleteObject(hbrush);
295 }
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500296 }
297 else if (endpointsi[0].y != endpointsi[1].y)
298 {
299 /* horizontal-ish gradient */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500300 int starty, endy; /* y co-ordinates of endpoints shifted to intersect the left of the visible rectangle */
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500301 int startrighty; /* y co-ordinate of start point shifted to intersect the right of the visible rectangle */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500302 int height;
303 COLORREF col;
304 HBRUSH hbrush, hprevbrush;
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500305 int topy, bottomy; /* y co-ordinates where the topmost and bottommost gradient lines hit the left of the visible rectangle */
306 int y;
307 int tilt; /* vertical distance covered by a gradient line */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500308
309 starty = roundr((rc.left - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
310 endy = roundr((rc.left - endpointsf[1].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[1].Y);
311 height = endy - starty;
312 startrighty = roundr((rc.right - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500313 tilt = starty - startrighty;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500314
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500315 if (starty >= startrighty)
316 {
317 topy = rc.top;
318 bottomy = rc.bottom + tilt;
319 }
320 else
321 {
322 topy = rc.top + tilt;
323 bottomy = rc.bottom;
324 }
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500325
326 poly[0].x = rc.right;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500327 poly[1].x = rc.left;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500328 poly[2].x = rc.left;
329 poly[3].x = rc.right;
330
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500331 for (y=topy; y<=bottomy; y++)
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500332 {
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500333 ARGB argb = blend_line_gradient(line, (y-starty)/(REAL)height);
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500334 col = ARGB2COLORREF(argb);
335 hbrush = CreateSolidBrush(col);
336 hprevbrush = SelectObject(graphics->hdc, hbrush);
Vincent Povirkcb478a32009-05-01 15:37:35 -0500337 poly[0].y = y - tilt - 1;
338 poly[1].y = y - 1;
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500339 poly[2].y = y;
340 poly[3].y = y - tilt;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500341 Polygon(graphics->hdc, poly, 4);
342 SelectObject(graphics->hdc, hprevbrush);
343 DeleteObject(hbrush);
344 }
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500345 }
346 /* else startpoint == endpoint */
347 }
348 break;
349 }
Vincent Povirk60167df2009-05-20 11:24:18 -0500350 case BrushTypeSolidColor:
351 {
352 GpSolidFill *fill = (GpSolidFill*)brush;
353 if (fill->bmp)
354 {
355 RECT rc;
356 /* partially transparent fill */
357
358 SelectClipPath(graphics->hdc, RGN_AND);
359 if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
360 {
361 HDC hdc = CreateCompatibleDC(NULL);
362 HBITMAP oldbmp;
363 BLENDFUNCTION bf;
364
365 if (!hdc) break;
366
367 oldbmp = SelectObject(hdc, fill->bmp);
368
369 bf.BlendOp = AC_SRC_OVER;
370 bf.BlendFlags = 0;
371 bf.SourceConstantAlpha = 255;
372 bf.AlphaFormat = AC_SRC_ALPHA;
373
374 GdiAlphaBlend(graphics->hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, hdc, 0, 0, 1, 1, bf);
375
376 SelectObject(hdc, oldbmp);
377 DeleteDC(hdc);
378 }
379
380 break;
381 }
382 /* else fall through */
383 }
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500384 default:
385 SelectObject(graphics->hdc, brush->gdibrush);
386 FillPath(graphics->hdc);
387 break;
388 }
389}
390
Evan Stade72ab72c502007-06-18 16:55:51 -0700391/* GdipDrawPie/GdipFillPie helper function */
Evan Stade4c424b32007-07-24 17:18:54 -0700392static void draw_pie(GpGraphics *graphics, REAL x, REAL y, REAL width,
393 REAL height, REAL startAngle, REAL sweepAngle)
Evan Stade72ab72c502007-06-18 16:55:51 -0700394{
Evan Staded01c6972007-07-23 20:24:53 -0700395 GpPointF ptf[4];
396 POINT pti[4];
Evan Stade72ab72c502007-06-18 16:55:51 -0700397
Evan Staded01c6972007-07-23 20:24:53 -0700398 ptf[0].X = x;
399 ptf[0].Y = y;
400 ptf[1].X = x + width;
401 ptf[1].Y = y + height;
Evan Stade72ab72c502007-06-18 16:55:51 -0700402
Evan Staded01c6972007-07-23 20:24:53 -0700403 deg2xy(startAngle+sweepAngle, x + width / 2.0, y + width / 2.0, &ptf[2].X, &ptf[2].Y);
404 deg2xy(startAngle, x + width / 2.0, y + width / 2.0, &ptf[3].X, &ptf[3].Y);
Evan Stade72ab72c502007-06-18 16:55:51 -0700405
Evan Staded01c6972007-07-23 20:24:53 -0700406 transform_and_round_points(graphics, pti, ptf, 4);
407
408 Pie(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y, pti[2].x,
409 pti[2].y, pti[3].x, pti[3].y);
Evan Stade72ab72c502007-06-18 16:55:51 -0700410}
411
Evan Stade5128e5d2007-07-07 13:20:41 -0700412/* Draws the linecap the specified color and size on the hdc. The linecap is in
Evan Stade8c5bcef2007-07-20 17:50:02 -0700413 * direction of the line from x1, y1 to x2, y2 and is anchored on x2, y2. Probably
414 * should not be called on an hdc that has a path you care about. */
Evan Staded01c6972007-07-23 20:24:53 -0700415static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL size,
Evan Stade85b5df42007-07-19 18:22:51 -0700416 const GpCustomLineCap *custom, REAL x1, REAL y1, REAL x2, REAL y2)
Evan Stade5128e5d2007-07-07 13:20:41 -0700417{
Evan Stadeb7053b72007-07-24 17:18:58 -0700418 HGDIOBJ oldbrush = NULL, oldpen = NULL;
Evan Stade85b5df42007-07-19 18:22:51 -0700419 GpMatrix *matrix = NULL;
Evan Stadeb7053b72007-07-24 17:18:58 -0700420 HBRUSH brush = NULL;
421 HPEN pen = NULL;
Evan Staded01c6972007-07-23 20:24:53 -0700422 PointF ptf[4], *custptf = NULL;
Evan Stade85b5df42007-07-19 18:22:51 -0700423 POINT pt[4], *custpt = NULL;
424 BYTE *tp = NULL;
Evan Staded01c6972007-07-23 20:24:53 -0700425 REAL theta, dsmall, dbig, dx, dy = 0.0;
Evan Stade85b5df42007-07-19 18:22:51 -0700426 INT i, count;
427 LOGBRUSH lb;
Evan Stadeb7053b72007-07-24 17:18:58 -0700428 BOOL customstroke;
Evan Stade5128e5d2007-07-07 13:20:41 -0700429
Evan Stade818051d2007-07-20 17:50:14 -0700430 if((x1 == x2) && (y1 == y2))
Evan Stade5128e5d2007-07-07 13:20:41 -0700431 return;
432
Evan Stade818051d2007-07-20 17:50:14 -0700433 theta = gdiplus_atan2(y2 - y1, x2 - x1);
434
Evan Stadeb7053b72007-07-24 17:18:58 -0700435 customstroke = (cap == LineCapCustom) && custom && (!custom->fill);
436 if(!customstroke){
437 brush = CreateSolidBrush(color);
438 lb.lbStyle = BS_SOLID;
439 lb.lbColor = color;
440 lb.lbHatch = 0;
441 pen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT |
442 PS_JOIN_MITER, 1, &lb, 0,
443 NULL);
444 oldbrush = SelectObject(graphics->hdc, brush);
445 oldpen = SelectObject(graphics->hdc, pen);
446 }
Evan Stade5128e5d2007-07-07 13:20:41 -0700447
448 switch(cap){
449 case LineCapFlat:
450 break;
451 case LineCapSquare:
452 case LineCapSquareAnchor:
453 case LineCapDiamondAnchor:
454 size = size * (cap & LineCapNoAnchor ? ANCHOR_WIDTH : 1.0) / 2.0;
455 if(cap == LineCapDiamondAnchor){
456 dsmall = cos(theta + M_PI_2) * size;
457 dbig = sin(theta + M_PI_2) * size;
458 }
459 else{
460 dsmall = cos(theta + M_PI_4) * size;
461 dbig = sin(theta + M_PI_4) * size;
462 }
463
Evan Staded01c6972007-07-23 20:24:53 -0700464 ptf[0].X = x2 - dsmall;
465 ptf[1].X = x2 + dbig;
Evan Stade5128e5d2007-07-07 13:20:41 -0700466
Evan Staded01c6972007-07-23 20:24:53 -0700467 ptf[0].Y = y2 - dbig;
468 ptf[3].Y = y2 + dsmall;
Evan Stade5128e5d2007-07-07 13:20:41 -0700469
Evan Staded01c6972007-07-23 20:24:53 -0700470 ptf[1].Y = y2 - dsmall;
471 ptf[2].Y = y2 + dbig;
Evan Stade5128e5d2007-07-07 13:20:41 -0700472
Evan Staded01c6972007-07-23 20:24:53 -0700473 ptf[3].X = x2 - dbig;
474 ptf[2].X = x2 + dsmall;
Evan Stade5128e5d2007-07-07 13:20:41 -0700475
Evan Staded01c6972007-07-23 20:24:53 -0700476 transform_and_round_points(graphics, pt, ptf, 4);
477 Polygon(graphics->hdc, pt, 4);
Evan Stade5128e5d2007-07-07 13:20:41 -0700478
479 break;
480 case LineCapArrowAnchor:
481 size = size * 4.0 / sqrt(3.0);
482
Evan Stadeea5898c2007-07-19 18:22:47 -0700483 dx = cos(M_PI / 6.0 + theta) * size;
484 dy = sin(M_PI / 6.0 + theta) * size;
Evan Stade5128e5d2007-07-07 13:20:41 -0700485
Evan Staded01c6972007-07-23 20:24:53 -0700486 ptf[0].X = x2 - dx;
487 ptf[0].Y = y2 - dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700488
Evan Stadeea5898c2007-07-19 18:22:47 -0700489 dx = cos(- M_PI / 6.0 + theta) * size;
490 dy = sin(- M_PI / 6.0 + theta) * size;
Evan Stade5128e5d2007-07-07 13:20:41 -0700491
Evan Staded01c6972007-07-23 20:24:53 -0700492 ptf[1].X = x2 - dx;
493 ptf[1].Y = y2 - dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700494
Evan Staded01c6972007-07-23 20:24:53 -0700495 ptf[2].X = x2;
496 ptf[2].Y = y2;
Evan Stade5128e5d2007-07-07 13:20:41 -0700497
Evan Staded01c6972007-07-23 20:24:53 -0700498 transform_and_round_points(graphics, pt, ptf, 3);
499 Polygon(graphics->hdc, pt, 3);
Evan Stade5128e5d2007-07-07 13:20:41 -0700500
501 break;
502 case LineCapRoundAnchor:
503 dx = dy = ANCHOR_WIDTH * size / 2.0;
504
Evan Staded01c6972007-07-23 20:24:53 -0700505 ptf[0].X = x2 - dx;
506 ptf[0].Y = y2 - dy;
507 ptf[1].X = x2 + dx;
508 ptf[1].Y = y2 + dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700509
Evan Staded01c6972007-07-23 20:24:53 -0700510 transform_and_round_points(graphics, pt, ptf, 2);
511 Ellipse(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
512
Evan Stade5128e5d2007-07-07 13:20:41 -0700513 break;
514 case LineCapTriangle:
515 size = size / 2.0;
516 dx = cos(M_PI_2 + theta) * size;
517 dy = sin(M_PI_2 + theta) * size;
518
Evan Staded01c6972007-07-23 20:24:53 -0700519 ptf[0].X = x2 - dx;
520 ptf[0].Y = y2 - dy;
521 ptf[1].X = x2 + dx;
522 ptf[1].Y = y2 + dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700523
Evan Stadeea5898c2007-07-19 18:22:47 -0700524 dx = cos(theta) * size;
525 dy = sin(theta) * size;
Evan Stade5128e5d2007-07-07 13:20:41 -0700526
Evan Staded01c6972007-07-23 20:24:53 -0700527 ptf[2].X = x2 + dx;
528 ptf[2].Y = y2 + dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700529
Evan Staded01c6972007-07-23 20:24:53 -0700530 transform_and_round_points(graphics, pt, ptf, 3);
531 Polygon(graphics->hdc, pt, 3);
Evan Stade5128e5d2007-07-07 13:20:41 -0700532
533 break;
534 case LineCapRound:
Evan Staded01c6972007-07-23 20:24:53 -0700535 dx = dy = size / 2.0;
536
537 ptf[0].X = x2 - dx;
538 ptf[0].Y = y2 - dy;
539 ptf[1].X = x2 + dx;
540 ptf[1].Y = y2 + dy;
541
Evan Stadeea5898c2007-07-19 18:22:47 -0700542 dx = -cos(M_PI_2 + theta) * size;
543 dy = -sin(M_PI_2 + theta) * size;
Evan Stade5128e5d2007-07-07 13:20:41 -0700544
Evan Staded01c6972007-07-23 20:24:53 -0700545 ptf[2].X = x2 - dx;
546 ptf[2].Y = y2 - dy;
547 ptf[3].X = x2 + dx;
548 ptf[3].Y = y2 + dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700549
Evan Staded01c6972007-07-23 20:24:53 -0700550 transform_and_round_points(graphics, pt, ptf, 4);
551 Pie(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x,
552 pt[2].y, pt[3].x, pt[3].y);
Evan Stade5128e5d2007-07-07 13:20:41 -0700553
Evan Stade5128e5d2007-07-07 13:20:41 -0700554 break;
555 case LineCapCustom:
Evan Stade85b5df42007-07-19 18:22:51 -0700556 if(!custom)
557 break;
558
Evan Stade85b5df42007-07-19 18:22:51 -0700559 count = custom->pathdata.Count;
560 custptf = GdipAlloc(count * sizeof(PointF));
561 custpt = GdipAlloc(count * sizeof(POINT));
562 tp = GdipAlloc(count);
563
564 if(!custptf || !custpt || !tp || (GdipCreateMatrix(&matrix) != Ok))
565 goto custend;
566
567 memcpy(custptf, custom->pathdata.Points, count * sizeof(PointF));
568
569 GdipScaleMatrix(matrix, size, size, MatrixOrderAppend);
570 GdipRotateMatrix(matrix, (180.0 / M_PI) * (theta - M_PI_2),
571 MatrixOrderAppend);
572 GdipTranslateMatrix(matrix, x2, y2, MatrixOrderAppend);
573 GdipTransformMatrixPoints(matrix, custptf, count);
574
Evan Staded01c6972007-07-23 20:24:53 -0700575 transform_and_round_points(graphics, custpt, custptf, count);
576
577 for(i = 0; i < count; i++)
Evan Stade85b5df42007-07-19 18:22:51 -0700578 tp[i] = convert_path_point_type(custom->pathdata.Types[i]);
Evan Stade85b5df42007-07-19 18:22:51 -0700579
Evan Stade8c5bcef2007-07-20 17:50:02 -0700580 if(custom->fill){
Evan Staded01c6972007-07-23 20:24:53 -0700581 BeginPath(graphics->hdc);
582 PolyDraw(graphics->hdc, custpt, tp, count);
583 EndPath(graphics->hdc);
584 StrokeAndFillPath(graphics->hdc);
Evan Stade8c5bcef2007-07-20 17:50:02 -0700585 }
586 else
Evan Staded01c6972007-07-23 20:24:53 -0700587 PolyDraw(graphics->hdc, custpt, tp, count);
Evan Stade85b5df42007-07-19 18:22:51 -0700588
589custend:
590 GdipFree(custptf);
591 GdipFree(custpt);
592 GdipFree(tp);
593 GdipDeleteMatrix(matrix);
594 break;
Evan Stade5128e5d2007-07-07 13:20:41 -0700595 default:
596 break;
597 }
598
Evan Stadeb7053b72007-07-24 17:18:58 -0700599 if(!customstroke){
600 SelectObject(graphics->hdc, oldbrush);
601 SelectObject(graphics->hdc, oldpen);
602 DeleteObject(brush);
603 DeleteObject(pen);
604 }
Evan Stade5128e5d2007-07-07 13:20:41 -0700605}
606
607/* Shortens the line by the given percent by changing x2, y2.
Evan Stadef56fa322007-07-20 17:50:07 -0700608 * If percent is > 1.0 then the line will change direction.
609 * If percent is negative it can lengthen the line. */
Evan Stade5128e5d2007-07-07 13:20:41 -0700610static void shorten_line_percent(REAL x1, REAL y1, REAL *x2, REAL *y2, REAL percent)
611{
612 REAL dist, theta, dx, dy;
613
614 if((y1 == *y2) && (x1 == *x2))
615 return;
616
Evan Stadef56fa322007-07-20 17:50:07 -0700617 dist = sqrt((*x2 - x1) * (*x2 - x1) + (*y2 - y1) * (*y2 - y1)) * -percent;
Evan Stade818051d2007-07-20 17:50:14 -0700618 theta = gdiplus_atan2((*y2 - y1), (*x2 - x1));
Evan Stade5128e5d2007-07-07 13:20:41 -0700619 dx = cos(theta) * dist;
620 dy = sin(theta) * dist;
621
Evan Stadef56fa322007-07-20 17:50:07 -0700622 *x2 = *x2 + dx;
623 *y2 = *y2 + dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700624}
625
626/* Shortens the line by the given amount by changing x2, y2.
Evan Stadef56fa322007-07-20 17:50:07 -0700627 * If the amount is greater than the distance, the line will become length 0.
628 * If the amount is negative, it can lengthen the line. */
Evan Stade5128e5d2007-07-07 13:20:41 -0700629static void shorten_line_amt(REAL x1, REAL y1, REAL *x2, REAL *y2, REAL amt)
630{
631 REAL dx, dy, percent;
632
633 dx = *x2 - x1;
634 dy = *y2 - y1;
635 if(dx == 0 && dy == 0)
636 return;
637
638 percent = amt / sqrt(dx * dx + dy * dy);
639 if(percent >= 1.0){
640 *x2 = x1;
641 *y2 = y1;
642 return;
643 }
644
645 shorten_line_percent(x1, y1, x2, y2, percent);
646}
647
648/* Draws lines between the given points, and if caps is true then draws an endcap
Evan Stade88ab6d32007-08-02 17:53:13 -0700649 * at the end of the last line. */
Evan Staded01c6972007-07-23 20:24:53 -0700650static GpStatus draw_polyline(GpGraphics *graphics, GpPen *pen,
651 GDIPCONST GpPointF * pt, INT count, BOOL caps)
Evan Stade5128e5d2007-07-07 13:20:41 -0700652{
Evan Stadea84b5672007-07-20 17:50:11 -0700653 POINT *pti = NULL;
654 GpPointF *ptcopy = NULL;
Evan Stade6f4ab522007-07-11 18:07:44 -0700655 GpStatus status = GenericError;
656
657 if(!count)
658 return Ok;
659
660 pti = GdipAlloc(count * sizeof(POINT));
Evan Stadea84b5672007-07-20 17:50:11 -0700661 ptcopy = GdipAlloc(count * sizeof(GpPointF));
Evan Stade6f4ab522007-07-11 18:07:44 -0700662
Evan Stadea84b5672007-07-20 17:50:11 -0700663 if(!pti || !ptcopy){
Evan Stade6f4ab522007-07-11 18:07:44 -0700664 status = OutOfMemory;
665 goto end;
666 }
Evan Stade5128e5d2007-07-07 13:20:41 -0700667
Evan Stadec3e8af42007-07-24 17:18:50 -0700668 memcpy(ptcopy, pt, count * sizeof(GpPointF));
Evan Staded01c6972007-07-23 20:24:53 -0700669
Evan Stadec3e8af42007-07-24 17:18:50 -0700670 if(caps){
Evan Stade5128e5d2007-07-07 13:20:41 -0700671 if(pen->endcap == LineCapArrowAnchor)
Evan Stadea84b5672007-07-20 17:50:11 -0700672 shorten_line_amt(ptcopy[count-2].X, ptcopy[count-2].Y,
673 &ptcopy[count-1].X, &ptcopy[count-1].Y, pen->width);
Evan Stadef56fa322007-07-20 17:50:07 -0700674 else if((pen->endcap == LineCapCustom) && pen->customend)
Evan Stadea84b5672007-07-20 17:50:11 -0700675 shorten_line_amt(ptcopy[count-2].X, ptcopy[count-2].Y,
676 &ptcopy[count-1].X, &ptcopy[count-1].Y,
677 pen->customend->inset * pen->width);
678
679 if(pen->startcap == LineCapArrowAnchor)
680 shorten_line_amt(ptcopy[1].X, ptcopy[1].Y,
681 &ptcopy[0].X, &ptcopy[0].Y, pen->width);
682 else if((pen->startcap == LineCapCustom) && pen->customstart)
683 shorten_line_amt(ptcopy[1].X, ptcopy[1].Y,
684 &ptcopy[0].X, &ptcopy[0].Y,
Evan Stade02887b62007-08-07 18:42:44 -0700685 pen->customstart->inset * pen->width);
Evan Stade5128e5d2007-07-07 13:20:41 -0700686
Evan Staded01c6972007-07-23 20:24:53 -0700687 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
Evan Stadea84b5672007-07-20 17:50:11 -0700688 pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X, pt[count - 1].Y);
Evan Staded01c6972007-07-23 20:24:53 -0700689 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
Michael Stefaniuc1f26b142007-12-31 17:29:57 +0100690 pt[1].X, pt[1].Y, pt[0].X, pt[0].Y);
Evan Stade5128e5d2007-07-07 13:20:41 -0700691 }
Evan Stadec3e8af42007-07-24 17:18:50 -0700692
693 transform_and_round_points(graphics, pti, ptcopy, count);
Evan Stade5128e5d2007-07-07 13:20:41 -0700694
Royal Chanc86f2c22008-02-10 12:40:52 -0800695 if(Polyline(graphics->hdc, pti, count))
696 status = Ok;
Evan Stade6f4ab522007-07-11 18:07:44 -0700697
698end:
Evan Stade5128e5d2007-07-07 13:20:41 -0700699 GdipFree(pti);
Evan Stadea84b5672007-07-20 17:50:11 -0700700 GdipFree(ptcopy);
Evan Stade6f4ab522007-07-11 18:07:44 -0700701
702 return status;
Evan Stade5128e5d2007-07-07 13:20:41 -0700703}
704
Evan Stade69a807c2007-07-06 16:13:49 -0700705/* Conducts a linear search to find the bezier points that will back off
706 * the endpoint of the curve by a distance of amt. Linear search works
707 * better than binary in this case because there are multiple solutions,
708 * and binary searches often find a bad one. I don't think this is what
709 * Windows does but short of rendering the bezier without GDI's help it's
Evan Stadea84b5672007-07-20 17:50:11 -0700710 * the best we can do. If rev then work from the start of the passed points
711 * instead of the end. */
712static void shorten_bezier_amt(GpPointF * pt, REAL amt, BOOL rev)
Evan Stade69a807c2007-07-06 16:13:49 -0700713{
714 GpPointF origpt[4];
Evan Stadea84b5672007-07-20 17:50:11 -0700715 REAL percent = 0.00, dx, dy, origx, origy, diff = -1.0;
716 INT i, first = 0, second = 1, third = 2, fourth = 3;
Evan Stade69a807c2007-07-06 16:13:49 -0700717
Evan Stadea84b5672007-07-20 17:50:11 -0700718 if(rev){
719 first = 3;
720 second = 2;
721 third = 1;
722 fourth = 0;
723 }
724
725 origx = pt[fourth].X;
726 origy = pt[fourth].Y;
Evan Stade69a807c2007-07-06 16:13:49 -0700727 memcpy(origpt, pt, sizeof(GpPointF) * 4);
728
729 for(i = 0; (i < MAX_ITERS) && (diff < amt); i++){
730 /* reset bezier points to original values */
731 memcpy(pt, origpt, sizeof(GpPointF) * 4);
732 /* Perform magic on bezier points. Order is important here.*/
Evan Stadea84b5672007-07-20 17:50:11 -0700733 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent);
734 shorten_line_percent(pt[second].X, pt[second].Y, &pt[third].X, &pt[third].Y, percent);
735 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent);
736 shorten_line_percent(pt[first].X, pt[first].Y, &pt[second].X, &pt[second].Y, percent);
737 shorten_line_percent(pt[second].X, pt[second].Y, &pt[third].X, &pt[third].Y, percent);
738 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent);
Evan Stade69a807c2007-07-06 16:13:49 -0700739
Evan Stadea84b5672007-07-20 17:50:11 -0700740 dx = pt[fourth].X - origx;
741 dy = pt[fourth].Y - origy;
Evan Stade69a807c2007-07-06 16:13:49 -0700742
743 diff = sqrt(dx * dx + dy * dy);
744 percent += 0.0005 * amt;
745 }
746}
747
748/* Draws bezier curves between given points, and if caps is true then draws an
Evan Stade88ab6d32007-08-02 17:53:13 -0700749 * endcap at the end of the last line. */
Evan Staded01c6972007-07-23 20:24:53 -0700750static GpStatus draw_polybezier(GpGraphics *graphics, GpPen *pen,
751 GDIPCONST GpPointF * pt, INT count, BOOL caps)
Evan Stade69a807c2007-07-06 16:13:49 -0700752{
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700753 POINT *pti;
Evan Stadea84b5672007-07-20 17:50:11 -0700754 GpPointF *ptcopy;
Evan Stadefa312172007-07-11 18:07:39 -0700755 GpStatus status = GenericError;
756
757 if(!count)
758 return Ok;
759
760 pti = GdipAlloc(count * sizeof(POINT));
Evan Stadea84b5672007-07-20 17:50:11 -0700761 ptcopy = GdipAlloc(count * sizeof(GpPointF));
Evan Stadefa312172007-07-11 18:07:39 -0700762
Evan Stadea84b5672007-07-20 17:50:11 -0700763 if(!pti || !ptcopy){
Evan Stadefa312172007-07-11 18:07:39 -0700764 status = OutOfMemory;
765 goto end;
766 }
Evan Stade69a807c2007-07-06 16:13:49 -0700767
Evan Stadec3e8af42007-07-24 17:18:50 -0700768 memcpy(ptcopy, pt, count * sizeof(GpPointF));
Evan Staded01c6972007-07-23 20:24:53 -0700769
Evan Stadec3e8af42007-07-24 17:18:50 -0700770 if(caps){
Evan Stade69a807c2007-07-06 16:13:49 -0700771 if(pen->endcap == LineCapArrowAnchor)
Evan Stadea84b5672007-07-20 17:50:11 -0700772 shorten_bezier_amt(&ptcopy[count-4], pen->width, FALSE);
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700773 else if((pen->endcap == LineCapCustom) && pen->customend)
774 shorten_bezier_amt(&ptcopy[count-4], pen->width * pen->customend->inset,
775 FALSE);
Evan Stade69a807c2007-07-06 16:13:49 -0700776
Evan Stadea84b5672007-07-20 17:50:11 -0700777 if(pen->startcap == LineCapArrowAnchor)
778 shorten_bezier_amt(ptcopy, pen->width, TRUE);
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700779 else if((pen->startcap == LineCapCustom) && pen->customstart)
Evan Stade02887b62007-08-07 18:42:44 -0700780 shorten_bezier_amt(ptcopy, pen->width * pen->customstart->inset, TRUE);
Evan Stadea84b5672007-07-20 17:50:11 -0700781
Evan Stade55d70e82007-07-11 18:08:26 -0700782 /* the direction of the line cap is parallel to the direction at the
783 * end of the bezier (which, if it has been shortened, is not the same
784 * as the direction from pt[count-2] to pt[count-1]) */
Evan Staded01c6972007-07-23 20:24:53 -0700785 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
Evan Stadea84b5672007-07-20 17:50:11 -0700786 pt[count - 1].X - (ptcopy[count - 1].X - ptcopy[count - 2].X),
787 pt[count - 1].Y - (ptcopy[count - 1].Y - ptcopy[count - 2].Y),
Evan Stade55d70e82007-07-11 18:08:26 -0700788 pt[count - 1].X, pt[count - 1].Y);
Evan Stadea84b5672007-07-20 17:50:11 -0700789
Evan Staded01c6972007-07-23 20:24:53 -0700790 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
Evan Stadea84b5672007-07-20 17:50:11 -0700791 pt[0].X - (ptcopy[0].X - ptcopy[1].X),
792 pt[0].Y - (ptcopy[0].Y - ptcopy[1].Y), pt[0].X, pt[0].Y);
Evan Stade69a807c2007-07-06 16:13:49 -0700793 }
Evan Stadec3e8af42007-07-24 17:18:50 -0700794
795 transform_and_round_points(graphics, pti, ptcopy, count);
Evan Stade69a807c2007-07-06 16:13:49 -0700796
Evan Staded01c6972007-07-23 20:24:53 -0700797 PolyBezier(graphics->hdc, pti, count);
Evan Stadefa312172007-07-11 18:07:39 -0700798
799 status = Ok;
800
801end:
Evan Stade69a807c2007-07-06 16:13:49 -0700802 GdipFree(pti);
Evan Stadea84b5672007-07-20 17:50:11 -0700803 GdipFree(ptcopy);
Evan Stadefa312172007-07-11 18:07:39 -0700804
805 return status;
Evan Stade69a807c2007-07-06 16:13:49 -0700806}
807
Evan Stade9d5f5682007-07-11 18:07:34 -0700808/* Draws a combination of bezier curves and lines between points. */
Evan Staded01c6972007-07-23 20:24:53 -0700809static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF * pt,
Evan Stade9d5f5682007-07-11 18:07:34 -0700810 GDIPCONST BYTE * types, INT count, BOOL caps)
811{
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700812 POINT *pti = GdipAlloc(count * sizeof(POINT));
Evan Stade9d5f5682007-07-11 18:07:34 -0700813 BYTE *tp = GdipAlloc(count);
Evan Stadea84b5672007-07-20 17:50:11 -0700814 GpPointF *ptcopy = GdipAlloc(count * sizeof(GpPointF));
Evan Stadea84b5672007-07-20 17:50:11 -0700815 INT i, j;
Evan Stade9d5f5682007-07-11 18:07:34 -0700816 GpStatus status = GenericError;
817
818 if(!count){
819 status = Ok;
820 goto end;
821 }
Evan Stadea84b5672007-07-20 17:50:11 -0700822 if(!pti || !tp || !ptcopy){
Evan Stade9d5f5682007-07-11 18:07:34 -0700823 status = OutOfMemory;
824 goto end;
825 }
826
Evan Stadea84b5672007-07-20 17:50:11 -0700827 for(i = 1; i < count; i++){
Evan Stade9d5f5682007-07-11 18:07:34 -0700828 if((types[i] & PathPointTypePathTypeMask) == PathPointTypeBezier){
829 if((i + 2 >= count) || !(types[i + 1] & PathPointTypeBezier)
830 || !(types[i + 1] & PathPointTypeBezier)){
831 ERR("Bad bezier points\n");
832 goto end;
833 }
Evan Stade9d5f5682007-07-11 18:07:34 -0700834 i += 2;
835 }
836 }
837
Evan Stadec3e8af42007-07-24 17:18:50 -0700838 memcpy(ptcopy, pt, count * sizeof(GpPointF));
839
Evan Stade9e883472007-07-13 17:51:49 -0700840 /* If we are drawing caps, go through the points and adjust them accordingly,
841 * and draw the caps. */
842 if(caps){
843 switch(types[count - 1] & PathPointTypePathTypeMask){
844 case PathPointTypeBezier:
Evan Stade9e883472007-07-13 17:51:49 -0700845 if(pen->endcap == LineCapArrowAnchor)
Evan Stadea84b5672007-07-20 17:50:11 -0700846 shorten_bezier_amt(&ptcopy[count - 4], pen->width, FALSE);
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700847 else if((pen->endcap == LineCapCustom) && pen->customend)
848 shorten_bezier_amt(&ptcopy[count - 4],
849 pen->width * pen->customend->inset, FALSE);
Evan Stade9e883472007-07-13 17:51:49 -0700850
Evan Staded01c6972007-07-23 20:24:53 -0700851 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
Evan Stadea84b5672007-07-20 17:50:11 -0700852 pt[count - 1].X - (ptcopy[count - 1].X - ptcopy[count - 2].X),
853 pt[count - 1].Y - (ptcopy[count - 1].Y - ptcopy[count - 2].Y),
Evan Stade9e883472007-07-13 17:51:49 -0700854 pt[count - 1].X, pt[count - 1].Y);
855
Evan Stade9e883472007-07-13 17:51:49 -0700856 break;
Evan Stade9e883472007-07-13 17:51:49 -0700857 case PathPointTypeLine:
858 if(pen->endcap == LineCapArrowAnchor)
Evan Stadea84b5672007-07-20 17:50:11 -0700859 shorten_line_amt(ptcopy[count - 2].X, ptcopy[count - 2].Y,
860 &ptcopy[count - 1].X, &ptcopy[count - 1].Y,
Evan Stade9e883472007-07-13 17:51:49 -0700861 pen->width);
Evan Stadef56fa322007-07-20 17:50:07 -0700862 else if((pen->endcap == LineCapCustom) && pen->customend)
Evan Stadea84b5672007-07-20 17:50:11 -0700863 shorten_line_amt(ptcopy[count - 2].X, ptcopy[count - 2].Y,
864 &ptcopy[count - 1].X, &ptcopy[count - 1].Y,
Evan Stadef56fa322007-07-20 17:50:07 -0700865 pen->customend->inset * pen->width);
Evan Stade9e883472007-07-13 17:51:49 -0700866
Evan Staded01c6972007-07-23 20:24:53 -0700867 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
Evan Stade85b5df42007-07-19 18:22:51 -0700868 pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X,
869 pt[count - 1].Y);
Evan Stade9e883472007-07-13 17:51:49 -0700870
Evan Stade9e883472007-07-13 17:51:49 -0700871 break;
872 default:
873 ERR("Bad path last point\n");
874 goto end;
Evan Stade9d5f5682007-07-11 18:07:34 -0700875 }
Evan Stadea84b5672007-07-20 17:50:11 -0700876
877 /* Find start of points */
878 for(j = 1; j < count && ((types[j] & PathPointTypePathTypeMask)
879 == PathPointTypeStart); j++);
880
881 switch(types[j] & PathPointTypePathTypeMask){
882 case PathPointTypeBezier:
883 if(pen->startcap == LineCapArrowAnchor)
884 shorten_bezier_amt(&ptcopy[j - 1], pen->width, TRUE);
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700885 else if((pen->startcap == LineCapCustom) && pen->customstart)
886 shorten_bezier_amt(&ptcopy[j - 1],
Evan Stade02887b62007-08-07 18:42:44 -0700887 pen->width * pen->customstart->inset, TRUE);
Evan Stadea84b5672007-07-20 17:50:11 -0700888
Evan Staded01c6972007-07-23 20:24:53 -0700889 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
Evan Stadea84b5672007-07-20 17:50:11 -0700890 pt[j - 1].X - (ptcopy[j - 1].X - ptcopy[j].X),
891 pt[j - 1].Y - (ptcopy[j - 1].Y - ptcopy[j].Y),
892 pt[j - 1].X, pt[j - 1].Y);
893
894 break;
895 case PathPointTypeLine:
896 if(pen->startcap == LineCapArrowAnchor)
897 shorten_line_amt(ptcopy[j].X, ptcopy[j].Y,
898 &ptcopy[j - 1].X, &ptcopy[j - 1].Y,
899 pen->width);
900 else if((pen->startcap == LineCapCustom) && pen->customstart)
901 shorten_line_amt(ptcopy[j].X, ptcopy[j].Y,
902 &ptcopy[j - 1].X, &ptcopy[j - 1].Y,
903 pen->customstart->inset * pen->width);
904
Evan Stade629e0132007-07-27 16:07:50 -0700905 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
Evan Stadea84b5672007-07-20 17:50:11 -0700906 pt[j].X, pt[j].Y, pt[j - 1].X,
907 pt[j - 1].Y);
908
909 break;
910 default:
911 ERR("Bad path points\n");
912 goto end;
913 }
Evan Stade9d5f5682007-07-11 18:07:34 -0700914 }
Evan Stadec3e8af42007-07-24 17:18:50 -0700915
916 transform_and_round_points(graphics, pti, ptcopy, count);
Evan Stade9d5f5682007-07-11 18:07:34 -0700917
918 for(i = 0; i < count; i++){
919 tp[i] = convert_path_point_type(types[i]);
920 }
921
Evan Staded01c6972007-07-23 20:24:53 -0700922 PolyDraw(graphics->hdc, pti, tp, count);
Evan Stade9d5f5682007-07-11 18:07:34 -0700923
924 status = Ok;
925
926end:
927 GdipFree(pti);
Evan Stadea84b5672007-07-20 17:50:11 -0700928 GdipFree(ptcopy);
Evan Stade9d5f5682007-07-11 18:07:34 -0700929 GdipFree(tp);
930
931 return status;
932}
933
Vincent Povirk08aa0ca2008-11-24 15:01:47 -0600934GpStatus trace_path(GpGraphics *graphics, GpPath *path)
935{
936 GpStatus result;
937
938 BeginPath(graphics->hdc);
939 result = draw_poly(graphics, NULL, path->pathdata.Points,
940 path->pathdata.Types, path->pathdata.Count, FALSE);
941 EndPath(graphics->hdc);
942 return result;
943}
944
Andrew Eikum632aef32009-07-05 17:04:20 -0500945typedef struct _GraphicsContainerItem {
946 struct list entry;
947 GraphicsContainer contid;
948
949 SmoothingMode smoothing;
950 CompositingQuality compqual;
951 InterpolationMode interpolation;
952 CompositingMode compmode;
953 TextRenderingHint texthint;
954 REAL scale;
955 GpUnit unit;
956 PixelOffsetMode pixeloffset;
957 UINT textcontrast;
958 GpMatrix* worldtrans;
959 GpRegion* clip;
960} GraphicsContainerItem;
961
962static GpStatus init_container(GraphicsContainerItem** container,
963 GDIPCONST GpGraphics* graphics){
964 GpStatus sts;
965
966 *container = GdipAlloc(sizeof(GraphicsContainerItem));
967 if(!(*container))
968 return OutOfMemory;
969
970 (*container)->contid = graphics->contid + 1;
971
972 (*container)->smoothing = graphics->smoothing;
973 (*container)->compqual = graphics->compqual;
974 (*container)->interpolation = graphics->interpolation;
975 (*container)->compmode = graphics->compmode;
976 (*container)->texthint = graphics->texthint;
977 (*container)->scale = graphics->scale;
978 (*container)->unit = graphics->unit;
979 (*container)->textcontrast = graphics->textcontrast;
980 (*container)->pixeloffset = graphics->pixeloffset;
981
982 sts = GdipCloneMatrix(graphics->worldtrans, &(*container)->worldtrans);
983 if(sts != Ok){
984 GdipFree(*container);
985 *container = NULL;
986 return sts;
987 }
988
989 sts = GdipCloneRegion(graphics->clip, &(*container)->clip);
990 if(sts != Ok){
991 GdipDeleteMatrix((*container)->worldtrans);
992 GdipFree(*container);
993 *container = NULL;
994 return sts;
995 }
996
997 return Ok;
998}
999
1000static void delete_container(GraphicsContainerItem* container){
1001 GdipDeleteMatrix(container->worldtrans);
1002 GdipDeleteRegion(container->clip);
1003 GdipFree(container);
1004}
1005
1006static GpStatus restore_container(GpGraphics* graphics,
1007 GDIPCONST GraphicsContainerItem* container){
1008 GpStatus sts;
1009 GpMatrix *newTrans;
1010 GpRegion *newClip;
1011
1012 sts = GdipCloneMatrix(container->worldtrans, &newTrans);
1013 if(sts != Ok)
1014 return sts;
1015
1016 sts = GdipCloneRegion(container->clip, &newClip);
1017 if(sts != Ok){
1018 GdipDeleteMatrix(newTrans);
1019 return sts;
1020 }
1021
1022 GdipDeleteMatrix(graphics->worldtrans);
1023 graphics->worldtrans = newTrans;
1024
1025 GdipDeleteRegion(graphics->clip);
1026 graphics->clip = newClip;
1027
1028 graphics->contid = container->contid - 1;
1029
1030 graphics->smoothing = container->smoothing;
1031 graphics->compqual = container->compqual;
1032 graphics->interpolation = container->interpolation;
1033 graphics->compmode = container->compmode;
1034 graphics->texthint = container->texthint;
1035 graphics->scale = container->scale;
1036 graphics->unit = container->unit;
1037 graphics->textcontrast = container->textcontrast;
1038 graphics->pixeloffset = container->pixeloffset;
1039
1040 return Ok;
1041}
1042
Evan Staded50be492007-06-11 11:54:03 -07001043GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics)
1044{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001045 TRACE("(%p, %p)\n", hdc, graphics);
1046
Stefan Leichterbfffb4f2007-12-23 10:56:32 +01001047 return GdipCreateFromHDC2(hdc, NULL, graphics);
1048}
1049
1050GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **graphics)
1051{
Evan Stadef30732f2007-07-24 17:18:47 -07001052 GpStatus retval;
1053
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001054 TRACE("(%p, %p, %p)\n", hdc, hDevice, graphics);
1055
Stefan Leichterbfffb4f2007-12-23 10:56:32 +01001056 if(hDevice != NULL) {
Ken Sharpe3f48592009-06-09 21:48:05 +01001057 FIXME("Don't know how to handle parameter hDevice\n");
Stefan Leichterbfffb4f2007-12-23 10:56:32 +01001058 return NotImplemented;
1059 }
1060
Evan Staded50be492007-06-11 11:54:03 -07001061 if(hdc == NULL)
1062 return OutOfMemory;
1063
1064 if(graphics == NULL)
1065 return InvalidParameter;
1066
Evan Stade6490dad2007-06-22 19:27:02 -07001067 *graphics = GdipAlloc(sizeof(GpGraphics));
1068 if(!*graphics) return OutOfMemory;
1069
Evan Stadef30732f2007-07-24 17:18:47 -07001070 if((retval = GdipCreateMatrix(&(*graphics)->worldtrans)) != Ok){
1071 GdipFree(*graphics);
1072 return retval;
1073 }
1074
Nikolay Sivovef50aa32008-08-27 02:03:27 +04001075 if((retval = GdipCreateRegion(&(*graphics)->clip)) != Ok){
1076 GdipFree((*graphics)->worldtrans);
1077 GdipFree(*graphics);
1078 return retval;
1079 }
1080
Evan Staded50be492007-06-11 11:54:03 -07001081 (*graphics)->hdc = hdc;
Nikolay Sivov7258dea2008-09-05 16:51:25 +04001082 (*graphics)->hwnd = WindowFromDC(hdc);
Vincent Povirk8a3d9ff2009-04-24 13:29:56 -05001083 (*graphics)->owndc = FALSE;
Evan Stade53e17d22007-07-13 17:51:13 -07001084 (*graphics)->smoothing = SmoothingModeDefault;
Evan Stade60cad232007-07-13 17:51:25 -07001085 (*graphics)->compqual = CompositingQualityDefault;
Evan Stadea87ce7a2007-07-13 17:51:29 -07001086 (*graphics)->interpolation = InterpolationModeDefault;
Evan Staded6bd866d2007-07-13 17:51:33 -07001087 (*graphics)->pixeloffset = PixelOffsetModeDefault;
Evan Stadee807eb92007-08-13 18:34:27 -07001088 (*graphics)->compmode = CompositingModeSourceOver;
Evan Stade10b575b2007-07-23 20:24:41 -07001089 (*graphics)->unit = UnitDisplay;
Evan Stade81621392007-07-24 17:18:39 -07001090 (*graphics)->scale = 1.0;
Nikolay Sivov366ae1e2008-08-24 14:45:18 +04001091 (*graphics)->busy = FALSE;
Nikolay Sivov56173d42008-11-09 14:32:26 +03001092 (*graphics)->textcontrast = 4;
Andrew Eikum632aef32009-07-05 17:04:20 -05001093 list_init(&(*graphics)->containers);
1094 (*graphics)->contid = 0;
Evan Staded50be492007-06-11 11:54:03 -07001095
1096 return Ok;
1097}
1098
1099GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics)
1100{
1101 GpStatus ret;
Vincent Povirkc3d23952009-04-24 13:34:55 -05001102 HDC hdc;
Evan Staded50be492007-06-11 11:54:03 -07001103
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001104 TRACE("(%p, %p)\n", hwnd, graphics);
1105
Vincent Povirkc3d23952009-04-24 13:34:55 -05001106 hdc = GetDC(hwnd);
1107
1108 if((ret = GdipCreateFromHDC(hdc, graphics)) != Ok)
1109 {
1110 ReleaseDC(hwnd, hdc);
Evan Staded50be492007-06-11 11:54:03 -07001111 return ret;
Vincent Povirkc3d23952009-04-24 13:34:55 -05001112 }
Evan Staded50be492007-06-11 11:54:03 -07001113
1114 (*graphics)->hwnd = hwnd;
Vincent Povirk8a3d9ff2009-04-24 13:29:56 -05001115 (*graphics)->owndc = TRUE;
Evan Staded50be492007-06-11 11:54:03 -07001116
1117 return Ok;
1118}
1119
Nikolay Sivoveb18ce92008-05-09 16:40:41 +04001120/* FIXME: no icm handling */
1121GpStatus WINGDIPAPI GdipCreateFromHWNDICM(HWND hwnd, GpGraphics **graphics)
1122{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001123 TRACE("(%p, %p)\n", hwnd, graphics);
1124
Nikolay Sivoveb18ce92008-05-09 16:40:41 +04001125 return GdipCreateFromHWND(hwnd, graphics);
1126}
1127
Evan Stade5cc8c102007-07-24 17:19:05 -07001128GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
1129 GpMetafile **metafile)
1130{
1131 static int calls;
1132
1133 if(!hemf || !metafile)
1134 return InvalidParameter;
1135
1136 if(!(calls++))
1137 FIXME("not implemented\n");
1138
1139 return NotImplemented;
1140}
1141
Evan Stade021997f2007-07-24 17:19:15 -07001142GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
1143 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
1144{
Evan Stadecfef9812007-07-31 19:15:12 -07001145 IStream *stream = NULL;
Evan Stade50799cf2007-07-30 19:10:03 -07001146 UINT read;
1147 BYTE* copy;
Evan Stade50799cf2007-07-30 19:10:03 -07001148 HENHMETAFILE hemf;
Evan Stadecfef9812007-07-31 19:15:12 -07001149 GpStatus retval = GenericError;
Evan Stade021997f2007-07-24 17:19:15 -07001150
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001151 TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
1152
Evan Stade021997f2007-07-24 17:19:15 -07001153 if(!hwmf || !metafile || !placeable)
1154 return InvalidParameter;
Evan Stade7d03a412007-08-07 18:42:16 -07001155
1156 *metafile = NULL;
Evan Stade50799cf2007-07-30 19:10:03 -07001157 read = GetMetaFileBitsEx(hwmf, 0, NULL);
1158 if(!read)
1159 return GenericError;
1160 copy = GdipAlloc(read);
1161 GetMetaFileBitsEx(hwmf, read, copy);
1162
Evan Stade192e1112007-08-01 17:55:33 -07001163 hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
Evan Stade50799cf2007-07-30 19:10:03 -07001164 GdipFree(copy);
1165
1166 read = GetEnhMetaFileBits(hemf, 0, NULL);
1167 copy = GdipAlloc(read);
1168 GetEnhMetaFileBits(hemf, read, copy);
1169 DeleteEnhMetaFile(hemf);
1170
1171 if(CreateStreamOnHGlobal(copy, TRUE, &stream) != S_OK){
1172 ERR("could not make stream\n");
Evan Stade7d03a412007-08-07 18:42:16 -07001173 GdipFree(copy);
1174 goto err;
Evan Stade50799cf2007-07-30 19:10:03 -07001175 }
1176
1177 *metafile = GdipAlloc(sizeof(GpMetafile));
Evan Stadecfef9812007-07-31 19:15:12 -07001178 if(!*metafile){
1179 retval = OutOfMemory;
Evan Stade7d03a412007-08-07 18:42:16 -07001180 goto err;
Evan Stadecfef9812007-07-31 19:15:12 -07001181 }
Evan Stade50799cf2007-07-30 19:10:03 -07001182
1183 if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
Evan Stade7d03a412007-08-07 18:42:16 -07001184 (LPVOID*) &((*metafile)->image.picture)) != S_OK)
1185 goto err;
1186
Evan Stade50799cf2007-07-30 19:10:03 -07001187
1188 (*metafile)->image.type = ImageTypeMetafile;
Evan Stade586e63e2007-07-30 19:09:57 -07001189 (*metafile)->bounds.X = ((REAL) placeable->BoundingBox.Left) / ((REAL) placeable->Inch);
1190 (*metafile)->bounds.Y = ((REAL) placeable->BoundingBox.Right) / ((REAL) placeable->Inch);
1191 (*metafile)->bounds.Width = ((REAL) (placeable->BoundingBox.Right
1192 - placeable->BoundingBox.Left)) / ((REAL) placeable->Inch);
1193 (*metafile)->bounds.Height = ((REAL) (placeable->BoundingBox.Bottom
1194 - placeable->BoundingBox.Top)) / ((REAL) placeable->Inch);
1195 (*metafile)->unit = UnitInch;
1196
Evan Stade50799cf2007-07-30 19:10:03 -07001197 if(delete)
1198 DeleteMetaFile(hwmf);
1199
Evan Stade7d03a412007-08-07 18:42:16 -07001200 return Ok;
Evan Stadecfef9812007-07-31 19:15:12 -07001201
Evan Stade7d03a412007-08-07 18:42:16 -07001202err:
1203 GdipFree(*metafile);
Evan Stadecfef9812007-07-31 19:15:12 -07001204 IStream_Release(stream);
Evan Stadecfef9812007-07-31 19:15:12 -07001205 return retval;
Evan Stade021997f2007-07-24 17:19:15 -07001206}
1207
Huw Davieseb9d7f52008-07-10 15:30:30 +01001208GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
1209 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
1210{
1211 HMETAFILE hmf = GetMetaFileW(file);
1212
1213 TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
1214
1215 if(!hmf) return InvalidParameter;
1216
1217 return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
1218}
1219
Andrew Eikumc02e75c2009-06-01 20:02:11 -05001220GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
1221 GpMetafile **metafile)
1222{
1223 FIXME("(%p, %p): stub\n", file, metafile);
1224 return NotImplemented;
1225}
1226
1227GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
1228 GpMetafile **metafile)
1229{
1230 FIXME("(%p, %p): stub\n", stream, metafile);
1231 return NotImplemented;
1232}
1233
Evan Stade3ea77f52007-08-07 18:42:00 -07001234GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename,
1235 UINT access, IStream **stream)
1236{
1237 DWORD dwMode;
1238 HRESULT ret;
1239
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001240 TRACE("(%s, %u, %p)\n", debugstr_w(filename), access, stream);
1241
Evan Stade3ea77f52007-08-07 18:42:00 -07001242 if(!stream || !filename)
1243 return InvalidParameter;
1244
1245 if(access & GENERIC_WRITE)
1246 dwMode = STGM_SHARE_DENY_WRITE | STGM_WRITE | STGM_CREATE;
1247 else if(access & GENERIC_READ)
1248 dwMode = STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE;
1249 else
1250 return InvalidParameter;
1251
1252 ret = SHCreateStreamOnFileW(filename, dwMode, stream);
1253
1254 return hresult_to_status(ret);
1255}
1256
Evan Staded50be492007-06-11 11:54:03 -07001257GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
1258{
Andrew Eikum632aef32009-07-05 17:04:20 -05001259 GraphicsContainerItem *cont, *next;
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001260 TRACE("(%p)\n", graphics);
1261
Evan Staded50be492007-06-11 11:54:03 -07001262 if(!graphics) return InvalidParameter;
Nikolay Sivov960de092008-08-26 01:58:33 +04001263 if(graphics->busy) return ObjectBusy;
1264
Vincent Povirk8a3d9ff2009-04-24 13:29:56 -05001265 if(graphics->owndc)
Evan Staded50be492007-06-11 11:54:03 -07001266 ReleaseDC(graphics->hwnd, graphics->hdc);
1267
Andrew Eikum632aef32009-07-05 17:04:20 -05001268 LIST_FOR_EACH_ENTRY_SAFE(cont, next, &graphics->containers, GraphicsContainerItem, entry){
1269 list_remove(&cont->entry);
1270 delete_container(cont);
1271 }
1272
Nikolay Sivovef50aa32008-08-27 02:03:27 +04001273 GdipDeleteRegion(graphics->clip);
Evan Stadef30732f2007-07-24 17:18:47 -07001274 GdipDeleteMatrix(graphics->worldtrans);
Nikolay Sivov6e37ec62008-08-24 14:45:05 +04001275 GdipFree(graphics);
Evan Staded50be492007-06-11 11:54:03 -07001276
1277 return Ok;
1278}
Evan Stade2689b182007-06-12 10:44:31 -07001279
Evan Stadec42f8792007-06-19 19:31:19 -07001280GpStatus WINGDIPAPI GdipDrawArc(GpGraphics *graphics, GpPen *pen, REAL x,
1281 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
1282{
Evan Stade40f22732007-07-11 18:07:09 -07001283 INT save_state, num_pts;
1284 GpPointF points[MAX_ARC_PTS];
Evan Stadefa312172007-07-11 18:07:39 -07001285 GpStatus retval;
Evan Stadec42f8792007-06-19 19:31:19 -07001286
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001287 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y,
1288 width, height, startAngle, sweepAngle);
1289
Royal Chanea928722008-02-25 21:06:27 -08001290 if(!graphics || !pen || width <= 0 || height <= 0)
Evan Stadec42f8792007-06-19 19:31:19 -07001291 return InvalidParameter;
1292
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001293 if(graphics->busy)
1294 return ObjectBusy;
1295
Evan Stade40f22732007-07-11 18:07:09 -07001296 num_pts = arc2polybezier(points, x, y, width, height, startAngle, sweepAngle);
Evan Stadec42f8792007-06-19 19:31:19 -07001297
Evan Stade4c424b32007-07-24 17:18:54 -07001298 save_state = prepare_dc(graphics, pen);
Evan Stadec42f8792007-06-19 19:31:19 -07001299
Evan Staded01c6972007-07-23 20:24:53 -07001300 retval = draw_polybezier(graphics, pen, points, num_pts, TRUE);
Evan Stadec42f8792007-06-19 19:31:19 -07001301
Evan Stade4c424b32007-07-24 17:18:54 -07001302 restore_dc(graphics, save_state);
Evan Stadec42f8792007-06-19 19:31:19 -07001303
Evan Stadefa312172007-07-11 18:07:39 -07001304 return retval;
Evan Stadec42f8792007-06-19 19:31:19 -07001305}
1306
Royal Chanfc313032008-02-25 21:02:59 -08001307GpStatus WINGDIPAPI GdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x,
1308 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
1309{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001310 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y,
1311 width, height, startAngle, sweepAngle);
1312
Nikolay Sivova77dc342008-05-08 00:39:05 +04001313 return GdipDrawArc(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle);
Royal Chanfc313032008-02-25 21:02:59 -08001314}
1315
Evan Stade8b9f5342007-06-15 21:27:38 -07001316GpStatus WINGDIPAPI GdipDrawBezier(GpGraphics *graphics, GpPen *pen, REAL x1,
1317 REAL y1, REAL x2, REAL y2, REAL x3, REAL y3, REAL x4, REAL y4)
1318{
Evan Stade69a807c2007-07-06 16:13:49 -07001319 INT save_state;
1320 GpPointF pt[4];
Evan Stadefa312172007-07-11 18:07:39 -07001321 GpStatus retval;
Evan Stade8b9f5342007-06-15 21:27:38 -07001322
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001323 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1,
1324 x2, y2, x3, y3, x4, y4);
1325
Evan Stade8b9f5342007-06-15 21:27:38 -07001326 if(!graphics || !pen)
1327 return InvalidParameter;
1328
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001329 if(graphics->busy)
1330 return ObjectBusy;
1331
Evan Stade69a807c2007-07-06 16:13:49 -07001332 pt[0].X = x1;
1333 pt[0].Y = y1;
1334 pt[1].X = x2;
1335 pt[1].Y = y2;
1336 pt[2].X = x3;
1337 pt[2].Y = y3;
1338 pt[3].X = x4;
1339 pt[3].Y = y4;
Evan Stade8b9f5342007-06-15 21:27:38 -07001340
Evan Stade4c424b32007-07-24 17:18:54 -07001341 save_state = prepare_dc(graphics, pen);
Evan Stade8b9f5342007-06-15 21:27:38 -07001342
Evan Staded01c6972007-07-23 20:24:53 -07001343 retval = draw_polybezier(graphics, pen, pt, 4, TRUE);
Evan Stade69a807c2007-07-06 16:13:49 -07001344
Evan Stade4c424b32007-07-24 17:18:54 -07001345 restore_dc(graphics, save_state);
Evan Stade8b9f5342007-06-15 21:27:38 -07001346
Evan Stadefa312172007-07-11 18:07:39 -07001347 return retval;
Evan Stade8b9f5342007-06-15 21:27:38 -07001348}
1349
Royal Chanda161a52008-02-25 21:00:43 -08001350GpStatus WINGDIPAPI GdipDrawBezierI(GpGraphics *graphics, GpPen *pen, INT x1,
1351 INT y1, INT x2, INT y2, INT x3, INT y3, INT x4, INT y4)
1352{
1353 INT save_state;
1354 GpPointF pt[4];
1355 GpStatus retval;
1356
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001357 TRACE("(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", graphics, pen, x1, y1,
1358 x2, y2, x3, y3, x4, y4);
1359
Royal Chanda161a52008-02-25 21:00:43 -08001360 if(!graphics || !pen)
1361 return InvalidParameter;
1362
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001363 if(graphics->busy)
1364 return ObjectBusy;
1365
Royal Chanda161a52008-02-25 21:00:43 -08001366 pt[0].X = x1;
1367 pt[0].Y = y1;
1368 pt[1].X = x2;
1369 pt[1].Y = y2;
1370 pt[2].X = x3;
1371 pt[2].Y = y3;
1372 pt[3].X = x4;
1373 pt[3].Y = y4;
1374
1375 save_state = prepare_dc(graphics, pen);
1376
1377 retval = draw_polybezier(graphics, pen, pt, 4, TRUE);
1378
1379 restore_dc(graphics, save_state);
1380
1381 return retval;
1382}
1383
Nikolay Sivovd0204742008-07-03 03:04:50 +04001384GpStatus WINGDIPAPI GdipDrawBeziers(GpGraphics *graphics, GpPen *pen,
1385 GDIPCONST GpPointF *points, INT count)
1386{
1387 INT i;
1388 GpStatus ret;
1389
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001390 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1391
Nikolay Sivovd0204742008-07-03 03:04:50 +04001392 if(!graphics || !pen || !points || (count <= 0))
1393 return InvalidParameter;
1394
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001395 if(graphics->busy)
1396 return ObjectBusy;
1397
Nikolay Sivovd0204742008-07-03 03:04:50 +04001398 for(i = 0; i < floor(count / 4); i++){
1399 ret = GdipDrawBezier(graphics, pen,
1400 points[4*i].X, points[4*i].Y,
1401 points[4*i + 1].X, points[4*i + 1].Y,
1402 points[4*i + 2].X, points[4*i + 2].Y,
1403 points[4*i + 3].X, points[4*i + 3].Y);
1404 if(ret != Ok)
1405 return ret;
1406 }
1407
1408 return Ok;
1409}
1410
1411GpStatus WINGDIPAPI GdipDrawBeziersI(GpGraphics *graphics, GpPen *pen,
1412 GDIPCONST GpPoint *points, INT count)
1413{
1414 GpPointF *pts;
1415 GpStatus ret;
1416 INT i;
1417
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001418 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1419
Nikolay Sivovd0204742008-07-03 03:04:50 +04001420 if(!graphics || !pen || !points || (count <= 0))
1421 return InvalidParameter;
1422
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001423 if(graphics->busy)
1424 return ObjectBusy;
1425
Nikolay Sivovd0204742008-07-03 03:04:50 +04001426 pts = GdipAlloc(sizeof(GpPointF) * count);
1427 if(!pts)
1428 return OutOfMemory;
1429
1430 for(i = 0; i < count; i++){
1431 pts[i].X = (REAL)points[i].X;
1432 pts[i].Y = (REAL)points[i].Y;
1433 }
1434
1435 ret = GdipDrawBeziers(graphics,pen,pts,count);
1436
1437 GdipFree(pts);
1438
1439 return ret;
1440}
1441
Nikolay Sivov55916bb2008-07-09 00:39:31 +04001442GpStatus WINGDIPAPI GdipDrawClosedCurve(GpGraphics *graphics, GpPen *pen,
1443 GDIPCONST GpPointF *points, INT count)
1444{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001445 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1446
Nikolay Sivov55916bb2008-07-09 00:39:31 +04001447 return GdipDrawClosedCurve2(graphics, pen, points, count, 1.0);
1448}
1449
1450GpStatus WINGDIPAPI GdipDrawClosedCurveI(GpGraphics *graphics, GpPen *pen,
1451 GDIPCONST GpPoint *points, INT count)
1452{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001453 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1454
Nikolay Sivov55916bb2008-07-09 00:39:31 +04001455 return GdipDrawClosedCurve2I(graphics, pen, points, count, 1.0);
1456}
1457
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001458GpStatus WINGDIPAPI GdipDrawClosedCurve2(GpGraphics *graphics, GpPen *pen,
1459 GDIPCONST GpPointF *points, INT count, REAL tension)
1460{
Nikolay Sivov9c60a572008-09-03 19:57:09 +04001461 GpPath *path;
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001462 GpStatus stat;
1463
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001464 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
1465
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001466 if(!graphics || !pen || !points || count <= 0)
1467 return InvalidParameter;
1468
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001469 if(graphics->busy)
1470 return ObjectBusy;
1471
Nikolay Sivov9c60a572008-09-03 19:57:09 +04001472 if((stat = GdipCreatePath(FillModeAlternate, &path)) != Ok)
1473 return stat;
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001474
Nikolay Sivov9c60a572008-09-03 19:57:09 +04001475 stat = GdipAddPathClosedCurve2(path, points, count, tension);
1476 if(stat != Ok){
1477 GdipDeletePath(path);
1478 return stat;
1479 }
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001480
Nikolay Sivov9c60a572008-09-03 19:57:09 +04001481 stat = GdipDrawPath(graphics, pen, path);
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001482
Nikolay Sivov9c60a572008-09-03 19:57:09 +04001483 GdipDeletePath(path);
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001484
1485 return stat;
1486}
1487
1488GpStatus WINGDIPAPI GdipDrawClosedCurve2I(GpGraphics *graphics, GpPen *pen,
1489 GDIPCONST GpPoint *points, INT count, REAL tension)
1490{
1491 GpPointF *ptf;
1492 GpStatus stat;
1493 INT i;
1494
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001495 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
1496
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001497 if(!points || count <= 0)
1498 return InvalidParameter;
1499
1500 ptf = GdipAlloc(sizeof(GpPointF)*count);
1501 if(!ptf)
1502 return OutOfMemory;
1503
1504 for(i = 0; i < count; i++){
1505 ptf[i].X = (REAL)points[i].X;
1506 ptf[i].Y = (REAL)points[i].Y;
1507 }
1508
1509 stat = GdipDrawClosedCurve2(graphics, pen, ptf, count, tension);
1510
1511 GdipFree(ptf);
1512
1513 return stat;
1514}
1515
Nikolay Sivovfe1782e2008-04-29 00:09:55 +04001516GpStatus WINGDIPAPI GdipDrawCurve(GpGraphics *graphics, GpPen *pen,
1517 GDIPCONST GpPointF *points, INT count)
1518{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001519 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1520
Nikolay Sivovfe1782e2008-04-29 00:09:55 +04001521 return GdipDrawCurve2(graphics,pen,points,count,1.0);
1522}
1523
1524GpStatus WINGDIPAPI GdipDrawCurveI(GpGraphics *graphics, GpPen *pen,
1525 GDIPCONST GpPoint *points, INT count)
1526{
1527 GpPointF *pointsF;
1528 GpStatus ret;
1529 INT i;
1530
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001531 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1532
Andrew Eikumfe55f0d2009-06-28 13:33:52 -05001533 if(!points)
Nikolay Sivovfe1782e2008-04-29 00:09:55 +04001534 return InvalidParameter;
1535
1536 pointsF = GdipAlloc(sizeof(GpPointF)*count);
1537 if(!pointsF)
1538 return OutOfMemory;
1539
1540 for(i = 0; i < count; i++){
1541 pointsF[i].X = (REAL)points[i].X;
1542 pointsF[i].Y = (REAL)points[i].Y;
1543 }
1544
1545 ret = GdipDrawCurve(graphics,pen,pointsF,count);
1546 GdipFree(pointsF);
1547
1548 return ret;
1549}
1550
Evan Stade5c8b83c2007-06-19 19:31:28 -07001551/* Approximates cardinal spline with Bezier curves. */
1552GpStatus WINGDIPAPI GdipDrawCurve2(GpGraphics *graphics, GpPen *pen,
1553 GDIPCONST GpPointF *points, INT count, REAL tension)
1554{
Evan Stade5c8b83c2007-06-19 19:31:28 -07001555 /* PolyBezier expects count*3-2 points. */
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001556 INT i, len_pt = count*3-2, save_state;
1557 GpPointF *pt;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001558 REAL x1, x2, y1, y2;
Evan Stadefa312172007-07-11 18:07:39 -07001559 GpStatus retval;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001560
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001561 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
1562
Evan Stade5c8b83c2007-06-19 19:31:28 -07001563 if(!graphics || !pen)
1564 return InvalidParameter;
1565
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001566 if(graphics->busy)
1567 return ObjectBusy;
1568
Andrew Eikum119e9af2009-06-06 12:02:29 -05001569 if(count < 2)
1570 return InvalidParameter;
1571
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001572 pt = GdipAlloc(len_pt * sizeof(GpPointF));
Andrew Eikum119e9af2009-06-06 12:02:29 -05001573 if(!pt)
1574 return OutOfMemory;
1575
Evan Stade5c8b83c2007-06-19 19:31:28 -07001576 tension = tension * TENSION_CONST;
1577
1578 calc_curve_bezier_endp(points[0].X, points[0].Y, points[1].X, points[1].Y,
1579 tension, &x1, &y1);
1580
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001581 pt[0].X = points[0].X;
1582 pt[0].Y = points[0].Y;
1583 pt[1].X = x1;
1584 pt[1].Y = y1;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001585
1586 for(i = 0; i < count-2; i++){
1587 calc_curve_bezier(&(points[i]), tension, &x1, &y1, &x2, &y2);
1588
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001589 pt[3*i+2].X = x1;
1590 pt[3*i+2].Y = y1;
1591 pt[3*i+3].X = points[i+1].X;
1592 pt[3*i+3].Y = points[i+1].Y;
1593 pt[3*i+4].X = x2;
1594 pt[3*i+4].Y = y2;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001595 }
1596
1597 calc_curve_bezier_endp(points[count-1].X, points[count-1].Y,
1598 points[count-2].X, points[count-2].Y, tension, &x1, &y1);
1599
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001600 pt[len_pt-2].X = x1;
1601 pt[len_pt-2].Y = y1;
1602 pt[len_pt-1].X = points[count-1].X;
1603 pt[len_pt-1].Y = points[count-1].Y;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001604
Evan Stade4c424b32007-07-24 17:18:54 -07001605 save_state = prepare_dc(graphics, pen);
Evan Stade5c8b83c2007-06-19 19:31:28 -07001606
Evan Staded01c6972007-07-23 20:24:53 -07001607 retval = draw_polybezier(graphics, pen, pt, len_pt, TRUE);
Evan Stade5c8b83c2007-06-19 19:31:28 -07001608
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001609 GdipFree(pt);
Evan Stade4c424b32007-07-24 17:18:54 -07001610 restore_dc(graphics, save_state);
Evan Stade5c8b83c2007-06-19 19:31:28 -07001611
Evan Stadefa312172007-07-11 18:07:39 -07001612 return retval;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001613}
1614
Nikolay Sivov00cfffb2008-04-29 00:09:44 +04001615GpStatus WINGDIPAPI GdipDrawCurve2I(GpGraphics *graphics, GpPen *pen,
1616 GDIPCONST GpPoint *points, INT count, REAL tension)
1617{
1618 GpPointF *pointsF;
1619 GpStatus ret;
1620 INT i;
1621
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001622 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
1623
Andrew Eikumc2aa66d2009-06-28 13:33:59 -05001624 if(!points)
Nikolay Sivov00cfffb2008-04-29 00:09:44 +04001625 return InvalidParameter;
1626
1627 pointsF = GdipAlloc(sizeof(GpPointF)*count);
1628 if(!pointsF)
1629 return OutOfMemory;
1630
1631 for(i = 0; i < count; i++){
1632 pointsF[i].X = (REAL)points[i].X;
1633 pointsF[i].Y = (REAL)points[i].Y;
1634 }
1635
1636 ret = GdipDrawCurve2(graphics,pen,pointsF,count,tension);
1637 GdipFree(pointsF);
1638
1639 return ret;
1640}
1641
Andrew Eikum4c0edba2009-06-29 22:12:40 -05001642GpStatus WINGDIPAPI GdipDrawCurve3(GpGraphics *graphics, GpPen *pen,
1643 GDIPCONST GpPointF *points, INT count, INT offset, INT numberOfSegments,
1644 REAL tension)
1645{
1646 TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension);
1647
1648 if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){
1649 return InvalidParameter;
1650 }
1651
1652 return GdipDrawCurve2(graphics, pen, points + offset, numberOfSegments + 1, tension);
1653}
1654
1655GpStatus WINGDIPAPI GdipDrawCurve3I(GpGraphics *graphics, GpPen *pen,
1656 GDIPCONST GpPoint *points, INT count, INT offset, INT numberOfSegments,
1657 REAL tension)
1658{
1659 TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension);
1660
1661 if(count < 0){
1662 return OutOfMemory;
1663 }
1664
1665 if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){
1666 return InvalidParameter;
1667 }
1668
1669 return GdipDrawCurve2I(graphics, pen, points + offset, numberOfSegments + 1, tension);
1670}
1671
Przemysław Białek864384e2008-06-27 10:59:23 +02001672GpStatus WINGDIPAPI GdipDrawEllipse(GpGraphics *graphics, GpPen *pen, REAL x,
1673 REAL y, REAL width, REAL height)
1674{
1675 INT save_state;
1676 GpPointF ptf[2];
1677 POINT pti[2];
1678
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001679 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height);
1680
Przemysław Białek864384e2008-06-27 10:59:23 +02001681 if(!graphics || !pen)
1682 return InvalidParameter;
1683
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001684 if(graphics->busy)
1685 return ObjectBusy;
1686
Przemysław Białek864384e2008-06-27 10:59:23 +02001687 ptf[0].X = x;
1688 ptf[0].Y = y;
1689 ptf[1].X = x + width;
1690 ptf[1].Y = y + height;
1691
1692 save_state = prepare_dc(graphics, pen);
1693 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
1694
1695 transform_and_round_points(graphics, pti, ptf, 2);
1696
1697 Ellipse(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y);
1698
1699 restore_dc(graphics, save_state);
1700
1701 return Ok;
1702}
1703
1704GpStatus WINGDIPAPI GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x,
1705 INT y, INT width, INT height)
1706{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001707 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height);
1708
Przemysław Białek864384e2008-06-27 10:59:23 +02001709 return GdipDrawEllipse(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
1710}
1711
1712
Nikolay Sivov49247042008-04-29 00:10:01 +04001713GpStatus WINGDIPAPI GdipDrawImage(GpGraphics *graphics, GpImage *image, REAL x, REAL y)
1714{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001715 TRACE("(%p, %p, %.2f, %.2f)\n", graphics, image, x, y);
1716
Nikolay Sivov49247042008-04-29 00:10:01 +04001717 /* IPicture::Render uses LONG coords */
1718 return GdipDrawImageI(graphics,image,roundr(x),roundr(y));
1719}
1720
Evan Stadede351ab2007-08-07 18:42:12 -07001721GpStatus WINGDIPAPI GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x,
1722 INT y)
1723{
1724 UINT width, height, srcw, srch;
1725
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001726 TRACE("(%p, %p, %d, %d)\n", graphics, image, x, y);
1727
Evan Stadede351ab2007-08-07 18:42:12 -07001728 if(!graphics || !image)
1729 return InvalidParameter;
1730
1731 GdipGetImageWidth(image, &width);
1732 GdipGetImageHeight(image, &height);
1733
1734 srcw = width * (((REAL) INCH_HIMETRIC) /
1735 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSX)));
1736 srch = height * (((REAL) INCH_HIMETRIC) /
1737 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSY)));
1738
1739 if(image->type != ImageTypeMetafile){
1740 y += height;
1741 height *= -1;
1742 }
1743
1744 IPicture_Render(image->picture, graphics->hdc, x, y, width, height,
1745 0, 0, srcw, srch, NULL);
1746
1747 return Ok;
1748}
1749
Andrew Eikumeec8d512009-06-02 22:34:37 -05001750GpStatus WINGDIPAPI GdipDrawImagePointRect(GpGraphics *graphics, GpImage *image,
1751 REAL x, REAL y, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight,
1752 GpUnit srcUnit)
1753{
1754 FIXME("(%p, %p, %f, %f, %f, %f, %f, %f, %d): stub\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
1755 return NotImplemented;
1756}
1757
1758GpStatus WINGDIPAPI GdipDrawImagePointRectI(GpGraphics *graphics, GpImage *image,
1759 INT x, INT y, INT srcx, INT srcy, INT srcwidth, INT srcheight,
1760 GpUnit srcUnit)
1761{
1762 FIXME("(%p, %p, %d, %d, %d, %d, %d, %d, %d): stub\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
1763 return NotImplemented;
1764}
1765
Andrew Eikum156eeb02009-06-03 23:31:21 -05001766GpStatus WINGDIPAPI GdipDrawImagePoints(GpGraphics *graphics, GpImage *image,
1767 GDIPCONST GpPointF *dstpoints, INT count)
1768{
1769 FIXME("(%p, %p, %p, %d): stub\n", graphics, image, dstpoints, count);
1770 return NotImplemented;
1771}
1772
1773GpStatus WINGDIPAPI GdipDrawImagePointsI(GpGraphics *graphics, GpImage *image,
1774 GDIPCONST GpPoint *dstpoints, INT count)
1775{
1776 FIXME("(%p, %p, %p, %d): stub\n", graphics, image, dstpoints, count);
1777 return NotImplemented;
1778}
1779
Evan Stade04d4c262007-08-09 18:25:09 -07001780/* FIXME: partially implemented (only works for rectangular parallelograms) */
Evan Stade460f01b2007-07-30 19:09:45 -07001781GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image,
Evan Stadea9c4f302007-07-30 19:10:07 -07001782 GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth,
1783 REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
1784 DrawImageAbort callback, VOID * callbackData)
Evan Stade460f01b2007-07-30 19:09:45 -07001785{
Evan Stadea9c4f302007-07-30 19:10:07 -07001786 GpPointF ptf[3];
1787 POINT pti[3];
Evan Stade6e0c5742007-07-31 19:16:23 -07001788 REAL dx, dy;
Evan Stade460f01b2007-07-30 19:09:45 -07001789
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001790 TRACE("(%p, %p, %p, %d, %f, %f, %f, %f, %d, %p, %p, %p)\n", graphics, image, points,
1791 count, srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback,
Evan Stadea9c4f302007-07-30 19:10:07 -07001792 callbackData);
Evan Stade460f01b2007-07-30 19:09:45 -07001793
Nikolay Sivov8cf56082008-04-25 01:58:36 +04001794 if(!graphics || !image || !points || count != 3)
Evan Stadea9c4f302007-07-30 19:10:07 -07001795 return InvalidParameter;
Evan Stade460f01b2007-07-30 19:09:45 -07001796
Evan Stade6e0c5742007-07-31 19:16:23 -07001797 if(srcUnit == UnitInch)
1798 dx = dy = (REAL) INCH_HIMETRIC;
1799 else if(srcUnit == UnitPixel){
1800 dx = ((REAL) INCH_HIMETRIC) /
1801 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSX));
1802 dy = ((REAL) INCH_HIMETRIC) /
1803 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSY));
1804 }
1805 else
Evan Stadea9c4f302007-07-30 19:10:07 -07001806 return NotImplemented;
1807
1808 memcpy(ptf, points, 3 * sizeof(GpPointF));
1809 transform_and_round_points(graphics, pti, ptf, 3);
1810
Evan Stade6e0c5742007-07-31 19:16:23 -07001811 /* IPicture renders bitmaps with the y-axis reversed
1812 * FIXME: flipping for unknown image type might not be correct. */
1813 if(image->type != ImageTypeMetafile){
1814 INT temp;
1815 temp = pti[0].y;
1816 pti[0].y = pti[2].y;
1817 pti[2].y = temp;
1818 }
1819
Evan Stadea9c4f302007-07-30 19:10:07 -07001820 if(IPicture_Render(image->picture, graphics->hdc,
1821 pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
Evan Stade6e0c5742007-07-31 19:16:23 -07001822 srcx * dx, srcy * dy,
1823 srcwidth * dx, srcheight * dy,
Evan Stadea9c4f302007-07-30 19:10:07 -07001824 NULL) != S_OK){
1825 if(callback)
1826 callback(callbackData);
1827 return GenericError;
1828 }
1829
1830 return Ok;
Evan Stade460f01b2007-07-30 19:09:45 -07001831}
1832
Nikolay Sivov79b49a82008-04-29 00:10:05 +04001833GpStatus WINGDIPAPI GdipDrawImagePointsRectI(GpGraphics *graphics, GpImage *image,
1834 GDIPCONST GpPoint *points, INT count, INT srcx, INT srcy, INT srcwidth,
1835 INT srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
1836 DrawImageAbort callback, VOID * callbackData)
1837{
1838 GpPointF pointsF[3];
1839 INT i;
1840
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001841 TRACE("(%p, %p, %p, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n", graphics, image, points, count,
1842 srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback,
1843 callbackData);
1844
Nikolay Sivov79b49a82008-04-29 00:10:05 +04001845 if(!points || count!=3)
1846 return InvalidParameter;
1847
1848 for(i = 0; i < count; i++){
1849 pointsF[i].X = (REAL)points[i].X;
1850 pointsF[i].Y = (REAL)points[i].Y;
1851 }
1852
1853 return GdipDrawImagePointsRect(graphics, image, pointsF, count, (REAL)srcx, (REAL)srcy,
1854 (REAL)srcwidth, (REAL)srcheight, srcUnit, imageAttributes,
1855 callback, callbackData);
1856}
1857
Evan Stade04d4c262007-08-09 18:25:09 -07001858GpStatus WINGDIPAPI GdipDrawImageRectRect(GpGraphics *graphics, GpImage *image,
1859 REAL dstx, REAL dsty, REAL dstwidth, REAL dstheight, REAL srcx, REAL srcy,
1860 REAL srcwidth, REAL srcheight, GpUnit srcUnit,
1861 GDIPCONST GpImageAttributes* imageattr, DrawImageAbort callback,
1862 VOID * callbackData)
1863{
1864 GpPointF points[3];
1865
Francois Gouget758c4532008-09-05 13:14:56 +02001866 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p, %p, %p)\n",
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001867 graphics, image, dstx, dsty, dstwidth, dstheight, srcx, srcy,
1868 srcwidth, srcheight, srcUnit, imageattr, callback, callbackData);
1869
Evan Stade04d4c262007-08-09 18:25:09 -07001870 points[0].X = dstx;
1871 points[0].Y = dsty;
1872 points[1].X = dstx + dstwidth;
1873 points[1].Y = dsty;
1874 points[2].X = dstx;
1875 points[2].Y = dsty + dstheight;
1876
1877 return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy,
1878 srcwidth, srcheight, srcUnit, imageattr, callback, callbackData);
1879}
1880
Jon Yang29bc9ba2008-02-28 21:54:47 -08001881GpStatus WINGDIPAPI GdipDrawImageRectRectI(GpGraphics *graphics, GpImage *image,
1882 INT dstx, INT dsty, INT dstwidth, INT dstheight, INT srcx, INT srcy,
1883 INT srcwidth, INT srcheight, GpUnit srcUnit,
1884 GDIPCONST GpImageAttributes* imageAttributes, DrawImageAbort callback,
1885 VOID * callbackData)
1886{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001887 GpPointF points[3];
1888
Francois Gouget758c4532008-09-05 13:14:56 +02001889 TRACE("(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n",
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001890 graphics, image, dstx, dsty, dstwidth, dstheight, srcx, srcy,
1891 srcwidth, srcheight, srcUnit, imageAttributes, callback, callbackData);
Jon Yang29bc9ba2008-02-28 21:54:47 -08001892
1893 points[0].X = dstx;
1894 points[0].Y = dsty;
1895 points[1].X = dstx + dstwidth;
1896 points[1].Y = dsty;
1897 points[2].X = dstx;
1898 points[2].Y = dsty + dstheight;
1899
1900 return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy,
1901 srcwidth, srcheight, srcUnit, imageAttributes, callback, callbackData);
1902}
1903
Nikolay Sivov8cf56082008-04-25 01:58:36 +04001904GpStatus WINGDIPAPI GdipDrawImageRect(GpGraphics *graphics, GpImage *image,
1905 REAL x, REAL y, REAL width, REAL height)
1906{
1907 RectF bounds;
1908 GpUnit unit;
1909 GpStatus ret;
1910
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001911 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, image, x, y, width, height);
1912
Nikolay Sivov8cf56082008-04-25 01:58:36 +04001913 if(!graphics || !image)
1914 return InvalidParameter;
1915
1916 ret = GdipGetImageBounds(image, &bounds, &unit);
1917 if(ret != Ok)
1918 return ret;
1919
1920 return GdipDrawImageRectRect(graphics, image, x, y, width, height,
1921 bounds.X, bounds.Y, bounds.Width, bounds.Height,
1922 unit, NULL, NULL, NULL);
1923}
1924
1925GpStatus WINGDIPAPI GdipDrawImageRectI(GpGraphics *graphics, GpImage *image,
1926 INT x, INT y, INT width, INT height)
1927{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001928 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, image, x, y, width, height);
1929
Nikolay Sivov8cf56082008-04-25 01:58:36 +04001930 return GdipDrawImageRect(graphics, image, (REAL)x, (REAL)y, (REAL)width, (REAL)height);
1931}
1932
Evan Stade5e29e372007-08-01 17:55:58 -07001933GpStatus WINGDIPAPI GdipDrawLine(GpGraphics *graphics, GpPen *pen, REAL x1,
1934 REAL y1, REAL x2, REAL y2)
1935{
1936 INT save_state;
1937 GpPointF pt[2];
1938 GpStatus retval;
1939
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001940 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1, x2, y2);
1941
Evan Stade5e29e372007-08-01 17:55:58 -07001942 if(!pen || !graphics)
1943 return InvalidParameter;
1944
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001945 if(graphics->busy)
1946 return ObjectBusy;
1947
Evan Stade5e29e372007-08-01 17:55:58 -07001948 pt[0].X = x1;
1949 pt[0].Y = y1;
1950 pt[1].X = x2;
1951 pt[1].Y = y2;
1952
1953 save_state = prepare_dc(graphics, pen);
1954
1955 retval = draw_polyline(graphics, pen, pt, 2, TRUE);
1956
1957 restore_dc(graphics, save_state);
1958
1959 return retval;
1960}
1961
Evan Stade2689b182007-06-12 10:44:31 -07001962GpStatus WINGDIPAPI GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1,
1963 INT y1, INT x2, INT y2)
1964{
Evan Staded9ef1722007-07-02 15:13:05 -07001965 INT save_state;
Evan Stade5128e5d2007-07-07 13:20:41 -07001966 GpPointF pt[2];
Evan Stade6f4ab522007-07-11 18:07:44 -07001967 GpStatus retval;
Evan Stade2689b182007-06-12 10:44:31 -07001968
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001969 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x1, y1, x2, y2);
1970
Evan Stade2689b182007-06-12 10:44:31 -07001971 if(!pen || !graphics)
1972 return InvalidParameter;
1973
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001974 if(graphics->busy)
1975 return ObjectBusy;
1976
Evan Stade5128e5d2007-07-07 13:20:41 -07001977 pt[0].X = (REAL)x1;
1978 pt[0].Y = (REAL)y1;
1979 pt[1].X = (REAL)x2;
1980 pt[1].Y = (REAL)y2;
1981
Evan Stade4c424b32007-07-24 17:18:54 -07001982 save_state = prepare_dc(graphics, pen);
Evan Staded9ef1722007-07-02 15:13:05 -07001983
Evan Staded01c6972007-07-23 20:24:53 -07001984 retval = draw_polyline(graphics, pen, pt, 2, TRUE);
Evan Staded9ef1722007-07-02 15:13:05 -07001985
Evan Stade4c424b32007-07-24 17:18:54 -07001986 restore_dc(graphics, save_state);
Evan Stade2689b182007-06-12 10:44:31 -07001987
Evan Stade6f4ab522007-07-11 18:07:44 -07001988 return retval;
Evan Stade2689b182007-06-12 10:44:31 -07001989}
Evan Stade4b9bfbe2007-06-12 10:51:20 -07001990
Evan Stadef6f04f62007-06-21 16:15:13 -07001991GpStatus WINGDIPAPI GdipDrawLines(GpGraphics *graphics, GpPen *pen, GDIPCONST
1992 GpPointF *points, INT count)
1993{
Evan Stade852aac82007-07-11 18:07:16 -07001994 INT save_state;
Evan Stade6f4ab522007-07-11 18:07:44 -07001995 GpStatus retval;
Evan Stadef6f04f62007-06-21 16:15:13 -07001996
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001997 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1998
Evan Stadef6f04f62007-06-21 16:15:13 -07001999 if(!pen || !graphics || (count < 2))
2000 return InvalidParameter;
2001
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002002 if(graphics->busy)
2003 return ObjectBusy;
2004
Evan Stade4c424b32007-07-24 17:18:54 -07002005 save_state = prepare_dc(graphics, pen);
Evan Stadef6f04f62007-06-21 16:15:13 -07002006
Evan Staded01c6972007-07-23 20:24:53 -07002007 retval = draw_polyline(graphics, pen, points, count, TRUE);
Evan Stadef6f04f62007-06-21 16:15:13 -07002008
Evan Stade4c424b32007-07-24 17:18:54 -07002009 restore_dc(graphics, save_state);
Evan Stadef6f04f62007-06-21 16:15:13 -07002010
Evan Stade6f4ab522007-07-11 18:07:44 -07002011 return retval;
Evan Stadef6f04f62007-06-21 16:15:13 -07002012}
2013
Royal Chan6e7b5342008-02-29 04:58:39 -08002014GpStatus WINGDIPAPI GdipDrawLinesI(GpGraphics *graphics, GpPen *pen, GDIPCONST
2015 GpPoint *points, INT count)
2016{
2017 INT save_state;
2018 GpStatus retval;
2019 GpPointF *ptf = NULL;
2020 int i;
2021
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002022 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
2023
Royal Chan6e7b5342008-02-29 04:58:39 -08002024 if(!pen || !graphics || (count < 2))
2025 return InvalidParameter;
2026
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002027 if(graphics->busy)
2028 return ObjectBusy;
2029
Royal Chan6e7b5342008-02-29 04:58:39 -08002030 ptf = GdipAlloc(count * sizeof(GpPointF));
2031 if(!ptf) return OutOfMemory;
2032
2033 for(i = 0; i < count; i ++){
2034 ptf[i].X = (REAL) points[i].X;
2035 ptf[i].Y = (REAL) points[i].Y;
2036 }
2037
2038 save_state = prepare_dc(graphics, pen);
2039
2040 retval = draw_polyline(graphics, pen, ptf, count, TRUE);
2041
2042 restore_dc(graphics, save_state);
2043
2044 GdipFree(ptf);
2045 return retval;
2046}
2047
Evan Stade9d5f5682007-07-11 18:07:34 -07002048GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
2049{
Evan Stade9e883472007-07-13 17:51:49 -07002050 INT save_state;
Evan Stade9d5f5682007-07-11 18:07:34 -07002051 GpStatus retval;
2052
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002053 TRACE("(%p, %p, %p)\n", graphics, pen, path);
2054
Evan Stade9d5f5682007-07-11 18:07:34 -07002055 if(!pen || !graphics)
2056 return InvalidParameter;
2057
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002058 if(graphics->busy)
2059 return ObjectBusy;
2060
Evan Stade4c424b32007-07-24 17:18:54 -07002061 save_state = prepare_dc(graphics, pen);
Evan Stade9d5f5682007-07-11 18:07:34 -07002062
Evan Staded01c6972007-07-23 20:24:53 -07002063 retval = draw_poly(graphics, pen, path->pathdata.Points,
Evan Stade9e883472007-07-13 17:51:49 -07002064 path->pathdata.Types, path->pathdata.Count, TRUE);
Evan Stade9d5f5682007-07-11 18:07:34 -07002065
Evan Stade4c424b32007-07-24 17:18:54 -07002066 restore_dc(graphics, save_state);
Evan Stade9d5f5682007-07-11 18:07:34 -07002067
2068 return retval;
2069}
2070
Evan Stade72ab72c502007-06-18 16:55:51 -07002071GpStatus WINGDIPAPI GdipDrawPie(GpGraphics *graphics, GpPen *pen, REAL x,
2072 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
2073{
Evan Stade4c424b32007-07-24 17:18:54 -07002074 INT save_state;
2075
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002076 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y,
2077 width, height, startAngle, sweepAngle);
2078
Evan Stade4c424b32007-07-24 17:18:54 -07002079 if(!graphics || !pen)
Evan Stade72ab72c502007-06-18 16:55:51 -07002080 return InvalidParameter;
2081
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002082 if(graphics->busy)
2083 return ObjectBusy;
2084
Evan Stade4c424b32007-07-24 17:18:54 -07002085 save_state = prepare_dc(graphics, pen);
2086 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
2087
2088 draw_pie(graphics, x, y, width, height, startAngle, sweepAngle);
2089
2090 restore_dc(graphics, save_state);
2091
2092 return Ok;
Evan Stade72ab72c502007-06-18 16:55:51 -07002093}
2094
Nikolay Sivov71931612008-04-24 20:48:00 +04002095GpStatus WINGDIPAPI GdipDrawPieI(GpGraphics *graphics, GpPen *pen, INT x,
2096 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
2097{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002098 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y,
2099 width, height, startAngle, sweepAngle);
2100
Nikolay Sivov71931612008-04-24 20:48:00 +04002101 return GdipDrawPie(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle);
2102}
2103
Nikolay Sivov172389e2008-04-20 21:27:10 +04002104GpStatus WINGDIPAPI GdipDrawRectangle(GpGraphics *graphics, GpPen *pen, REAL x,
2105 REAL y, REAL width, REAL height)
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002106{
Evan Stade14e0df12007-07-09 20:54:18 -07002107 INT save_state;
Evan Stadec84c2042007-08-07 18:43:08 -07002108 GpPointF ptf[4];
2109 POINT pti[4];
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002110
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002111 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height);
2112
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002113 if(!pen || !graphics)
2114 return InvalidParameter;
2115
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002116 if(graphics->busy)
2117 return ObjectBusy;
2118
Evan Stadec84c2042007-08-07 18:43:08 -07002119 ptf[0].X = x;
2120 ptf[0].Y = y;
2121 ptf[1].X = x + width;
2122 ptf[1].Y = y;
2123 ptf[2].X = x + width;
2124 ptf[2].Y = y + height;
2125 ptf[3].X = x;
2126 ptf[3].Y = y + height;
2127
Evan Stade4c424b32007-07-24 17:18:54 -07002128 save_state = prepare_dc(graphics, pen);
Evan Stade14e0df12007-07-09 20:54:18 -07002129 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002130
Evan Stadec84c2042007-08-07 18:43:08 -07002131 transform_and_round_points(graphics, pti, ptf, 4);
2132 Polygon(graphics->hdc, pti, 4);
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002133
Evan Stade4c424b32007-07-24 17:18:54 -07002134 restore_dc(graphics, save_state);
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002135
2136 return Ok;
2137}
Evan Stade72ab72c502007-06-18 16:55:51 -07002138
Nikolay Sivov172389e2008-04-20 21:27:10 +04002139GpStatus WINGDIPAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x,
2140 INT y, INT width, INT height)
2141{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002142 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height);
2143
Nikolay Sivov172389e2008-04-20 21:27:10 +04002144 return GdipDrawRectangle(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
2145}
2146
Evan Stade9d6e0752007-08-13 18:34:46 -07002147GpStatus WINGDIPAPI GdipDrawRectangles(GpGraphics *graphics, GpPen *pen,
Francois Gougetb6b97b12007-08-29 21:42:01 +02002148 GDIPCONST GpRectF* rects, INT count)
Evan Stade9d6e0752007-08-13 18:34:46 -07002149{
2150 GpPointF *ptf;
2151 POINT *pti;
2152 INT save_state, i;
2153
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002154 TRACE("(%p, %p, %p, %d)\n", graphics, pen, rects, count);
2155
Evan Stade9d6e0752007-08-13 18:34:46 -07002156 if(!graphics || !pen || !rects || count < 1)
2157 return InvalidParameter;
2158
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002159 if(graphics->busy)
2160 return ObjectBusy;
2161
Evan Stade9d6e0752007-08-13 18:34:46 -07002162 ptf = GdipAlloc(4 * count * sizeof(GpPointF));
2163 pti = GdipAlloc(4 * count * sizeof(POINT));
2164
2165 if(!ptf || !pti){
2166 GdipFree(ptf);
2167 GdipFree(pti);
2168 return OutOfMemory;
2169 }
2170
2171 for(i = 0; i < count; i++){
2172 ptf[4 * i + 3].X = ptf[4 * i].X = rects[i].X;
2173 ptf[4 * i + 1].Y = ptf[4 * i].Y = rects[i].Y;
2174 ptf[4 * i + 2].X = ptf[4 * i + 1].X = rects[i].X + rects[i].Width;
2175 ptf[4 * i + 3].Y = ptf[4 * i + 2].Y = rects[i].Y + rects[i].Height;
2176 }
2177
2178 save_state = prepare_dc(graphics, pen);
2179 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
2180
2181 transform_and_round_points(graphics, pti, ptf, 4 * count);
2182
2183 for(i = 0; i < count; i++)
2184 Polygon(graphics->hdc, &pti[4 * i], 4);
2185
2186 restore_dc(graphics, save_state);
2187
2188 GdipFree(ptf);
2189 GdipFree(pti);
2190
2191 return Ok;
2192}
2193
Nikolay Sivov3903ac62008-04-24 20:48:08 +04002194GpStatus WINGDIPAPI GdipDrawRectanglesI(GpGraphics *graphics, GpPen *pen,
2195 GDIPCONST GpRect* rects, INT count)
2196{
2197 GpRectF *rectsF;
2198 GpStatus ret;
2199 INT i;
2200
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002201 TRACE("(%p, %p, %p, %d)\n", graphics, pen, rects, count);
2202
Nikolay Sivov3903ac62008-04-24 20:48:08 +04002203 if(!rects || count<=0)
2204 return InvalidParameter;
2205
2206 rectsF = GdipAlloc(sizeof(GpRectF) * count);
2207 if(!rectsF)
2208 return OutOfMemory;
2209
2210 for(i = 0;i < count;i++){
2211 rectsF[i].X = (REAL)rects[i].X;
2212 rectsF[i].Y = (REAL)rects[i].Y;
2213 rectsF[i].Width = (REAL)rects[i].Width;
2214 rectsF[i].Height = (REAL)rects[i].Height;
2215 }
2216
2217 ret = GdipDrawRectangles(graphics, pen, rectsF, count);
2218 GdipFree(rectsF);
2219
2220 return ret;
2221}
2222
Evan Stadef7d27e02007-08-14 18:58:39 -07002223GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string,
2224 INT length, GDIPCONST GpFont *font, GDIPCONST RectF *rect,
2225 GDIPCONST GpStringFormat *format, GDIPCONST GpBrush *brush)
2226{
Evan Stadeca949392007-08-15 16:22:13 -07002227 HRGN rgn = NULL;
Evan Stadef7d27e02007-08-14 18:58:39 -07002228 HFONT gdifont;
2229 LOGFONTW lfw;
2230 TEXTMETRICW textmet;
2231 GpPointF pt[2], rectcpy[4];
2232 POINT corners[4];
2233 WCHAR* stringdup;
2234 REAL angle, ang_cos, ang_sin, rel_width, rel_height;
Stephan Roseeb3904d2009-06-04 18:51:07 -04002235 INT sum = 0, height = 0, offsety = 0, fit, fitcpy, save_state, i, j, lret, nwidth,
Vincent Povirke0d9d172009-07-24 16:24:19 -05002236 nheight, lineend;
Evan Stadef7d27e02007-08-14 18:58:39 -07002237 SIZE size;
Vincent Povirkaa9602d2009-06-29 16:36:11 -05002238 POINT drawbase;
2239 UINT drawflags;
Evan Stadebe66c3c2007-08-15 16:22:17 -07002240 RECT drawcoord;
Evan Stadef7d27e02007-08-14 18:58:39 -07002241
Vincent Povirk3dd5ce72009-05-13 13:55:46 -05002242 TRACE("(%p, %s, %i, %p, %s, %p, %p)\n", graphics, debugstr_wn(string, length),
2243 length, font, debugstr_rectf(rect), format, brush);
2244
Evan Stadef7d27e02007-08-14 18:58:39 -07002245 if(!graphics || !string || !font || !brush || !rect)
2246 return InvalidParameter;
2247
Evan Stade3f320832007-08-15 16:22:00 -07002248 if((brush->bt != BrushTypeSolidColor)){
Evan Stadef7d27e02007-08-14 18:58:39 -07002249 FIXME("not implemented for given parameters\n");
2250 return NotImplemented;
2251 }
2252
Stephan Roseeb3904d2009-06-04 18:51:07 -04002253 if(format){
Evan Stade3f320832007-08-15 16:22:00 -07002254 TRACE("may be ignoring some format flags: attr %x\n", format->attr);
2255
Stephan Roseeb3904d2009-06-04 18:51:07 -04002256 /* Should be no need to explicitly test for StringAlignmentNear as
2257 * that is default behavior if no alignment is passed. */
2258 if(format->vertalign != StringAlignmentNear){
2259 RectF bounds;
2260 GdipMeasureString(graphics, string, length, font, rect, format, &bounds, 0, 0);
2261
2262 if(format->vertalign == StringAlignmentCenter)
2263 offsety = (rect->Height - bounds.Height) / 2;
2264 else if(format->vertalign == StringAlignmentFar)
2265 offsety = (rect->Height - bounds.Height);
2266 }
2267 }
2268
Evan Staded0cead32007-08-14 19:01:07 -07002269 if(length == -1) length = lstrlenW(string);
2270
Evan Stadef7d27e02007-08-14 18:58:39 -07002271 stringdup = GdipAlloc(length * sizeof(WCHAR));
2272 if(!stringdup) return OutOfMemory;
2273
2274 save_state = SaveDC(graphics->hdc);
2275 SetBkMode(graphics->hdc, TRANSPARENT);
2276 SetTextColor(graphics->hdc, brush->lb.lbColor);
2277
2278 rectcpy[3].X = rectcpy[0].X = rect->X;
Stephan Roseeb3904d2009-06-04 18:51:07 -04002279 rectcpy[1].Y = rectcpy[0].Y = rect->Y + offsety;
Evan Stadef7d27e02007-08-14 18:58:39 -07002280 rectcpy[2].X = rectcpy[1].X = rect->X + rect->Width;
Stephan Roseeb3904d2009-06-04 18:51:07 -04002281 rectcpy[3].Y = rectcpy[2].Y = rect->Y + offsety + rect->Height;
Evan Stadef7d27e02007-08-14 18:58:39 -07002282 transform_and_round_points(graphics, corners, rectcpy, 4);
Evan Stadef7d27e02007-08-14 18:58:39 -07002283
Vincent Povirk0879b762009-04-01 14:08:12 -05002284 if (roundr(rect->Width) == 0)
2285 {
2286 rel_width = 1.0;
2287 nwidth = INT_MAX;
Evan Stadeca949392007-08-15 16:22:13 -07002288 }
Vincent Povirk0879b762009-04-01 14:08:12 -05002289 else
2290 {
Evan Stadeca949392007-08-15 16:22:13 -07002291 rel_width = sqrt((corners[1].x - corners[0].x) * (corners[1].x - corners[0].x) +
2292 (corners[1].y - corners[0].y) * (corners[1].y - corners[0].y))
2293 / rect->Width;
Vincent Povirk0879b762009-04-01 14:08:12 -05002294 nwidth = roundr(rel_width * rect->Width);
2295 }
2296
2297 if (roundr(rect->Height) == 0)
2298 {
2299 rel_height = 1.0;
2300 nheight = INT_MAX;
2301 }
2302 else
2303 {
Evan Stadeca949392007-08-15 16:22:13 -07002304 rel_height = sqrt((corners[2].x - corners[1].x) * (corners[2].x - corners[1].x) +
2305 (corners[2].y - corners[1].y) * (corners[2].y - corners[1].y))
2306 / rect->Height;
Evan Stadeca949392007-08-15 16:22:13 -07002307 nheight = roundr(rel_height * rect->Height);
Vincent Povirk0879b762009-04-01 14:08:12 -05002308 }
2309
2310 if (roundr(rect->Width) != 0 && roundr(rect->Height) != 0)
2311 {
2312 /* FIXME: If only the width or only the height is 0, we should probably still clip */
Evan Stadeca949392007-08-15 16:22:13 -07002313 rgn = CreatePolygonRgn(corners, 4, ALTERNATE);
2314 SelectClipRgn(graphics->hdc, rgn);
2315 }
Evan Stadef7d27e02007-08-14 18:58:39 -07002316
2317 /* Use gdi to find the font, then perform transformations on it (height,
2318 * width, angle). */
2319 SelectObject(graphics->hdc, CreateFontIndirectW(&font->lfw));
2320 GetTextMetricsW(graphics->hdc, &textmet);
Andrew Talbot5e8253a2008-02-29 22:06:47 +00002321 lfw = font->lfw;
Evan Stadef7d27e02007-08-14 18:58:39 -07002322
2323 lfw.lfHeight = roundr(((REAL)lfw.lfHeight) * rel_height);
2324 lfw.lfWidth = roundr(textmet.tmAveCharWidth * rel_width);
2325
2326 pt[0].X = 0.0;
2327 pt[0].Y = 0.0;
2328 pt[1].X = 1.0;
2329 pt[1].Y = 0.0;
2330 GdipTransformMatrixPoints(graphics->worldtrans, pt, 2);
Vincent Povirkb330ebf2009-07-24 13:56:22 -05002331 angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
Evan Stadef7d27e02007-08-14 18:58:39 -07002332 ang_cos = cos(angle);
2333 ang_sin = sin(angle);
Vincent Povirkb330ebf2009-07-24 13:56:22 -05002334 lfw.lfEscapement = lfw.lfOrientation = roundr((angle / M_PI) * 1800.0);
Evan Stadef7d27e02007-08-14 18:58:39 -07002335
2336 gdifont = CreateFontIndirectW(&lfw);
2337 DeleteObject(SelectObject(graphics->hdc, CreateFontIndirectW(&lfw)));
2338
2339 for(i = 0, j = 0; i < length; i++){
2340 if(!isprintW(string[i]) && (string[i] != '\n'))
2341 continue;
2342
2343 stringdup[j] = string[i];
2344 j++;
2345 }
2346
Evan Stadef7d27e02007-08-14 18:58:39 -07002347 length = j;
2348
Vincent Povirk9fceef32009-06-30 09:23:07 -05002349 if (!format || format->align == StringAlignmentNear)
Vincent Povirkaa9602d2009-06-29 16:36:11 -05002350 {
2351 drawbase.x = corners[0].x;
2352 drawbase.y = corners[0].y;
2353 drawflags = DT_NOCLIP | DT_EXPANDTABS;
2354 }
2355 else if (format->align == StringAlignmentCenter)
2356 {
2357 drawbase.x = (corners[0].x + corners[1].x)/2;
2358 drawbase.y = (corners[0].y + corners[1].y)/2;
2359 drawflags = DT_NOCLIP | DT_EXPANDTABS | DT_CENTER;
2360 }
2361 else /* (format->align == StringAlignmentFar) */
2362 {
2363 drawbase.x = corners[1].x;
2364 drawbase.y = corners[1].y;
2365 drawflags = DT_NOCLIP | DT_EXPANDTABS | DT_RIGHT;
2366 }
2367
Evan Stadef7d27e02007-08-14 18:58:39 -07002368 while(sum < length){
Vincent Povirkaa9602d2009-06-29 16:36:11 -05002369 drawcoord.left = drawcoord.right = drawbase.x + roundr(ang_sin * (REAL) height);
2370 drawcoord.top = drawcoord.bottom = drawbase.y + roundr(ang_cos * (REAL) height);
Evan Stadebe66c3c2007-08-15 16:22:17 -07002371
Evan Stade92aa57b2007-08-15 16:21:56 -07002372 GetTextExtentExPointW(graphics->hdc, stringdup + sum, length - sum,
2373 nwidth, &fit, NULL, &size);
Evan Stadef7d27e02007-08-14 18:58:39 -07002374 fitcpy = fit;
2375
2376 if(fit == 0){
Vincent Povirkaa9602d2009-06-29 16:36:11 -05002377 DrawTextW(graphics->hdc, stringdup + sum, 1, &drawcoord, drawflags);
Evan Stadef7d27e02007-08-14 18:58:39 -07002378 break;
2379 }
2380
2381 for(lret = 0; lret < fit; lret++)
2382 if(*(stringdup + sum + lret) == '\n')
2383 break;
2384
2385 /* Line break code (may look strange, but it imitates windows). */
2386 if(lret < fit)
Vincent Povirke0d9d172009-07-24 16:24:19 -05002387 lineend = fit = lret; /* this is not an off-by-one error */
Evan Stade92aa57b2007-08-15 16:21:56 -07002388 else if(fit < (length - sum)){
2389 if(*(stringdup + sum + fit) == ' ')
2390 while(*(stringdup + sum + fit) == ' ')
2391 fit++;
2392 else
2393 while(*(stringdup + sum + fit - 1) != ' '){
2394 fit--;
Evan Stadef7d27e02007-08-14 18:58:39 -07002395
Evan Stade92aa57b2007-08-15 16:21:56 -07002396 if(*(stringdup + sum + fit) == '\t')
2397 break;
Evan Stadef7d27e02007-08-14 18:58:39 -07002398
Evan Stade92aa57b2007-08-15 16:21:56 -07002399 if(fit == 0){
2400 fit = fitcpy;
2401 break;
2402 }
Evan Stadef7d27e02007-08-14 18:58:39 -07002403 }
Vincent Povirke0d9d172009-07-24 16:24:19 -05002404 lineend = fit;
2405 while(*(stringdup + sum + lineend - 1) == ' ' ||
2406 *(stringdup + sum + lineend - 1) == '\t')
2407 lineend--;
Evan Stade92aa57b2007-08-15 16:21:56 -07002408 }
Vincent Povirke0d9d172009-07-24 16:24:19 -05002409 else
2410 lineend = fit;
2411 DrawTextW(graphics->hdc, stringdup + sum, min(length - sum, lineend),
Vincent Povirkaa9602d2009-06-29 16:36:11 -05002412 &drawcoord, drawflags);
Evan Stadef7d27e02007-08-14 18:58:39 -07002413
2414 sum += fit + (lret < fitcpy ? 1 : 0);
2415 height += size.cy;
2416
Evan Stadeca949392007-08-15 16:22:13 -07002417 if(height > nheight)
Evan Stadef7d27e02007-08-14 18:58:39 -07002418 break;
Evan Stade3f320832007-08-15 16:22:00 -07002419
2420 /* Stop if this was a linewrap (but not if it was a linebreak). */
2421 if((lret == fitcpy) && format && (format->attr & StringFormatFlagsNoWrap))
2422 break;
Evan Stadef7d27e02007-08-14 18:58:39 -07002423 }
2424
Andrew Talbotdfac0632007-09-25 20:52:58 +01002425 GdipFree(stringdup);
Evan Stadef7d27e02007-08-14 18:58:39 -07002426 DeleteObject(rgn);
2427 DeleteObject(gdifont);
2428
2429 RestoreDC(graphics->hdc, save_state);
2430
2431 return Ok;
2432}
2433
Nikolay Sivov4a441002008-08-22 02:16:49 +04002434GpStatus WINGDIPAPI GdipFillClosedCurve2(GpGraphics *graphics, GpBrush *brush,
2435 GDIPCONST GpPointF *points, INT count, REAL tension, GpFillMode fill)
2436{
2437 GpPath *path;
2438 GpStatus stat;
2439
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002440 TRACE("(%p, %p, %p, %d, %.2f, %d)\n", graphics, brush, points,
2441 count, tension, fill);
2442
Nikolay Sivov4a441002008-08-22 02:16:49 +04002443 if(!graphics || !brush || !points)
2444 return InvalidParameter;
2445
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002446 if(graphics->busy)
2447 return ObjectBusy;
2448
Nikolay Sivov4a441002008-08-22 02:16:49 +04002449 stat = GdipCreatePath(fill, &path);
2450 if(stat != Ok)
2451 return stat;
2452
2453 stat = GdipAddPathClosedCurve2(path, points, count, tension);
2454 if(stat != Ok){
2455 GdipDeletePath(path);
2456 return stat;
2457 }
2458
2459 stat = GdipFillPath(graphics, brush, path);
2460 if(stat != Ok){
2461 GdipDeletePath(path);
2462 return stat;
2463 }
2464
2465 GdipDeletePath(path);
2466
2467 return Ok;
2468}
2469
2470GpStatus WINGDIPAPI GdipFillClosedCurve2I(GpGraphics *graphics, GpBrush *brush,
2471 GDIPCONST GpPoint *points, INT count, REAL tension, GpFillMode fill)
2472{
2473 GpPointF *ptf;
2474 GpStatus stat;
2475 INT i;
2476
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002477 TRACE("(%p, %p, %p, %d, %.2f, %d)\n", graphics, brush, points,
2478 count, tension, fill);
2479
Nikolay Sivov4a441002008-08-22 02:16:49 +04002480 if(!points || count <= 0)
2481 return InvalidParameter;
2482
2483 ptf = GdipAlloc(sizeof(GpPointF)*count);
2484 if(!ptf)
2485 return OutOfMemory;
2486
2487 for(i = 0;i < count;i++){
2488 ptf[i].X = (REAL)points[i].X;
2489 ptf[i].Y = (REAL)points[i].Y;
2490 }
2491
2492 stat = GdipFillClosedCurve2(graphics, brush, ptf, count, tension, fill);
2493
2494 GdipFree(ptf);
2495
2496 return stat;
2497}
2498
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002499GpStatus WINGDIPAPI GdipFillEllipse(GpGraphics *graphics, GpBrush *brush, REAL x,
2500 REAL y, REAL width, REAL height)
2501{
2502 INT save_state;
2503 GpPointF ptf[2];
2504 POINT pti[2];
2505
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002506 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height);
2507
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002508 if(!graphics || !brush)
2509 return InvalidParameter;
2510
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002511 if(graphics->busy)
2512 return ObjectBusy;
2513
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002514 ptf[0].X = x;
2515 ptf[0].Y = y;
2516 ptf[1].X = x + width;
2517 ptf[1].Y = y + height;
2518
2519 save_state = SaveDC(graphics->hdc);
2520 EndPath(graphics->hdc);
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002521
2522 transform_and_round_points(graphics, pti, ptf, 2);
2523
Vincent Povirke3063162009-07-11 10:29:44 -05002524 BeginPath(graphics->hdc);
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002525 Ellipse(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y);
Vincent Povirke3063162009-07-11 10:29:44 -05002526 EndPath(graphics->hdc);
2527
2528 brush_fill_path(graphics, brush);
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002529
2530 RestoreDC(graphics->hdc, save_state);
2531
2532 return Ok;
2533}
2534
2535GpStatus WINGDIPAPI GdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x,
2536 INT y, INT width, INT height)
2537{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002538 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height);
2539
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002540 return GdipFillEllipse(graphics,brush,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
2541}
2542
Evan Staded362b582007-07-13 20:19:46 -07002543GpStatus WINGDIPAPI GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *path)
2544{
2545 INT save_state;
2546 GpStatus retval;
2547
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002548 TRACE("(%p, %p, %p)\n", graphics, brush, path);
2549
Evan Staded362b582007-07-13 20:19:46 -07002550 if(!brush || !graphics || !path)
2551 return InvalidParameter;
2552
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002553 if(graphics->busy)
2554 return ObjectBusy;
2555
Evan Staded362b582007-07-13 20:19:46 -07002556 save_state = SaveDC(graphics->hdc);
2557 EndPath(graphics->hdc);
Evan Staded362b582007-07-13 20:19:46 -07002558 SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
2559 : WINDING));
2560
2561 BeginPath(graphics->hdc);
Evan Staded01c6972007-07-23 20:24:53 -07002562 retval = draw_poly(graphics, NULL, path->pathdata.Points,
Evan Staded362b582007-07-13 20:19:46 -07002563 path->pathdata.Types, path->pathdata.Count, FALSE);
2564
2565 if(retval != Ok)
2566 goto end;
2567
2568 EndPath(graphics->hdc);
Vincent Povirk68dba4e2009-03-16 12:51:04 -05002569 brush_fill_path(graphics, brush);
Evan Staded362b582007-07-13 20:19:46 -07002570
2571 retval = Ok;
2572
2573end:
2574 RestoreDC(graphics->hdc, save_state);
2575
2576 return retval;
2577}
2578
Evan Stade72ab72c502007-06-18 16:55:51 -07002579GpStatus WINGDIPAPI GdipFillPie(GpGraphics *graphics, GpBrush *brush, REAL x,
2580 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
2581{
Evan Stade4c424b32007-07-24 17:18:54 -07002582 INT save_state;
2583
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002584 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
2585 graphics, brush, x, y, width, height, startAngle, sweepAngle);
2586
Evan Stade4c424b32007-07-24 17:18:54 -07002587 if(!graphics || !brush)
Evan Stade72ab72c502007-06-18 16:55:51 -07002588 return InvalidParameter;
2589
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002590 if(graphics->busy)
2591 return ObjectBusy;
2592
Evan Stade4c424b32007-07-24 17:18:54 -07002593 save_state = SaveDC(graphics->hdc);
2594 EndPath(graphics->hdc);
Evan Stade4c424b32007-07-24 17:18:54 -07002595
Vincent Povirkbedbd402009-07-11 10:32:34 -05002596 BeginPath(graphics->hdc);
Evan Stade4c424b32007-07-24 17:18:54 -07002597 draw_pie(graphics, x, y, width, height, startAngle, sweepAngle);
Vincent Povirkbedbd402009-07-11 10:32:34 -05002598 EndPath(graphics->hdc);
2599
2600 brush_fill_path(graphics, brush);
Evan Stade4c424b32007-07-24 17:18:54 -07002601
2602 RestoreDC(graphics->hdc, save_state);
2603
2604 return Ok;
Evan Stade72ab72c502007-06-18 16:55:51 -07002605}
Evan Stade53e17d22007-07-13 17:51:13 -07002606
Nikolay Sivov2c059d72008-04-24 20:48:23 +04002607GpStatus WINGDIPAPI GdipFillPieI(GpGraphics *graphics, GpBrush *brush, INT x,
2608 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
2609{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002610 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n",
2611 graphics, brush, x, y, width, height, startAngle, sweepAngle);
2612
Nikolay Sivov2c059d72008-04-24 20:48:23 +04002613 return GdipFillPie(graphics,brush,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle);
2614}
2615
Evan Stade1ef77932007-08-01 17:55:50 -07002616GpStatus WINGDIPAPI GdipFillPolygon(GpGraphics *graphics, GpBrush *brush,
2617 GDIPCONST GpPointF *points, INT count, GpFillMode fillMode)
2618{
2619 INT save_state;
2620 GpPointF *ptf = NULL;
2621 POINT *pti = NULL;
2622 GpStatus retval = Ok;
2623
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002624 TRACE("(%p, %p, %p, %d, %d)\n", graphics, brush, points, count, fillMode);
2625
Evan Stade1ef77932007-08-01 17:55:50 -07002626 if(!graphics || !brush || !points || !count)
2627 return InvalidParameter;
2628
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002629 if(graphics->busy)
2630 return ObjectBusy;
2631
Evan Stade1ef77932007-08-01 17:55:50 -07002632 ptf = GdipAlloc(count * sizeof(GpPointF));
2633 pti = GdipAlloc(count * sizeof(POINT));
2634 if(!ptf || !pti){
2635 retval = OutOfMemory;
2636 goto end;
2637 }
2638
2639 memcpy(ptf, points, count * sizeof(GpPointF));
2640
2641 save_state = SaveDC(graphics->hdc);
2642 EndPath(graphics->hdc);
Evan Stade1ef77932007-08-01 17:55:50 -07002643 SetPolyFillMode(graphics->hdc, (fillMode == FillModeAlternate ? ALTERNATE
2644 : WINDING));
2645
2646 transform_and_round_points(graphics, pti, ptf, count);
Vincent Povirk15fef072009-07-11 10:35:40 -05002647
2648 BeginPath(graphics->hdc);
Evan Stade1ef77932007-08-01 17:55:50 -07002649 Polygon(graphics->hdc, pti, count);
Vincent Povirk15fef072009-07-11 10:35:40 -05002650 EndPath(graphics->hdc);
2651
2652 brush_fill_path(graphics, brush);
Evan Stade1ef77932007-08-01 17:55:50 -07002653
2654 RestoreDC(graphics->hdc, save_state);
2655
2656end:
2657 GdipFree(ptf);
2658 GdipFree(pti);
2659
2660 return retval;
2661}
2662
Evan Stade64675262007-07-23 20:24:35 -07002663GpStatus WINGDIPAPI GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush,
2664 GDIPCONST GpPoint *points, INT count, GpFillMode fillMode)
2665{
Evan Staded01c6972007-07-23 20:24:53 -07002666 INT save_state, i;
2667 GpPointF *ptf = NULL;
2668 POINT *pti = NULL;
2669 GpStatus retval = Ok;
Evan Stade64675262007-07-23 20:24:35 -07002670
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002671 TRACE("(%p, %p, %p, %d, %d)\n", graphics, brush, points, count, fillMode);
2672
Evan Stade64675262007-07-23 20:24:35 -07002673 if(!graphics || !brush || !points || !count)
2674 return InvalidParameter;
2675
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002676 if(graphics->busy)
2677 return ObjectBusy;
2678
Evan Staded01c6972007-07-23 20:24:53 -07002679 ptf = GdipAlloc(count * sizeof(GpPointF));
2680 pti = GdipAlloc(count * sizeof(POINT));
2681 if(!ptf || !pti){
2682 retval = OutOfMemory;
2683 goto end;
2684 }
2685
2686 for(i = 0; i < count; i ++){
2687 ptf[i].X = (REAL) points[i].X;
2688 ptf[i].Y = (REAL) points[i].Y;
2689 }
2690
Evan Stade64675262007-07-23 20:24:35 -07002691 save_state = SaveDC(graphics->hdc);
2692 EndPath(graphics->hdc);
Evan Stade64675262007-07-23 20:24:35 -07002693 SetPolyFillMode(graphics->hdc, (fillMode == FillModeAlternate ? ALTERNATE
2694 : WINDING));
Evan Staded01c6972007-07-23 20:24:53 -07002695
2696 transform_and_round_points(graphics, pti, ptf, count);
Vincent Povirk38fc8942009-07-11 10:37:22 -05002697
2698 BeginPath(graphics->hdc);
Evan Staded01c6972007-07-23 20:24:53 -07002699 Polygon(graphics->hdc, pti, count);
Vincent Povirk38fc8942009-07-11 10:37:22 -05002700 EndPath(graphics->hdc);
2701
2702 brush_fill_path(graphics, brush);
Evan Stade64675262007-07-23 20:24:35 -07002703
2704 RestoreDC(graphics->hdc, save_state);
Evan Staded01c6972007-07-23 20:24:53 -07002705
2706end:
2707 GdipFree(ptf);
2708 GdipFree(pti);
2709
2710 return retval;
Evan Stade64675262007-07-23 20:24:35 -07002711}
2712
Nikolay Sivove04a6622008-08-03 12:19:36 +04002713GpStatus WINGDIPAPI GdipFillPolygon2(GpGraphics *graphics, GpBrush *brush,
2714 GDIPCONST GpPointF *points, INT count)
2715{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002716 TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count);
2717
Nikolay Sivove04a6622008-08-03 12:19:36 +04002718 return GdipFillPolygon(graphics, brush, points, count, FillModeAlternate);
2719}
2720
2721GpStatus WINGDIPAPI GdipFillPolygon2I(GpGraphics *graphics, GpBrush *brush,
2722 GDIPCONST GpPoint *points, INT count)
2723{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002724 TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count);
2725
Nikolay Sivove04a6622008-08-03 12:19:36 +04002726 return GdipFillPolygonI(graphics, brush, points, count, FillModeAlternate);
2727}
2728
Evan Stadeb66c0a02007-08-08 19:42:10 -07002729GpStatus WINGDIPAPI GdipFillRectangle(GpGraphics *graphics, GpBrush *brush,
2730 REAL x, REAL y, REAL width, REAL height)
2731{
2732 INT save_state;
2733 GpPointF ptf[4];
2734 POINT pti[4];
2735
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002736 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height);
2737
Evan Stadeb66c0a02007-08-08 19:42:10 -07002738 if(!graphics || !brush)
2739 return InvalidParameter;
2740
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002741 if(graphics->busy)
2742 return ObjectBusy;
2743
Evan Stadeb66c0a02007-08-08 19:42:10 -07002744 ptf[0].X = x;
2745 ptf[0].Y = y;
2746 ptf[1].X = x + width;
2747 ptf[1].Y = y;
2748 ptf[2].X = x + width;
2749 ptf[2].Y = y + height;
2750 ptf[3].X = x;
2751 ptf[3].Y = y + height;
2752
2753 save_state = SaveDC(graphics->hdc);
2754 EndPath(graphics->hdc);
Evan Stadeb66c0a02007-08-08 19:42:10 -07002755
2756 transform_and_round_points(graphics, pti, ptf, 4);
2757
Vincent Povirk323e7e682009-05-06 16:34:19 -05002758 BeginPath(graphics->hdc);
Evan Stadeb66c0a02007-08-08 19:42:10 -07002759 Polygon(graphics->hdc, pti, 4);
Vincent Povirk323e7e682009-05-06 16:34:19 -05002760 EndPath(graphics->hdc);
2761
2762 brush_fill_path(graphics, brush);
Evan Stadeb66c0a02007-08-08 19:42:10 -07002763
2764 RestoreDC(graphics->hdc, save_state);
2765
2766 return Ok;
2767}
2768
Evan Stadebb904a22007-08-07 18:43:04 -07002769GpStatus WINGDIPAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush,
2770 INT x, INT y, INT width, INT height)
2771{
2772 INT save_state;
2773 GpPointF ptf[4];
2774 POINT pti[4];
2775
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002776 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height);
2777
Evan Stadebb904a22007-08-07 18:43:04 -07002778 if(!graphics || !brush)
2779 return InvalidParameter;
2780
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002781 if(graphics->busy)
2782 return ObjectBusy;
2783
Evan Stadebb904a22007-08-07 18:43:04 -07002784 ptf[0].X = x;
2785 ptf[0].Y = y;
2786 ptf[1].X = x + width;
2787 ptf[1].Y = y;
2788 ptf[2].X = x + width;
2789 ptf[2].Y = y + height;
2790 ptf[3].X = x;
2791 ptf[3].Y = y + height;
2792
2793 save_state = SaveDC(graphics->hdc);
2794 EndPath(graphics->hdc);
Evan Stadebb904a22007-08-07 18:43:04 -07002795
2796 transform_and_round_points(graphics, pti, ptf, 4);
2797
Vincent Povirk849af302009-07-11 10:38:47 -05002798 BeginPath(graphics->hdc);
Evan Stadebb904a22007-08-07 18:43:04 -07002799 Polygon(graphics->hdc, pti, 4);
Vincent Povirk849af302009-07-11 10:38:47 -05002800 EndPath(graphics->hdc);
2801
2802 brush_fill_path(graphics, brush);
Evan Stadebb904a22007-08-07 18:43:04 -07002803
2804 RestoreDC(graphics->hdc, save_state);
2805
2806 return Ok;
2807}
2808
Nikolay Sivov7ce48b02008-04-29 00:10:15 +04002809GpStatus WINGDIPAPI GdipFillRectangles(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRectF *rects,
2810 INT count)
2811{
2812 GpStatus ret;
2813 INT i;
2814
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002815 TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count);
2816
Nikolay Sivov7ce48b02008-04-29 00:10:15 +04002817 if(!rects)
2818 return InvalidParameter;
2819
2820 for(i = 0; i < count; i++){
2821 ret = GdipFillRectangle(graphics, brush, rects[i].X, rects[i].Y, rects[i].Width, rects[i].Height);
2822 if(ret != Ok) return ret;
2823 }
2824
2825 return Ok;
2826}
2827
2828GpStatus WINGDIPAPI GdipFillRectanglesI(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRect *rects,
2829 INT count)
2830{
2831 GpRectF *rectsF;
2832 GpStatus ret;
2833 INT i;
2834
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002835 TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count);
2836
Nikolay Sivov7ce48b02008-04-29 00:10:15 +04002837 if(!rects || count <= 0)
2838 return InvalidParameter;
2839
2840 rectsF = GdipAlloc(sizeof(GpRectF)*count);
2841 if(!rectsF)
2842 return OutOfMemory;
2843
2844 for(i = 0; i < count; i++){
2845 rectsF[i].X = (REAL)rects[i].X;
2846 rectsF[i].Y = (REAL)rects[i].Y;
2847 rectsF[i].X = (REAL)rects[i].Width;
2848 rectsF[i].Height = (REAL)rects[i].Height;
2849 }
2850
2851 ret = GdipFillRectangles(graphics,brush,rectsF,count);
2852 GdipFree(rectsF);
2853
2854 return ret;
2855}
2856
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002857/*****************************************************************************
2858 * GdipFillRegion [GDIPLUS.@]
2859 */
Nikolay Sivov0e840f62008-07-10 23:15:59 +04002860GpStatus WINGDIPAPI GdipFillRegion(GpGraphics* graphics, GpBrush* brush,
2861 GpRegion* region)
2862{
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002863 INT save_state;
2864 GpStatus status;
2865 HRGN hrgn;
Vincent Povirk6a8a7702009-07-11 10:57:07 -05002866 RECT rc;
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002867
2868 TRACE("(%p, %p, %p)\n", graphics, brush, region);
2869
Nikolay Sivov0e840f62008-07-10 23:15:59 +04002870 if (!(graphics && brush && region))
2871 return InvalidParameter;
2872
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002873 if(graphics->busy)
2874 return ObjectBusy;
2875
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002876 status = GdipGetRegionHRgn(region, graphics, &hrgn);
2877 if(status != Ok)
2878 return status;
Nikolay Sivov0e840f62008-07-10 23:15:59 +04002879
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002880 save_state = SaveDC(graphics->hdc);
2881 EndPath(graphics->hdc);
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002882
Vincent Povirk6a8a7702009-07-11 10:57:07 -05002883 ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
2884
2885 if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
2886 {
2887 BeginPath(graphics->hdc);
2888 Rectangle(graphics->hdc, rc.left, rc.top, rc.right, rc.bottom);
2889 EndPath(graphics->hdc);
2890
2891 brush_fill_path(graphics, brush);
2892 }
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002893
2894 RestoreDC(graphics->hdc, save_state);
2895
2896 DeleteObject(hrgn);
2897
2898 return Ok;
Nikolay Sivov0e840f62008-07-10 23:15:59 +04002899}
2900
Nikolay Sivovf620b662008-06-18 11:33:10 +04002901GpStatus WINGDIPAPI GdipFlush(GpGraphics *graphics, GpFlushIntention intention)
2902{
2903 static int calls;
2904
2905 if(!graphics)
2906 return InvalidParameter;
2907
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002908 if(graphics->busy)
2909 return ObjectBusy;
2910
Nikolay Sivovf620b662008-06-18 11:33:10 +04002911 if(!(calls++))
2912 FIXME("not implemented\n");
2913
2914 return NotImplemented;
2915}
2916
Nikolay Sivovbcfe4e72009-02-02 22:58:27 +03002917/*****************************************************************************
2918 * GdipGetClipBounds [GDIPLUS.@]
2919 */
2920GpStatus WINGDIPAPI GdipGetClipBounds(GpGraphics *graphics, GpRectF *rect)
2921{
2922 TRACE("(%p, %p)\n", graphics, rect);
2923
2924 if(!graphics)
2925 return InvalidParameter;
2926
Nikolay Sivov8c096162009-02-02 23:48:01 +03002927 if(graphics->busy)
2928 return ObjectBusy;
2929
Nikolay Sivovbcfe4e72009-02-02 22:58:27 +03002930 return GdipGetRegionBounds(graphics->clip, graphics, rect);
2931}
2932
2933/*****************************************************************************
2934 * GdipGetClipBoundsI [GDIPLUS.@]
2935 */
2936GpStatus WINGDIPAPI GdipGetClipBoundsI(GpGraphics *graphics, GpRect *rect)
2937{
2938 TRACE("(%p, %p)\n", graphics, rect);
2939
2940 if(!graphics)
2941 return InvalidParameter;
2942
Nikolay Sivov8c096162009-02-02 23:48:01 +03002943 if(graphics->busy)
2944 return ObjectBusy;
2945
Nikolay Sivovbcfe4e72009-02-02 22:58:27 +03002946 return GdipGetRegionBoundsI(graphics->clip, graphics, rect);
2947}
2948
Evan Stadee807eb92007-08-13 18:34:27 -07002949/* FIXME: Compositing mode is not used anywhere except the getter/setter. */
2950GpStatus WINGDIPAPI GdipGetCompositingMode(GpGraphics *graphics,
2951 CompositingMode *mode)
2952{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002953 TRACE("(%p, %p)\n", graphics, mode);
2954
Evan Stadee807eb92007-08-13 18:34:27 -07002955 if(!graphics || !mode)
2956 return InvalidParameter;
2957
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002958 if(graphics->busy)
2959 return ObjectBusy;
2960
Evan Stadee807eb92007-08-13 18:34:27 -07002961 *mode = graphics->compmode;
2962
2963 return Ok;
2964}
2965
Evan Stade60cad232007-07-13 17:51:25 -07002966/* FIXME: Compositing quality is not used anywhere except the getter/setter. */
2967GpStatus WINGDIPAPI GdipGetCompositingQuality(GpGraphics *graphics,
2968 CompositingQuality *quality)
2969{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002970 TRACE("(%p, %p)\n", graphics, quality);
2971
Evan Stade60cad232007-07-13 17:51:25 -07002972 if(!graphics || !quality)
2973 return InvalidParameter;
2974
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002975 if(graphics->busy)
2976 return ObjectBusy;
2977
Evan Stade60cad232007-07-13 17:51:25 -07002978 *quality = graphics->compqual;
2979
2980 return Ok;
2981}
2982
Evan Stadea87ce7a2007-07-13 17:51:29 -07002983/* FIXME: Interpolation mode is not used anywhere except the getter/setter. */
2984GpStatus WINGDIPAPI GdipGetInterpolationMode(GpGraphics *graphics,
2985 InterpolationMode *mode)
2986{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002987 TRACE("(%p, %p)\n", graphics, mode);
2988
Evan Stadea87ce7a2007-07-13 17:51:29 -07002989 if(!graphics || !mode)
2990 return InvalidParameter;
2991
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002992 if(graphics->busy)
2993 return ObjectBusy;
2994
Evan Stadea87ce7a2007-07-13 17:51:29 -07002995 *mode = graphics->interpolation;
2996
2997 return Ok;
2998}
2999
Nikolay Sivov63ae7142008-12-11 10:32:43 +03003000GpStatus WINGDIPAPI GdipGetNearestColor(GpGraphics *graphics, ARGB* argb)
3001{
3002 if(!graphics || !argb)
3003 return InvalidParameter;
3004
3005 if(graphics->busy)
3006 return ObjectBusy;
3007
3008 FIXME("(%p, %p): stub\n", graphics, argb);
3009
3010 return NotImplemented;
3011}
3012
Evan Stade81621392007-07-24 17:18:39 -07003013GpStatus WINGDIPAPI GdipGetPageScale(GpGraphics *graphics, REAL *scale)
3014{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003015 TRACE("(%p, %p)\n", graphics, scale);
3016
Evan Stade81621392007-07-24 17:18:39 -07003017 if(!graphics || !scale)
3018 return InvalidParameter;
3019
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003020 if(graphics->busy)
3021 return ObjectBusy;
3022
Evan Stade81621392007-07-24 17:18:39 -07003023 *scale = graphics->scale;
3024
3025 return Ok;
3026}
3027
Evan Stade10b575b2007-07-23 20:24:41 -07003028GpStatus WINGDIPAPI GdipGetPageUnit(GpGraphics *graphics, GpUnit *unit)
3029{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003030 TRACE("(%p, %p)\n", graphics, unit);
3031
Evan Stade10b575b2007-07-23 20:24:41 -07003032 if(!graphics || !unit)
3033 return InvalidParameter;
3034
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003035 if(graphics->busy)
3036 return ObjectBusy;
3037
Evan Stade10b575b2007-07-23 20:24:41 -07003038 *unit = graphics->unit;
3039
3040 return Ok;
3041}
3042
Evan Staded6bd866d2007-07-13 17:51:33 -07003043/* FIXME: Pixel offset mode is not used anywhere except the getter/setter. */
3044GpStatus WINGDIPAPI GdipGetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
3045 *mode)
3046{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003047 TRACE("(%p, %p)\n", graphics, mode);
3048
Evan Staded6bd866d2007-07-13 17:51:33 -07003049 if(!graphics || !mode)
3050 return InvalidParameter;
3051
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003052 if(graphics->busy)
3053 return ObjectBusy;
3054
Evan Staded6bd866d2007-07-13 17:51:33 -07003055 *mode = graphics->pixeloffset;
3056
3057 return Ok;
3058}
3059
Evan Stade53e17d22007-07-13 17:51:13 -07003060/* FIXME: Smoothing mode is not used anywhere except the getter/setter. */
3061GpStatus WINGDIPAPI GdipGetSmoothingMode(GpGraphics *graphics, SmoothingMode *mode)
3062{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003063 TRACE("(%p, %p)\n", graphics, mode);
3064
Evan Stade53e17d22007-07-13 17:51:13 -07003065 if(!graphics || !mode)
3066 return InvalidParameter;
3067
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003068 if(graphics->busy)
3069 return ObjectBusy;
3070
Evan Stade53e17d22007-07-13 17:51:13 -07003071 *mode = graphics->smoothing;
3072
3073 return Ok;
3074}
3075
Nikolay Sivov56173d42008-11-09 14:32:26 +03003076GpStatus WINGDIPAPI GdipGetTextContrast(GpGraphics *graphics, UINT *contrast)
3077{
3078 TRACE("(%p, %p)\n", graphics, contrast);
3079
3080 if(!graphics || !contrast)
3081 return InvalidParameter;
3082
3083 *contrast = graphics->textcontrast;
3084
3085 return Ok;
3086}
3087
Evan Stade56628202007-08-14 19:00:09 -07003088/* FIXME: Text rendering hint is not used anywhere except the getter/setter. */
3089GpStatus WINGDIPAPI GdipGetTextRenderingHint(GpGraphics *graphics,
3090 TextRenderingHint *hint)
3091{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003092 TRACE("(%p, %p)\n", graphics, hint);
3093
Evan Stade56628202007-08-14 19:00:09 -07003094 if(!graphics || !hint)
3095 return InvalidParameter;
3096
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003097 if(graphics->busy)
3098 return ObjectBusy;
3099
Evan Stade56628202007-08-14 19:00:09 -07003100 *hint = graphics->texthint;
3101
3102 return Ok;
3103}
3104
Evan Stadef30732f2007-07-24 17:18:47 -07003105GpStatus WINGDIPAPI GdipGetWorldTransform(GpGraphics *graphics, GpMatrix *matrix)
3106{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003107 TRACE("(%p, %p)\n", graphics, matrix);
3108
Evan Stadef30732f2007-07-24 17:18:47 -07003109 if(!graphics || !matrix)
3110 return InvalidParameter;
3111
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003112 if(graphics->busy)
3113 return ObjectBusy;
3114
Andrew Talbot5e8253a2008-02-29 22:06:47 +00003115 *matrix = *graphics->worldtrans;
Evan Stadef30732f2007-07-24 17:18:47 -07003116 return Ok;
3117}
3118
Nikolay Sivovbff16782008-09-05 13:56:10 +04003119GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics *graphics, ARGB color)
3120{
3121 GpSolidFill *brush;
3122 GpStatus stat;
3123 RECT rect;
3124
3125 TRACE("(%p, %x)\n", graphics, color);
3126
3127 if(!graphics)
3128 return InvalidParameter;
3129
3130 if(graphics->busy)
3131 return ObjectBusy;
3132
3133 if((stat = GdipCreateSolidFill(color, &brush)) != Ok)
3134 return stat;
3135
3136 if(graphics->hwnd){
3137 if(!GetWindowRect(graphics->hwnd, &rect)){
3138 GdipDeleteBrush((GpBrush*)brush);
3139 return GenericError;
3140 }
3141
3142 GdipFillRectangle(graphics, (GpBrush*)brush, 0.0, 0.0, (REAL)(rect.right - rect.left),
3143 (REAL)(rect.bottom - rect.top));
3144 }
3145 else
3146 GdipFillRectangle(graphics, (GpBrush*)brush, 0.0, 0.0, (REAL)GetDeviceCaps(graphics->hdc, HORZRES),
3147 (REAL)GetDeviceCaps(graphics->hdc, VERTRES));
3148
3149 GdipDeleteBrush((GpBrush*)brush);
3150
3151 return Ok;
3152}
3153
Nikolay Sivov813d6dc2008-08-28 17:49:41 +04003154GpStatus WINGDIPAPI GdipIsClipEmpty(GpGraphics *graphics, BOOL *res)
3155{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003156 TRACE("(%p, %p)\n", graphics, res);
3157
Nikolay Sivov813d6dc2008-08-28 17:49:41 +04003158 if(!graphics || !res)
3159 return InvalidParameter;
3160
3161 return GdipIsEmptyRegion(graphics->clip, graphics, res);
3162}
3163
Nikolay Sivov3ecb8bd2008-09-26 22:34:39 +04003164GpStatus WINGDIPAPI GdipIsVisiblePoint(GpGraphics *graphics, REAL x, REAL y, BOOL *result)
3165{
3166 FIXME("(%p, %.2f, %.2f, %p) stub\n", graphics, x, y, result);
3167
3168 if(!graphics || !result)
3169 return InvalidParameter;
3170
3171 if(graphics->busy)
3172 return ObjectBusy;
3173
3174 return NotImplemented;
3175}
3176
3177GpStatus WINGDIPAPI GdipIsVisiblePointI(GpGraphics *graphics, INT x, INT y, BOOL *result)
3178{
3179 FIXME("(%p, %d, %d, %p) stub\n", graphics, x, y, result);
3180
3181 if(!graphics || !result)
3182 return InvalidParameter;
3183
3184 if(graphics->busy)
3185 return ObjectBusy;
3186
3187 return NotImplemented;
3188}
3189
Adam Petacciabe4a2262008-07-09 03:33:40 -04003190GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics,
3191 GDIPCONST WCHAR* string, INT length, GDIPCONST GpFont* font,
3192 GDIPCONST RectF* layoutRect, GDIPCONST GpStringFormat *stringFormat,
3193 INT regionCount, GpRegion** regions)
3194{
3195 if (!(graphics && string && font && layoutRect && stringFormat && regions))
3196 return InvalidParameter;
3197
3198 FIXME("stub: %p %s %d %p %p %p %d %p\n", graphics, debugstr_w(string),
3199 length, font, layoutRect, stringFormat, regionCount, regions);
3200
3201 return NotImplemented;
3202}
3203
Evan Stade44e98392007-08-15 16:22:09 -07003204/* Find the smallest rectangle that bounds the text when it is printed in rect
3205 * according to the format options listed in format. If rect has 0 width and
3206 * height, then just find the smallest rectangle that bounds the text when it's
3207 * printed at location (rect->X, rect-Y). */
Evan Stadea51cf1d2007-08-15 16:21:52 -07003208GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
3209 GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font,
3210 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, RectF *bounds,
3211 INT *codepointsfitted, INT *linesfilled)
3212{
3213 HFONT oldfont;
3214 WCHAR* stringdup;
Evan Stade44e98392007-08-15 16:22:09 -07003215 INT sum = 0, height = 0, fit, fitcpy, max_width = 0, i, j, lret, nwidth,
Vincent Povirke0d9d172009-07-24 16:24:19 -05003216 nheight, lineend;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003217 SIZE size;
3218
Vincent Povirk0f80aa82009-05-13 14:30:00 -05003219 TRACE("(%p, %s, %i, %p, %s, %p, %p, %p, %p)\n", graphics,
3220 debugstr_wn(string, length), length, font, debugstr_rectf(rect), format,
3221 bounds, codepointsfitted, linesfilled);
3222
Evan Stadea51cf1d2007-08-15 16:21:52 -07003223 if(!graphics || !string || !font || !rect)
3224 return InvalidParameter;
3225
Hans Leidekker1e170c92008-11-24 10:22:26 +01003226 if(linesfilled) *linesfilled = 0;
3227 if(codepointsfitted) *codepointsfitted = 0;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003228
Evan Staded4107db2007-08-15 16:22:04 -07003229 if(format)
3230 TRACE("may be ignoring some format flags: attr %x\n", format->attr);
3231
Evan Stadea51cf1d2007-08-15 16:21:52 -07003232 if(length == -1) length = lstrlenW(string);
3233
Alexandre Julliarda2d04672008-09-25 11:19:23 +02003234 stringdup = GdipAlloc((length + 1) * sizeof(WCHAR));
Evan Stadea51cf1d2007-08-15 16:21:52 -07003235 if(!stringdup) return OutOfMemory;
3236
3237 oldfont = SelectObject(graphics->hdc, CreateFontIndirectW(&font->lfw));
3238 nwidth = roundr(rect->Width);
Evan Stade44e98392007-08-15 16:22:09 -07003239 nheight = roundr(rect->Height);
3240
3241 if((nwidth == 0) && (nheight == 0))
3242 nwidth = nheight = INT_MAX;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003243
3244 for(i = 0, j = 0; i < length; i++){
3245 if(!isprintW(string[i]) && (string[i] != '\n'))
3246 continue;
3247
3248 stringdup[j] = string[i];
3249 j++;
3250 }
3251
3252 stringdup[j] = 0;
3253 length = j;
3254
3255 while(sum < length){
3256 GetTextExtentExPointW(graphics->hdc, stringdup + sum, length - sum,
3257 nwidth, &fit, NULL, &size);
3258 fitcpy = fit;
3259
3260 if(fit == 0)
3261 break;
3262
3263 for(lret = 0; lret < fit; lret++)
3264 if(*(stringdup + sum + lret) == '\n')
3265 break;
3266
3267 /* Line break code (may look strange, but it imitates windows). */
3268 if(lret < fit)
Vincent Povirke0d9d172009-07-24 16:24:19 -05003269 lineend = fit = lret; /* this is not an off-by-one error */
Evan Stadea51cf1d2007-08-15 16:21:52 -07003270 else if(fit < (length - sum)){
3271 if(*(stringdup + sum + fit) == ' ')
3272 while(*(stringdup + sum + fit) == ' ')
3273 fit++;
3274 else
3275 while(*(stringdup + sum + fit - 1) != ' '){
3276 fit--;
3277
3278 if(*(stringdup + sum + fit) == '\t')
3279 break;
3280
3281 if(fit == 0){
3282 fit = fitcpy;
3283 break;
3284 }
3285 }
Vincent Povirke0d9d172009-07-24 16:24:19 -05003286 lineend = fit;
3287 while(*(stringdup + sum + lineend - 1) == ' ' ||
3288 *(stringdup + sum + lineend - 1) == '\t')
3289 lineend--;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003290 }
Vincent Povirke0d9d172009-07-24 16:24:19 -05003291 else
3292 lineend = fit;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003293
Vincent Povirke0d9d172009-07-24 16:24:19 -05003294 GetTextExtentExPointW(graphics->hdc, stringdup + sum, lineend,
Evan Stadea51cf1d2007-08-15 16:21:52 -07003295 nwidth, &j, NULL, &size);
3296
3297 sum += fit + (lret < fitcpy ? 1 : 0);
Hans Leidekker1e170c92008-11-24 10:22:26 +01003298 if(codepointsfitted) *codepointsfitted = sum;
3299
Evan Stadea51cf1d2007-08-15 16:21:52 -07003300 height += size.cy;
Hans Leidekker1e170c92008-11-24 10:22:26 +01003301 if(linesfilled) *linesfilled += size.cy;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003302 max_width = max(max_width, size.cx);
3303
Evan Stade44e98392007-08-15 16:22:09 -07003304 if(height > nheight)
Evan Stadea51cf1d2007-08-15 16:21:52 -07003305 break;
Evan Staded4107db2007-08-15 16:22:04 -07003306
3307 /* Stop if this was a linewrap (but not if it was a linebreak). */
3308 if((lret == fitcpy) && format && (format->attr & StringFormatFlagsNoWrap))
3309 break;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003310 }
3311
3312 bounds->X = rect->X;
3313 bounds->Y = rect->Y;
3314 bounds->Width = (REAL)max_width;
Evan Stade44e98392007-08-15 16:22:09 -07003315 bounds->Height = (REAL) min(height, nheight);
Evan Stadea51cf1d2007-08-15 16:21:52 -07003316
Andrew Talbotdfac0632007-09-25 20:52:58 +01003317 GdipFree(stringdup);
Evan Stadea51cf1d2007-08-15 16:21:52 -07003318 DeleteObject(SelectObject(graphics->hdc, oldfont));
3319
3320 return Ok;
3321}
3322
Nikolay Sivovff88d4e2008-08-28 17:34:22 +04003323GpStatus WINGDIPAPI GdipResetClip(GpGraphics *graphics)
3324{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003325 TRACE("(%p)\n", graphics);
3326
Nikolay Sivovff88d4e2008-08-28 17:34:22 +04003327 if(!graphics)
3328 return InvalidParameter;
3329
3330 if(graphics->busy)
3331 return ObjectBusy;
3332
3333 return GdipSetInfinite(graphics->clip);
3334}
3335
Nikolay Sivov169e87d2008-08-06 18:36:16 +04003336GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics)
3337{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003338 TRACE("(%p)\n", graphics);
3339
Nikolay Sivov169e87d2008-08-06 18:36:16 +04003340 if(!graphics)
3341 return InvalidParameter;
3342
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003343 if(graphics->busy)
3344 return ObjectBusy;
3345
Nikolay Sivov169e87d2008-08-06 18:36:16 +04003346 graphics->worldtrans->matrix[0] = 1.0;
3347 graphics->worldtrans->matrix[1] = 0.0;
3348 graphics->worldtrans->matrix[2] = 0.0;
3349 graphics->worldtrans->matrix[3] = 1.0;
3350 graphics->worldtrans->matrix[4] = 0.0;
3351 graphics->worldtrans->matrix[5] = 0.0;
3352
3353 return Ok;
3354}
3355
Evan Stadec7606682007-07-13 17:51:37 -07003356GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state)
3357{
Andrew Eikum1ef13942009-07-07 22:30:49 -05003358 return GdipEndContainer(graphics, state);
Evan Stadec7606682007-07-13 17:51:37 -07003359}
3360
Evan Stade3126c772007-08-13 18:34:35 -07003361GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle,
3362 GpMatrixOrder order)
3363{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003364 TRACE("(%p, %.2f, %d)\n", graphics, angle, order);
3365
Evan Stade3126c772007-08-13 18:34:35 -07003366 if(!graphics)
3367 return InvalidParameter;
3368
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003369 if(graphics->busy)
3370 return ObjectBusy;
3371
Evan Stade3126c772007-08-13 18:34:35 -07003372 return GdipRotateMatrix(graphics->worldtrans, angle, order);
3373}
3374
Evan Stadec7606682007-07-13 17:51:37 -07003375GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state)
3376{
Andrew Eikum1ef13942009-07-07 22:30:49 -05003377 return GdipBeginContainer2(graphics, state);
Evan Stadec7606682007-07-13 17:51:37 -07003378}
3379
Andrew Eikum632aef32009-07-05 17:04:20 -05003380GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics,
3381 GraphicsContainer *state)
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003382{
Andrew Eikum632aef32009-07-05 17:04:20 -05003383 GraphicsContainerItem *container;
3384 GpStatus sts;
3385
3386 TRACE("(%p, %p)\n", graphics, state);
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003387
3388 if(!graphics || !state)
3389 return InvalidParameter;
3390
Andrew Eikum632aef32009-07-05 17:04:20 -05003391 sts = init_container(&container, graphics);
3392 if(sts != Ok)
3393 return sts;
3394
3395 list_add_head(&graphics->containers, &container->entry);
3396 *state = graphics->contid = container->contid;
3397
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003398 return Ok;
3399}
3400
Andrew Eikum30915062009-05-31 15:00:03 -05003401GpStatus WINGDIPAPI GdipBeginContainer(GpGraphics *graphics, GDIPCONST GpRectF *dstrect, GDIPCONST GpRectF *srcrect, GpUnit unit, GraphicsContainer *state)
3402{
3403 FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state);
3404 return NotImplemented;
3405}
3406
3407GpStatus WINGDIPAPI GdipBeginContainerI(GpGraphics *graphics, GDIPCONST GpRect *dstrect, GDIPCONST GpRect *srcrect, GpUnit unit, GraphicsContainer *state)
3408{
3409 FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state);
3410 return NotImplemented;
3411}
3412
Andrew Eikumb8500082009-06-01 20:01:43 -05003413GpStatus WINGDIPAPI GdipComment(GpGraphics *graphics, UINT sizeData, GDIPCONST BYTE *data)
3414{
3415 FIXME("(%p, %d, %p): stub\n", graphics, sizeData, data);
3416 return NotImplemented;
3417}
3418
Andrew Eikuma06c2572009-07-07 22:30:29 -05003419GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer state)
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003420{
Andrew Eikum632aef32009-07-05 17:04:20 -05003421 GpStatus sts;
3422 GraphicsContainerItem *container, *container2;
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003423
Andrew Eikum632aef32009-07-05 17:04:20 -05003424 TRACE("(%p, %x)\n", graphics, state);
3425
3426 if(!graphics)
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003427 return InvalidParameter;
3428
Andrew Eikum632aef32009-07-05 17:04:20 -05003429 LIST_FOR_EACH_ENTRY(container, &graphics->containers, GraphicsContainerItem, entry){
3430 if(container->contid == state)
3431 break;
3432 }
3433
3434 /* did not find a matching container */
3435 if(&container->entry == &graphics->containers)
3436 return Ok;
3437
Andrew Eikuma06c2572009-07-07 22:30:29 -05003438 sts = restore_container(graphics, container);
3439 if(sts != Ok)
3440 return sts;
3441
Andrew Eikum632aef32009-07-05 17:04:20 -05003442 /* remove all of the containers on top of the found container */
3443 LIST_FOR_EACH_ENTRY_SAFE(container, container2, &graphics->containers, GraphicsContainerItem, entry){
3444 if(container->contid == state)
3445 break;
3446 list_remove(&container->entry);
3447 delete_container(container);
3448 }
3449
3450 list_remove(&container->entry);
Andrew Eikum632aef32009-07-05 17:04:20 -05003451 delete_container(container);
3452
Andrew Eikuma06c2572009-07-07 22:30:29 -05003453 return Ok;
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003454}
3455
Evan Stade30fdcc72007-08-13 18:34:38 -07003456GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics *graphics, REAL sx,
3457 REAL sy, GpMatrixOrder order)
3458{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003459 TRACE("(%p, %.2f, %.2f, %d)\n", graphics, sx, sy, order);
3460
Evan Stade30fdcc72007-08-13 18:34:38 -07003461 if(!graphics)
3462 return InvalidParameter;
3463
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003464 if(graphics->busy)
3465 return ObjectBusy;
3466
Evan Stade30fdcc72007-08-13 18:34:38 -07003467 return GdipScaleMatrix(graphics->worldtrans, sx, sy, order);
3468}
3469
Nikolay Sivovc543f3d2008-10-22 20:03:10 +04003470GpStatus WINGDIPAPI GdipSetClipGraphics(GpGraphics *graphics, GpGraphics *srcgraphics,
3471 CombineMode mode)
3472{
3473 TRACE("(%p, %p, %d)\n", graphics, srcgraphics, mode);
3474
3475 if(!graphics || !srcgraphics)
3476 return InvalidParameter;
3477
3478 return GdipCombineRegionRegion(graphics->clip, srcgraphics->clip, mode);
3479}
3480
Evan Stadee807eb92007-08-13 18:34:27 -07003481GpStatus WINGDIPAPI GdipSetCompositingMode(GpGraphics *graphics,
3482 CompositingMode mode)
3483{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003484 TRACE("(%p, %d)\n", graphics, mode);
3485
Evan Stadee807eb92007-08-13 18:34:27 -07003486 if(!graphics)
3487 return InvalidParameter;
3488
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003489 if(graphics->busy)
3490 return ObjectBusy;
3491
Evan Stadee807eb92007-08-13 18:34:27 -07003492 graphics->compmode = mode;
3493
3494 return Ok;
3495}
3496
Evan Stade60cad232007-07-13 17:51:25 -07003497GpStatus WINGDIPAPI GdipSetCompositingQuality(GpGraphics *graphics,
3498 CompositingQuality quality)
3499{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003500 TRACE("(%p, %d)\n", graphics, quality);
3501
Evan Stade60cad232007-07-13 17:51:25 -07003502 if(!graphics)
3503 return InvalidParameter;
3504
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003505 if(graphics->busy)
3506 return ObjectBusy;
3507
Evan Stade60cad232007-07-13 17:51:25 -07003508 graphics->compqual = quality;
3509
3510 return Ok;
3511}
3512
Evan Stadea87ce7a2007-07-13 17:51:29 -07003513GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics,
3514 InterpolationMode mode)
3515{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003516 TRACE("(%p, %d)\n", graphics, mode);
3517
Evan Stadea87ce7a2007-07-13 17:51:29 -07003518 if(!graphics)
3519 return InvalidParameter;
3520
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003521 if(graphics->busy)
3522 return ObjectBusy;
3523
Evan Stadea87ce7a2007-07-13 17:51:29 -07003524 graphics->interpolation = mode;
3525
3526 return Ok;
3527}
3528
Evan Stade81621392007-07-24 17:18:39 -07003529GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale)
3530{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003531 TRACE("(%p, %.2f)\n", graphics, scale);
3532
Evan Stade81621392007-07-24 17:18:39 -07003533 if(!graphics || (scale <= 0.0))
3534 return InvalidParameter;
3535
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003536 if(graphics->busy)
3537 return ObjectBusy;
3538
Evan Stade81621392007-07-24 17:18:39 -07003539 graphics->scale = scale;
3540
3541 return Ok;
3542}
3543
Evan Stade10b575b2007-07-23 20:24:41 -07003544GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics *graphics, GpUnit unit)
3545{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003546 TRACE("(%p, %d)\n", graphics, unit);
3547
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003548 if(!graphics)
3549 return InvalidParameter;
3550
3551 if(graphics->busy)
3552 return ObjectBusy;
3553
3554 if(unit == UnitWorld)
Evan Stade10b575b2007-07-23 20:24:41 -07003555 return InvalidParameter;
3556
3557 graphics->unit = unit;
3558
3559 return Ok;
3560}
3561
Evan Staded6bd866d2007-07-13 17:51:33 -07003562GpStatus WINGDIPAPI GdipSetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
3563 mode)
3564{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003565 TRACE("(%p, %d)\n", graphics, mode);
3566
Evan Staded6bd866d2007-07-13 17:51:33 -07003567 if(!graphics)
3568 return InvalidParameter;
3569
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003570 if(graphics->busy)
3571 return ObjectBusy;
3572
Evan Staded6bd866d2007-07-13 17:51:33 -07003573 graphics->pixeloffset = mode;
3574
3575 return Ok;
3576}
3577
Vincent Povirk27b47ea2009-05-06 16:03:27 -05003578GpStatus WINGDIPAPI GdipSetRenderingOrigin(GpGraphics *graphics, INT x, INT y)
3579{
3580 static int calls;
3581
3582 TRACE("(%p,%i,%i)\n", graphics, x, y);
3583
3584 if (!(calls++))
3585 FIXME("not implemented\n");
3586
3587 return NotImplemented;
3588}
3589
Evan Stade53e17d22007-07-13 17:51:13 -07003590GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode mode)
3591{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003592 TRACE("(%p, %d)\n", graphics, mode);
3593
Evan Stade53e17d22007-07-13 17:51:13 -07003594 if(!graphics)
3595 return InvalidParameter;
3596
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003597 if(graphics->busy)
3598 return ObjectBusy;
3599
Evan Stade53e17d22007-07-13 17:51:13 -07003600 graphics->smoothing = mode;
3601
3602 return Ok;
3603}
Evan Stadef30732f2007-07-24 17:18:47 -07003604
Nikolay Sivov71264732008-11-09 14:38:16 +03003605GpStatus WINGDIPAPI GdipSetTextContrast(GpGraphics *graphics, UINT contrast)
3606{
3607 TRACE("(%p, %d)\n", graphics, contrast);
3608
3609 if(!graphics)
3610 return InvalidParameter;
3611
3612 graphics->textcontrast = contrast;
3613
3614 return Ok;
3615}
3616
Evan Stade56628202007-08-14 19:00:09 -07003617GpStatus WINGDIPAPI GdipSetTextRenderingHint(GpGraphics *graphics,
3618 TextRenderingHint hint)
3619{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003620 TRACE("(%p, %d)\n", graphics, hint);
3621
Evan Stade56628202007-08-14 19:00:09 -07003622 if(!graphics)
3623 return InvalidParameter;
3624
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003625 if(graphics->busy)
3626 return ObjectBusy;
3627
Evan Stade56628202007-08-14 19:00:09 -07003628 graphics->texthint = hint;
3629
3630 return Ok;
3631}
3632
Evan Stadef30732f2007-07-24 17:18:47 -07003633GpStatus WINGDIPAPI GdipSetWorldTransform(GpGraphics *graphics, GpMatrix *matrix)
3634{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003635 TRACE("(%p, %p)\n", graphics, matrix);
3636
Evan Stadef30732f2007-07-24 17:18:47 -07003637 if(!graphics || !matrix)
3638 return InvalidParameter;
3639
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003640 if(graphics->busy)
3641 return ObjectBusy;
3642
Evan Stadef30732f2007-07-24 17:18:47 -07003643 GdipDeleteMatrix(graphics->worldtrans);
3644 return GdipCloneMatrix(matrix, &graphics->worldtrans);
3645}
Evan Stade795b6222007-08-09 18:25:31 -07003646
3647GpStatus WINGDIPAPI GdipTranslateWorldTransform(GpGraphics *graphics, REAL dx,
3648 REAL dy, GpMatrixOrder order)
3649{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003650 TRACE("(%p, %.2f, %.2f, %d)\n", graphics, dx, dy, order);
3651
Evan Stade795b6222007-08-09 18:25:31 -07003652 if(!graphics)
3653 return InvalidParameter;
3654
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003655 if(graphics->busy)
3656 return ObjectBusy;
3657
Evan Stade795b6222007-08-09 18:25:31 -07003658 return GdipTranslateMatrix(graphics->worldtrans, dx, dy, order);
3659}
Lei Zhangd9a42992008-04-08 14:44:41 -07003660
Nikolay Sivovf8edb062009-02-02 23:33:41 +03003661/*****************************************************************************
3662 * GdipSetClipHrgn [GDIPLUS.@]
3663 */
3664GpStatus WINGDIPAPI GdipSetClipHrgn(GpGraphics *graphics, HRGN hrgn, CombineMode mode)
3665{
3666 GpRegion *region;
3667 GpStatus status;
3668
3669 TRACE("(%p, %p, %d)\n", graphics, hrgn, mode);
3670
3671 if(!graphics)
3672 return InvalidParameter;
3673
3674 status = GdipCreateRegionHrgn(hrgn, &region);
3675 if(status != Ok)
3676 return status;
3677
3678 status = GdipSetClipRegion(graphics, region, mode);
3679
3680 GdipDeleteRegion(region);
3681 return status;
3682}
3683
Nikolay Sivove2817e52008-09-26 22:18:09 +04003684GpStatus WINGDIPAPI GdipSetClipPath(GpGraphics *graphics, GpPath *path, CombineMode mode)
3685{
3686 TRACE("(%p, %p, %d)\n", graphics, path, mode);
3687
3688 if(!graphics)
3689 return InvalidParameter;
3690
3691 if(graphics->busy)
3692 return ObjectBusy;
3693
3694 return GdipCombineRegionPath(graphics->clip, path, mode);
3695}
3696
Nikolay Sivov8d9c4862008-09-25 10:41:15 +04003697GpStatus WINGDIPAPI GdipSetClipRect(GpGraphics *graphics, REAL x, REAL y,
3698 REAL width, REAL height,
3699 CombineMode mode)
Lei Zhangd9a42992008-04-08 14:44:41 -07003700{
Nikolay Sivov8d9c4862008-09-25 10:41:15 +04003701 GpRectF rect;
3702
3703 TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %d)\n", graphics, x, y, width, height, mode);
Lei Zhangd9a42992008-04-08 14:44:41 -07003704
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003705 if(!graphics)
3706 return InvalidParameter;
3707
3708 if(graphics->busy)
3709 return ObjectBusy;
3710
Nikolay Sivov8d9c4862008-09-25 10:41:15 +04003711 rect.X = x;
3712 rect.Y = y;
3713 rect.Width = width;
3714 rect.Height = height;
Lei Zhangd9a42992008-04-08 14:44:41 -07003715
Nikolay Sivov8d9c4862008-09-25 10:41:15 +04003716 return GdipCombineRegionRect(graphics->clip, &rect, mode);
3717}
3718
3719GpStatus WINGDIPAPI GdipSetClipRectI(GpGraphics *graphics, INT x, INT y,
3720 INT width, INT height,
3721 CombineMode mode)
3722{
3723 TRACE("(%p, %d, %d, %d, %d, %d)\n", graphics, x, y, width, height, mode);
3724
3725 if(!graphics)
3726 return InvalidParameter;
3727
3728 if(graphics->busy)
3729 return ObjectBusy;
3730
3731 return GdipSetClipRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, mode);
Lei Zhangd9a42992008-04-08 14:44:41 -07003732}
Lei Zhangcec6c2e2008-04-09 12:35:29 -07003733
3734GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region,
Nikolay Sivov0df5fb52008-08-27 23:30:59 +04003735 CombineMode mode)
Lei Zhangcec6c2e2008-04-09 12:35:29 -07003736{
Nikolay Sivov0df5fb52008-08-27 23:30:59 +04003737 TRACE("(%p, %p, %d)\n", graphics, region, mode);
Lei Zhangcec6c2e2008-04-09 12:35:29 -07003738
Nikolay Sivov0df5fb52008-08-27 23:30:59 +04003739 if(!graphics || !region)
3740 return InvalidParameter;
Lei Zhangcec6c2e2008-04-09 12:35:29 -07003741
Nikolay Sivov0df5fb52008-08-27 23:30:59 +04003742 if(graphics->busy)
3743 return ObjectBusy;
3744
3745 return GdipCombineRegionRegion(graphics->clip, region, mode);
Lei Zhangcec6c2e2008-04-09 12:35:29 -07003746}
Lei Zhang54a06642008-04-10 12:40:21 -07003747
Nikolay Sivov45705012008-08-24 14:45:14 +04003748GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
Lei Zhang54a06642008-04-10 12:40:21 -07003749 UINT limitDpi)
3750{
3751 static int calls;
3752
3753 if(!(calls++))
3754 FIXME("not implemented\n");
3755
3756 return NotImplemented;
3757}
Nikolay Sivov46975932008-04-24 20:48:17 +04003758
3759GpStatus WINGDIPAPI GdipDrawPolygon(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPointF *points,
3760 INT count)
3761{
3762 INT save_state;
3763 POINT *pti;
3764
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003765 TRACE("(%p, %p, %d)\n", graphics, points, count);
3766
Nikolay Sivov46975932008-04-24 20:48:17 +04003767 if(!graphics || !pen || count<=0)
3768 return InvalidParameter;
3769
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003770 if(graphics->busy)
3771 return ObjectBusy;
3772
Nikolay Sivov46975932008-04-24 20:48:17 +04003773 pti = GdipAlloc(sizeof(POINT) * count);
3774
3775 save_state = prepare_dc(graphics, pen);
3776 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
3777
3778 transform_and_round_points(graphics, pti, (GpPointF*)points, count);
3779 Polygon(graphics->hdc, pti, count);
3780
3781 restore_dc(graphics, save_state);
3782 GdipFree(pti);
3783
3784 return Ok;
3785}
3786
3787GpStatus WINGDIPAPI GdipDrawPolygonI(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPoint *points,
3788 INT count)
3789{
3790 GpStatus ret;
3791 GpPointF *ptf;
3792 INT i;
3793
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003794 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
3795
Nikolay Sivov46975932008-04-24 20:48:17 +04003796 if(count<=0) return InvalidParameter;
3797 ptf = GdipAlloc(sizeof(GpPointF) * count);
3798
3799 for(i = 0;i < count; i++){
3800 ptf[i].X = (REAL)points[i].X;
3801 ptf[i].Y = (REAL)points[i].Y;
3802 }
3803
3804 ret = GdipDrawPolygon(graphics,pen,ptf,count);
3805 GdipFree(ptf);
3806
3807 return ret;
3808}
Nikolay Sivovd5769952008-04-29 00:10:20 +04003809
3810GpStatus WINGDIPAPI GdipGetDpiX(GpGraphics *graphics, REAL* dpi)
3811{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003812 TRACE("(%p, %p)\n", graphics, dpi);
3813
Nikolay Sivovd5769952008-04-29 00:10:20 +04003814 if(!graphics || !dpi)
3815 return InvalidParameter;
3816
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003817 if(graphics->busy)
3818 return ObjectBusy;
3819
Nikolay Sivovd5769952008-04-29 00:10:20 +04003820 *dpi = (REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSX);
3821
3822 return Ok;
3823}
3824
3825GpStatus WINGDIPAPI GdipGetDpiY(GpGraphics *graphics, REAL* dpi)
3826{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003827 TRACE("(%p, %p)\n", graphics, dpi);
3828
Nikolay Sivovd5769952008-04-29 00:10:20 +04003829 if(!graphics || !dpi)
3830 return InvalidParameter;
3831
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003832 if(graphics->busy)
3833 return ObjectBusy;
3834
Nikolay Sivovd5769952008-04-29 00:10:20 +04003835 *dpi = (REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSY);
3836
3837 return Ok;
3838}
Nikolay Sivov510c26a2008-04-30 01:28:40 +04003839
3840GpStatus WINGDIPAPI GdipMultiplyWorldTransform(GpGraphics *graphics, GDIPCONST GpMatrix *matrix,
3841 GpMatrixOrder order)
3842{
3843 GpMatrix m;
3844 GpStatus ret;
3845
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003846 TRACE("(%p, %p, %d)\n", graphics, matrix, order);
3847
Nikolay Sivov510c26a2008-04-30 01:28:40 +04003848 if(!graphics || !matrix)
3849 return InvalidParameter;
3850
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003851 if(graphics->busy)
3852 return ObjectBusy;
3853
Nikolay Sivov510c26a2008-04-30 01:28:40 +04003854 m = *(graphics->worldtrans);
3855
Michael Stefaniucb53877d2009-01-14 09:52:24 +01003856 ret = GdipMultiplyMatrix(&m, matrix, order);
Nikolay Sivov510c26a2008-04-30 01:28:40 +04003857 if(ret == Ok)
3858 *(graphics->worldtrans) = m;
3859
3860 return ret;
3861}
Huw Davies6cfb4692008-05-12 16:51:32 +01003862
3863GpStatus WINGDIPAPI GdipGetDC(GpGraphics *graphics, HDC *hdc)
3864{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003865 TRACE("(%p, %p)\n", graphics, hdc);
3866
Nikolay Sivov45705012008-08-24 14:45:14 +04003867 if(!graphics || !hdc)
3868 return InvalidParameter;
3869
Nikolay Sivov366ae1e2008-08-24 14:45:18 +04003870 if(graphics->busy)
3871 return ObjectBusy;
3872
3873 *hdc = graphics->hdc;
3874 graphics->busy = TRUE;
3875
3876 return Ok;
Huw Davies6cfb4692008-05-12 16:51:32 +01003877}
3878
3879GpStatus WINGDIPAPI GdipReleaseDC(GpGraphics *graphics, HDC hdc)
3880{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003881 TRACE("(%p, %p)\n", graphics, hdc);
3882
Nikolay Sivov45705012008-08-24 14:45:14 +04003883 if(!graphics)
3884 return InvalidParameter;
3885
Nikolay Sivov366ae1e2008-08-24 14:45:18 +04003886 if(graphics->hdc != hdc || !(graphics->busy))
Nikolay Sivov45705012008-08-24 14:45:14 +04003887 return InvalidParameter;
3888
Nikolay Sivov366ae1e2008-08-24 14:45:18 +04003889 graphics->busy = FALSE;
3890
3891 return Ok;
Huw Davies6cfb4692008-05-12 16:51:32 +01003892}
Huw Daviesd5ccbe22008-05-12 16:57:28 +01003893
3894GpStatus WINGDIPAPI GdipGetClip(GpGraphics *graphics, GpRegion *region)
3895{
Nikolay Sivovef50aa32008-08-27 02:03:27 +04003896 GpRegion *clip;
3897 GpStatus status;
3898
3899 TRACE("(%p, %p)\n", graphics, region);
3900
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003901 if(!graphics || !region)
3902 return InvalidParameter;
Huw Daviesd5ccbe22008-05-12 16:57:28 +01003903
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003904 if(graphics->busy)
3905 return ObjectBusy;
3906
Nikolay Sivovef50aa32008-08-27 02:03:27 +04003907 if((status = GdipCloneRegion(graphics->clip, &clip)) != Ok)
3908 return status;
3909
3910 /* free everything except root node and header */
3911 delete_element(&region->node);
3912 memcpy(region, clip, sizeof(GpRegion));
3913
3914 return Ok;
Huw Daviesd5ccbe22008-05-12 16:57:28 +01003915}
Huw Davies3ab76662008-07-10 15:26:58 +01003916
3917GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space,
3918 GpCoordinateSpace src_space, GpPointF *points, INT count)
3919{
Vincent Povirk2af29ed2009-03-23 16:34:12 -05003920 GpMatrix *matrix;
3921 GpStatus stat;
3922 REAL unitscale;
3923
Nikolay Sivovc61ece62008-08-26 01:58:42 +04003924 if(!graphics || !points || count <= 0)
3925 return InvalidParameter;
3926
3927 if(graphics->busy)
3928 return ObjectBusy;
3929
Vincent Povirk2af29ed2009-03-23 16:34:12 -05003930 TRACE("(%p, %d, %d, %p, %d)\n", graphics, dst_space, src_space, points, count);
Huw Davies3ab76662008-07-10 15:26:58 +01003931
Vincent Povirk2af29ed2009-03-23 16:34:12 -05003932 if (src_space == dst_space) return Ok;
3933
3934 stat = GdipCreateMatrix(&matrix);
3935 if (stat == Ok)
3936 {
3937 unitscale = convert_unit(graphics->hdc, graphics->unit);
3938
3939 if(graphics->unit != UnitDisplay)
3940 unitscale *= graphics->scale;
3941
3942 /* transform from src_space to CoordinateSpacePage */
3943 switch (src_space)
3944 {
3945 case CoordinateSpaceWorld:
3946 GdipMultiplyMatrix(matrix, graphics->worldtrans, MatrixOrderAppend);
3947 break;
3948 case CoordinateSpacePage:
3949 break;
3950 case CoordinateSpaceDevice:
3951 GdipScaleMatrix(matrix, 1.0/unitscale, 1.0/unitscale, MatrixOrderAppend);
3952 break;
3953 }
3954
3955 /* transform from CoordinateSpacePage to dst_space */
3956 switch (dst_space)
3957 {
3958 case CoordinateSpaceWorld:
3959 {
3960 GpMatrix *inverted_transform;
3961 stat = GdipCloneMatrix(graphics->worldtrans, &inverted_transform);
3962 if (stat == Ok)
3963 {
3964 stat = GdipInvertMatrix(inverted_transform);
3965 if (stat == Ok)
3966 GdipMultiplyMatrix(matrix, inverted_transform, MatrixOrderAppend);
3967 GdipDeleteMatrix(inverted_transform);
3968 }
3969 break;
3970 }
3971 case CoordinateSpacePage:
3972 break;
3973 case CoordinateSpaceDevice:
3974 GdipScaleMatrix(matrix, unitscale, unitscale, MatrixOrderAppend);
3975 break;
3976 }
3977
3978 if (stat == Ok)
3979 stat = GdipTransformMatrixPoints(matrix, points, count);
3980
3981 GdipDeleteMatrix(matrix);
3982 }
3983
3984 return stat;
Huw Davies3ab76662008-07-10 15:26:58 +01003985}
3986
3987GpStatus WINGDIPAPI GdipTransformPointsI(GpGraphics *graphics, GpCoordinateSpace dst_space,
3988 GpCoordinateSpace src_space, GpPoint *points, INT count)
3989{
Vincent Povirkc486e812009-05-19 15:40:43 -05003990 GpPointF *pointsF;
3991 GpStatus ret;
3992 INT i;
Huw Davies3ab76662008-07-10 15:26:58 +01003993
Vincent Povirkc486e812009-05-19 15:40:43 -05003994 TRACE("(%p, %d, %d, %p, %d)\n", graphics, dst_space, src_space, points, count);
3995
3996 if(count <= 0)
3997 return InvalidParameter;
3998
3999 pointsF = GdipAlloc(sizeof(GpPointF) * count);
4000 if(!pointsF)
4001 return OutOfMemory;
4002
4003 for(i = 0; i < count; i++){
4004 pointsF[i].X = (REAL)points[i].X;
4005 pointsF[i].Y = (REAL)points[i].Y;
4006 }
4007
4008 ret = GdipTransformPoints(graphics, dst_space, src_space, pointsF, count);
4009
4010 if(ret == Ok)
4011 for(i = 0; i < count; i++){
4012 points[i].X = roundr(pointsF[i].X);
4013 points[i].Y = roundr(pointsF[i].Y);
4014 }
4015 GdipFree(pointsF);
4016
4017 return ret;
Huw Davies3ab76662008-07-10 15:26:58 +01004018}
Hans Leidekker6122c772008-11-24 10:23:03 +01004019
4020HPALETTE WINGDIPAPI GdipCreateHalftonePalette(void)
4021{
4022 FIXME("\n");
4023
4024 return NULL;
4025}
Nikolay Sivov5da52e02009-01-31 00:07:30 +03004026
4027/*****************************************************************************
4028 * GdipTranslateClip [GDIPLUS.@]
4029 */
4030GpStatus WINGDIPAPI GdipTranslateClip(GpGraphics *graphics, REAL dx, REAL dy)
4031{
4032 TRACE("(%p, %.2f, %.2f)\n", graphics, dx, dy);
4033
4034 if(!graphics)
4035 return InvalidParameter;
4036
Nikolay Sivov8c096162009-02-02 23:48:01 +03004037 if(graphics->busy)
4038 return ObjectBusy;
4039
Nikolay Sivov5da52e02009-01-31 00:07:30 +03004040 return GdipTranslateRegion(graphics->clip, dx, dy);
4041}
4042
4043/*****************************************************************************
4044 * GdipTranslateClipI [GDIPLUS.@]
4045 */
4046GpStatus WINGDIPAPI GdipTranslateClipI(GpGraphics *graphics, INT dx, INT dy)
4047{
4048 TRACE("(%p, %d, %d)\n", graphics, dx, dy);
4049
4050 if(!graphics)
4051 return InvalidParameter;
4052
Nikolay Sivov8c096162009-02-02 23:48:01 +03004053 if(graphics->busy)
4054 return ObjectBusy;
4055
Nikolay Sivov5da52e02009-01-31 00:07:30 +03004056 return GdipTranslateRegion(graphics->clip, (REAL)dx, (REAL)dy);
4057}
Ken Sharpe3f48592009-06-09 21:48:05 +01004058
4059
4060/*****************************************************************************
4061 * GdipMeasureDriverString [GDIPLUS.@]
4062 */
4063GpStatus WINGDIPAPI GdipMeasureDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length,
4064 GDIPCONST GpFont *font, GDIPCONST PointF *positions,
4065 INT flags, GDIPCONST GpMatrix *matrix, RectF *boundingBox)
4066{
4067 FIXME("(%p %p %d %p %p %d %p %p): stub\n", graphics, text, length, font, positions, flags, matrix, boundingBox);
4068 return NotImplemented;
4069}
4070
4071/*****************************************************************************
4072 * GdipGetVisibleClipBoundsI [GDIPLUS.@]
4073 */
4074GpStatus WINGDIPAPI GdipGetVisibleClipBoundsI(GpGraphics *graphics, GpRect *rect)
4075{
4076 FIXME("(%p %p): stub\n", graphics, rect);
4077 return NotImplemented;
4078}
4079
4080/*****************************************************************************
4081 * GdipDrawDriverString [GDIPLUS.@]
4082 */
4083GpStatus WINGDIPAPI GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length,
4084 GDIPCONST GpFont *font, GDIPCONST GpBrush *brush,
4085 GDIPCONST PointF *positions, INT flags,
4086 GDIPCONST GpMatrix *matrix )
4087{
Francois Gouget489bd522009-06-15 11:00:03 +02004088 FIXME("(%p %p %d %p %p %p %d %p): stub\n", graphics, text, length, font, brush, positions, flags, matrix);
Ken Sharpe3f48592009-06-09 21:48:05 +01004089 return NotImplemented;
4090}
Ken Sharpe096b592009-06-22 21:59:59 +01004091
4092/*****************************************************************************
4093 * GdipIsVisibleRegionPointI [GDIPLUS.@]
4094 */
4095GpStatus WINGDIPAPI GdipIsVisibleRegionPointI(GpRegion *region, INT x, INT y, GpGraphics *graphics, BOOL *result)
4096{
4097 FIXME("(%p %d %d %p %p): stub\n", region, x, y, graphics, result);
4098 return NotImplemented;
4099}
Alistair Leslie-Hughes7b2292f2009-07-30 13:56:42 +10004100
4101/*****************************************************************************
4102 * GdipRecordMetafileI [GDIPLUS.@]
4103 */
4104GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
4105 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
4106{
4107 FIXME("(%p %d %p %d %p %p): stub\n", hdc, type, frameRect, frameUnit, desc, metafile);
4108 return NotImplemented;
4109}