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