brush.c 13.6 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * GDI brush objects
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
4
 * Copyright 1993, 1994  Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
19
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
20

21 22
#include "config.h"

23
#include <stdarg.h>
24
#include <string.h>
25

26
#include "windef.h"
27
#include "winbase.h"
28
#include "wingdi.h"
29
#include "gdi_private.h"
30
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
31

32
WINE_DEFAULT_DEBUG_CHANNEL(gdi);
33

34 35 36
/* GDI logical brush object */
typedef struct
{
37 38
    GDIOBJHDR             header;
    LOGBRUSH              logbrush;
39
    struct brush_pattern  pattern;
40 41 42 43
} BRUSHOBJ;

#define NB_HATCH_STYLES  6

44
static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, HDC hdc );
45
static INT BRUSH_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
46
static BOOL BRUSH_DeleteObject( HGDIOBJ handle );
47 48 49 50 51 52 53 54 55 56

static const struct gdi_obj_funcs brush_funcs =
{
    BRUSH_SelectObject,  /* pSelectObject */
    BRUSH_GetObject,     /* pGetObjectA */
    BRUSH_GetObject,     /* pGetObjectW */
    NULL,                /* pUnrealizeObject */
    BRUSH_DeleteObject   /* pDeleteObject */
};

Ulrich Czekalla's avatar
Ulrich Czekalla committed
57

58
static BOOL copy_bitmap( struct brush_pattern *brush, HBITMAP bitmap )
59
{
60 61
    char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256])];
    BITMAPINFO *info = (BITMAPINFO *)buffer;
62 63
    struct gdi_image_bits bits;
    struct bitblt_coords src;
64
    BITMAPOBJ *bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP );
65

66
    if (!bmp) return FALSE;
67 68 69

    src.visrect.left   = src.x = 0;
    src.visrect.top    = src.y = 0;
70 71
    src.visrect.right  = src.width = bmp->dib.dsBm.bmWidth;
    src.visrect.bottom = src.height = bmp->dib.dsBm.bmHeight;
72
    if (get_image_from_bitmap( bmp, info, &bits, &src )) goto done;
73

74 75
    brush->bits = bits;
    if (!bits.free)
76
    {
77 78 79
        if (!(brush->bits.ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
        memcpy( brush->bits.ptr, bits.ptr, info->bmiHeader.biSizeImage );
        brush->bits.free = free_heap_bits;
80 81
    }

82
    if (!(brush->info = HeapAlloc( GetProcessHeap(), 0, get_dib_info_size( info, DIB_RGB_COLORS ))))
83
    {
84
        if (brush->bits.free) brush->bits.free( &brush->bits );
85 86
        goto done;
    }
87 88
    memcpy( brush->info, info, get_dib_info_size( info, DIB_RGB_COLORS ));
    brush->bits.is_copy = FALSE;  /* the bits can't be modified */
89 90 91 92 93 94 95
    brush->usage = DIB_RGB_COLORS;

done:
    GDI_ReleaseObj( bitmap );
    return brush->info != NULL;
}

96 97 98 99 100 101 102 103 104 105 106
BOOL store_brush_pattern( LOGBRUSH *brush, struct brush_pattern *pattern )
{
    HGLOBAL hmem = 0;

    pattern->info = NULL;
    pattern->bits.free = NULL;

    switch (brush->lbStyle)
    {
    case BS_SOLID:
    case BS_HOLLOW:
107 108
        return TRUE;

109
    case BS_HATCHED:
110 111 112 113 114 115
        if (brush->lbHatch > HS_DIAGCROSS)
        {
            if (brush->lbHatch >= HS_API_MAX) return FALSE;
            brush->lbStyle = BS_SOLID;
            brush->lbHatch = 0;
        }
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
        return TRUE;

    case BS_PATTERN8X8:
        brush->lbStyle = BS_PATTERN;
        /* fall through */
    case BS_PATTERN:
        brush->lbColor = 0;
        return copy_bitmap( pattern, (HBITMAP)brush->lbHatch );

    case BS_DIBPATTERN:
        hmem = (HGLOBAL)brush->lbHatch;
        if (!(brush->lbHatch = (ULONG_PTR)GlobalLock( hmem ))) return FALSE;
        /* fall through */
    case BS_DIBPATTERNPT:
        pattern->usage = brush->lbColor;
        pattern->info = copy_packed_dib( (BITMAPINFO *)brush->lbHatch, pattern->usage );
        if (hmem) GlobalUnlock( hmem );
        if (!pattern->info) return FALSE;
        pattern->bits.ptr = (char *)pattern->info + get_dib_info_size( pattern->info, pattern->usage );
        brush->lbStyle = BS_DIBPATTERN;
        brush->lbColor = 0;
        return TRUE;

    case BS_DIBPATTERN8X8:
    case BS_MONOPATTERN:
    case BS_INDEXED:
    default:
        WARN( "invalid brush style %u\n", brush->lbStyle );
        return FALSE;
    }
}

void free_brush_pattern( struct brush_pattern *pattern )
{
    if (pattern->bits.free) pattern->bits.free( &pattern->bits );
    HeapFree( GetProcessHeap(), 0, pattern->info );
}

154 155 156 157 158 159 160
BOOL get_brush_bitmap_info( HBRUSH handle, BITMAPINFO *info, void **bits, UINT *usage )
{
    BRUSHOBJ *brush;
    BOOL ret = FALSE;

    if (!(brush = GDI_GetObjPtr( handle, OBJ_BRUSH ))) return FALSE;

161
    if (brush->pattern.info)
162
    {
163
        memcpy( info, brush->pattern.info, get_dib_info_size( brush->pattern.info, brush->pattern.usage ));
164 165
        if (info->bmiHeader.biBitCount <= 8 && !info->bmiHeader.biClrUsed)
            fill_default_color_table( info );
166 167
        *bits = brush->pattern.bits.ptr;
        *usage = brush->pattern.usage;
168 169 170 171 172 173 174
        ret = TRUE;
    }
    GDI_ReleaseObj( handle );
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
175
/***********************************************************************
176
 *           CreateBrushIndirect    (GDI32.@)
Ulrich Czekalla's avatar
Ulrich Czekalla committed
177
 *
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
 * Create a logical brush with a given style, color or pattern.
 *
 * PARAMS
 *  brush [I] Pointer to a LOGBRUSH structure describing the desired brush.
 *
 * RETURNS
 *  A handle to the created brush, or a NULL handle if the brush cannot be 
 *  created.
 *
 * NOTES
 * - The brush returned should be freed by the caller using DeleteObject()
 *   when it is no longer required.
 * - Windows 95 and earlier cannot create brushes from bitmaps or DIBs larger
 *   than 8x8 pixels. If a larger bitmap is given, only a portion of the bitmap
 *   is used.
Alexandre Julliard's avatar
Alexandre Julliard committed
193
 */
194
HBRUSH WINAPI CreateBrushIndirect( const LOGBRUSH * brush )
Alexandre Julliard's avatar
Alexandre Julliard committed
195
{
196
    BRUSHOBJ * ptr;
197
    HBRUSH hbrush;
198

199
    if (!(ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(*ptr) ))) return 0;
200

201
    ptr->logbrush = *brush;
202

203 204
    if (store_brush_pattern( &ptr->logbrush, &ptr->pattern ) &&
        (hbrush = alloc_gdi_handle( &ptr->header, OBJ_BRUSH, &brush_funcs )))
205 206 207 208
    {
        TRACE("%p\n", hbrush);
        return hbrush;
    }
209

210
    free_brush_pattern( &ptr->pattern );
211
    HeapFree( GetProcessHeap(), 0, ptr );
212
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
213 214 215 216
}


/***********************************************************************
217
 *           CreateHatchBrush    (GDI32.@)
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
 *
 * Create a logical brush with a hatched pattern.
 *
 * PARAMS
 *  style [I] Direction of lines for the hatch pattern (HS_* values from "wingdi.h")
 *  color [I] Colour of the hatched pattern
 *
 * RETURNS
 *  A handle to the created brush, or a NULL handle if the brush cannot
 *  be created.
 *
 * NOTES
 * - This function uses CreateBrushIndirect() to create the brush.
 * - The brush returned should be freed by the caller using DeleteObject()
 *   when it is no longer required.
Alexandre Julliard's avatar
Alexandre Julliard committed
233
 */
234
HBRUSH WINAPI CreateHatchBrush( INT style, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
235
{
236 237
    LOGBRUSH logbrush;

238
    TRACE("%d %06x\n", style, color );
239 240 241 242 243

    logbrush.lbStyle = BS_HATCHED;
    logbrush.lbColor = color;
    logbrush.lbHatch = style;

244
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
245 246 247
}


Alexandre Julliard's avatar
Alexandre Julliard committed
248
/***********************************************************************
249
 *           CreatePatternBrush    (GDI32.@)
250 251 252 253 254 255 256 257 258 259 260 261 262 263
 *
 * Create a logical brush with a pattern from a bitmap.
 *
 * PARAMS
 *  hbitmap  [I] Bitmap containing pattern for the brush
 *
 * RETURNS
 *  A handle to the created brush, or a NULL handle if the brush cannot 
 *  be created.
 *
 * NOTES
 * - This function uses CreateBrushIndirect() to create the brush.
 * - The brush returned should be freed by the caller using DeleteObject()
 *   when it is no longer required.
Alexandre Julliard's avatar
Alexandre Julliard committed
264
 */
265
HBRUSH WINAPI CreatePatternBrush( HBITMAP hbitmap )
Alexandre Julliard's avatar
Alexandre Julliard committed
266
{
267
    LOGBRUSH logbrush = { BS_PATTERN, 0, 0 };
268
    TRACE("%p\n", hbitmap );
Alexandre Julliard's avatar
Alexandre Julliard committed
269

270
    logbrush.lbHatch = (ULONG_PTR)hbitmap;
271
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
272 273 274
}


Alexandre Julliard's avatar
Alexandre Julliard committed
275
/***********************************************************************
276
 *           CreateDIBPatternBrush    (GDI32.@)
277
 *
278
 * Create a logical brush with a pattern from a DIB.
279
 *
280 281 282
 * PARAMS
 *  hbitmap  [I] Global object containing BITMAPINFO structure for the pattern
 *  coloruse [I] Specifies color format, if provided
283 284
 *
 * RETURNS
285 286
 *  A handle to the created brush, or a NULL handle if the brush cannot 
 *  be created.
287
 *
288 289 290 291 292 293
 * NOTES
 * - This function uses CreateBrushIndirect() to create the brush.
 * - The brush returned should be freed by the caller using DeleteObject()
 *   when it is no longer required.
 * - This function is for compatibility only. CreateDIBPatternBrushPt() should 
 *   be used instead.
Alexandre Julliard's avatar
Alexandre Julliard committed
294
 */
295
HBRUSH WINAPI CreateDIBPatternBrush( HGLOBAL hbitmap, UINT coloruse )
Alexandre Julliard's avatar
Alexandre Julliard committed
296
{
297
    LOGBRUSH logbrush;
298

299
    TRACE("%p\n", hbitmap );
Alexandre Julliard's avatar
Alexandre Julliard committed
300

301 302
    logbrush.lbStyle = BS_DIBPATTERN;
    logbrush.lbColor = coloruse;
Alexandre Julliard's avatar
Alexandre Julliard committed
303

304
    logbrush.lbHatch = (ULONG_PTR)hbitmap;
Alexandre Julliard's avatar
Alexandre Julliard committed
305

306
    return CreateBrushIndirect( &logbrush );
307 308 309 310
}


/***********************************************************************
311
 *           CreateDIBPatternBrushPt    (GDI32.@)
312
 *
313
 * Create a logical brush with a pattern from a DIB.
314
 *
315 316 317
 * PARAMS
 *  data     [I] Pointer to a BITMAPINFO structure and image data  for the pattern
 *  coloruse [I] Specifies color format, if provided
318
 *
319 320 321
 * RETURNS
 *  A handle to the created brush, or a NULL handle if the brush cannot
 *  be created.
322
 *
323 324 325 326
 * NOTES
 * - This function uses CreateBrushIndirect() to create the brush.
 * - The brush returned should be freed by the caller using DeleteObject()
 *   when it is no longer required.
327
 */
328
HBRUSH WINAPI CreateDIBPatternBrushPt( const void* data, UINT coloruse )
329
{
330
    const BITMAPINFO *info=data;
Patrik Stridvall's avatar
Patrik Stridvall committed
331
    LOGBRUSH logbrush;
332

333 334 335
    if (!data)
        return NULL;

336
    TRACE("%p %dx%d %dbpp\n", info, info->bmiHeader.biWidth,
337
	  info->bmiHeader.biHeight,  info->bmiHeader.biBitCount);
338

Ulrich Czekalla's avatar
Ulrich Czekalla committed
339
    logbrush.lbStyle = BS_DIBPATTERNPT;
Patrik Stridvall's avatar
Patrik Stridvall committed
340
    logbrush.lbColor = coloruse;
341
    logbrush.lbHatch = (ULONG_PTR)data;
342

343
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
344 345 346
}


Alexandre Julliard's avatar
Alexandre Julliard committed
347
/***********************************************************************
348
 *           CreateSolidBrush    (GDI32.@)
349 350 351 352 353 354 355 356 357 358 359 360 361 362
 *
 * Create a logical brush consisting of a single colour.
 *
 * PARAMS
 *  color [I] Colour to make the solid brush
 *
 * RETURNS
 *  A handle to the newly created brush, or a NULL handle if the brush cannot
 *  be created.
 *
 * NOTES
 * - This function uses CreateBrushIndirect() to create the brush.
 * - The brush returned should be freed by the caller using DeleteObject()
 *   when it is no longer required.
Alexandre Julliard's avatar
Alexandre Julliard committed
363
 */
364
HBRUSH WINAPI CreateSolidBrush( COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
365
{
366 367
    LOGBRUSH logbrush;

368
    TRACE("%06x\n", color );
369 370 371 372 373

    logbrush.lbStyle = BS_SOLID;
    logbrush.lbColor = color;
    logbrush.lbHatch = 0;

374
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
375 376 377
}


Alexandre Julliard's avatar
Alexandre Julliard committed
378
/***********************************************************************
379
 *           SetBrushOrgEx    (GDI32.@)
380 381 382 383
 *
 * Set the brush origin for a device context.
 *
 * PARAMS
384
 *  hdc    [I] Device context to set the brush origin for
385
 *  x      [I] New x origin
386
 *  y      [I] New y origin
387 388 389 390
 *  oldorg [O] If non NULL, destination for previously set brush origin.
 *
 * RETURNS
 *  Success: TRUE. The origin is set to (x,y), and oldorg is updated if given.
Alexandre Julliard's avatar
Alexandre Julliard committed
391
 */
392
BOOL WINAPI SetBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
Alexandre Julliard's avatar
Alexandre Julliard committed
393
{
394
    DC *dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
395 396 397 398

    if (!dc) return FALSE;
    if (oldorg)
    {
399 400
        oldorg->x = dc->brushOrgX;
        oldorg->y = dc->brushOrgY;
Alexandre Julliard's avatar
Alexandre Julliard committed
401
    }
402 403
    dc->brushOrgX = x;
    dc->brushOrgY = y;
404
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
405 406 407
    return TRUE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
408
/***********************************************************************
409
 *           FixBrushOrgEx    (GDI32.@)
410 411 412 413 414 415
 *
 * See SetBrushOrgEx.
 *
 * NOTES
 *  This function is no longer documented by MSDN, but in Win95 GDI32 it
 *  is the same as SetBrushOrgEx().
Alexandre Julliard's avatar
Alexandre Julliard committed
416
 */
417
BOOL WINAPI FixBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
Alexandre Julliard's avatar
Alexandre Julliard committed
418 419 420 421
{
    return SetBrushOrgEx(hdc,x,y,oldorg);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
422

423 424 425
/***********************************************************************
 *           BRUSH_SelectObject
 */
426
static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, HDC hdc )
427
{
428 429 430
    BRUSHOBJ *brush;
    HGDIOBJ ret = 0;
    DC *dc = get_dc_ptr( hdc );
431

432 433 434 435 436
    if (!dc)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return 0;
    }
437

438
    if ((brush = GDI_GetObjPtr( handle, OBJ_BRUSH )))
439
    {
440
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSelectBrush );
441
        struct brush_pattern *pattern = &brush->pattern;
442

443
        if (!pattern->info) pattern = NULL;
444

445 446 447
        GDI_inc_ref_count( handle );
        GDI_ReleaseObj( handle );

448
        if (!physdev->funcs->pSelectBrush( physdev, handle, pattern ))
449 450 451 452
        {
            GDI_dec_ref_count( handle );
        }
        else
453 454 455 456 457
        {
            ret = dc->hBrush;
            dc->hBrush = handle;
            GDI_dec_ref_count( ret );
        }
458 459
    }
    release_dc_ptr( dc );
460 461 462 463
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
464 465 466
/***********************************************************************
 *           BRUSH_DeleteObject
 */
467
static BOOL BRUSH_DeleteObject( HGDIOBJ handle )
Alexandre Julliard's avatar
Alexandre Julliard committed
468
{
469
    BRUSHOBJ *brush = free_gdi_handle( handle );
470

471
    if (!brush) return FALSE;
472
    free_brush_pattern( &brush->pattern );
473
    return HeapFree( GetProcessHeap(), 0, brush );
Alexandre Julliard's avatar
Alexandre Julliard committed
474 475 476
}


Alexandre Julliard's avatar
Alexandre Julliard committed
477
/***********************************************************************
478
 *           BRUSH_GetObject
Alexandre Julliard's avatar
Alexandre Julliard committed
479
 */
480
static INT BRUSH_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
Alexandre Julliard's avatar
Alexandre Julliard committed
481
{
482
    BRUSHOBJ *brush = GDI_GetObjPtr( handle, OBJ_BRUSH );
483

484 485 486 487 488 489 490 491
    if (!brush) return 0;
    if (buffer)
    {
        if (count > sizeof(brush->logbrush)) count = sizeof(brush->logbrush);
        memcpy( buffer, &brush->logbrush, count );
    }
    else count = sizeof(brush->logbrush);
    GDI_ReleaseObj( handle );
Alexandre Julliard's avatar
Alexandre Julliard committed
492 493
    return count;
}