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