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