Implement AlphaBlend using the XRENDER extension.
[wine] / dlls / gdi / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "wine/wingdi16.h"
30 #include "gdi.h"
31 #include "wownt32.h"
32 #include "gdi_private.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
36
37 /* GDI logical brush object */
38 typedef struct
39 {
40     GDIOBJHDR header;
41     LOGBRUSH  logbrush;
42 } BRUSHOBJ;
43
44 #define NB_HATCH_STYLES  6
45
46 static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, void *obj, HDC hdc );
47 static INT BRUSH_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
48 static INT BRUSH_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
49 static BOOL BRUSH_DeleteObject( HGDIOBJ handle, void *obj );
50
51 static const struct gdi_obj_funcs brush_funcs =
52 {
53     BRUSH_SelectObject,  /* pSelectObject */
54     BRUSH_GetObject16,   /* pGetObject16 */
55     BRUSH_GetObject,     /* pGetObjectA */
56     BRUSH_GetObject,     /* pGetObjectW */
57     NULL,                /* pUnrealizeObject */
58     BRUSH_DeleteObject   /* pDeleteObject */
59 };
60
61 static HGLOBAL16 dib_copy(BITMAPINFO *info, UINT coloruse)
62 {
63     BITMAPINFO  *newInfo;
64     HGLOBAL16   hmem;
65     INT         size;
66
67     if (info->bmiHeader.biCompression)
68         size = info->bmiHeader.biSizeImage;
69     else
70         size = DIB_GetDIBImageBytes(info->bmiHeader.biWidth,
71                                     info->bmiHeader.biHeight,
72                                     info->bmiHeader.biBitCount);
73     size += DIB_BitmapInfoSize( info, coloruse );
74
75     if (!(hmem = GlobalAlloc16( GMEM_MOVEABLE, size )))
76     {
77         return 0;
78     }
79     newInfo = (BITMAPINFO *) GlobalLock16( hmem );
80     memcpy( newInfo, info, size );
81     GlobalUnlock16( hmem );
82     return hmem;
83 }
84
85
86 /***********************************************************************
87  *           CreateBrushIndirect    (GDI32.@)
88  *
89  * BUGS
90  *      As for Windows 95 and Windows 98:
91  *      Creating brushes from bitmaps or DIBs larger than 8x8 pixels
92  *      is not supported. If a larger bitmap is given, only a portion
93  *      of the bitmap is used.
94  */
95 HBRUSH WINAPI CreateBrushIndirect( const LOGBRUSH * brush )
96 {
97     BRUSHOBJ * ptr;
98     HBRUSH hbrush;
99
100     if (!(ptr = GDI_AllocObject( sizeof(BRUSHOBJ), BRUSH_MAGIC,
101                                  (HGDIOBJ *)&hbrush, &brush_funcs ))) return 0;
102     ptr->logbrush.lbStyle = brush->lbStyle;
103     ptr->logbrush.lbColor = brush->lbColor;
104     ptr->logbrush.lbHatch = brush->lbHatch;
105
106     switch (ptr->logbrush.lbStyle)
107     {
108     case BS_PATTERN8X8:
109         ptr->logbrush.lbStyle = BS_PATTERN;
110         /* fall through */
111     case BS_PATTERN:
112         ptr->logbrush.lbHatch = (LONG)BITMAP_CopyBitmap( (HBITMAP) ptr->logbrush.lbHatch );
113         if (!ptr->logbrush.lbHatch) goto error;
114         break;
115
116     case BS_DIBPATTERNPT:
117         ptr->logbrush.lbStyle = BS_DIBPATTERN;
118         ptr->logbrush.lbHatch = (LONG)dib_copy( (BITMAPINFO *) ptr->logbrush.lbHatch,
119                                                 ptr->logbrush.lbColor);
120         if (!ptr->logbrush.lbHatch) goto error;
121         break;
122
123     case BS_DIBPATTERN8X8:
124     case BS_DIBPATTERN:
125        {
126             BITMAPINFO* bmi;
127             HGLOBAL h = (HGLOBAL)ptr->logbrush.lbHatch;
128
129             ptr->logbrush.lbStyle = BS_DIBPATTERN;
130             if (!(bmi = (BITMAPINFO *)GlobalLock( h ))) goto error;
131             ptr->logbrush.lbHatch = dib_copy( bmi, ptr->logbrush.lbColor);
132             GlobalUnlock( h );
133             if (!ptr->logbrush.lbHatch) goto error;
134             break;
135        }
136
137     default:
138         if(ptr->logbrush.lbStyle > BS_MONOPATTERN) goto error;
139         break;
140     }
141
142     GDI_ReleaseObj( hbrush );
143     TRACE("%p\n", hbrush);
144     return hbrush;
145
146  error:
147     GDI_FreeObject( hbrush, ptr );
148     return 0;
149 }
150
151
152 /***********************************************************************
153  *           CreateHatchBrush    (GDI32.@)
154  */
155 HBRUSH WINAPI CreateHatchBrush( INT style, COLORREF color )
156 {
157     LOGBRUSH logbrush;
158
159     TRACE("%d %06lx\n", style, color );
160
161     logbrush.lbStyle = BS_HATCHED;
162     logbrush.lbColor = color;
163     logbrush.lbHatch = style;
164
165     return CreateBrushIndirect( &logbrush );
166 }
167
168
169 /***********************************************************************
170  *           CreatePatternBrush    (GDI32.@)
171  */
172 HBRUSH WINAPI CreatePatternBrush( HBITMAP hbitmap )
173 {
174     LOGBRUSH logbrush = { BS_PATTERN, 0, 0 };
175     TRACE("%p\n", hbitmap );
176
177     logbrush.lbHatch = (ULONG_PTR)hbitmap;
178     return CreateBrushIndirect( &logbrush );
179 }
180
181
182 /***********************************************************************
183  *           CreateDIBPatternBrush    (GDI32.@)
184  *
185  *      Create a logical brush which has the pattern specified by the DIB
186  *
187  *      Function call is for compatibility only.  CreateDIBPatternBrushPt should be used.
188  *
189  * RETURNS
190  *
191  *      Handle to a logical brush on success, NULL on failure.
192  *
193  * BUGS
194  *
195  */
196 HBRUSH WINAPI CreateDIBPatternBrush(
197                 HGLOBAL hbitmap, /* [in] Global object containg BITMAPINFO structure */
198                 UINT coloruse    /* [in] Specifies color format, if provided */
199 )
200 {
201     LOGBRUSH logbrush;
202
203     TRACE("%p\n", hbitmap );
204
205     logbrush.lbStyle = BS_DIBPATTERN;
206     logbrush.lbColor = coloruse;
207
208     logbrush.lbHatch = (LONG)hbitmap;
209
210     return CreateBrushIndirect( &logbrush );
211 }
212
213
214 /***********************************************************************
215  *           CreateDIBPatternBrushPt    (GDI32.@)
216  *
217  *      Create a logical brush which has the pattern specified by the DIB
218  *
219  * RETURNS
220  *
221  *      Handle to a logical brush on success, NULL on failure.
222  *
223  * BUGS
224  *
225  */
226 HBRUSH WINAPI CreateDIBPatternBrushPt(
227                 const void* data, /* [in] Pointer to a BITMAPINFO structure followed by more data */
228                 UINT coloruse     /* [in] Specifies color format, if provided */
229 )
230 {
231     BITMAPINFO *info=(BITMAPINFO*)data;
232     LOGBRUSH logbrush;
233
234     if (!data)
235         return NULL;
236
237     TRACE("%p %ldx%ld %dbpp\n", info, info->bmiHeader.biWidth,
238           info->bmiHeader.biHeight,  info->bmiHeader.biBitCount);
239
240     logbrush.lbStyle = BS_DIBPATTERNPT;
241     logbrush.lbColor = coloruse;
242     logbrush.lbHatch = (LONG) data;
243
244     return CreateBrushIndirect( &logbrush );
245 }
246
247
248 /***********************************************************************
249  *           CreateSolidBrush    (GDI32.@)
250  */
251 HBRUSH WINAPI CreateSolidBrush( COLORREF color )
252 {
253     LOGBRUSH logbrush;
254
255     TRACE("%06lx\n", color );
256
257     logbrush.lbStyle = BS_SOLID;
258     logbrush.lbColor = color;
259     logbrush.lbHatch = 0;
260
261     return CreateBrushIndirect( &logbrush );
262 }
263
264
265 /***********************************************************************
266  *           SetBrushOrgEx    (GDI32.@)
267  */
268 BOOL WINAPI SetBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
269 {
270     DC *dc = DC_GetDCPtr( hdc );
271
272     if (!dc) return FALSE;
273     if (oldorg)
274     {
275         oldorg->x = dc->brushOrgX;
276         oldorg->y = dc->brushOrgY;
277     }
278     dc->brushOrgX = x;
279     dc->brushOrgY = y;
280     GDI_ReleaseObj( hdc );
281     return TRUE;
282 }
283
284 /***********************************************************************
285  *           FixBrushOrgEx    (GDI32.@)
286  * SDK says discontinued, but in Win95 GDI32 this is the same as SetBrushOrgEx
287  */
288 BOOL WINAPI FixBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
289 {
290     return SetBrushOrgEx(hdc,x,y,oldorg);
291 }
292
293
294 /***********************************************************************
295  *           BRUSH_SelectObject
296  */
297 static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, void *obj, HDC hdc )
298 {
299     BRUSHOBJ *brush = obj;
300     HGDIOBJ ret;
301     DC *dc = DC_GetDCPtr( hdc );
302
303     if (!dc) return 0;
304
305     if (brush->logbrush.lbStyle == BS_PATTERN)
306         BITMAP_SetOwnerDC( (HBITMAP)brush->logbrush.lbHatch, dc );
307
308     ret = dc->hBrush;
309     if (dc->funcs->pSelectBrush) handle = dc->funcs->pSelectBrush( dc->physDev, handle );
310     if (handle) dc->hBrush = handle;
311     else ret = 0;
312     GDI_ReleaseObj( hdc );
313     return ret;
314 }
315
316
317 /***********************************************************************
318  *           BRUSH_DeleteObject
319  */
320 static BOOL BRUSH_DeleteObject( HGDIOBJ handle, void *obj )
321 {
322     BRUSHOBJ *brush = obj;
323
324     switch(brush->logbrush.lbStyle)
325     {
326       case BS_PATTERN:
327           DeleteObject( (HGDIOBJ)brush->logbrush.lbHatch );
328           break;
329       case BS_DIBPATTERN:
330           GlobalFree16( (HGLOBAL16)brush->logbrush.lbHatch );
331           break;
332     }
333     return GDI_FreeObject( handle, obj );
334 }
335
336
337 /***********************************************************************
338  *           BRUSH_GetObject16
339  */
340 static INT BRUSH_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
341 {
342     BRUSHOBJ *brush = obj;
343     LOGBRUSH16 logbrush;
344
345     logbrush.lbStyle = brush->logbrush.lbStyle;
346     logbrush.lbColor = brush->logbrush.lbColor;
347     logbrush.lbHatch = brush->logbrush.lbHatch;
348     if (count > sizeof(logbrush)) count = sizeof(logbrush);
349     memcpy( buffer, &logbrush, count );
350     return count;
351 }
352
353
354 /***********************************************************************
355  *           BRUSH_GetObject
356  */
357 static INT BRUSH_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
358 {
359     BRUSHOBJ *brush = obj;
360
361     if( !buffer )
362         return sizeof(brush->logbrush);
363
364     if (count > sizeof(brush->logbrush)) count = sizeof(brush->logbrush);
365     memcpy( buffer, &brush->logbrush, count );
366     return count;
367 }
368
369
370 /***********************************************************************
371  *           SetSolidBrush   (GDI.604)
372  *
373  *  If hBrush is a solid brush, change its color to newColor.
374  *
375  *  RETURNS
376  *           TRUE on success, FALSE on failure.
377  *
378  *  FIXME: untested, not sure if correct.
379  */
380 BOOL16 WINAPI SetSolidBrush16(HBRUSH16 hBrush, COLORREF newColor )
381 {
382     BRUSHOBJ * brushPtr;
383     BOOL16 res = FALSE;
384
385     TRACE("(hBrush %04x, newColor %08lx)\n", hBrush, (DWORD)newColor);
386     if (!(brushPtr = (BRUSHOBJ *) GDI_GetObjPtr( HBRUSH_32(hBrush), BRUSH_MAGIC )))
387         return FALSE;
388
389     if (brushPtr->logbrush.lbStyle == BS_SOLID)
390     {
391         brushPtr->logbrush.lbColor = newColor;
392         res = TRUE;
393     }
394
395      GDI_ReleaseObj( HBRUSH_32(hBrush) );
396      return res;
397 }