gdiplus: Test for the lowest rejected startup version.
[wine] / dlls / gdiplus / tests / 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 "windows.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 < 42, "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     status = GdipSetPenDashArray(pen, dashes, 0);
229     ok(status == OutOfMemory || status == InvalidParameter,
230        "Expected OutOfMemory or InvalidParameter, got %.8x\n", status);
231     GdipGetPenDashStyle(pen, &style);
232     expect(DashStyleDot, style);
233
234     GdipDeletePen(pen);
235 }
236
237 static void test_customcap(void)
238 {
239     GpPen *pen;
240     GpStatus status;
241     GpCustomLineCap *custom;
242
243     status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
244     expect(Ok, status);
245
246     /* NULL args */
247     status = GdipGetPenCustomStartCap(NULL, NULL);
248     expect(InvalidParameter, status);
249     status = GdipGetPenCustomStartCap(pen, NULL);
250     expect(InvalidParameter, status);
251     status = GdipGetPenCustomStartCap(NULL, &custom);
252     expect(InvalidParameter, status);
253
254     status = GdipGetPenCustomEndCap(NULL, NULL);
255     expect(InvalidParameter, status);
256     status = GdipGetPenCustomEndCap(pen, NULL);
257     expect(InvalidParameter, status);
258     status = GdipGetPenCustomEndCap(NULL, &custom);
259     expect(InvalidParameter, status);
260
261     /* native crashes on pen == NULL, custom != NULL */
262     status = GdipSetPenCustomStartCap(NULL, NULL);
263     expect(InvalidParameter, status);
264     status = GdipSetPenCustomStartCap(pen, NULL);
265     expect(InvalidParameter, status);
266
267     status = GdipSetPenCustomEndCap(NULL, NULL);
268     expect(InvalidParameter, status);
269     status = GdipSetPenCustomEndCap(pen, NULL);
270     expect(InvalidParameter, status);
271
272     /* get without setting previously */
273     custom = (GpCustomLineCap*)0xdeadbeef;
274     status = GdipGetPenCustomEndCap(pen, &custom);
275     expect(Ok, status);
276     ok(custom == NULL,"Expect CustomCap == NULL\n");
277
278     custom = (GpCustomLineCap*)0xdeadbeef;
279     status = GdipGetPenCustomStartCap(pen, &custom);
280     expect(Ok, status);
281     ok(custom == NULL,"Expect CustomCap == NULL\n");
282
283     GdipDeletePen(pen);
284 }
285
286 static void test_penfilltype(void)
287 {
288     GpPen *pen;
289     GpSolidFill *solid;
290     GpLineGradient *line;
291     GpPointF a, b;
292     GpStatus status;
293     GpPenType type;
294
295     /* NULL */
296     status = GdipGetPenFillType(NULL, NULL);
297     expect(InvalidParameter, status);
298
299     status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
300     expect(Ok, status);
301     status = GdipGetPenFillType(pen, NULL);
302     expect(InvalidParameter, status);
303
304     /* created with GdipCreatePen1() */
305     status = GdipGetPenFillType(pen, &type);
306     expect(Ok, status);
307     expect(PenTypeSolidColor, type);
308     GdipDeletePen(pen);
309
310     /* based on SolidBrush */
311     status = GdipCreateSolidFill((ARGB)0xffff00ff, &solid);
312     expect(Ok, status);
313     status = GdipCreatePen2((GpBrush*)solid, 10.0f, UnitPixel, &pen);
314     expect(Ok, status);
315     status = GdipGetPenFillType(pen, &type);
316     expect(Ok, status);
317     expect(PenTypeSolidColor, type);
318     GdipDeletePen(pen);
319     GdipDeleteBrush((GpBrush*)solid);
320
321     /* based on LinearGradientBrush */
322     a.X = a.Y = 0.0;
323     b.X = b.Y = 10.0;
324     status = GdipCreateLineBrush(&a, &b, (ARGB)0xffff00ff, (ARGB)0xffff0000,
325                                  WrapModeTile, &line);
326     expect(Ok, status);
327     status = GdipCreatePen2((GpBrush*)line, 10.0f, UnitPixel, &pen);
328     expect(Ok, status);
329     status = GdipGetPenFillType(pen, &type);
330     expect(Ok, status);
331     expect(PenTypeLinearGradient, type);
332     GdipDeletePen(pen);
333     GdipDeleteBrush((GpBrush*)line);
334 }
335
336 static void test_compoundarray(void)
337 {
338     GpStatus status;
339     GpPen *pen;
340     static const REAL testvalues[] = {0.2, 0.4, 0.6, 0.8};
341
342     status = GdipSetPenCompoundArray(NULL, testvalues, 4);
343     expect(InvalidParameter, status);
344
345     status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen);
346     expect(Ok, status);
347
348     status = GdipSetPenCompoundArray(pen, NULL, 4);
349     expect(InvalidParameter, status);
350     status = GdipSetPenCompoundArray(pen, testvalues, 3);
351     expect(InvalidParameter, status);
352     status = GdipSetPenCompoundArray(pen, testvalues, 0);
353     expect(InvalidParameter, status);
354     status = GdipSetPenCompoundArray(pen, testvalues, -2);
355     expect(InvalidParameter, status);
356
357     status = GdipSetPenCompoundArray(pen, testvalues, 4);
358     todo_wine expect(Ok, status);
359
360     GdipDeletePen(pen);
361 }
362
363 START_TEST(pen)
364 {
365     struct GdiplusStartupInput gdiplusStartupInput;
366     ULONG_PTR gdiplusToken;
367
368     test_startup();
369
370     gdiplusStartupInput.GdiplusVersion              = 1;
371     gdiplusStartupInput.DebugEventCallback          = NULL;
372     gdiplusStartupInput.SuppressBackgroundThread    = 0;
373     gdiplusStartupInput.SuppressExternalCodecs      = 0;
374
375     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
376
377     test_constructor_destructor();
378     test_constructor_destructor2();
379     test_brushfill();
380     test_dasharray();
381     test_customcap();
382     test_penfilltype();
383     test_compoundarray();
384
385     GdiplusShutdown(gdiplusToken);
386 }