gdi32: Add support for DIBINDEX colors in 1-bpp blits.
[wine.git] / dlls / gdi32 / tests / pen.c
blob43f00d8f50fbe1fd175639c9fbe2b6cf9014dc57
1 /*
2 * Unit test suite for pens
4 * Copyright 2006 Dmitry Timoshkov
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.
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.
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
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
28 #include "wine/test.h"
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)
34 static void test_logpen(void)
36 static const struct
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) },
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;
75 for (i = 0; i < sizeof(pen)/sizeof(pen[0]); i++)
77 trace("%d: testing style %u\n", i, pen[i].style);
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)
89 win_skip("No support for pen style %u (%d)\n", pen[i].style, i);
90 continue;
93 obj_type = GetObjectType(hpen);
94 ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
96 memset(&lp, 0xb0, sizeof(lp));
97 SetLastError(0xdeadbeef);
98 size = GetObjectW(hpen, sizeof(lp), &lp);
99 ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
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);
106 DeleteObject(hpen);
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());
113 obj_type = GetObjectType(hpen);
114 ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
116 /* check what's the real size of the object */
117 size = GetObjectW(hpen, 0, NULL);
118 ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
120 /* ask for truncated data */
121 memset(&lp, 0xb0, sizeof(lp));
122 SetLastError(0xdeadbeef);
123 size = GetObjectW(hpen, sizeof(lp.lopnStyle), &lp);
124 ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
126 /* see how larger buffer sizes are handled */
127 memset(&lp, 0xb0, sizeof(lp));
128 SetLastError(0xdeadbeef);
129 size = GetObjectW(hpen, sizeof(lp) * 4, &lp);
130 ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
132 /* see how larger buffer sizes are handled */
133 memset(&elp, 0xb0, sizeof(elp));
134 SetLastError(0xdeadbeef);
135 size = GetObjectW(hpen, sizeof(elp) * 2, &elp);
136 ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
138 memset(&lp, 0xb0, sizeof(lp));
139 SetLastError(0xdeadbeef);
140 size = GetObjectW(hpen, sizeof(lp), &lp);
141 ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
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);
148 memset(&elp, 0xb0, sizeof(elp));
149 SetLastError(0xdeadbeef);
150 size = GetObjectW(hpen, sizeof(elp), &elp);
152 /* for some reason XP differentiates PS_NULL here */
153 if (pen[i].style == PS_NULL)
155 ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n");
156 ok(size == offsetof(EXTLOGPEN, elpStyleEntry[1]), "GetObject returned %d, error %d\n",
157 size, GetLastError());
158 ok(elp.elpPenStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, elp.elpPenStyle);
159 ok(elp.elpWidth == 0, "expected 0, got %u\n", elp.elpWidth);
160 ok(elp.elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, elp.elpColor);
161 ok(elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %u\n", elp.elpBrushStyle);
162 ok(elp.elpHatch == 0, "expected 0, got %p\n", (void *)elp.elpHatch);
163 ok(elp.elpNumEntries == 0, "expected 0, got %x\n", elp.elpNumEntries);
165 else
167 ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
168 memcpy(&lp, &elp, sizeof(lp));
169 ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
170 ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
171 ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
172 ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
175 DeleteObject(hpen);
177 /********** cosmetic pens created by ExtCreatePen ***********/
178 lb.lbStyle = BS_SOLID;
179 lb.lbColor = pen[i].color;
180 lb.lbHatch = HS_CROSS; /* just in case */
181 SetLastError(0xdeadbeef);
182 hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 2, user_style);
183 if (pen[i].style != PS_USERSTYLE)
185 ok(hpen == 0, "ExtCreatePen should fail\n");
186 ok(GetLastError() == ERROR_INVALID_PARAMETER,
187 "wrong last error value %d\n", GetLastError());
188 SetLastError(0xdeadbeef);
189 hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 0, NULL);
190 if (pen[i].style != PS_NULL)
192 ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
193 ok(GetLastError() == ERROR_INVALID_PARAMETER,
194 "wrong last error value %d\n", GetLastError());
196 SetLastError(0xdeadbeef);
197 hpen = ExtCreatePen(pen[i].style, 1, &lb, 0, NULL);
200 else
202 ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
203 ok(GetLastError() == ERROR_INVALID_PARAMETER,
204 "wrong last error value %d\n", GetLastError());
205 SetLastError(0xdeadbeef);
206 hpen = ExtCreatePen(pen[i].style, 1, &lb, 2, user_style);
208 if (pen[i].style == PS_INSIDEFRAME)
210 /* This style is applicable only for geometric pens */
211 ok(hpen == 0, "ExtCreatePen should fail\n");
212 goto test_geometric_pens;
214 if (pen[i].style > PS_ALTERNATE)
216 ok(hpen == 0, "ExtCreatePen should fail\n");
217 ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong last error value %d\n", GetLastError());
218 goto test_geometric_pens;
220 ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError());
222 obj_type = GetObjectType(hpen);
223 /* for some reason XP differentiates PS_NULL here */
224 if (pen[i].style == PS_NULL)
226 ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
227 ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n");
229 else
230 ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type);
232 /* check what's the real size of the object */
233 SetLastError(0xdeadbeef);
234 size = GetObjectW(hpen, 0, NULL);
235 switch (pen[i].style)
237 case PS_NULL:
238 ok(size == sizeof(LOGPEN),
239 "GetObject returned %d, error %d\n", size, GetLastError());
240 break;
242 case PS_USERSTYLE:
243 ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ),
244 "GetObject returned %d, error %d\n", size, GetLastError());
245 break;
247 default:
248 ok(size == offsetof( EXTLOGPEN, elpStyleEntry ),
249 "GetObject returned %d, error %d\n", size, GetLastError());
250 break;
253 /* ask for truncated data */
254 memset(&elp, 0xb0, sizeof(elp));
255 SetLastError(0xdeadbeef);
256 size = GetObjectW(hpen, sizeof(elp.elpPenStyle), &elp);
257 ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
259 /* see how larger buffer sizes are handled */
260 memset(elp_buffer, 0xb0, sizeof(elp_buffer));
261 SetLastError(0xdeadbeef);
262 size = GetObjectW(hpen, sizeof(elp_buffer), elp_buffer);
263 switch (pen[i].style)
265 case PS_NULL:
266 ok(size == sizeof(LOGPEN),
267 "GetObject returned %d, error %d\n", size, GetLastError());
268 memcpy(&lp, ext_pen, sizeof(lp));
269 ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
270 ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
271 ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
272 ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
274 /* for PS_NULL it also works this way */
275 memset(&elp, 0xb0, sizeof(elp));
276 memset(&unset_hatch, 0xb0, sizeof(unset_hatch));
277 SetLastError(0xdeadbeef);
278 size = GetObjectW(hpen, sizeof(elp), &elp);
279 ok(size == offsetof(EXTLOGPEN, elpStyleEntry[1]),
280 "GetObject returned %d, error %d\n", size, GetLastError());
281 ok(ext_pen->elpHatch == unset_hatch, "expected 0xb0b0b0b0, got %p\n", (void *)ext_pen->elpHatch);
282 ok(ext_pen->elpNumEntries == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %x\n", ext_pen->elpNumEntries);
283 break;
285 case PS_USERSTYLE:
286 ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ),
287 "GetObject returned %d, error %d\n", size, GetLastError());
288 ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
289 ok(ext_pen->elpNumEntries == 2, "expected 0, got %x\n", ext_pen->elpNumEntries);
290 ok(ext_style[0] == 0xabc, "expected 0xabc, got %x\n", ext_style[0]);
291 ok(ext_style[1] == 0xdef, "expected 0xdef, got %x\n", ext_style[1]);
292 break;
294 default:
295 ok(size == offsetof( EXTLOGPEN, elpStyleEntry ),
296 "GetObject returned %d, error %d\n", size, GetLastError());
297 ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
298 ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
299 break;
302 ok(ext_pen->elpPenStyle == pen[i].style, "expected %x, got %x\n", pen[i].style, ext_pen->elpPenStyle);
303 ok(ext_pen->elpWidth == 1, "expected 1, got %x\n", ext_pen->elpWidth);
304 ok(ext_pen->elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen->elpColor);
305 ok(ext_pen->elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen->elpBrushStyle);
307 DeleteObject(hpen);
309 test_geometric_pens:
310 /********************** geometric pens **********************/
311 lb.lbStyle = BS_SOLID;
312 lb.lbColor = pen[i].color;
313 lb.lbHatch = HS_CROSS; /* just in case */
314 SetLastError(0xdeadbeef);
315 hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 2, user_style);
316 if (pen[i].style != PS_USERSTYLE)
318 ok(hpen == 0, "ExtCreatePen should fail\n");
319 SetLastError(0xdeadbeef);
320 hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 0, NULL);
322 if (pen[i].style == PS_ALTERNATE)
324 /* This style is applicable only for cosmetic pens */
325 ok(hpen == 0, "ExtCreatePen should fail\n");
326 continue;
328 if (pen[i].style > PS_ALTERNATE)
330 ok(hpen == 0, "ExtCreatePen should fail\n");
331 ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong last error value %d\n", GetLastError());
332 continue;
334 ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError());
336 obj_type = GetObjectType(hpen);
337 /* for some reason XP differentiates PS_NULL here */
338 if (pen[i].style == PS_NULL)
339 ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
340 else
341 ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type);
343 /* check what's the real size of the object */
344 size = GetObjectW(hpen, 0, NULL);
345 switch (pen[i].style)
347 case PS_NULL:
348 ok(size == sizeof(LOGPEN),
349 "GetObject returned %d, error %d\n", size, GetLastError());
350 break;
352 case PS_USERSTYLE:
353 ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ),
354 "GetObject returned %d, error %d\n", size, GetLastError());
355 break;
357 default:
358 ok(size == offsetof( EXTLOGPEN, elpStyleEntry ),
359 "GetObject returned %d, error %d\n", size, GetLastError());
360 break;
363 /* ask for truncated data */
364 memset(&lp, 0xb0, sizeof(lp));
365 SetLastError(0xdeadbeef);
366 size = GetObjectW(hpen, sizeof(lp.lopnStyle), &lp);
367 ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
369 memset(&lp, 0xb0, sizeof(lp));
370 SetLastError(0xdeadbeef);
371 size = GetObjectW(hpen, sizeof(lp), &lp);
372 /* for some reason XP differentiates PS_NULL here */
373 if (pen[i].style == PS_NULL)
375 ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
376 ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
377 ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
378 ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
379 ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
381 else
382 /* XP doesn't set last error here */
383 ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
384 "GetObject should fail: size %d, error %d\n", size, GetLastError());
386 memset(elp_buffer, 0xb0, sizeof(elp_buffer));
387 SetLastError(0xdeadbeef);
388 /* buffer is too small for user styles */
389 size = GetObjectW(hpen, offsetof(EXTLOGPEN, elpStyleEntry[1]), elp_buffer);
390 switch (pen[i].style)
392 case PS_NULL:
393 ok(size == offsetof(EXTLOGPEN, elpStyleEntry[1]),
394 "GetObject returned %d, error %d\n", size, GetLastError());
395 ok(ext_pen->elpHatch == 0, "expected 0, got %p\n", (void *)ext_pen->elpHatch);
396 ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
398 /* for PS_NULL it also works this way */
399 SetLastError(0xdeadbeef);
400 size = GetObjectW(hpen, sizeof(elp_buffer), &lp);
401 ok(size == sizeof(LOGPEN),
402 "GetObject returned %d, error %d\n", size, GetLastError());
403 ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
404 ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
405 ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
406 ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
407 break;
409 case PS_USERSTYLE:
410 ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
411 "GetObject should fail: size %d, error %d\n", size, GetLastError());
412 size = GetObjectW(hpen, sizeof(elp_buffer), elp_buffer);
413 ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ),
414 "GetObject returned %d, error %d\n", size, GetLastError());
415 ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
416 ok(ext_pen->elpNumEntries == 2, "expected 0, got %x\n", ext_pen->elpNumEntries);
417 ok(ext_style[0] == 0xabc, "expected 0xabc, got %x\n", ext_style[0]);
418 ok(ext_style[1] == 0xdef, "expected 0xdef, got %x\n", ext_style[1]);
419 break;
421 default:
422 ok(size == offsetof( EXTLOGPEN, elpStyleEntry ),
423 "GetObject returned %d, error %d\n", size, GetLastError());
424 ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
425 ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
426 break;
429 /* for some reason XP differentiates PS_NULL here */
430 if (pen[i].style == PS_NULL)
431 ok(ext_pen->elpPenStyle == pen[i].ret_style, "expected %x, got %x\n", pen[i].ret_style, ext_pen->elpPenStyle);
432 else
434 ok(ext_pen->elpPenStyle == (PS_GEOMETRIC | pen[i].style), "expected %x, got %x\n", PS_GEOMETRIC | pen[i].style, ext_pen->elpPenStyle);
437 if (pen[i].style == PS_NULL)
438 ok(ext_pen->elpWidth == 0, "expected 0, got %x\n", ext_pen->elpWidth);
439 else
440 ok(ext_pen->elpWidth == pen[i].ret_width, "expected %u, got %x\n", pen[i].ret_width, ext_pen->elpWidth);
441 ok(ext_pen->elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen->elpColor);
442 ok(ext_pen->elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen->elpBrushStyle);
444 DeleteObject(hpen);
448 static unsigned int atoi2(const char *s)
450 unsigned int ret = 0;
451 while(*s) ret = (ret << 1) | (*s++ == '1');
452 return ret;
455 #define TEST_LINE(x1, x2, z) \
456 { int buf = 0; \
457 SetBitmapBits(bmp, sizeof(buf), &buf); \
458 MoveToEx(hdc, x1, 0, NULL); \
459 LineTo(hdc, x2, 0); \
460 GetBitmapBits(bmp, sizeof(buf), &buf); \
461 expect(atoi2(z), buf); }
463 static void test_ps_alternate(void)
465 HDC hdc;
466 HBITMAP bmp;
467 HPEN pen;
468 LOGBRUSH lb;
469 INT iRet;
470 HGDIOBJ hRet;
472 lb.lbStyle = BS_SOLID;
473 lb.lbColor = RGB(0xff,0xff,0xff);
475 SetLastError(0xdeadbeef);
476 pen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
477 if(pen == NULL && GetLastError() == 0xdeadbeef) {
478 skip("looks like 9x, skipping PS_ALTERNATE tests\n");
479 return;
481 ok(pen != NULL, "gle=%d\n", GetLastError());
482 hdc = CreateCompatibleDC(NULL);
483 ok(hdc != NULL, "gle=%d\n", GetLastError());
484 bmp = CreateBitmap(8, 1, 1, 1, NULL);
485 ok(bmp != NULL, "gle=%d\n", GetLastError());
486 hRet = SelectObject(hdc, bmp);
487 ok(hRet != NULL, "gle=%d\n", GetLastError());
488 hRet = SelectObject(hdc, pen);
489 ok(hRet != NULL, "gle=%d\n", GetLastError());
490 iRet = SetBkMode(hdc, TRANSPARENT);
491 ok(iRet, "gle=%d\n", GetLastError());
493 TEST_LINE(0, 1, "10000000")
494 TEST_LINE(0, 2, "10000000")
495 TEST_LINE(0, 3, "10100000")
496 TEST_LINE(0, 4, "10100000")
497 TEST_LINE(1, 4, "01010000")
498 TEST_LINE(1, 5, "01010000")
499 TEST_LINE(4, 8, "00001010")
501 DeleteObject(pen);
502 DeleteObject(bmp);
503 DeleteDC(hdc);
506 static void test_ps_userstyle(void)
508 static DWORD style[17] = {0, 2, 0, 4, 5, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 17};
509 static DWORD bad_style[5] = {0, 0, 0, 0, 0};
510 static DWORD bad_style2[5] = {4, 7, 8, 3, -1};
512 LOGBRUSH lb;
513 HPEN pen;
514 INT size, i;
515 char buffer[offsetof(EXTLOGPEN, elpStyleEntry) + 16 * sizeof(DWORD)];
516 EXTLOGPEN *ext_pen = (EXTLOGPEN *)buffer;
518 lb.lbColor = 0x00ff0000;
519 lb.lbStyle = BS_SOLID;
520 lb.lbHatch = 0;
522 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 3, NULL);
523 ok(pen == 0, "ExtCreatePen should fail\n");
524 expect(ERROR_INVALID_PARAMETER, GetLastError());
525 DeleteObject(pen);
526 SetLastError(0xdeadbeef);
528 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 0, style);
529 ok(pen == 0, "ExtCreatePen should fail\n");
530 expect2(0xdeadbeef, ERROR_INVALID_PARAMETER, GetLastError());
531 DeleteObject(pen);
532 SetLastError(0xdeadbeef);
534 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 17, style);
535 ok(pen == 0, "ExtCreatePen should fail\n");
536 expect(ERROR_INVALID_PARAMETER, GetLastError());
537 DeleteObject(pen);
538 SetLastError(0xdeadbeef);
540 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, -1, style);
541 ok(pen == 0, "ExtCreatePen should fail\n");
542 expect(0xdeadbeef, GetLastError());
543 DeleteObject(pen);
544 SetLastError(0xdeadbeef);
546 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style);
547 ok(pen == 0, "ExtCreatePen should fail\n");
548 expect(ERROR_INVALID_PARAMETER, GetLastError());
549 DeleteObject(pen);
550 SetLastError(0xdeadbeef);
552 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style2);
553 ok(pen == 0, "ExtCreatePen should fail\n");
554 expect(ERROR_INVALID_PARAMETER, GetLastError());
555 DeleteObject(pen);
556 SetLastError(0xdeadbeef);
558 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 16, style);
559 ok(pen != 0, "ExtCreatePen should not fail\n");
561 size = GetObjectW(pen, sizeof(buffer), ext_pen);
562 ok(size == offsetof(EXTLOGPEN, elpStyleEntry[16]), "wrong size %d\n", size);
564 for(i = 0; i < 16; i++)
565 expect(style[i], ext_pen->elpStyleEntry[i]);
567 DeleteObject(pen);
570 static void test_brush_pens(void)
572 char buffer[offsetof(EXTLOGPEN, elpStyleEntry) + 16 * sizeof(DWORD)];
573 EXTLOGPEN *elp = (EXTLOGPEN *)buffer;
574 LOGBRUSH lb;
575 HPEN pen = 0;
576 DWORD size;
577 HBITMAP bmp = CreateBitmap( 8, 8, 1, 1, NULL );
578 BITMAPINFO *info;
579 HGLOBAL hmem;
581 hmem = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(*info) + 16 * 16 * 4 );
582 info = GlobalLock( hmem );
583 info->bmiHeader.biSize = sizeof(info->bmiHeader);
584 info->bmiHeader.biWidth = 16;
585 info->bmiHeader.biHeight = 16;
586 info->bmiHeader.biPlanes = 1;
587 info->bmiHeader.biBitCount = 32;
588 info->bmiHeader.biCompression = BI_RGB;
590 for (lb.lbStyle = BS_SOLID; lb.lbStyle <= BS_MONOPATTERN + 1; lb.lbStyle++)
592 SetLastError( 0xdeadbeef );
593 memset( buffer, 0xcc, sizeof(buffer) );
594 trace( "testing brush style %u\n", lb.lbStyle );
596 switch (lb.lbStyle)
598 case BS_SOLID:
599 case BS_HATCHED:
600 lb.lbColor = RGB(12,34,56);
601 lb.lbHatch = HS_CROSS;
602 pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
603 ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
604 size = GetObjectW( pen, sizeof(buffer), elp );
605 ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
606 ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle );
607 ok( elp->elpBrushStyle == lb.lbStyle, "wrong brush style %x\n", elp->elpBrushStyle );
608 ok( elp->elpColor == RGB(12,34,56), "wrong color %x\n", elp->elpColor );
609 ok( elp->elpHatch == HS_CROSS, "wrong hatch %lx\n", elp->elpHatch );
610 ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries );
611 break;
613 case BS_NULL:
614 pen = ExtCreatePen( PS_SOLID | PS_GEOMETRIC, 3, &lb, 0, NULL );
615 ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
616 size = GetObjectW( pen, sizeof(buffer), elp );
617 ok( size == sizeof(LOGPEN), "wrong size %u\n", size );
618 ok( ((LOGPEN *)elp)->lopnStyle == PS_NULL,
619 "wrong pen style %x\n", ((LOGPEN *)elp)->lopnStyle );
620 ok( ((LOGPEN *)elp)->lopnColor == 0,
621 "wrong color %x\n", ((LOGPEN *)elp)->lopnColor );
622 break;
624 case BS_PATTERN:
625 lb.lbColor = RGB(12,34,56);
626 lb.lbHatch = (ULONG_PTR)bmp;
627 pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
628 ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
629 size = GetObjectW( pen, sizeof(buffer), elp );
630 ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
631 ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle );
632 ok( elp->elpBrushStyle == BS_PATTERN, "wrong brush style %x\n", elp->elpBrushStyle );
633 ok( elp->elpColor == 0, "wrong color %x\n", elp->elpColor );
634 ok( elp->elpHatch == (ULONG_PTR)bmp, "wrong hatch %lx/%p\n", elp->elpHatch, bmp );
635 ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries );
636 break;
638 case BS_DIBPATTERN:
639 case BS_DIBPATTERNPT:
640 lb.lbColor = DIB_PAL_COLORS;
641 lb.lbHatch = lb.lbStyle == BS_DIBPATTERN ? (ULONG_PTR)hmem : (ULONG_PTR)info;
642 pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
643 ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
644 size = GetObjectW( pen, sizeof(buffer), elp );
645 ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
646 ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle );
647 ok( elp->elpBrushStyle == BS_DIBPATTERNPT, "wrong brush style %x\n", elp->elpBrushStyle );
648 ok( elp->elpColor == 0, "wrong color %x\n", elp->elpColor );
649 ok( elp->elpHatch == lb.lbHatch || broken(elp->elpHatch != lb.lbHatch), /* <= w2k */
650 "wrong hatch %lx/%lx\n", elp->elpHatch, lb.lbHatch );
651 ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries );
652 break;
654 default:
655 pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
656 ok( !pen, "ExtCreatePen succeeded\n" );
657 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
658 break;
661 if (pen) DeleteObject( pen );
662 else continue;
664 /* cosmetic pens require BS_SOLID */
665 SetLastError( 0xdeadbeef );
666 pen = ExtCreatePen( PS_DOT, 1, &lb, 0, NULL );
667 if (lb.lbStyle == BS_SOLID)
669 ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
670 size = GetObjectW( pen, sizeof(buffer), elp );
671 ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
672 ok( elp->elpPenStyle == PS_DOT, "wrong pen style %x\n", elp->elpPenStyle );
673 ok( elp->elpBrushStyle == BS_SOLID, "wrong brush style %x\n", elp->elpBrushStyle );
674 ok( elp->elpColor == RGB(12,34,56), "wrong color %x\n", elp->elpColor );
675 ok( elp->elpHatch == HS_CROSS, "wrong hatch %lx\n", elp->elpHatch );
676 DeleteObject( pen );
678 else
680 ok( !pen, "ExtCreatePen succeeded\n" );
681 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
685 GlobalUnlock( hmem );
686 GlobalFree( hmem );
687 DeleteObject( bmp );
690 START_TEST(pen)
692 test_logpen();
693 test_brush_pens();
694 test_ps_alternate();
695 test_ps_userstyle();