[GDIPLUS_WINETEST] Sync with Wine Staging 3.9. CORE-14656
[reactos.git] / modules / rostests / winetests / gdiplus / pen.c
1 /*
2 * Unit test suite for pens (and init)
3 *
4 * Copyright (C) 2007 Google (Evan Stade)
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <math.h>
22
23 #include "objbase.h"
24 #include "gdiplus.h"
25 #include "wine/test.h"
26
27 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
28 #define expectf(expected, got) ok(fabs(got - expected) < 0.1, "Expected %.2f, got %.2f\n", expected, got)
29
30 static void test_startup(void)
31 {
32 GpPen *pen = NULL;
33 Status status;
34 struct GdiplusStartupInput gdiplusStartupInput;
35 ULONG_PTR gdiplusToken;
36 int gpversion;
37
38 gdiplusStartupInput.DebugEventCallback = NULL;
39 gdiplusStartupInput.SuppressBackgroundThread = 0;
40 gdiplusStartupInput.SuppressExternalCodecs = 0;
41
42 for (gpversion=1; gpversion<256; gpversion++)
43 {
44 gdiplusStartupInput.GdiplusVersion = gpversion;
45 status = GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
46 ok(status == Ok || status == UnsupportedGdiplusVersion,
47 "GdiplusStartup returned %x\n", status);
48 GdiplusShutdown(gdiplusToken);
49 if (status != Ok)
50 {
51 gpversion--;
52 break;
53 }
54 }
55
56 ok(gpversion > 0 && gpversion <= 2, "unexpected gdiplus version %i\n", gpversion);
57 trace("gdiplus version is %i\n", gpversion);
58
59 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
60
61 todo_wine
62 expect(GdiplusNotInitialized, status);
63
64 GdipDeletePen(pen);
65 }
66
67 static void test_constructor_destructor(void)
68 {
69 GpStatus status;
70 GpPen *pen = NULL;
71
72 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, NULL);
73 expect(InvalidParameter, status);
74 ok(pen == NULL, "Expected pen to be NULL\n");
75
76 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
77 expect(Ok, status);
78 ok(pen != NULL, "Expected pen to be initialized\n");
79
80 status = GdipDeletePen(NULL);
81 expect(InvalidParameter, status);
82
83 status = GdipDeletePen(pen);
84 expect(Ok, status);
85 }
86
87 static void test_constructor_destructor2(void)
88 {
89 GpStatus status;
90 GpPen *pen = NULL;
91 GpBrush *brush = NULL;
92 GpPointF points[2];
93
94 status = GdipCreatePen2(NULL, 10.0f, UnitPixel, &pen);
95 expect(InvalidParameter, status);
96 ok(pen == NULL, "Expected pen to be NULL\n");
97
98 points[0].X = 7.0;
99 points[0].Y = 11.0;
100 points[1].X = 13.0;
101 points[1].Y = 17.0;
102
103 status = GdipCreateLineBrush(&points[0], &points[1], (ARGB)0xffff00ff,
104 (ARGB)0xff0000ff, WrapModeTile, (GpLineGradient **)&brush);
105 expect(Ok, status);
106 ok(brush != NULL, "Expected brush to be initialized\n");
107
108 status = GdipCreatePen2(brush, 10.0f, UnitPixel, &pen);
109 expect(Ok, status);
110 ok(pen != NULL, "Expected pen to be initialized\n");
111
112 status = GdipDeletePen(pen);
113 expect(Ok, status);
114
115 status = GdipDeleteBrush(brush);
116 expect(Ok, status);
117 }
118
119 static void test_brushfill(void)
120 {
121 GpStatus status;
122 GpPen *pen;
123 GpBrush *brush, *brush2;
124 GpBrushType type;
125 ARGB color = 0;
126
127 /* default solid */
128 GdipCreatePen1(0xdeadbeef, 4.5, UnitWorld, &pen);
129 status = GdipGetPenBrushFill(pen, &brush);
130 expect(Ok, status);
131 GdipGetBrushType(brush, &type);
132 expect(BrushTypeSolidColor, type);
133 GdipGetPenColor(pen, &color);
134 expect(0xdeadbeef, color);
135 GdipDeleteBrush(brush);
136
137 /* color controlled by brush */
138 GdipCreateSolidFill(0xabaddeed, (GpSolidFill**)&brush);
139 status = GdipSetPenBrushFill(pen, brush);
140 expect(Ok, status);
141 GdipGetPenColor(pen, &color);
142 expect(0xabaddeed, color);
143 GdipDeleteBrush(brush);
144 color = 0;
145
146 /* get returns a clone, not a reference */
147 GdipGetPenBrushFill(pen, &brush);
148 GdipSetSolidFillColor((GpSolidFill*)brush, 0xbeadfeed);
149 GdipGetPenBrushFill(pen, &brush2);
150 ok(brush != brush2, "Expected to get a clone, not a copy of the reference\n");
151 GdipGetSolidFillColor((GpSolidFill*)brush2, &color);
152 expect(0xabaddeed, color);
153 GdipDeleteBrush(brush);
154 GdipDeleteBrush(brush2);
155
156 /* brush cannot be NULL */
157 status = GdipSetPenBrushFill(pen, NULL);
158 expect(InvalidParameter, status);
159
160 GdipDeletePen(pen);
161 }
162
163 static void test_dasharray(void)
164 {
165 GpPen *pen;
166 GpDashStyle style;
167 GpStatus status;
168 REAL dashes[12];
169
170 GdipCreatePen1(0xdeadbeef, 10.0, UnitWorld, &pen);
171 dashes[0] = 10.0;
172 dashes[1] = 11.0;
173 dashes[2] = 12.0;
174 dashes[3] = 13.0;
175 dashes[4] = 14.0;
176 dashes[5] = -100.0;
177 dashes[6] = -100.0;
178 dashes[7] = dashes[8] = dashes[9] = dashes[10] = dashes[11] = 0.0;
179
180 /* setting the array sets the type to custom */
181 GdipGetPenDashStyle(pen, &style);
182 expect(DashStyleSolid, style);
183 status = GdipSetPenDashArray(pen, dashes, 2);
184 expect(Ok, status);
185 GdipGetPenDashStyle(pen, &style);
186 expect(DashStyleCustom, style);
187
188 /* Getting the array on a non-custom pen returns invalid parameter (unless
189 * you are getting 0 elements).*/
190 GdipSetPenDashStyle(pen, DashStyleSolid);
191 status = GdipGetPenDashArray(pen, &dashes[5], 2);
192 expect(InvalidParameter, status);
193 status = GdipGetPenDashArray(pen, &dashes[5], 0);
194 expect(Ok, status);
195
196 /* What does setting DashStyleCustom do to the array length? */
197 GdipSetPenDashArray(pen, dashes, 2);
198 GdipSetPenDashStyle(pen, DashStyleCustom);
199 status = GdipGetPenDashArray(pen, &dashes[5], 2);
200 expect(Ok, status);
201 expectf(10.0, dashes[5]);
202 expectf(11.0, dashes[6]);
203
204 /* Set the array, then get with different sized buffers. */
205 status = GdipSetPenDashArray(pen, dashes, 5);
206 expect(Ok, status);
207 dashes[5] = -100.0;
208 dashes[6] = -100.0;
209 status = GdipGetPenDashArray(pen, &dashes[5], 1);
210 expect(Ok, status); /* not InsufficientBuffer! */
211 expectf(10.0, dashes[5]);
212 expectf(-100.0, dashes[6]);
213 dashes[5] = -100.0;
214 status = GdipGetPenDashArray(pen, &dashes[5], 6);
215 expect(InvalidParameter, status); /* not Ok! */
216 expectf(-100.0, dashes[5]);
217 expectf(-100.0, dashes[6]);
218
219 /* Some invalid array values. */
220 status = GdipSetPenDashArray(pen, &dashes[7], 5);
221 expect(InvalidParameter, status);
222 dashes[9] = -1.0;
223 status = GdipSetPenDashArray(pen, &dashes[7], 5);
224 expect(InvalidParameter, status);
225
226 /* Try to set with count = 0. */
227 GdipSetPenDashStyle(pen, DashStyleDot);
228 if (0) /* corrupts stack on 64-bit Vista */
229 {
230 status = GdipSetPenDashArray(pen, dashes, 0);
231 ok(status == OutOfMemory || status == InvalidParameter,
232 "Expected OutOfMemory or InvalidParameter, got %.8x\n", status);
233 }
234 status = GdipSetPenDashArray(pen, dashes, -1);
235 ok(status == OutOfMemory || status == InvalidParameter,
236 "Expected OutOfMemory or InvalidParameter, got %.8x\n", status);
237 GdipGetPenDashStyle(pen, &style);
238 expect(DashStyleDot, style);
239
240 GdipDeletePen(pen);
241 }
242
243 static void test_customcap(void)
244 {
245 GpPen *pen;
246 GpStatus status;
247 GpCustomLineCap *custom;
248
249 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
250 expect(Ok, status);
251
252 /* NULL args */
253 status = GdipGetPenCustomStartCap(NULL, NULL);
254 expect(InvalidParameter, status);
255 status = GdipGetPenCustomStartCap(pen, NULL);
256 expect(InvalidParameter, status);
257 status = GdipGetPenCustomStartCap(NULL, &custom);
258 expect(InvalidParameter, status);
259
260 status = GdipGetPenCustomEndCap(NULL, NULL);
261 expect(InvalidParameter, status);
262 status = GdipGetPenCustomEndCap(pen, NULL);
263 expect(InvalidParameter, status);
264 status = GdipGetPenCustomEndCap(NULL, &custom);
265 expect(InvalidParameter, status);
266
267 /* native crashes on pen == NULL, custom != NULL */
268 status = GdipSetPenCustomStartCap(NULL, NULL);
269 expect(InvalidParameter, status);
270 status = GdipSetPenCustomStartCap(pen, NULL);
271 expect(InvalidParameter, status);
272
273 status = GdipSetPenCustomEndCap(NULL, NULL);
274 expect(InvalidParameter, status);
275 status = GdipSetPenCustomEndCap(pen, NULL);
276 expect(InvalidParameter, status);
277
278 /* get without setting previously */
279 custom = (GpCustomLineCap*)0xdeadbeef;
280 status = GdipGetPenCustomEndCap(pen, &custom);
281 expect(Ok, status);
282 ok(custom == NULL,"Expect CustomCap == NULL\n");
283
284 custom = (GpCustomLineCap*)0xdeadbeef;
285 status = GdipGetPenCustomStartCap(pen, &custom);
286 expect(Ok, status);
287 ok(custom == NULL,"Expect CustomCap == NULL\n");
288
289 GdipDeletePen(pen);
290 }
291
292 static void test_penfilltype(void)
293 {
294 GpPen *pen;
295 GpSolidFill *solid;
296 GpLineGradient *line;
297 GpPointF a, b;
298 GpStatus status;
299 GpPenType type;
300
301 /* NULL */
302 status = GdipGetPenFillType(NULL, NULL);
303 expect(InvalidParameter, status);
304
305 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
306 expect(Ok, status);
307 status = GdipGetPenFillType(pen, NULL);
308 expect(InvalidParameter, status);
309
310 /* created with GdipCreatePen1() */
311 status = GdipGetPenFillType(pen, &type);
312 expect(Ok, status);
313 expect(PenTypeSolidColor, type);
314 GdipDeletePen(pen);
315
316 /* based on SolidBrush */
317 status = GdipCreateSolidFill((ARGB)0xffff00ff, &solid);
318 expect(Ok, status);
319 status = GdipCreatePen2((GpBrush*)solid, 10.0f, UnitPixel, &pen);
320 expect(Ok, status);
321 status = GdipGetPenFillType(pen, &type);
322 expect(Ok, status);
323 expect(PenTypeSolidColor, type);
324 GdipDeletePen(pen);
325 GdipDeleteBrush((GpBrush*)solid);
326
327 /* based on LinearGradientBrush */
328 a.X = a.Y = 0.0;
329 b.X = b.Y = 10.0;
330 status = GdipCreateLineBrush(&a, &b, (ARGB)0xffff00ff, (ARGB)0xffff0000,
331 WrapModeTile, &line);
332 expect(Ok, status);
333 status = GdipCreatePen2((GpBrush*)line, 10.0f, UnitPixel, &pen);
334 expect(Ok, status);
335 status = GdipGetPenFillType(pen, &type);
336 expect(Ok, status);
337 expect(PenTypeLinearGradient, type);
338 GdipDeletePen(pen);
339 GdipDeleteBrush((GpBrush*)line);
340 }
341
342 static void test_compoundarray(void)
343 {
344 GpStatus status;
345 GpPen *pen;
346 static const REAL testvalues[] = {0.2, 0.4, 0.6, 0.8};
347 INT count;
348
349 status = GdipSetPenCompoundArray(NULL, testvalues, 4);
350 expect(InvalidParameter, status);
351
352 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
353 expect(Ok, status);
354
355 status = GdipGetPenCompoundCount(NULL, NULL);
356 expect(InvalidParameter, status);
357
358 status = GdipGetPenCompoundCount(pen, NULL);
359 expect(InvalidParameter, status);
360
361 count = 10;
362 status = GdipGetPenCompoundCount(pen, &count);
363 todo_wine {
364 expect(Ok, status);
365 ok(count == 0, "Unexpected compound count %d\n", count);
366 }
367 status = GdipSetPenCompoundArray(pen, NULL, 0);
368 expect(InvalidParameter, status);
369 status = GdipSetPenCompoundArray(pen, NULL, 4);
370 expect(InvalidParameter, status);
371 status = GdipSetPenCompoundArray(pen, testvalues, 3);
372 expect(InvalidParameter, status);
373 status = GdipSetPenCompoundArray(pen, testvalues, 0);
374 expect(InvalidParameter, status);
375 status = GdipSetPenCompoundArray(pen, testvalues, -2);
376 expect(InvalidParameter, status);
377
378 status = GdipSetPenCompoundArray(pen, testvalues, 4);
379 todo_wine expect(Ok, status);
380 status = GdipSetPenCompoundArray(pen, NULL, 0);
381 expect(InvalidParameter, status);
382
383 count = 0;
384 status = GdipGetPenCompoundCount(pen, &count);
385 todo_wine {
386 expect(Ok, status);
387 ok(count == 4, "Unexpected compound count %d\n", count);
388 }
389 GdipDeletePen(pen);
390 }
391
392 static void test_transform(void)
393 {
394 GpStatus status;
395 GpPen *pen;
396 GpMatrix *matrix, *matrix2;
397 REAL values[6];
398
399 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
400 expect(Ok, status);
401
402 status = GdipCreateMatrix(&matrix);
403 expect(Ok, status);
404
405 status = GdipGetPenTransform(pen, matrix);
406 expect(Ok, status);
407
408 status = GdipGetMatrixElements(matrix, values);
409 expect(Ok, status);
410
411 expectf(1.0, values[0]);
412 expectf(0.0, values[1]);
413 expectf(0.0, values[2]);
414 expectf(1.0, values[3]);
415 expectf(0.0, values[4]);
416 expectf(0.0, values[5]);
417
418 GdipCreateMatrix2(3.0, -2.0, 5.0, 2.0, 6.0, 3.0, &matrix2);
419 status = GdipSetPenTransform(pen, matrix2);
420 expect(Ok, status);
421 GdipDeleteMatrix(matrix2);
422
423 status = GdipGetPenTransform(pen, matrix);
424 expect(Ok, status);
425 status = GdipGetMatrixElements(matrix, values);
426 expect(Ok, status);
427 expectf(3.0, values[0]);
428 expectf(-2.0, values[1]);
429 expectf(5.0, values[2]);
430 expectf(2.0, values[3]);
431 expectf(6.0, values[4]);
432 expectf(3.0, values[5]);
433
434 /* Translate */
435 status = GdipTranslatePenTransform(NULL, 1.0, -2.0, MatrixOrderAppend);
436 expect(InvalidParameter, status);
437
438 status = GdipTranslatePenTransform(pen, 1.0, -2.0, MatrixOrderAppend);
439 expect(Ok, status);
440
441 status = GdipGetPenTransform(pen, matrix);
442 expect(Ok, status);
443 status = GdipGetMatrixElements(matrix, values);
444 expect(Ok, status);
445 expectf(3.0, values[0]);
446 expectf(-2.0, values[1]);
447 expectf(5.0, values[2]);
448 expectf(2.0, values[3]);
449 expectf(7.0, values[4]);
450 expectf(1.0, values[5]);
451
452 status = GdipTranslatePenTransform(pen, -3.0, 5.0, MatrixOrderPrepend);
453 expect(Ok, status);
454
455 status = GdipGetPenTransform(pen, matrix);
456 expect(Ok, status);
457 status = GdipGetMatrixElements(matrix, values);
458 expect(Ok, status);
459 expectf(3.0, values[0]);
460 expectf(-2.0, values[1]);
461 expectf(5.0, values[2]);
462 expectf(2.0, values[3]);
463 expectf(23.0, values[4]);
464 expectf(17.0, values[5]);
465
466 status = GdipResetPenTransform(pen);
467 expect(Ok, status);
468
469 status = GdipGetPenTransform(pen, matrix);
470 expect(Ok, status);
471 status = GdipGetMatrixElements(matrix, values);
472 expect(Ok, status);
473
474 expectf(1.0, values[0]);
475 expectf(0.0, values[1]);
476 expectf(0.0, values[2]);
477 expectf(1.0, values[3]);
478 expectf(0.0, values[4]);
479 expectf(0.0, values[5]);
480
481 GdipDeletePen(pen);
482
483 GdipDeleteMatrix(matrix);
484 }
485
486 START_TEST(pen)
487 {
488 struct GdiplusStartupInput gdiplusStartupInput;
489 ULONG_PTR gdiplusToken;
490 HMODULE hmsvcrt;
491 int (CDECL * _controlfp_s)(unsigned int *cur, unsigned int newval, unsigned int mask);
492
493 /* Enable all FP exceptions except _EM_INEXACT, which gdi32 can trigger */
494 hmsvcrt = LoadLibraryA("msvcrt");
495 _controlfp_s = (void*)GetProcAddress(hmsvcrt, "_controlfp_s");
496 if (_controlfp_s) _controlfp_s(0, 0, 0x0008001e);
497
498 test_startup();
499
500 gdiplusStartupInput.GdiplusVersion = 1;
501 gdiplusStartupInput.DebugEventCallback = NULL;
502 gdiplusStartupInput.SuppressBackgroundThread = 0;
503 gdiplusStartupInput.SuppressExternalCodecs = 0;
504
505 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
506
507 test_constructor_destructor();
508 test_constructor_destructor2();
509 test_brushfill();
510 test_dasharray();
511 test_customcap();
512 test_penfilltype();
513 test_compoundarray();
514 test_transform();
515
516 GdiplusShutdown(gdiplusToken);
517 }