gdi32: Always store a DIBSECTION structure in the bitmap object.
[wine] / dlls / gdi32 / brush.c
1 /*
2  * GDI brush objects
3  *
4  * Copyright 1993, 1994  Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * 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 #include "config.h"
22
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"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
33
34 /* GDI logical brush object */
35 typedef struct
36 {
37     GDIOBJHDR             header;
38     LOGBRUSH              logbrush;
39     struct brush_pattern  pattern;
40 } BRUSHOBJ;
41
42 #define NB_HATCH_STYLES  6
43
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 static const struct gdi_obj_funcs brush_funcs =
49 {
50     BRUSH_SelectObject,  /* pSelectObject */
51     BRUSH_GetObject,     /* pGetObjectA */
52     BRUSH_GetObject,     /* pGetObjectW */
53     NULL,                /* pUnrealizeObject */
54     BRUSH_DeleteObject   /* pDeleteObject */
55 };
56
57
58 /* fetch the contents of the brush bitmap and cache them in the brush pattern */
59 void cache_pattern_bits( PHYSDEV physdev, struct brush_pattern *pattern )
60 {
61     struct gdi_image_bits bits;
62     struct bitblt_coords src;
63     BITMAPINFO *info;
64     BITMAPOBJ *bmp;
65
66     if (pattern->info) return;  /* already cached */
67     if (!(bmp = GDI_GetObjPtr( pattern->bitmap, OBJ_BITMAP ))) return;
68
69     /* we don't need to cache if we are selecting into the same type of DC */
70     if (physdev && bmp->funcs == physdev->funcs) goto done;
71
72     if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
73
74     src.visrect.left   = src.x = 0;
75     src.visrect.top    = src.y = 0;
76     src.visrect.right  = src.width = bmp->bitmap.bmWidth;
77     src.visrect.bottom = src.height = bmp->bitmap.bmHeight;
78     if (bmp->funcs->pGetImage( NULL, pattern->bitmap, info, &bits, &src ))
79     {
80         HeapFree( GetProcessHeap(), 0, info );
81         goto done;
82     }
83
84     /* release the unneeded space */
85     HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, info,
86                  get_dib_info_size( info, DIB_RGB_COLORS ));
87     pattern->info  = info;
88     pattern->bits  = bits;
89     pattern->usage = DIB_RGB_COLORS;
90
91 done:
92     GDI_ReleaseObj( pattern->bitmap );
93 }
94
95 static BOOL copy_bitmap( struct brush_pattern *brush, HBITMAP bitmap )
96 {
97     BITMAPINFO *info;
98     BITMAPOBJ *bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP );
99
100     if (!bmp) return FALSE;
101
102     if (!is_bitmapobj_dib( bmp ))
103     {
104         if ((brush->bitmap = CreateBitmap( bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
105                                            bmp->bitmap.bmPlanes, bmp->bitmap.bmBitsPixel, NULL )))
106         {
107             if (bmp->funcs->pCopyBitmap( bitmap, brush->bitmap ))
108             {
109                 BITMAPOBJ *copy = GDI_GetObjPtr( brush->bitmap, OBJ_BITMAP );
110                 copy->funcs = bmp->funcs;
111                 GDI_ReleaseObj( copy );
112             }
113             else
114             {
115                 DeleteObject( brush->bitmap );
116                 brush->bitmap = 0;
117             }
118         }
119         GDI_ReleaseObj( bitmap );
120         return brush->bitmap != 0;
121     }
122
123     info = HeapAlloc( GetProcessHeap(), 0,
124                       get_dib_info_size( (BITMAPINFO *)&bmp->dib.dsBmih, DIB_RGB_COLORS ));
125     if (!info) goto done;
126     info->bmiHeader = bmp->dib.dsBmih;
127     if (info->bmiHeader.biCompression == BI_BITFIELDS)
128         memcpy( &info->bmiHeader + 1, bmp->dib.dsBitfields, sizeof(bmp->dib.dsBitfields) );
129     else if (info->bmiHeader.biClrUsed)
130         memcpy( &info->bmiHeader + 1, bmp->color_table, info->bmiHeader.biClrUsed * sizeof(RGBQUAD) );
131     if (!(brush->bits.ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
132     {
133         HeapFree( GetProcessHeap(), 0, info );
134         goto done;
135     }
136     memcpy( brush->bits.ptr, bmp->dib.dsBm.bmBits, info->bmiHeader.biSizeImage );
137     brush->bits.is_copy = TRUE;
138     brush->bits.free = free_heap_bits;
139     brush->info = info;
140     brush->usage = DIB_RGB_COLORS;
141
142 done:
143     GDI_ReleaseObj( bitmap );
144     return brush->info != NULL;
145 }
146
147 BOOL store_brush_pattern( LOGBRUSH *brush, struct brush_pattern *pattern )
148 {
149     HGLOBAL hmem = 0;
150
151     pattern->bitmap = 0;
152     pattern->info = NULL;
153     pattern->bits.free = NULL;
154
155     switch (brush->lbStyle)
156     {
157     case BS_SOLID:
158     case BS_HOLLOW:
159         return TRUE;
160
161     case BS_HATCHED:
162         if (brush->lbHatch > HS_DIAGCROSS)
163         {
164             if (brush->lbHatch >= HS_API_MAX) return FALSE;
165             brush->lbStyle = BS_SOLID;
166             brush->lbHatch = 0;
167         }
168         return TRUE;
169
170     case BS_PATTERN8X8:
171         brush->lbStyle = BS_PATTERN;
172         /* fall through */
173     case BS_PATTERN:
174         brush->lbColor = 0;
175         return copy_bitmap( pattern, (HBITMAP)brush->lbHatch );
176
177     case BS_DIBPATTERN:
178         hmem = (HGLOBAL)brush->lbHatch;
179         if (!(brush->lbHatch = (ULONG_PTR)GlobalLock( hmem ))) return FALSE;
180         /* fall through */
181     case BS_DIBPATTERNPT:
182         pattern->usage = brush->lbColor;
183         pattern->info = copy_packed_dib( (BITMAPINFO *)brush->lbHatch, pattern->usage );
184         if (hmem) GlobalUnlock( hmem );
185         if (!pattern->info) return FALSE;
186         pattern->bits.ptr = (char *)pattern->info + get_dib_info_size( pattern->info, pattern->usage );
187         brush->lbStyle = BS_DIBPATTERN;
188         brush->lbColor = 0;
189         return TRUE;
190
191     case BS_DIBPATTERN8X8:
192     case BS_MONOPATTERN:
193     case BS_INDEXED:
194     default:
195         WARN( "invalid brush style %u\n", brush->lbStyle );
196         return FALSE;
197     }
198 }
199
200 void free_brush_pattern( struct brush_pattern *pattern )
201 {
202     if (pattern->bits.free) pattern->bits.free( &pattern->bits );
203     if (pattern->bitmap) DeleteObject( pattern->bitmap );
204     HeapFree( GetProcessHeap(), 0, pattern->info );
205 }
206
207 BOOL get_brush_bitmap_info( HBRUSH handle, BITMAPINFO *info, void **bits, UINT *usage )
208 {
209     BRUSHOBJ *brush;
210     BOOL ret = FALSE;
211
212     if (!(brush = GDI_GetObjPtr( handle, OBJ_BRUSH ))) return FALSE;
213
214     if (!brush->pattern.info) cache_pattern_bits( NULL, &brush->pattern );
215
216     if (brush->pattern.info)
217     {
218         memcpy( info, brush->pattern.info, get_dib_info_size( brush->pattern.info, brush->pattern.usage ));
219         if (info->bmiHeader.biBitCount <= 8 && !info->bmiHeader.biClrUsed)
220             fill_default_color_table( info );
221         *bits = brush->pattern.bits.ptr;
222         *usage = brush->pattern.usage;
223         ret = TRUE;
224     }
225     GDI_ReleaseObj( handle );
226     return ret;
227 }
228
229
230 /***********************************************************************
231  *           CreateBrushIndirect    (GDI32.@)
232  *
233  * Create a logical brush with a given style, color or pattern.
234  *
235  * PARAMS
236  *  brush [I] Pointer to a LOGBRUSH structure describing the desired brush.
237  *
238  * RETURNS
239  *  A handle to the created brush, or a NULL handle if the brush cannot be 
240  *  created.
241  *
242  * NOTES
243  * - The brush returned should be freed by the caller using DeleteObject()
244  *   when it is no longer required.
245  * - Windows 95 and earlier cannot create brushes from bitmaps or DIBs larger
246  *   than 8x8 pixels. If a larger bitmap is given, only a portion of the bitmap
247  *   is used.
248  */
249 HBRUSH WINAPI CreateBrushIndirect( const LOGBRUSH * brush )
250 {
251     BRUSHOBJ * ptr;
252     HBRUSH hbrush;
253
254     if (!(ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(*ptr) ))) return 0;
255
256     ptr->logbrush = *brush;
257
258     if (store_brush_pattern( &ptr->logbrush, &ptr->pattern ) &&
259         (hbrush = alloc_gdi_handle( &ptr->header, OBJ_BRUSH, &brush_funcs )))
260     {
261         TRACE("%p\n", hbrush);
262         return hbrush;
263     }
264
265     free_brush_pattern( &ptr->pattern );
266     HeapFree( GetProcessHeap(), 0, ptr );
267     return 0;
268 }
269
270
271 /***********************************************************************
272  *           CreateHatchBrush    (GDI32.@)
273  *
274  * Create a logical brush with a hatched pattern.
275  *
276  * PARAMS
277  *  style [I] Direction of lines for the hatch pattern (HS_* values from "wingdi.h")
278  *  color [I] Colour of the hatched pattern
279  *
280  * RETURNS
281  *  A handle to the created brush, or a NULL handle if the brush cannot
282  *  be created.
283  *
284  * NOTES
285  * - This function uses CreateBrushIndirect() to create the brush.
286  * - The brush returned should be freed by the caller using DeleteObject()
287  *   when it is no longer required.
288  */
289 HBRUSH WINAPI CreateHatchBrush( INT style, COLORREF color )
290 {
291     LOGBRUSH logbrush;
292
293     TRACE("%d %06x\n", style, color );
294
295     logbrush.lbStyle = BS_HATCHED;
296     logbrush.lbColor = color;
297     logbrush.lbHatch = style;
298
299     return CreateBrushIndirect( &logbrush );
300 }
301
302
303 /***********************************************************************
304  *           CreatePatternBrush    (GDI32.@)
305  *
306  * Create a logical brush with a pattern from a bitmap.
307  *
308  * PARAMS
309  *  hbitmap  [I] Bitmap containing pattern for the brush
310  *
311  * RETURNS
312  *  A handle to the created brush, or a NULL handle if the brush cannot 
313  *  be created.
314  *
315  * NOTES
316  * - This function uses CreateBrushIndirect() to create the brush.
317  * - The brush returned should be freed by the caller using DeleteObject()
318  *   when it is no longer required.
319  */
320 HBRUSH WINAPI CreatePatternBrush( HBITMAP hbitmap )
321 {
322     LOGBRUSH logbrush = { BS_PATTERN, 0, 0 };
323     TRACE("%p\n", hbitmap );
324
325     logbrush.lbHatch = (ULONG_PTR)hbitmap;
326     return CreateBrushIndirect( &logbrush );
327 }
328
329
330 /***********************************************************************
331  *           CreateDIBPatternBrush    (GDI32.@)
332  *
333  * Create a logical brush with a pattern from a DIB.
334  *
335  * PARAMS
336  *  hbitmap  [I] Global object containing BITMAPINFO structure for the pattern
337  *  coloruse [I] Specifies color format, if provided
338  *
339  * RETURNS
340  *  A handle to the created brush, or a NULL handle if the brush cannot 
341  *  be created.
342  *
343  * NOTES
344  * - This function uses CreateBrushIndirect() to create the brush.
345  * - The brush returned should be freed by the caller using DeleteObject()
346  *   when it is no longer required.
347  * - This function is for compatibility only. CreateDIBPatternBrushPt() should 
348  *   be used instead.
349  */
350 HBRUSH WINAPI CreateDIBPatternBrush( HGLOBAL hbitmap, UINT coloruse )
351 {
352     LOGBRUSH logbrush;
353
354     TRACE("%p\n", hbitmap );
355
356     logbrush.lbStyle = BS_DIBPATTERN;
357     logbrush.lbColor = coloruse;
358
359     logbrush.lbHatch = (ULONG_PTR)hbitmap;
360
361     return CreateBrushIndirect( &logbrush );
362 }
363
364
365 /***********************************************************************
366  *           CreateDIBPatternBrushPt    (GDI32.@)
367  *
368  * Create a logical brush with a pattern from a DIB.
369  *
370  * PARAMS
371  *  data     [I] Pointer to a BITMAPINFO structure and image data  for the pattern
372  *  coloruse [I] Specifies color format, if provided
373  *
374  * RETURNS
375  *  A handle to the created brush, or a NULL handle if the brush cannot
376  *  be created.
377  *
378  * NOTES
379  * - This function uses CreateBrushIndirect() to create the brush.
380  * - The brush returned should be freed by the caller using DeleteObject()
381  *   when it is no longer required.
382  */
383 HBRUSH WINAPI CreateDIBPatternBrushPt( const void* data, UINT coloruse )
384 {
385     const BITMAPINFO *info=data;
386     LOGBRUSH logbrush;
387
388     if (!data)
389         return NULL;
390
391     TRACE("%p %dx%d %dbpp\n", info, info->bmiHeader.biWidth,
392           info->bmiHeader.biHeight,  info->bmiHeader.biBitCount);
393
394     logbrush.lbStyle = BS_DIBPATTERNPT;
395     logbrush.lbColor = coloruse;
396     logbrush.lbHatch = (ULONG_PTR)data;
397
398     return CreateBrushIndirect( &logbrush );
399 }
400
401
402 /***********************************************************************
403  *           CreateSolidBrush    (GDI32.@)
404  *
405  * Create a logical brush consisting of a single colour.
406  *
407  * PARAMS
408  *  color [I] Colour to make the solid brush
409  *
410  * RETURNS
411  *  A handle to the newly created brush, or a NULL handle if the brush cannot
412  *  be created.
413  *
414  * NOTES
415  * - This function uses CreateBrushIndirect() to create the brush.
416  * - The brush returned should be freed by the caller using DeleteObject()
417  *   when it is no longer required.
418  */
419 HBRUSH WINAPI CreateSolidBrush( COLORREF color )
420 {
421     LOGBRUSH logbrush;
422
423     TRACE("%06x\n", color );
424
425     logbrush.lbStyle = BS_SOLID;
426     logbrush.lbColor = color;
427     logbrush.lbHatch = 0;
428
429     return CreateBrushIndirect( &logbrush );
430 }
431
432
433 /***********************************************************************
434  *           SetBrushOrgEx    (GDI32.@)
435  *
436  * Set the brush origin for a device context.
437  *
438  * PARAMS
439  *  hdc    [I] Device context to set the brush origin for
440  *  x      [I] New x origin
441  *  y      [I] New y origin
442  *  oldorg [O] If non NULL, destination for previously set brush origin.
443  *
444  * RETURNS
445  *  Success: TRUE. The origin is set to (x,y), and oldorg is updated if given.
446  */
447 BOOL WINAPI SetBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
448 {
449     DC *dc = get_dc_ptr( hdc );
450
451     if (!dc) return FALSE;
452     if (oldorg)
453     {
454         oldorg->x = dc->brushOrgX;
455         oldorg->y = dc->brushOrgY;
456     }
457     dc->brushOrgX = x;
458     dc->brushOrgY = y;
459     release_dc_ptr( dc );
460     return TRUE;
461 }
462
463 /***********************************************************************
464  *           FixBrushOrgEx    (GDI32.@)
465  *
466  * See SetBrushOrgEx.
467  *
468  * NOTES
469  *  This function is no longer documented by MSDN, but in Win95 GDI32 it
470  *  is the same as SetBrushOrgEx().
471  */
472 BOOL WINAPI FixBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
473 {
474     return SetBrushOrgEx(hdc,x,y,oldorg);
475 }
476
477
478 /***********************************************************************
479  *           BRUSH_SelectObject
480  */
481 static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, HDC hdc )
482 {
483     BRUSHOBJ *brush;
484     HGDIOBJ ret = 0;
485     DC *dc = get_dc_ptr( hdc );
486
487     if (!dc)
488     {
489         SetLastError( ERROR_INVALID_HANDLE );
490         return 0;
491     }
492
493     if ((brush = GDI_GetObjPtr( handle, OBJ_BRUSH )))
494     {
495         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSelectBrush );
496         struct brush_pattern *pattern = &brush->pattern;
497
498         if (!pattern->info)
499         {
500             if (pattern->bitmap) cache_pattern_bits( physdev, pattern );
501             else pattern = NULL;
502         }
503
504         GDI_inc_ref_count( handle );
505         GDI_ReleaseObj( handle );
506
507         if (!physdev->funcs->pSelectBrush( physdev, handle, pattern ))
508         {
509             GDI_dec_ref_count( handle );
510         }
511         else
512         {
513             ret = dc->hBrush;
514             dc->hBrush = handle;
515             GDI_dec_ref_count( ret );
516         }
517     }
518     release_dc_ptr( dc );
519     return ret;
520 }
521
522
523 /***********************************************************************
524  *           BRUSH_DeleteObject
525  */
526 static BOOL BRUSH_DeleteObject( HGDIOBJ handle )
527 {
528     BRUSHOBJ *brush = free_gdi_handle( handle );
529
530     if (!brush) return FALSE;
531     free_brush_pattern( &brush->pattern );
532     return HeapFree( GetProcessHeap(), 0, brush );
533 }
534
535
536 /***********************************************************************
537  *           BRUSH_GetObject
538  */
539 static INT BRUSH_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
540 {
541     BRUSHOBJ *brush = GDI_GetObjPtr( handle, OBJ_BRUSH );
542
543     if (!brush) return 0;
544     if (buffer)
545     {
546         if (count > sizeof(brush->logbrush)) count = sizeof(brush->logbrush);
547         memcpy( buffer, &brush->logbrush, count );
548     }
549     else count = sizeof(brush->logbrush);
550     GDI_ReleaseObj( handle );
551     return count;
552 }