brush.c 12.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 37 38 39 40 41 42
/* GDI logical brush object */
typedef struct
{
    GDIOBJHDR header;
    LOGBRUSH  logbrush;
} 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 */
};

56
static HGLOBAL dib_copy(const BITMAPINFO *info, UINT coloruse)
Ulrich Czekalla's avatar
Ulrich Czekalla committed
57 58
{
    BITMAPINFO  *newInfo;
59
    HGLOBAL     hmem;
Ulrich Czekalla's avatar
Ulrich Czekalla committed
60 61
    INT         size;

62
    if (info->bmiHeader.biCompression != BI_RGB && info->bmiHeader.biCompression != BI_BITFIELDS)
Ulrich Czekalla's avatar
Ulrich Czekalla committed
63 64 65 66 67
        size = info->bmiHeader.biSizeImage;
    else
        size = DIB_GetDIBImageBytes(info->bmiHeader.biWidth,
                                    info->bmiHeader.biHeight,
                                    info->bmiHeader.biBitCount);
68
    size += bitmap_info_size( info, coloruse );
Ulrich Czekalla's avatar
Ulrich Czekalla committed
69

70
    if (!(hmem = GlobalAlloc( GMEM_MOVEABLE, size )))
Ulrich Czekalla's avatar
Ulrich Czekalla committed
71 72 73
    {
        return 0;
    }
74
    newInfo = GlobalLock( hmem );
Ulrich Czekalla's avatar
Ulrich Czekalla committed
75
    memcpy( newInfo, info, size );
76
    GlobalUnlock( hmem );
Ulrich Czekalla's avatar
Ulrich Czekalla committed
77 78 79 80
    return hmem;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
81
/***********************************************************************
82
 *           CreateBrushIndirect    (GDI32.@)
Ulrich Czekalla's avatar
Ulrich Czekalla committed
83
 *
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
 * 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
99
 */
100
HBRUSH WINAPI CreateBrushIndirect( const LOGBRUSH * brush )
Alexandre Julliard's avatar
Alexandre Julliard committed
101
{
102
    BRUSHOBJ * ptr;
103
    HBRUSH hbrush;
104

105 106
    if (!(ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(*ptr) ))) return 0;

107 108 109 110 111
    ptr->logbrush.lbStyle = brush->lbStyle;
    ptr->logbrush.lbColor = brush->lbColor;
    ptr->logbrush.lbHatch = brush->lbHatch;

    switch (ptr->logbrush.lbStyle)
Ulrich Czekalla's avatar
Ulrich Czekalla committed
112
    {
113 114 115 116
    case BS_PATTERN8X8:
        ptr->logbrush.lbStyle = BS_PATTERN;
        /* fall through */
    case BS_PATTERN:
117
        ptr->logbrush.lbHatch = (ULONG_PTR)BITMAP_CopyBitmap( (HBITMAP) ptr->logbrush.lbHatch );
118 119 120 121 122
        if (!ptr->logbrush.lbHatch) goto error;
        break;

    case BS_DIBPATTERNPT:
        ptr->logbrush.lbStyle = BS_DIBPATTERN;
123 124
        ptr->logbrush.lbHatch = (ULONG_PTR)dib_copy( (BITMAPINFO *) ptr->logbrush.lbHatch,
                                                     ptr->logbrush.lbColor);
125 126 127 128 129 130 131 132 133 134
        if (!ptr->logbrush.lbHatch) goto error;
        break;

    case BS_DIBPATTERN8X8:
    case BS_DIBPATTERN:
       {
            BITMAPINFO* bmi;
            HGLOBAL h = (HGLOBAL)ptr->logbrush.lbHatch;

            ptr->logbrush.lbStyle = BS_DIBPATTERN;
135
            if (!(bmi = GlobalLock( h ))) goto error;
136
            ptr->logbrush.lbHatch = (ULONG_PTR)dib_copy( bmi, ptr->logbrush.lbColor);
137 138 139 140 141 142 143 144
            GlobalUnlock( h );
            if (!ptr->logbrush.lbHatch) goto error;
            break;
       }

    default:
        if(ptr->logbrush.lbStyle > BS_MONOPATTERN) goto error;
        break;
Ulrich Czekalla's avatar
Ulrich Czekalla committed
145
    }
146

147 148 149 150 151
    if ((hbrush = alloc_gdi_handle( &ptr->header, OBJ_BRUSH, &brush_funcs )))
    {
        TRACE("%p\n", hbrush);
        return hbrush;
    }
152 153

 error:
154 155 156 157 158
    if (ptr->logbrush.lbHatch)
    {
        if (ptr->logbrush.lbStyle == BS_PATTERN)
            DeleteObject( (HGDIOBJ)ptr->logbrush.lbHatch );
        else if (ptr->logbrush.lbStyle == BS_DIBPATTERN)
159
            GlobalFree( (HGLOBAL)ptr->logbrush.lbHatch );
160 161
    }
    HeapFree( GetProcessHeap(), 0, ptr );
162
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
163 164 165 166
}


/***********************************************************************
167
 *           CreateHatchBrush    (GDI32.@)
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
 *
 * 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
183
 */
184
HBRUSH WINAPI CreateHatchBrush( INT style, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
185
{
186 187
    LOGBRUSH logbrush;

188
    TRACE("%d %06x\n", style, color );
189 190 191 192 193

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

194
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
195 196 197
}


Alexandre Julliard's avatar
Alexandre Julliard committed
198
/***********************************************************************
199
 *           CreatePatternBrush    (GDI32.@)
200 201 202 203 204 205 206 207 208 209 210 211 212 213
 *
 * 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
214
 */
215
HBRUSH WINAPI CreatePatternBrush( HBITMAP hbitmap )
Alexandre Julliard's avatar
Alexandre Julliard committed
216
{
217
    LOGBRUSH logbrush = { BS_PATTERN, 0, 0 };
218
    TRACE("%p\n", hbitmap );
Alexandre Julliard's avatar
Alexandre Julliard committed
219

220
    logbrush.lbHatch = (ULONG_PTR)hbitmap;
221
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
222 223 224
}


Alexandre Julliard's avatar
Alexandre Julliard committed
225
/***********************************************************************
226
 *           CreateDIBPatternBrush    (GDI32.@)
227
 *
228
 * Create a logical brush with a pattern from a DIB.
229
 *
230 231 232
 * PARAMS
 *  hbitmap  [I] Global object containing BITMAPINFO structure for the pattern
 *  coloruse [I] Specifies color format, if provided
233 234
 *
 * RETURNS
235 236
 *  A handle to the created brush, or a NULL handle if the brush cannot 
 *  be created.
237
 *
238 239 240 241 242 243
 * 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
244
 */
245
HBRUSH WINAPI CreateDIBPatternBrush( HGLOBAL hbitmap, UINT coloruse )
Alexandre Julliard's avatar
Alexandre Julliard committed
246
{
247
    LOGBRUSH logbrush;
248

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

251 252
    logbrush.lbStyle = BS_DIBPATTERN;
    logbrush.lbColor = coloruse;
Alexandre Julliard's avatar
Alexandre Julliard committed
253

254
    logbrush.lbHatch = (ULONG_PTR)hbitmap;
Alexandre Julliard's avatar
Alexandre Julliard committed
255

256
    return CreateBrushIndirect( &logbrush );
257 258 259 260
}


/***********************************************************************
261
 *           CreateDIBPatternBrushPt    (GDI32.@)
262
 *
263
 * Create a logical brush with a pattern from a DIB.
264
 *
265 266 267
 * PARAMS
 *  data     [I] Pointer to a BITMAPINFO structure and image data  for the pattern
 *  coloruse [I] Specifies color format, if provided
268
 *
269 270 271
 * RETURNS
 *  A handle to the created brush, or a NULL handle if the brush cannot
 *  be created.
272
 *
273 274 275 276
 * 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.
277
 */
278
HBRUSH WINAPI CreateDIBPatternBrushPt( const void* data, UINT coloruse )
279
{
280
    const BITMAPINFO *info=data;
Patrik Stridvall's avatar
Patrik Stridvall committed
281
    LOGBRUSH logbrush;
282

283 284 285
    if (!data)
        return NULL;

286
    TRACE("%p %dx%d %dbpp\n", info, info->bmiHeader.biWidth,
287
	  info->bmiHeader.biHeight,  info->bmiHeader.biBitCount);
288

Ulrich Czekalla's avatar
Ulrich Czekalla committed
289
    logbrush.lbStyle = BS_DIBPATTERNPT;
Patrik Stridvall's avatar
Patrik Stridvall committed
290
    logbrush.lbColor = coloruse;
291
    logbrush.lbHatch = (ULONG_PTR)data;
292

293
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
294 295 296
}


Alexandre Julliard's avatar
Alexandre Julliard committed
297
/***********************************************************************
298
 *           CreateSolidBrush    (GDI32.@)
299 300 301 302 303 304 305 306 307 308 309 310 311 312
 *
 * 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
313
 */
314
HBRUSH WINAPI CreateSolidBrush( COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
315
{
316 317
    LOGBRUSH logbrush;

318
    TRACE("%06x\n", color );
319 320 321 322 323

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

324
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
325 326 327
}


Alexandre Julliard's avatar
Alexandre Julliard committed
328
/***********************************************************************
329
 *           SetBrushOrgEx    (GDI32.@)
330 331 332 333 334 335 336 337 338 339 340
 *
 * Set the brush origin for a device context.
 *
 * PARAMS
 *  hdc    [I] Device context to set the brush origin for 
 *  x      [I] New x origin
 *  y      [I] Ney y origin
 *  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
341
 */
342
BOOL WINAPI SetBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
Alexandre Julliard's avatar
Alexandre Julliard committed
343
{
344
    DC *dc = get_dc_ptr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
345 346 347 348

    if (!dc) return FALSE;
    if (oldorg)
    {
349 350
        oldorg->x = dc->brushOrgX;
        oldorg->y = dc->brushOrgY;
Alexandre Julliard's avatar
Alexandre Julliard committed
351
    }
352 353
    dc->brushOrgX = x;
    dc->brushOrgY = y;
354
    release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
355 356 357
    return TRUE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
358
/***********************************************************************
359
 *           FixBrushOrgEx    (GDI32.@)
360 361 362 363 364 365
 *
 * 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
366
 */
367
BOOL WINAPI FixBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
Alexandre Julliard's avatar
Alexandre Julliard committed
368 369 370 371
{
    return SetBrushOrgEx(hdc,x,y,oldorg);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
372

373 374 375
/***********************************************************************
 *           BRUSH_SelectObject
 */
376
static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, HDC hdc )
377
{
378 379 380
    BRUSHOBJ *brush;
    HGDIOBJ ret = 0;
    DC *dc = get_dc_ptr( hdc );
381

382 383 384 385 386
    if (!dc)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return 0;
    }
387

388
    if ((brush = GDI_GetObjPtr( handle, OBJ_BRUSH )))
389
    {
390 391
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSelectBrush );

392
        if (brush->logbrush.lbStyle == BS_PATTERN)
393 394 395 396 397 398 399 400 401
        {
            PHYSDEV pattern_dev = physdev;
            /* FIXME: This will go away once the dib driver implements
               pattern brushes */
            if(pattern_dev == &dc->dibdrv.dev)
                pattern_dev = GET_NEXT_PHYSDEV( physdev, pSelectBrush );

            BITMAP_SetOwnerDC( (HBITMAP)brush->logbrush.lbHatch, pattern_dev );
        }
402

403 404 405
        GDI_inc_ref_count( handle );
        GDI_ReleaseObj( handle );

406
        if (!physdev->funcs->pSelectBrush( physdev, handle ))
407 408 409 410
        {
            GDI_dec_ref_count( handle );
        }
        else
411 412 413 414 415
        {
            ret = dc->hBrush;
            dc->hBrush = handle;
            GDI_dec_ref_count( ret );
        }
416 417
    }
    release_dc_ptr( dc );
418 419 420 421
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
422 423 424
/***********************************************************************
 *           BRUSH_DeleteObject
 */
425
static BOOL BRUSH_DeleteObject( HGDIOBJ handle )
Alexandre Julliard's avatar
Alexandre Julliard committed
426
{
427
    BRUSHOBJ *brush = free_gdi_handle( handle );
428

429
    if (!brush) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
430 431 432
    switch(brush->logbrush.lbStyle)
    {
      case BS_PATTERN:
433
	  DeleteObject( (HGDIOBJ)brush->logbrush.lbHatch );
Alexandre Julliard's avatar
Alexandre Julliard committed
434 435
	  break;
      case BS_DIBPATTERN:
436
	  GlobalFree( (HGLOBAL)brush->logbrush.lbHatch );
Alexandre Julliard's avatar
Alexandre Julliard committed
437 438
	  break;
    }
439
    return HeapFree( GetProcessHeap(), 0, brush );
Alexandre Julliard's avatar
Alexandre Julliard committed
440 441 442
}


Alexandre Julliard's avatar
Alexandre Julliard committed
443
/***********************************************************************
444
 *           BRUSH_GetObject
Alexandre Julliard's avatar
Alexandre Julliard committed
445
 */
446
static INT BRUSH_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
Alexandre Julliard's avatar
Alexandre Julliard committed
447
{
448
    BRUSHOBJ *brush = GDI_GetObjPtr( handle, OBJ_BRUSH );
449

450 451 452 453 454 455 456 457
    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
458 459
    return count;
}