pen.c 23.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Unit test suite for pens
 *
 * Copyright 2006 Dmitry Timoshkov
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 22 23 24 25 26 27 28 29 30
 */

#include <stdarg.h>
#include <assert.h>

#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"

#include "wine/test.h"

31
#define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
32 33
#define expect2(expected, alt, got) ok(got == expected || got == alt, \
                                       "Expected %.8x or %.8x, got %.8x\n", expected, alt, got)
34

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
static void test_logpen(void)
{
    static const struct
    {
        UINT style;
        INT width;
        COLORREF color;
        UINT ret_style;
        INT ret_width;
        COLORREF ret_color;
    } pen[] = {
        { PS_SOLID, -123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
        { PS_SOLID, 0, RGB(0x12,0x34,0x56), PS_SOLID, 0, RGB(0x12,0x34,0x56) },
        { PS_SOLID, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
        { PS_DASH, 123, RGB(0x12,0x34,0x56), PS_DASH, 123, RGB(0x12,0x34,0x56) },
        { PS_DOT, 123, RGB(0x12,0x34,0x56), PS_DOT, 123, RGB(0x12,0x34,0x56) },
        { PS_DASHDOT, 123, RGB(0x12,0x34,0x56), PS_DASHDOT, 123, RGB(0x12,0x34,0x56) },
        { PS_DASHDOTDOT, 123, RGB(0x12,0x34,0x56), PS_DASHDOTDOT, 123, RGB(0x12,0x34,0x56) },
        { PS_NULL, -123, RGB(0x12,0x34,0x56), PS_NULL, 1, 0 },
        { PS_NULL, 123, RGB(0x12,0x34,0x56), PS_NULL, 1, 0 },
        { PS_INSIDEFRAME, 123, RGB(0x12,0x34,0x56), PS_INSIDEFRAME, 123, RGB(0x12,0x34,0x56) },
        { PS_USERSTYLE, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
        { PS_ALTERNATE, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) }
    };
    INT i, size;
    HPEN hpen;
    LOGPEN lp;
    EXTLOGPEN elp;
    LOGBRUSH lb;
64
    DWORD_PTR unset_hatch;
65 66 67 68 69 70 71 72 73
    DWORD obj_type, user_style[2] = { 0xabc, 0xdef };
    struct
    {
        EXTLOGPEN elp;
        DWORD style_data[10];
    } ext_pen;

    for (i = 0; i < sizeof(pen)/sizeof(pen[0]); i++)
    {
74
        trace("%d: testing style %u\n", i, pen[i].style);
75 76 77 78 79 80 81 82 83

        /********************** cosmetic pens **********************/
        /* CreatePenIndirect behaviour */
        lp.lopnStyle = pen[i].style,
        lp.lopnWidth.x = pen[i].width;
        lp.lopnWidth.y = 11; /* just in case */
        lp.lopnColor = pen[i].color;
        SetLastError(0xdeadbeef);
        hpen = CreatePenIndirect(&lp);
84
        ok(hpen != 0, "CreatePen error %d\n", GetLastError());
85 86

        obj_type = GetObjectType(hpen);
87
        ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
88 89 90 91

        memset(&lp, 0xb0, sizeof(lp));
        SetLastError(0xdeadbeef);
        size = GetObject(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 96 97
        ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
        ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
        ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
98 99 100 101 102 103

        DeleteObject(hpen);

        /* CreatePen behaviour */
        SetLastError(0xdeadbeef);
        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 110

        /* check what's the real size of the object */
        size = GetObject(hpen, 0, NULL);
111
        ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
112 113 114 115 116

        /* ask for truncated data */
        memset(&lp, 0xb0, sizeof(lp));
        SetLastError(0xdeadbeef);
        size = GetObject(hpen, sizeof(lp.lopnStyle), &lp);
117
        ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
118 119 120 121

        /* see how larger buffer sizes are handled */
        memset(&lp, 0xb0, sizeof(lp));
        SetLastError(0xdeadbeef);
122
        size = GetObject(hpen, sizeof(lp) * 4, &lp);
123
        ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
124 125 126 127 128

        /* see how larger buffer sizes are handled */
        memset(&elp, 0xb0, sizeof(elp));
        SetLastError(0xdeadbeef);
        size = GetObject(hpen, sizeof(elp) * 2, &elp);
129
        ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError());
130 131 132 133

        memset(&lp, 0xb0, sizeof(lp));
        SetLastError(0xdeadbeef);
        size = GetObject(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 138 139
        ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
        ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
        ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
140 141 142 143 144 145 146 147

        memset(&elp, 0xb0, sizeof(elp));
        SetLastError(0xdeadbeef);
        size = GetObject(hpen, sizeof(elp), &elp);

        /* for some reason XP differentiates PS_NULL here */
        if (pen[i].style == PS_NULL)
        {
148
            ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n");
149 150 151 152
            ok(size == sizeof(EXTLOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
            ok(elp.elpPenStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, elp.elpPenStyle);
            ok(elp.elpWidth == 0, "expected 0, got %u\n", elp.elpWidth);
            ok(elp.elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, elp.elpColor);
153 154
            ok(elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %u\n", elp.elpBrushStyle);
            ok(elp.elpHatch == 0, "expected 0, got %p\n", (void *)elp.elpHatch);
155
            ok(elp.elpNumEntries == 0, "expected 0, got %x\n", elp.elpNumEntries);
156 157 158
        }
        else
        {
159
            ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
160 161
            memcpy(&lp, &elp, sizeof(lp));
            ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
162 163 164
            ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
            ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
            ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
165 166 167 168 169 170 171 172 173 174 175 176 177 178
        }

        DeleteObject(hpen);

        /********** cosmetic pens created by ExtCreatePen ***********/
        lb.lbStyle = BS_SOLID;
        lb.lbColor = pen[i].color;
        lb.lbHatch = HS_CROSS; /* just in case */
        SetLastError(0xdeadbeef);
        hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 2, user_style);
        if (pen[i].style != PS_USERSTYLE)
        {
            ok(hpen == 0, "ExtCreatePen should fail\n");
            ok(GetLastError() == ERROR_INVALID_PARAMETER,
179
               "wrong last error value %d\n", GetLastError());
180 181 182 183 184 185
            SetLastError(0xdeadbeef);
            hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 0, NULL);
            if (pen[i].style != PS_NULL)
            {
                ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
                ok(GetLastError() == ERROR_INVALID_PARAMETER,
186
                   "wrong last error value %d\n", GetLastError());
187 188 189 190 191 192 193 194 195

                SetLastError(0xdeadbeef);
                hpen = ExtCreatePen(pen[i].style, 1, &lb, 0, NULL);
            }
        }
        else
        {
            ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
            ok(GetLastError() == ERROR_INVALID_PARAMETER,
196
               "wrong last error value %d\n", GetLastError());
197 198 199 200 201
            SetLastError(0xdeadbeef);
            hpen = ExtCreatePen(pen[i].style, 1, &lb, 2, user_style);
        }
        if (pen[i].style == PS_INSIDEFRAME)
        {
Austin English's avatar
Austin English committed
202
            /* This style is applicable only for geometric pens */
203 204 205
            ok(hpen == 0, "ExtCreatePen should fail\n");
            goto test_geometric_pens;
        }
206
        ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError());
207 208 209 210

        obj_type = GetObjectType(hpen);
        /* for some reason XP differentiates PS_NULL here */
        if (pen[i].style == PS_NULL)
211
        {
212
            ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
213 214
            ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n");
        }
215
        else
216
            ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type);
217 218 219 220 221 222 223 224

        /* check what's the real size of the object */
        SetLastError(0xdeadbeef);
        size = GetObject(hpen, 0, NULL);
        switch (pen[i].style)
        {
        case PS_NULL:
            ok(size == sizeof(LOGPEN),
225
               "GetObject returned %d, error %d\n", size, GetLastError());
226 227 228 229
            break;

        case PS_USERSTYLE:
            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
230
               "GetObject returned %d, error %d\n", size, GetLastError());
231 232 233 234
            break;

        default:
            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry),
235
               "GetObject returned %d, error %d\n", size, GetLastError());
236 237 238 239 240 241 242
            break;
        }

        /* ask for truncated data */
        memset(&elp, 0xb0, sizeof(elp));
        SetLastError(0xdeadbeef);
        size = GetObject(hpen, sizeof(elp.elpPenStyle), &elp);
243
        ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
244 245 246 247 248 249 250 251 252

        /* see how larger buffer sizes are handled */
        memset(&ext_pen, 0xb0, sizeof(ext_pen));
        SetLastError(0xdeadbeef);
        size = GetObject(hpen, sizeof(ext_pen), &ext_pen.elp);
        switch (pen[i].style)
        {
        case PS_NULL:
            ok(size == sizeof(LOGPEN),
253
               "GetObject returned %d, error %d\n", size, GetLastError());
254 255
            memcpy(&lp, &ext_pen.elp, sizeof(lp));
            ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
256 257 258
            ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
            ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
            ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
259 260 261

            /* for PS_NULL it also works this way */
            memset(&elp, 0xb0, sizeof(elp));
262
            memset(&unset_hatch, 0xb0, sizeof(unset_hatch));
263 264 265
            SetLastError(0xdeadbeef);
            size = GetObject(hpen, sizeof(elp), &elp);
            ok(size == sizeof(EXTLOGPEN),
266
                "GetObject returned %d, error %d\n", size, GetLastError());
267
            ok(ext_pen.elp.elpHatch == unset_hatch, "expected 0xb0b0b0b0, got %p\n", (void *)ext_pen.elp.elpHatch);
268
            ok(ext_pen.elp.elpNumEntries == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %x\n", ext_pen.elp.elpNumEntries);
269 270 271 272
            break;

        case PS_USERSTYLE:
            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
273
               "GetObject returned %d, error %d\n", size, GetLastError());
274
            ok(ext_pen.elp.elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen.elp.elpHatch);
275 276 277
            ok(ext_pen.elp.elpNumEntries == 2, "expected 0, got %x\n", ext_pen.elp.elpNumEntries);
            ok(ext_pen.elp.elpStyleEntry[0] == 0xabc, "expected 0xabc, got %x\n", ext_pen.elp.elpStyleEntry[0]);
            ok(ext_pen.elp.elpStyleEntry[1] == 0xdef, "expected 0xabc, got %x\n", ext_pen.elp.elpStyleEntry[1]);
278 279 280 281
            break;

        default:
            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry),
282
               "GetObject returned %d, error %d\n", size, GetLastError());
283
            ok(ext_pen.elp.elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen.elp.elpHatch);
284
            ok(ext_pen.elp.elpNumEntries == 0, "expected 0, got %x\n", ext_pen.elp.elpNumEntries);
285 286 287 288 289 290
            break;
        }

if (pen[i].style == PS_USERSTYLE)
{
    todo_wine
291
        ok(ext_pen.elp.elpPenStyle == pen[i].style, "expected %x, got %x\n", pen[i].style, ext_pen.elp.elpPenStyle);
292 293
}
else
294 295 296
        ok(ext_pen.elp.elpPenStyle == pen[i].style, "expected %x, got %x\n", pen[i].style, ext_pen.elp.elpPenStyle);
        ok(ext_pen.elp.elpWidth == 1, "expected 1, got %x\n", ext_pen.elp.elpWidth);
        ok(ext_pen.elp.elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen.elp.elpColor);
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
        ok(ext_pen.elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen.elp.elpBrushStyle);

        DeleteObject(hpen);

test_geometric_pens:
        /********************** geometric pens **********************/
        lb.lbStyle = BS_SOLID;
        lb.lbColor = pen[i].color;
        lb.lbHatch = HS_CROSS; /* just in case */
        SetLastError(0xdeadbeef);
        hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 2, user_style);
        if (pen[i].style != PS_USERSTYLE)
        {
            ok(hpen == 0, "ExtCreatePen should fail\n");
            SetLastError(0xdeadbeef);
            hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 0, NULL);
        }
        if (pen[i].style == PS_ALTERNATE)
        {
            /* This style is applicable only for cosmetic pens */
            ok(hpen == 0, "ExtCreatePen should fail\n");
            continue;
        }
320
        ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError());
321 322 323 324

        obj_type = GetObjectType(hpen);
        /* for some reason XP differentiates PS_NULL here */
        if (pen[i].style == PS_NULL)
325
            ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
326
        else
327
            ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type);
328 329 330 331 332 333 334

        /* check what's the real size of the object */
        size = GetObject(hpen, 0, NULL);
        switch (pen[i].style)
        {
        case PS_NULL:
            ok(size == sizeof(LOGPEN),
335
               "GetObject returned %d, error %d\n", size, GetLastError());
336 337 338 339
            break;

        case PS_USERSTYLE:
            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
340
               "GetObject returned %d, error %d\n", size, GetLastError());
341 342 343 344
            break;

        default:
            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry),
345
               "GetObject returned %d, error %d\n", size, GetLastError());
346 347 348 349 350 351 352
            break;
        }

        /* ask for truncated data */
        memset(&lp, 0xb0, sizeof(lp));
        SetLastError(0xdeadbeef);
        size = GetObject(hpen, sizeof(lp.lopnStyle), &lp);
353
        ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
354 355 356 357

        memset(&lp, 0xb0, sizeof(lp));
        SetLastError(0xdeadbeef);
        size = GetObject(hpen, sizeof(lp), &lp);
Austin English's avatar
Austin English committed
358
        /* for some reason XP differentiates PS_NULL here */
359 360
        if (pen[i].style == PS_NULL)
        {
361
            ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
362
            ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
363 364 365
            ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
            ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
            ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
366 367 368 369
        }
        else
            /* XP doesn't set last error here */
            ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
370
               "GetObject should fail: size %d, error %d\n", size, GetLastError());
371 372 373 374 375 376 377 378 379

        memset(&ext_pen, 0xb0, sizeof(ext_pen));
        SetLastError(0xdeadbeef);
        /* buffer is too small for user styles */
        size = GetObject(hpen, sizeof(elp), &ext_pen.elp);
        switch (pen[i].style)
        {
        case PS_NULL:
            ok(size == sizeof(EXTLOGPEN),
380
                "GetObject returned %d, error %d\n", size, GetLastError());
381
            ok(ext_pen.elp.elpHatch == 0, "expected 0, got %p\n", (void *)ext_pen.elp.elpHatch);
382
            ok(ext_pen.elp.elpNumEntries == 0, "expected 0, got %x\n", ext_pen.elp.elpNumEntries);
383 384 385 386 387

            /* for PS_NULL it also works this way */
            SetLastError(0xdeadbeef);
            size = GetObject(hpen, sizeof(ext_pen), &lp);
            ok(size == sizeof(LOGPEN),
388
                "GetObject returned %d, error %d\n", size, GetLastError());
389
            ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
390 391 392
            ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
            ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
            ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
393 394 395 396
            break;

        case PS_USERSTYLE:
            ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
397
               "GetObject should fail: size %d, error %d\n", size, GetLastError());
398 399
            size = GetObject(hpen, sizeof(ext_pen), &ext_pen.elp);
            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
400
               "GetObject returned %d, error %d\n", size, GetLastError());
401
            ok(ext_pen.elp.elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen.elp.elpHatch);
402 403 404
            ok(ext_pen.elp.elpNumEntries == 2, "expected 0, got %x\n", ext_pen.elp.elpNumEntries);
            ok(ext_pen.elp.elpStyleEntry[0] == 0xabc, "expected 0xabc, got %x\n", ext_pen.elp.elpStyleEntry[0]);
            ok(ext_pen.elp.elpStyleEntry[1] == 0xdef, "expected 0xabc, got %x\n", ext_pen.elp.elpStyleEntry[1]);
405 406 407 408
            break;

        default:
            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry),
409
               "GetObject returned %d, error %d\n", size, GetLastError());
410
            ok(ext_pen.elp.elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen.elp.elpHatch);
411
            ok(ext_pen.elp.elpNumEntries == 0, "expected 0, got %x\n", ext_pen.elp.elpNumEntries);
412 413 414
            break;
        }

Austin English's avatar
Austin English committed
415
        /* for some reason XP differentiates PS_NULL here */
416
        if (pen[i].style == PS_NULL)
417
            ok(ext_pen.elp.elpPenStyle == pen[i].ret_style, "expected %x, got %x\n", pen[i].ret_style, ext_pen.elp.elpPenStyle);
418 419
        else
        {
420
            ok(ext_pen.elp.elpPenStyle == (PS_GEOMETRIC | pen[i].style), "expected %x, got %x\n", PS_GEOMETRIC | pen[i].style, ext_pen.elp.elpPenStyle);
421 422 423
        }

        if (pen[i].style == PS_NULL)
424
            ok(ext_pen.elp.elpWidth == 0, "expected 0, got %x\n", ext_pen.elp.elpWidth);
425
        else
426 427
            ok(ext_pen.elp.elpWidth == pen[i].ret_width, "expected %u, got %x\n", pen[i].ret_width, ext_pen.elp.elpWidth);
        ok(ext_pen.elp.elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen.elp.elpColor);
428 429 430 431 432 433
        ok(ext_pen.elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen.elp.elpBrushStyle);

        DeleteObject(hpen);
    }
}

434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
static unsigned int atoi2(const char *s)
{
    unsigned int ret = 0;
    while(*s) ret = (ret << 1) | (*s++ == '1');
    return ret;
}

#define TEST_LINE(x1, x2, z) \
    { int buf = 0; \
      SetBitmapBits(bmp, sizeof(buf), &buf); \
      MoveToEx(hdc, x1, 0, NULL); \
      LineTo(hdc, x2, 0); \
      GetBitmapBits(bmp, sizeof(buf), &buf); \
      expect(atoi2(z), buf); }

static void test_ps_alternate(void)
{
    HDC hdc;
    HBITMAP bmp;
    HPEN pen;
    LOGBRUSH lb;

    lb.lbStyle = BS_SOLID;
    lb.lbColor = RGB(0xff,0xff,0xff);

    SetLastError(0xdeadbeef);
    pen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
    if(pen == NULL && GetLastError() == 0xdeadbeef) {
        skip("looks like 9x, skipping PS_ALTERNATE tests\n");
        return;
    }
    ok(pen != NULL, "gle=%d\n", GetLastError());
    hdc = CreateCompatibleDC(NULL);
    ok(hdc != NULL, "gle=%d\n", GetLastError());
    bmp = CreateBitmap(8, 1, 1, 1, NULL);
    ok(bmp != NULL, "gle=%d\n", GetLastError());
    ok(SelectObject(hdc, bmp) != NULL, "gle=%d\n", GetLastError());
    ok(SelectObject(hdc, pen) != NULL, "gle=%d\n", GetLastError());
    ok(SetBkMode(hdc, TRANSPARENT), "gle=%d\n", GetLastError());

    TEST_LINE(0, 1, "10000000")
    TEST_LINE(0, 2, "10000000")
    TEST_LINE(0, 3, "10100000")
    TEST_LINE(0, 4, "10100000")
    TEST_LINE(1, 4, "01010000")
    TEST_LINE(1, 5, "01010000")
    TEST_LINE(4, 8, "00001010")

    DeleteObject(pen);
    DeleteObject(bmp);
    DeleteDC(hdc);
}

487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
static void test_ps_userstyle(void)
{
    static DWORD style[17] = {0, 2, 0, 4, 5, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 17};
    static DWORD bad_style[5] = {0, 0, 0, 0, 0};
    static DWORD bad_style2[5] = {4, 7, 8, 3, -1};

    LOGBRUSH lb;
    HPEN pen;
    INT size, i;

    struct
    {
        EXTLOGPEN elp;
        DWORD style_data[15];
    } ext_pen;

    lb.lbColor = 0x00ff0000;
    lb.lbStyle = BS_SOLID;
    lb.lbHatch = 0;

    pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 3, NULL);
    ok(pen == 0, "ExtCreatePen should fail\n");
    expect(ERROR_INVALID_PARAMETER, GetLastError());
    DeleteObject(pen);
    SetLastError(0xdeadbeef);

    pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 0, style);
    ok(pen == 0, "ExtCreatePen should fail\n");
515
    expect2(0xdeadbeef, ERROR_INVALID_PARAMETER, GetLastError());
516 517 518 519 520 521 522 523 524 525 526
    DeleteObject(pen);
    SetLastError(0xdeadbeef);

    pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 17, style);
    ok(pen == 0, "ExtCreatePen should fail\n");
    expect(ERROR_INVALID_PARAMETER, GetLastError());
    DeleteObject(pen);
    SetLastError(0xdeadbeef);

    pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, -1, style);
    ok(pen == 0, "ExtCreatePen should fail\n");
527
    expect(0xdeadbeef, GetLastError());
528 529 530 531
    DeleteObject(pen);
    SetLastError(0xdeadbeef);

    pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style);
532 533
    ok(pen == 0, "ExtCreatePen should fail\n");
    expect(ERROR_INVALID_PARAMETER, GetLastError());
534 535 536 537
    DeleteObject(pen);
    SetLastError(0xdeadbeef);

    pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style2);
538 539
    ok(pen == 0, "ExtCreatePen should fail\n");
    expect(ERROR_INVALID_PARAMETER, GetLastError());
540 541 542 543 544 545 546
    DeleteObject(pen);
    SetLastError(0xdeadbeef);

    pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 16, style);
    ok(pen != 0, "ExtCreatePen should not fail\n");

    size = GetObject(pen, sizeof(ext_pen), &ext_pen);
547
    expect(FIELD_OFFSET(EXTLOGPEN,elpStyleEntry[16]), size);
548 549 550 551 552 553 554

    for(i = 0; i < 16; i++)
        expect(style[i], ext_pen.elp.elpStyleEntry[i]);

    DeleteObject(pen);
}

555 556 557
START_TEST(pen)
{
    test_logpen();
558
    test_ps_alternate();
559
    test_ps_userstyle();
560
}