brush.c 13.2 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 18
 *
 * 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 29
#include "wingdi.h"
#include "wine/wingdi16.h"
30
#include "gdi.h"
Michael Stefaniuc's avatar
Michael Stefaniuc committed
31
#include "wownt32.h"
32
#include "gdi_private.h"
33
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
34

35
WINE_DEFAULT_DEBUG_CHANNEL(gdi);
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
/* GDI logical brush object */
typedef struct
{
    GDIOBJHDR header;
    LOGBRUSH  logbrush;
} BRUSHOBJ;

#define NB_HATCH_STYLES  6

static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, void *obj, HDC hdc );
static INT BRUSH_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
static INT BRUSH_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
static BOOL BRUSH_DeleteObject( HGDIOBJ handle, void *obj );

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

Ulrich Czekalla's avatar
Ulrich Czekalla committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
static HGLOBAL16 dib_copy(BITMAPINFO *info, UINT coloruse)
{
    BITMAPINFO  *newInfo;
    HGLOBAL16   hmem;
    INT         size;

    if (info->bmiHeader.biCompression)
        size = info->bmiHeader.biSizeImage;
    else
        size = DIB_GetDIBImageBytes(info->bmiHeader.biWidth,
                                    info->bmiHeader.biHeight,
                                    info->bmiHeader.biBitCount);
    size += DIB_BitmapInfoSize( info, coloruse );

    if (!(hmem = GlobalAlloc16( GMEM_MOVEABLE, size )))
    {
        return 0;
    }
    newInfo = (BITMAPINFO *) GlobalLock16( hmem );
    memcpy( newInfo, info, size );
    GlobalUnlock16( hmem );
    return hmem;
}


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

Michael Stefaniuc's avatar
Michael Stefaniuc committed
110
    if (!(ptr = GDI_AllocObject( sizeof(BRUSHOBJ), BRUSH_MAGIC,
111
                                (HGDIOBJ *)&hbrush, &brush_funcs ))) return 0;
112 113 114 115 116
    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
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
    case BS_PATTERN8X8:
        ptr->logbrush.lbStyle = BS_PATTERN;
        /* fall through */
    case BS_PATTERN:
        ptr->logbrush.lbHatch = (LONG)BITMAP_CopyBitmap( (HBITMAP) ptr->logbrush.lbHatch );
        if (!ptr->logbrush.lbHatch) goto error;
        break;

    case BS_DIBPATTERNPT:
        ptr->logbrush.lbStyle = BS_DIBPATTERN;
        ptr->logbrush.lbHatch = (LONG)dib_copy( (BITMAPINFO *) ptr->logbrush.lbHatch,
                                                ptr->logbrush.lbColor);
        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;
            if (!(bmi = (BITMAPINFO *)GlobalLock( h ))) goto error;
            ptr->logbrush.lbHatch = dib_copy( bmi, ptr->logbrush.lbColor);
            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
150
    }
151 152

    GDI_ReleaseObj( hbrush );
153
    TRACE("%p\n", hbrush);
Alexandre Julliard's avatar
Alexandre Julliard committed
154
    return hbrush;
155 156 157 158

 error:
    GDI_FreeObject( hbrush, ptr );
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
159 160 161 162
}


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

184
    TRACE("%d %06lx\n", style, color );
185 186 187 188 189

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

190
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
191 192 193
}


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

216
    logbrush.lbHatch = (ULONG_PTR)hbitmap;
217
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
218 219 220
}


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

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

247 248
    logbrush.lbStyle = BS_DIBPATTERN;
    logbrush.lbColor = coloruse;
Alexandre Julliard's avatar
Alexandre Julliard committed
249

Ulrich Czekalla's avatar
Ulrich Czekalla committed
250
    logbrush.lbHatch = (LONG)hbitmap;
Alexandre Julliard's avatar
Alexandre Julliard committed
251

252
    return CreateBrushIndirect( &logbrush );
253 254 255 256
}


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

279 280 281
    if (!data)
        return NULL;

282
    TRACE("%p %ldx%ld %dbpp\n", info, info->bmiHeader.biWidth,
283
	  info->bmiHeader.biHeight,  info->bmiHeader.biBitCount);
284

Ulrich Czekalla's avatar
Ulrich Czekalla committed
285
    logbrush.lbStyle = BS_DIBPATTERNPT;
Patrik Stridvall's avatar
Patrik Stridvall committed
286
    logbrush.lbColor = coloruse;
Ulrich Czekalla's avatar
Ulrich Czekalla committed
287
    logbrush.lbHatch = (LONG) data;
288

289
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
290 291 292
}


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

314
    TRACE("%06lx\n", color );
315 316 317 318 319

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

320
    return CreateBrushIndirect( &logbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
321 322 323
}


Alexandre Julliard's avatar
Alexandre Julliard committed
324
/***********************************************************************
325
 *           SetBrushOrgEx    (GDI32.@)
326 327 328 329 330 331 332 333 334 335 336
 *
 * 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
337
 */
338
BOOL WINAPI SetBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
Alexandre Julliard's avatar
Alexandre Julliard committed
339
{
340
    DC *dc = DC_GetDCPtr( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
341 342 343 344

    if (!dc) return FALSE;
    if (oldorg)
    {
345 346
        oldorg->x = dc->brushOrgX;
        oldorg->y = dc->brushOrgY;
Alexandre Julliard's avatar
Alexandre Julliard committed
347
    }
348 349
    dc->brushOrgX = x;
    dc->brushOrgY = y;
350
    GDI_ReleaseObj( hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
351 352 353
    return TRUE;
}

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

Alexandre Julliard's avatar
Alexandre Julliard committed
368

369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
/***********************************************************************
 *           BRUSH_SelectObject
 */
static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, void *obj, HDC hdc )
{
    BRUSHOBJ *brush = obj;
    HGDIOBJ ret;
    DC *dc = DC_GetDCPtr( hdc );

    if (!dc) return 0;

    if (brush->logbrush.lbStyle == BS_PATTERN)
        BITMAP_SetOwnerDC( (HBITMAP)brush->logbrush.lbHatch, dc );

    ret = dc->hBrush;
    if (dc->funcs->pSelectBrush) handle = dc->funcs->pSelectBrush( dc->physDev, handle );
    if (handle) dc->hBrush = handle;
    else ret = 0;
    GDI_ReleaseObj( hdc );
    return ret;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
392 393 394
/***********************************************************************
 *           BRUSH_DeleteObject
 */
395
static BOOL BRUSH_DeleteObject( HGDIOBJ handle, void *obj )
Alexandre Julliard's avatar
Alexandre Julliard committed
396
{
397 398
    BRUSHOBJ *brush = obj;

Alexandre Julliard's avatar
Alexandre Julliard committed
399 400 401
    switch(brush->logbrush.lbStyle)
    {
      case BS_PATTERN:
402
	  DeleteObject( (HGDIOBJ)brush->logbrush.lbHatch );
Alexandre Julliard's avatar
Alexandre Julliard committed
403 404
	  break;
      case BS_DIBPATTERN:
Alexandre Julliard's avatar
Alexandre Julliard committed
405
	  GlobalFree16( (HGLOBAL16)brush->logbrush.lbHatch );
Alexandre Julliard's avatar
Alexandre Julliard committed
406 407
	  break;
    }
408
    return GDI_FreeObject( handle, obj );
Alexandre Julliard's avatar
Alexandre Julliard committed
409 410 411 412
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
413
 *           BRUSH_GetObject16
Alexandre Julliard's avatar
Alexandre Julliard committed
414
 */
415
static INT BRUSH_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
Alexandre Julliard's avatar
Alexandre Julliard committed
416
{
417
    BRUSHOBJ *brush = obj;
Alexandre Julliard's avatar
Alexandre Julliard committed
418 419 420 421 422 423 424 425 426 427 428 429
    LOGBRUSH16 logbrush;

    logbrush.lbStyle = brush->logbrush.lbStyle;
    logbrush.lbColor = brush->logbrush.lbColor;
    logbrush.lbHatch = brush->logbrush.lbHatch;
    if (count > sizeof(logbrush)) count = sizeof(logbrush);
    memcpy( buffer, &logbrush, count );
    return count;
}


/***********************************************************************
430
 *           BRUSH_GetObject
Alexandre Julliard's avatar
Alexandre Julliard committed
431
 */
432
static INT BRUSH_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
Alexandre Julliard's avatar
Alexandre Julliard committed
433
{
434 435
    BRUSHOBJ *brush = obj;

436 437 438
    if( !buffer )
        return sizeof(brush->logbrush);

Alexandre Julliard's avatar
Alexandre Julliard committed
439
    if (count > sizeof(brush->logbrush)) count = sizeof(brush->logbrush);
Alexandre Julliard's avatar
Alexandre Julliard committed
440 441 442
    memcpy( buffer, &brush->logbrush, count );
    return count;
}
443 444 445


/***********************************************************************
446
 *           SetSolidBrush   (GDI.604)
447
 *
448
 * Change the color of a solid brush.
449
 *
450 451 452 453 454 455 456
 * PARAMS
 *  hBrush   [I] Brush to change the color of
 *  newColor [I] New color for hBrush
 *
 * RETURNS
 *  Success: TRUE. The color of hBrush is set to newColor.
 *  Failure: FALSE.
457
 *
458 459 460
 * FIXME
 *  This function is undocumented and untested. The implementation may
 *  not be correct.
461 462 463
 */
BOOL16 WINAPI SetSolidBrush16(HBRUSH16 hBrush, COLORREF newColor )
{
464 465 466 467
    BRUSHOBJ * brushPtr;
    BOOL16 res = FALSE;

    TRACE("(hBrush %04x, newColor %08lx)\n", hBrush, (DWORD)newColor);
Michael Stefaniuc's avatar
Michael Stefaniuc committed
468
    if (!(brushPtr = (BRUSHOBJ *) GDI_GetObjPtr( HBRUSH_32(hBrush), BRUSH_MAGIC )))
469 470 471 472 473 474 475
	return FALSE;

    if (brushPtr->logbrush.lbStyle == BS_SOLID)
    {
        brushPtr->logbrush.lbColor = newColor;
	res = TRUE;
    }
476

Michael Stefaniuc's avatar
Michael Stefaniuc committed
477
     GDI_ReleaseObj( HBRUSH_32(hBrush) );
478
     return res;
479
}