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