1 /*
2  * Unit test suite for customlinecap
3  *
4  * Copyright (C) 2008 Nikolay Sivov
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 #include <limits.h>
21 
22 #include "objbase.h"
23 #include "gdiplus.h"
24 #include "wine/test.h"
25 
26 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
27 #define expectf(expected, got) ok(got == expected, "Expected %.2f, got %.2f\n", expected, got)
28 
compare_float(float f,float g,unsigned int ulps)29 static BOOL compare_float(float f, float g, unsigned int ulps)
30 {
31     int x = *(int *)&f;
32     int y = *(int *)&g;
33 
34     if (x < 0)
35         x = INT_MIN - x;
36     if (y < 0)
37         y = INT_MIN - y;
38 
39     if (abs(x - y) > ulps)
40         return FALSE;
41 
42     return TRUE;
43 }
44 
test_constructor_destructor(void)45 static void test_constructor_destructor(void)
46 {
47     GpCustomLineCap *custom;
48     GpPath *path, *path2;
49     GpStatus stat;
50 
51     stat = GdipCreatePath(FillModeAlternate, &path);
52     expect(Ok, stat);
53     stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0);
54     expect(Ok, stat);
55 
56     stat = GdipCreatePath(FillModeAlternate, &path2);
57     expect(Ok, stat);
58     stat = GdipAddPathRectangle(path2, 5.0, 5.0, 10.0, 10.0);
59     expect(Ok, stat);
60 
61     /* NULL args */
62     stat = GdipCreateCustomLineCap(NULL, NULL, LineCapFlat, 0.0, NULL);
63     expect(InvalidParameter, stat);
64     stat = GdipCreateCustomLineCap(path, NULL, LineCapFlat, 0.0, NULL);
65     expect(InvalidParameter, stat);
66     stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, NULL);
67     expect(InvalidParameter, stat);
68     stat = GdipCreateCustomLineCap(NULL, NULL, LineCapFlat, 0.0, &custom);
69     expect(InvalidParameter, stat);
70     stat = GdipDeleteCustomLineCap(NULL);
71     expect(InvalidParameter, stat);
72 
73     /* valid args */
74     stat = GdipCreateCustomLineCap(NULL, path2, LineCapFlat, 0.0, &custom);
75     expect(Ok, stat);
76     stat = GdipDeleteCustomLineCap(custom);
77     expect(Ok, stat);
78     /* it's strange but native returns NotImplemented on stroke == NULL */
79     custom = NULL;
80     stat = GdipCreateCustomLineCap(path, NULL, LineCapFlat, 10.0, &custom);
81     todo_wine expect(NotImplemented, stat);
82     todo_wine ok(custom == NULL, "Expected a failure on creation\n");
83     if(stat == Ok) GdipDeleteCustomLineCap(custom);
84 
85     GdipDeletePath(path2);
86     GdipDeletePath(path);
87 }
88 
test_linejoin(void)89 static void test_linejoin(void)
90 {
91     GpCustomLineCap *custom;
92     GpPath *path;
93     GpLineJoin join;
94     GpStatus stat;
95 
96     stat = GdipCreatePath(FillModeAlternate, &path);
97     expect(Ok, stat);
98     stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0);
99     expect(Ok, stat);
100 
101     stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &custom);
102     expect(Ok, stat);
103 
104     /* NULL args */
105     stat = GdipGetCustomLineCapStrokeJoin(NULL, NULL);
106     expect(InvalidParameter, stat);
107     stat = GdipGetCustomLineCapStrokeJoin(custom, NULL);
108     expect(InvalidParameter, stat);
109     stat = GdipGetCustomLineCapStrokeJoin(NULL, &join);
110     expect(InvalidParameter, stat);
111     stat = GdipSetCustomLineCapStrokeJoin(NULL, LineJoinBevel);
112     expect(InvalidParameter, stat);
113 
114     /* LineJoinMiter is default */
115     stat = GdipGetCustomLineCapStrokeJoin(custom, &join);
116     expect(Ok, stat);
117     expect(LineJoinMiter, join);
118 
119     /* set/get */
120     stat = GdipSetCustomLineCapStrokeJoin(custom, LineJoinBevel);
121     expect(Ok, stat);
122     stat = GdipGetCustomLineCapStrokeJoin(custom, &join);
123     expect(Ok, stat);
124     expect(LineJoinBevel, join);
125     stat = GdipSetCustomLineCapStrokeJoin(custom, LineJoinRound);
126     expect(Ok, stat);
127     stat = GdipGetCustomLineCapStrokeJoin(custom, &join);
128     expect(Ok, stat);
129     expect(LineJoinRound, join);
130     stat = GdipSetCustomLineCapStrokeJoin(custom, LineJoinMiterClipped);
131     expect(Ok, stat);
132     stat = GdipGetCustomLineCapStrokeJoin(custom, &join);
133     expect(Ok, stat);
134     expect(LineJoinMiterClipped, join);
135 
136     GdipDeleteCustomLineCap(custom);
137     GdipDeletePath(path);
138 }
139 
test_inset(void)140 static void test_inset(void)
141 {
142     GpCustomLineCap *custom;
143     GpPath *path;
144     REAL inset;
145     GpStatus stat;
146 
147     stat = GdipCreatePath(FillModeAlternate, &path);
148     expect(Ok, stat);
149     stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0);
150     expect(Ok, stat);
151 
152     stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &custom);
153     expect(Ok, stat);
154 
155     /* NULL args */
156     stat = GdipGetCustomLineCapBaseInset(NULL, NULL);
157     expect(InvalidParameter, stat);
158     stat = GdipGetCustomLineCapBaseInset(NULL, &inset);
159     expect(InvalidParameter, stat);
160     stat = GdipGetCustomLineCapBaseInset(custom, NULL);
161     expect(InvalidParameter, stat);
162     /* valid args */
163     inset = (REAL)0xdeadbeef;
164     stat = GdipGetCustomLineCapBaseInset(custom, &inset);
165     expect(Ok, stat);
166     expectf(0.0, inset);
167 
168     GdipDeleteCustomLineCap(custom);
169     GdipDeletePath(path);
170 }
171 
test_scale(void)172 static void test_scale(void)
173 {
174     GpCustomLineCap *custom;
175     GpPath *path;
176     REAL scale;
177     GpStatus stat;
178 
179     stat = GdipCreatePath(FillModeAlternate, &path);
180     expect(Ok, stat);
181     stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0);
182     expect(Ok, stat);
183 
184     stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &custom);
185     expect(Ok, stat);
186 
187     /* NULL args */
188     stat = GdipGetCustomLineCapWidthScale(NULL, NULL);
189     expect(InvalidParameter, stat);
190     stat = GdipGetCustomLineCapWidthScale(NULL, &scale);
191     expect(InvalidParameter, stat);
192     stat = GdipGetCustomLineCapWidthScale(custom, NULL);
193     expect(InvalidParameter, stat);
194 
195     stat = GdipSetCustomLineCapWidthScale(NULL, 2.0);
196     expect(InvalidParameter, stat);
197 
198     /* valid args: read default */
199     scale = (REAL)0xdeadbeef;
200     stat = GdipGetCustomLineCapWidthScale(custom, &scale);
201     expect(Ok, stat);
202     expectf(1.0, scale);
203 
204     /* set and read back some scale values: there is no limit for the scale */
205     stat = GdipSetCustomLineCapWidthScale(custom, 2.5);
206     expect(Ok, stat);
207     scale = (REAL)0xdeadbeef;
208     stat = GdipGetCustomLineCapWidthScale(custom, &scale);
209     expect(Ok, stat);
210     expectf(2.5, scale);
211 
212     stat = GdipSetCustomLineCapWidthScale(custom, 42.0);
213     expect(Ok, stat);
214     scale = (REAL)0xdeadbeef;
215     stat = GdipGetCustomLineCapWidthScale(custom, &scale);
216     expect(Ok, stat);
217     expectf(42.0, scale);
218 
219     stat = GdipSetCustomLineCapWidthScale(custom, 3000.0);
220     expect(Ok, stat);
221     scale = (REAL)0xdeadbeef;
222     stat = GdipGetCustomLineCapWidthScale(custom, &scale);
223     expect(Ok, stat);
224     expectf(3000.0, scale);
225 
226     stat = GdipSetCustomLineCapWidthScale(custom, 0.0);
227     expect(Ok, stat);
228     scale = (REAL)0xdeadbeef;
229     stat = GdipGetCustomLineCapWidthScale(custom, &scale);
230     expect(Ok, stat);
231     expectf(0.0, scale);
232 
233     GdipDeleteCustomLineCap(custom);
234     GdipDeletePath(path);
235 }
236 
test_create_adjustable_cap(void)237 static void test_create_adjustable_cap(void)
238 {
239     REAL inset, scale, height, width;
240     GpAdjustableArrowCap *cap;
241     GpLineJoin join;
242     GpStatus stat;
243     GpLineCap base;
244     BOOL ret;
245 
246     stat = GdipCreateAdjustableArrowCap(10.0, 10.0, TRUE, NULL);
247     ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
248 
249     stat = GdipCreateAdjustableArrowCap(17.0, 15.0, TRUE, &cap);
250     ok(stat == Ok, "Failed to create adjustable cap, %d\n", stat);
251 
252     stat = GdipGetAdjustableArrowCapFillState(cap, NULL);
253     ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
254 
255     ret = FALSE;
256     stat = GdipGetAdjustableArrowCapFillState(cap, &ret);
257     ok(stat == Ok, "Unexpected return code, %d\n", stat);
258     ok(ret, "Unexpected fill state %d\n", ret);
259 
260     stat = GdipGetAdjustableArrowCapHeight(cap, NULL);
261     ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
262 
263     stat = GdipGetAdjustableArrowCapHeight(cap, &height);
264     ok(stat == Ok, "Unexpected return code, %d\n", stat);
265     ok(height == 17.0, "Unexpected cap height %f\n", height);
266 
267     stat = GdipGetAdjustableArrowCapWidth(cap, NULL);
268     ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
269 
270     stat = GdipGetAdjustableArrowCapWidth(cap, &width);
271     ok(stat == Ok, "Unexpected return code, %d\n", stat);
272     ok(width == 15.0, "Unexpected cap width %f\n", width);
273 
274     stat = GdipGetAdjustableArrowCapMiddleInset(cap, NULL);
275     ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
276 
277     stat = GdipGetAdjustableArrowCapMiddleInset(cap, &inset);
278     ok(stat == Ok, "Unexpected return code, %d\n", stat);
279     ok(inset == 0.0f, "Unexpected middle inset %f\n", inset);
280 
281     stat = GdipGetCustomLineCapBaseCap((GpCustomLineCap*)cap, &base);
282     ok(stat == Ok, "Unexpected return code, %d\n", stat);
283     ok(base == LineCapTriangle, "Unexpected base cap %d\n", base);
284 
285     stat = GdipSetCustomLineCapBaseCap((GpCustomLineCap*)cap, LineCapSquare);
286 todo_wine
287     ok(stat == Ok, "Unexpected return code, %d\n", stat);
288 
289     stat = GdipGetCustomLineCapBaseCap((GpCustomLineCap*)cap, &base);
290     ok(stat == Ok, "Unexpected return code, %d\n", stat);
291 todo_wine
292     ok(base == LineCapSquare, "Unexpected base cap %d\n", base);
293 
294     /* Base inset */
295     stat = GdipGetAdjustableArrowCapWidth(cap, &width);
296     ok(stat == Ok, "Unexpected return code, %d\n", stat);
297 
298     stat = GdipGetAdjustableArrowCapHeight(cap, &height);
299     ok(stat == Ok, "Unexpected return code, %d\n", stat);
300 
301     inset = 0.0;
302     stat = GdipGetCustomLineCapBaseInset((GpCustomLineCap*)cap, &inset);
303     ok(stat == Ok, "Unexpected return code, %d\n", stat);
304     ok(compare_float(inset, height / width, 1), "Unexpected inset %f\n", inset);
305 
306     stat = GdipSetAdjustableArrowCapMiddleInset(cap, 1.0);
307     ok(stat == Ok, "Unexpected return code, %d\n", stat);
308 
309     inset = 0.0;
310     stat = GdipGetCustomLineCapBaseInset((GpCustomLineCap*)cap, &inset);
311     ok(stat == Ok, "Unexpected return code, %d\n", stat);
312     ok(compare_float(inset, height / width, 1), "Unexpected inset %f\n", inset);
313 
314     stat = GdipSetAdjustableArrowCapHeight(cap, 2.0 * height);
315     ok(stat == Ok, "Unexpected return code, %d\n", stat);
316 
317     inset = 0.0;
318     stat = GdipGetCustomLineCapBaseInset((GpCustomLineCap*)cap, &inset);
319     ok(stat == Ok, "Unexpected return code, %d\n", stat);
320     ok(compare_float(inset, 2.0 * height / width, 1), "Unexpected inset %f\n", inset);
321 
322     stat = GdipGetCustomLineCapWidthScale((GpCustomLineCap*)cap, &scale);
323     ok(stat == Ok, "Unexpected return code, %d\n", stat);
324     ok(scale == 1.0f, "Unexpected width scale %f\n", scale);
325 
326     stat = GdipGetCustomLineCapStrokeJoin((GpCustomLineCap*)cap, &join);
327     ok(stat == Ok, "Unexpected return code, %d\n", stat);
328     ok(join == LineJoinMiter, "Unexpected stroke join %d\n", join);
329 
330     GdipDeleteCustomLineCap((GpCustomLineCap*)cap);
331 }
332 
test_captype(void)333 static void test_captype(void)
334 {
335     GpAdjustableArrowCap *arrowcap;
336     GpCustomLineCap *custom;
337     CustomLineCapType type;
338     GpStatus stat;
339     GpPath *path;
340 
341     stat = GdipGetCustomLineCapType(NULL, NULL);
342     ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
343 
344     type = 10;
345     stat = GdipGetCustomLineCapType(NULL, &type);
346     ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat);
347     ok(type == 10, "Unexpected cap type, %d\n", type);
348 
349     /* default cap */
350     stat = GdipCreatePath(FillModeAlternate, &path);
351     ok(stat == Ok, "Failed to create path, %d\n", stat);
352     stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0);
353     ok(stat == Ok, "AddPathRectangle failed, %d\n", stat);
354 
355     stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &custom);
356     ok(stat == Ok, "Failed to create cap, %d\n", stat);
357     stat = GdipGetCustomLineCapType(custom, &type);
358     ok(stat == Ok, "Failed to get cap type, %d\n", stat);
359     ok(type == CustomLineCapTypeDefault, "Unexpected cap type %d\n", stat);
360     GdipDeleteCustomLineCap(custom);
361     GdipDeletePath(path);
362 
363     /* arrow cap */
364     stat = GdipCreateAdjustableArrowCap(17.0, 15.0, TRUE, &arrowcap);
365     ok(stat == Ok, "Failed to create adjustable cap, %d\n", stat);
366 
367     stat = GdipGetCustomLineCapType((GpCustomLineCap*)arrowcap, &type);
368     ok(stat == Ok, "Failed to get cap type, %d\n", stat);
369     ok(type == CustomLineCapTypeAdjustableArrow, "Unexpected cap type %d\n", stat);
370 
371     GdipDeleteCustomLineCap((GpCustomLineCap*)arrowcap);
372 }
373 
START_TEST(customlinecap)374 START_TEST(customlinecap)
375 {
376     struct GdiplusStartupInput gdiplusStartupInput;
377     ULONG_PTR gdiplusToken;
378     HMODULE hmsvcrt;
379     int (CDECL * _controlfp_s)(unsigned int *cur, unsigned int newval, unsigned int mask);
380 
381     /* Enable all FP exceptions except _EM_INEXACT, which gdi32 can trigger */
382     hmsvcrt = LoadLibraryA("msvcrt");
383     _controlfp_s = (void*)GetProcAddress(hmsvcrt, "_controlfp_s");
384     if (_controlfp_s) _controlfp_s(0, 0, 0x0008001e);
385 
386     gdiplusStartupInput.GdiplusVersion              = 1;
387     gdiplusStartupInput.DebugEventCallback          = NULL;
388     gdiplusStartupInput.SuppressBackgroundThread    = 0;
389     gdiplusStartupInput.SuppressExternalCodecs      = 0;
390 
391     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
392 
393     test_constructor_destructor();
394     test_linejoin();
395     test_inset();
396     test_scale();
397     test_create_adjustable_cap();
398     test_captype();
399 
400     GdiplusShutdown(gdiplusToken);
401 }
402