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