mshtml: Wine Gecko 1.4 release.
[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     };
58     INT i, size;
59     HPEN hpen;
60     LOGPEN lp;
61     EXTLOGPEN elp;
62     LOGBRUSH lb;
63     DWORD_PTR unset_hatch;
64     DWORD obj_type, user_style[2] = { 0xabc, 0xdef };
65     char elp_buffer[128];
66     EXTLOGPEN *ext_pen = (EXTLOGPEN *)elp_buffer;
67     DWORD *ext_style = ext_pen->elpStyleEntry;
68
69     for (i = 0; i < sizeof(pen)/sizeof(pen[0]); i++)
70     {
71         trace("%d: testing style %u\n", i, pen[i].style);
72
73         /********************** cosmetic pens **********************/
74         /* CreatePenIndirect behaviour */
75         lp.lopnStyle = pen[i].style,
76         lp.lopnWidth.x = pen[i].width;
77         lp.lopnWidth.y = 11; /* just in case */
78         lp.lopnColor = pen[i].color;
79         SetLastError(0xdeadbeef);
80         hpen = CreatePenIndirect(&lp);
81         if(hpen == 0 && GetLastError() == ERROR_INVALID_PARAMETER)
82         {
83             win_skip("No support for pen style %u (%d)\n", pen[i].style, i);
84             continue;
85         }
86
87         obj_type = GetObjectType(hpen);
88         ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
89
90         memset(&lp, 0xb0, sizeof(lp));
91         SetLastError(0xdeadbeef);
92         size = GetObject(hpen, sizeof(lp), &lp);
93         ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
94
95         if (pen[i].style == PS_USERSTYLE || pen[i].style == PS_ALTERNATE)
96         {
97            if (lp.lopnStyle == pen[i].style)
98            {
99                win_skip("Skipping PS_USERSTYLE and PS_ALTERNATE tests on Win9x\n");
100                continue;
101            }
102         }
103         ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
104         ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
105         ok(lp.lopnWidth.y == 0 ||
106             broken(lp.lopnWidth.y == 0xb), /* Win9x */
107             "expected 0, got %d\n", lp.lopnWidth.y);
108         ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
109
110         DeleteObject(hpen);
111
112         /* CreatePen behaviour */
113         SetLastError(0xdeadbeef);
114         hpen = CreatePen(pen[i].style, pen[i].width, pen[i].color);
115         ok(hpen != 0, "CreatePen error %d\n", GetLastError());
116
117         obj_type = GetObjectType(hpen);
118         ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
119
120         /* check what's the real size of the object */
121         size = GetObject(hpen, 0, NULL);
122         ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
123
124         /* ask for truncated data */
125         memset(&lp, 0xb0, sizeof(lp));
126         SetLastError(0xdeadbeef);
127         size = GetObject(hpen, sizeof(lp.lopnStyle), &lp);
128         ok(!size ||
129             broken(size == sizeof(lp.lopnStyle)), /* Win9x */
130             "GetObject should fail: size %d, error %d\n", size, GetLastError());
131
132         /* see how larger buffer sizes are handled */
133         memset(&lp, 0xb0, sizeof(lp));
134         SetLastError(0xdeadbeef);
135         size = GetObject(hpen, sizeof(lp) * 4, &lp);
136         ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
137
138         /* see how larger buffer sizes are handled */
139         memset(&elp, 0xb0, sizeof(elp));
140         SetLastError(0xdeadbeef);
141         size = GetObject(hpen, sizeof(elp) * 2, &elp);
142         ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
143
144         memset(&lp, 0xb0, sizeof(lp));
145         SetLastError(0xdeadbeef);
146         size = GetObject(hpen, sizeof(lp), &lp);
147         ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
148
149         ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
150         ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
151         ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
152         ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
153
154         memset(&elp, 0xb0, sizeof(elp));
155         SetLastError(0xdeadbeef);
156         size = GetObject(hpen, sizeof(elp), &elp);
157
158         /* for some reason XP differentiates PS_NULL here */
159         if (pen[i].style == PS_NULL)
160         {
161             ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n");
162             ok(size == sizeof(EXTLOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
163             ok(elp.elpPenStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, elp.elpPenStyle);
164             ok(elp.elpWidth == 0, "expected 0, got %u\n", elp.elpWidth);
165             ok(elp.elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, elp.elpColor);
166             ok(elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %u\n", elp.elpBrushStyle);
167             ok(elp.elpHatch == 0, "expected 0, got %p\n", (void *)elp.elpHatch);
168             ok(elp.elpNumEntries == 0, "expected 0, got %x\n", elp.elpNumEntries);
169         }
170         else
171         {
172             ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
173             memcpy(&lp, &elp, sizeof(lp));
174             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
175             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
176             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
177             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
178         }
179
180         DeleteObject(hpen);
181
182         /********** cosmetic pens created by ExtCreatePen ***********/
183         lb.lbStyle = BS_SOLID;
184         lb.lbColor = pen[i].color;
185         lb.lbHatch = HS_CROSS; /* just in case */
186         SetLastError(0xdeadbeef);
187         hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 2, user_style);
188         if (pen[i].style != PS_USERSTYLE)
189         {
190             ok(hpen == 0, "ExtCreatePen should fail\n");
191             ok(GetLastError() == ERROR_INVALID_PARAMETER,
192                "wrong last error value %d\n", GetLastError());
193             SetLastError(0xdeadbeef);
194             hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 0, NULL);
195             if (pen[i].style != PS_NULL)
196             {
197                 ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
198                 ok(GetLastError() == ERROR_INVALID_PARAMETER,
199                    "wrong last error value %d\n", GetLastError());
200
201                 SetLastError(0xdeadbeef);
202                 hpen = ExtCreatePen(pen[i].style, 1, &lb, 0, NULL);
203             }
204         }
205         else
206         {
207             ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
208             ok(GetLastError() == ERROR_INVALID_PARAMETER,
209                "wrong last error value %d\n", GetLastError());
210             SetLastError(0xdeadbeef);
211             hpen = ExtCreatePen(pen[i].style, 1, &lb, 2, user_style);
212         }
213         if (pen[i].style == PS_INSIDEFRAME)
214         {
215             /* This style is applicable only for geometric pens */
216             ok(hpen == 0, "ExtCreatePen should fail\n");
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 == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style) ||
243                broken(size == 0 && GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
244                "GetObject returned %d, error %d\n", size, GetLastError());
245             break;
246
247         default:
248             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) ||
249                broken(size == sizeof(LOGPEN)) || /* Win9x */
250                broken(pen[i].style == PS_ALTERNATE &&
251                       size == 0 &&
252                       GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
253                "GetObject returned %d, error %d\n", size, GetLastError());
254             break;
255         }
256
257         /* ask for truncated data */
258         memset(&elp, 0xb0, sizeof(elp));
259         SetLastError(0xdeadbeef);
260         size = GetObject(hpen, sizeof(elp.elpPenStyle), &elp);
261         ok(!size ||
262             broken(size == sizeof(elp.elpPenStyle)), /* Win9x */
263             "GetObject should fail: size %d, error %d\n", size, GetLastError());
264
265         /* see how larger buffer sizes are handled */
266         memset(elp_buffer, 0xb0, sizeof(elp_buffer));
267         SetLastError(0xdeadbeef);
268         size = GetObject(hpen, sizeof(elp_buffer), elp_buffer);
269         switch (pen[i].style)
270         {
271         case PS_NULL:
272             ok(size == sizeof(LOGPEN),
273                "GetObject returned %d, error %d\n", size, GetLastError());
274             memcpy(&lp, ext_pen, sizeof(lp));
275             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
276             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
277             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
278             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
279
280             /* for PS_NULL it also works this way */
281             memset(&elp, 0xb0, sizeof(elp));
282             memset(&unset_hatch, 0xb0, sizeof(unset_hatch));
283             SetLastError(0xdeadbeef);
284             size = GetObject(hpen, sizeof(elp), &elp);
285             ok(size == sizeof(EXTLOGPEN),
286                 "GetObject returned %d, error %d\n", size, GetLastError());
287             ok(ext_pen->elpHatch == unset_hatch, "expected 0xb0b0b0b0, got %p\n", (void *)ext_pen->elpHatch);
288             ok(ext_pen->elpNumEntries == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %x\n", ext_pen->elpNumEntries);
289             break;
290
291         case PS_USERSTYLE:
292             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
293                "GetObject returned %d, error %d\n", size, GetLastError());
294             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
295             ok(ext_pen->elpNumEntries == 2, "expected 0, got %x\n", ext_pen->elpNumEntries);
296             ok(ext_style[0] == 0xabc, "expected 0xabc, got %x\n", ext_style[0]);
297             ok(ext_style[1] == 0xdef, "expected 0xdef, got %x\n", ext_style[1]);
298             break;
299
300         default:
301             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) ||
302                broken(size == sizeof(LOGPEN)) || /* Win9x */
303                broken(pen[i].style == PS_ALTERNATE &&
304                       size == 0 &&
305                       GetLastError() == ERROR_INVALID_PARAMETER), /* Win9x */
306                "GetObject returned %d, error %d\n", size, GetLastError());
307             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
308             ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
309             break;
310         }
311
312         ok(ext_pen->elpPenStyle == pen[i].style, "expected %x, got %x\n", pen[i].style, ext_pen->elpPenStyle);
313         ok(ext_pen->elpWidth == 1, "expected 1, got %x\n", ext_pen->elpWidth);
314         ok(ext_pen->elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen->elpColor);
315         ok(ext_pen->elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen->elpBrushStyle);
316
317         DeleteObject(hpen);
318
319 test_geometric_pens:
320         /********************** geometric pens **********************/
321         lb.lbStyle = BS_SOLID;
322         lb.lbColor = pen[i].color;
323         lb.lbHatch = HS_CROSS; /* just in case */
324         SetLastError(0xdeadbeef);
325         hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 2, user_style);
326         if (pen[i].style != PS_USERSTYLE)
327         {
328             ok(hpen == 0, "ExtCreatePen should fail\n");
329             SetLastError(0xdeadbeef);
330             hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 0, NULL);
331         }
332         if (pen[i].style == PS_ALTERNATE)
333         {
334             /* This style is applicable only for cosmetic pens */
335             ok(hpen == 0, "ExtCreatePen should fail\n");
336             continue;
337         }
338         ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError());
339
340         obj_type = GetObjectType(hpen);
341         /* for some reason XP differentiates PS_NULL here */
342         if (pen[i].style == PS_NULL)
343             ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
344         else
345             ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type);
346
347         /* check what's the real size of the object */
348         size = GetObject(hpen, 0, NULL);
349         switch (pen[i].style)
350         {
351         case PS_NULL:
352             ok(size == sizeof(LOGPEN),
353                "GetObject returned %d, error %d\n", size, GetLastError());
354             break;
355
356         case PS_USERSTYLE:
357             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
358                "GetObject returned %d, error %d\n", size, GetLastError());
359             break;
360
361         default:
362             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry),
363                "GetObject returned %d, error %d\n", size, GetLastError());
364             break;
365         }
366
367         /* ask for truncated data */
368         memset(&lp, 0xb0, sizeof(lp));
369         SetLastError(0xdeadbeef);
370         size = GetObject(hpen, sizeof(lp.lopnStyle), &lp);
371         ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
372
373         memset(&lp, 0xb0, sizeof(lp));
374         SetLastError(0xdeadbeef);
375         size = GetObject(hpen, sizeof(lp), &lp);
376         /* for some reason XP differentiates PS_NULL here */
377         if (pen[i].style == PS_NULL)
378         {
379             ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
380             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
381             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
382             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
383             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
384         }
385         else
386             /* XP doesn't set last error here */
387             ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
388                "GetObject should fail: size %d, error %d\n", size, GetLastError());
389
390         memset(elp_buffer, 0xb0, sizeof(elp_buffer));
391         SetLastError(0xdeadbeef);
392         /* buffer is too small for user styles */
393         size = GetObject(hpen, sizeof(EXTLOGPEN), elp_buffer);
394         switch (pen[i].style)
395         {
396         case PS_NULL:
397             ok(size == sizeof(EXTLOGPEN),
398                 "GetObject returned %d, error %d\n", size, GetLastError());
399             ok(ext_pen->elpHatch == 0, "expected 0, got %p\n", (void *)ext_pen->elpHatch);
400             ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
401
402             /* for PS_NULL it also works this way */
403             SetLastError(0xdeadbeef);
404             size = GetObject(hpen, sizeof(elp_buffer), &lp);
405             ok(size == sizeof(LOGPEN),
406                 "GetObject returned %d, error %d\n", size, GetLastError());
407             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
408             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
409             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
410             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
411             break;
412
413         case PS_USERSTYLE:
414             ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
415                "GetObject should fail: size %d, error %d\n", size, GetLastError());
416             size = GetObject(hpen, sizeof(elp_buffer), elp_buffer);
417             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
418                "GetObject returned %d, error %d\n", size, GetLastError());
419             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
420             ok(ext_pen->elpNumEntries == 2, "expected 0, got %x\n", ext_pen->elpNumEntries);
421             ok(ext_style[0] == 0xabc, "expected 0xabc, got %x\n", ext_style[0]);
422             ok(ext_style[1] == 0xdef, "expected 0xdef, got %x\n", ext_style[1]);
423             break;
424
425         default:
426             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry),
427                "GetObject returned %d, error %d\n", size, GetLastError());
428             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
429             ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
430             break;
431         }
432
433         /* for some reason XP differentiates PS_NULL here */
434         if (pen[i].style == PS_NULL)
435             ok(ext_pen->elpPenStyle == pen[i].ret_style, "expected %x, got %x\n", pen[i].ret_style, ext_pen->elpPenStyle);
436         else
437         {
438             ok(ext_pen->elpPenStyle == (PS_GEOMETRIC | pen[i].style), "expected %x, got %x\n", PS_GEOMETRIC | pen[i].style, ext_pen->elpPenStyle);
439         }
440
441         if (pen[i].style == PS_NULL)
442             ok(ext_pen->elpWidth == 0, "expected 0, got %x\n", ext_pen->elpWidth);
443         else
444             ok(ext_pen->elpWidth == pen[i].ret_width, "expected %u, got %x\n", pen[i].ret_width, ext_pen->elpWidth);
445         ok(ext_pen->elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen->elpColor);
446         ok(ext_pen->elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen->elpBrushStyle);
447
448         DeleteObject(hpen);
449     }
450 }
451
452 static unsigned int atoi2(const char *s)
453 {
454     unsigned int ret = 0;
455     while(*s) ret = (ret << 1) | (*s++ == '1');
456     return ret;
457 }
458
459 #define TEST_LINE(x1, x2, z) \
460     { int buf = 0; \
461       SetBitmapBits(bmp, sizeof(buf), &buf); \
462       MoveToEx(hdc, x1, 0, NULL); \
463       LineTo(hdc, x2, 0); \
464       GetBitmapBits(bmp, sizeof(buf), &buf); \
465       expect(atoi2(z), buf); }
466
467 static void test_ps_alternate(void)
468 {
469     HDC hdc;
470     HBITMAP bmp;
471     HPEN pen;
472     LOGBRUSH lb;
473     INT iRet;
474     HGDIOBJ hRet;
475
476     lb.lbStyle = BS_SOLID;
477     lb.lbColor = RGB(0xff,0xff,0xff);
478
479     SetLastError(0xdeadbeef);
480     pen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
481     if(pen == NULL && GetLastError() == 0xdeadbeef) {
482         skip("looks like 9x, skipping PS_ALTERNATE tests\n");
483         return;
484     }
485     ok(pen != NULL, "gle=%d\n", GetLastError());
486     hdc = CreateCompatibleDC(NULL);
487     ok(hdc != NULL, "gle=%d\n", GetLastError());
488     bmp = CreateBitmap(8, 1, 1, 1, NULL);
489     ok(bmp != NULL, "gle=%d\n", GetLastError());
490     hRet = SelectObject(hdc, bmp);
491     ok(hRet != NULL, "gle=%d\n", GetLastError());
492     hRet = SelectObject(hdc, pen);
493     ok(hRet != NULL, "gle=%d\n", GetLastError());
494     iRet = SetBkMode(hdc, TRANSPARENT);
495     ok(iRet, "gle=%d\n", GetLastError());
496
497     TEST_LINE(0, 1, "10000000")
498     TEST_LINE(0, 2, "10000000")
499     TEST_LINE(0, 3, "10100000")
500     TEST_LINE(0, 4, "10100000")
501     TEST_LINE(1, 4, "01010000")
502     TEST_LINE(1, 5, "01010000")
503     TEST_LINE(4, 8, "00001010")
504
505     DeleteObject(pen);
506     DeleteObject(bmp);
507     DeleteDC(hdc);
508 }
509
510 static void test_ps_userstyle(void)
511 {
512     static DWORD style[17] = {0, 2, 0, 4, 5, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 17};
513     static DWORD bad_style[5] = {0, 0, 0, 0, 0};
514     static DWORD bad_style2[5] = {4, 7, 8, 3, -1};
515
516     LOGBRUSH lb;
517     HPEN pen;
518     INT size, i;
519
520     struct
521     {
522         EXTLOGPEN elp;
523         DWORD style_data[15];
524     } ext_pen;
525
526     lb.lbColor = 0x00ff0000;
527     lb.lbStyle = BS_SOLID;
528     lb.lbHatch = 0;
529
530     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 3, NULL);
531     ok(pen == 0, "ExtCreatePen should fail\n");
532     if (pen == 0 && GetLastError() == 0xdeadbeef)
533     {
534         win_skip("Looks like 9x, skipping PS_USERSTYLE tests\n");
535         return;
536     }
537     expect(ERROR_INVALID_PARAMETER, GetLastError());
538     DeleteObject(pen);
539     SetLastError(0xdeadbeef);
540
541     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 0, style);
542     ok(pen == 0, "ExtCreatePen should fail\n");
543     expect2(0xdeadbeef, ERROR_INVALID_PARAMETER, GetLastError());
544     DeleteObject(pen);
545     SetLastError(0xdeadbeef);
546
547     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 17, style);
548     ok(pen == 0, "ExtCreatePen should fail\n");
549     expect(ERROR_INVALID_PARAMETER, GetLastError());
550     DeleteObject(pen);
551     SetLastError(0xdeadbeef);
552
553     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, -1, style);
554     ok(pen == 0, "ExtCreatePen should fail\n");
555     expect(0xdeadbeef, GetLastError());
556     DeleteObject(pen);
557     SetLastError(0xdeadbeef);
558
559     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style);
560     ok(pen == 0, "ExtCreatePen should fail\n");
561     expect(ERROR_INVALID_PARAMETER, GetLastError());
562     DeleteObject(pen);
563     SetLastError(0xdeadbeef);
564
565     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style2);
566     ok(pen == 0, "ExtCreatePen should fail\n");
567     expect(ERROR_INVALID_PARAMETER, GetLastError());
568     DeleteObject(pen);
569     SetLastError(0xdeadbeef);
570
571     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 16, style);
572     ok(pen != 0, "ExtCreatePen should not fail\n");
573
574     size = GetObject(pen, sizeof(ext_pen), &ext_pen);
575     expect(FIELD_OFFSET(EXTLOGPEN,elpStyleEntry[16]), size);
576
577     for(i = 0; i < 16; i++)
578         expect(style[i], ext_pen.elp.elpStyleEntry[i]);
579
580     DeleteObject(pen);
581 }
582
583 START_TEST(pen)
584 {
585     test_logpen();
586     test_ps_alternate();
587     test_ps_userstyle();
588 }