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