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