blob: 6a1dc10d600ea6518b77eda2acc7d68c6ab61f47 [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 Povirk9c380b12010-04-15 14:11:07 -0500176/* Draw non-premultiplied ARGB data to the given graphics object */
177static GpStatus alpha_blend_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
178 const BYTE *src, INT src_width, INT src_height, INT src_stride)
179{
180 if (graphics->image && graphics->image->type == ImageTypeBitmap)
181 {
182 GpBitmap *dst_bitmap = (GpBitmap*)graphics->image;
183 INT x, y;
184
185 for (x=0; x<src_width; x++)
186 {
187 for (y=0; y<src_height; y++)
188 {
189 ARGB dst_color, src_color;
190 GdipBitmapGetPixel(dst_bitmap, x+dst_x, y+dst_y, &dst_color);
191 src_color = ((ARGB*)(src + src_stride * y))[x];
192 GdipBitmapSetPixel(dst_bitmap, x+dst_x, y+dst_y, color_over(dst_color, src_color));
193 }
194 }
195
196 return Ok;
197 }
198 else
199 {
200 ERR("Not implemented for non-bitmap DC's\n");
201 return GenericError;
202 }
203}
204
Vincent Povirka6161302009-05-01 14:26:50 -0500205static ARGB blend_colors(ARGB start, ARGB end, REAL position)
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500206{
207 ARGB result=0;
208 ARGB i;
209 for (i=0xff; i<=0xff0000; i = i << 8)
Vincent Povirka6161302009-05-01 14:26:50 -0500210 result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500211 return result;
212}
213
Vincent Povirka6161302009-05-01 14:26:50 -0500214static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
215{
216 REAL blendfac;
217
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500218 /* clamp to between 0.0 and 1.0, using the wrap mode */
219 if (brush->wrap == WrapModeTile)
220 {
221 position = fmodf(position, 1.0f);
222 if (position < 0.0f) position += 1.0f;
223 }
224 else /* WrapModeFlip* */
225 {
226 position = fmodf(position, 2.0f);
227 if (position < 0.0f) position += 2.0f;
228 if (position > 1.0f) position = 2.0f - position;
229 }
230
Vincent Povirka6161302009-05-01 14:26:50 -0500231 if (brush->blendcount == 1)
232 blendfac = position;
233 else
234 {
235 int i=1;
236 REAL left_blendpos, left_blendfac, right_blendpos, right_blendfac;
237 REAL range;
238
239 /* locate the blend positions surrounding this position */
240 while (position > brush->blendpos[i])
241 i++;
242
243 /* interpolate between the blend positions */
244 left_blendpos = brush->blendpos[i-1];
245 left_blendfac = brush->blendfac[i-1];
246 right_blendpos = brush->blendpos[i];
247 right_blendfac = brush->blendfac[i];
248 range = right_blendpos - left_blendpos;
249 blendfac = (left_blendfac * (right_blendpos - position) +
250 right_blendfac * (position - left_blendpos)) / range;
251 }
Vincent Povirkd2e999d2009-09-14 16:48:03 -0500252
253 if (brush->pblendcount == 0)
254 return blend_colors(brush->startcolor, brush->endcolor, blendfac);
255 else
256 {
257 int i=1;
258 ARGB left_blendcolor, right_blendcolor;
259 REAL left_blendpos, right_blendpos;
260
261 /* locate the blend colors surrounding this position */
262 while (blendfac > brush->pblendpos[i])
263 i++;
264
265 /* interpolate between the blend colors */
266 left_blendpos = brush->pblendpos[i-1];
267 left_blendcolor = brush->pblendcolor[i-1];
268 right_blendpos = brush->pblendpos[i];
269 right_blendcolor = brush->pblendcolor[i];
270 blendfac = (blendfac - left_blendpos) / (right_blendpos - left_blendpos);
271 return blend_colors(left_blendcolor, right_blendcolor, blendfac);
272 }
Vincent Povirka6161302009-05-01 14:26:50 -0500273}
274
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500275static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
276{
277 switch (brush->bt)
278 {
279 case BrushTypeLinearGradient:
280 {
281 GpLineGradient *line = (GpLineGradient*)brush;
282 RECT rc;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500283
284 SelectClipPath(graphics->hdc, RGN_AND);
285 if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
286 {
287 GpPointF endpointsf[2];
288 POINT endpointsi[2];
289 POINT poly[4];
290
291 SelectObject(graphics->hdc, GetStockObject(NULL_PEN));
292
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500293 endpointsf[0] = line->startpoint;
294 endpointsf[1] = line->endpoint;
295 transform_and_round_points(graphics, endpointsi, endpointsf, 2);
296
297 if (abs(endpointsi[0].x-endpointsi[1].x) > abs(endpointsi[0].y-endpointsi[1].y))
298 {
299 /* vertical-ish gradient */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500300 int startx, endx; /* x co-ordinates of endpoints shifted to intersect the top of the visible rectangle */
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500301 int startbottomx; /* x co-ordinate of start point shifted to intersect the bottom of the visible rectangle */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500302 int width;
303 COLORREF col;
304 HBRUSH hbrush, hprevbrush;
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500305 int leftx, rightx; /* x co-ordinates where the leftmost and rightmost gradient lines hit the top of the visible rectangle */
306 int x;
307 int tilt; /* horizontal distance covered by a gradient line */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500308
309 startx = roundr((rc.top - endpointsf[0].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[0].X);
310 endx = roundr((rc.top - endpointsf[1].Y) * (endpointsf[1].Y - endpointsf[0].Y) / (endpointsf[0].X - endpointsf[1].X) + endpointsf[1].X);
311 width = endx - startx;
312 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 -0500313 tilt = startx - startbottomx;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500314
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500315 if (startx >= startbottomx)
316 {
317 leftx = rc.left;
318 rightx = rc.right + tilt;
319 }
320 else
321 {
322 leftx = rc.left + tilt;
323 rightx = rc.right;
324 }
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500325
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500326 poly[0].y = rc.bottom;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500327 poly[1].y = rc.top;
328 poly[2].y = rc.top;
329 poly[3].y = rc.bottom;
330
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500331 for (x=leftx; x<=rightx; x++)
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500332 {
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500333 ARGB argb = blend_line_gradient(line, (x-startx)/(REAL)width);
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].x = x - tilt - 1;
338 poly[1].x = x - 1;
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500339 poly[2].x = x;
340 poly[3].x = x - 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 if (endpointsi[0].y != endpointsi[1].y)
347 {
348 /* horizontal-ish gradient */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500349 int starty, endy; /* y co-ordinates of endpoints shifted to intersect the left of the visible rectangle */
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500350 int startrighty; /* y co-ordinate of start point shifted to intersect the right of the visible rectangle */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500351 int height;
352 COLORREF col;
353 HBRUSH hbrush, hprevbrush;
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500354 int topy, bottomy; /* y co-ordinates where the topmost and bottommost gradient lines hit the left of the visible rectangle */
355 int y;
356 int tilt; /* vertical distance covered by a gradient line */
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500357
358 starty = roundr((rc.left - endpointsf[0].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[0].Y);
359 endy = roundr((rc.left - endpointsf[1].X) * (endpointsf[0].X - endpointsf[1].X) / (endpointsf[1].Y - endpointsf[0].Y) + endpointsf[1].Y);
360 height = endy - starty;
361 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 -0500362 tilt = starty - startrighty;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500363
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500364 if (starty >= startrighty)
365 {
366 topy = rc.top;
367 bottomy = rc.bottom + tilt;
368 }
369 else
370 {
371 topy = rc.top + tilt;
372 bottomy = rc.bottom;
373 }
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500374
375 poly[0].x = rc.right;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500376 poly[1].x = rc.left;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500377 poly[2].x = rc.left;
378 poly[3].x = rc.right;
379
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500380 for (y=topy; y<=bottomy; y++)
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500381 {
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500382 ARGB argb = blend_line_gradient(line, (y-starty)/(REAL)height);
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500383 col = ARGB2COLORREF(argb);
384 hbrush = CreateSolidBrush(col);
385 hprevbrush = SelectObject(graphics->hdc, hbrush);
Vincent Povirkcb478a32009-05-01 15:37:35 -0500386 poly[0].y = y - tilt - 1;
387 poly[1].y = y - 1;
Vincent Povirk966fd5e2009-05-01 15:23:02 -0500388 poly[2].y = y;
389 poly[3].y = y - tilt;
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500390 Polygon(graphics->hdc, poly, 4);
391 SelectObject(graphics->hdc, hprevbrush);
392 DeleteObject(hbrush);
393 }
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500394 }
395 /* else startpoint == endpoint */
396 }
397 break;
398 }
Vincent Povirk60167df2009-05-20 11:24:18 -0500399 case BrushTypeSolidColor:
400 {
401 GpSolidFill *fill = (GpSolidFill*)brush;
402 if (fill->bmp)
403 {
404 RECT rc;
405 /* partially transparent fill */
406
407 SelectClipPath(graphics->hdc, RGN_AND);
408 if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
409 {
410 HDC hdc = CreateCompatibleDC(NULL);
411 HBITMAP oldbmp;
412 BLENDFUNCTION bf;
413
414 if (!hdc) break;
415
416 oldbmp = SelectObject(hdc, fill->bmp);
417
418 bf.BlendOp = AC_SRC_OVER;
419 bf.BlendFlags = 0;
420 bf.SourceConstantAlpha = 255;
421 bf.AlphaFormat = AC_SRC_ALPHA;
422
423 GdiAlphaBlend(graphics->hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, hdc, 0, 0, 1, 1, bf);
424
425 SelectObject(hdc, oldbmp);
426 DeleteDC(hdc);
427 }
428
429 break;
430 }
431 /* else fall through */
432 }
Vincent Povirk68dba4e2009-03-16 12:51:04 -0500433 default:
434 SelectObject(graphics->hdc, brush->gdibrush);
435 FillPath(graphics->hdc);
436 break;
437 }
438}
439
Evan Stade72ab72c502007-06-18 16:55:51 -0700440/* GdipDrawPie/GdipFillPie helper function */
Evan Stade4c424b32007-07-24 17:18:54 -0700441static void draw_pie(GpGraphics *graphics, REAL x, REAL y, REAL width,
442 REAL height, REAL startAngle, REAL sweepAngle)
Evan Stade72ab72c502007-06-18 16:55:51 -0700443{
Evan Staded01c6972007-07-23 20:24:53 -0700444 GpPointF ptf[4];
445 POINT pti[4];
Evan Stade72ab72c502007-06-18 16:55:51 -0700446
Evan Staded01c6972007-07-23 20:24:53 -0700447 ptf[0].X = x;
448 ptf[0].Y = y;
449 ptf[1].X = x + width;
450 ptf[1].Y = y + height;
Evan Stade72ab72c502007-06-18 16:55:51 -0700451
Evan Staded01c6972007-07-23 20:24:53 -0700452 deg2xy(startAngle+sweepAngle, x + width / 2.0, y + width / 2.0, &ptf[2].X, &ptf[2].Y);
453 deg2xy(startAngle, x + width / 2.0, y + width / 2.0, &ptf[3].X, &ptf[3].Y);
Evan Stade72ab72c502007-06-18 16:55:51 -0700454
Evan Staded01c6972007-07-23 20:24:53 -0700455 transform_and_round_points(graphics, pti, ptf, 4);
456
457 Pie(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y, pti[2].x,
458 pti[2].y, pti[3].x, pti[3].y);
Evan Stade72ab72c502007-06-18 16:55:51 -0700459}
460
Evan Stade5128e5d2007-07-07 13:20:41 -0700461/* Draws the linecap the specified color and size on the hdc. The linecap is in
Evan Stade8c5bcef2007-07-20 17:50:02 -0700462 * direction of the line from x1, y1 to x2, y2 and is anchored on x2, y2. Probably
463 * should not be called on an hdc that has a path you care about. */
Evan Staded01c6972007-07-23 20:24:53 -0700464static void draw_cap(GpGraphics *graphics, COLORREF color, GpLineCap cap, REAL size,
Evan Stade85b5df42007-07-19 18:22:51 -0700465 const GpCustomLineCap *custom, REAL x1, REAL y1, REAL x2, REAL y2)
Evan Stade5128e5d2007-07-07 13:20:41 -0700466{
Evan Stadeb7053b72007-07-24 17:18:58 -0700467 HGDIOBJ oldbrush = NULL, oldpen = NULL;
Evan Stade85b5df42007-07-19 18:22:51 -0700468 GpMatrix *matrix = NULL;
Evan Stadeb7053b72007-07-24 17:18:58 -0700469 HBRUSH brush = NULL;
470 HPEN pen = NULL;
Evan Staded01c6972007-07-23 20:24:53 -0700471 PointF ptf[4], *custptf = NULL;
Evan Stade85b5df42007-07-19 18:22:51 -0700472 POINT pt[4], *custpt = NULL;
473 BYTE *tp = NULL;
Evan Staded01c6972007-07-23 20:24:53 -0700474 REAL theta, dsmall, dbig, dx, dy = 0.0;
Evan Stade85b5df42007-07-19 18:22:51 -0700475 INT i, count;
476 LOGBRUSH lb;
Evan Stadeb7053b72007-07-24 17:18:58 -0700477 BOOL customstroke;
Evan Stade5128e5d2007-07-07 13:20:41 -0700478
Evan Stade818051d2007-07-20 17:50:14 -0700479 if((x1 == x2) && (y1 == y2))
Evan Stade5128e5d2007-07-07 13:20:41 -0700480 return;
481
Evan Stade818051d2007-07-20 17:50:14 -0700482 theta = gdiplus_atan2(y2 - y1, x2 - x1);
483
Evan Stadeb7053b72007-07-24 17:18:58 -0700484 customstroke = (cap == LineCapCustom) && custom && (!custom->fill);
485 if(!customstroke){
486 brush = CreateSolidBrush(color);
487 lb.lbStyle = BS_SOLID;
488 lb.lbColor = color;
489 lb.lbHatch = 0;
490 pen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT |
491 PS_JOIN_MITER, 1, &lb, 0,
492 NULL);
493 oldbrush = SelectObject(graphics->hdc, brush);
494 oldpen = SelectObject(graphics->hdc, pen);
495 }
Evan Stade5128e5d2007-07-07 13:20:41 -0700496
497 switch(cap){
498 case LineCapFlat:
499 break;
500 case LineCapSquare:
501 case LineCapSquareAnchor:
502 case LineCapDiamondAnchor:
503 size = size * (cap & LineCapNoAnchor ? ANCHOR_WIDTH : 1.0) / 2.0;
504 if(cap == LineCapDiamondAnchor){
505 dsmall = cos(theta + M_PI_2) * size;
506 dbig = sin(theta + M_PI_2) * size;
507 }
508 else{
509 dsmall = cos(theta + M_PI_4) * size;
510 dbig = sin(theta + M_PI_4) * size;
511 }
512
Evan Staded01c6972007-07-23 20:24:53 -0700513 ptf[0].X = x2 - dsmall;
514 ptf[1].X = x2 + dbig;
Evan Stade5128e5d2007-07-07 13:20:41 -0700515
Evan Staded01c6972007-07-23 20:24:53 -0700516 ptf[0].Y = y2 - dbig;
517 ptf[3].Y = y2 + dsmall;
Evan Stade5128e5d2007-07-07 13:20:41 -0700518
Evan Staded01c6972007-07-23 20:24:53 -0700519 ptf[1].Y = y2 - dsmall;
520 ptf[2].Y = y2 + dbig;
Evan Stade5128e5d2007-07-07 13:20:41 -0700521
Evan Staded01c6972007-07-23 20:24:53 -0700522 ptf[3].X = x2 - dbig;
523 ptf[2].X = x2 + dsmall;
Evan Stade5128e5d2007-07-07 13:20:41 -0700524
Evan Staded01c6972007-07-23 20:24:53 -0700525 transform_and_round_points(graphics, pt, ptf, 4);
526 Polygon(graphics->hdc, pt, 4);
Evan Stade5128e5d2007-07-07 13:20:41 -0700527
528 break;
529 case LineCapArrowAnchor:
530 size = size * 4.0 / sqrt(3.0);
531
Evan Stadeea5898c2007-07-19 18:22:47 -0700532 dx = cos(M_PI / 6.0 + theta) * size;
533 dy = sin(M_PI / 6.0 + theta) * size;
Evan Stade5128e5d2007-07-07 13:20:41 -0700534
Evan Staded01c6972007-07-23 20:24:53 -0700535 ptf[0].X = x2 - dx;
536 ptf[0].Y = y2 - dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700537
Evan Stadeea5898c2007-07-19 18:22:47 -0700538 dx = cos(- M_PI / 6.0 + theta) * size;
539 dy = sin(- M_PI / 6.0 + theta) * size;
Evan Stade5128e5d2007-07-07 13:20:41 -0700540
Evan Staded01c6972007-07-23 20:24:53 -0700541 ptf[1].X = x2 - dx;
542 ptf[1].Y = y2 - dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700543
Evan Staded01c6972007-07-23 20:24:53 -0700544 ptf[2].X = x2;
545 ptf[2].Y = y2;
Evan Stade5128e5d2007-07-07 13:20:41 -0700546
Evan Staded01c6972007-07-23 20:24:53 -0700547 transform_and_round_points(graphics, pt, ptf, 3);
548 Polygon(graphics->hdc, pt, 3);
Evan Stade5128e5d2007-07-07 13:20:41 -0700549
550 break;
551 case LineCapRoundAnchor:
552 dx = dy = ANCHOR_WIDTH * size / 2.0;
553
Evan Staded01c6972007-07-23 20:24:53 -0700554 ptf[0].X = x2 - dx;
555 ptf[0].Y = y2 - dy;
556 ptf[1].X = x2 + dx;
557 ptf[1].Y = y2 + dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700558
Evan Staded01c6972007-07-23 20:24:53 -0700559 transform_and_round_points(graphics, pt, ptf, 2);
560 Ellipse(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
561
Evan Stade5128e5d2007-07-07 13:20:41 -0700562 break;
563 case LineCapTriangle:
564 size = size / 2.0;
565 dx = cos(M_PI_2 + theta) * size;
566 dy = sin(M_PI_2 + theta) * size;
567
Evan Staded01c6972007-07-23 20:24:53 -0700568 ptf[0].X = x2 - dx;
569 ptf[0].Y = y2 - dy;
570 ptf[1].X = x2 + dx;
571 ptf[1].Y = y2 + dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700572
Evan Stadeea5898c2007-07-19 18:22:47 -0700573 dx = cos(theta) * size;
574 dy = sin(theta) * size;
Evan Stade5128e5d2007-07-07 13:20:41 -0700575
Evan Staded01c6972007-07-23 20:24:53 -0700576 ptf[2].X = x2 + dx;
577 ptf[2].Y = y2 + dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700578
Evan Staded01c6972007-07-23 20:24:53 -0700579 transform_and_round_points(graphics, pt, ptf, 3);
580 Polygon(graphics->hdc, pt, 3);
Evan Stade5128e5d2007-07-07 13:20:41 -0700581
582 break;
583 case LineCapRound:
Evan Staded01c6972007-07-23 20:24:53 -0700584 dx = dy = size / 2.0;
585
586 ptf[0].X = x2 - dx;
587 ptf[0].Y = y2 - dy;
588 ptf[1].X = x2 + dx;
589 ptf[1].Y = y2 + dy;
590
Evan Stadeea5898c2007-07-19 18:22:47 -0700591 dx = -cos(M_PI_2 + theta) * size;
592 dy = -sin(M_PI_2 + theta) * size;
Evan Stade5128e5d2007-07-07 13:20:41 -0700593
Evan Staded01c6972007-07-23 20:24:53 -0700594 ptf[2].X = x2 - dx;
595 ptf[2].Y = y2 - dy;
596 ptf[3].X = x2 + dx;
597 ptf[3].Y = y2 + dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700598
Evan Staded01c6972007-07-23 20:24:53 -0700599 transform_and_round_points(graphics, pt, ptf, 4);
600 Pie(graphics->hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x,
601 pt[2].y, pt[3].x, pt[3].y);
Evan Stade5128e5d2007-07-07 13:20:41 -0700602
Evan Stade5128e5d2007-07-07 13:20:41 -0700603 break;
604 case LineCapCustom:
Evan Stade85b5df42007-07-19 18:22:51 -0700605 if(!custom)
606 break;
607
Evan Stade85b5df42007-07-19 18:22:51 -0700608 count = custom->pathdata.Count;
609 custptf = GdipAlloc(count * sizeof(PointF));
610 custpt = GdipAlloc(count * sizeof(POINT));
611 tp = GdipAlloc(count);
612
613 if(!custptf || !custpt || !tp || (GdipCreateMatrix(&matrix) != Ok))
614 goto custend;
615
616 memcpy(custptf, custom->pathdata.Points, count * sizeof(PointF));
617
618 GdipScaleMatrix(matrix, size, size, MatrixOrderAppend);
619 GdipRotateMatrix(matrix, (180.0 / M_PI) * (theta - M_PI_2),
620 MatrixOrderAppend);
621 GdipTranslateMatrix(matrix, x2, y2, MatrixOrderAppend);
622 GdipTransformMatrixPoints(matrix, custptf, count);
623
Evan Staded01c6972007-07-23 20:24:53 -0700624 transform_and_round_points(graphics, custpt, custptf, count);
625
626 for(i = 0; i < count; i++)
Evan Stade85b5df42007-07-19 18:22:51 -0700627 tp[i] = convert_path_point_type(custom->pathdata.Types[i]);
Evan Stade85b5df42007-07-19 18:22:51 -0700628
Evan Stade8c5bcef2007-07-20 17:50:02 -0700629 if(custom->fill){
Evan Staded01c6972007-07-23 20:24:53 -0700630 BeginPath(graphics->hdc);
631 PolyDraw(graphics->hdc, custpt, tp, count);
632 EndPath(graphics->hdc);
633 StrokeAndFillPath(graphics->hdc);
Evan Stade8c5bcef2007-07-20 17:50:02 -0700634 }
635 else
Evan Staded01c6972007-07-23 20:24:53 -0700636 PolyDraw(graphics->hdc, custpt, tp, count);
Evan Stade85b5df42007-07-19 18:22:51 -0700637
638custend:
639 GdipFree(custptf);
640 GdipFree(custpt);
641 GdipFree(tp);
642 GdipDeleteMatrix(matrix);
643 break;
Evan Stade5128e5d2007-07-07 13:20:41 -0700644 default:
645 break;
646 }
647
Evan Stadeb7053b72007-07-24 17:18:58 -0700648 if(!customstroke){
649 SelectObject(graphics->hdc, oldbrush);
650 SelectObject(graphics->hdc, oldpen);
651 DeleteObject(brush);
652 DeleteObject(pen);
653 }
Evan Stade5128e5d2007-07-07 13:20:41 -0700654}
655
656/* Shortens the line by the given percent by changing x2, y2.
Evan Stadef56fa322007-07-20 17:50:07 -0700657 * If percent is > 1.0 then the line will change direction.
658 * If percent is negative it can lengthen the line. */
Evan Stade5128e5d2007-07-07 13:20:41 -0700659static void shorten_line_percent(REAL x1, REAL y1, REAL *x2, REAL *y2, REAL percent)
660{
661 REAL dist, theta, dx, dy;
662
663 if((y1 == *y2) && (x1 == *x2))
664 return;
665
Evan Stadef56fa322007-07-20 17:50:07 -0700666 dist = sqrt((*x2 - x1) * (*x2 - x1) + (*y2 - y1) * (*y2 - y1)) * -percent;
Evan Stade818051d2007-07-20 17:50:14 -0700667 theta = gdiplus_atan2((*y2 - y1), (*x2 - x1));
Evan Stade5128e5d2007-07-07 13:20:41 -0700668 dx = cos(theta) * dist;
669 dy = sin(theta) * dist;
670
Evan Stadef56fa322007-07-20 17:50:07 -0700671 *x2 = *x2 + dx;
672 *y2 = *y2 + dy;
Evan Stade5128e5d2007-07-07 13:20:41 -0700673}
674
675/* Shortens the line by the given amount by changing x2, y2.
Evan Stadef56fa322007-07-20 17:50:07 -0700676 * If the amount is greater than the distance, the line will become length 0.
677 * If the amount is negative, it can lengthen the line. */
Evan Stade5128e5d2007-07-07 13:20:41 -0700678static void shorten_line_amt(REAL x1, REAL y1, REAL *x2, REAL *y2, REAL amt)
679{
680 REAL dx, dy, percent;
681
682 dx = *x2 - x1;
683 dy = *y2 - y1;
684 if(dx == 0 && dy == 0)
685 return;
686
687 percent = amt / sqrt(dx * dx + dy * dy);
688 if(percent >= 1.0){
689 *x2 = x1;
690 *y2 = y1;
691 return;
692 }
693
694 shorten_line_percent(x1, y1, x2, y2, percent);
695}
696
697/* Draws lines between the given points, and if caps is true then draws an endcap
Evan Stade88ab6d32007-08-02 17:53:13 -0700698 * at the end of the last line. */
Evan Staded01c6972007-07-23 20:24:53 -0700699static GpStatus draw_polyline(GpGraphics *graphics, GpPen *pen,
700 GDIPCONST GpPointF * pt, INT count, BOOL caps)
Evan Stade5128e5d2007-07-07 13:20:41 -0700701{
Evan Stadea84b5672007-07-20 17:50:11 -0700702 POINT *pti = NULL;
703 GpPointF *ptcopy = NULL;
Evan Stade6f4ab522007-07-11 18:07:44 -0700704 GpStatus status = GenericError;
705
706 if(!count)
707 return Ok;
708
709 pti = GdipAlloc(count * sizeof(POINT));
Evan Stadea84b5672007-07-20 17:50:11 -0700710 ptcopy = GdipAlloc(count * sizeof(GpPointF));
Evan Stade6f4ab522007-07-11 18:07:44 -0700711
Evan Stadea84b5672007-07-20 17:50:11 -0700712 if(!pti || !ptcopy){
Evan Stade6f4ab522007-07-11 18:07:44 -0700713 status = OutOfMemory;
714 goto end;
715 }
Evan Stade5128e5d2007-07-07 13:20:41 -0700716
Evan Stadec3e8af42007-07-24 17:18:50 -0700717 memcpy(ptcopy, pt, count * sizeof(GpPointF));
Evan Staded01c6972007-07-23 20:24:53 -0700718
Evan Stadec3e8af42007-07-24 17:18:50 -0700719 if(caps){
Evan Stade5128e5d2007-07-07 13:20:41 -0700720 if(pen->endcap == LineCapArrowAnchor)
Evan Stadea84b5672007-07-20 17:50:11 -0700721 shorten_line_amt(ptcopy[count-2].X, ptcopy[count-2].Y,
722 &ptcopy[count-1].X, &ptcopy[count-1].Y, pen->width);
Evan Stadef56fa322007-07-20 17:50:07 -0700723 else if((pen->endcap == LineCapCustom) && pen->customend)
Evan Stadea84b5672007-07-20 17:50:11 -0700724 shorten_line_amt(ptcopy[count-2].X, ptcopy[count-2].Y,
725 &ptcopy[count-1].X, &ptcopy[count-1].Y,
726 pen->customend->inset * pen->width);
727
728 if(pen->startcap == LineCapArrowAnchor)
729 shorten_line_amt(ptcopy[1].X, ptcopy[1].Y,
730 &ptcopy[0].X, &ptcopy[0].Y, pen->width);
731 else if((pen->startcap == LineCapCustom) && pen->customstart)
732 shorten_line_amt(ptcopy[1].X, ptcopy[1].Y,
733 &ptcopy[0].X, &ptcopy[0].Y,
Evan Stade02887b62007-08-07 18:42:44 -0700734 pen->customstart->inset * pen->width);
Evan Stade5128e5d2007-07-07 13:20:41 -0700735
Evan Staded01c6972007-07-23 20:24:53 -0700736 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
Evan Stadea84b5672007-07-20 17:50:11 -0700737 pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X, pt[count - 1].Y);
Evan Staded01c6972007-07-23 20:24:53 -0700738 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
Michael Stefaniuc1f26b142007-12-31 17:29:57 +0100739 pt[1].X, pt[1].Y, pt[0].X, pt[0].Y);
Evan Stade5128e5d2007-07-07 13:20:41 -0700740 }
Evan Stadec3e8af42007-07-24 17:18:50 -0700741
742 transform_and_round_points(graphics, pti, ptcopy, count);
Evan Stade5128e5d2007-07-07 13:20:41 -0700743
Royal Chanc86f2c22008-02-10 12:40:52 -0800744 if(Polyline(graphics->hdc, pti, count))
745 status = Ok;
Evan Stade6f4ab522007-07-11 18:07:44 -0700746
747end:
Evan Stade5128e5d2007-07-07 13:20:41 -0700748 GdipFree(pti);
Evan Stadea84b5672007-07-20 17:50:11 -0700749 GdipFree(ptcopy);
Evan Stade6f4ab522007-07-11 18:07:44 -0700750
751 return status;
Evan Stade5128e5d2007-07-07 13:20:41 -0700752}
753
Evan Stade69a807c2007-07-06 16:13:49 -0700754/* Conducts a linear search to find the bezier points that will back off
755 * the endpoint of the curve by a distance of amt. Linear search works
756 * better than binary in this case because there are multiple solutions,
757 * and binary searches often find a bad one. I don't think this is what
758 * Windows does but short of rendering the bezier without GDI's help it's
Evan Stadea84b5672007-07-20 17:50:11 -0700759 * the best we can do. If rev then work from the start of the passed points
760 * instead of the end. */
761static void shorten_bezier_amt(GpPointF * pt, REAL amt, BOOL rev)
Evan Stade69a807c2007-07-06 16:13:49 -0700762{
763 GpPointF origpt[4];
Evan Stadea84b5672007-07-20 17:50:11 -0700764 REAL percent = 0.00, dx, dy, origx, origy, diff = -1.0;
765 INT i, first = 0, second = 1, third = 2, fourth = 3;
Evan Stade69a807c2007-07-06 16:13:49 -0700766
Evan Stadea84b5672007-07-20 17:50:11 -0700767 if(rev){
768 first = 3;
769 second = 2;
770 third = 1;
771 fourth = 0;
772 }
773
774 origx = pt[fourth].X;
775 origy = pt[fourth].Y;
Evan Stade69a807c2007-07-06 16:13:49 -0700776 memcpy(origpt, pt, sizeof(GpPointF) * 4);
777
778 for(i = 0; (i < MAX_ITERS) && (diff < amt); i++){
779 /* reset bezier points to original values */
780 memcpy(pt, origpt, sizeof(GpPointF) * 4);
781 /* Perform magic on bezier points. Order is important here.*/
Evan Stadea84b5672007-07-20 17:50:11 -0700782 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent);
783 shorten_line_percent(pt[second].X, pt[second].Y, &pt[third].X, &pt[third].Y, percent);
784 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent);
785 shorten_line_percent(pt[first].X, pt[first].Y, &pt[second].X, &pt[second].Y, percent);
786 shorten_line_percent(pt[second].X, pt[second].Y, &pt[third].X, &pt[third].Y, percent);
787 shorten_line_percent(pt[third].X, pt[third].Y, &pt[fourth].X, &pt[fourth].Y, percent);
Evan Stade69a807c2007-07-06 16:13:49 -0700788
Evan Stadea84b5672007-07-20 17:50:11 -0700789 dx = pt[fourth].X - origx;
790 dy = pt[fourth].Y - origy;
Evan Stade69a807c2007-07-06 16:13:49 -0700791
792 diff = sqrt(dx * dx + dy * dy);
793 percent += 0.0005 * amt;
794 }
795}
796
797/* Draws bezier curves between given points, and if caps is true then draws an
Evan Stade88ab6d32007-08-02 17:53:13 -0700798 * endcap at the end of the last line. */
Evan Staded01c6972007-07-23 20:24:53 -0700799static GpStatus draw_polybezier(GpGraphics *graphics, GpPen *pen,
800 GDIPCONST GpPointF * pt, INT count, BOOL caps)
Evan Stade69a807c2007-07-06 16:13:49 -0700801{
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700802 POINT *pti;
Evan Stadea84b5672007-07-20 17:50:11 -0700803 GpPointF *ptcopy;
Evan Stadefa312172007-07-11 18:07:39 -0700804 GpStatus status = GenericError;
805
806 if(!count)
807 return Ok;
808
809 pti = GdipAlloc(count * sizeof(POINT));
Evan Stadea84b5672007-07-20 17:50:11 -0700810 ptcopy = GdipAlloc(count * sizeof(GpPointF));
Evan Stadefa312172007-07-11 18:07:39 -0700811
Evan Stadea84b5672007-07-20 17:50:11 -0700812 if(!pti || !ptcopy){
Evan Stadefa312172007-07-11 18:07:39 -0700813 status = OutOfMemory;
814 goto end;
815 }
Evan Stade69a807c2007-07-06 16:13:49 -0700816
Evan Stadec3e8af42007-07-24 17:18:50 -0700817 memcpy(ptcopy, pt, count * sizeof(GpPointF));
Evan Staded01c6972007-07-23 20:24:53 -0700818
Evan Stadec3e8af42007-07-24 17:18:50 -0700819 if(caps){
Evan Stade69a807c2007-07-06 16:13:49 -0700820 if(pen->endcap == LineCapArrowAnchor)
Evan Stadea84b5672007-07-20 17:50:11 -0700821 shorten_bezier_amt(&ptcopy[count-4], pen->width, FALSE);
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700822 else if((pen->endcap == LineCapCustom) && pen->customend)
823 shorten_bezier_amt(&ptcopy[count-4], pen->width * pen->customend->inset,
824 FALSE);
Evan Stade69a807c2007-07-06 16:13:49 -0700825
Evan Stadea84b5672007-07-20 17:50:11 -0700826 if(pen->startcap == LineCapArrowAnchor)
827 shorten_bezier_amt(ptcopy, pen->width, TRUE);
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700828 else if((pen->startcap == LineCapCustom) && pen->customstart)
Evan Stade02887b62007-08-07 18:42:44 -0700829 shorten_bezier_amt(ptcopy, pen->width * pen->customstart->inset, TRUE);
Evan Stadea84b5672007-07-20 17:50:11 -0700830
Evan Stade55d70e82007-07-11 18:08:26 -0700831 /* the direction of the line cap is parallel to the direction at the
832 * end of the bezier (which, if it has been shortened, is not the same
833 * as the direction from pt[count-2] to pt[count-1]) */
Evan Staded01c6972007-07-23 20:24:53 -0700834 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
Evan Stadea84b5672007-07-20 17:50:11 -0700835 pt[count - 1].X - (ptcopy[count - 1].X - ptcopy[count - 2].X),
836 pt[count - 1].Y - (ptcopy[count - 1].Y - ptcopy[count - 2].Y),
Evan Stade55d70e82007-07-11 18:08:26 -0700837 pt[count - 1].X, pt[count - 1].Y);
Evan Stadea84b5672007-07-20 17:50:11 -0700838
Evan Staded01c6972007-07-23 20:24:53 -0700839 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
Evan Stadea84b5672007-07-20 17:50:11 -0700840 pt[0].X - (ptcopy[0].X - ptcopy[1].X),
841 pt[0].Y - (ptcopy[0].Y - ptcopy[1].Y), pt[0].X, pt[0].Y);
Evan Stade69a807c2007-07-06 16:13:49 -0700842 }
Evan Stadec3e8af42007-07-24 17:18:50 -0700843
844 transform_and_round_points(graphics, pti, ptcopy, count);
Evan Stade69a807c2007-07-06 16:13:49 -0700845
Evan Staded01c6972007-07-23 20:24:53 -0700846 PolyBezier(graphics->hdc, pti, count);
Evan Stadefa312172007-07-11 18:07:39 -0700847
848 status = Ok;
849
850end:
Evan Stade69a807c2007-07-06 16:13:49 -0700851 GdipFree(pti);
Evan Stadea84b5672007-07-20 17:50:11 -0700852 GdipFree(ptcopy);
Evan Stadefa312172007-07-11 18:07:39 -0700853
854 return status;
Evan Stade69a807c2007-07-06 16:13:49 -0700855}
856
Evan Stade9d5f5682007-07-11 18:07:34 -0700857/* Draws a combination of bezier curves and lines between points. */
Evan Staded01c6972007-07-23 20:24:53 -0700858static GpStatus draw_poly(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPointF * pt,
Evan Stade9d5f5682007-07-11 18:07:34 -0700859 GDIPCONST BYTE * types, INT count, BOOL caps)
860{
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700861 POINT *pti = GdipAlloc(count * sizeof(POINT));
Evan Stade9d5f5682007-07-11 18:07:34 -0700862 BYTE *tp = GdipAlloc(count);
Evan Stadea84b5672007-07-20 17:50:11 -0700863 GpPointF *ptcopy = GdipAlloc(count * sizeof(GpPointF));
Evan Stadea84b5672007-07-20 17:50:11 -0700864 INT i, j;
Evan Stade9d5f5682007-07-11 18:07:34 -0700865 GpStatus status = GenericError;
866
867 if(!count){
868 status = Ok;
869 goto end;
870 }
Evan Stadea84b5672007-07-20 17:50:11 -0700871 if(!pti || !tp || !ptcopy){
Evan Stade9d5f5682007-07-11 18:07:34 -0700872 status = OutOfMemory;
873 goto end;
874 }
875
Evan Stadea84b5672007-07-20 17:50:11 -0700876 for(i = 1; i < count; i++){
Evan Stade9d5f5682007-07-11 18:07:34 -0700877 if((types[i] & PathPointTypePathTypeMask) == PathPointTypeBezier){
878 if((i + 2 >= count) || !(types[i + 1] & PathPointTypeBezier)
879 || !(types[i + 1] & PathPointTypeBezier)){
880 ERR("Bad bezier points\n");
881 goto end;
882 }
Evan Stade9d5f5682007-07-11 18:07:34 -0700883 i += 2;
884 }
885 }
886
Evan Stadec3e8af42007-07-24 17:18:50 -0700887 memcpy(ptcopy, pt, count * sizeof(GpPointF));
888
Evan Stade9e883472007-07-13 17:51:49 -0700889 /* If we are drawing caps, go through the points and adjust them accordingly,
890 * and draw the caps. */
891 if(caps){
892 switch(types[count - 1] & PathPointTypePathTypeMask){
893 case PathPointTypeBezier:
Evan Stade9e883472007-07-13 17:51:49 -0700894 if(pen->endcap == LineCapArrowAnchor)
Evan Stadea84b5672007-07-20 17:50:11 -0700895 shorten_bezier_amt(&ptcopy[count - 4], pen->width, FALSE);
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700896 else if((pen->endcap == LineCapCustom) && pen->customend)
897 shorten_bezier_amt(&ptcopy[count - 4],
898 pen->width * pen->customend->inset, FALSE);
Evan Stade9e883472007-07-13 17:51:49 -0700899
Evan Staded01c6972007-07-23 20:24:53 -0700900 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
Evan Stadea84b5672007-07-20 17:50:11 -0700901 pt[count - 1].X - (ptcopy[count - 1].X - ptcopy[count - 2].X),
902 pt[count - 1].Y - (ptcopy[count - 1].Y - ptcopy[count - 2].Y),
Evan Stade9e883472007-07-13 17:51:49 -0700903 pt[count - 1].X, pt[count - 1].Y);
904
Evan Stade9e883472007-07-13 17:51:49 -0700905 break;
Evan Stade9e883472007-07-13 17:51:49 -0700906 case PathPointTypeLine:
907 if(pen->endcap == LineCapArrowAnchor)
Evan Stadea84b5672007-07-20 17:50:11 -0700908 shorten_line_amt(ptcopy[count - 2].X, ptcopy[count - 2].Y,
909 &ptcopy[count - 1].X, &ptcopy[count - 1].Y,
Evan Stade9e883472007-07-13 17:51:49 -0700910 pen->width);
Evan Stadef56fa322007-07-20 17:50:07 -0700911 else if((pen->endcap == LineCapCustom) && pen->customend)
Evan Stadea84b5672007-07-20 17:50:11 -0700912 shorten_line_amt(ptcopy[count - 2].X, ptcopy[count - 2].Y,
913 &ptcopy[count - 1].X, &ptcopy[count - 1].Y,
Evan Stadef56fa322007-07-20 17:50:07 -0700914 pen->customend->inset * pen->width);
Evan Stade9e883472007-07-13 17:51:49 -0700915
Evan Staded01c6972007-07-23 20:24:53 -0700916 draw_cap(graphics, pen->brush->lb.lbColor, pen->endcap, pen->width, pen->customend,
Evan Stade85b5df42007-07-19 18:22:51 -0700917 pt[count - 2].X, pt[count - 2].Y, pt[count - 1].X,
918 pt[count - 1].Y);
Evan Stade9e883472007-07-13 17:51:49 -0700919
Evan Stade9e883472007-07-13 17:51:49 -0700920 break;
921 default:
922 ERR("Bad path last point\n");
923 goto end;
Evan Stade9d5f5682007-07-11 18:07:34 -0700924 }
Evan Stadea84b5672007-07-20 17:50:11 -0700925
926 /* Find start of points */
927 for(j = 1; j < count && ((types[j] & PathPointTypePathTypeMask)
928 == PathPointTypeStart); j++);
929
930 switch(types[j] & PathPointTypePathTypeMask){
931 case PathPointTypeBezier:
932 if(pen->startcap == LineCapArrowAnchor)
933 shorten_bezier_amt(&ptcopy[j - 1], pen->width, TRUE);
Evan Stade7f0aa3a2007-08-02 17:53:08 -0700934 else if((pen->startcap == LineCapCustom) && pen->customstart)
935 shorten_bezier_amt(&ptcopy[j - 1],
Evan Stade02887b62007-08-07 18:42:44 -0700936 pen->width * pen->customstart->inset, TRUE);
Evan Stadea84b5672007-07-20 17:50:11 -0700937
Evan Staded01c6972007-07-23 20:24:53 -0700938 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
Evan Stadea84b5672007-07-20 17:50:11 -0700939 pt[j - 1].X - (ptcopy[j - 1].X - ptcopy[j].X),
940 pt[j - 1].Y - (ptcopy[j - 1].Y - ptcopy[j].Y),
941 pt[j - 1].X, pt[j - 1].Y);
942
943 break;
944 case PathPointTypeLine:
945 if(pen->startcap == LineCapArrowAnchor)
946 shorten_line_amt(ptcopy[j].X, ptcopy[j].Y,
947 &ptcopy[j - 1].X, &ptcopy[j - 1].Y,
948 pen->width);
949 else if((pen->startcap == LineCapCustom) && pen->customstart)
950 shorten_line_amt(ptcopy[j].X, ptcopy[j].Y,
951 &ptcopy[j - 1].X, &ptcopy[j - 1].Y,
952 pen->customstart->inset * pen->width);
953
Evan Stade629e0132007-07-27 16:07:50 -0700954 draw_cap(graphics, pen->brush->lb.lbColor, pen->startcap, pen->width, pen->customstart,
Evan Stadea84b5672007-07-20 17:50:11 -0700955 pt[j].X, pt[j].Y, pt[j - 1].X,
956 pt[j - 1].Y);
957
958 break;
959 default:
960 ERR("Bad path points\n");
961 goto end;
962 }
Evan Stade9d5f5682007-07-11 18:07:34 -0700963 }
Evan Stadec3e8af42007-07-24 17:18:50 -0700964
965 transform_and_round_points(graphics, pti, ptcopy, count);
Evan Stade9d5f5682007-07-11 18:07:34 -0700966
967 for(i = 0; i < count; i++){
968 tp[i] = convert_path_point_type(types[i]);
969 }
970
Evan Staded01c6972007-07-23 20:24:53 -0700971 PolyDraw(graphics->hdc, pti, tp, count);
Evan Stade9d5f5682007-07-11 18:07:34 -0700972
973 status = Ok;
974
975end:
976 GdipFree(pti);
Evan Stadea84b5672007-07-20 17:50:11 -0700977 GdipFree(ptcopy);
Evan Stade9d5f5682007-07-11 18:07:34 -0700978 GdipFree(tp);
979
980 return status;
981}
982
Vincent Povirk08aa0ca2008-11-24 15:01:47 -0600983GpStatus trace_path(GpGraphics *graphics, GpPath *path)
984{
985 GpStatus result;
986
987 BeginPath(graphics->hdc);
988 result = draw_poly(graphics, NULL, path->pathdata.Points,
989 path->pathdata.Types, path->pathdata.Count, FALSE);
990 EndPath(graphics->hdc);
991 return result;
992}
993
Andrew Eikum632aef32009-07-05 17:04:20 -0500994typedef struct _GraphicsContainerItem {
995 struct list entry;
996 GraphicsContainer contid;
997
998 SmoothingMode smoothing;
999 CompositingQuality compqual;
1000 InterpolationMode interpolation;
1001 CompositingMode compmode;
1002 TextRenderingHint texthint;
1003 REAL scale;
1004 GpUnit unit;
1005 PixelOffsetMode pixeloffset;
1006 UINT textcontrast;
1007 GpMatrix* worldtrans;
1008 GpRegion* clip;
1009} GraphicsContainerItem;
1010
1011static GpStatus init_container(GraphicsContainerItem** container,
1012 GDIPCONST GpGraphics* graphics){
1013 GpStatus sts;
1014
1015 *container = GdipAlloc(sizeof(GraphicsContainerItem));
1016 if(!(*container))
1017 return OutOfMemory;
1018
1019 (*container)->contid = graphics->contid + 1;
1020
1021 (*container)->smoothing = graphics->smoothing;
1022 (*container)->compqual = graphics->compqual;
1023 (*container)->interpolation = graphics->interpolation;
1024 (*container)->compmode = graphics->compmode;
1025 (*container)->texthint = graphics->texthint;
1026 (*container)->scale = graphics->scale;
1027 (*container)->unit = graphics->unit;
1028 (*container)->textcontrast = graphics->textcontrast;
1029 (*container)->pixeloffset = graphics->pixeloffset;
1030
1031 sts = GdipCloneMatrix(graphics->worldtrans, &(*container)->worldtrans);
1032 if(sts != Ok){
1033 GdipFree(*container);
1034 *container = NULL;
1035 return sts;
1036 }
1037
1038 sts = GdipCloneRegion(graphics->clip, &(*container)->clip);
1039 if(sts != Ok){
1040 GdipDeleteMatrix((*container)->worldtrans);
1041 GdipFree(*container);
1042 *container = NULL;
1043 return sts;
1044 }
1045
1046 return Ok;
1047}
1048
1049static void delete_container(GraphicsContainerItem* container){
1050 GdipDeleteMatrix(container->worldtrans);
1051 GdipDeleteRegion(container->clip);
1052 GdipFree(container);
1053}
1054
1055static GpStatus restore_container(GpGraphics* graphics,
1056 GDIPCONST GraphicsContainerItem* container){
1057 GpStatus sts;
1058 GpMatrix *newTrans;
1059 GpRegion *newClip;
1060
1061 sts = GdipCloneMatrix(container->worldtrans, &newTrans);
1062 if(sts != Ok)
1063 return sts;
1064
1065 sts = GdipCloneRegion(container->clip, &newClip);
1066 if(sts != Ok){
1067 GdipDeleteMatrix(newTrans);
1068 return sts;
1069 }
1070
1071 GdipDeleteMatrix(graphics->worldtrans);
1072 graphics->worldtrans = newTrans;
1073
1074 GdipDeleteRegion(graphics->clip);
1075 graphics->clip = newClip;
1076
1077 graphics->contid = container->contid - 1;
1078
1079 graphics->smoothing = container->smoothing;
1080 graphics->compqual = container->compqual;
1081 graphics->interpolation = container->interpolation;
1082 graphics->compmode = container->compmode;
1083 graphics->texthint = container->texthint;
1084 graphics->scale = container->scale;
1085 graphics->unit = container->unit;
1086 graphics->textcontrast = container->textcontrast;
1087 graphics->pixeloffset = container->pixeloffset;
1088
1089 return Ok;
1090}
1091
Andrew Eikumfdf48f12009-08-12 15:36:54 -05001092static GpStatus get_graphics_bounds(GpGraphics* graphics, GpRectF* rect)
1093{
1094 RECT wnd_rect;
1095
1096 if(graphics->hwnd) {
1097 if(!GetClientRect(graphics->hwnd, &wnd_rect))
1098 return GenericError;
1099
1100 rect->X = wnd_rect.left;
1101 rect->Y = wnd_rect.top;
1102 rect->Width = wnd_rect.right - wnd_rect.left;
1103 rect->Height = wnd_rect.bottom - wnd_rect.top;
1104 }else{
1105 rect->X = 0;
1106 rect->Y = 0;
1107 rect->Width = GetDeviceCaps(graphics->hdc, HORZRES);
1108 rect->Height = GetDeviceCaps(graphics->hdc, VERTRES);
1109 }
1110
1111 return Ok;
1112}
1113
Andrew Eikum39f6f492009-08-26 18:03:08 -05001114/* on success, rgn will contain the region of the graphics object which
1115 * is visible after clipping has been applied */
1116static GpStatus get_visible_clip_region(GpGraphics *graphics, GpRegion *rgn)
1117{
1118 GpStatus stat;
1119 GpRectF rectf;
1120 GpRegion* tmp;
1121
1122 if((stat = get_graphics_bounds(graphics, &rectf)) != Ok)
1123 return stat;
1124
1125 if((stat = GdipCreateRegion(&tmp)) != Ok)
1126 return stat;
1127
1128 if((stat = GdipCombineRegionRect(tmp, &rectf, CombineModeReplace)) != Ok)
1129 goto end;
1130
1131 if((stat = GdipCombineRegionRegion(tmp, graphics->clip, CombineModeIntersect)) != Ok)
1132 goto end;
1133
1134 stat = GdipCombineRegionRegion(rgn, tmp, CombineModeReplace);
1135
1136end:
1137 GdipDeleteRegion(tmp);
1138 return stat;
1139}
1140
Evan Staded50be492007-06-11 11:54:03 -07001141GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics)
1142{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001143 TRACE("(%p, %p)\n", hdc, graphics);
1144
Stefan Leichterbfffb4f2007-12-23 10:56:32 +01001145 return GdipCreateFromHDC2(hdc, NULL, graphics);
1146}
1147
1148GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **graphics)
1149{
Evan Stadef30732f2007-07-24 17:18:47 -07001150 GpStatus retval;
1151
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001152 TRACE("(%p, %p, %p)\n", hdc, hDevice, graphics);
1153
Stefan Leichterbfffb4f2007-12-23 10:56:32 +01001154 if(hDevice != NULL) {
Ken Sharpe3f48592009-06-09 21:48:05 +01001155 FIXME("Don't know how to handle parameter hDevice\n");
Stefan Leichterbfffb4f2007-12-23 10:56:32 +01001156 return NotImplemented;
1157 }
1158
Evan Staded50be492007-06-11 11:54:03 -07001159 if(hdc == NULL)
1160 return OutOfMemory;
1161
1162 if(graphics == NULL)
1163 return InvalidParameter;
1164
Evan Stade6490dad2007-06-22 19:27:02 -07001165 *graphics = GdipAlloc(sizeof(GpGraphics));
1166 if(!*graphics) return OutOfMemory;
1167
Evan Stadef30732f2007-07-24 17:18:47 -07001168 if((retval = GdipCreateMatrix(&(*graphics)->worldtrans)) != Ok){
1169 GdipFree(*graphics);
1170 return retval;
1171 }
1172
Nikolay Sivovef50aa32008-08-27 02:03:27 +04001173 if((retval = GdipCreateRegion(&(*graphics)->clip)) != Ok){
1174 GdipFree((*graphics)->worldtrans);
1175 GdipFree(*graphics);
1176 return retval;
1177 }
1178
Evan Staded50be492007-06-11 11:54:03 -07001179 (*graphics)->hdc = hdc;
Nikolay Sivov7258dea2008-09-05 16:51:25 +04001180 (*graphics)->hwnd = WindowFromDC(hdc);
Vincent Povirk8a3d9ff2009-04-24 13:29:56 -05001181 (*graphics)->owndc = FALSE;
Evan Stade53e17d22007-07-13 17:51:13 -07001182 (*graphics)->smoothing = SmoothingModeDefault;
Evan Stade60cad232007-07-13 17:51:25 -07001183 (*graphics)->compqual = CompositingQualityDefault;
Evan Stadea87ce7a2007-07-13 17:51:29 -07001184 (*graphics)->interpolation = InterpolationModeDefault;
Evan Staded6bd866d2007-07-13 17:51:33 -07001185 (*graphics)->pixeloffset = PixelOffsetModeDefault;
Evan Stadee807eb92007-08-13 18:34:27 -07001186 (*graphics)->compmode = CompositingModeSourceOver;
Evan Stade10b575b2007-07-23 20:24:41 -07001187 (*graphics)->unit = UnitDisplay;
Evan Stade81621392007-07-24 17:18:39 -07001188 (*graphics)->scale = 1.0;
Nikolay Sivov366ae1e2008-08-24 14:45:18 +04001189 (*graphics)->busy = FALSE;
Nikolay Sivov56173d42008-11-09 14:32:26 +03001190 (*graphics)->textcontrast = 4;
Andrew Eikum632aef32009-07-05 17:04:20 -05001191 list_init(&(*graphics)->containers);
1192 (*graphics)->contid = 0;
Evan Staded50be492007-06-11 11:54:03 -07001193
Vincent Povirkf8ca3722009-12-18 15:09:45 -06001194 TRACE("<-- %p\n", *graphics);
1195
Evan Staded50be492007-06-11 11:54:03 -07001196 return Ok;
1197}
1198
1199GpStatus WINGDIPAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics)
1200{
1201 GpStatus ret;
Vincent Povirkc3d23952009-04-24 13:34:55 -05001202 HDC hdc;
Evan Staded50be492007-06-11 11:54:03 -07001203
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001204 TRACE("(%p, %p)\n", hwnd, graphics);
1205
Vincent Povirkc3d23952009-04-24 13:34:55 -05001206 hdc = GetDC(hwnd);
1207
1208 if((ret = GdipCreateFromHDC(hdc, graphics)) != Ok)
1209 {
1210 ReleaseDC(hwnd, hdc);
Evan Staded50be492007-06-11 11:54:03 -07001211 return ret;
Vincent Povirkc3d23952009-04-24 13:34:55 -05001212 }
Evan Staded50be492007-06-11 11:54:03 -07001213
1214 (*graphics)->hwnd = hwnd;
Vincent Povirk8a3d9ff2009-04-24 13:29:56 -05001215 (*graphics)->owndc = TRUE;
Evan Staded50be492007-06-11 11:54:03 -07001216
1217 return Ok;
1218}
1219
Nikolay Sivoveb18ce92008-05-09 16:40:41 +04001220/* FIXME: no icm handling */
1221GpStatus WINGDIPAPI GdipCreateFromHWNDICM(HWND hwnd, GpGraphics **graphics)
1222{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001223 TRACE("(%p, %p)\n", hwnd, graphics);
1224
Nikolay Sivoveb18ce92008-05-09 16:40:41 +04001225 return GdipCreateFromHWND(hwnd, graphics);
1226}
1227
Evan Stade5cc8c102007-07-24 17:19:05 -07001228GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
1229 GpMetafile **metafile)
1230{
1231 static int calls;
1232
Vincent Povirk2005fe92009-12-18 16:04:20 -06001233 TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
1234
Evan Stade5cc8c102007-07-24 17:19:05 -07001235 if(!hemf || !metafile)
1236 return InvalidParameter;
1237
1238 if(!(calls++))
1239 FIXME("not implemented\n");
1240
1241 return NotImplemented;
1242}
1243
Evan Stade021997f2007-07-24 17:19:15 -07001244GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
1245 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
1246{
Evan Stadecfef9812007-07-31 19:15:12 -07001247 IStream *stream = NULL;
Evan Stade50799cf2007-07-30 19:10:03 -07001248 UINT read;
1249 BYTE* copy;
Evan Stade50799cf2007-07-30 19:10:03 -07001250 HENHMETAFILE hemf;
Vincent Povirk01b32952009-12-31 16:15:37 -06001251 GpStatus retval = Ok;
Evan Stade021997f2007-07-24 17:19:15 -07001252
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001253 TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
1254
Evan Stade021997f2007-07-24 17:19:15 -07001255 if(!hwmf || !metafile || !placeable)
1256 return InvalidParameter;
Evan Stade7d03a412007-08-07 18:42:16 -07001257
1258 *metafile = NULL;
Evan Stade50799cf2007-07-30 19:10:03 -07001259 read = GetMetaFileBitsEx(hwmf, 0, NULL);
1260 if(!read)
1261 return GenericError;
1262 copy = GdipAlloc(read);
1263 GetMetaFileBitsEx(hwmf, read, copy);
1264
Evan Stade192e1112007-08-01 17:55:33 -07001265 hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
Evan Stade50799cf2007-07-30 19:10:03 -07001266 GdipFree(copy);
1267
1268 read = GetEnhMetaFileBits(hemf, 0, NULL);
1269 copy = GdipAlloc(read);
1270 GetEnhMetaFileBits(hemf, read, copy);
1271 DeleteEnhMetaFile(hemf);
1272
1273 if(CreateStreamOnHGlobal(copy, TRUE, &stream) != S_OK){
1274 ERR("could not make stream\n");
Evan Stade7d03a412007-08-07 18:42:16 -07001275 GdipFree(copy);
Vincent Povirk01b32952009-12-31 16:15:37 -06001276 retval = GenericError;
Evan Stade7d03a412007-08-07 18:42:16 -07001277 goto err;
Evan Stade50799cf2007-07-30 19:10:03 -07001278 }
1279
1280 *metafile = GdipAlloc(sizeof(GpMetafile));
Evan Stadecfef9812007-07-31 19:15:12 -07001281 if(!*metafile){
1282 retval = OutOfMemory;
Evan Stade7d03a412007-08-07 18:42:16 -07001283 goto err;
Evan Stadecfef9812007-07-31 19:15:12 -07001284 }
Evan Stade50799cf2007-07-30 19:10:03 -07001285
1286 if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
Evan Stade7d03a412007-08-07 18:42:16 -07001287 (LPVOID*) &((*metafile)->image.picture)) != S_OK)
Vincent Povirk01b32952009-12-31 16:15:37 -06001288 {
1289 retval = GenericError;
Evan Stade7d03a412007-08-07 18:42:16 -07001290 goto err;
Vincent Povirk01b32952009-12-31 16:15:37 -06001291 }
Evan Stade7d03a412007-08-07 18:42:16 -07001292
Evan Stade50799cf2007-07-30 19:10:03 -07001293
1294 (*metafile)->image.type = ImageTypeMetafile;
Vincent Povirk0595fc52009-09-14 11:23:45 -05001295 memcpy(&(*metafile)->image.format, &ImageFormatWMF, sizeof(GUID));
Vincent Povirk39dc81c2009-12-11 16:51:46 -06001296 (*metafile)->image.palette_flags = 0;
1297 (*metafile)->image.palette_count = 0;
1298 (*metafile)->image.palette_size = 0;
1299 (*metafile)->image.palette_entries = NULL;
Vincent Povirk1aea88c2009-12-26 20:46:55 -05001300 (*metafile)->image.xres = (REAL)placeable->Inch;
1301 (*metafile)->image.yres = (REAL)placeable->Inch;
Evan Stade586e63e2007-07-30 19:09:57 -07001302 (*metafile)->bounds.X = ((REAL) placeable->BoundingBox.Left) / ((REAL) placeable->Inch);
Vincent Povirkc38d3342009-12-26 20:07:37 -05001303 (*metafile)->bounds.Y = ((REAL) placeable->BoundingBox.Top) / ((REAL) placeable->Inch);
Evan Stade586e63e2007-07-30 19:09:57 -07001304 (*metafile)->bounds.Width = ((REAL) (placeable->BoundingBox.Right
Vincent Povirk2f9c6092010-04-15 13:32:44 -05001305 - placeable->BoundingBox.Left));
Evan Stade586e63e2007-07-30 19:09:57 -07001306 (*metafile)->bounds.Height = ((REAL) (placeable->BoundingBox.Bottom
Vincent Povirk2f9c6092010-04-15 13:32:44 -05001307 - placeable->BoundingBox.Top));
1308 (*metafile)->unit = UnitPixel;
Evan Stade586e63e2007-07-30 19:09:57 -07001309
Evan Stade50799cf2007-07-30 19:10:03 -07001310 if(delete)
1311 DeleteMetaFile(hwmf);
1312
Vincent Povirkf8ca3722009-12-18 15:09:45 -06001313 TRACE("<-- %p\n", *metafile);
1314
Evan Stade7d03a412007-08-07 18:42:16 -07001315err:
Vincent Povirk01b32952009-12-31 16:15:37 -06001316 if (retval != Ok)
1317 GdipFree(*metafile);
Evan Stadecfef9812007-07-31 19:15:12 -07001318 IStream_Release(stream);
Evan Stadecfef9812007-07-31 19:15:12 -07001319 return retval;
Evan Stade021997f2007-07-24 17:19:15 -07001320}
1321
Huw Davieseb9d7f52008-07-10 15:30:30 +01001322GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
1323 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
1324{
1325 HMETAFILE hmf = GetMetaFileW(file);
1326
1327 TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
1328
1329 if(!hmf) return InvalidParameter;
1330
1331 return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
1332}
1333
Andrew Eikumc02e75c2009-06-01 20:02:11 -05001334GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
1335 GpMetafile **metafile)
1336{
1337 FIXME("(%p, %p): stub\n", file, metafile);
1338 return NotImplemented;
1339}
1340
1341GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
1342 GpMetafile **metafile)
1343{
1344 FIXME("(%p, %p): stub\n", stream, metafile);
1345 return NotImplemented;
1346}
1347
Evan Stade3ea77f52007-08-07 18:42:00 -07001348GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename,
1349 UINT access, IStream **stream)
1350{
1351 DWORD dwMode;
1352 HRESULT ret;
1353
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001354 TRACE("(%s, %u, %p)\n", debugstr_w(filename), access, stream);
1355
Evan Stade3ea77f52007-08-07 18:42:00 -07001356 if(!stream || !filename)
1357 return InvalidParameter;
1358
1359 if(access & GENERIC_WRITE)
1360 dwMode = STGM_SHARE_DENY_WRITE | STGM_WRITE | STGM_CREATE;
1361 else if(access & GENERIC_READ)
1362 dwMode = STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE;
1363 else
1364 return InvalidParameter;
1365
1366 ret = SHCreateStreamOnFileW(filename, dwMode, stream);
1367
1368 return hresult_to_status(ret);
1369}
1370
Evan Staded50be492007-06-11 11:54:03 -07001371GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
1372{
Andrew Eikum632aef32009-07-05 17:04:20 -05001373 GraphicsContainerItem *cont, *next;
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001374 TRACE("(%p)\n", graphics);
1375
Evan Staded50be492007-06-11 11:54:03 -07001376 if(!graphics) return InvalidParameter;
Nikolay Sivov960de092008-08-26 01:58:33 +04001377 if(graphics->busy) return ObjectBusy;
1378
Vincent Povirk8a3d9ff2009-04-24 13:29:56 -05001379 if(graphics->owndc)
Evan Staded50be492007-06-11 11:54:03 -07001380 ReleaseDC(graphics->hwnd, graphics->hdc);
1381
Andrew Eikum632aef32009-07-05 17:04:20 -05001382 LIST_FOR_EACH_ENTRY_SAFE(cont, next, &graphics->containers, GraphicsContainerItem, entry){
1383 list_remove(&cont->entry);
1384 delete_container(cont);
1385 }
1386
Nikolay Sivovef50aa32008-08-27 02:03:27 +04001387 GdipDeleteRegion(graphics->clip);
Evan Stadef30732f2007-07-24 17:18:47 -07001388 GdipDeleteMatrix(graphics->worldtrans);
Nikolay Sivov6e37ec62008-08-24 14:45:05 +04001389 GdipFree(graphics);
Evan Staded50be492007-06-11 11:54:03 -07001390
1391 return Ok;
1392}
Evan Stade2689b182007-06-12 10:44:31 -07001393
Evan Stadec42f8792007-06-19 19:31:19 -07001394GpStatus WINGDIPAPI GdipDrawArc(GpGraphics *graphics, GpPen *pen, REAL x,
1395 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
1396{
Evan Stade40f22732007-07-11 18:07:09 -07001397 INT save_state, num_pts;
1398 GpPointF points[MAX_ARC_PTS];
Evan Stadefa312172007-07-11 18:07:39 -07001399 GpStatus retval;
Evan Stadec42f8792007-06-19 19:31:19 -07001400
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001401 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y,
1402 width, height, startAngle, sweepAngle);
1403
Royal Chanea928722008-02-25 21:06:27 -08001404 if(!graphics || !pen || width <= 0 || height <= 0)
Evan Stadec42f8792007-06-19 19:31:19 -07001405 return InvalidParameter;
1406
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001407 if(graphics->busy)
1408 return ObjectBusy;
1409
Evan Stade40f22732007-07-11 18:07:09 -07001410 num_pts = arc2polybezier(points, x, y, width, height, startAngle, sweepAngle);
Evan Stadec42f8792007-06-19 19:31:19 -07001411
Evan Stade4c424b32007-07-24 17:18:54 -07001412 save_state = prepare_dc(graphics, pen);
Evan Stadec42f8792007-06-19 19:31:19 -07001413
Evan Staded01c6972007-07-23 20:24:53 -07001414 retval = draw_polybezier(graphics, pen, points, num_pts, TRUE);
Evan Stadec42f8792007-06-19 19:31:19 -07001415
Evan Stade4c424b32007-07-24 17:18:54 -07001416 restore_dc(graphics, save_state);
Evan Stadec42f8792007-06-19 19:31:19 -07001417
Evan Stadefa312172007-07-11 18:07:39 -07001418 return retval;
Evan Stadec42f8792007-06-19 19:31:19 -07001419}
1420
Royal Chanfc313032008-02-25 21:02:59 -08001421GpStatus WINGDIPAPI GdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x,
1422 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
1423{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001424 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y,
1425 width, height, startAngle, sweepAngle);
1426
Nikolay Sivova77dc342008-05-08 00:39:05 +04001427 return GdipDrawArc(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle);
Royal Chanfc313032008-02-25 21:02:59 -08001428}
1429
Evan Stade8b9f5342007-06-15 21:27:38 -07001430GpStatus WINGDIPAPI GdipDrawBezier(GpGraphics *graphics, GpPen *pen, REAL x1,
1431 REAL y1, REAL x2, REAL y2, REAL x3, REAL y3, REAL x4, REAL y4)
1432{
Evan Stade69a807c2007-07-06 16:13:49 -07001433 INT save_state;
1434 GpPointF pt[4];
Evan Stadefa312172007-07-11 18:07:39 -07001435 GpStatus retval;
Evan Stade8b9f5342007-06-15 21:27:38 -07001436
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001437 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1,
1438 x2, y2, x3, y3, x4, y4);
1439
Evan Stade8b9f5342007-06-15 21:27:38 -07001440 if(!graphics || !pen)
1441 return InvalidParameter;
1442
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001443 if(graphics->busy)
1444 return ObjectBusy;
1445
Evan Stade69a807c2007-07-06 16:13:49 -07001446 pt[0].X = x1;
1447 pt[0].Y = y1;
1448 pt[1].X = x2;
1449 pt[1].Y = y2;
1450 pt[2].X = x3;
1451 pt[2].Y = y3;
1452 pt[3].X = x4;
1453 pt[3].Y = y4;
Evan Stade8b9f5342007-06-15 21:27:38 -07001454
Evan Stade4c424b32007-07-24 17:18:54 -07001455 save_state = prepare_dc(graphics, pen);
Evan Stade8b9f5342007-06-15 21:27:38 -07001456
Evan Staded01c6972007-07-23 20:24:53 -07001457 retval = draw_polybezier(graphics, pen, pt, 4, TRUE);
Evan Stade69a807c2007-07-06 16:13:49 -07001458
Evan Stade4c424b32007-07-24 17:18:54 -07001459 restore_dc(graphics, save_state);
Evan Stade8b9f5342007-06-15 21:27:38 -07001460
Evan Stadefa312172007-07-11 18:07:39 -07001461 return retval;
Evan Stade8b9f5342007-06-15 21:27:38 -07001462}
1463
Royal Chanda161a52008-02-25 21:00:43 -08001464GpStatus WINGDIPAPI GdipDrawBezierI(GpGraphics *graphics, GpPen *pen, INT x1,
1465 INT y1, INT x2, INT y2, INT x3, INT y3, INT x4, INT y4)
1466{
1467 INT save_state;
1468 GpPointF pt[4];
1469 GpStatus retval;
1470
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001471 TRACE("(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", graphics, pen, x1, y1,
1472 x2, y2, x3, y3, x4, y4);
1473
Royal Chanda161a52008-02-25 21:00:43 -08001474 if(!graphics || !pen)
1475 return InvalidParameter;
1476
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001477 if(graphics->busy)
1478 return ObjectBusy;
1479
Royal Chanda161a52008-02-25 21:00:43 -08001480 pt[0].X = x1;
1481 pt[0].Y = y1;
1482 pt[1].X = x2;
1483 pt[1].Y = y2;
1484 pt[2].X = x3;
1485 pt[2].Y = y3;
1486 pt[3].X = x4;
1487 pt[3].Y = y4;
1488
1489 save_state = prepare_dc(graphics, pen);
1490
1491 retval = draw_polybezier(graphics, pen, pt, 4, TRUE);
1492
1493 restore_dc(graphics, save_state);
1494
1495 return retval;
1496}
1497
Nikolay Sivovd0204742008-07-03 03:04:50 +04001498GpStatus WINGDIPAPI GdipDrawBeziers(GpGraphics *graphics, GpPen *pen,
1499 GDIPCONST GpPointF *points, INT count)
1500{
1501 INT i;
1502 GpStatus ret;
1503
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001504 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1505
Nikolay Sivovd0204742008-07-03 03:04:50 +04001506 if(!graphics || !pen || !points || (count <= 0))
1507 return InvalidParameter;
1508
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001509 if(graphics->busy)
1510 return ObjectBusy;
1511
Nikolay Sivovd0204742008-07-03 03:04:50 +04001512 for(i = 0; i < floor(count / 4); i++){
1513 ret = GdipDrawBezier(graphics, pen,
1514 points[4*i].X, points[4*i].Y,
1515 points[4*i + 1].X, points[4*i + 1].Y,
1516 points[4*i + 2].X, points[4*i + 2].Y,
1517 points[4*i + 3].X, points[4*i + 3].Y);
1518 if(ret != Ok)
1519 return ret;
1520 }
1521
1522 return Ok;
1523}
1524
1525GpStatus WINGDIPAPI GdipDrawBeziersI(GpGraphics *graphics, GpPen *pen,
1526 GDIPCONST GpPoint *points, INT count)
1527{
1528 GpPointF *pts;
1529 GpStatus ret;
1530 INT i;
1531
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001532 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1533
Nikolay Sivovd0204742008-07-03 03:04:50 +04001534 if(!graphics || !pen || !points || (count <= 0))
1535 return InvalidParameter;
1536
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001537 if(graphics->busy)
1538 return ObjectBusy;
1539
Nikolay Sivovd0204742008-07-03 03:04:50 +04001540 pts = GdipAlloc(sizeof(GpPointF) * count);
1541 if(!pts)
1542 return OutOfMemory;
1543
1544 for(i = 0; i < count; i++){
1545 pts[i].X = (REAL)points[i].X;
1546 pts[i].Y = (REAL)points[i].Y;
1547 }
1548
1549 ret = GdipDrawBeziers(graphics,pen,pts,count);
1550
1551 GdipFree(pts);
1552
1553 return ret;
1554}
1555
Nikolay Sivov55916bb2008-07-09 00:39:31 +04001556GpStatus WINGDIPAPI GdipDrawClosedCurve(GpGraphics *graphics, GpPen *pen,
1557 GDIPCONST GpPointF *points, INT count)
1558{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001559 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1560
Nikolay Sivov55916bb2008-07-09 00:39:31 +04001561 return GdipDrawClosedCurve2(graphics, pen, points, count, 1.0);
1562}
1563
1564GpStatus WINGDIPAPI GdipDrawClosedCurveI(GpGraphics *graphics, GpPen *pen,
1565 GDIPCONST GpPoint *points, INT count)
1566{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001567 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1568
Nikolay Sivov55916bb2008-07-09 00:39:31 +04001569 return GdipDrawClosedCurve2I(graphics, pen, points, count, 1.0);
1570}
1571
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001572GpStatus WINGDIPAPI GdipDrawClosedCurve2(GpGraphics *graphics, GpPen *pen,
1573 GDIPCONST GpPointF *points, INT count, REAL tension)
1574{
Nikolay Sivov9c60a572008-09-03 19:57:09 +04001575 GpPath *path;
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001576 GpStatus stat;
1577
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001578 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
1579
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001580 if(!graphics || !pen || !points || count <= 0)
1581 return InvalidParameter;
1582
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001583 if(graphics->busy)
1584 return ObjectBusy;
1585
Nikolay Sivov9c60a572008-09-03 19:57:09 +04001586 if((stat = GdipCreatePath(FillModeAlternate, &path)) != Ok)
1587 return stat;
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001588
Nikolay Sivov9c60a572008-09-03 19:57:09 +04001589 stat = GdipAddPathClosedCurve2(path, points, count, tension);
1590 if(stat != Ok){
1591 GdipDeletePath(path);
1592 return stat;
1593 }
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001594
Nikolay Sivov9c60a572008-09-03 19:57:09 +04001595 stat = GdipDrawPath(graphics, pen, path);
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001596
Nikolay Sivov9c60a572008-09-03 19:57:09 +04001597 GdipDeletePath(path);
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001598
1599 return stat;
1600}
1601
1602GpStatus WINGDIPAPI GdipDrawClosedCurve2I(GpGraphics *graphics, GpPen *pen,
1603 GDIPCONST GpPoint *points, INT count, REAL tension)
1604{
1605 GpPointF *ptf;
1606 GpStatus stat;
1607 INT i;
1608
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001609 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
1610
Nikolay Sivov8b8864b2008-07-09 00:39:19 +04001611 if(!points || count <= 0)
1612 return InvalidParameter;
1613
1614 ptf = GdipAlloc(sizeof(GpPointF)*count);
1615 if(!ptf)
1616 return OutOfMemory;
1617
1618 for(i = 0; i < count; i++){
1619 ptf[i].X = (REAL)points[i].X;
1620 ptf[i].Y = (REAL)points[i].Y;
1621 }
1622
1623 stat = GdipDrawClosedCurve2(graphics, pen, ptf, count, tension);
1624
1625 GdipFree(ptf);
1626
1627 return stat;
1628}
1629
Nikolay Sivovfe1782e2008-04-29 00:09:55 +04001630GpStatus WINGDIPAPI GdipDrawCurve(GpGraphics *graphics, GpPen *pen,
1631 GDIPCONST GpPointF *points, INT count)
1632{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001633 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1634
Nikolay Sivovfe1782e2008-04-29 00:09:55 +04001635 return GdipDrawCurve2(graphics,pen,points,count,1.0);
1636}
1637
1638GpStatus WINGDIPAPI GdipDrawCurveI(GpGraphics *graphics, GpPen *pen,
1639 GDIPCONST GpPoint *points, INT count)
1640{
1641 GpPointF *pointsF;
1642 GpStatus ret;
1643 INT i;
1644
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001645 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
1646
Andrew Eikumfe55f0d2009-06-28 13:33:52 -05001647 if(!points)
Nikolay Sivovfe1782e2008-04-29 00:09:55 +04001648 return InvalidParameter;
1649
1650 pointsF = GdipAlloc(sizeof(GpPointF)*count);
1651 if(!pointsF)
1652 return OutOfMemory;
1653
1654 for(i = 0; i < count; i++){
1655 pointsF[i].X = (REAL)points[i].X;
1656 pointsF[i].Y = (REAL)points[i].Y;
1657 }
1658
1659 ret = GdipDrawCurve(graphics,pen,pointsF,count);
1660 GdipFree(pointsF);
1661
1662 return ret;
1663}
1664
Evan Stade5c8b83c2007-06-19 19:31:28 -07001665/* Approximates cardinal spline with Bezier curves. */
1666GpStatus WINGDIPAPI GdipDrawCurve2(GpGraphics *graphics, GpPen *pen,
1667 GDIPCONST GpPointF *points, INT count, REAL tension)
1668{
Evan Stade5c8b83c2007-06-19 19:31:28 -07001669 /* PolyBezier expects count*3-2 points. */
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001670 INT i, len_pt = count*3-2, save_state;
1671 GpPointF *pt;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001672 REAL x1, x2, y1, y2;
Evan Stadefa312172007-07-11 18:07:39 -07001673 GpStatus retval;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001674
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001675 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
1676
Evan Stade5c8b83c2007-06-19 19:31:28 -07001677 if(!graphics || !pen)
1678 return InvalidParameter;
1679
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001680 if(graphics->busy)
1681 return ObjectBusy;
1682
Andrew Eikum119e9af2009-06-06 12:02:29 -05001683 if(count < 2)
1684 return InvalidParameter;
1685
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001686 pt = GdipAlloc(len_pt * sizeof(GpPointF));
Andrew Eikum119e9af2009-06-06 12:02:29 -05001687 if(!pt)
1688 return OutOfMemory;
1689
Evan Stade5c8b83c2007-06-19 19:31:28 -07001690 tension = tension * TENSION_CONST;
1691
1692 calc_curve_bezier_endp(points[0].X, points[0].Y, points[1].X, points[1].Y,
1693 tension, &x1, &y1);
1694
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001695 pt[0].X = points[0].X;
1696 pt[0].Y = points[0].Y;
1697 pt[1].X = x1;
1698 pt[1].Y = y1;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001699
1700 for(i = 0; i < count-2; i++){
1701 calc_curve_bezier(&(points[i]), tension, &x1, &y1, &x2, &y2);
1702
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001703 pt[3*i+2].X = x1;
1704 pt[3*i+2].Y = y1;
1705 pt[3*i+3].X = points[i+1].X;
1706 pt[3*i+3].Y = points[i+1].Y;
1707 pt[3*i+4].X = x2;
1708 pt[3*i+4].Y = y2;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001709 }
1710
1711 calc_curve_bezier_endp(points[count-1].X, points[count-1].Y,
1712 points[count-2].X, points[count-2].Y, tension, &x1, &y1);
1713
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001714 pt[len_pt-2].X = x1;
1715 pt[len_pt-2].Y = y1;
1716 pt[len_pt-1].X = points[count-1].X;
1717 pt[len_pt-1].Y = points[count-1].Y;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001718
Evan Stade4c424b32007-07-24 17:18:54 -07001719 save_state = prepare_dc(graphics, pen);
Evan Stade5c8b83c2007-06-19 19:31:28 -07001720
Evan Staded01c6972007-07-23 20:24:53 -07001721 retval = draw_polybezier(graphics, pen, pt, len_pt, TRUE);
Evan Stade5c8b83c2007-06-19 19:31:28 -07001722
Evan Stadeb72dc0d2007-07-09 20:54:23 -07001723 GdipFree(pt);
Evan Stade4c424b32007-07-24 17:18:54 -07001724 restore_dc(graphics, save_state);
Evan Stade5c8b83c2007-06-19 19:31:28 -07001725
Evan Stadefa312172007-07-11 18:07:39 -07001726 return retval;
Evan Stade5c8b83c2007-06-19 19:31:28 -07001727}
1728
Nikolay Sivov00cfffb2008-04-29 00:09:44 +04001729GpStatus WINGDIPAPI GdipDrawCurve2I(GpGraphics *graphics, GpPen *pen,
1730 GDIPCONST GpPoint *points, INT count, REAL tension)
1731{
1732 GpPointF *pointsF;
1733 GpStatus ret;
1734 INT i;
1735
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001736 TRACE("(%p, %p, %p, %d, %.2f)\n", graphics, pen, points, count, tension);
1737
Andrew Eikumc2aa66d2009-06-28 13:33:59 -05001738 if(!points)
Nikolay Sivov00cfffb2008-04-29 00:09:44 +04001739 return InvalidParameter;
1740
1741 pointsF = GdipAlloc(sizeof(GpPointF)*count);
1742 if(!pointsF)
1743 return OutOfMemory;
1744
1745 for(i = 0; i < count; i++){
1746 pointsF[i].X = (REAL)points[i].X;
1747 pointsF[i].Y = (REAL)points[i].Y;
1748 }
1749
1750 ret = GdipDrawCurve2(graphics,pen,pointsF,count,tension);
1751 GdipFree(pointsF);
1752
1753 return ret;
1754}
1755
Andrew Eikum4c0edba2009-06-29 22:12:40 -05001756GpStatus WINGDIPAPI GdipDrawCurve3(GpGraphics *graphics, GpPen *pen,
1757 GDIPCONST GpPointF *points, INT count, INT offset, INT numberOfSegments,
1758 REAL tension)
1759{
1760 TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension);
1761
1762 if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){
1763 return InvalidParameter;
1764 }
1765
1766 return GdipDrawCurve2(graphics, pen, points + offset, numberOfSegments + 1, tension);
1767}
1768
1769GpStatus WINGDIPAPI GdipDrawCurve3I(GpGraphics *graphics, GpPen *pen,
1770 GDIPCONST GpPoint *points, INT count, INT offset, INT numberOfSegments,
1771 REAL tension)
1772{
1773 TRACE("(%p, %p, %p, %d, %d, %d, %.2f)\n", graphics, pen, points, count, offset, numberOfSegments, tension);
1774
1775 if(count < 0){
1776 return OutOfMemory;
1777 }
1778
1779 if(offset >= count || numberOfSegments > count - offset - 1 || numberOfSegments <= 0){
1780 return InvalidParameter;
1781 }
1782
1783 return GdipDrawCurve2I(graphics, pen, points + offset, numberOfSegments + 1, tension);
1784}
1785
Przemysław Białek864384e2008-06-27 10:59:23 +02001786GpStatus WINGDIPAPI GdipDrawEllipse(GpGraphics *graphics, GpPen *pen, REAL x,
1787 REAL y, REAL width, REAL height)
1788{
1789 INT save_state;
1790 GpPointF ptf[2];
1791 POINT pti[2];
1792
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001793 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height);
1794
Przemysław Białek864384e2008-06-27 10:59:23 +02001795 if(!graphics || !pen)
1796 return InvalidParameter;
1797
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04001798 if(graphics->busy)
1799 return ObjectBusy;
1800
Przemysław Białek864384e2008-06-27 10:59:23 +02001801 ptf[0].X = x;
1802 ptf[0].Y = y;
1803 ptf[1].X = x + width;
1804 ptf[1].Y = y + height;
1805
1806 save_state = prepare_dc(graphics, pen);
1807 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
1808
1809 transform_and_round_points(graphics, pti, ptf, 2);
1810
1811 Ellipse(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y);
1812
1813 restore_dc(graphics, save_state);
1814
1815 return Ok;
1816}
1817
1818GpStatus WINGDIPAPI GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x,
1819 INT y, INT width, INT height)
1820{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001821 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height);
1822
Przemysław Białek864384e2008-06-27 10:59:23 +02001823 return GdipDrawEllipse(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
1824}
1825
1826
Nikolay Sivov49247042008-04-29 00:10:01 +04001827GpStatus WINGDIPAPI GdipDrawImage(GpGraphics *graphics, GpImage *image, REAL x, REAL y)
1828{
Vincent Povirke72defc2009-08-20 16:16:05 -05001829 UINT width, height;
1830 GpPointF points[3];
1831
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001832 TRACE("(%p, %p, %.2f, %.2f)\n", graphics, image, x, y);
1833
Evan Stadede351ab2007-08-07 18:42:12 -07001834 if(!graphics || !image)
1835 return InvalidParameter;
1836
1837 GdipGetImageWidth(image, &width);
1838 GdipGetImageHeight(image, &height);
1839
Vincent Povirke72defc2009-08-20 16:16:05 -05001840 /* FIXME: we should use the graphics and image dpi, somehow */
Evan Stadede351ab2007-08-07 18:42:12 -07001841
Vincent Povirke72defc2009-08-20 16:16:05 -05001842 points[0].X = points[2].X = x;
1843 points[0].Y = points[1].Y = y;
1844 points[1].X = x + width;
1845 points[2].Y = y + height;
Evan Stadede351ab2007-08-07 18:42:12 -07001846
Vincent Povirke72defc2009-08-20 16:16:05 -05001847 return GdipDrawImagePointsRect(graphics, image, points, 3, 0, 0, width, height,
1848 UnitPixel, NULL, NULL, NULL);
1849}
Evan Stadede351ab2007-08-07 18:42:12 -07001850
Vincent Povirke72defc2009-08-20 16:16:05 -05001851GpStatus WINGDIPAPI GdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x,
1852 INT y)
1853{
1854 TRACE("(%p, %p, %d, %d)\n", graphics, image, x, y);
1855
1856 return GdipDrawImage(graphics, image, (REAL)x, (REAL)y);
Evan Stadede351ab2007-08-07 18:42:12 -07001857}
1858
Andrew Eikumeec8d512009-06-02 22:34:37 -05001859GpStatus WINGDIPAPI GdipDrawImagePointRect(GpGraphics *graphics, GpImage *image,
1860 REAL x, REAL y, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight,
1861 GpUnit srcUnit)
1862{
Vincent Povirk94ab2332009-09-04 12:51:48 -05001863 GpPointF points[3];
1864 TRACE("(%p, %p, %f, %f, %f, %f, %f, %f, %d)\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
1865
1866 points[0].X = points[2].X = x;
1867 points[0].Y = points[1].Y = y;
1868
1869 /* FIXME: convert image coordinates to Graphics coordinates? */
1870 points[1].X = x + srcwidth;
1871 points[2].Y = y + srcheight;
1872
1873 return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy,
1874 srcwidth, srcheight, srcUnit, NULL, NULL, NULL);
Andrew Eikumeec8d512009-06-02 22:34:37 -05001875}
1876
1877GpStatus WINGDIPAPI GdipDrawImagePointRectI(GpGraphics *graphics, GpImage *image,
1878 INT x, INT y, INT srcx, INT srcy, INT srcwidth, INT srcheight,
1879 GpUnit srcUnit)
1880{
Vincent Povirk94ab2332009-09-04 12:51:48 -05001881 return GdipDrawImagePointRect(graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
Andrew Eikumeec8d512009-06-02 22:34:37 -05001882}
1883
Andrew Eikum156eeb02009-06-03 23:31:21 -05001884GpStatus WINGDIPAPI GdipDrawImagePoints(GpGraphics *graphics, GpImage *image,
1885 GDIPCONST GpPointF *dstpoints, INT count)
1886{
1887 FIXME("(%p, %p, %p, %d): stub\n", graphics, image, dstpoints, count);
1888 return NotImplemented;
1889}
1890
1891GpStatus WINGDIPAPI GdipDrawImagePointsI(GpGraphics *graphics, GpImage *image,
1892 GDIPCONST GpPoint *dstpoints, INT count)
1893{
1894 FIXME("(%p, %p, %p, %d): stub\n", graphics, image, dstpoints, count);
1895 return NotImplemented;
1896}
1897
Evan Stade04d4c262007-08-09 18:25:09 -07001898/* FIXME: partially implemented (only works for rectangular parallelograms) */
Evan Stade460f01b2007-07-30 19:09:45 -07001899GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image,
Evan Stadea9c4f302007-07-30 19:10:07 -07001900 GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth,
1901 REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
1902 DrawImageAbort callback, VOID * callbackData)
Evan Stade460f01b2007-07-30 19:09:45 -07001903{
Vincent Povirk54339692010-03-28 22:25:20 -05001904 GpPointF ptf[4];
1905 POINT pti[4];
Evan Stade6e0c5742007-07-31 19:16:23 -07001906 REAL dx, dy;
Vincent Povirk54339692010-03-28 22:25:20 -05001907 GpStatus stat;
Evan Stade460f01b2007-07-30 19:09:45 -07001908
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04001909 TRACE("(%p, %p, %p, %d, %f, %f, %f, %f, %d, %p, %p, %p)\n", graphics, image, points,
1910 count, srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback,
Evan Stadea9c4f302007-07-30 19:10:07 -07001911 callbackData);
Evan Stade460f01b2007-07-30 19:09:45 -07001912
Nikolay Sivov8cf56082008-04-25 01:58:36 +04001913 if(!graphics || !image || !points || count != 3)
Evan Stadea9c4f302007-07-30 19:10:07 -07001914 return InvalidParameter;
Evan Stade460f01b2007-07-30 19:09:45 -07001915
Vincent Povirk7ded3d82009-12-18 15:45:02 -06001916 TRACE("%s %s %s\n", debugstr_pointf(&points[0]), debugstr_pointf(&points[1]),
1917 debugstr_pointf(&points[2]));
1918
Evan Stadea9c4f302007-07-30 19:10:07 -07001919 memcpy(ptf, points, 3 * sizeof(GpPointF));
Vincent Povirk54339692010-03-28 22:25:20 -05001920 ptf[3].X = ptf[2].X + ptf[1].X - ptf[0].X;
1921 ptf[3].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y;
1922 transform_and_round_points(graphics, pti, ptf, 4);
Evan Stadea9c4f302007-07-30 19:10:07 -07001923
Vincent Povirk436b3be2009-08-28 16:21:27 -05001924 if (image->picture)
1925 {
1926 if(srcUnit == UnitInch)
1927 dx = dy = (REAL) INCH_HIMETRIC;
1928 else if(srcUnit == UnitPixel){
1929 dx = ((REAL) INCH_HIMETRIC) /
1930 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSX));
1931 dy = ((REAL) INCH_HIMETRIC) /
1932 ((REAL) GetDeviceCaps(graphics->hdc, LOGPIXELSY));
1933 }
1934 else
1935 return NotImplemented;
Evan Stade6e0c5742007-07-31 19:16:23 -07001936
Vincent Povirk436b3be2009-08-28 16:21:27 -05001937 if(IPicture_Render(image->picture, graphics->hdc,
1938 pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
1939 srcx * dx, srcy * dy,
1940 srcwidth * dx, srcheight * dy,
1941 NULL) != S_OK){
1942 if(callback)
1943 callback(callbackData);
1944 return GenericError;
1945 }
1946 }
1947 else if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap)
1948 {
Vincent Povirk436b3be2009-08-28 16:21:27 -05001949 GpBitmap* bitmap = (GpBitmap*)image;
Vincent Povirk54339692010-03-28 22:25:20 -05001950 int use_software=0;
Vincent Povirk436b3be2009-08-28 16:21:27 -05001951
1952 if (srcUnit == UnitInch)
1953 dx = dy = 96.0; /* FIXME: use the image resolution */
1954 else if (srcUnit == UnitPixel)
1955 dx = dy = 1.0;
1956 else
1957 return NotImplemented;
1958
Vincent Povirk54339692010-03-28 22:25:20 -05001959 if (graphics->image && graphics->image->type == ImageTypeBitmap)
Vincent Povirk436b3be2009-08-28 16:21:27 -05001960 {
Vincent Povirk54339692010-03-28 22:25:20 -05001961 GpBitmap *dst_bitmap = (GpBitmap*)graphics->image;
1962 if (!(dst_bitmap->format == PixelFormat16bppRGB555 ||
1963 dst_bitmap->format == PixelFormat24bppRGB ||
1964 dst_bitmap->format == PixelFormat32bppRGB))
1965 use_software = 1;
1966 }
Vincent Povirk895c6d82009-08-28 17:21:10 -05001967
Vincent Povirk54339692010-03-28 22:25:20 -05001968 if (use_software)
1969 {
1970 RECT src_area, dst_area;
Vincent Povirk9c380b12010-04-15 14:11:07 -05001971 int i, x, y, stride;
Vincent Povirk54339692010-03-28 22:25:20 -05001972 GpMatrix *dst_to_src;
1973 REAL m11, m12, m21, m22, mdx, mdy;
Vincent Povirk9c380b12010-04-15 14:11:07 -05001974 LPBYTE data;
Vincent Povirk895c6d82009-08-28 17:21:10 -05001975
Vincent Povirk54339692010-03-28 22:25:20 -05001976 src_area.left = srcx*dx;
1977 src_area.top = srcy*dy;
1978 src_area.right = (srcx+srcwidth)*dx;
1979 src_area.bottom = (srcy+srcheight)*dy;
Vincent Povirk895c6d82009-08-28 17:21:10 -05001980
Vincent Povirk54339692010-03-28 22:25:20 -05001981 dst_area.left = dst_area.right = pti[0].x;
1982 dst_area.top = dst_area.bottom = pti[0].y;
1983 for (i=1; i<4; i++)
1984 {
1985 if (dst_area.left > pti[i].x) dst_area.left = pti[i].x;
1986 if (dst_area.right < pti[i].x) dst_area.right = pti[i].x;
1987 if (dst_area.top > pti[i].y) dst_area.top = pti[i].y;
1988 if (dst_area.bottom < pti[i].y) dst_area.bottom = pti[i].y;
1989 }
1990
1991 m11 = (ptf[1].X - ptf[0].X) / srcwidth;
1992 m12 = (ptf[2].X - ptf[0].X) / srcheight;
1993 mdx = ptf[0].X - m11 * srcx - m12 * srcy;
1994 m21 = (ptf[1].Y - ptf[0].Y) / srcwidth;
1995 m22 = (ptf[2].Y - ptf[0].Y) / srcheight;
1996 mdy = ptf[0].Y - m21 * srcx - m22 * srcy;
1997
1998 stat = GdipCreateMatrix2(m11, m12, m21, m22, mdx, mdy, &dst_to_src);
1999 if (stat != Ok) return stat;
2000
2001 stat = GdipInvertMatrix(dst_to_src);
2002 if (stat != Ok)
2003 {
2004 GdipDeleteMatrix(dst_to_src);
2005 return stat;
2006 }
2007
Vincent Povirk9c380b12010-04-15 14:11:07 -05002008 data = GdipAlloc(sizeof(ARGB) * (dst_area.right - dst_area.left) * (dst_area.bottom - dst_area.top));
2009 if (!data)
2010 {
2011 GdipDeleteMatrix(dst_to_src);
2012 return OutOfMemory;
2013 }
2014
2015 stride = sizeof(ARGB) * (dst_area.right - dst_area.left);
2016
Vincent Povirk54339692010-03-28 22:25:20 -05002017 for (x=dst_area.left; x<dst_area.right; x++)
2018 {
2019 for (y=dst_area.top; y<dst_area.bottom; y++)
2020 {
2021 GpPointF src_pointf;
2022 int src_x, src_y;
Vincent Povirk9c380b12010-04-15 14:11:07 -05002023 ARGB *src_color;
Vincent Povirk54339692010-03-28 22:25:20 -05002024
2025 src_pointf.X = x;
2026 src_pointf.Y = y;
2027
2028 GdipTransformMatrixPoints(dst_to_src, &src_pointf, 1);
2029
2030 src_x = roundr(src_pointf.X);
2031 src_y = roundr(src_pointf.Y);
2032
Vincent Povirk9c380b12010-04-15 14:11:07 -05002033 src_color = (ARGB*)(data + stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left));
2034
Vincent Povirk54339692010-03-28 22:25:20 -05002035 if (src_x < src_area.left || src_x >= src_area.right ||
2036 src_y < src_area.top || src_y >= src_area.bottom)
2037 /* FIXME: Use wrapmode */
Vincent Povirk9c380b12010-04-15 14:11:07 -05002038 *src_color = 0;
2039 else
2040 GdipBitmapGetPixel(bitmap, src_x, src_y, src_color);
Vincent Povirk54339692010-03-28 22:25:20 -05002041 }
2042 }
2043
2044 GdipDeleteMatrix(dst_to_src);
Vincent Povirk9c380b12010-04-15 14:11:07 -05002045
2046 stat = alpha_blend_pixels(graphics, dst_area.left, dst_area.top,
2047 data, dst_area.right - dst_area.left, dst_area.bottom - dst_area.top, stride);
2048
2049 GdipFree(data);
2050
2051 return stat;
Vincent Povirk54339692010-03-28 22:25:20 -05002052 }
2053 else
2054 {
2055 HDC hdc;
2056 int temp_hdc=0, temp_bitmap=0;
2057 HBITMAP hbitmap, old_hbm=NULL;
2058
2059 if (!(bitmap->format == PixelFormat16bppRGB555 ||
2060 bitmap->format == PixelFormat24bppRGB ||
2061 bitmap->format == PixelFormat32bppRGB ||
2062 bitmap->format == PixelFormat32bppPARGB))
2063 {
2064 BITMAPINFOHEADER bih;
2065 BYTE *temp_bits;
2066 PixelFormat dst_format;
2067
2068 /* we can't draw a bitmap of this format directly */
2069 hdc = CreateCompatibleDC(0);
2070 temp_hdc = 1;
2071 temp_bitmap = 1;
2072
2073 bih.biSize = sizeof(BITMAPINFOHEADER);
2074 bih.biWidth = bitmap->width;
2075 bih.biHeight = -bitmap->height;
2076 bih.biPlanes = 1;
2077 bih.biBitCount = 32;
2078 bih.biCompression = BI_RGB;
2079 bih.biSizeImage = 0;
2080 bih.biXPelsPerMeter = 0;
2081 bih.biYPelsPerMeter = 0;
2082 bih.biClrUsed = 0;
2083 bih.biClrImportant = 0;
2084
2085 hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS,
2086 (void**)&temp_bits, NULL, 0);
2087
2088 if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha))
2089 dst_format = PixelFormat32bppPARGB;
2090 else
2091 dst_format = PixelFormat32bppRGB;
2092
2093 convert_pixels(bitmap->width, bitmap->height,
2094 bitmap->width*4, temp_bits, dst_format,
2095 bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette_entries);
2096 }
2097 else
2098 {
2099 hbitmap = bitmap->hbitmap;
2100 hdc = bitmap->hdc;
2101 temp_hdc = (hdc == 0);
2102 }
2103
2104 if (temp_hdc)
2105 {
2106 if (!hdc) hdc = CreateCompatibleDC(0);
2107 old_hbm = SelectObject(hdc, hbitmap);
2108 }
Vincent Povirk895c6d82009-08-28 17:21:10 -05002109
Vincent Povirk00dec582010-02-05 13:48:36 -06002110 if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha))
Vincent Povirk54339692010-03-28 22:25:20 -05002111 {
2112 BLENDFUNCTION bf;
2113
2114 bf.BlendOp = AC_SRC_OVER;
2115 bf.BlendFlags = 0;
2116 bf.SourceConstantAlpha = 255;
2117 bf.AlphaFormat = AC_SRC_ALPHA;
2118
2119 GdiAlphaBlend(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y,
2120 hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, bf);
2121 }
Vincent Povirk00dec582010-02-05 13:48:36 -06002122 else
Vincent Povirk54339692010-03-28 22:25:20 -05002123 {
2124 StretchBlt(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y,
2125 hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, SRCCOPY);
2126 }
Vincent Povirk00dec582010-02-05 13:48:36 -06002127
Vincent Povirk54339692010-03-28 22:25:20 -05002128 if (temp_hdc)
2129 {
2130 SelectObject(hdc, old_hbm);
2131 DeleteDC(hdc);
2132 }
2133
2134 if (temp_bitmap)
2135 DeleteObject(hbitmap);
Vincent Povirk895c6d82009-08-28 17:21:10 -05002136 }
Vincent Povirk436b3be2009-08-28 16:21:27 -05002137 }
2138 else
2139 {
2140 ERR("GpImage with no IPicture or HBITMAP?!\n");
2141 return NotImplemented;
Evan Stadea9c4f302007-07-30 19:10:07 -07002142 }
2143
2144 return Ok;
Evan Stade460f01b2007-07-30 19:09:45 -07002145}
2146
Nikolay Sivov79b49a82008-04-29 00:10:05 +04002147GpStatus WINGDIPAPI GdipDrawImagePointsRectI(GpGraphics *graphics, GpImage *image,
2148 GDIPCONST GpPoint *points, INT count, INT srcx, INT srcy, INT srcwidth,
2149 INT srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
2150 DrawImageAbort callback, VOID * callbackData)
2151{
2152 GpPointF pointsF[3];
2153 INT i;
2154
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002155 TRACE("(%p, %p, %p, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n", graphics, image, points, count,
2156 srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback,
2157 callbackData);
2158
Nikolay Sivov79b49a82008-04-29 00:10:05 +04002159 if(!points || count!=3)
2160 return InvalidParameter;
2161
2162 for(i = 0; i < count; i++){
2163 pointsF[i].X = (REAL)points[i].X;
2164 pointsF[i].Y = (REAL)points[i].Y;
2165 }
2166
2167 return GdipDrawImagePointsRect(graphics, image, pointsF, count, (REAL)srcx, (REAL)srcy,
2168 (REAL)srcwidth, (REAL)srcheight, srcUnit, imageAttributes,
2169 callback, callbackData);
2170}
2171
Evan Stade04d4c262007-08-09 18:25:09 -07002172GpStatus WINGDIPAPI GdipDrawImageRectRect(GpGraphics *graphics, GpImage *image,
2173 REAL dstx, REAL dsty, REAL dstwidth, REAL dstheight, REAL srcx, REAL srcy,
2174 REAL srcwidth, REAL srcheight, GpUnit srcUnit,
2175 GDIPCONST GpImageAttributes* imageattr, DrawImageAbort callback,
2176 VOID * callbackData)
2177{
2178 GpPointF points[3];
2179
Francois Gouget758c4532008-09-05 13:14:56 +02002180 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p, %p, %p)\n",
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002181 graphics, image, dstx, dsty, dstwidth, dstheight, srcx, srcy,
2182 srcwidth, srcheight, srcUnit, imageattr, callback, callbackData);
2183
Evan Stade04d4c262007-08-09 18:25:09 -07002184 points[0].X = dstx;
2185 points[0].Y = dsty;
2186 points[1].X = dstx + dstwidth;
2187 points[1].Y = dsty;
2188 points[2].X = dstx;
2189 points[2].Y = dsty + dstheight;
2190
2191 return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy,
2192 srcwidth, srcheight, srcUnit, imageattr, callback, callbackData);
2193}
2194
Jon Yang29bc9ba2008-02-28 21:54:47 -08002195GpStatus WINGDIPAPI GdipDrawImageRectRectI(GpGraphics *graphics, GpImage *image,
2196 INT dstx, INT dsty, INT dstwidth, INT dstheight, INT srcx, INT srcy,
2197 INT srcwidth, INT srcheight, GpUnit srcUnit,
2198 GDIPCONST GpImageAttributes* imageAttributes, DrawImageAbort callback,
2199 VOID * callbackData)
2200{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002201 GpPointF points[3];
2202
Francois Gouget758c4532008-09-05 13:14:56 +02002203 TRACE("(%p, %p, %d, %d, %d, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n",
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002204 graphics, image, dstx, dsty, dstwidth, dstheight, srcx, srcy,
2205 srcwidth, srcheight, srcUnit, imageAttributes, callback, callbackData);
Jon Yang29bc9ba2008-02-28 21:54:47 -08002206
2207 points[0].X = dstx;
2208 points[0].Y = dsty;
2209 points[1].X = dstx + dstwidth;
2210 points[1].Y = dsty;
2211 points[2].X = dstx;
2212 points[2].Y = dsty + dstheight;
2213
2214 return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy,
2215 srcwidth, srcheight, srcUnit, imageAttributes, callback, callbackData);
2216}
2217
Nikolay Sivov8cf56082008-04-25 01:58:36 +04002218GpStatus WINGDIPAPI GdipDrawImageRect(GpGraphics *graphics, GpImage *image,
2219 REAL x, REAL y, REAL width, REAL height)
2220{
2221 RectF bounds;
2222 GpUnit unit;
2223 GpStatus ret;
2224
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002225 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, image, x, y, width, height);
2226
Nikolay Sivov8cf56082008-04-25 01:58:36 +04002227 if(!graphics || !image)
2228 return InvalidParameter;
2229
2230 ret = GdipGetImageBounds(image, &bounds, &unit);
2231 if(ret != Ok)
2232 return ret;
2233
2234 return GdipDrawImageRectRect(graphics, image, x, y, width, height,
2235 bounds.X, bounds.Y, bounds.Width, bounds.Height,
2236 unit, NULL, NULL, NULL);
2237}
2238
2239GpStatus WINGDIPAPI GdipDrawImageRectI(GpGraphics *graphics, GpImage *image,
2240 INT x, INT y, INT width, INT height)
2241{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002242 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, image, x, y, width, height);
2243
Nikolay Sivov8cf56082008-04-25 01:58:36 +04002244 return GdipDrawImageRect(graphics, image, (REAL)x, (REAL)y, (REAL)width, (REAL)height);
2245}
2246
Evan Stade5e29e372007-08-01 17:55:58 -07002247GpStatus WINGDIPAPI GdipDrawLine(GpGraphics *graphics, GpPen *pen, REAL x1,
2248 REAL y1, REAL x2, REAL y2)
2249{
2250 INT save_state;
2251 GpPointF pt[2];
2252 GpStatus retval;
2253
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002254 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x1, y1, x2, y2);
2255
Evan Stade5e29e372007-08-01 17:55:58 -07002256 if(!pen || !graphics)
2257 return InvalidParameter;
2258
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002259 if(graphics->busy)
2260 return ObjectBusy;
2261
Evan Stade5e29e372007-08-01 17:55:58 -07002262 pt[0].X = x1;
2263 pt[0].Y = y1;
2264 pt[1].X = x2;
2265 pt[1].Y = y2;
2266
2267 save_state = prepare_dc(graphics, pen);
2268
2269 retval = draw_polyline(graphics, pen, pt, 2, TRUE);
2270
2271 restore_dc(graphics, save_state);
2272
2273 return retval;
2274}
2275
Evan Stade2689b182007-06-12 10:44:31 -07002276GpStatus WINGDIPAPI GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1,
2277 INT y1, INT x2, INT y2)
2278{
Evan Staded9ef1722007-07-02 15:13:05 -07002279 INT save_state;
Evan Stade5128e5d2007-07-07 13:20:41 -07002280 GpPointF pt[2];
Evan Stade6f4ab522007-07-11 18:07:44 -07002281 GpStatus retval;
Evan Stade2689b182007-06-12 10:44:31 -07002282
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002283 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x1, y1, x2, y2);
2284
Evan Stade2689b182007-06-12 10:44:31 -07002285 if(!pen || !graphics)
2286 return InvalidParameter;
2287
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002288 if(graphics->busy)
2289 return ObjectBusy;
2290
Evan Stade5128e5d2007-07-07 13:20:41 -07002291 pt[0].X = (REAL)x1;
2292 pt[0].Y = (REAL)y1;
2293 pt[1].X = (REAL)x2;
2294 pt[1].Y = (REAL)y2;
2295
Evan Stade4c424b32007-07-24 17:18:54 -07002296 save_state = prepare_dc(graphics, pen);
Evan Staded9ef1722007-07-02 15:13:05 -07002297
Evan Staded01c6972007-07-23 20:24:53 -07002298 retval = draw_polyline(graphics, pen, pt, 2, TRUE);
Evan Staded9ef1722007-07-02 15:13:05 -07002299
Evan Stade4c424b32007-07-24 17:18:54 -07002300 restore_dc(graphics, save_state);
Evan Stade2689b182007-06-12 10:44:31 -07002301
Evan Stade6f4ab522007-07-11 18:07:44 -07002302 return retval;
Evan Stade2689b182007-06-12 10:44:31 -07002303}
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002304
Evan Stadef6f04f62007-06-21 16:15:13 -07002305GpStatus WINGDIPAPI GdipDrawLines(GpGraphics *graphics, GpPen *pen, GDIPCONST
2306 GpPointF *points, INT count)
2307{
Evan Stade852aac82007-07-11 18:07:16 -07002308 INT save_state;
Evan Stade6f4ab522007-07-11 18:07:44 -07002309 GpStatus retval;
Evan Stadef6f04f62007-06-21 16:15:13 -07002310
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002311 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
2312
Evan Stadef6f04f62007-06-21 16:15:13 -07002313 if(!pen || !graphics || (count < 2))
2314 return InvalidParameter;
2315
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002316 if(graphics->busy)
2317 return ObjectBusy;
2318
Evan Stade4c424b32007-07-24 17:18:54 -07002319 save_state = prepare_dc(graphics, pen);
Evan Stadef6f04f62007-06-21 16:15:13 -07002320
Evan Staded01c6972007-07-23 20:24:53 -07002321 retval = draw_polyline(graphics, pen, points, count, TRUE);
Evan Stadef6f04f62007-06-21 16:15:13 -07002322
Evan Stade4c424b32007-07-24 17:18:54 -07002323 restore_dc(graphics, save_state);
Evan Stadef6f04f62007-06-21 16:15:13 -07002324
Evan Stade6f4ab522007-07-11 18:07:44 -07002325 return retval;
Evan Stadef6f04f62007-06-21 16:15:13 -07002326}
2327
Royal Chan6e7b5342008-02-29 04:58:39 -08002328GpStatus WINGDIPAPI GdipDrawLinesI(GpGraphics *graphics, GpPen *pen, GDIPCONST
2329 GpPoint *points, INT count)
2330{
2331 INT save_state;
2332 GpStatus retval;
2333 GpPointF *ptf = NULL;
2334 int i;
2335
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002336 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
2337
Royal Chan6e7b5342008-02-29 04:58:39 -08002338 if(!pen || !graphics || (count < 2))
2339 return InvalidParameter;
2340
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002341 if(graphics->busy)
2342 return ObjectBusy;
2343
Royal Chan6e7b5342008-02-29 04:58:39 -08002344 ptf = GdipAlloc(count * sizeof(GpPointF));
2345 if(!ptf) return OutOfMemory;
2346
2347 for(i = 0; i < count; i ++){
2348 ptf[i].X = (REAL) points[i].X;
2349 ptf[i].Y = (REAL) points[i].Y;
2350 }
2351
2352 save_state = prepare_dc(graphics, pen);
2353
2354 retval = draw_polyline(graphics, pen, ptf, count, TRUE);
2355
2356 restore_dc(graphics, save_state);
2357
2358 GdipFree(ptf);
2359 return retval;
2360}
2361
Evan Stade9d5f5682007-07-11 18:07:34 -07002362GpStatus WINGDIPAPI GdipDrawPath(GpGraphics *graphics, GpPen *pen, GpPath *path)
2363{
Evan Stade9e883472007-07-13 17:51:49 -07002364 INT save_state;
Evan Stade9d5f5682007-07-11 18:07:34 -07002365 GpStatus retval;
2366
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002367 TRACE("(%p, %p, %p)\n", graphics, pen, path);
2368
Evan Stade9d5f5682007-07-11 18:07:34 -07002369 if(!pen || !graphics)
2370 return InvalidParameter;
2371
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002372 if(graphics->busy)
2373 return ObjectBusy;
2374
Evan Stade4c424b32007-07-24 17:18:54 -07002375 save_state = prepare_dc(graphics, pen);
Evan Stade9d5f5682007-07-11 18:07:34 -07002376
Evan Staded01c6972007-07-23 20:24:53 -07002377 retval = draw_poly(graphics, pen, path->pathdata.Points,
Evan Stade9e883472007-07-13 17:51:49 -07002378 path->pathdata.Types, path->pathdata.Count, TRUE);
Evan Stade9d5f5682007-07-11 18:07:34 -07002379
Evan Stade4c424b32007-07-24 17:18:54 -07002380 restore_dc(graphics, save_state);
Evan Stade9d5f5682007-07-11 18:07:34 -07002381
2382 return retval;
2383}
2384
Evan Stade72ab72c502007-06-18 16:55:51 -07002385GpStatus WINGDIPAPI GdipDrawPie(GpGraphics *graphics, GpPen *pen, REAL x,
2386 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
2387{
Evan Stade4c424b32007-07-24 17:18:54 -07002388 INT save_state;
2389
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002390 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y,
2391 width, height, startAngle, sweepAngle);
2392
Evan Stade4c424b32007-07-24 17:18:54 -07002393 if(!graphics || !pen)
Evan Stade72ab72c502007-06-18 16:55:51 -07002394 return InvalidParameter;
2395
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002396 if(graphics->busy)
2397 return ObjectBusy;
2398
Evan Stade4c424b32007-07-24 17:18:54 -07002399 save_state = prepare_dc(graphics, pen);
2400 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
2401
2402 draw_pie(graphics, x, y, width, height, startAngle, sweepAngle);
2403
2404 restore_dc(graphics, save_state);
2405
2406 return Ok;
Evan Stade72ab72c502007-06-18 16:55:51 -07002407}
2408
Nikolay Sivov71931612008-04-24 20:48:00 +04002409GpStatus WINGDIPAPI GdipDrawPieI(GpGraphics *graphics, GpPen *pen, INT x,
2410 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
2411{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002412 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n", graphics, pen, x, y,
2413 width, height, startAngle, sweepAngle);
2414
Nikolay Sivov71931612008-04-24 20:48:00 +04002415 return GdipDrawPie(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle);
2416}
2417
Nikolay Sivov172389e2008-04-20 21:27:10 +04002418GpStatus WINGDIPAPI GdipDrawRectangle(GpGraphics *graphics, GpPen *pen, REAL x,
2419 REAL y, REAL width, REAL height)
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002420{
Evan Stade14e0df12007-07-09 20:54:18 -07002421 INT save_state;
Evan Stadec84c2042007-08-07 18:43:08 -07002422 GpPointF ptf[4];
2423 POINT pti[4];
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002424
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002425 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, pen, x, y, width, height);
2426
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002427 if(!pen || !graphics)
2428 return InvalidParameter;
2429
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002430 if(graphics->busy)
2431 return ObjectBusy;
2432
Evan Stadec84c2042007-08-07 18:43:08 -07002433 ptf[0].X = x;
2434 ptf[0].Y = y;
2435 ptf[1].X = x + width;
2436 ptf[1].Y = y;
2437 ptf[2].X = x + width;
2438 ptf[2].Y = y + height;
2439 ptf[3].X = x;
2440 ptf[3].Y = y + height;
2441
Evan Stade4c424b32007-07-24 17:18:54 -07002442 save_state = prepare_dc(graphics, pen);
Evan Stade14e0df12007-07-09 20:54:18 -07002443 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002444
Evan Stadec84c2042007-08-07 18:43:08 -07002445 transform_and_round_points(graphics, pti, ptf, 4);
2446 Polygon(graphics->hdc, pti, 4);
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002447
Evan Stade4c424b32007-07-24 17:18:54 -07002448 restore_dc(graphics, save_state);
Evan Stade4b9bfbe2007-06-12 10:51:20 -07002449
2450 return Ok;
2451}
Evan Stade72ab72c502007-06-18 16:55:51 -07002452
Nikolay Sivov172389e2008-04-20 21:27:10 +04002453GpStatus WINGDIPAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x,
2454 INT y, INT width, INT height)
2455{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002456 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, pen, x, y, width, height);
2457
Nikolay Sivov172389e2008-04-20 21:27:10 +04002458 return GdipDrawRectangle(graphics,pen,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
2459}
2460
Evan Stade9d6e0752007-08-13 18:34:46 -07002461GpStatus WINGDIPAPI GdipDrawRectangles(GpGraphics *graphics, GpPen *pen,
Francois Gougetb6b97b12007-08-29 21:42:01 +02002462 GDIPCONST GpRectF* rects, INT count)
Evan Stade9d6e0752007-08-13 18:34:46 -07002463{
2464 GpPointF *ptf;
2465 POINT *pti;
2466 INT save_state, i;
2467
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002468 TRACE("(%p, %p, %p, %d)\n", graphics, pen, rects, count);
2469
Evan Stade9d6e0752007-08-13 18:34:46 -07002470 if(!graphics || !pen || !rects || count < 1)
2471 return InvalidParameter;
2472
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002473 if(graphics->busy)
2474 return ObjectBusy;
2475
Evan Stade9d6e0752007-08-13 18:34:46 -07002476 ptf = GdipAlloc(4 * count * sizeof(GpPointF));
2477 pti = GdipAlloc(4 * count * sizeof(POINT));
2478
2479 if(!ptf || !pti){
2480 GdipFree(ptf);
2481 GdipFree(pti);
2482 return OutOfMemory;
2483 }
2484
2485 for(i = 0; i < count; i++){
2486 ptf[4 * i + 3].X = ptf[4 * i].X = rects[i].X;
2487 ptf[4 * i + 1].Y = ptf[4 * i].Y = rects[i].Y;
2488 ptf[4 * i + 2].X = ptf[4 * i + 1].X = rects[i].X + rects[i].Width;
2489 ptf[4 * i + 3].Y = ptf[4 * i + 2].Y = rects[i].Y + rects[i].Height;
2490 }
2491
2492 save_state = prepare_dc(graphics, pen);
2493 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
2494
2495 transform_and_round_points(graphics, pti, ptf, 4 * count);
2496
2497 for(i = 0; i < count; i++)
2498 Polygon(graphics->hdc, &pti[4 * i], 4);
2499
2500 restore_dc(graphics, save_state);
2501
2502 GdipFree(ptf);
2503 GdipFree(pti);
2504
2505 return Ok;
2506}
2507
Nikolay Sivov3903ac62008-04-24 20:48:08 +04002508GpStatus WINGDIPAPI GdipDrawRectanglesI(GpGraphics *graphics, GpPen *pen,
2509 GDIPCONST GpRect* rects, INT count)
2510{
2511 GpRectF *rectsF;
2512 GpStatus ret;
2513 INT i;
2514
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002515 TRACE("(%p, %p, %p, %d)\n", graphics, pen, rects, count);
2516
Nikolay Sivov3903ac62008-04-24 20:48:08 +04002517 if(!rects || count<=0)
2518 return InvalidParameter;
2519
2520 rectsF = GdipAlloc(sizeof(GpRectF) * count);
2521 if(!rectsF)
2522 return OutOfMemory;
2523
2524 for(i = 0;i < count;i++){
2525 rectsF[i].X = (REAL)rects[i].X;
2526 rectsF[i].Y = (REAL)rects[i].Y;
2527 rectsF[i].Width = (REAL)rects[i].Width;
2528 rectsF[i].Height = (REAL)rects[i].Height;
2529 }
2530
2531 ret = GdipDrawRectangles(graphics, pen, rectsF, count);
2532 GdipFree(rectsF);
2533
2534 return ret;
2535}
2536
Nikolay Sivov4a441002008-08-22 02:16:49 +04002537GpStatus WINGDIPAPI GdipFillClosedCurve2(GpGraphics *graphics, GpBrush *brush,
2538 GDIPCONST GpPointF *points, INT count, REAL tension, GpFillMode fill)
2539{
2540 GpPath *path;
2541 GpStatus stat;
2542
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002543 TRACE("(%p, %p, %p, %d, %.2f, %d)\n", graphics, brush, points,
2544 count, tension, fill);
2545
Nikolay Sivov4a441002008-08-22 02:16:49 +04002546 if(!graphics || !brush || !points)
2547 return InvalidParameter;
2548
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002549 if(graphics->busy)
2550 return ObjectBusy;
2551
Nikolay Sivov4a441002008-08-22 02:16:49 +04002552 stat = GdipCreatePath(fill, &path);
2553 if(stat != Ok)
2554 return stat;
2555
2556 stat = GdipAddPathClosedCurve2(path, points, count, tension);
2557 if(stat != Ok){
2558 GdipDeletePath(path);
2559 return stat;
2560 }
2561
2562 stat = GdipFillPath(graphics, brush, path);
2563 if(stat != Ok){
2564 GdipDeletePath(path);
2565 return stat;
2566 }
2567
2568 GdipDeletePath(path);
2569
2570 return Ok;
2571}
2572
2573GpStatus WINGDIPAPI GdipFillClosedCurve2I(GpGraphics *graphics, GpBrush *brush,
2574 GDIPCONST GpPoint *points, INT count, REAL tension, GpFillMode fill)
2575{
2576 GpPointF *ptf;
2577 GpStatus stat;
2578 INT i;
2579
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002580 TRACE("(%p, %p, %p, %d, %.2f, %d)\n", graphics, brush, points,
2581 count, tension, fill);
2582
Nikolay Sivov4a441002008-08-22 02:16:49 +04002583 if(!points || count <= 0)
2584 return InvalidParameter;
2585
2586 ptf = GdipAlloc(sizeof(GpPointF)*count);
2587 if(!ptf)
2588 return OutOfMemory;
2589
2590 for(i = 0;i < count;i++){
2591 ptf[i].X = (REAL)points[i].X;
2592 ptf[i].Y = (REAL)points[i].Y;
2593 }
2594
2595 stat = GdipFillClosedCurve2(graphics, brush, ptf, count, tension, fill);
2596
2597 GdipFree(ptf);
2598
2599 return stat;
2600}
2601
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002602GpStatus WINGDIPAPI GdipFillEllipse(GpGraphics *graphics, GpBrush *brush, REAL x,
2603 REAL y, REAL width, REAL height)
2604{
2605 INT save_state;
2606 GpPointF ptf[2];
2607 POINT pti[2];
2608
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002609 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height);
2610
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002611 if(!graphics || !brush)
2612 return InvalidParameter;
2613
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002614 if(graphics->busy)
2615 return ObjectBusy;
2616
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002617 ptf[0].X = x;
2618 ptf[0].Y = y;
2619 ptf[1].X = x + width;
2620 ptf[1].Y = y + height;
2621
2622 save_state = SaveDC(graphics->hdc);
2623 EndPath(graphics->hdc);
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002624
2625 transform_and_round_points(graphics, pti, ptf, 2);
2626
Vincent Povirke3063162009-07-11 10:29:44 -05002627 BeginPath(graphics->hdc);
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002628 Ellipse(graphics->hdc, pti[0].x, pti[0].y, pti[1].x, pti[1].y);
Vincent Povirke3063162009-07-11 10:29:44 -05002629 EndPath(graphics->hdc);
2630
2631 brush_fill_path(graphics, brush);
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002632
2633 RestoreDC(graphics->hdc, save_state);
2634
2635 return Ok;
2636}
2637
2638GpStatus WINGDIPAPI GdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x,
2639 INT y, INT width, INT height)
2640{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002641 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height);
2642
Nikolay Sivovfc2dc8b2008-04-29 00:10:10 +04002643 return GdipFillEllipse(graphics,brush,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
2644}
2645
Evan Staded362b582007-07-13 20:19:46 -07002646GpStatus WINGDIPAPI GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *path)
2647{
2648 INT save_state;
2649 GpStatus retval;
2650
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002651 TRACE("(%p, %p, %p)\n", graphics, brush, path);
2652
Evan Staded362b582007-07-13 20:19:46 -07002653 if(!brush || !graphics || !path)
2654 return InvalidParameter;
2655
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002656 if(graphics->busy)
2657 return ObjectBusy;
2658
Evan Staded362b582007-07-13 20:19:46 -07002659 save_state = SaveDC(graphics->hdc);
2660 EndPath(graphics->hdc);
Evan Staded362b582007-07-13 20:19:46 -07002661 SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE
2662 : WINDING));
2663
2664 BeginPath(graphics->hdc);
Evan Staded01c6972007-07-23 20:24:53 -07002665 retval = draw_poly(graphics, NULL, path->pathdata.Points,
Evan Staded362b582007-07-13 20:19:46 -07002666 path->pathdata.Types, path->pathdata.Count, FALSE);
2667
2668 if(retval != Ok)
2669 goto end;
2670
2671 EndPath(graphics->hdc);
Vincent Povirk68dba4e2009-03-16 12:51:04 -05002672 brush_fill_path(graphics, brush);
Evan Staded362b582007-07-13 20:19:46 -07002673
2674 retval = Ok;
2675
2676end:
2677 RestoreDC(graphics->hdc, save_state);
2678
2679 return retval;
2680}
2681
Evan Stade72ab72c502007-06-18 16:55:51 -07002682GpStatus WINGDIPAPI GdipFillPie(GpGraphics *graphics, GpBrush *brush, REAL x,
2683 REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle)
2684{
Evan Stade4c424b32007-07-24 17:18:54 -07002685 INT save_state;
2686
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002687 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
2688 graphics, brush, x, y, width, height, startAngle, sweepAngle);
2689
Evan Stade4c424b32007-07-24 17:18:54 -07002690 if(!graphics || !brush)
Evan Stade72ab72c502007-06-18 16:55:51 -07002691 return InvalidParameter;
2692
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002693 if(graphics->busy)
2694 return ObjectBusy;
2695
Evan Stade4c424b32007-07-24 17:18:54 -07002696 save_state = SaveDC(graphics->hdc);
2697 EndPath(graphics->hdc);
Evan Stade4c424b32007-07-24 17:18:54 -07002698
Vincent Povirkbedbd402009-07-11 10:32:34 -05002699 BeginPath(graphics->hdc);
Evan Stade4c424b32007-07-24 17:18:54 -07002700 draw_pie(graphics, x, y, width, height, startAngle, sweepAngle);
Vincent Povirkbedbd402009-07-11 10:32:34 -05002701 EndPath(graphics->hdc);
2702
2703 brush_fill_path(graphics, brush);
Evan Stade4c424b32007-07-24 17:18:54 -07002704
2705 RestoreDC(graphics->hdc, save_state);
2706
2707 return Ok;
Evan Stade72ab72c502007-06-18 16:55:51 -07002708}
Evan Stade53e17d22007-07-13 17:51:13 -07002709
Nikolay Sivov2c059d72008-04-24 20:48:23 +04002710GpStatus WINGDIPAPI GdipFillPieI(GpGraphics *graphics, GpBrush *brush, INT x,
2711 INT y, INT width, INT height, REAL startAngle, REAL sweepAngle)
2712{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002713 TRACE("(%p, %p, %d, %d, %d, %d, %.2f, %.2f)\n",
2714 graphics, brush, x, y, width, height, startAngle, sweepAngle);
2715
Nikolay Sivov2c059d72008-04-24 20:48:23 +04002716 return GdipFillPie(graphics,brush,(REAL)x,(REAL)y,(REAL)width,(REAL)height,startAngle,sweepAngle);
2717}
2718
Evan Stade1ef77932007-08-01 17:55:50 -07002719GpStatus WINGDIPAPI GdipFillPolygon(GpGraphics *graphics, GpBrush *brush,
2720 GDIPCONST GpPointF *points, INT count, GpFillMode fillMode)
2721{
2722 INT save_state;
2723 GpPointF *ptf = NULL;
2724 POINT *pti = NULL;
2725 GpStatus retval = Ok;
2726
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002727 TRACE("(%p, %p, %p, %d, %d)\n", graphics, brush, points, count, fillMode);
2728
Evan Stade1ef77932007-08-01 17:55:50 -07002729 if(!graphics || !brush || !points || !count)
2730 return InvalidParameter;
2731
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002732 if(graphics->busy)
2733 return ObjectBusy;
2734
Evan Stade1ef77932007-08-01 17:55:50 -07002735 ptf = GdipAlloc(count * sizeof(GpPointF));
2736 pti = GdipAlloc(count * sizeof(POINT));
2737 if(!ptf || !pti){
2738 retval = OutOfMemory;
2739 goto end;
2740 }
2741
2742 memcpy(ptf, points, count * sizeof(GpPointF));
2743
2744 save_state = SaveDC(graphics->hdc);
2745 EndPath(graphics->hdc);
Evan Stade1ef77932007-08-01 17:55:50 -07002746 SetPolyFillMode(graphics->hdc, (fillMode == FillModeAlternate ? ALTERNATE
2747 : WINDING));
2748
2749 transform_and_round_points(graphics, pti, ptf, count);
Vincent Povirk15fef072009-07-11 10:35:40 -05002750
2751 BeginPath(graphics->hdc);
Evan Stade1ef77932007-08-01 17:55:50 -07002752 Polygon(graphics->hdc, pti, count);
Vincent Povirk15fef072009-07-11 10:35:40 -05002753 EndPath(graphics->hdc);
2754
2755 brush_fill_path(graphics, brush);
Evan Stade1ef77932007-08-01 17:55:50 -07002756
2757 RestoreDC(graphics->hdc, save_state);
2758
2759end:
2760 GdipFree(ptf);
2761 GdipFree(pti);
2762
2763 return retval;
2764}
2765
Evan Stade64675262007-07-23 20:24:35 -07002766GpStatus WINGDIPAPI GdipFillPolygonI(GpGraphics *graphics, GpBrush *brush,
2767 GDIPCONST GpPoint *points, INT count, GpFillMode fillMode)
2768{
Evan Staded01c6972007-07-23 20:24:53 -07002769 INT save_state, i;
2770 GpPointF *ptf = NULL;
2771 POINT *pti = NULL;
2772 GpStatus retval = Ok;
Evan Stade64675262007-07-23 20:24:35 -07002773
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002774 TRACE("(%p, %p, %p, %d, %d)\n", graphics, brush, points, count, fillMode);
2775
Evan Stade64675262007-07-23 20:24:35 -07002776 if(!graphics || !brush || !points || !count)
2777 return InvalidParameter;
2778
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002779 if(graphics->busy)
2780 return ObjectBusy;
2781
Evan Staded01c6972007-07-23 20:24:53 -07002782 ptf = GdipAlloc(count * sizeof(GpPointF));
2783 pti = GdipAlloc(count * sizeof(POINT));
2784 if(!ptf || !pti){
2785 retval = OutOfMemory;
2786 goto end;
2787 }
2788
2789 for(i = 0; i < count; i ++){
2790 ptf[i].X = (REAL) points[i].X;
2791 ptf[i].Y = (REAL) points[i].Y;
2792 }
2793
Evan Stade64675262007-07-23 20:24:35 -07002794 save_state = SaveDC(graphics->hdc);
2795 EndPath(graphics->hdc);
Evan Stade64675262007-07-23 20:24:35 -07002796 SetPolyFillMode(graphics->hdc, (fillMode == FillModeAlternate ? ALTERNATE
2797 : WINDING));
Evan Staded01c6972007-07-23 20:24:53 -07002798
2799 transform_and_round_points(graphics, pti, ptf, count);
Vincent Povirk38fc8942009-07-11 10:37:22 -05002800
2801 BeginPath(graphics->hdc);
Evan Staded01c6972007-07-23 20:24:53 -07002802 Polygon(graphics->hdc, pti, count);
Vincent Povirk38fc8942009-07-11 10:37:22 -05002803 EndPath(graphics->hdc);
2804
2805 brush_fill_path(graphics, brush);
Evan Stade64675262007-07-23 20:24:35 -07002806
2807 RestoreDC(graphics->hdc, save_state);
Evan Staded01c6972007-07-23 20:24:53 -07002808
2809end:
2810 GdipFree(ptf);
2811 GdipFree(pti);
2812
2813 return retval;
Evan Stade64675262007-07-23 20:24:35 -07002814}
2815
Nikolay Sivove04a6622008-08-03 12:19:36 +04002816GpStatus WINGDIPAPI GdipFillPolygon2(GpGraphics *graphics, GpBrush *brush,
2817 GDIPCONST GpPointF *points, INT count)
2818{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002819 TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count);
2820
Nikolay Sivove04a6622008-08-03 12:19:36 +04002821 return GdipFillPolygon(graphics, brush, points, count, FillModeAlternate);
2822}
2823
2824GpStatus WINGDIPAPI GdipFillPolygon2I(GpGraphics *graphics, GpBrush *brush,
2825 GDIPCONST GpPoint *points, INT count)
2826{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002827 TRACE("(%p, %p, %p, %d)\n", graphics, brush, points, count);
2828
Nikolay Sivove04a6622008-08-03 12:19:36 +04002829 return GdipFillPolygonI(graphics, brush, points, count, FillModeAlternate);
2830}
2831
Evan Stadeb66c0a02007-08-08 19:42:10 -07002832GpStatus WINGDIPAPI GdipFillRectangle(GpGraphics *graphics, GpBrush *brush,
2833 REAL x, REAL y, REAL width, REAL height)
2834{
2835 INT save_state;
2836 GpPointF ptf[4];
2837 POINT pti[4];
2838
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002839 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f)\n", graphics, brush, x, y, width, height);
2840
Evan Stadeb66c0a02007-08-08 19:42:10 -07002841 if(!graphics || !brush)
2842 return InvalidParameter;
2843
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002844 if(graphics->busy)
2845 return ObjectBusy;
2846
Evan Stadeb66c0a02007-08-08 19:42:10 -07002847 ptf[0].X = x;
2848 ptf[0].Y = y;
2849 ptf[1].X = x + width;
2850 ptf[1].Y = y;
2851 ptf[2].X = x + width;
2852 ptf[2].Y = y + height;
2853 ptf[3].X = x;
2854 ptf[3].Y = y + height;
2855
2856 save_state = SaveDC(graphics->hdc);
2857 EndPath(graphics->hdc);
Evan Stadeb66c0a02007-08-08 19:42:10 -07002858
2859 transform_and_round_points(graphics, pti, ptf, 4);
2860
Vincent Povirk323e7e682009-05-06 16:34:19 -05002861 BeginPath(graphics->hdc);
Evan Stadeb66c0a02007-08-08 19:42:10 -07002862 Polygon(graphics->hdc, pti, 4);
Vincent Povirk323e7e682009-05-06 16:34:19 -05002863 EndPath(graphics->hdc);
2864
2865 brush_fill_path(graphics, brush);
Evan Stadeb66c0a02007-08-08 19:42:10 -07002866
2867 RestoreDC(graphics->hdc, save_state);
2868
2869 return Ok;
2870}
2871
Evan Stadebb904a22007-08-07 18:43:04 -07002872GpStatus WINGDIPAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush,
2873 INT x, INT y, INT width, INT height)
2874{
2875 INT save_state;
2876 GpPointF ptf[4];
2877 POINT pti[4];
2878
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002879 TRACE("(%p, %p, %d, %d, %d, %d)\n", graphics, brush, x, y, width, height);
2880
Evan Stadebb904a22007-08-07 18:43:04 -07002881 if(!graphics || !brush)
2882 return InvalidParameter;
2883
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002884 if(graphics->busy)
2885 return ObjectBusy;
2886
Evan Stadebb904a22007-08-07 18:43:04 -07002887 ptf[0].X = x;
2888 ptf[0].Y = y;
2889 ptf[1].X = x + width;
2890 ptf[1].Y = y;
2891 ptf[2].X = x + width;
2892 ptf[2].Y = y + height;
2893 ptf[3].X = x;
2894 ptf[3].Y = y + height;
2895
2896 save_state = SaveDC(graphics->hdc);
2897 EndPath(graphics->hdc);
Evan Stadebb904a22007-08-07 18:43:04 -07002898
2899 transform_and_round_points(graphics, pti, ptf, 4);
2900
Vincent Povirk849af302009-07-11 10:38:47 -05002901 BeginPath(graphics->hdc);
Evan Stadebb904a22007-08-07 18:43:04 -07002902 Polygon(graphics->hdc, pti, 4);
Vincent Povirk849af302009-07-11 10:38:47 -05002903 EndPath(graphics->hdc);
2904
2905 brush_fill_path(graphics, brush);
Evan Stadebb904a22007-08-07 18:43:04 -07002906
2907 RestoreDC(graphics->hdc, save_state);
2908
2909 return Ok;
2910}
2911
Nikolay Sivov7ce48b02008-04-29 00:10:15 +04002912GpStatus WINGDIPAPI GdipFillRectangles(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRectF *rects,
2913 INT count)
2914{
2915 GpStatus ret;
2916 INT i;
2917
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002918 TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count);
2919
Nikolay Sivov7ce48b02008-04-29 00:10:15 +04002920 if(!rects)
2921 return InvalidParameter;
2922
2923 for(i = 0; i < count; i++){
2924 ret = GdipFillRectangle(graphics, brush, rects[i].X, rects[i].Y, rects[i].Width, rects[i].Height);
2925 if(ret != Ok) return ret;
2926 }
2927
2928 return Ok;
2929}
2930
2931GpStatus WINGDIPAPI GdipFillRectanglesI(GpGraphics *graphics, GpBrush *brush, GDIPCONST GpRect *rects,
2932 INT count)
2933{
2934 GpRectF *rectsF;
2935 GpStatus ret;
2936 INT i;
2937
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04002938 TRACE("(%p, %p, %p, %d)\n", graphics, brush, rects, count);
2939
Nikolay Sivov7ce48b02008-04-29 00:10:15 +04002940 if(!rects || count <= 0)
2941 return InvalidParameter;
2942
2943 rectsF = GdipAlloc(sizeof(GpRectF)*count);
2944 if(!rectsF)
2945 return OutOfMemory;
2946
2947 for(i = 0; i < count; i++){
2948 rectsF[i].X = (REAL)rects[i].X;
2949 rectsF[i].Y = (REAL)rects[i].Y;
2950 rectsF[i].X = (REAL)rects[i].Width;
2951 rectsF[i].Height = (REAL)rects[i].Height;
2952 }
2953
2954 ret = GdipFillRectangles(graphics,brush,rectsF,count);
2955 GdipFree(rectsF);
2956
2957 return ret;
2958}
2959
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002960/*****************************************************************************
2961 * GdipFillRegion [GDIPLUS.@]
2962 */
Nikolay Sivov0e840f62008-07-10 23:15:59 +04002963GpStatus WINGDIPAPI GdipFillRegion(GpGraphics* graphics, GpBrush* brush,
2964 GpRegion* region)
2965{
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002966 INT save_state;
2967 GpStatus status;
2968 HRGN hrgn;
Vincent Povirk6a8a7702009-07-11 10:57:07 -05002969 RECT rc;
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002970
2971 TRACE("(%p, %p, %p)\n", graphics, brush, region);
2972
Nikolay Sivov0e840f62008-07-10 23:15:59 +04002973 if (!(graphics && brush && region))
2974 return InvalidParameter;
2975
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04002976 if(graphics->busy)
2977 return ObjectBusy;
2978
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002979 status = GdipGetRegionHRgn(region, graphics, &hrgn);
2980 if(status != Ok)
2981 return status;
Nikolay Sivov0e840f62008-07-10 23:15:59 +04002982
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002983 save_state = SaveDC(graphics->hdc);
2984 EndPath(graphics->hdc);
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002985
Vincent Povirk6a8a7702009-07-11 10:57:07 -05002986 ExtSelectClipRgn(graphics->hdc, hrgn, RGN_AND);
2987
2988 if (GetClipBox(graphics->hdc, &rc) != NULLREGION)
2989 {
2990 BeginPath(graphics->hdc);
2991 Rectangle(graphics->hdc, rc.left, rc.top, rc.right, rc.bottom);
2992 EndPath(graphics->hdc);
2993
2994 brush_fill_path(graphics, brush);
2995 }
Nikolay Sivov9f0edc52009-02-03 22:17:47 +03002996
2997 RestoreDC(graphics->hdc, save_state);
2998
2999 DeleteObject(hrgn);
3000
3001 return Ok;
Nikolay Sivov0e840f62008-07-10 23:15:59 +04003002}
3003
Nikolay Sivovf620b662008-06-18 11:33:10 +04003004GpStatus WINGDIPAPI GdipFlush(GpGraphics *graphics, GpFlushIntention intention)
3005{
Vincent Povirk2005fe92009-12-18 16:04:20 -06003006 TRACE("(%p,%u)\n", graphics, intention);
3007
Nikolay Sivovf620b662008-06-18 11:33:10 +04003008 if(!graphics)
3009 return InvalidParameter;
3010
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003011 if(graphics->busy)
3012 return ObjectBusy;
3013
Vincent Povirkade25062010-04-02 09:19:13 -05003014 /* We have no internal operation queue, so there's no need to clear it. */
Nikolay Sivovf620b662008-06-18 11:33:10 +04003015
Vincent Povirkade25062010-04-02 09:19:13 -05003016 if (graphics->hdc)
3017 GdiFlush();
3018
3019 return Ok;
Nikolay Sivovf620b662008-06-18 11:33:10 +04003020}
3021
Nikolay Sivovbcfe4e72009-02-02 22:58:27 +03003022/*****************************************************************************
3023 * GdipGetClipBounds [GDIPLUS.@]
3024 */
3025GpStatus WINGDIPAPI GdipGetClipBounds(GpGraphics *graphics, GpRectF *rect)
3026{
3027 TRACE("(%p, %p)\n", graphics, rect);
3028
3029 if(!graphics)
3030 return InvalidParameter;
3031
Nikolay Sivov8c096162009-02-02 23:48:01 +03003032 if(graphics->busy)
3033 return ObjectBusy;
3034
Nikolay Sivovbcfe4e72009-02-02 22:58:27 +03003035 return GdipGetRegionBounds(graphics->clip, graphics, rect);
3036}
3037
3038/*****************************************************************************
3039 * GdipGetClipBoundsI [GDIPLUS.@]
3040 */
3041GpStatus WINGDIPAPI GdipGetClipBoundsI(GpGraphics *graphics, GpRect *rect)
3042{
3043 TRACE("(%p, %p)\n", graphics, rect);
3044
3045 if(!graphics)
3046 return InvalidParameter;
3047
Nikolay Sivov8c096162009-02-02 23:48:01 +03003048 if(graphics->busy)
3049 return ObjectBusy;
3050
Nikolay Sivovbcfe4e72009-02-02 22:58:27 +03003051 return GdipGetRegionBoundsI(graphics->clip, graphics, rect);
3052}
3053
Evan Stadee807eb92007-08-13 18:34:27 -07003054/* FIXME: Compositing mode is not used anywhere except the getter/setter. */
3055GpStatus WINGDIPAPI GdipGetCompositingMode(GpGraphics *graphics,
3056 CompositingMode *mode)
3057{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003058 TRACE("(%p, %p)\n", graphics, mode);
3059
Evan Stadee807eb92007-08-13 18:34:27 -07003060 if(!graphics || !mode)
3061 return InvalidParameter;
3062
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003063 if(graphics->busy)
3064 return ObjectBusy;
3065
Evan Stadee807eb92007-08-13 18:34:27 -07003066 *mode = graphics->compmode;
3067
3068 return Ok;
3069}
3070
Evan Stade60cad232007-07-13 17:51:25 -07003071/* FIXME: Compositing quality is not used anywhere except the getter/setter. */
3072GpStatus WINGDIPAPI GdipGetCompositingQuality(GpGraphics *graphics,
3073 CompositingQuality *quality)
3074{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003075 TRACE("(%p, %p)\n", graphics, quality);
3076
Evan Stade60cad232007-07-13 17:51:25 -07003077 if(!graphics || !quality)
3078 return InvalidParameter;
3079
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003080 if(graphics->busy)
3081 return ObjectBusy;
3082
Evan Stade60cad232007-07-13 17:51:25 -07003083 *quality = graphics->compqual;
3084
3085 return Ok;
3086}
3087
Evan Stadea87ce7a2007-07-13 17:51:29 -07003088/* FIXME: Interpolation mode is not used anywhere except the getter/setter. */
3089GpStatus WINGDIPAPI GdipGetInterpolationMode(GpGraphics *graphics,
3090 InterpolationMode *mode)
3091{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003092 TRACE("(%p, %p)\n", graphics, mode);
3093
Evan Stadea87ce7a2007-07-13 17:51:29 -07003094 if(!graphics || !mode)
3095 return InvalidParameter;
3096
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003097 if(graphics->busy)
3098 return ObjectBusy;
3099
Evan Stadea87ce7a2007-07-13 17:51:29 -07003100 *mode = graphics->interpolation;
3101
3102 return Ok;
3103}
3104
Justin Chevrierb4bfa6e2010-02-25 21:45:55 -05003105/* FIXME: Need to handle color depths less than 24bpp */
Nikolay Sivov63ae7142008-12-11 10:32:43 +03003106GpStatus WINGDIPAPI GdipGetNearestColor(GpGraphics *graphics, ARGB* argb)
3107{
Justin Chevrierb4bfa6e2010-02-25 21:45:55 -05003108 FIXME("(%p, %p): Passing color unmodified\n", graphics, argb);
Vincent Povirk2005fe92009-12-18 16:04:20 -06003109
Nikolay Sivov63ae7142008-12-11 10:32:43 +03003110 if(!graphics || !argb)
3111 return InvalidParameter;
3112
3113 if(graphics->busy)
3114 return ObjectBusy;
3115
Justin Chevrierb4bfa6e2010-02-25 21:45:55 -05003116 return Ok;
Nikolay Sivov63ae7142008-12-11 10:32:43 +03003117}
3118
Evan Stade81621392007-07-24 17:18:39 -07003119GpStatus WINGDIPAPI GdipGetPageScale(GpGraphics *graphics, REAL *scale)
3120{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003121 TRACE("(%p, %p)\n", graphics, scale);
3122
Evan Stade81621392007-07-24 17:18:39 -07003123 if(!graphics || !scale)
3124 return InvalidParameter;
3125
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003126 if(graphics->busy)
3127 return ObjectBusy;
3128
Evan Stade81621392007-07-24 17:18:39 -07003129 *scale = graphics->scale;
3130
3131 return Ok;
3132}
3133
Evan Stade10b575b2007-07-23 20:24:41 -07003134GpStatus WINGDIPAPI GdipGetPageUnit(GpGraphics *graphics, GpUnit *unit)
3135{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003136 TRACE("(%p, %p)\n", graphics, unit);
3137
Evan Stade10b575b2007-07-23 20:24:41 -07003138 if(!graphics || !unit)
3139 return InvalidParameter;
3140
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003141 if(graphics->busy)
3142 return ObjectBusy;
3143
Evan Stade10b575b2007-07-23 20:24:41 -07003144 *unit = graphics->unit;
3145
3146 return Ok;
3147}
3148
Evan Staded6bd866d2007-07-13 17:51:33 -07003149/* FIXME: Pixel offset mode is not used anywhere except the getter/setter. */
3150GpStatus WINGDIPAPI GdipGetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
3151 *mode)
3152{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003153 TRACE("(%p, %p)\n", graphics, mode);
3154
Evan Staded6bd866d2007-07-13 17:51:33 -07003155 if(!graphics || !mode)
3156 return InvalidParameter;
3157
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003158 if(graphics->busy)
3159 return ObjectBusy;
3160
Evan Staded6bd866d2007-07-13 17:51:33 -07003161 *mode = graphics->pixeloffset;
3162
3163 return Ok;
3164}
3165
Evan Stade53e17d22007-07-13 17:51:13 -07003166/* FIXME: Smoothing mode is not used anywhere except the getter/setter. */
3167GpStatus WINGDIPAPI GdipGetSmoothingMode(GpGraphics *graphics, SmoothingMode *mode)
3168{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003169 TRACE("(%p, %p)\n", graphics, mode);
3170
Evan Stade53e17d22007-07-13 17:51:13 -07003171 if(!graphics || !mode)
3172 return InvalidParameter;
3173
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003174 if(graphics->busy)
3175 return ObjectBusy;
3176
Evan Stade53e17d22007-07-13 17:51:13 -07003177 *mode = graphics->smoothing;
3178
3179 return Ok;
3180}
3181
Nikolay Sivov56173d42008-11-09 14:32:26 +03003182GpStatus WINGDIPAPI GdipGetTextContrast(GpGraphics *graphics, UINT *contrast)
3183{
3184 TRACE("(%p, %p)\n", graphics, contrast);
3185
3186 if(!graphics || !contrast)
3187 return InvalidParameter;
3188
3189 *contrast = graphics->textcontrast;
3190
3191 return Ok;
3192}
3193
Evan Stade56628202007-08-14 19:00:09 -07003194/* FIXME: Text rendering hint is not used anywhere except the getter/setter. */
3195GpStatus WINGDIPAPI GdipGetTextRenderingHint(GpGraphics *graphics,
3196 TextRenderingHint *hint)
3197{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003198 TRACE("(%p, %p)\n", graphics, hint);
3199
Evan Stade56628202007-08-14 19:00:09 -07003200 if(!graphics || !hint)
3201 return InvalidParameter;
3202
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003203 if(graphics->busy)
3204 return ObjectBusy;
3205
Evan Stade56628202007-08-14 19:00:09 -07003206 *hint = graphics->texthint;
3207
3208 return Ok;
3209}
3210
Andrew Eikumef0ee6e2009-08-12 15:37:09 -05003211GpStatus WINGDIPAPI GdipGetVisibleClipBounds(GpGraphics *graphics, GpRectF *rect)
3212{
3213 GpRegion *clip_rgn;
3214 GpStatus stat;
Andrew Eikumef0ee6e2009-08-12 15:37:09 -05003215
3216 TRACE("(%p, %p)\n", graphics, rect);
3217
3218 if(!graphics || !rect)
3219 return InvalidParameter;
3220
3221 if(graphics->busy)
3222 return ObjectBusy;
3223
Andrew Eikumef0ee6e2009-08-12 15:37:09 -05003224 /* intersect window and graphics clipping regions */
3225 if((stat = GdipCreateRegion(&clip_rgn)) != Ok)
3226 return stat;
3227
Andrew Eikum39f6f492009-08-26 18:03:08 -05003228 if((stat = get_visible_clip_region(graphics, clip_rgn)) != Ok)
Andrew Eikumef0ee6e2009-08-12 15:37:09 -05003229 goto cleanup;
3230
3231 /* get bounds of the region */
3232 stat = GdipGetRegionBounds(clip_rgn, graphics, rect);
3233
3234cleanup:
3235 GdipDeleteRegion(clip_rgn);
3236
3237 return stat;
3238}
3239
3240GpStatus WINGDIPAPI GdipGetVisibleClipBoundsI(GpGraphics *graphics, GpRect *rect)
3241{
3242 GpRectF rectf;
3243 GpStatus stat;
3244
3245 TRACE("(%p, %p)\n", graphics, rect);
3246
3247 if(!graphics || !rect)
3248 return InvalidParameter;
3249
3250 if((stat = GdipGetVisibleClipBounds(graphics, &rectf)) == Ok)
3251 {
3252 rect->X = roundr(rectf.X);
3253 rect->Y = roundr(rectf.Y);
3254 rect->Width = roundr(rectf.Width);
3255 rect->Height = roundr(rectf.Height);
3256 }
3257
3258 return stat;
3259}
3260
Evan Stadef30732f2007-07-24 17:18:47 -07003261GpStatus WINGDIPAPI GdipGetWorldTransform(GpGraphics *graphics, GpMatrix *matrix)
3262{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003263 TRACE("(%p, %p)\n", graphics, matrix);
3264
Evan Stadef30732f2007-07-24 17:18:47 -07003265 if(!graphics || !matrix)
3266 return InvalidParameter;
3267
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003268 if(graphics->busy)
3269 return ObjectBusy;
3270
Andrew Talbot5e8253a2008-02-29 22:06:47 +00003271 *matrix = *graphics->worldtrans;
Evan Stadef30732f2007-07-24 17:18:47 -07003272 return Ok;
3273}
3274
Nikolay Sivovbff16782008-09-05 13:56:10 +04003275GpStatus WINGDIPAPI GdipGraphicsClear(GpGraphics *graphics, ARGB color)
3276{
3277 GpSolidFill *brush;
3278 GpStatus stat;
Andrew Eikumfdf48f12009-08-12 15:36:54 -05003279 GpRectF wnd_rect;
Nikolay Sivovbff16782008-09-05 13:56:10 +04003280
3281 TRACE("(%p, %x)\n", graphics, color);
3282
3283 if(!graphics)
3284 return InvalidParameter;
3285
3286 if(graphics->busy)
3287 return ObjectBusy;
3288
3289 if((stat = GdipCreateSolidFill(color, &brush)) != Ok)
3290 return stat;
3291
Andrew Eikumfdf48f12009-08-12 15:36:54 -05003292 if((stat = get_graphics_bounds(graphics, &wnd_rect)) != Ok){
3293 GdipDeleteBrush((GpBrush*)brush);
3294 return stat;
Nikolay Sivovbff16782008-09-05 13:56:10 +04003295 }
Andrew Eikumfdf48f12009-08-12 15:36:54 -05003296
3297 GdipFillRectangle(graphics, (GpBrush*)brush, wnd_rect.X, wnd_rect.Y,
3298 wnd_rect.Width, wnd_rect.Height);
Nikolay Sivovbff16782008-09-05 13:56:10 +04003299
3300 GdipDeleteBrush((GpBrush*)brush);
3301
3302 return Ok;
3303}
3304
Nikolay Sivov813d6dc2008-08-28 17:49:41 +04003305GpStatus WINGDIPAPI GdipIsClipEmpty(GpGraphics *graphics, BOOL *res)
3306{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003307 TRACE("(%p, %p)\n", graphics, res);
3308
Nikolay Sivov813d6dc2008-08-28 17:49:41 +04003309 if(!graphics || !res)
3310 return InvalidParameter;
3311
3312 return GdipIsEmptyRegion(graphics->clip, graphics, res);
3313}
3314
Nikolay Sivov3ecb8bd2008-09-26 22:34:39 +04003315GpStatus WINGDIPAPI GdipIsVisiblePoint(GpGraphics *graphics, REAL x, REAL y, BOOL *result)
3316{
Andrew Eikumd06dd2d2009-08-26 18:03:11 -05003317 GpStatus stat;
3318 GpRegion* rgn;
3319 GpPointF pt;
3320
3321 TRACE("(%p, %.2f, %.2f, %p)\n", graphics, x, y, result);
Nikolay Sivov3ecb8bd2008-09-26 22:34:39 +04003322
3323 if(!graphics || !result)
3324 return InvalidParameter;
3325
3326 if(graphics->busy)
3327 return ObjectBusy;
3328
Andrew Eikumd06dd2d2009-08-26 18:03:11 -05003329 pt.X = x;
3330 pt.Y = y;
3331 if((stat = GdipTransformPoints(graphics, CoordinateSpaceDevice,
3332 CoordinateSpaceWorld, &pt, 1)) != Ok)
3333 return stat;
3334
3335 if((stat = GdipCreateRegion(&rgn)) != Ok)
3336 return stat;
3337
3338 if((stat = get_visible_clip_region(graphics, rgn)) != Ok)
3339 goto cleanup;
3340
3341 stat = GdipIsVisibleRegionPoint(rgn, pt.X, pt.Y, graphics, result);
3342
3343cleanup:
3344 GdipDeleteRegion(rgn);
3345 return stat;
Nikolay Sivov3ecb8bd2008-09-26 22:34:39 +04003346}
3347
3348GpStatus WINGDIPAPI GdipIsVisiblePointI(GpGraphics *graphics, INT x, INT y, BOOL *result)
3349{
Andrew Eikumd06dd2d2009-08-26 18:03:11 -05003350 return GdipIsVisiblePoint(graphics, (REAL)x, (REAL)y, result);
Nikolay Sivov3ecb8bd2008-09-26 22:34:39 +04003351}
3352
Andrew Eikumf5896a22009-08-26 18:03:13 -05003353GpStatus WINGDIPAPI GdipIsVisibleRect(GpGraphics *graphics, REAL x, REAL y, REAL width, REAL height, BOOL *result)
3354{
3355 GpStatus stat;
3356 GpRegion* rgn;
3357 GpPointF pts[2];
3358
3359 TRACE("(%p %.2f %.2f %.2f %.2f %p)\n", graphics, x, y, width, height, result);
3360
3361 if(!graphics || !result)
3362 return InvalidParameter;
3363
3364 if(graphics->busy)
3365 return ObjectBusy;
3366
3367 pts[0].X = x;
3368 pts[0].Y = y;
3369 pts[1].X = x + width;
3370 pts[1].Y = y + height;
3371
3372 if((stat = GdipTransformPoints(graphics, CoordinateSpaceDevice,
3373 CoordinateSpaceWorld, pts, 2)) != Ok)
3374 return stat;
3375
3376 pts[1].X -= pts[0].X;
3377 pts[1].Y -= pts[0].Y;
3378
3379 if((stat = GdipCreateRegion(&rgn)) != Ok)
3380 return stat;
3381
3382 if((stat = get_visible_clip_region(graphics, rgn)) != Ok)
3383 goto cleanup;
3384
3385 stat = GdipIsVisibleRegionRect(rgn, pts[0].X, pts[0].Y, pts[1].X, pts[1].Y, graphics, result);
3386
3387cleanup:
3388 GdipDeleteRegion(rgn);
3389 return stat;
3390}
3391
3392GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics *graphics, INT x, INT y, INT width, INT height, BOOL *result)
3393{
3394 return GdipIsVisibleRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, result);
3395}
3396
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003397typedef GpStatus (*gdip_format_string_callback)(GpGraphics *graphics,
3398 GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
3399 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
3400 INT lineno, const RectF *bounds, void *user_data);
Adam Petacciabe4a2262008-07-09 03:33:40 -04003401
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003402static GpStatus gdip_format_string(GpGraphics *graphics,
Evan Stadea51cf1d2007-08-15 16:21:52 -07003403 GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font,
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003404 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
3405 gdip_format_string_callback callback, void *user_data)
Evan Stadea51cf1d2007-08-15 16:21:52 -07003406{
Evan Stadea51cf1d2007-08-15 16:21:52 -07003407 WCHAR* stringdup;
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003408 INT sum = 0, height = 0, fit, fitcpy, i, j, lret, nwidth,
3409 nheight, lineend, lineno = 0;
3410 RectF bounds;
3411 StringAlignment halign;
3412 GpStatus stat = Ok;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003413 SIZE size;
3414
Evan Stadea51cf1d2007-08-15 16:21:52 -07003415 if(length == -1) length = lstrlenW(string);
3416
Alexandre Julliarda2d04672008-09-25 11:19:23 +02003417 stringdup = GdipAlloc((length + 1) * sizeof(WCHAR));
Evan Stadea51cf1d2007-08-15 16:21:52 -07003418 if(!stringdup) return OutOfMemory;
3419
Evan Stadea51cf1d2007-08-15 16:21:52 -07003420 nwidth = roundr(rect->Width);
Evan Stade44e98392007-08-15 16:22:09 -07003421 nheight = roundr(rect->Height);
3422
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003423 if (nwidth == 0) nwidth = INT_MAX;
3424 if (nheight == 0) nheight = INT_MAX;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003425
3426 for(i = 0, j = 0; i < length; i++){
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003427 /* FIXME: This makes the indexes passed to callback inaccurate. */
Evan Stadea51cf1d2007-08-15 16:21:52 -07003428 if(!isprintW(string[i]) && (string[i] != '\n'))
3429 continue;
3430
3431 stringdup[j] = string[i];
3432 j++;
3433 }
3434
Evan Stadea51cf1d2007-08-15 16:21:52 -07003435 length = j;
3436
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003437 if (format) halign = format->align;
3438 else halign = StringAlignmentNear;
3439
Evan Stadea51cf1d2007-08-15 16:21:52 -07003440 while(sum < length){
3441 GetTextExtentExPointW(graphics->hdc, stringdup + sum, length - sum,
3442 nwidth, &fit, NULL, &size);
3443 fitcpy = fit;
3444
3445 if(fit == 0)
3446 break;
3447
3448 for(lret = 0; lret < fit; lret++)
3449 if(*(stringdup + sum + lret) == '\n')
3450 break;
3451
3452 /* Line break code (may look strange, but it imitates windows). */
3453 if(lret < fit)
Vincent Povirke0d9d172009-07-24 16:24:19 -05003454 lineend = fit = lret; /* this is not an off-by-one error */
Evan Stadea51cf1d2007-08-15 16:21:52 -07003455 else if(fit < (length - sum)){
3456 if(*(stringdup + sum + fit) == ' ')
3457 while(*(stringdup + sum + fit) == ' ')
3458 fit++;
3459 else
3460 while(*(stringdup + sum + fit - 1) != ' '){
3461 fit--;
3462
3463 if(*(stringdup + sum + fit) == '\t')
3464 break;
3465
3466 if(fit == 0){
3467 fit = fitcpy;
3468 break;
3469 }
3470 }
Vincent Povirke0d9d172009-07-24 16:24:19 -05003471 lineend = fit;
3472 while(*(stringdup + sum + lineend - 1) == ' ' ||
3473 *(stringdup + sum + lineend - 1) == '\t')
3474 lineend--;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003475 }
Vincent Povirke0d9d172009-07-24 16:24:19 -05003476 else
3477 lineend = fit;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003478
Vincent Povirke0d9d172009-07-24 16:24:19 -05003479 GetTextExtentExPointW(graphics->hdc, stringdup + sum, lineend,
Evan Stadea51cf1d2007-08-15 16:21:52 -07003480 nwidth, &j, NULL, &size);
3481
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003482 bounds.Width = size.cx;
Hans Leidekker1e170c92008-11-24 10:22:26 +01003483
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003484 if(height + size.cy > nheight)
3485 bounds.Height = nheight - (height + size.cy);
3486 else
3487 bounds.Height = size.cy;
3488
3489 bounds.Y = rect->Y + height;
3490
3491 switch (halign)
3492 {
3493 case StringAlignmentNear:
3494 default:
3495 bounds.X = rect->X;
3496 break;
3497 case StringAlignmentCenter:
3498 bounds.X = rect->X + (rect->Width/2) - (bounds.Width/2);
3499 break;
3500 case StringAlignmentFar:
3501 bounds.X = rect->X + rect->Width - bounds.Width;
3502 break;
3503 }
3504
3505 stat = callback(graphics, stringdup, sum, lineend,
3506 font, rect, format, lineno, &bounds, user_data);
3507
3508 if (stat != Ok)
3509 break;
3510
3511 sum += fit + (lret < fitcpy ? 1 : 0);
Evan Stadea51cf1d2007-08-15 16:21:52 -07003512 height += size.cy;
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003513 lineno++;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003514
Evan Stade44e98392007-08-15 16:22:09 -07003515 if(height > nheight)
Evan Stadea51cf1d2007-08-15 16:21:52 -07003516 break;
Evan Staded4107db2007-08-15 16:22:04 -07003517
3518 /* Stop if this was a linewrap (but not if it was a linebreak). */
3519 if((lret == fitcpy) && format && (format->attr & StringFormatFlagsNoWrap))
3520 break;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003521 }
3522
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003523 GdipFree(stringdup);
3524
3525 return stat;
3526}
3527
Vincent Povirkdeb64662010-03-30 15:51:44 -05003528struct measure_ranges_args {
3529 GpRegion **regions;
3530};
3531
3532GpStatus measure_ranges_callback(GpGraphics *graphics,
3533 GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
3534 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
3535 INT lineno, const RectF *bounds, void *user_data)
3536{
3537 int i;
3538 GpStatus stat = Ok;
3539 struct measure_ranges_args *args = user_data;
3540
3541 for (i=0; i<format->range_count; i++)
3542 {
3543 INT range_start = max(index, format->character_ranges[i].First);
3544 INT range_end = min(index+length, format->character_ranges[i].First+format->character_ranges[i].Length);
3545 if (range_start < range_end)
3546 {
3547 GpRectF range_rect;
3548 SIZE range_size;
3549
3550 range_rect.Y = bounds->Y;
3551 range_rect.Height = bounds->Height;
3552
3553 GetTextExtentExPointW(graphics->hdc, string + index, range_start - index,
3554 INT_MAX, NULL, NULL, &range_size);
3555 range_rect.X = bounds->X + range_size.cx;
3556
3557 GetTextExtentExPointW(graphics->hdc, string + index, range_end - index,
3558 INT_MAX, NULL, NULL, &range_size);
3559 range_rect.Width = (bounds->X + range_size.cx) - range_rect.X;
3560
3561 stat = GdipCombineRegionRect(args->regions[i], &range_rect, CombineModeUnion);
3562 if (stat != Ok)
3563 break;
3564 }
3565 }
3566
3567 return stat;
3568}
3569
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003570GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics* graphics,
3571 GDIPCONST WCHAR* string, INT length, GDIPCONST GpFont* font,
3572 GDIPCONST RectF* layoutRect, GDIPCONST GpStringFormat *stringFormat,
3573 INT regionCount, GpRegion** regions)
3574{
Vincent Povirkdeb64662010-03-30 15:51:44 -05003575 GpStatus stat;
3576 int i;
3577 HFONT oldfont;
3578 struct measure_ranges_args args;
3579
3580 TRACE("(%p %s %d %p %s %p %d %p)\n", graphics, debugstr_w(string),
3581 length, font, debugstr_rectf(layoutRect), stringFormat, regionCount, regions);
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003582
3583 if (!(graphics && string && font && layoutRect && stringFormat && regions))
3584 return InvalidParameter;
3585
Vincent Povirkdeb64662010-03-30 15:51:44 -05003586 if (regionCount < stringFormat->range_count)
3587 return InvalidParameter;
3588
3589 if (stringFormat->attr)
3590 TRACE("may be ignoring some format flags: attr %x\n", stringFormat->attr);
3591
3592 oldfont = SelectObject(graphics->hdc, CreateFontIndirectW(&font->lfw));
3593
3594 for (i=0; i<stringFormat->range_count; i++)
3595 {
3596 stat = GdipSetEmpty(regions[i]);
3597 if (stat != Ok)
3598 return stat;
3599 }
3600
3601 args.regions = regions;
3602
3603 stat = gdip_format_string(graphics, string, length, font, layoutRect, stringFormat,
3604 measure_ranges_callback, &args);
3605
3606 DeleteObject(SelectObject(graphics->hdc, oldfont));
3607
3608 return stat;
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003609}
3610
3611struct measure_string_args {
3612 RectF *bounds;
3613 INT *codepointsfitted;
3614 INT *linesfilled;
3615};
3616
3617static GpStatus measure_string_callback(GpGraphics *graphics,
3618 GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
3619 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
3620 INT lineno, const RectF *bounds, void *user_data)
3621{
3622 struct measure_string_args *args = user_data;
3623
3624 if (bounds->Width > args->bounds->Width)
3625 args->bounds->Width = bounds->Width;
3626
3627 if (bounds->Height + bounds->Y > args->bounds->Height + args->bounds->Y)
3628 args->bounds->Height = bounds->Height + bounds->Y - args->bounds->Y;
3629
3630 if (args->codepointsfitted)
3631 *args->codepointsfitted = index + length;
3632
3633 if (args->linesfilled)
Vincent Povirk21109a42010-03-30 14:22:06 -05003634 (*args->linesfilled)++;
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003635
3636 return Ok;
3637}
3638
3639/* Find the smallest rectangle that bounds the text when it is printed in rect
3640 * according to the format options listed in format. If rect has 0 width and
3641 * height, then just find the smallest rectangle that bounds the text when it's
3642 * printed at location (rect->X, rect-Y). */
3643GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics,
3644 GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font,
3645 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, RectF *bounds,
3646 INT *codepointsfitted, INT *linesfilled)
3647{
3648 HFONT oldfont;
3649 struct measure_string_args args;
3650
3651 TRACE("(%p, %s, %i, %p, %s, %p, %p, %p, %p)\n", graphics,
3652 debugstr_wn(string, length), length, font, debugstr_rectf(rect), format,
3653 bounds, codepointsfitted, linesfilled);
3654
3655 if(!graphics || !string || !font || !rect || !bounds)
3656 return InvalidParameter;
3657
3658 if(linesfilled) *linesfilled = 0;
3659 if(codepointsfitted) *codepointsfitted = 0;
3660
3661 if(format)
3662 TRACE("may be ignoring some format flags: attr %x\n", format->attr);
3663
3664 oldfont = SelectObject(graphics->hdc, CreateFontIndirectW(&font->lfw));
3665
Evan Stadea51cf1d2007-08-15 16:21:52 -07003666 bounds->X = rect->X;
3667 bounds->Y = rect->Y;
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003668 bounds->Width = 0.0;
3669 bounds->Height = 0.0;
Evan Stadea51cf1d2007-08-15 16:21:52 -07003670
Vincent Povirk3cee74c2010-03-30 13:41:04 -05003671 args.bounds = bounds;
3672 args.codepointsfitted = codepointsfitted;
3673 args.linesfilled = linesfilled;
3674
3675 gdip_format_string(graphics, string, length, font, rect, format,
3676 measure_string_callback, &args);
3677
Evan Stadea51cf1d2007-08-15 16:21:52 -07003678 DeleteObject(SelectObject(graphics->hdc, oldfont));
3679
3680 return Ok;
3681}
3682
Vincent Povirk2cde94a2010-03-30 14:15:48 -05003683struct draw_string_args {
3684 POINT drawbase;
3685 UINT drawflags;
3686 REAL ang_cos, ang_sin;
3687};
3688
3689static GpStatus draw_string_callback(GpGraphics *graphics,
3690 GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
3691 GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
3692 INT lineno, const RectF *bounds, void *user_data)
3693{
3694 struct draw_string_args *args = user_data;
3695 RECT drawcoord;
3696
3697 drawcoord.left = drawcoord.right = args->drawbase.x + roundr(args->ang_sin * bounds->Y);
3698 drawcoord.top = drawcoord.bottom = args->drawbase.y + roundr(args->ang_cos * bounds->Y);
3699
3700 DrawTextW(graphics->hdc, string + index, length, &drawcoord, args->drawflags);
3701
3702 return Ok;
3703}
3704
3705GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string,
3706 INT length, GDIPCONST GpFont *font, GDIPCONST RectF *rect,
3707 GDIPCONST GpStringFormat *format, GDIPCONST GpBrush *brush)
3708{
3709 HRGN rgn = NULL;
3710 HFONT gdifont;
3711 LOGFONTW lfw;
3712 TEXTMETRICW textmet;
3713 GpPointF pt[3], rectcpy[4];
3714 POINT corners[4];
3715 REAL angle, rel_width, rel_height;
3716 INT offsety = 0, save_state;
3717 struct draw_string_args args;
3718 RectF scaled_rect;
3719
3720 TRACE("(%p, %s, %i, %p, %s, %p, %p)\n", graphics, debugstr_wn(string, length),
3721 length, font, debugstr_rectf(rect), format, brush);
3722
3723 if(!graphics || !string || !font || !brush || !rect)
3724 return InvalidParameter;
3725
3726 if((brush->bt != BrushTypeSolidColor)){
3727 FIXME("not implemented for given parameters\n");
3728 return NotImplemented;
3729 }
3730
3731 if(format){
3732 TRACE("may be ignoring some format flags: attr %x\n", format->attr);
3733
3734 /* Should be no need to explicitly test for StringAlignmentNear as
3735 * that is default behavior if no alignment is passed. */
3736 if(format->vertalign != StringAlignmentNear){
3737 RectF bounds;
3738 GdipMeasureString(graphics, string, length, font, rect, format, &bounds, 0, 0);
3739
3740 if(format->vertalign == StringAlignmentCenter)
3741 offsety = (rect->Height - bounds.Height) / 2;
3742 else if(format->vertalign == StringAlignmentFar)
3743 offsety = (rect->Height - bounds.Height);
3744 }
3745 }
3746
3747 save_state = SaveDC(graphics->hdc);
3748 SetBkMode(graphics->hdc, TRANSPARENT);
3749 SetTextColor(graphics->hdc, brush->lb.lbColor);
3750
3751 pt[0].X = 0.0;
3752 pt[0].Y = 0.0;
3753 pt[1].X = 1.0;
3754 pt[1].Y = 0.0;
3755 pt[2].X = 0.0;
3756 pt[2].Y = 1.0;
3757 GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
3758 angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
3759 args.ang_cos = cos(angle);
3760 args.ang_sin = sin(angle);
3761 rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+
3762 (pt[1].X-pt[0].X)*(pt[1].X-pt[0].X));
3763 rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+
3764 (pt[2].X-pt[0].X)*(pt[2].X-pt[0].X));
3765
3766 rectcpy[3].X = rectcpy[0].X = rect->X;
3767 rectcpy[1].Y = rectcpy[0].Y = rect->Y + offsety;
3768 rectcpy[2].X = rectcpy[1].X = rect->X + rect->Width;
3769 rectcpy[3].Y = rectcpy[2].Y = rect->Y + offsety + rect->Height;
3770 transform_and_round_points(graphics, corners, rectcpy, 4);
3771
3772 scaled_rect.X = 0.0;
3773 scaled_rect.Y = 0.0;
3774 scaled_rect.Width = rel_width * rect->Width;
3775 scaled_rect.Height = rel_height * rect->Height;
3776
3777 if (roundr(scaled_rect.Width) != 0 && roundr(scaled_rect.Height) != 0)
3778 {
3779 /* FIXME: If only the width or only the height is 0, we should probably still clip */
3780 rgn = CreatePolygonRgn(corners, 4, ALTERNATE);
3781 SelectClipRgn(graphics->hdc, rgn);
3782 }
3783
3784 /* Use gdi to find the font, then perform transformations on it (height,
3785 * width, angle). */
3786 SelectObject(graphics->hdc, CreateFontIndirectW(&font->lfw));
3787 GetTextMetricsW(graphics->hdc, &textmet);
3788 lfw = font->lfw;
3789
3790 lfw.lfHeight = roundr(((REAL)lfw.lfHeight) * rel_height);
3791 lfw.lfWidth = roundr(textmet.tmAveCharWidth * rel_width);
3792
3793 lfw.lfEscapement = lfw.lfOrientation = roundr((angle / M_PI) * 1800.0);
3794
3795 gdifont = CreateFontIndirectW(&lfw);
3796 DeleteObject(SelectObject(graphics->hdc, CreateFontIndirectW(&lfw)));
3797
3798 if (!format || format->align == StringAlignmentNear)
3799 {
3800 args.drawbase.x = corners[0].x;
3801 args.drawbase.y = corners[0].y;
3802 args.drawflags = DT_NOCLIP | DT_EXPANDTABS;
3803 }
3804 else if (format->align == StringAlignmentCenter)
3805 {
3806 args.drawbase.x = (corners[0].x + corners[1].x)/2;
3807 args.drawbase.y = (corners[0].y + corners[1].y)/2;
3808 args.drawflags = DT_NOCLIP | DT_EXPANDTABS | DT_CENTER;
3809 }
3810 else /* (format->align == StringAlignmentFar) */
3811 {
3812 args.drawbase.x = corners[1].x;
3813 args.drawbase.y = corners[1].y;
3814 args.drawflags = DT_NOCLIP | DT_EXPANDTABS | DT_RIGHT;
3815 }
3816
3817 gdip_format_string(graphics, string, length, font, &scaled_rect, format,
3818 draw_string_callback, &args);
3819
3820 DeleteObject(rgn);
3821 DeleteObject(gdifont);
3822
3823 RestoreDC(graphics->hdc, save_state);
3824
3825 return Ok;
3826}
3827
Nikolay Sivovff88d4e2008-08-28 17:34:22 +04003828GpStatus WINGDIPAPI GdipResetClip(GpGraphics *graphics)
3829{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003830 TRACE("(%p)\n", graphics);
3831
Nikolay Sivovff88d4e2008-08-28 17:34:22 +04003832 if(!graphics)
3833 return InvalidParameter;
3834
3835 if(graphics->busy)
3836 return ObjectBusy;
3837
3838 return GdipSetInfinite(graphics->clip);
3839}
3840
Nikolay Sivov169e87d2008-08-06 18:36:16 +04003841GpStatus WINGDIPAPI GdipResetWorldTransform(GpGraphics *graphics)
3842{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003843 TRACE("(%p)\n", graphics);
3844
Nikolay Sivov169e87d2008-08-06 18:36:16 +04003845 if(!graphics)
3846 return InvalidParameter;
3847
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003848 if(graphics->busy)
3849 return ObjectBusy;
3850
Nikolay Sivov169e87d2008-08-06 18:36:16 +04003851 graphics->worldtrans->matrix[0] = 1.0;
3852 graphics->worldtrans->matrix[1] = 0.0;
3853 graphics->worldtrans->matrix[2] = 0.0;
3854 graphics->worldtrans->matrix[3] = 1.0;
3855 graphics->worldtrans->matrix[4] = 0.0;
3856 graphics->worldtrans->matrix[5] = 0.0;
3857
3858 return Ok;
3859}
3860
Evan Stadec7606682007-07-13 17:51:37 -07003861GpStatus WINGDIPAPI GdipRestoreGraphics(GpGraphics *graphics, GraphicsState state)
3862{
Andrew Eikum1ef13942009-07-07 22:30:49 -05003863 return GdipEndContainer(graphics, state);
Evan Stadec7606682007-07-13 17:51:37 -07003864}
3865
Evan Stade3126c772007-08-13 18:34:35 -07003866GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle,
3867 GpMatrixOrder order)
3868{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003869 TRACE("(%p, %.2f, %d)\n", graphics, angle, order);
3870
Evan Stade3126c772007-08-13 18:34:35 -07003871 if(!graphics)
3872 return InvalidParameter;
3873
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003874 if(graphics->busy)
3875 return ObjectBusy;
3876
Evan Stade3126c772007-08-13 18:34:35 -07003877 return GdipRotateMatrix(graphics->worldtrans, angle, order);
3878}
3879
Evan Stadec7606682007-07-13 17:51:37 -07003880GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state)
3881{
Andrew Eikum1ef13942009-07-07 22:30:49 -05003882 return GdipBeginContainer2(graphics, state);
Evan Stadec7606682007-07-13 17:51:37 -07003883}
3884
Andrew Eikum632aef32009-07-05 17:04:20 -05003885GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics,
3886 GraphicsContainer *state)
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003887{
Andrew Eikum632aef32009-07-05 17:04:20 -05003888 GraphicsContainerItem *container;
3889 GpStatus sts;
3890
3891 TRACE("(%p, %p)\n", graphics, state);
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003892
3893 if(!graphics || !state)
3894 return InvalidParameter;
3895
Andrew Eikum632aef32009-07-05 17:04:20 -05003896 sts = init_container(&container, graphics);
3897 if(sts != Ok)
3898 return sts;
3899
3900 list_add_head(&graphics->containers, &container->entry);
3901 *state = graphics->contid = container->contid;
3902
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003903 return Ok;
3904}
3905
Andrew Eikum30915062009-05-31 15:00:03 -05003906GpStatus WINGDIPAPI GdipBeginContainer(GpGraphics *graphics, GDIPCONST GpRectF *dstrect, GDIPCONST GpRectF *srcrect, GpUnit unit, GraphicsContainer *state)
3907{
3908 FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state);
3909 return NotImplemented;
3910}
3911
3912GpStatus WINGDIPAPI GdipBeginContainerI(GpGraphics *graphics, GDIPCONST GpRect *dstrect, GDIPCONST GpRect *srcrect, GpUnit unit, GraphicsContainer *state)
3913{
3914 FIXME("(%p, %p, %p, %d, %p): stub\n", graphics, dstrect, srcrect, unit, state);
3915 return NotImplemented;
3916}
3917
Andrew Eikumb8500082009-06-01 20:01:43 -05003918GpStatus WINGDIPAPI GdipComment(GpGraphics *graphics, UINT sizeData, GDIPCONST BYTE *data)
3919{
3920 FIXME("(%p, %d, %p): stub\n", graphics, sizeData, data);
3921 return NotImplemented;
3922}
3923
Andrew Eikuma06c2572009-07-07 22:30:29 -05003924GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsContainer state)
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003925{
Andrew Eikum632aef32009-07-05 17:04:20 -05003926 GpStatus sts;
3927 GraphicsContainerItem *container, *container2;
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003928
Andrew Eikum632aef32009-07-05 17:04:20 -05003929 TRACE("(%p, %x)\n", graphics, state);
3930
3931 if(!graphics)
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003932 return InvalidParameter;
3933
Andrew Eikum632aef32009-07-05 17:04:20 -05003934 LIST_FOR_EACH_ENTRY(container, &graphics->containers, GraphicsContainerItem, entry){
3935 if(container->contid == state)
3936 break;
3937 }
3938
3939 /* did not find a matching container */
3940 if(&container->entry == &graphics->containers)
3941 return Ok;
3942
Andrew Eikuma06c2572009-07-07 22:30:29 -05003943 sts = restore_container(graphics, container);
3944 if(sts != Ok)
3945 return sts;
3946
Andrew Eikum632aef32009-07-05 17:04:20 -05003947 /* remove all of the containers on top of the found container */
3948 LIST_FOR_EACH_ENTRY_SAFE(container, container2, &graphics->containers, GraphicsContainerItem, entry){
3949 if(container->contid == state)
3950 break;
3951 list_remove(&container->entry);
3952 delete_container(container);
3953 }
3954
3955 list_remove(&container->entry);
Andrew Eikum632aef32009-07-05 17:04:20 -05003956 delete_container(container);
3957
Andrew Eikuma06c2572009-07-07 22:30:29 -05003958 return Ok;
Hans Leidekker5ce729a2008-11-24 10:22:51 +01003959}
3960
Evan Stade30fdcc72007-08-13 18:34:38 -07003961GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics *graphics, REAL sx,
3962 REAL sy, GpMatrixOrder order)
3963{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003964 TRACE("(%p, %.2f, %.2f, %d)\n", graphics, sx, sy, order);
3965
Evan Stade30fdcc72007-08-13 18:34:38 -07003966 if(!graphics)
3967 return InvalidParameter;
3968
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003969 if(graphics->busy)
3970 return ObjectBusy;
3971
Evan Stade30fdcc72007-08-13 18:34:38 -07003972 return GdipScaleMatrix(graphics->worldtrans, sx, sy, order);
3973}
3974
Nikolay Sivovc543f3d2008-10-22 20:03:10 +04003975GpStatus WINGDIPAPI GdipSetClipGraphics(GpGraphics *graphics, GpGraphics *srcgraphics,
3976 CombineMode mode)
3977{
3978 TRACE("(%p, %p, %d)\n", graphics, srcgraphics, mode);
3979
3980 if(!graphics || !srcgraphics)
3981 return InvalidParameter;
3982
3983 return GdipCombineRegionRegion(graphics->clip, srcgraphics->clip, mode);
3984}
3985
Evan Stadee807eb92007-08-13 18:34:27 -07003986GpStatus WINGDIPAPI GdipSetCompositingMode(GpGraphics *graphics,
3987 CompositingMode mode)
3988{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04003989 TRACE("(%p, %d)\n", graphics, mode);
3990
Evan Stadee807eb92007-08-13 18:34:27 -07003991 if(!graphics)
3992 return InvalidParameter;
3993
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04003994 if(graphics->busy)
3995 return ObjectBusy;
3996
Evan Stadee807eb92007-08-13 18:34:27 -07003997 graphics->compmode = mode;
3998
3999 return Ok;
4000}
4001
Evan Stade60cad232007-07-13 17:51:25 -07004002GpStatus WINGDIPAPI GdipSetCompositingQuality(GpGraphics *graphics,
4003 CompositingQuality quality)
4004{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004005 TRACE("(%p, %d)\n", graphics, quality);
4006
Evan Stade60cad232007-07-13 17:51:25 -07004007 if(!graphics)
4008 return InvalidParameter;
4009
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004010 if(graphics->busy)
4011 return ObjectBusy;
4012
Evan Stade60cad232007-07-13 17:51:25 -07004013 graphics->compqual = quality;
4014
4015 return Ok;
4016}
4017
Evan Stadea87ce7a2007-07-13 17:51:29 -07004018GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics,
4019 InterpolationMode mode)
4020{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004021 TRACE("(%p, %d)\n", graphics, mode);
4022
Evan Stadea87ce7a2007-07-13 17:51:29 -07004023 if(!graphics)
4024 return InvalidParameter;
4025
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004026 if(graphics->busy)
4027 return ObjectBusy;
4028
Evan Stadea87ce7a2007-07-13 17:51:29 -07004029 graphics->interpolation = mode;
4030
4031 return Ok;
4032}
4033
Evan Stade81621392007-07-24 17:18:39 -07004034GpStatus WINGDIPAPI GdipSetPageScale(GpGraphics *graphics, REAL scale)
4035{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004036 TRACE("(%p, %.2f)\n", graphics, scale);
4037
Evan Stade81621392007-07-24 17:18:39 -07004038 if(!graphics || (scale <= 0.0))
4039 return InvalidParameter;
4040
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004041 if(graphics->busy)
4042 return ObjectBusy;
4043
Evan Stade81621392007-07-24 17:18:39 -07004044 graphics->scale = scale;
4045
4046 return Ok;
4047}
4048
Evan Stade10b575b2007-07-23 20:24:41 -07004049GpStatus WINGDIPAPI GdipSetPageUnit(GpGraphics *graphics, GpUnit unit)
4050{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004051 TRACE("(%p, %d)\n", graphics, unit);
4052
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004053 if(!graphics)
4054 return InvalidParameter;
4055
4056 if(graphics->busy)
4057 return ObjectBusy;
4058
4059 if(unit == UnitWorld)
Evan Stade10b575b2007-07-23 20:24:41 -07004060 return InvalidParameter;
4061
4062 graphics->unit = unit;
4063
4064 return Ok;
4065}
4066
Evan Staded6bd866d2007-07-13 17:51:33 -07004067GpStatus WINGDIPAPI GdipSetPixelOffsetMode(GpGraphics *graphics, PixelOffsetMode
4068 mode)
4069{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004070 TRACE("(%p, %d)\n", graphics, mode);
4071
Evan Staded6bd866d2007-07-13 17:51:33 -07004072 if(!graphics)
4073 return InvalidParameter;
4074
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004075 if(graphics->busy)
4076 return ObjectBusy;
4077
Evan Staded6bd866d2007-07-13 17:51:33 -07004078 graphics->pixeloffset = mode;
4079
4080 return Ok;
4081}
4082
Vincent Povirk27b47ea2009-05-06 16:03:27 -05004083GpStatus WINGDIPAPI GdipSetRenderingOrigin(GpGraphics *graphics, INT x, INT y)
4084{
4085 static int calls;
4086
4087 TRACE("(%p,%i,%i)\n", graphics, x, y);
4088
4089 if (!(calls++))
4090 FIXME("not implemented\n");
4091
4092 return NotImplemented;
4093}
4094
Evan Stade53e17d22007-07-13 17:51:13 -07004095GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode mode)
4096{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004097 TRACE("(%p, %d)\n", graphics, mode);
4098
Evan Stade53e17d22007-07-13 17:51:13 -07004099 if(!graphics)
4100 return InvalidParameter;
4101
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004102 if(graphics->busy)
4103 return ObjectBusy;
4104
Evan Stade53e17d22007-07-13 17:51:13 -07004105 graphics->smoothing = mode;
4106
4107 return Ok;
4108}
Evan Stadef30732f2007-07-24 17:18:47 -07004109
Nikolay Sivov71264732008-11-09 14:38:16 +03004110GpStatus WINGDIPAPI GdipSetTextContrast(GpGraphics *graphics, UINT contrast)
4111{
4112 TRACE("(%p, %d)\n", graphics, contrast);
4113
4114 if(!graphics)
4115 return InvalidParameter;
4116
4117 graphics->textcontrast = contrast;
4118
4119 return Ok;
4120}
4121
Evan Stade56628202007-08-14 19:00:09 -07004122GpStatus WINGDIPAPI GdipSetTextRenderingHint(GpGraphics *graphics,
4123 TextRenderingHint hint)
4124{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004125 TRACE("(%p, %d)\n", graphics, hint);
4126
Evan Stade56628202007-08-14 19:00:09 -07004127 if(!graphics)
4128 return InvalidParameter;
4129
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004130 if(graphics->busy)
4131 return ObjectBusy;
4132
Evan Stade56628202007-08-14 19:00:09 -07004133 graphics->texthint = hint;
4134
4135 return Ok;
4136}
4137
Evan Stadef30732f2007-07-24 17:18:47 -07004138GpStatus WINGDIPAPI GdipSetWorldTransform(GpGraphics *graphics, GpMatrix *matrix)
4139{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004140 TRACE("(%p, %p)\n", graphics, matrix);
4141
Evan Stadef30732f2007-07-24 17:18:47 -07004142 if(!graphics || !matrix)
4143 return InvalidParameter;
4144
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004145 if(graphics->busy)
4146 return ObjectBusy;
4147
Evan Stadef30732f2007-07-24 17:18:47 -07004148 GdipDeleteMatrix(graphics->worldtrans);
4149 return GdipCloneMatrix(matrix, &graphics->worldtrans);
4150}
Evan Stade795b6222007-08-09 18:25:31 -07004151
4152GpStatus WINGDIPAPI GdipTranslateWorldTransform(GpGraphics *graphics, REAL dx,
4153 REAL dy, GpMatrixOrder order)
4154{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004155 TRACE("(%p, %.2f, %.2f, %d)\n", graphics, dx, dy, order);
4156
Evan Stade795b6222007-08-09 18:25:31 -07004157 if(!graphics)
4158 return InvalidParameter;
4159
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004160 if(graphics->busy)
4161 return ObjectBusy;
4162
Evan Stade795b6222007-08-09 18:25:31 -07004163 return GdipTranslateMatrix(graphics->worldtrans, dx, dy, order);
4164}
Lei Zhangd9a42992008-04-08 14:44:41 -07004165
Nikolay Sivovf8edb062009-02-02 23:33:41 +03004166/*****************************************************************************
4167 * GdipSetClipHrgn [GDIPLUS.@]
4168 */
4169GpStatus WINGDIPAPI GdipSetClipHrgn(GpGraphics *graphics, HRGN hrgn, CombineMode mode)
4170{
4171 GpRegion *region;
4172 GpStatus status;
4173
4174 TRACE("(%p, %p, %d)\n", graphics, hrgn, mode);
4175
4176 if(!graphics)
4177 return InvalidParameter;
4178
4179 status = GdipCreateRegionHrgn(hrgn, &region);
4180 if(status != Ok)
4181 return status;
4182
4183 status = GdipSetClipRegion(graphics, region, mode);
4184
4185 GdipDeleteRegion(region);
4186 return status;
4187}
4188
Nikolay Sivove2817e52008-09-26 22:18:09 +04004189GpStatus WINGDIPAPI GdipSetClipPath(GpGraphics *graphics, GpPath *path, CombineMode mode)
4190{
4191 TRACE("(%p, %p, %d)\n", graphics, path, mode);
4192
4193 if(!graphics)
4194 return InvalidParameter;
4195
4196 if(graphics->busy)
4197 return ObjectBusy;
4198
4199 return GdipCombineRegionPath(graphics->clip, path, mode);
4200}
4201
Nikolay Sivov8d9c4862008-09-25 10:41:15 +04004202GpStatus WINGDIPAPI GdipSetClipRect(GpGraphics *graphics, REAL x, REAL y,
4203 REAL width, REAL height,
4204 CombineMode mode)
Lei Zhangd9a42992008-04-08 14:44:41 -07004205{
Nikolay Sivov8d9c4862008-09-25 10:41:15 +04004206 GpRectF rect;
4207
4208 TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %d)\n", graphics, x, y, width, height, mode);
Lei Zhangd9a42992008-04-08 14:44:41 -07004209
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004210 if(!graphics)
4211 return InvalidParameter;
4212
4213 if(graphics->busy)
4214 return ObjectBusy;
4215
Nikolay Sivov8d9c4862008-09-25 10:41:15 +04004216 rect.X = x;
4217 rect.Y = y;
4218 rect.Width = width;
4219 rect.Height = height;
Lei Zhangd9a42992008-04-08 14:44:41 -07004220
Nikolay Sivov8d9c4862008-09-25 10:41:15 +04004221 return GdipCombineRegionRect(graphics->clip, &rect, mode);
4222}
4223
4224GpStatus WINGDIPAPI GdipSetClipRectI(GpGraphics *graphics, INT x, INT y,
4225 INT width, INT height,
4226 CombineMode mode)
4227{
4228 TRACE("(%p, %d, %d, %d, %d, %d)\n", graphics, x, y, width, height, mode);
4229
4230 if(!graphics)
4231 return InvalidParameter;
4232
4233 if(graphics->busy)
4234 return ObjectBusy;
4235
4236 return GdipSetClipRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, mode);
Lei Zhangd9a42992008-04-08 14:44:41 -07004237}
Lei Zhangcec6c2e2008-04-09 12:35:29 -07004238
4239GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region,
Nikolay Sivov0df5fb52008-08-27 23:30:59 +04004240 CombineMode mode)
Lei Zhangcec6c2e2008-04-09 12:35:29 -07004241{
Nikolay Sivov0df5fb52008-08-27 23:30:59 +04004242 TRACE("(%p, %p, %d)\n", graphics, region, mode);
Lei Zhangcec6c2e2008-04-09 12:35:29 -07004243
Nikolay Sivov0df5fb52008-08-27 23:30:59 +04004244 if(!graphics || !region)
4245 return InvalidParameter;
Lei Zhangcec6c2e2008-04-09 12:35:29 -07004246
Nikolay Sivov0df5fb52008-08-27 23:30:59 +04004247 if(graphics->busy)
4248 return ObjectBusy;
4249
4250 return GdipCombineRegionRegion(graphics->clip, region, mode);
Lei Zhangcec6c2e2008-04-09 12:35:29 -07004251}
Lei Zhang54a06642008-04-10 12:40:21 -07004252
Nikolay Sivov45705012008-08-24 14:45:14 +04004253GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
Lei Zhang54a06642008-04-10 12:40:21 -07004254 UINT limitDpi)
4255{
4256 static int calls;
4257
Vincent Povirk2005fe92009-12-18 16:04:20 -06004258 TRACE("(%p,%u)\n", metafile, limitDpi);
4259
Lei Zhang54a06642008-04-10 12:40:21 -07004260 if(!(calls++))
4261 FIXME("not implemented\n");
4262
4263 return NotImplemented;
4264}
Nikolay Sivov46975932008-04-24 20:48:17 +04004265
4266GpStatus WINGDIPAPI GdipDrawPolygon(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPointF *points,
4267 INT count)
4268{
4269 INT save_state;
4270 POINT *pti;
4271
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004272 TRACE("(%p, %p, %d)\n", graphics, points, count);
4273
Nikolay Sivov46975932008-04-24 20:48:17 +04004274 if(!graphics || !pen || count<=0)
4275 return InvalidParameter;
4276
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004277 if(graphics->busy)
4278 return ObjectBusy;
4279
Nikolay Sivov46975932008-04-24 20:48:17 +04004280 pti = GdipAlloc(sizeof(POINT) * count);
4281
4282 save_state = prepare_dc(graphics, pen);
4283 SelectObject(graphics->hdc, GetStockObject(NULL_BRUSH));
4284
4285 transform_and_round_points(graphics, pti, (GpPointF*)points, count);
4286 Polygon(graphics->hdc, pti, count);
4287
4288 restore_dc(graphics, save_state);
4289 GdipFree(pti);
4290
4291 return Ok;
4292}
4293
4294GpStatus WINGDIPAPI GdipDrawPolygonI(GpGraphics *graphics,GpPen *pen,GDIPCONST GpPoint *points,
4295 INT count)
4296{
4297 GpStatus ret;
4298 GpPointF *ptf;
4299 INT i;
4300
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004301 TRACE("(%p, %p, %p, %d)\n", graphics, pen, points, count);
4302
Nikolay Sivov46975932008-04-24 20:48:17 +04004303 if(count<=0) return InvalidParameter;
4304 ptf = GdipAlloc(sizeof(GpPointF) * count);
4305
4306 for(i = 0;i < count; i++){
4307 ptf[i].X = (REAL)points[i].X;
4308 ptf[i].Y = (REAL)points[i].Y;
4309 }
4310
4311 ret = GdipDrawPolygon(graphics,pen,ptf,count);
4312 GdipFree(ptf);
4313
4314 return ret;
4315}
Nikolay Sivovd5769952008-04-29 00:10:20 +04004316
4317GpStatus WINGDIPAPI GdipGetDpiX(GpGraphics *graphics, REAL* dpi)
4318{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004319 TRACE("(%p, %p)\n", graphics, dpi);
4320
Nikolay Sivovd5769952008-04-29 00:10:20 +04004321 if(!graphics || !dpi)
4322 return InvalidParameter;
4323
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004324 if(graphics->busy)
4325 return ObjectBusy;
4326
Nikolay Sivovd5769952008-04-29 00:10:20 +04004327 *dpi = (REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSX);
4328
4329 return Ok;
4330}
4331
4332GpStatus WINGDIPAPI GdipGetDpiY(GpGraphics *graphics, REAL* dpi)
4333{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004334 TRACE("(%p, %p)\n", graphics, dpi);
4335
Nikolay Sivovd5769952008-04-29 00:10:20 +04004336 if(!graphics || !dpi)
4337 return InvalidParameter;
4338
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004339 if(graphics->busy)
4340 return ObjectBusy;
4341
Nikolay Sivovd5769952008-04-29 00:10:20 +04004342 *dpi = (REAL)GetDeviceCaps(graphics->hdc, LOGPIXELSY);
4343
4344 return Ok;
4345}
Nikolay Sivov510c26a2008-04-30 01:28:40 +04004346
4347GpStatus WINGDIPAPI GdipMultiplyWorldTransform(GpGraphics *graphics, GDIPCONST GpMatrix *matrix,
4348 GpMatrixOrder order)
4349{
4350 GpMatrix m;
4351 GpStatus ret;
4352
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004353 TRACE("(%p, %p, %d)\n", graphics, matrix, order);
4354
Nikolay Sivov510c26a2008-04-30 01:28:40 +04004355 if(!graphics || !matrix)
4356 return InvalidParameter;
4357
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004358 if(graphics->busy)
4359 return ObjectBusy;
4360
Nikolay Sivov510c26a2008-04-30 01:28:40 +04004361 m = *(graphics->worldtrans);
4362
Michael Stefaniucb53877d2009-01-14 09:52:24 +01004363 ret = GdipMultiplyMatrix(&m, matrix, order);
Nikolay Sivov510c26a2008-04-30 01:28:40 +04004364 if(ret == Ok)
4365 *(graphics->worldtrans) = m;
4366
4367 return ret;
4368}
Huw Davies6cfb4692008-05-12 16:51:32 +01004369
4370GpStatus WINGDIPAPI GdipGetDC(GpGraphics *graphics, HDC *hdc)
4371{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004372 TRACE("(%p, %p)\n", graphics, hdc);
4373
Nikolay Sivov45705012008-08-24 14:45:14 +04004374 if(!graphics || !hdc)
4375 return InvalidParameter;
4376
Nikolay Sivov366ae1e2008-08-24 14:45:18 +04004377 if(graphics->busy)
4378 return ObjectBusy;
4379
4380 *hdc = graphics->hdc;
4381 graphics->busy = TRUE;
4382
4383 return Ok;
Huw Davies6cfb4692008-05-12 16:51:32 +01004384}
4385
4386GpStatus WINGDIPAPI GdipReleaseDC(GpGraphics *graphics, HDC hdc)
4387{
Nikolay Sivov29f4c9d2008-09-02 23:45:39 +04004388 TRACE("(%p, %p)\n", graphics, hdc);
4389
Nikolay Sivov45705012008-08-24 14:45:14 +04004390 if(!graphics)
4391 return InvalidParameter;
4392
Nikolay Sivov366ae1e2008-08-24 14:45:18 +04004393 if(graphics->hdc != hdc || !(graphics->busy))
Nikolay Sivov45705012008-08-24 14:45:14 +04004394 return InvalidParameter;
4395
Nikolay Sivov366ae1e2008-08-24 14:45:18 +04004396 graphics->busy = FALSE;
4397
4398 return Ok;
Huw Davies6cfb4692008-05-12 16:51:32 +01004399}
Huw Daviesd5ccbe22008-05-12 16:57:28 +01004400
4401GpStatus WINGDIPAPI GdipGetClip(GpGraphics *graphics, GpRegion *region)
4402{
Nikolay Sivovef50aa32008-08-27 02:03:27 +04004403 GpRegion *clip;
4404 GpStatus status;
4405
4406 TRACE("(%p, %p)\n", graphics, region);
4407
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004408 if(!graphics || !region)
4409 return InvalidParameter;
Huw Daviesd5ccbe22008-05-12 16:57:28 +01004410
Nikolay Sivovf0a507e2008-08-24 14:45:23 +04004411 if(graphics->busy)
4412 return ObjectBusy;
4413
Nikolay Sivovef50aa32008-08-27 02:03:27 +04004414 if((status = GdipCloneRegion(graphics->clip, &clip)) != Ok)
4415 return status;
4416
4417 /* free everything except root node and header */
4418 delete_element(&region->node);
4419 memcpy(region, clip, sizeof(GpRegion));
Huw Davies68bacfb2009-12-12 16:49:15 +00004420 GdipFree(clip);
Nikolay Sivovef50aa32008-08-27 02:03:27 +04004421
4422 return Ok;
Huw Daviesd5ccbe22008-05-12 16:57:28 +01004423}
Huw Davies3ab76662008-07-10 15:26:58 +01004424
4425GpStatus WINGDIPAPI GdipTransformPoints(GpGraphics *graphics, GpCoordinateSpace dst_space,
4426 GpCoordinateSpace src_space, GpPointF *points, INT count)
4427{
Vincent Povirk2af29ed2009-03-23 16:34:12 -05004428 GpMatrix *matrix;
4429 GpStatus stat;
4430 REAL unitscale;
4431
Nikolay Sivovc61ece62008-08-26 01:58:42 +04004432 if(!graphics || !points || count <= 0)
4433 return InvalidParameter;
4434
4435 if(graphics->busy)
4436 return ObjectBusy;
4437
Vincent Povirk2af29ed2009-03-23 16:34:12 -05004438 TRACE("(%p, %d, %d, %p, %d)\n", graphics, dst_space, src_space, points, count);
Huw Davies3ab76662008-07-10 15:26:58 +01004439
Vincent Povirk2af29ed2009-03-23 16:34:12 -05004440 if (src_space == dst_space) return Ok;
4441
4442 stat = GdipCreateMatrix(&matrix);
4443 if (stat == Ok)
4444 {
4445 unitscale = convert_unit(graphics->hdc, graphics->unit);
4446
4447 if(graphics->unit != UnitDisplay)
4448 unitscale *= graphics->scale;
4449
4450 /* transform from src_space to CoordinateSpacePage */
4451 switch (src_space)
4452 {
4453 case CoordinateSpaceWorld:
4454 GdipMultiplyMatrix(matrix, graphics->worldtrans, MatrixOrderAppend);
4455 break;
4456 case CoordinateSpacePage:
4457 break;
4458 case CoordinateSpaceDevice:
4459 GdipScaleMatrix(matrix, 1.0/unitscale, 1.0/unitscale, MatrixOrderAppend);
4460 break;
4461 }
4462
4463 /* transform from CoordinateSpacePage to dst_space */
4464 switch (dst_space)
4465 {
4466 case CoordinateSpaceWorld:
4467 {
4468 GpMatrix *inverted_transform;
4469 stat = GdipCloneMatrix(graphics->worldtrans, &inverted_transform);
4470 if (stat == Ok)
4471 {
4472 stat = GdipInvertMatrix(inverted_transform);
4473 if (stat == Ok)
4474 GdipMultiplyMatrix(matrix, inverted_transform, MatrixOrderAppend);
4475 GdipDeleteMatrix(inverted_transform);
4476 }
4477 break;
4478 }
4479 case CoordinateSpacePage:
4480 break;
4481 case CoordinateSpaceDevice:
4482 GdipScaleMatrix(matrix, unitscale, unitscale, MatrixOrderAppend);
4483 break;
4484 }
4485
4486 if (stat == Ok)
4487 stat = GdipTransformMatrixPoints(matrix, points, count);
4488
4489 GdipDeleteMatrix(matrix);
4490 }
4491
4492 return stat;
Huw Davies3ab76662008-07-10 15:26:58 +01004493}
4494
4495GpStatus WINGDIPAPI GdipTransformPointsI(GpGraphics *graphics, GpCoordinateSpace dst_space,
4496 GpCoordinateSpace src_space, GpPoint *points, INT count)
4497{
Vincent Povirkc486e812009-05-19 15:40:43 -05004498 GpPointF *pointsF;
4499 GpStatus ret;
4500 INT i;
Huw Davies3ab76662008-07-10 15:26:58 +01004501
Vincent Povirkc486e812009-05-19 15:40:43 -05004502 TRACE("(%p, %d, %d, %p, %d)\n", graphics, dst_space, src_space, points, count);
4503
4504 if(count <= 0)
4505 return InvalidParameter;
4506
4507 pointsF = GdipAlloc(sizeof(GpPointF) * count);
4508 if(!pointsF)
4509 return OutOfMemory;
4510
4511 for(i = 0; i < count; i++){
4512 pointsF[i].X = (REAL)points[i].X;
4513 pointsF[i].Y = (REAL)points[i].Y;
4514 }
4515
4516 ret = GdipTransformPoints(graphics, dst_space, src_space, pointsF, count);
4517
4518 if(ret == Ok)
4519 for(i = 0; i < count; i++){
4520 points[i].X = roundr(pointsF[i].X);
4521 points[i].Y = roundr(pointsF[i].Y);
4522 }
4523 GdipFree(pointsF);
4524
4525 return ret;
Huw Davies3ab76662008-07-10 15:26:58 +01004526}
Hans Leidekker6122c772008-11-24 10:23:03 +01004527
4528HPALETTE WINGDIPAPI GdipCreateHalftonePalette(void)
4529{
Vincent Povirk9a4618a2010-04-09 10:32:22 -05004530 static int calls;
4531
4532 TRACE("\n");
4533
4534 if (!calls++)
4535 FIXME("stub\n");
Hans Leidekker6122c772008-11-24 10:23:03 +01004536
4537 return NULL;
4538}
Nikolay Sivov5da52e02009-01-31 00:07:30 +03004539
4540/*****************************************************************************
4541 * GdipTranslateClip [GDIPLUS.@]
4542 */
4543GpStatus WINGDIPAPI GdipTranslateClip(GpGraphics *graphics, REAL dx, REAL dy)
4544{
4545 TRACE("(%p, %.2f, %.2f)\n", graphics, dx, dy);
4546
4547 if(!graphics)
4548 return InvalidParameter;
4549
Nikolay Sivov8c096162009-02-02 23:48:01 +03004550 if(graphics->busy)
4551 return ObjectBusy;
4552
Nikolay Sivov5da52e02009-01-31 00:07:30 +03004553 return GdipTranslateRegion(graphics->clip, dx, dy);
4554}
4555
4556/*****************************************************************************
4557 * GdipTranslateClipI [GDIPLUS.@]
4558 */
4559GpStatus WINGDIPAPI GdipTranslateClipI(GpGraphics *graphics, INT dx, INT dy)
4560{
4561 TRACE("(%p, %d, %d)\n", graphics, dx, dy);
4562
4563 if(!graphics)
4564 return InvalidParameter;
4565
Nikolay Sivov8c096162009-02-02 23:48:01 +03004566 if(graphics->busy)
4567 return ObjectBusy;
4568
Nikolay Sivov5da52e02009-01-31 00:07:30 +03004569 return GdipTranslateRegion(graphics->clip, (REAL)dx, (REAL)dy);
4570}
Ken Sharpe3f48592009-06-09 21:48:05 +01004571
4572
4573/*****************************************************************************
4574 * GdipMeasureDriverString [GDIPLUS.@]
4575 */
4576GpStatus WINGDIPAPI GdipMeasureDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length,
4577 GDIPCONST GpFont *font, GDIPCONST PointF *positions,
4578 INT flags, GDIPCONST GpMatrix *matrix, RectF *boundingBox)
4579{
4580 FIXME("(%p %p %d %p %p %d %p %p): stub\n", graphics, text, length, font, positions, flags, matrix, boundingBox);
4581 return NotImplemented;
4582}
4583
4584/*****************************************************************************
Ken Sharpe3f48592009-06-09 21:48:05 +01004585 * GdipDrawDriverString [GDIPLUS.@]
4586 */
4587GpStatus WINGDIPAPI GdipDrawDriverString(GpGraphics *graphics, GDIPCONST UINT16 *text, INT length,
4588 GDIPCONST GpFont *font, GDIPCONST GpBrush *brush,
4589 GDIPCONST PointF *positions, INT flags,
4590 GDIPCONST GpMatrix *matrix )
4591{
Francois Gouget489bd522009-06-15 11:00:03 +02004592 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 +01004593 return NotImplemented;
4594}
Ken Sharpe096b592009-06-22 21:59:59 +01004595
4596/*****************************************************************************
Alistair Leslie-Hughes7b2292f2009-07-30 13:56:42 +10004597 * GdipRecordMetafileI [GDIPLUS.@]
4598 */
4599GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
4600 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
4601{
4602 FIXME("(%p %d %p %d %p %p): stub\n", hdc, type, frameRect, frameUnit, desc, metafile);
4603 return NotImplemented;
4604}
Alistair Leslie-Hughes03e31f92009-12-23 13:53:27 +11004605
4606/*****************************************************************************
4607 * GdipIsVisibleClipEmpty [GDIPLUS.@]
4608 */
4609GpStatus WINGDIPAPI GdipIsVisibleClipEmpty(GpGraphics *graphics, BOOL *res)
4610{
4611 GpStatus stat;
4612 GpRegion* rgn;
4613
4614 TRACE("(%p, %p)\n", graphics, res);
4615
4616 if((stat = GdipCreateRegion(&rgn)) != Ok)
4617 return stat;
4618
4619 if((stat = get_visible_clip_region(graphics, rgn)) != Ok)
4620 goto cleanup;
4621
4622 stat = GdipIsEmptyRegion(rgn, graphics, res);
4623
4624cleanup:
4625 GdipDeleteRegion(rgn);
4626 return stat;
4627}