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