brush.c 13.5 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
    LOGBRUSH              logbrush;
38
    struct brush_pattern  pattern;
39 40 41 42
} BRUSHOBJ;

#define NB_HATCH_STYLES  6

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

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
56

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

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

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

73 74
    brush->bits = bits;
    if (!bits.free)
75
    {
76 77 78
        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;
79 80
    }

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

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

95 96 97 98 99 100 101 102 103 104 105
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:
106 107
        return TRUE;

108
    case BS_HATCHED:
109 110 111 112 113 114
        if (brush->lbHatch > HS_DIAGCROSS)
        {
            if (brush->lbHatch >= HS_API_MAX) return FALSE;
            brush->lbStyle = BS_SOLID;
            brush->lbHatch = 0;
        }
115 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
        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 );
}

153 154 155 156 157 158 159
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;

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


Alexandre Julliard's avatar
Alexandre Julliard committed
174
/***********************************************************************
175
 *           CreateBrushIndirect    (GDI32.@)
Ulrich Czekalla's avatar
Ulrich Czekalla committed
176
 *
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
 * 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
192
 */
193
HBRUSH WINAPI CreateBrushIndirect( const LOGBRUSH * brush )
Alexandre Julliard's avatar
Alexandre Julliard committed
194
{
195
    BRUSHOBJ * ptr;
196
    HBRUSH hbrush;
197

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

200
    ptr->logbrush = *brush;
201

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

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


/***********************************************************************
216
 *           CreateHatchBrush    (GDI32.@)
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
 *
 * 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
232
 */
233
HBRUSH WINAPI CreateHatchBrush( INT style, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
234
{
235 236
    LOGBRUSH logbrush;

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

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

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


Alexandre Julliard's avatar
Alexandre Julliard committed
247
/***********************************************************************
248
 *           CreatePatternBrush    (GDI32.@)
249 250 251 252 253 254 255 256 257 258 259 260 261 262
 *
 * 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
263
 */
264
HBRUSH WINAPI CreatePatternBrush( HBITMAP hbitmap )
Alexandre Julliard's avatar
Alexandre Julliard committed
265
{
266
    LOGBRUSH logbrush = { BS_PATTERN, 0, 0 };
267
    TRACE("%p\n", hbitmap );
Alexandre Julliard's avatar
Alexandre Julliard committed
268

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


Alexandre Julliard's avatar
Alexandre Julliard committed
274
/***********************************************************************
275
 *           CreateDIBPatternBrush    (GDI32.@)
276
 *
277
 * Create a logical brush with a pattern from a DIB.
278
 *
279 280 281
 * PARAMS
 *  hbitmap  [I] Global object containing BITMAPINFO structure for the pattern
 *  coloruse [I] Specifies color format, if provided
282 283
 *
 * RETURNS
284 285
 *  A handle to the created brush, or a NULL handle if the brush cannot 
 *  be created.
286
 *
287 288 289 290 291 292
 * 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
293
 */
294
HBRUSH WINAPI CreateDIBPatternBrush( HGLOBAL hbitmap, UINT coloruse )
Alexandre Julliard's avatar
Alexandre Julliard committed
295
{
296
    LOGBRUSH logbrush;
297

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

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

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

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


/***********************************************************************
310
 *           CreateDIBPatternBrushPt    (GDI32.@)
311
 *
312
 * Create a logical brush with a pattern from a DIB.
313
 *
314 315 316
 * PARAMS
 *  data     [I] Pointer to a BITMAPINFO structure and image data  for the pattern
 *  coloruse [I] Specifies color format, if provided
317
 *
318 319 320
 * RETURNS
 *  A handle to the created brush, or a NULL handle if the brush cannot
 *  be created.
321
 *
322 323 324 325
 * 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.
326
 */
327
HBRUSH WINAPI CreateDIBPatternBrushPt( const void* data, UINT coloruse )
328
{
329
    const BITMAPINFO *info=data;
Patrik Stridvall's avatar
Patrik Stridvall committed
330
    LOGBRUSH logbrush;
331

332 333 334
    if (!data)
        return NULL;

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

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

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


Alexandre Julliard's avatar
Alexandre Julliard committed
346
/***********************************************************************
347
 *           CreateSolidBrush    (GDI32.@)
348 349 350 351 352 353 354 355 356 357 358 359 360 361
 *
 * 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
362
 */
363
HBRUSH WINAPI CreateSolidBrush( COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
364
{
365 366
    LOGBRUSH logbrush;

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

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

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


Alexandre Julliard's avatar
Alexandre Julliard committed
377
/***********************************************************************
378
 *           SetBrushOrgEx    (GDI32.@)
379 380 381 382
 *
 * Set the brush origin for a device context.
 *
 * PARAMS
383
 *  hdc    [I] Device context to set the brush origin for
384
 *  x      [I] New x origin
385
 *  y      [I] New y origin
386 387 388 389
 *  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
390
 */
391
BOOL WINAPI SetBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
Alexandre Julliard's avatar
Alexandre Julliard committed
392
{
393
    DC *dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
394 395 396

    if (!dc) return FALSE;
    if (oldorg)
397 398 399 400
        *oldorg = dc->brush_org;

    dc->brush_org.x = x;
    dc->brush_org.y = y;
401
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
402 403 404
    return TRUE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
405
/***********************************************************************
406
 *           FixBrushOrgEx    (GDI32.@)
407 408 409 410 411 412
 *
 * 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
413
 */
414
BOOL WINAPI FixBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
Alexandre Julliard's avatar
Alexandre Julliard committed
415 416 417 418
{
    return SetBrushOrgEx(hdc,x,y,oldorg);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
419

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

429 430 431 432 433
    if (!dc)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return 0;
    }
434

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

440
        if (!pattern->info) pattern = NULL;
441

442 443 444
        GDI_inc_ref_count( handle );
        GDI_ReleaseObj( handle );

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


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

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


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

481 482 483 484 485 486 487 488
    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
489 490
    return count;
}