Fix BS_PATTERN brushes in mfdrv. Un-comment the corresponding test.
[wine] / dlls / gdi / mfdrv / objects.c
1 /*
2  * GDI objects
3  *
4  * Copyright 1993 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 <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "wownt32.h"
30 #include "mfdrv/metafiledrv.h"
31 #include "gdi.h"
32 #include "gdi_private.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
36
37 /******************************************************************
38  *         MFDRV_AddHandle
39  */
40 UINT MFDRV_AddHandle( PHYSDEV dev, HGDIOBJ obj )
41 {
42     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
43     UINT16 index;
44
45     for(index = 0; index < physDev->handles_size; index++)
46         if(physDev->handles[index] == 0) break; 
47     if(index == physDev->handles_size) {
48         physDev->handles_size += HANDLE_LIST_INC;
49         physDev->handles = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
50                                        physDev->handles,
51                                        physDev->handles_size * sizeof(physDev->handles[0]));
52     }
53     physDev->handles[index] = obj;
54
55     physDev->cur_handles++; 
56     if(physDev->cur_handles > physDev->mh->mtNoObjects)
57         physDev->mh->mtNoObjects++;
58
59     return index ; /* index 0 is not reserved for metafiles */
60 }
61
62 /******************************************************************
63  *         MFDRV_FindObject
64  */
65 static INT16 MFDRV_FindObject( PHYSDEV dev, HGDIOBJ obj )
66 {
67     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
68     INT16 index;
69
70     for(index = 0; index < physDev->handles_size; index++)
71         if(physDev->handles[index] == obj) break;
72
73     if(index == physDev->handles_size) return -1;
74
75     return index ;
76 }
77
78
79 /******************************************************************
80  *         MFDRV_DeleteObject
81  */
82 BOOL MFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj )
83 {   
84     METARECORD mr;
85     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
86     INT16 index;
87     BOOL ret = TRUE;
88
89     index = MFDRV_FindObject(dev, obj);
90     if( index < 0 )
91         return 0;
92
93     mr.rdSize = sizeof mr / 2;
94     mr.rdFunction = META_DELETEOBJECT;
95     mr.rdParm[0] = index;
96
97     if(!MFDRV_WriteRecord( dev, &mr, mr.rdSize*2 ))
98         ret = FALSE;
99
100     physDev->handles[index] = 0;
101     physDev->cur_handles--;
102     return ret;
103 }
104
105
106 /***********************************************************************
107  *           MFDRV_SelectObject
108  */
109 static BOOL MFDRV_SelectObject( PHYSDEV dev, INT16 index)
110 {
111     METARECORD mr;
112
113     mr.rdSize = sizeof mr / 2;
114     mr.rdFunction = META_SELECTOBJECT;
115     mr.rdParm[0] = index;
116
117     return MFDRV_WriteRecord( dev, &mr, mr.rdSize*2 );
118 }
119
120
121 /***********************************************************************
122  *           MFDRV_SelectBitmap
123  */
124 HBITMAP MFDRV_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
125 {
126     return 0;
127 }
128
129 /***********************************************************************
130  * Internal helper for MFDRV_CreateBrushIndirect():
131  * Change the padding of a bitmap from 16 (BMP) to 32 (DIB) bits.
132  */
133 static inline void MFDRV_PadTo32(LPBYTE lpRows, int height, int width)
134 {
135     int bytes16 = 2 * ((width + 15) / 16);
136     int bytes32 = 4 * ((width + 31) / 32);
137     LPBYTE lpSrc, lpDst;
138     int i;
139
140     if (!height)
141         return;
142
143     height = abs(height) - 1;
144     lpSrc = lpRows + height * bytes16;
145     lpDst = lpRows + height * bytes32;
146
147     /* Note that we work backwards so we can re-pad in place */
148     while (height >= 0)
149     {
150         for (i = bytes32; i > bytes16; i--)
151             lpDst[i - 1] = 0; /* Zero the padding bytes */
152         for (; i > 0; i--)
153             lpDst[i - 1] = lpSrc[i - 1]; /* Move image bytes into alignment */
154         lpSrc -= bytes16;
155         lpDst -= bytes32;
156         height--;
157     }
158 }
159
160 /***********************************************************************
161  * Internal helper for MFDRV_CreateBrushIndirect():
162  * Reverse order of bitmap rows in going from BMP to DIB.
163  */
164 static inline void MFDRV_Reverse(LPBYTE lpRows, int height, int width)
165 {
166     int bytes = 4 * ((width + 31) / 32);
167     LPBYTE lpSrc, lpDst;
168     BYTE temp;
169     int i;
170
171     if (!height)
172         return;
173
174     lpSrc = lpRows;
175     lpDst = lpRows + (height-1) * bytes;
176     height = height/2;
177
178     while (height > 0)
179     {
180         for (i = 0; i < bytes; i++)
181         {
182             temp = lpDst[i];
183             lpDst[i] = lpSrc[i];
184             lpSrc[i] = temp;
185         }
186         lpSrc += bytes;
187         lpDst -= bytes;
188         height--;
189     }
190 }
191
192 /******************************************************************
193  *         MFDRV_CreateBrushIndirect
194  */
195
196 INT16 MFDRV_CreateBrushIndirect(PHYSDEV dev, HBRUSH hBrush )
197 {
198     DWORD size;
199     METARECORD *mr;
200     LOGBRUSH logbrush;
201     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
202     BOOL r;
203
204     if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return -1;
205
206     switch(logbrush.lbStyle)
207     {
208     case BS_SOLID:
209     case BS_NULL:
210     case BS_HATCHED:
211         {
212             LOGBRUSH16 lb16;
213
214             lb16.lbStyle = logbrush.lbStyle;
215             lb16.lbColor = logbrush.lbColor;
216             lb16.lbHatch = logbrush.lbHatch;
217             size = sizeof(METARECORD) + sizeof(LOGBRUSH16) - 2;
218             mr = HeapAlloc( GetProcessHeap(), 0, size );
219             mr->rdSize = size / 2;
220             mr->rdFunction = META_CREATEBRUSHINDIRECT;
221             memcpy( mr->rdParm, &lb16, sizeof(LOGBRUSH16));
222             break;
223         }
224     case BS_PATTERN:
225         {
226             BITMAP bm;
227             BITMAPINFO *info;
228             DWORD bmSize;
229             COLORREF cref;
230
231             GetObjectA((HANDLE)logbrush.lbHatch, sizeof(bm), &bm);
232             if(bm.bmBitsPixel != 1 || bm.bmPlanes != 1) {
233                 FIXME("Trying to store a colour pattern brush\n");
234                 goto done;
235             }
236
237             bmSize = DIB_GetDIBImageBytes(bm.bmWidth, bm.bmHeight, DIB_PAL_COLORS);
238
239             size = sizeof(METARECORD) + sizeof(WORD) + sizeof(BITMAPINFO) +
240               sizeof(RGBQUAD) + bmSize;
241
242             mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
243             if(!mr) goto done;
244             mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
245             mr->rdSize = size / 2;
246             mr->rdParm[0] = BS_PATTERN;
247             mr->rdParm[1] = DIB_RGB_COLORS;
248             info = (BITMAPINFO *)(mr->rdParm + 2);
249
250             info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
251             info->bmiHeader.biWidth = bm.bmWidth;
252             info->bmiHeader.biHeight = bm.bmHeight;
253             info->bmiHeader.biPlanes = 1;
254             info->bmiHeader.biBitCount = 1;
255             info->bmiHeader.biSizeImage = bmSize;
256
257             GetBitmapBits((HANDLE)logbrush.lbHatch,
258                       bm.bmHeight * BITMAP_GetWidthBytes (bm.bmWidth, bm.bmBitsPixel),
259                       (LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD));
260
261             /* Change the padding to be DIB compatible if needed */
262             if(bm.bmWidth & 31)
263                 MFDRV_PadTo32((LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD),
264                       bm.bmWidth, bm.bmHeight);
265             /* BMP and DIB have opposite row order conventions */
266             MFDRV_Reverse((LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD),
267                       bm.bmWidth, bm.bmHeight);
268
269             cref = GetTextColor(physDev->hdc);
270             info->bmiColors[0].rgbRed = GetRValue(cref);
271             info->bmiColors[0].rgbGreen = GetGValue(cref);
272             info->bmiColors[0].rgbBlue = GetBValue(cref);
273             info->bmiColors[0].rgbReserved = 0;
274             cref = GetBkColor(physDev->hdc);
275             info->bmiColors[1].rgbRed = GetRValue(cref);
276             info->bmiColors[1].rgbGreen = GetGValue(cref);
277             info->bmiColors[1].rgbBlue = GetBValue(cref);
278             info->bmiColors[1].rgbReserved = 0;
279             break;
280         }
281
282     case BS_DIBPATTERN:
283         {
284               BITMAPINFO *info;
285               DWORD bmSize, biSize;
286
287               info = GlobalLock16((HGLOBAL16)logbrush.lbHatch);
288               if (info->bmiHeader.biCompression)
289                   bmSize = info->bmiHeader.biSizeImage;
290               else
291                   bmSize = DIB_GetDIBImageBytes(info->bmiHeader.biWidth,
292                                                 info->bmiHeader.biHeight,
293                                                 info->bmiHeader.biBitCount);
294               biSize = DIB_BitmapInfoSize(info, LOWORD(logbrush.lbColor));
295               size = sizeof(METARECORD) + biSize + bmSize + 2;
296               mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
297               if(!mr) goto done;
298               mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
299               mr->rdSize = size / 2;
300               *(mr->rdParm) = logbrush.lbStyle;
301               *(mr->rdParm + 1) = LOWORD(logbrush.lbColor);
302               memcpy(mr->rdParm + 2, info, biSize + bmSize);
303               break;
304         }
305         default:
306             FIXME("Unkonwn brush style %x\n", logbrush.lbStyle);
307             return 0;
308     }
309     r = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2);
310     HeapFree(GetProcessHeap(), 0, mr);
311     if( !r )
312         return -1;
313 done:
314     return MFDRV_AddHandle( dev, hBrush );
315 }
316
317
318 /***********************************************************************
319  *           MFDRV_SelectBrush
320  */
321 HBRUSH MFDRV_SelectBrush( PHYSDEV dev, HBRUSH hbrush )
322 {
323     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
324     INT16 index;
325
326     index = MFDRV_FindObject(dev, hbrush);
327     if( index < 0 )
328     {
329         index = MFDRV_CreateBrushIndirect( dev, hbrush );
330         if( index < 0 )
331             return 0;
332         GDI_hdc_using_object(hbrush, physDev->hdc);
333     }
334     return MFDRV_SelectObject( dev, index ) ? hbrush : HGDI_ERROR;
335 }
336
337 /******************************************************************
338  *         MFDRV_CreateFontIndirect
339  */
340
341 static UINT16 MFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont, LOGFONT16 *logfont)
342 {
343     char buffer[sizeof(METARECORD) - 2 + sizeof(LOGFONT16)];
344     METARECORD *mr = (METARECORD *)&buffer;
345
346     mr->rdSize = (sizeof(METARECORD) + sizeof(LOGFONT16) - 2) / 2;
347     mr->rdFunction = META_CREATEFONTINDIRECT;
348     memcpy(&(mr->rdParm), logfont, sizeof(LOGFONT16));
349     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
350         return 0;
351     return MFDRV_AddHandle( dev, hFont );
352 }
353
354
355 /***********************************************************************
356  *           MFDRV_SelectFont
357  */
358 HFONT MFDRV_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
359 {
360     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
361     LOGFONT16 lf16;
362     INT16 index;
363
364     index = MFDRV_FindObject(dev, hfont);
365     if( index < 0 )
366     {
367         if (!GetObject16( HFONT_16(hfont), sizeof(lf16), &lf16 ))
368             return HGDI_ERROR;
369         index = MFDRV_CreateFontIndirect(dev, hfont, &lf16);
370         if( index < 0 )
371             return HGDI_ERROR;
372         GDI_hdc_using_object(hfont, physDev->hdc);
373     }
374     return MFDRV_SelectObject( dev, index ) ? hfont : HGDI_ERROR;
375 }
376
377 /******************************************************************
378  *         MFDRV_CreatePenIndirect
379  */
380 static UINT16 MFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen, LOGPEN16 *logpen)
381 {
382     char buffer[sizeof(METARECORD) - 2 + sizeof(*logpen)];
383     METARECORD *mr = (METARECORD *)&buffer;
384
385     mr->rdSize = (sizeof(METARECORD) + sizeof(*logpen) - 2) / 2;
386     mr->rdFunction = META_CREATEPENINDIRECT;
387     memcpy(&(mr->rdParm), logpen, sizeof(*logpen));
388     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
389         return 0;
390     return MFDRV_AddHandle( dev, hPen );
391 }
392
393
394 /***********************************************************************
395  *           MFDRV_SelectPen
396  */
397 HPEN MFDRV_SelectPen( PHYSDEV dev, HPEN hpen )
398 {
399     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
400     LOGPEN16 logpen;
401     INT16 index;
402
403     index = MFDRV_FindObject(dev, hpen);
404     if( index < 0 )
405     {
406         if (!GetObject16( HPEN_16(hpen), sizeof(logpen), &logpen ))
407             return 0;
408         index = MFDRV_CreatePenIndirect( dev, hpen, &logpen );
409         if( index < 0 )
410             return 0;
411         GDI_hdc_using_object(hpen, physDev->hdc);
412     }
413     return MFDRV_SelectObject( dev, index ) ? hpen : HGDI_ERROR;
414 }
415
416
417 /******************************************************************
418  *         MFDRV_CreatePalette
419  */
420 static BOOL MFDRV_CreatePalette(PHYSDEV dev, HPALETTE hPalette, LOGPALETTE* logPalette, int sizeofPalette)
421 {
422     int index;
423     BOOL ret;
424     METARECORD *mr;
425
426     mr = HeapAlloc( GetProcessHeap(), 0, sizeof(METARECORD) + sizeofPalette - sizeof(WORD) );
427     mr->rdSize = (sizeof(METARECORD) + sizeofPalette - sizeof(WORD)) / sizeof(WORD);
428     mr->rdFunction = META_CREATEPALETTE;
429     memcpy(&(mr->rdParm), logPalette, sizeofPalette);
430     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD))))
431     {
432         HeapFree(GetProcessHeap(), 0, mr);
433         return FALSE;
434     }
435
436     mr->rdSize = sizeof(METARECORD) / sizeof(WORD);
437     mr->rdFunction = META_SELECTPALETTE;
438
439     if ((index = MFDRV_AddHandle( dev, hPalette )) == -1) ret = FALSE;
440     else
441     {
442         *(mr->rdParm) = index;
443         ret = MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD));
444     }
445     HeapFree(GetProcessHeap(), 0, mr);
446     return ret;
447 }
448
449
450 /***********************************************************************
451  *           MFDRV_SelectPalette
452  */
453 HPALETTE MFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPalette, BOOL bForceBackground )
454 {
455 #define PALVERSION 0x0300
456
457     PLOGPALETTE logPalette;
458     WORD        wNumEntries = 0;
459     BOOL        creationSucceed;
460     int         sizeofPalette;
461
462     GetObjectA(hPalette, sizeof(WORD), (LPSTR) &wNumEntries);
463
464     if (wNumEntries == 0) return 0;
465
466     sizeofPalette = sizeof(LOGPALETTE) + ((wNumEntries-1) * sizeof(PALETTEENTRY));
467     logPalette = HeapAlloc( GetProcessHeap(), 0, sizeofPalette );
468
469     if (logPalette == NULL) return 0;
470
471     logPalette->palVersion = PALVERSION;
472     logPalette->palNumEntries = wNumEntries;
473
474     GetPaletteEntries(hPalette, 0, wNumEntries, logPalette->palPalEntry);
475
476     creationSucceed = MFDRV_CreatePalette( dev, hPalette, logPalette, sizeofPalette );
477
478     HeapFree( GetProcessHeap(), 0, logPalette );
479
480     if (creationSucceed)
481         return hPalette;
482
483     return 0;
484 }
485
486 /***********************************************************************
487  *           MFDRV_RealizePalette
488  */
489 UINT MFDRV_RealizePalette(PHYSDEV dev, HPALETTE hPalette, BOOL dummy)
490 {
491     char buffer[sizeof(METARECORD) - sizeof(WORD)];
492     METARECORD *mr = (METARECORD *)&buffer;
493
494     mr->rdSize = (sizeof(METARECORD) - sizeof(WORD)) / sizeof(WORD);
495     mr->rdFunction = META_REALIZEPALETTE;
496
497     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD)))) return 0;
498
499     /* The return value is suppose to be the number of entries
500        in the logical palette mapped to the system palette or 0
501        if the function failed. Since it's not trivial here to
502        get that kind of information and since it's of little
503        use in the case of metafiles, we'll always return 1. */
504     return 1;
505 }