gdi32: ntmCellHeight and ntmAvgWidth should be in font units.
[wine] / dlls / gdi32 / tests / pen.c
1 /*
2  * Unit test suite for pens
3  *
4  * Copyright 2006 Dmitry Timoshkov
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 <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27
28 #include "wine/test.h"
29
30 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
31 #define expect2(expected, alt, got) ok(got == expected || got == alt, \
32                                        "Expected %.8x or %.8x, got %.8x\n", expected, alt, got)
33
34 static void test_logpen(void)
35 {
36     static const struct
37     {
38         UINT style;
39         INT width;
40         COLORREF color;
41         UINT ret_style;
42         INT ret_width;
43         COLORREF ret_color;
44     } pen[] = {
45         { PS_SOLID, -123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
46         { PS_SOLID, 0, RGB(0x12,0x34,0x56), PS_SOLID, 0, RGB(0x12,0x34,0x56) },
47         { PS_SOLID, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
48         { PS_DASH, 123, RGB(0x12,0x34,0x56), PS_DASH, 123, RGB(0x12,0x34,0x56) },
49         { PS_DOT, 123, RGB(0x12,0x34,0x56), PS_DOT, 123, RGB(0x12,0x34,0x56) },
50         { PS_DASHDOT, 123, RGB(0x12,0x34,0x56), PS_DASHDOT, 123, RGB(0x12,0x34,0x56) },
51         { PS_DASHDOTDOT, 123, RGB(0x12,0x34,0x56), PS_DASHDOTDOT, 123, RGB(0x12,0x34,0x56) },
52         { PS_NULL, -123, RGB(0x12,0x34,0x56), PS_NULL, 1, 0 },
53         { PS_NULL, 123, RGB(0x12,0x34,0x56), PS_NULL, 1, 0 },
54         { PS_INSIDEFRAME, 123, RGB(0x12,0x34,0x56), PS_INSIDEFRAME, 123, RGB(0x12,0x34,0x56) },
55         { PS_USERSTYLE, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
56         { PS_ALTERNATE, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
57         {  9, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
58         { 10, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
59         { 11, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
60         { 13, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
61         { 14, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
62         { 15, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
63     };
64     INT i, size;
65     HPEN hpen;
66     LOGPEN lp;
67     EXTLOGPEN elp;
68     LOGBRUSH lb;
69     DWORD_PTR unset_hatch;
70     DWORD obj_type, user_style[2] = { 0xabc, 0xdef };
71     char elp_buffer[128];
72     EXTLOGPEN *ext_pen = (EXTLOGPEN *)elp_buffer;
73     DWORD *ext_style = ext_pen->elpStyleEntry;
74
75     for (i = 0; i < sizeof(pen)/sizeof(pen[0]); i++)
76     {
77         trace("%d: testing style %u\n", i, pen[i].style);
78
79         /********************** cosmetic pens **********************/
80         /* CreatePenIndirect behaviour */
81         lp.lopnStyle = pen[i].style,
82         lp.lopnWidth.x = pen[i].width;
83         lp.lopnWidth.y = 11; /* just in case */
84         lp.lopnColor = pen[i].color;
85         SetLastError(0xdeadbeef);
86         hpen = CreatePenIndirect(&lp);
87         if(hpen == 0 && GetLastError() == ERROR_INVALID_PARAMETER)
88         {
89             win_skip("No support for pen style %u (%d)\n", pen[i].style, i);
90             continue;
91         }
92
93         obj_type = GetObjectType(hpen);
94         ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
95
96         memset(&lp, 0xb0, sizeof(lp));
97         SetLastError(0xdeadbeef);
98         size = GetObject(hpen, sizeof(lp), &lp);
99         ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
100
101         ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
102         ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
103         ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
104         ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
105
106         DeleteObject(hpen);
107
108         /* CreatePen behaviour */
109         SetLastError(0xdeadbeef);
110         hpen = CreatePen(pen[i].style, pen[i].width, pen[i].color);
111         ok(hpen != 0, "CreatePen error %d\n", GetLastError());
112
113         obj_type = GetObjectType(hpen);
114         ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
115
116         /* check what's the real size of the object */
117         size = GetObject(hpen, 0, NULL);
118         ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
119
120         /* ask for truncated data */
121         memset(&lp, 0xb0, sizeof(lp));
122         SetLastError(0xdeadbeef);
123         size = GetObject(hpen, sizeof(lp.lopnStyle), &lp);
124         ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
125
126         /* see how larger buffer sizes are handled */
127         memset(&lp, 0xb0, sizeof(lp));
128         SetLastError(0xdeadbeef);
129         size = GetObject(hpen, sizeof(lp) * 4, &lp);
130         ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
131
132         /* see how larger buffer sizes are handled */
133         memset(&elp, 0xb0, sizeof(elp));
134         SetLastError(0xdeadbeef);
135         size = GetObject(hpen, sizeof(elp) * 2, &elp);
136         ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
137
138         memset(&lp, 0xb0, sizeof(lp));
139         SetLastError(0xdeadbeef);
140         size = GetObject(hpen, sizeof(lp), &lp);
141         ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
142
143         ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
144         ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
145         ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
146         ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
147
148         memset(&elp, 0xb0, sizeof(elp));
149         SetLastError(0xdeadbeef);
150         size = GetObject(hpen, sizeof(elp), &elp);
151
152         /* for some reason XP differentiates PS_NULL here */
153         if (pen[i].style == PS_NULL)
154         {
155             ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n");
156             ok(size == sizeof(EXTLOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
157             ok(elp.elpPenStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, elp.elpPenStyle);
158             ok(elp.elpWidth == 0, "expected 0, got %u\n", elp.elpWidth);
159             ok(elp.elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, elp.elpColor);
160             ok(elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %u\n", elp.elpBrushStyle);
161             ok(elp.elpHatch == 0, "expected 0, got %p\n", (void *)elp.elpHatch);
162             ok(elp.elpNumEntries == 0, "expected 0, got %x\n", elp.elpNumEntries);
163         }
164         else
165         {
166             ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
167             memcpy(&lp, &elp, sizeof(lp));
168             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
169             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
170             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
171             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
172         }
173
174         DeleteObject(hpen);
175
176         /********** cosmetic pens created by ExtCreatePen ***********/
177         lb.lbStyle = BS_SOLID;
178         lb.lbColor = pen[i].color;
179         lb.lbHatch = HS_CROSS; /* just in case */
180         SetLastError(0xdeadbeef);
181         hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 2, user_style);
182         if (pen[i].style != PS_USERSTYLE)
183         {
184             ok(hpen == 0, "ExtCreatePen should fail\n");
185             ok(GetLastError() == ERROR_INVALID_PARAMETER,
186                "wrong last error value %d\n", GetLastError());
187             SetLastError(0xdeadbeef);
188             hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 0, NULL);
189             if (pen[i].style != PS_NULL)
190             {
191                 ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
192                 ok(GetLastError() == ERROR_INVALID_PARAMETER,
193                    "wrong last error value %d\n", GetLastError());
194
195                 SetLastError(0xdeadbeef);
196                 hpen = ExtCreatePen(pen[i].style, 1, &lb, 0, NULL);
197             }
198         }
199         else
200         {
201             ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
202             ok(GetLastError() == ERROR_INVALID_PARAMETER,
203                "wrong last error value %d\n", GetLastError());
204             SetLastError(0xdeadbeef);
205             hpen = ExtCreatePen(pen[i].style, 1, &lb, 2, user_style);
206         }
207         if (pen[i].style == PS_INSIDEFRAME)
208         {
209             /* This style is applicable only for geometric pens */
210             ok(hpen == 0, "ExtCreatePen should fail\n");
211             goto test_geometric_pens;
212         }
213         if (pen[i].style > PS_ALTERNATE)
214         {
215             ok(hpen == 0, "ExtCreatePen should fail\n");
216             ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong last error value %d\n", GetLastError());
217             goto test_geometric_pens;
218         }
219         ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError());
220
221         obj_type = GetObjectType(hpen);
222         /* for some reason XP differentiates PS_NULL here */
223         if (pen[i].style == PS_NULL)
224         {
225             ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
226             ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n");
227         }
228         else
229             ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type);
230
231         /* check what's the real size of the object */
232         SetLastError(0xdeadbeef);
233         size = GetObject(hpen, 0, NULL);
234         switch (pen[i].style)
235         {
236         case PS_NULL:
237             ok(size == sizeof(LOGPEN),
238                "GetObject returned %d, error %d\n", size, GetLastError());
239             break;
240
241         case PS_USERSTYLE:
242             ok(size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry[2] ),
243                "GetObject returned %d, error %d\n", size, GetLastError());
244             break;
245
246         default:
247             ok(size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ),
248                "GetObject returned %d, error %d\n", size, GetLastError());
249             break;
250         }
251
252         /* ask for truncated data */
253         memset(&elp, 0xb0, sizeof(elp));
254         SetLastError(0xdeadbeef);
255         size = GetObject(hpen, sizeof(elp.elpPenStyle), &elp);
256         ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
257
258         /* see how larger buffer sizes are handled */
259         memset(elp_buffer, 0xb0, sizeof(elp_buffer));
260         SetLastError(0xdeadbeef);
261         size = GetObject(hpen, sizeof(elp_buffer), elp_buffer);
262         switch (pen[i].style)
263         {
264         case PS_NULL:
265             ok(size == sizeof(LOGPEN),
266                "GetObject returned %d, error %d\n", size, GetLastError());
267             memcpy(&lp, ext_pen, sizeof(lp));
268             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
269             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
270             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
271             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
272
273             /* for PS_NULL it also works this way */
274             memset(&elp, 0xb0, sizeof(elp));
275             memset(&unset_hatch, 0xb0, sizeof(unset_hatch));
276             SetLastError(0xdeadbeef);
277             size = GetObject(hpen, sizeof(elp), &elp);
278             ok(size == sizeof(EXTLOGPEN),
279                 "GetObject returned %d, error %d\n", size, GetLastError());
280             ok(ext_pen->elpHatch == unset_hatch, "expected 0xb0b0b0b0, got %p\n", (void *)ext_pen->elpHatch);
281             ok(ext_pen->elpNumEntries == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %x\n", ext_pen->elpNumEntries);
282             break;
283
284         case PS_USERSTYLE:
285             ok(size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry[2] ),
286                "GetObject returned %d, error %d\n", size, GetLastError());
287             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
288             ok(ext_pen->elpNumEntries == 2, "expected 0, got %x\n", ext_pen->elpNumEntries);
289             ok(ext_style[0] == 0xabc, "expected 0xabc, got %x\n", ext_style[0]);
290             ok(ext_style[1] == 0xdef, "expected 0xdef, got %x\n", ext_style[1]);
291             break;
292
293         default:
294             ok(size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ),
295                "GetObject returned %d, error %d\n", size, GetLastError());
296             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
297             ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
298             break;
299         }
300
301         ok(ext_pen->elpPenStyle == pen[i].style, "expected %x, got %x\n", pen[i].style, ext_pen->elpPenStyle);
302         ok(ext_pen->elpWidth == 1, "expected 1, got %x\n", ext_pen->elpWidth);
303         ok(ext_pen->elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen->elpColor);
304         ok(ext_pen->elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen->elpBrushStyle);
305
306         DeleteObject(hpen);
307
308 test_geometric_pens:
309         /********************** geometric pens **********************/
310         lb.lbStyle = BS_SOLID;
311         lb.lbColor = pen[i].color;
312         lb.lbHatch = HS_CROSS; /* just in case */
313         SetLastError(0xdeadbeef);
314         hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 2, user_style);
315         if (pen[i].style != PS_USERSTYLE)
316         {
317             ok(hpen == 0, "ExtCreatePen should fail\n");
318             SetLastError(0xdeadbeef);
319             hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 0, NULL);
320         }
321         if (pen[i].style == PS_ALTERNATE)
322         {
323             /* This style is applicable only for cosmetic pens */
324             ok(hpen == 0, "ExtCreatePen should fail\n");
325             continue;
326         }
327         if (pen[i].style > PS_ALTERNATE)
328         {
329             ok(hpen == 0, "ExtCreatePen should fail\n");
330             ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong last error value %d\n", GetLastError());
331             continue;
332         }
333         ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError());
334
335         obj_type = GetObjectType(hpen);
336         /* for some reason XP differentiates PS_NULL here */
337         if (pen[i].style == PS_NULL)
338             ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
339         else
340             ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type);
341
342         /* check what's the real size of the object */
343         size = GetObject(hpen, 0, NULL);
344         switch (pen[i].style)
345         {
346         case PS_NULL:
347             ok(size == sizeof(LOGPEN),
348                "GetObject returned %d, error %d\n", size, GetLastError());
349             break;
350
351         case PS_USERSTYLE:
352             ok(size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry[2] ),
353                "GetObject returned %d, error %d\n", size, GetLastError());
354             break;
355
356         default:
357             ok(size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ),
358                "GetObject returned %d, error %d\n", size, GetLastError());
359             break;
360         }
361
362         /* ask for truncated data */
363         memset(&lp, 0xb0, sizeof(lp));
364         SetLastError(0xdeadbeef);
365         size = GetObject(hpen, sizeof(lp.lopnStyle), &lp);
366         ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
367
368         memset(&lp, 0xb0, sizeof(lp));
369         SetLastError(0xdeadbeef);
370         size = GetObject(hpen, sizeof(lp), &lp);
371         /* for some reason XP differentiates PS_NULL here */
372         if (pen[i].style == PS_NULL)
373         {
374             ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
375             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
376             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
377             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
378             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
379         }
380         else
381             /* XP doesn't set last error here */
382             ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
383                "GetObject should fail: size %d, error %d\n", size, GetLastError());
384
385         memset(elp_buffer, 0xb0, sizeof(elp_buffer));
386         SetLastError(0xdeadbeef);
387         /* buffer is too small for user styles */
388         size = GetObject(hpen, sizeof(EXTLOGPEN), elp_buffer);
389         switch (pen[i].style)
390         {
391         case PS_NULL:
392             ok(size == sizeof(EXTLOGPEN),
393                 "GetObject returned %d, error %d\n", size, GetLastError());
394             ok(ext_pen->elpHatch == 0, "expected 0, got %p\n", (void *)ext_pen->elpHatch);
395             ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
396
397             /* for PS_NULL it also works this way */
398             SetLastError(0xdeadbeef);
399             size = GetObject(hpen, sizeof(elp_buffer), &lp);
400             ok(size == sizeof(LOGPEN),
401                 "GetObject returned %d, error %d\n", size, GetLastError());
402             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
403             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
404             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
405             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
406             break;
407
408         case PS_USERSTYLE:
409             ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
410                "GetObject should fail: size %d, error %d\n", size, GetLastError());
411             size = GetObject(hpen, sizeof(elp_buffer), elp_buffer);
412             ok(size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry[2] ),
413                "GetObject returned %d, error %d\n", size, GetLastError());
414             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
415             ok(ext_pen->elpNumEntries == 2, "expected 0, got %x\n", ext_pen->elpNumEntries);
416             ok(ext_style[0] == 0xabc, "expected 0xabc, got %x\n", ext_style[0]);
417             ok(ext_style[1] == 0xdef, "expected 0xdef, got %x\n", ext_style[1]);
418             break;
419
420         default:
421             ok(size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ),
422                "GetObject returned %d, error %d\n", size, GetLastError());
423             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
424             ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
425             break;
426         }
427
428         /* for some reason XP differentiates PS_NULL here */
429         if (pen[i].style == PS_NULL)
430             ok(ext_pen->elpPenStyle == pen[i].ret_style, "expected %x, got %x\n", pen[i].ret_style, ext_pen->elpPenStyle);
431         else
432         {
433             ok(ext_pen->elpPenStyle == (PS_GEOMETRIC | pen[i].style), "expected %x, got %x\n", PS_GEOMETRIC | pen[i].style, ext_pen->elpPenStyle);
434         }
435
436         if (pen[i].style == PS_NULL)
437             ok(ext_pen->elpWidth == 0, "expected 0, got %x\n", ext_pen->elpWidth);
438         else
439             ok(ext_pen->elpWidth == pen[i].ret_width, "expected %u, got %x\n", pen[i].ret_width, ext_pen->elpWidth);
440         ok(ext_pen->elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen->elpColor);
441         ok(ext_pen->elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen->elpBrushStyle);
442
443         DeleteObject(hpen);
444     }
445 }
446
447 static unsigned int atoi2(const char *s)
448 {
449     unsigned int ret = 0;
450     while(*s) ret = (ret << 1) | (*s++ == '1');
451     return ret;
452 }
453
454 #define TEST_LINE(x1, x2, z) \
455     { int buf = 0; \
456       SetBitmapBits(bmp, sizeof(buf), &buf); \
457       MoveToEx(hdc, x1, 0, NULL); \
458       LineTo(hdc, x2, 0); \
459       GetBitmapBits(bmp, sizeof(buf), &buf); \
460       expect(atoi2(z), buf); }
461
462 static void test_ps_alternate(void)
463 {
464     HDC hdc;
465     HBITMAP bmp;
466     HPEN pen;
467     LOGBRUSH lb;
468     INT iRet;
469     HGDIOBJ hRet;
470
471     lb.lbStyle = BS_SOLID;
472     lb.lbColor = RGB(0xff,0xff,0xff);
473
474     SetLastError(0xdeadbeef);
475     pen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
476     if(pen == NULL && GetLastError() == 0xdeadbeef) {
477         skip("looks like 9x, skipping PS_ALTERNATE tests\n");
478         return;
479     }
480     ok(pen != NULL, "gle=%d\n", GetLastError());
481     hdc = CreateCompatibleDC(NULL);
482     ok(hdc != NULL, "gle=%d\n", GetLastError());
483     bmp = CreateBitmap(8, 1, 1, 1, NULL);
484     ok(bmp != NULL, "gle=%d\n", GetLastError());
485     hRet = SelectObject(hdc, bmp);
486     ok(hRet != NULL, "gle=%d\n", GetLastError());
487     hRet = SelectObject(hdc, pen);
488     ok(hRet != NULL, "gle=%d\n", GetLastError());
489     iRet = SetBkMode(hdc, TRANSPARENT);
490     ok(iRet, "gle=%d\n", GetLastError());
491
492     TEST_LINE(0, 1, "10000000")
493     TEST_LINE(0, 2, "10000000")
494     TEST_LINE(0, 3, "10100000")
495     TEST_LINE(0, 4, "10100000")
496     TEST_LINE(1, 4, "01010000")
497     TEST_LINE(1, 5, "01010000")
498     TEST_LINE(4, 8, "00001010")
499
500     DeleteObject(pen);
501     DeleteObject(bmp);
502     DeleteDC(hdc);
503 }
504
505 static void test_ps_userstyle(void)
506 {
507     static DWORD style[17] = {0, 2, 0, 4, 5, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 17};
508     static DWORD bad_style[5] = {0, 0, 0, 0, 0};
509     static DWORD bad_style2[5] = {4, 7, 8, 3, -1};
510
511     LOGBRUSH lb;
512     HPEN pen;
513     INT size, i;
514
515     struct
516     {
517         EXTLOGPEN elp;
518         DWORD style_data[15];
519     } ext_pen;
520
521     lb.lbColor = 0x00ff0000;
522     lb.lbStyle = BS_SOLID;
523     lb.lbHatch = 0;
524
525     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 3, NULL);
526     ok(pen == 0, "ExtCreatePen should fail\n");
527     expect(ERROR_INVALID_PARAMETER, GetLastError());
528     DeleteObject(pen);
529     SetLastError(0xdeadbeef);
530
531     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 0, style);
532     ok(pen == 0, "ExtCreatePen should fail\n");
533     expect2(0xdeadbeef, ERROR_INVALID_PARAMETER, GetLastError());
534     DeleteObject(pen);
535     SetLastError(0xdeadbeef);
536
537     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 17, style);
538     ok(pen == 0, "ExtCreatePen should fail\n");
539     expect(ERROR_INVALID_PARAMETER, GetLastError());
540     DeleteObject(pen);
541     SetLastError(0xdeadbeef);
542
543     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, -1, style);
544     ok(pen == 0, "ExtCreatePen should fail\n");
545     expect(0xdeadbeef, GetLastError());
546     DeleteObject(pen);
547     SetLastError(0xdeadbeef);
548
549     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style);
550     ok(pen == 0, "ExtCreatePen should fail\n");
551     expect(ERROR_INVALID_PARAMETER, GetLastError());
552     DeleteObject(pen);
553     SetLastError(0xdeadbeef);
554
555     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style2);
556     ok(pen == 0, "ExtCreatePen should fail\n");
557     expect(ERROR_INVALID_PARAMETER, GetLastError());
558     DeleteObject(pen);
559     SetLastError(0xdeadbeef);
560
561     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 16, style);
562     ok(pen != 0, "ExtCreatePen should not fail\n");
563
564     size = GetObject(pen, sizeof(ext_pen), &ext_pen);
565     expect(FIELD_OFFSET(EXTLOGPEN,elpStyleEntry[16]), size);
566
567     for(i = 0; i < 16; i++)
568         expect(style[i], ext_pen.elp.elpStyleEntry[i]);
569
570     DeleteObject(pen);
571 }
572
573 static void test_brush_pens(void)
574 {
575     char buffer[sizeof(EXTLOGPEN) + 15 * sizeof(DWORD)];
576     EXTLOGPEN *elp = (EXTLOGPEN *)buffer;
577     LOGBRUSH lb;
578     HPEN pen = 0;
579     DWORD size;
580     HBITMAP bmp = CreateBitmap( 8, 8, 1, 1, NULL );
581     BITMAPINFO *info;
582     HGLOBAL hmem;
583
584     hmem = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(*info) + 16 * 16 * 4 );
585     info = GlobalLock( hmem );
586     info->bmiHeader.biSize        = sizeof(info->bmiHeader);
587     info->bmiHeader.biWidth       = 16;
588     info->bmiHeader.biHeight      = 16;
589     info->bmiHeader.biPlanes      = 1;
590     info->bmiHeader.biBitCount    = 32;
591     info->bmiHeader.biCompression = BI_RGB;
592
593     for (lb.lbStyle = BS_SOLID; lb.lbStyle <= BS_MONOPATTERN + 1; lb.lbStyle++)
594     {
595         SetLastError( 0xdeadbeef );
596         memset( buffer, 0xcc, sizeof(buffer) );
597         trace( "testing brush style %u\n", lb.lbStyle );
598
599         switch (lb.lbStyle)
600         {
601         case BS_SOLID:
602         case BS_HATCHED:
603             lb.lbColor = RGB(12,34,56);
604             lb.lbHatch = HS_CROSS;
605             pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
606             ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
607             size = GetObject( pen, sizeof(buffer), elp );
608             ok( size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
609             ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle );
610             ok( elp->elpBrushStyle == lb.lbStyle, "wrong brush style %x\n", elp->elpBrushStyle );
611             ok( elp->elpColor == RGB(12,34,56), "wrong color %x\n", elp->elpColor );
612             ok( elp->elpHatch == HS_CROSS, "wrong hatch %lx\n", elp->elpHatch );
613             ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries );
614             break;
615
616         case BS_NULL:
617             pen = ExtCreatePen( PS_SOLID | PS_GEOMETRIC, 3, &lb, 0, NULL );
618             ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
619             size = GetObject( pen, sizeof(buffer), elp );
620             ok( size == sizeof(LOGPEN), "wrong size %u\n", size );
621             ok( ((LOGPEN *)elp)->lopnStyle == PS_NULL,
622                 "wrong pen style %x\n", ((LOGPEN *)elp)->lopnStyle );
623             ok( ((LOGPEN *)elp)->lopnColor == 0,
624                 "wrong color %x\n", ((LOGPEN *)elp)->lopnColor );
625             break;
626
627         case BS_PATTERN:
628             lb.lbColor = RGB(12,34,56);
629             lb.lbHatch = (ULONG_PTR)bmp;
630             pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
631             ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
632             size = GetObject( pen, sizeof(buffer), elp );
633             ok( size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
634             ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle );
635             ok( elp->elpBrushStyle == BS_PATTERN, "wrong brush style %x\n", elp->elpBrushStyle );
636             ok( elp->elpColor == 0, "wrong color %x\n", elp->elpColor );
637             ok( elp->elpHatch == (ULONG_PTR)bmp, "wrong hatch %lx/%p\n", elp->elpHatch, bmp );
638             ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries );
639             break;
640
641         case BS_DIBPATTERN:
642         case BS_DIBPATTERNPT:
643             lb.lbColor = DIB_PAL_COLORS;
644             lb.lbHatch = lb.lbStyle == BS_DIBPATTERN ? (ULONG_PTR)hmem : (ULONG_PTR)info;
645             pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
646             ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
647             size = GetObject( pen, sizeof(buffer), elp );
648             ok( size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
649             ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle );
650             ok( elp->elpBrushStyle == BS_DIBPATTERNPT, "wrong brush style %x\n", elp->elpBrushStyle );
651             ok( elp->elpColor == 0, "wrong color %x\n", elp->elpColor );
652             ok( elp->elpHatch == lb.lbHatch || broken(elp->elpHatch != lb.lbHatch), /* <= w2k */
653                 "wrong hatch %lx/%lx\n", elp->elpHatch, lb.lbHatch );
654             ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries );
655             break;
656
657         default:
658             pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
659             ok( !pen, "ExtCreatePen succeeded\n" );
660             ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
661             break;
662         }
663
664         if (pen) DeleteObject( pen );
665         else continue;
666
667         /* cosmetic pens require BS_SOLID */
668         SetLastError( 0xdeadbeef );
669         pen = ExtCreatePen( PS_DOT, 1, &lb, 0, NULL );
670         if (lb.lbStyle == BS_SOLID)
671         {
672             ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
673             size = GetObject( pen, sizeof(buffer), elp );
674             ok( size == FIELD_OFFSET( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
675             ok( elp->elpPenStyle == PS_DOT, "wrong pen style %x\n", elp->elpPenStyle );
676             ok( elp->elpBrushStyle == BS_SOLID, "wrong brush style %x\n", elp->elpBrushStyle );
677             ok( elp->elpColor == RGB(12,34,56), "wrong color %x\n", elp->elpColor );
678             ok( elp->elpHatch == HS_CROSS, "wrong hatch %lx\n", elp->elpHatch );
679             DeleteObject( pen );
680         }
681         else
682         {
683             ok( !pen, "ExtCreatePen succeeded\n" );
684             ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
685         }
686     }
687
688     GlobalUnlock( hmem );
689     GlobalFree( hmem );
690     DeleteObject( bmp );
691 }
692
693 START_TEST(pen)
694 {
695     test_logpen();
696     test_brush_pens();
697     test_ps_alternate();
698     test_ps_userstyle();
699 }