gdi32: Add a helper function to add a rectangle to a region.
[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     case BS_DIBPATTERN:
178         {
179             char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
180             BITMAPINFO *dst_info, *src_info = (BITMAPINFO *)buffer;
181             DWORD info_size;
182             char *dst_ptr;
183             void *bits;
184             UINT usage;
185
186             if (!get_brush_bitmap_info( hBrush, src_info, &bits, &usage )) goto done;
187
188             info_size = get_dib_info_size( src_info, usage );
189             size = FIELD_OFFSET( METARECORD, rdParm[2] ) + info_size + src_info->bmiHeader.biSizeImage;
190
191             if (!(mr = HeapAlloc( GetProcessHeap(), 0, size ))) goto done;
192             mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
193             mr->rdSize = size / 2;
194             mr->rdParm[0] = logbrush.lbStyle;
195             mr->rdParm[1] = usage;
196             dst_info = (BITMAPINFO *)(mr->rdParm + 2);
197             memcpy( dst_info, src_info, info_size );
198             if (dst_info->bmiHeader.biClrUsed == 1 << dst_info->bmiHeader.biBitCount)
199                 dst_info->bmiHeader.biClrUsed = 0;
200             dst_ptr = (char *)dst_info + info_size;
201
202             /* always return a bottom-up DIB */
203             if (dst_info->bmiHeader.biHeight < 0)
204             {
205                 int i, width_bytes = get_dib_stride( dst_info->bmiHeader.biWidth,
206                                                      dst_info->bmiHeader.biBitCount );
207                 dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
208                 dst_ptr += (dst_info->bmiHeader.biHeight - 1) * width_bytes;
209                 for (i = 0; i < dst_info->bmiHeader.biHeight; i++, dst_ptr -= width_bytes)
210                     memcpy( dst_ptr, (char *)bits + i * width_bytes, width_bytes );
211             }
212             else memcpy( dst_ptr, bits, src_info->bmiHeader.biSizeImage );
213             break;
214         }
215
216         default:
217             FIXME("Unkonwn brush style %x\n", logbrush.lbStyle);
218             return 0;
219     }
220     r = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2);
221     HeapFree(GetProcessHeap(), 0, mr);
222     if( !r )
223         return -1;
224 done:
225     return MFDRV_AddHandle( dev, hBrush );
226 }
227
228
229 /***********************************************************************
230  *           MFDRV_SelectBrush
231  */
232 HBRUSH MFDRV_SelectBrush( PHYSDEV dev, HBRUSH hbrush, HBITMAP bitmap,
233                           const BITMAPINFO *info, void *bits, UINT usage )
234 {
235     INT16 index;
236
237     index = MFDRV_FindObject(dev, hbrush);
238     if( index < 0 )
239     {
240         index = MFDRV_CreateBrushIndirect( dev, hbrush );
241         if( index < 0 )
242             return 0;
243         GDI_hdc_using_object(hbrush, dev->hdc);
244     }
245     return MFDRV_SelectObject( dev, index ) ? hbrush : 0;
246 }
247
248 /******************************************************************
249  *         MFDRV_CreateFontIndirect
250  */
251
252 static UINT16 MFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont, LOGFONTW *logfont)
253 {
254     char buffer[sizeof(METARECORD) - 2 + sizeof(LOGFONT16)];
255     METARECORD *mr = (METARECORD *)&buffer;
256     LOGFONT16 *font16;
257     INT written;
258
259     mr->rdSize = (sizeof(METARECORD) + sizeof(LOGFONT16) - 2) / 2;
260     mr->rdFunction = META_CREATEFONTINDIRECT;
261     font16 = (LOGFONT16 *)&mr->rdParm;
262
263     font16->lfHeight         = logfont->lfHeight;
264     font16->lfWidth          = logfont->lfWidth;
265     font16->lfEscapement     = logfont->lfEscapement;
266     font16->lfOrientation    = logfont->lfOrientation;
267     font16->lfWeight         = logfont->lfWeight;
268     font16->lfItalic         = logfont->lfItalic;
269     font16->lfUnderline      = logfont->lfUnderline;
270     font16->lfStrikeOut      = logfont->lfStrikeOut;
271     font16->lfCharSet        = logfont->lfCharSet;
272     font16->lfOutPrecision   = logfont->lfOutPrecision;
273     font16->lfClipPrecision  = logfont->lfClipPrecision;
274     font16->lfQuality        = logfont->lfQuality;
275     font16->lfPitchAndFamily = logfont->lfPitchAndFamily;
276     written = WideCharToMultiByte( CP_ACP, 0, logfont->lfFaceName, -1, font16->lfFaceName, LF_FACESIZE - 1, NULL, NULL );
277     /* Zero pad the facename buffer, so that we don't write uninitialized data to disk */
278     memset(font16->lfFaceName + written, 0, LF_FACESIZE - written);
279
280     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
281         return 0;
282     return MFDRV_AddHandle( dev, hFont );
283 }
284
285
286 /***********************************************************************
287  *           MFDRV_SelectFont
288  */
289 HFONT MFDRV_SelectFont( PHYSDEV dev, HFONT hfont )
290 {
291     LOGFONTW font;
292     INT16 index;
293
294     index = MFDRV_FindObject(dev, hfont);
295     if( index < 0 )
296     {
297         if (!GetObjectW( hfont, sizeof(font), &font ))
298             return 0;
299         index = MFDRV_CreateFontIndirect(dev, hfont, &font);
300         if( index < 0 )
301             return 0;
302         GDI_hdc_using_object(hfont, dev->hdc);
303     }
304     return MFDRV_SelectObject( dev, index ) ? hfont : 0;
305 }
306
307 /******************************************************************
308  *         MFDRV_CreatePenIndirect
309  */
310 static UINT16 MFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen, LOGPEN16 *logpen)
311 {
312     char buffer[sizeof(METARECORD) - 2 + sizeof(*logpen)];
313     METARECORD *mr = (METARECORD *)&buffer;
314
315     mr->rdSize = (sizeof(METARECORD) + sizeof(*logpen) - 2) / 2;
316     mr->rdFunction = META_CREATEPENINDIRECT;
317     memcpy(&(mr->rdParm), logpen, sizeof(*logpen));
318     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
319         return 0;
320     return MFDRV_AddHandle( dev, hPen );
321 }
322
323
324 /***********************************************************************
325  *           MFDRV_SelectPen
326  */
327 HPEN MFDRV_SelectPen( PHYSDEV dev, HPEN hpen )
328 {
329     LOGPEN16 logpen;
330     INT16 index;
331
332     index = MFDRV_FindObject(dev, hpen);
333     if( index < 0 )
334     {
335         /* must be an extended pen */
336         INT size = GetObjectW( hpen, 0, NULL );
337
338         if (!size) return 0;
339
340         if (size == sizeof(LOGPEN))
341         {
342             LOGPEN pen;
343
344             GetObjectW( hpen, sizeof(pen), &pen );
345             logpen.lopnStyle   = pen.lopnStyle;
346             logpen.lopnWidth.x = pen.lopnWidth.x;
347             logpen.lopnWidth.y = pen.lopnWidth.y;
348             logpen.lopnColor   = pen.lopnColor;
349         }
350         else  /* must be an extended pen */
351         {
352             EXTLOGPEN *elp = HeapAlloc( GetProcessHeap(), 0, size );
353
354             GetObjectW( hpen, size, elp );
355             /* FIXME: add support for user style pens */
356             logpen.lopnStyle = elp->elpPenStyle;
357             logpen.lopnWidth.x = elp->elpWidth;
358             logpen.lopnWidth.y = 0;
359             logpen.lopnColor = elp->elpColor;
360
361             HeapFree( GetProcessHeap(), 0, elp );
362         }
363
364         index = MFDRV_CreatePenIndirect( dev, hpen, &logpen );
365         if( index < 0 )
366             return 0;
367         GDI_hdc_using_object(hpen, dev->hdc);
368     }
369     return MFDRV_SelectObject( dev, index ) ? hpen : 0;
370 }
371
372
373 /******************************************************************
374  *         MFDRV_CreatePalette
375  */
376 static BOOL MFDRV_CreatePalette(PHYSDEV dev, HPALETTE hPalette, LOGPALETTE* logPalette, int sizeofPalette)
377 {
378     int index;
379     BOOL ret;
380     METARECORD *mr;
381
382     mr = HeapAlloc( GetProcessHeap(), 0, sizeof(METARECORD) + sizeofPalette - sizeof(WORD) );
383     mr->rdSize = (sizeof(METARECORD) + sizeofPalette - sizeof(WORD)) / sizeof(WORD);
384     mr->rdFunction = META_CREATEPALETTE;
385     memcpy(&(mr->rdParm), logPalette, sizeofPalette);
386     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD))))
387     {
388         HeapFree(GetProcessHeap(), 0, mr);
389         return FALSE;
390     }
391
392     mr->rdSize = sizeof(METARECORD) / sizeof(WORD);
393     mr->rdFunction = META_SELECTPALETTE;
394
395     if ((index = MFDRV_AddHandle( dev, hPalette )) == -1) ret = FALSE;
396     else
397     {
398         *(mr->rdParm) = index;
399         ret = MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD));
400     }
401     HeapFree(GetProcessHeap(), 0, mr);
402     return ret;
403 }
404
405
406 /***********************************************************************
407  *           MFDRV_SelectPalette
408  */
409 HPALETTE MFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPalette, BOOL bForceBackground )
410 {
411 #define PALVERSION 0x0300
412
413     PLOGPALETTE logPalette;
414     WORD        wNumEntries = 0;
415     BOOL        creationSucceed;
416     int         sizeofPalette;
417
418     GetObjectA(hPalette, sizeof(WORD), &wNumEntries);
419
420     if (wNumEntries == 0) return 0;
421
422     sizeofPalette = sizeof(LOGPALETTE) + ((wNumEntries-1) * sizeof(PALETTEENTRY));
423     logPalette = HeapAlloc( GetProcessHeap(), 0, sizeofPalette );
424
425     if (logPalette == NULL) return 0;
426
427     logPalette->palVersion = PALVERSION;
428     logPalette->palNumEntries = wNumEntries;
429
430     GetPaletteEntries(hPalette, 0, wNumEntries, logPalette->palPalEntry);
431
432     creationSucceed = MFDRV_CreatePalette( dev, hPalette, logPalette, sizeofPalette );
433
434     HeapFree( GetProcessHeap(), 0, logPalette );
435
436     if (creationSucceed)
437         return hPalette;
438
439     return 0;
440 }
441
442 /***********************************************************************
443  *           MFDRV_RealizePalette
444  */
445 UINT MFDRV_RealizePalette(PHYSDEV dev, HPALETTE hPalette, BOOL dummy)
446 {
447     char buffer[sizeof(METARECORD) - sizeof(WORD)];
448     METARECORD *mr = (METARECORD *)&buffer;
449
450     mr->rdSize = (sizeof(METARECORD) - sizeof(WORD)) / sizeof(WORD);
451     mr->rdFunction = META_REALIZEPALETTE;
452
453     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD)))) return 0;
454
455     /* The return value is suppose to be the number of entries
456        in the logical palette mapped to the system palette or 0
457        if the function failed. Since it's not trivial here to
458        get that kind of information and since it's of little
459        use in the case of metafiles, we'll always return 1. */
460     return 1;
461 }