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